OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2011 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can | |
4 * be found in the LICENSE file. | |
5 */ | |
6 | |
7 #include <string> | |
8 | |
9 #include "debug_conn/debug_host.h" | |
10 #include "debug_conn/debug_packet.h" | |
11 #include "debug_conn/debug_pipe.h" | |
12 #include "debug_conn/debug_socket.h" | |
13 #include "debug_conn/debug_util.h" | |
14 | |
15 using namespace nacl_debug_conn; | |
16 | |
17 using std::string; | |
18 | |
19 DebugHost::DebugHost(DebugPipe *pipe) | |
20 : pipe_(pipe), | |
21 outputFunc_(0), | |
22 outputObj_(0), | |
23 stopFunc_(0), | |
24 stopObj_(0) { } | |
25 | |
26 DebugHost::~DebugHost() { | |
27 if (pipe_) | |
28 delete pipe_; | |
29 } | |
30 | |
31 DebugHost *DebugHost::SocketConnect(const char *addr) { | |
32 DebugSocket *sock = DebugSocket::CreateClient(addr); | |
33 if (NULL == sock) | |
34 return NULL; | |
35 | |
36 DebugPipe *pipe = new DebugPipe(sock); | |
37 DebugHost *host = new DebugHost(pipe); | |
38 | |
39 pipe->SetName("host"); | |
40 pipe->SetFlagsMasked(DebugPipe::DPF_DEBUG_SEND | DebugPipe::DPF_DEBUG_RECV, De
bugPipe::DPF_DEBUG_MASK); | |
41 pipe->SetFlagsMasked(DebugPipe::DPF_IGNORE_ACK, DebugPipe::DPF_IGNORE_ACK); | |
42 pipe->SetFlagsMasked(DebugPipe::DPF_USE_SEQ, DebugPipe::DPF_USE_SEQ); | |
43 return host; | |
44 } | |
45 | |
46 DebugHost::DHResult DebugHost::Transact(DebugPacket *outPkt, DebugPacket *inPkt)
{ | |
47 DebugPipe::DPResult res; | |
48 bool stopPending = false; | |
49 | |
50 if (NULL == pipe_) | |
51 return DHR_LOST; | |
52 | |
53 res = pipe_->SendPacket(outPkt); | |
54 if (res == DebugPipe::DPR_ERROR) | |
55 return DHR_LOST; | |
56 | |
57 if (res == DebugPipe::DPR_NO_DATA) | |
58 return DHR_TIMEOUT; | |
59 | |
60 if (res == DHR_OK) { | |
61 while(1) { | |
62 // HACK HACK HACK: cheezy wait/timeout implementation | |
63 // TODO(noelallen): make this really async | |
64 // FIXME(mmortensen) -- address/remove the comment above | |
65 const DWORD timeout = 0xffffffff; | |
66 DWORD start = GetTickCount(); | |
67 debug_log_info("DebugHost::Transact...Start=%u stopPending=%ld\n", | |
68 start, stopPending); | |
69 while(!pipe_->DataAvail()) { | |
70 debug_log_info("DebugHost::Transact...No data avail\n"); | |
71 Sleep(0); | |
72 if(GetTickCount() - start > timeout) { | |
73 debug_log_info("DebugHost::Transact returning DHR_TIMEOUT(%d)\n", | |
74 DHR_TIMEOUT); | |
75 return DHR_TIMEOUT; | |
76 } | |
77 } | |
78 | |
79 res = pipe_->GetPacket(inPkt); | |
80 const char *packet_string = 0; | |
81 // Look at (peek at) packet without modifying it -- some packet methods | |
82 // modify of the received data. | |
83 inPkt->PeekString(&packet_string); | |
84 debug_log_info("DebugHost::Transact inPkt->GetPacket res=%d {%s}\n", | |
85 res, packet_string); | |
86 if (res == DebugPipe::DPR_ERROR) | |
87 return DHR_LOST; | |
88 | |
89 if (res == DebugPipe::DPR_NO_DATA) | |
90 return DHR_TIMEOUT; | |
91 | |
92 char peek_char; | |
93 if (inPkt->PeekChar(&peek_char)) { | |
94 debug_log_info("DebugHost::Transact PeekChar for inPkt='%c'\n", | |
95 peek_char); | |
96 if (peek_char == 'W' || peek_char == 'O' || | |
97 peek_char == 'S' || peek_char == 'T') { | |
98 | |
99 // Find the command -- the first character received. | |
100 char cmd = peek_char; | |
101 | |
102 switch(cmd) { | |
103 case 'W': | |
104 case 'S': | |
105 case 'T': | |
106 flags_.SetFlagsMasked(0, DHF_RUNNING); | |
107 stopPending = true; | |
108 debug_log_info("DebugHost::Transact cmd=%c," | |
109 " set flags to DHF_RUNNING\n", | |
110 cmd, stopPending); | |
111 | |
112 if (stopFunc_) { | |
113 debug_log_info("DebugHost::Transact Calling stopFunc @%s:%d\n", | |
114 __FILE__, __LINE__); | |
115 stopFunc_(DHR_OK, stopObj_); | |
116 debug_log_info("DebugHost::Transact Called stopFunc..." | |
117 "returning DebugHost::DHR_OK(%d)\n", | |
118 DebugHost::DHR_OK); | |
119 return DebugHost::DHR_OK; | |
120 } | |
121 continue; // sends us back to the TOP of the loop & block | |
122 case 'O': | |
123 if (outputFunc_) { | |
124 const char *str = 0; | |
125 if (inPkt->GetHexString(&str)) { | |
126 debug_log_info(" DebugHost::Transact %d Calling outputFunc" | |
127 " with str=[%s] packet_string=[%s]\n", | |
128 __LINE__, str, packet_string); | |
129 // outputFunc_(DHR_OK, outputObj_, str); | |
130 outputFunc_(DHR_OK, outputObj_, packet_string); | |
131 free((void *) str); | |
132 return DebugHost::DHR_OK; | |
133 } | |
134 } | |
135 continue; | |
136 default: | |
137 debug_log_info("DebugHost::Transact returning DHR_LOST\n"); | |
138 return DebugHost::DHR_LOST; | |
139 } // end switch | |
140 // end 'if peek_char is W,S,O, or T' | |
141 } else { | |
142 debug_log_info("DebugHost::Transact peek_char is not W,S,O,T\n"); | |
143 } | |
144 // end if inPkt->PeekChar returns true | |
145 } else { | |
146 debug_log_info("DebugHost::Transact inPkt->PeekChar returned false\n"); | |
147 } | |
148 | |
149 if (stopPending && stopFunc_) { | |
150 debug_log_info("DebugHost::Transact Calling stopFunc @ %s:%d\n", | |
151 __FILE__, __LINE__); | |
152 stopFunc_(DHR_OK, stopObj_); | |
153 } else { | |
154 debug_log_info("DebugHost::Transact Didn't call stopFunc," | |
155 " stopPending=%d\n", stopPending); | |
156 } | |
157 | |
158 debug_log_info("DebugHost::Transact returning DHR_OK %s:%d\n", | |
159 __FILE__, __LINE__); | |
160 return DHR_OK; | |
161 } | |
162 } | |
163 debug_log_info("DebugHost::Transact returning DHR_FAILED %s:%d\n", | |
164 __FILE__, __LINE__); | |
165 return DHR_FAILED; | |
166 } | |
167 | |
168 | |
169 | |
170 | |
171 nacl_debug_conn::DebugHost::DHResult nacl_debug_conn::DebugHost::SendString( con
st char* str, const char** ppReply ) | |
172 { | |
173 DebugPacket outPkt, inPkt; | |
174 DHResult res; | |
175 | |
176 outPkt.Clear(); | |
177 outPkt.AddString(str); | |
178 res = Transact(&outPkt, &inPkt); | |
179 | |
180 if (res == DHR_OK) { | |
181 if (!inPkt.GetString(&str)) { | |
182 res = DHR_FAILED; | |
183 } | |
184 } | |
185 | |
186 return res; | |
187 } | |
188 | |
189 DebugHost::DHResult DebugHost::SendStringAsync(const char *str, DHAsyncStr reply
, void *obj) { | |
190 DebugPacket outPkt, inPkt; | |
191 DHResult res; | |
192 | |
193 outPkt.Clear(); | |
194 outPkt.AddString(str); | |
195 debug_log_info("DebugHost::SendStringAsync Calling Transact %s %d\n", | |
196 __FILE__, __LINE__); | |
197 res = Transact(&outPkt, &inPkt); | |
198 debug_log_info("DebugHost::SendStringAsync [%s], Transact returned %d\n", | |
199 str, res); | |
200 if (res == DHR_OK) { | |
201 const char *pstr; | |
202 debug_log_info("DebugHost::SendStringAsync, calling GetString on inPkt\n"); | |
203 if (inPkt.GetString(&pstr)) { | |
204 debug_log_info("DebugHost::SendStringAsync, REPLY pstr=[%s]\n", pstr); | |
205 reply(DHR_OK, obj, pstr); | |
206 delete[] pstr; | |
207 } else { | |
208 debug_log_info("DebugHost::SendStringAsync inPkt.GetString failed"); | |
209 } | |
210 } | |
211 | |
212 // Note: it's NOT asynchronous! | |
213 // Danger: callback gets called only in some cases! | |
214 | |
215 return res; | |
216 } | |
217 | |
218 typedef struct { | |
219 DebugHost::DHAsyncStr func; | |
220 uint32_t count; | |
221 void *obj; | |
222 } StripObj_t; | |
223 | |
224 static void __stdcall StripResult(DebugHost::DHResult res, void *obj, const char
*str) { | |
225 StripObj_t *sobj = reinterpret_cast<StripObj_t *>(obj); | |
226 uint32_t pos = static_cast<uint32_t>(strlen(str)); | |
227 | |
228 if (pos > sobj->count) | |
229 pos = sobj->count; | |
230 | |
231 sobj->func(res, sobj->obj, &str[pos]); | |
232 } | |
233 | |
234 DebugHost::DHResult DebugHost::GetArchAsync(DHAsyncStr reply, void *obj) { | |
235 StripObj_t sobj; | |
236 | |
237 sobj.count= 1; | |
238 sobj.func = reply; | |
239 sobj.obj = obj; | |
240 | |
241 return SendStringAsync("qXfer:features:read:target.xml:0,fff", StripResult, &s
obj); | |
242 } | |
243 | |
244 DebugHost::DHResult DebugHost::GetLastSig(int *sig) { | |
245 DebugPacket outPkt, inPkt; | |
246 DHResult res; | |
247 | |
248 outPkt.Clear(); | |
249 outPkt.AddString("?"); | |
250 debug_log_info("DebugHost::GetLastSig Calling Transact\n"); | |
251 res = Transact(&outPkt, &inPkt); | |
252 debug_log_info("DebugHost::GetLastSig, Transact returned %d\n", res); | |
253 if (res == DHR_OK) { | |
254 char ch; | |
255 uint8_t num; | |
256 bool local_result = inPkt.GetRawChar(&ch); | |
257 debug_log_info("DebugHost::GetLastSig: GetRawChar returned %d, ch=%c\n", | |
258 local_result, ch); | |
259 if (local_result && 'S' == ch) { | |
260 if (inPkt.GetByte(&num)) { | |
261 debug_log_info("DebugHost::GetLastSig: GetByte num=%d\n", num); | |
262 *sig = num; | |
263 return DHR_OK; | |
264 } | |
265 } | |
266 return DHR_FAILED; | |
267 } | |
268 return res; | |
269 } | |
270 | |
271 | |
272 typedef struct { | |
273 string outstr; | |
274 bool done; | |
275 } ThreadFetchObj_t; | |
276 | |
277 static void __stdcall ThreadFetch(DebugHost::DHResult res, void *obj, const char
*str) { | |
278 ThreadFetchObj_t *tfo = reinterpret_cast<ThreadFetchObj_t *>(obj); | |
279 char *words[32]; | |
280 char tmp[128]; | |
281 | |
282 if (res == DebugHost::DHR_OK) { | |
283 if ('m' == str[0]) { | |
284 debug_log_info("DebugHost::ThreadFetch Found 'm' in ThreadFetch [%s]\n", | |
285 str); | |
286 int loop; | |
287 int cnt = debug_get_tokens(&str[1], ',', words, 32); | |
288 debug_log_info("DebugHost::ThreadFetch. cnt=%d\n", cnt); | |
289 for (loop = 0; loop < cnt; loop++) { | |
290 sprintf(tmp, "<thread id=\"%s\" core=\"0\"/>\n", words[loop]); | |
291 tfo->outstr += tmp; | |
292 } | |
293 debug_log_info("DebugHost::ThreadFetch. tfo->outstr = [%s]\n", | |
294 tfo->outstr.c_str()); | |
295 return; | |
296 } | |
297 } | |
298 | |
299 tfo->done = 1; | |
300 } | |
301 | |
302 DebugHost::DHResult DebugHost::GetThreadsAsync(DHAsyncStr cb, void *obj) { | |
303 DHResult res; | |
304 ThreadFetchObj_t tfo; | |
305 | |
306 tfo.done = 0; | |
307 tfo.outstr = "<threads>\n"; | |
308 debug_log_info("DebugHost::GetThreadsAsync"); | |
309 res = SendStringAsync("qfThreadInfo", ThreadFetch, &tfo); | |
310 while (!tfo.done) { | |
311 if (res != DHR_OK) | |
312 break; | |
313 res = SendStringAsync("qsThreadInfo", ThreadFetch, &tfo); | |
314 } | |
315 tfo.outstr += "</threads>\n"; | |
316 cb(res, obj, tfo.outstr.data()); | |
317 return res; | |
318 } | |
319 | |
320 nacl_debug_conn::DebugHost::DHResult nacl_debug_conn::DebugHost::GetRegisters( v
oid *data, uint32_t max ) | |
321 { | |
322 DebugPacket outPkt, inPkt; | |
323 DHResult res; | |
324 | |
325 outPkt.Clear(); | |
326 outPkt.AddRawChar('g'); | |
327 debug_log_info("DebugHost::GetRegisters max=%d Calling Transact\n", max); | |
328 res = Transact(&outPkt, &inPkt); | |
329 | |
330 // Log if an error occurs. On success log the length of the reply, since | |
331 // a short reply occurs if we get out of sync and get something like "S05" | |
332 // from a previous transmission instead of a long list of register values. | |
333 if (res == DHR_OK) { | |
334 int len = inPkt.Read(data, max); | |
335 debug_log_info("DebugHost::GetRegisters res=OK, max=%d len=%d\n", max, len); | |
336 } else { | |
337 debug_log_info("DebugHost::GetRegisters, bad res=%d, max=%d\n", res, max); | |
338 } | |
339 return res; | |
340 } | |
341 | |
342 DebugHost::DHResult DebugHost::SetRegisters(void *data, uint32_t size) { | |
343 DebugPacket outPkt, inPkt; | |
344 DHResult res; | |
345 | |
346 outPkt.Clear(); | |
347 outPkt.AddRawChar('G'); | |
348 outPkt.AddBlock(data, size); | |
349 res = Transact(&outPkt, &inPkt); | |
350 debug_log_info("DebugHost::SetRegisters, Transact returned %d\n", res); | |
351 if (res == DHR_OK) { | |
352 const char *str; | |
353 if (inPkt.GetString(&str)) { | |
354 if (!strcmp(str, "OK")) | |
355 res = DHR_OK; | |
356 else { | |
357 if (str[0] == 'E') { | |
358 debug_log_warning("DebugHost::Set registers error, str='%s'\n", str); | |
359 res = DHR_FAILED; | |
360 } | |
361 } | |
362 delete[] str; | |
363 } | |
364 } | |
365 | |
366 return res; | |
367 } | |
368 | |
369 | |
370 nacl_debug_conn::DebugHost::DHResult nacl_debug_conn::DebugHost::GetMemory(uint6
4_t offs, void* data, uint32_t max) | |
371 { | |
372 DebugPacket outPkt, inPkt; | |
373 DHResult res; | |
374 | |
375 int len = 0; | |
376 | |
377 outPkt.Clear(); | |
378 outPkt.AddRawChar('m'); | |
379 outPkt.AddNumberSep(offs, ','); | |
380 outPkt.AddNumberSep(max, 0); | |
381 debug_log_info("DebugHost::GetMemory Calling Transact\n"); | |
382 res = Transact(&outPkt, &inPkt); | |
383 debug_log_info("DebugHost::GetMemory, Transact returned %d\n", res); | |
384 if (res == DHR_OK) { | |
385 len = inPkt.Read(data, max); | |
386 debug_log_info(" DebugHost::GetMemory, len=%d\n", len); | |
387 if (len == max) { | |
388 res = DHR_OK; | |
389 } else { | |
390 res = DHR_LOST; | |
391 } | |
392 } | |
393 | |
394 return res; | |
395 } | |
396 | |
397 DebugHost::DHResult DebugHost::SetMemory(uint64_t offs, void *data, uint32_t max
) { | |
398 DebugPacket outPkt, inPkt; | |
399 DHResult res; | |
400 | |
401 outPkt.Clear(); | |
402 outPkt.AddRawChar('M'); | |
403 outPkt.AddNumberSep(offs, ','); | |
404 outPkt.AddNumberSep(max, ':'); | |
405 outPkt.AddBlock(data, max); | |
406 debug_log_info("DebugHost::SetMemory Calling Transact\n"); | |
407 res = Transact(&outPkt, &inPkt); | |
408 debug_log_info("DebugHost::SetMemory, Transact returned %d\n", res); | |
409 if (res == DHR_OK) { | |
410 const char *str; | |
411 if (inPkt.GetString(&str)) { | |
412 debug_log_info("DebugHost::SetMemory, inPkt.GetString returned '%s'\n", | |
413 str); | |
414 if (!strcmp(str, "OK")) | |
415 res = DHR_OK; | |
416 else { | |
417 if (str[0] == 'E') { | |
418 debug_log_warning("DebugHost::Set memory reported error '%s'\n", | |
419 str); | |
420 res = DHR_FAILED; | |
421 } | |
422 } | |
423 delete[] str; | |
424 } | |
425 } | |
426 | |
427 debug_log_info("DebugHost::SetMemory returning %d\n", res); | |
428 return res; | |
429 } | |
430 | |
431 DebugHost::DHResult DebugHost::WaitForReply() { | |
432 DebugPacket inPkt; | |
433 while (true) { | |
434 DebugPipe::DPResult res = pipe_->GetPacket(&inPkt); | |
435 if (res == DebugPipe::DPR_NO_DATA) | |
436 continue; | |
437 | |
438 if (res == DebugPipe::DPR_OK) { | |
439 char cmd = 0; | |
440 //Find the command | |
441 inPkt.GetRawChar(&cmd); | |
442 debug_log_info("DebutHost::SendAndWaitForBreak cmd=%d\n", cmd); | |
443 switch(cmd) { | |
444 case 'W': | |
445 case 'S': | |
446 case 'T': | |
447 flags_.ClearFlag(DHF_RUNNING); | |
448 if (stopFunc_) { | |
449 debug_log_info("Calling stopFunc @ %s:%d\n", __FILE__, __LINE__); | |
450 stopFunc_(DHR_OK, stopObj_); | |
451 } | |
452 debug_log_info("Called stopFunc...returning DebugHost::DHR_OK(%d)\n", | |
453 DebugHost::DHR_OK); | |
454 return DebugHost::DHR_OK; | |
455 | |
456 case 'O': | |
457 if (outputFunc_) { | |
458 const char *str = 0; | |
459 if (inPkt.GetHexString(&str)) { | |
460 outputFunc_(DHR_OK, outputObj_, str); | |
461 free((void *) str); | |
462 } | |
463 } | |
464 continue; | |
465 | |
466 default: | |
467 return DebugHost::DHR_LOST; | |
468 } | |
469 } | |
470 return DebugHost::DHR_LOST; | |
471 } | |
472 return DHR_OK; | |
473 } | |
474 | |
475 DebugHost::DHResult DebugHost::SendAndWaitForBreak(const char* str, bool w) { | |
476 DebugPipe::DPResult res; | |
477 DebugPacket outPkt, inPkt; | |
478 | |
479 // Send CTRL-C for break signal | |
480 outPkt.Clear(); | |
481 outPkt.AddString(str); | |
482 | |
483 debug_log_info("DebugHost::SendAndWaitFor Break [%s] w=%d\n", str, w); | |
484 if (NULL == pipe_) | |
485 return DHR_LOST; | |
486 | |
487 res = pipe_->SendPacket(&outPkt); | |
488 if (res == DebugPipe::DPR_ERROR) | |
489 return DHR_LOST; | |
490 | |
491 if (res == DebugPipe::DPR_NO_DATA) | |
492 return DHR_TIMEOUT; | |
493 | |
494 if (w) | |
495 return WaitForReply(); | |
496 return DHR_OK; | |
497 } | |
498 | |
499 DebugHost::DHResult DebugHost::RequestContinue() { | |
500 debug_log_info("DebugHost::RequestContinue\n"); | |
501 | |
502 // When we send 'c', there will be a reply (e.g. "S05"), so | |
503 // we don't wait for it here, but wait in the worker thread. | |
504 flags_.SetFlag(DHF_RUNNING); | |
505 return SendAndWaitForBreak("c", false); | |
506 } | |
507 | |
508 DebugHost::DHResult DebugHost::RequestStep() { | |
509 debug_log_info("DebugHost::ReqeuestStep\n"); | |
510 return SendAndWaitForBreak("s", true); | |
511 } | |
512 | |
513 DebugHost::DHResult DebugHost::RequestBreak() { | |
514 debug_log_info("DebugHost::ReqeuestBreak\n"); | |
515 return SendAndWaitForBreak("\03", false); | |
516 } | |
517 | |
518 // ********************************************************* | |
519 // | |
520 // Breakpoint Functions | |
521 // | |
522 // ********************************************************* | |
523 bool DebugHost::HasBreakpoint(uint64_t offs) { | |
524 if (breaks_.count(offs)) { | |
525 debug_log_info("DebugHost::HasBreakpoint offs=0x%x breaks_.count=%d\n", | |
526 offs, breaks_.count(offs)); | |
527 return true; | |
528 } | |
529 debug_log_info("DebugHost::HasBreakpoint did NOT find offset=0x%x\n", offs); | |
530 return false; | |
531 } | |
532 | |
533 DebugHost::DHResult DebugHost::AddBreakpoint(uint64_t offs) { | |
534 char ch; | |
535 | |
536 debug_log_info("DebugHost::AddBreakpoint 0x%x\n", offs); | |
537 if (breaks_.count(offs)) | |
538 return DHR_OK; | |
539 | |
540 debug_log_info("DebugHost::AddBreakpoint getting memory for 0x%x\n", offs); | |
541 GetMemory(offs, &ch, 1); | |
542 debug_log_info("DebugHost::AddBreakpoint got char '%d'\n", (unsigned int) ch); | |
543 BreakpointRecord br = { | |
544 offs, | |
545 false, | |
546 false, | |
547 ch | |
548 }; | |
549 breaks_[offs] = br; | |
550 | |
551 EnableBreakpoint(offs); | |
552 return DHR_OK; | |
553 } | |
554 | |
555 DebugHost::DHResult DebugHost::EnableBreakpoint(uint64_t offs) { | |
556 // Check if we know about this breakpoint | |
557 if (breaks_.count(offs) == 0) | |
558 { | |
559 debug_log_warning("DebugHost::EnableBreakpoint Could not find BP 0x%x.\n", | |
560 offs); | |
561 return DHR_FAILED; | |
562 } | |
563 debug_log_warning("DebugHost::EnableBreakpoint enabling BP 0x%x.\n", offs); | |
564 breaks_[offs].enabled = true; | |
565 return BreakpointStatusChanged(offs); | |
566 } | |
567 | |
568 DebugHost::DHResult DebugHost::DisableBreakpoint(uint64_t offs) { | |
569 // Check if we know about this breakpoint | |
570 if (breaks_.count(offs) == 0) { | |
571 debug_log_info("DebugHost::DisableBreakpoint - did not find 0x%x\n", offs); | |
572 return DHR_FAILED; | |
573 } | |
574 debug_log_info("DebugHost::DisableBreakpoint - disabling 0x%x\n", offs); | |
575 breaks_[offs].enabled = false; | |
576 return BreakpointStatusChanged(offs); | |
577 } | |
578 | |
579 DebugHost::DHResult DebugHost::RemoveBreakpoint(uint64_t offs) { | |
580 if (breaks_.count(offs) == 0) { | |
581 debug_log_info("DebugHost::RemoveBreakpoint count 0x%x is 0," | |
582 " returning DHR_FAILED\n", offs); | |
583 return DHR_FAILED; | |
584 } | |
585 | |
586 debug_log_info("DebugHost::RemoveBreakpoint 0x%x," | |
587 " calling DisableBreakpoint\n", offs); | |
588 // Make sure to disable it just in case. | |
589 DisableBreakpoint(offs); | |
590 | |
591 breaks_.erase(offs); | |
592 debug_log_info("DebugHost::RemoveBreakpoint returning DHR_OK\n"); | |
593 return DHR_OK; | |
594 } | |
595 | |
596 DebugHost::DHResult nacl_debug_conn::DebugHost::SuspendBreakpoint( uint64_t offs
) | |
597 { | |
598 // Check if we know about this breakpoint | |
599 if (breaks_.count(offs) == 0) { | |
600 debug_log_warning("DebugHost::SuspendBreakpoint: Did not find BP 0x%x.\n", | |
601 offs); | |
602 return DHR_FAILED; | |
603 } | |
604 | |
605 debug_log_warning("DebugHost::SuspendBreakpoint: suspending 0x%x.\n", offs); | |
606 breaks_[offs].suspended = true; | |
607 return BreakpointStatusChanged(offs); | |
608 } | |
609 | |
610 DebugHost::DHResult nacl_debug_conn::DebugHost::ResumeBreakpoint( uint64_t offs
) | |
611 { | |
612 // Check if we know about this breakpoint | |
613 if (breaks_.count(offs) == 0) { | |
614 debug_log_warning("DebugHost::ResumeBreakpoint Could not find BP 0x%x.\n", | |
615 offs); | |
616 return DHR_FAILED; | |
617 } | |
618 debug_log_warning("DebugHost::ResumeBreakpoint resuming BP 0x%x.\n", offs); | |
619 breaks_[offs].suspended = false; | |
620 return BreakpointStatusChanged(offs); | |
621 } | |
622 | |
623 nacl_debug_conn::DebugHost::DHResult nacl_debug_conn::DebugHost::BreakpointStatu
sChanged( uint64_t offs ) | |
624 { | |
625 if (breaks_.count(offs) == 0) { | |
626 debug_log_warning("DebugHost::BreakpointStatusChanged" | |
627 "Could not find BP 0x%x.\n", offs); | |
628 return DHR_FAILED; | |
629 } | |
630 debug_log_warning("DebugHost::Breakpoint status changed 0x%x.\n", offs); | |
631 BreakpointRecord br = breaks_[offs]; | |
632 | |
633 // if breakpoint is enabled and not suspended, write a 0xCC byte. Otherwise, | |
634 // restore the original memory. Both of these operations are idempotent, so | |
635 // we're not concerned about the breakpoint's previous status. | |
636 if (br.enabled && !br.suspended) { | |
637 unsigned char ch = 0xCC; | |
638 debug_log_warning("conn::DebugHost::BreakpointStatusChanged enabled" | |
639 " && !suspended - setting 0xCC\n"); | |
640 return SetMemory(offs, &ch, 1); | |
641 } else { | |
642 char ch = breaks_[offs].previousContents; | |
643 debug_log_warning("conn::DebugHost::BreakpointStatusChanged setting" | |
644 " %c to memory\n", ch); | |
645 return SetMemory(offs, &ch, 1); | |
646 } | |
647 } | |
648 | |
649 bool DebugHost::IsRunning() { | |
650 debug_log_info("DebugHost::IsRunning"); | |
651 return flags_.GetFlags() & DHF_RUNNING; | |
652 } | |
653 | |
654 void DebugHost::SetOutputAsync(DHAsyncStr reply, void *obj) { | |
655 outputFunc_ = reply; | |
656 outputObj_ = obj; | |
657 } | |
658 | |
659 void DebugHost::SetStopAsync(DHAsync reply, void *obj) { | |
660 debug_log_info("DebugHost::SetStopAsync stopFunc=%p obj=%p\n", reply, obj); | |
661 stopFunc_ = reply; | |
662 stopObj_ = obj; | |
663 } | |
664 | |
665 DebugHost::DHResult DebugHost::RequestStepBackground() { | |
666 DebugPipe::DPResult res; | |
667 DebugPacket outPkt; | |
668 | |
669 debug_log_info("DebugHost::RequestStepBackground"); | |
670 if (NULL == pipe_) | |
671 return DHR_LOST; | |
672 | |
673 outPkt.AddString("s"); | |
674 | |
675 // Turn off sequences for out of sequence requests | |
676 uint32_t flags = pipe_->GetFlagsMasked(DebugPipe::DPF_USE_SEQ); | |
677 pipe_->SetFlagsMasked(0, DebugPipe::DPF_USE_SEQ); | |
678 res = pipe_->SendPacket(&outPkt); | |
679 pipe_->SetFlagsMasked(flags, DebugPipe::DPF_USE_SEQ); | |
680 | |
681 if (res == DebugPipe::DPR_ERROR) | |
682 return DHR_LOST; | |
683 | |
684 if (res == DebugPipe::DPR_NO_DATA) | |
685 return DHR_TIMEOUT; | |
686 | |
687 return DHR_OK; | |
688 } | |
689 | |
OLD | NEW |