OLD | NEW |
| (Empty) |
1 #include "debugger/debug_server/debug_server.h" | |
2 #include <assert.h> | |
3 #include <algorithm> | |
4 #include "debugger/core/debuggee_thread.h" | |
5 #include "debugger/core/debuggee_process.h" | |
6 #include "debugger/rsp/rsp_packet.h" | |
7 #include "debugger/core/debug_logger.h" | |
8 | |
9 namespace { | |
10 const int kReadBufferSize = 1024; | |
11 const int kVS2008_THREAD_INFO = 0x406D1388; | |
12 | |
13 void MakeContinueDecision( | |
14 const debug::DebugEvent& debug_event, | |
15 debug::DebuggeeThread* thread, | |
16 bool* halt, | |
17 bool* pass_exception); | |
18 rsp::StopReply GetStopReply( | |
19 debug::IDebuggeeProcess* halted_process); | |
20 int GetSignalNumber(const debug::DebugEvent& debug_event); | |
21 | |
22 bool ExitedNormally(int ret_code) { | |
23 return ((ret_code >=0) && (ret_code < 256)); | |
24 } | |
25 void PrintCONTEXT(const CONTEXT& ct); | |
26 } // namespace | |
27 | |
28 namespace debug { | |
29 DebugServer::DebugServer() | |
30 : connection_was_established_(false), | |
31 focused_process_id_(0), | |
32 focused_thread_id_(0), | |
33 main_nexe_thread_id_(0) { | |
34 rsp_packetizer_.SetPacketConsumer(this); | |
35 execution_engine_ = new ExecutionEngine(&debug_api_); | |
36 | |
37 #ifdef COMN_LOG | |
38 logger_ = Logger::Get(); | |
39 #else | |
40 debug::TextFileLogger* log = new debug::TextFileLogger(); | |
41 log->Open("nacl_gdbserver_log.txt"); | |
42 log->EnableStdout(true); | |
43 logger_ = log; | |
44 #endif | |
45 } | |
46 | |
47 DebugServer::~DebugServer() { | |
48 delete execution_engine_; | |
49 } | |
50 | |
51 bool DebugServer::ListenOnPort(int port) { | |
52 bool res = listening_socket_.Listen(port); | |
53 if (res) | |
54 logger_->Log("TR100.1", "Started listening on port %d ...\n", port); | |
55 return res; | |
56 } | |
57 | |
58 bool DebugServer::StartProcess(const char* cmd, const char* work_dir) { | |
59 bool res = execution_engine_->StartProcess(cmd, work_dir); | |
60 if (res) | |
61 logger_->Log("TR100.2", "Starting process [%s]...\n", cmd); | |
62 return res; | |
63 } | |
64 | |
65 void DebugServer::DoWork(int wait_ms) { | |
66 if (!debugger_connection_.IsConnected()) { | |
67 if (connection_was_established_) { | |
68 connection_was_established_ = false; | |
69 logger_->Log("TR100.3", "Dropped connection from debugger.\n"); | |
70 } | |
71 if (listening_socket_.Accept(&debugger_connection_, 0)) { | |
72 connection_was_established_ = true; | |
73 logger_->Log("TR100.4", "Got connection from debugger.\n"); | |
74 } | |
75 } else { | |
76 char buff[kReadBufferSize]; | |
77 for (int i = 0; i < 100; i++) { | |
78 size_t read_bytes = debugger_connection_.Read(buff, | |
79 sizeof(buff) - 1, | |
80 0); | |
81 if (read_bytes > 0) { | |
82 buff[read_bytes] = 0; | |
83 logger_->Log("R>", "[%s]\n", buff); | |
84 if (strncmp(buff, "+$Xc000206", 10) == 0) | |
85 printf(""); | |
86 | |
87 rsp_packetizer_.OnData(buff, read_bytes); | |
88 } else { | |
89 break; | |
90 } | |
91 } | |
92 } | |
93 int pid = 0; | |
94 execution_engine_->WaitForDebugEventAndDispatchIt(wait_ms, &pid); | |
95 IDebuggeeProcess* halted_process = execution_engine_->GetProcess(pid); | |
96 if (NULL != halted_process) { | |
97 if (debug::DebugEvent::kThreadIsAboutToStart == | |
98 execution_engine_->debug_event().nacl_debug_event_code()) { | |
99 DebuggeeThread* thread = halted_process->GetHaltedThread(); | |
100 if ((NULL != thread) && thread->IsNaClAppThread()) | |
101 logger_->Log("TR100.5", | |
102 "NaClThreadStart mem_base=%p entry_point=%p thread_id=%d\n", | |
103 halted_process->nexe_mem_base(), | |
104 halted_process->nexe_entry_point(), | |
105 thread->id()); | |
106 } | |
107 | |
108 bool halt = false; | |
109 bool pass_exception = true; | |
110 MakeContinueDecision(execution_engine_->debug_event(), | |
111 halted_process->GetHaltedThread(), | |
112 &halt, | |
113 &pass_exception); | |
114 if (halt) | |
115 OnHaltedProcess(halted_process, execution_engine_->debug_event()); | |
116 else if (pass_exception) | |
117 halted_process->ContinueAndPassExceptionToDebuggee(); | |
118 else | |
119 halted_process->Continue(); | |
120 } | |
121 } | |
122 | |
123 void DebugServer::Quit() { | |
124 execution_engine_->Stop(300); | |
125 listening_socket_.Close(); | |
126 debugger_connection_.Close(); | |
127 } | |
128 | |
129 void DebugServer::OnHaltedProcess(IDebuggeeProcess* halted_process, | |
130 const DebugEvent& debug_event) { | |
131 char tmp[1000]; | |
132 debug_event.ToString(tmp, sizeof(tmp)); | |
133 logger_->Log("TR100.6", | |
134 "Halted: pid=%d tid=%d\ndebugevent=%s\n", | |
135 halted_process->id(), | |
136 halted_process->GetHaltedThread()->id(), | |
137 tmp); | |
138 | |
139 assert(halted_process->GetHaltedThread()->IsNaClAppThread()); | |
140 | |
141 // TODO: cleanup | |
142 CONTEXT ct; | |
143 halted_process->GetHaltedThread()->GetContext(&ct); | |
144 PrintCONTEXT(ct); | |
145 | |
146 if (0 == main_nexe_thread_id_) { | |
147 focused_process_id_ = halted_process->id(); | |
148 main_nexe_thread_id_ = focused_thread_id_; | |
149 } | |
150 focused_thread_id_ = halted_process->GetHaltedThread()->id(); | |
151 | |
152 if (debugger_connection_.IsConnected()) | |
153 PostRspMessage(GetStopReply(halted_process)); | |
154 } | |
155 | |
156 void DebugServer::PostRspMessage(const rsp::Packet& msg) { | |
157 Blob text; | |
158 msg.ToBlob(&text); | |
159 Blob wire_msg; | |
160 rsp::PacketUtil::AddEnvelope(text, &wire_msg); | |
161 debugger_connection_.WriteAll(wire_msg); | |
162 logger_->Log("T>", "[%s]\n", text.ToString().c_str()); | |
163 } | |
164 | |
165 void DebugServer::OnUnknownCommand() { | |
166 PostRspMessage(rsp::EmptyPacket()); | |
167 } | |
168 | |
169 void DebugServer::OnPacket(const Blob& body, bool valid_checksum) { | |
170 if (valid_checksum) | |
171 debugger_connection_.WriteAll("+"); | |
172 | |
173 Blob msg = body; | |
174 rsp::Packet* command = rsp::Packet::CreateFromBlob(&msg); | |
175 if (NULL != command) { | |
176 command->AcceptVisitor(this); | |
177 delete command; | |
178 } else { | |
179 PostRspMessage(rsp::EmptyPacket()); | |
180 } | |
181 } | |
182 | |
183 void DebugServer::OnUnexpectedChar(char unexpected_char) { | |
184 logger_->Log("WARN21.01", "msg='DebugServer::OnUnexpectedChar' c='0x%x'", stat
ic_cast<int>(unexpected_char)); | |
185 } | |
186 | |
187 void DebugServer::OnBreak() { | |
188 if (0 != focused_process_id_) { | |
189 //TODO : implement | |
190 OnUnknownCommand(); | |
191 } else { | |
192 PostRspMessage(rsp::ErrorReply(1)); | |
193 } | |
194 } | |
195 | |
196 void DebugServer::Visit(rsp::GetStopReasonCommand* packet) { | |
197 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
198 if (NULL == proc) { | |
199 PostRspMessage(rsp::ErrorReply(2)); | |
200 return; | |
201 } | |
202 DebugEvent debug_event = proc->last_debug_event(); | |
203 DEBUG_EVENT wde = debug_event.windows_debug_event(); | |
204 if (wde.dwDebugEventCode == EXIT_THREAD_DEBUG_EVENT) { | |
205 if (wde.dwThreadId == main_nexe_thread_id_) { | |
206 int ret_code = wde.u.ExitThread.dwExitCode; | |
207 if (ExitedNormally(ret_code)) { | |
208 rsp::StopReply reply(rsp::StopReply::EXITED); | |
209 reply.set_exit_code(ret_code); | |
210 PostRspMessage(reply); | |
211 } else { | |
212 rsp::StopReply reply(rsp::StopReply::TERMINATED); | |
213 reply.set_signal_number(ret_code); | |
214 PostRspMessage(reply); | |
215 } | |
216 return; | |
217 } | |
218 } | |
219 if (proc->IsHalted()) | |
220 PostRspMessage(GetStopReply(proc)); | |
221 else if (DebuggeeProcess::kDead == proc->state()) | |
222 PostRspMessage(rsp::ErrorReply(5)); | |
223 else // Process is running. | |
224 PostRspMessage(rsp::StopReply(rsp::StopReply::STILL_RUNNING)); | |
225 } | |
226 | |
227 void DebugServer::Visit(rsp::ContinueCommand* packet) { | |
228 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
229 if (NULL == proc) | |
230 PostRspMessage(rsp::ErrorReply(4)); | |
231 else | |
232 proc->Continue(); | |
233 } | |
234 | |
235 void DebugServer::Visit(rsp::QuerySupportedCommand* packet) { | |
236 rsp::QuerySupportedReply reply; | |
237 reply.AddFeature("PacketSize", "7cf"); | |
238 reply.AddFeature("qXfer:libraries:read", "+"); | |
239 reply.AddFeature("qXfer:features:read", "+"); | |
240 PostRspMessage(reply); | |
241 } | |
242 | |
243 void DebugServer::Visit(rsp::QXferFeaturesReadCommand* packet) { | |
244 //qXfer:features:read:target.xml:0,7ca | |
245 if (packet->file_name() == "target.xml") { | |
246 rsp::QXferReply reply; | |
247 reply.set_body("<target><architecture>i386:x86-64</architecture></target>"); | |
248 reply.set_eom(true); | |
249 PostRspMessage(reply); | |
250 } else { | |
251 OnUnknownCommand(); | |
252 } | |
253 } | |
254 | |
255 void DebugServer::Visit(rsp::SetCurrentThreadCommand* packet) { | |
256 int tid = static_cast<int>(packet->thread_id()); | |
257 bool res = false; | |
258 if (-1 == tid) { // all threads | |
259 res = false; | |
260 } else if (0 == tid) { // any thread | |
261 res = true; | |
262 } else { | |
263 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
264 if (NULL != proc) { | |
265 DebuggeeThread* thread = proc->GetThread(tid); | |
266 if (NULL != thread) { | |
267 res = true; | |
268 focused_thread_id_ = tid; | |
269 } | |
270 } | |
271 } | |
272 if (res) | |
273 PostRspMessage(rsp::OkReply()); | |
274 else | |
275 PostRspMessage(rsp::ErrorReply(3)); | |
276 } | |
277 | |
278 void DebugServer::Visit(rsp::ReadMemoryCommand* packet) { | |
279 int sz = packet->num_of_bytes(); | |
280 if (0 == sz) { | |
281 PostRspMessage(rsp::ErrorReply(4)); | |
282 return; | |
283 } | |
284 // We advertize max size of RSP packet as 1999 | |
285 char buff[3000]; | |
286 if (sizeof(buff) < sz) { | |
287 PostRspMessage(rsp::ErrorReply(5)); | |
288 return; | |
289 } | |
290 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
291 if (NULL != proc) { | |
292 char* addr = reinterpret_cast<char*>(packet->addr()); | |
293 // massage address to support gdb | |
294 if (addr < proc->nexe_mem_base()) | |
295 addr += reinterpret_cast<size_t>(proc->nexe_mem_base()); | |
296 | |
297 if (proc->ReadMemory(addr, sz, buff)) { | |
298 rsp::BlobReply reply; | |
299 reply.set_data(buff, sz); | |
300 PostRspMessage(reply); | |
301 } else { | |
302 PostRspMessage(rsp::ErrorReply(6)); | |
303 } | |
304 } else { | |
305 PostRspMessage(rsp::ErrorReply(7)); | |
306 } | |
307 } | |
308 | |
309 void DebugServer::Visit(rsp::WriteMemoryCommand* packet) { | |
310 const debug::Blob& data = packet->data(); | |
311 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
312 if (NULL != proc) { | |
313 void* tmp = data.ToCBuffer(); | |
314 if (NULL == tmp) { | |
315 PostRspMessage(rsp::ErrorReply(8)); | |
316 return; | |
317 } | |
318 | |
319 char* addr = reinterpret_cast<char*>(packet->addr()); | |
320 // massage address to support gdb | |
321 if (addr < proc->nexe_mem_base()) | |
322 addr += reinterpret_cast<size_t>(proc->nexe_mem_base()); | |
323 | |
324 bool res = proc->WriteMemory(addr, data.size(), tmp); | |
325 free(tmp); | |
326 if (res) | |
327 PostRspMessage(rsp::OkReply()); | |
328 else | |
329 PostRspMessage(rsp::ErrorReply(9)); | |
330 } else { | |
331 logger_->Log("WARN21.02", "Can't find process pid=%d", focused_process_id_); | |
332 PostRspMessage(rsp::ErrorReply(10)); | |
333 } | |
334 } | |
335 | |
336 void DebugServer::Visit(rsp::ReadRegistersCommand* packet) { | |
337 Blob registers_blob; | |
338 if (ReadGdbRegisters(®isters_blob)) { | |
339 rsp::BlobReply reply; | |
340 reply.set_data(registers_blob); | |
341 PostRspMessage(reply); | |
342 } else { | |
343 logger_->Log("WARN21.03", "DebugServer::ReadGdbRegisters pid=%d tid=%d -> fa
lse", focused_process_id_, focused_thread_id_); | |
344 PostRspMessage(rsp::ErrorReply(113)); | |
345 } | |
346 } | |
347 | |
348 void DebugServer::Visit(rsp::WriteRegistersCommand* packet) { | |
349 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
350 if (NULL == proc) { | |
351 PostRspMessage(rsp::ErrorReply(14)); | |
352 return; | |
353 } | |
354 DebuggeeThread* thread = proc->GetThread(focused_thread_id_); | |
355 if (NULL == thread) { | |
356 PostRspMessage(rsp::ErrorReply(15)); | |
357 return; | |
358 } | |
359 CONTEXT ct; | |
360 if (!thread->GetContext(&ct)) { | |
361 PostRspMessage(rsp::ErrorReply(16)); | |
362 return; | |
363 } | |
364 GdbRegistersToCONTEXT(packet->data(), &ct); | |
365 if (!thread->SetContext(ct)) | |
366 PostRspMessage(rsp::ErrorReply(16)); | |
367 else | |
368 PostRspMessage(rsp::OkReply()); | |
369 } | |
370 | |
371 #define X86_32_REGS \ | |
372 REG(Eax); \ | |
373 REG(Ecx); \ | |
374 REG(Edx); \ | |
375 REG(Ebx); \ | |
376 REG(Esp); \ | |
377 REG(Ebp); \ | |
378 REG(Esi); \ | |
379 REG(Edi); \ | |
380 REG(Eip); \ | |
381 REG(EFlags); \ | |
382 REG(SegCs); \ | |
383 REG(SegSs); \ | |
384 REG(SegDs); \ | |
385 REG(SegEs); \ | |
386 REG(SegFs); \ | |
387 REG(SegGs) | |
388 | |
389 #define X86_64_REGS \ | |
390 REG(Rax); \ | |
391 REG(Rbx); \ | |
392 REG(Rcx); \ | |
393 REG(Rdx); \ | |
394 REG(Rsi); \ | |
395 REG(Rdi); \ | |
396 REG(Rbp); \ | |
397 REG(Rsp); \ | |
398 REG(R8); \ | |
399 REG(R9); \ | |
400 REG(R10); \ | |
401 REG(R11); \ | |
402 REG(R12); \ | |
403 REG(R13); \ | |
404 REG(R14); \ | |
405 REG(R15); \ | |
406 REG(Rip); \ | |
407 REG(EFlags); \ | |
408 REG(SegCs); \ | |
409 REG(SegSs); \ | |
410 REG(SegDs); \ | |
411 REG(SegEs); \ | |
412 REG(SegFs); \ | |
413 REG(SegGs) | |
414 | |
415 char* names_of_bad_regs = "EFlags,SegCs,SegSs,SegDs,SegEs,SegFs,SegGs,"; | |
416 | |
417 size_t WriteReg(const Blob& blob, size_t offset, void* dst, int reg_size, const
char* name) { | |
418 char* pp = strstr(names_of_bad_regs,name); | |
419 size_t name_len = strlen(name); | |
420 if ((NULL != pp) && (',' == *(pp + name_len))) { | |
421 unsigned long reg = 0; | |
422 reg_size = sizeof(reg); | |
423 blob.Peek(offset, ®, sizeof(reg)); | |
424 memcpy(dst, ®, 2); | |
425 } else { | |
426 blob.Peek(offset, dst, reg_size); | |
427 } | |
428 return offset + reg_size; | |
429 } | |
430 | |
431 void DebugServer::GdbRegistersToCONTEXT(const Blob& gdb_regs, CONTEXT* ct) { | |
432 size_t offset = 0; | |
433 #define REG(name) ct->name = 0; offset = WriteReg(gdb_regs, offset, &ct->name, s
izeof(ct->name), #name) | |
434 #ifdef _WIN64 | |
435 X86_64_REGS; | |
436 #else | |
437 X86_32_REGS; | |
438 #endif | |
439 #undef REG | |
440 } | |
441 | |
442 void ReadReg(Blob* blob, void* src, int reg_size, const char* name) { | |
443 char* pp = strstr(names_of_bad_regs,name); | |
444 size_t name_len = strlen(name); | |
445 if ((NULL != pp) && (',' == *(pp + name_len))) { | |
446 unsigned long reg = 0; | |
447 memcpy(®, src, 2); | |
448 blob->Append(Blob(®, sizeof(reg))); | |
449 } else { | |
450 blob->Append(Blob(src, reg_size)); | |
451 } | |
452 } | |
453 | |
454 bool DebugServer::ReadGdbRegisters(Blob* blob) { | |
455 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
456 if (NULL == proc) { | |
457 logger_->Log("WARN21.05", "Can't find process pid=%d", focused_process_id_); | |
458 return false; | |
459 } | |
460 | |
461 DebuggeeThread* thread = proc->GetThread(focused_thread_id_); | |
462 if (NULL == thread) { | |
463 logger_->Log("WARN21.06", "Can't find thread pid=%d tid=%d", focused_process
_id_, focused_thread_id_); | |
464 return false; | |
465 } | |
466 | |
467 CONTEXT ct; | |
468 if (!thread->GetContext(&ct)) { | |
469 logger_->Log("WARN21.07", "thread->GetContext failed. pid=%d tid=%d", focuse
d_process_id_, focused_thread_id_); | |
470 return false; | |
471 } | |
472 | |
473 #define REG(name) ReadReg(blob, &ct.name, sizeof(ct.name), #name) | |
474 #ifdef _WIN64 | |
475 X86_64_REGS; | |
476 #else | |
477 X86_32_REGS; | |
478 #endif | |
479 #undef REG | |
480 | |
481 logger_->Log("TRACE21.08", "DebugServer::ReadGdbRegisters pid=%d tid=%d -> tru
e", focused_process_id_, focused_thread_id_); | |
482 return true; | |
483 } | |
484 | |
485 void DebugServer::Visit(rsp::GetCurrentThreadCommand* packet) { | |
486 rsp::GetCurrentThreadReply reply; | |
487 reply.set_value(focused_thread_id_); | |
488 PostRspMessage(reply); | |
489 } | |
490 | |
491 void DebugServer::Visit(rsp::StepCommand* packet) { | |
492 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
493 if (NULL == proc) | |
494 PostRspMessage(rsp::ErrorReply(20)); | |
495 else if (!proc->SingleStep()) | |
496 PostRspMessage(rsp::ErrorReply(21)); | |
497 } | |
498 | |
499 void DebugServer::Visit(rsp::IsThreadAliveCommand* packet) { | |
500 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
501 if (NULL == proc) { | |
502 PostRspMessage(rsp::ErrorReply(22)); | |
503 return; | |
504 } | |
505 std::deque<int> tids; | |
506 proc->GetThreadIds(&tids); | |
507 if (std::find(tids.begin(), tids.end(), packet->value()) != tids.end()) { | |
508 PostRspMessage(rsp::OkReply()); | |
509 // found it | |
510 } else { | |
511 PostRspMessage(rsp::ErrorReply(23)); // TODO: make error codes declared con
stants | |
512 } | |
513 } | |
514 | |
515 void DebugServer::Visit(rsp::GetThreadInfoCommand* packet) { | |
516 IDebuggeeProcess* proc = execution_engine_->GetProcess(focused_process_id_); | |
517 if (NULL == proc) { | |
518 PostRspMessage(rsp::ErrorReply(24)); | |
519 return; | |
520 } | |
521 rsp::GetThreadInfoReply reply; | |
522 if (packet->get_more()) { | |
523 reply.set_eom(true); // TODO(garianov): add support for multy packet replie
s. | |
524 } else { | |
525 std::deque<int> tids; | |
526 proc->GetThreadIds(&tids); | |
527 | |
528 std::deque<int> nexe_tids; | |
529 for (size_t i = 0; i < tids.size(); i++) { | |
530 int tid = tids[i]; | |
531 DebuggeeThread* thread = proc->GetThread(tid); | |
532 if ((NULL != thread) && (thread->IsNaClAppThread())) | |
533 nexe_tids.push_back(tid); | |
534 } | |
535 reply.set_threads_ids(nexe_tids); | |
536 reply.set_eom(false); | |
537 } | |
538 PostRspMessage(reply); | |
539 } | |
540 | |
541 } // namespace debug | |
542 | |
543 namespace { | |
544 void MakeContinueDecision( | |
545 const debug::DebugEvent& debug_event, | |
546 debug::DebuggeeThread* thread, | |
547 bool* halt, | |
548 bool* pass_exception) { | |
549 if (OUTPUT_DEBUG_STRING_EVENT == debug_event.windows_debug_event().dwDebugEven
tCode) { | |
550 *halt = false; | |
551 *pass_exception = false; | |
552 } | |
553 | |
554 if (debug::DebugEvent::kNotNaClDebugEvent != debug_event.nacl_debug_event_code
()) { | |
555 *halt = true; | |
556 return; | |
557 } | |
558 int exception_code = debug_event.windows_debug_event().u.Exception.ExceptionRe
cord.ExceptionCode; | |
559 | |
560 if (EXCEPTION_DEBUG_EVENT == debug_event.windows_debug_event().dwDebugEventCod
e) { | |
561 if (kVS2008_THREAD_INFO == exception_code) { | |
562 *halt = false; | |
563 } else { | |
564 bool is_nexe = false; | |
565 if (NULL != thread) | |
566 is_nexe = thread->IsNaClAppThread(); | |
567 | |
568 if (is_nexe) | |
569 printf(""); | |
570 | |
571 *pass_exception = true; | |
572 | |
573 if (EXCEPTION_BREAKPOINT == exception_code) | |
574 *pass_exception = false; | |
575 | |
576 if (is_nexe) { | |
577 *halt = true; | |
578 } else { | |
579 *halt = false; | |
580 } | |
581 } | |
582 } | |
583 } | |
584 | |
585 rsp::StopReply GetStopReply(debug::IDebuggeeProcess* halted_process) { | |
586 debug::DebugEvent debug_event = halted_process->last_debug_event(); | |
587 DEBUG_EVENT wde = debug_event.windows_debug_event(); | |
588 | |
589 int exception_code = wde.u.Exception.ExceptionRecord.ExceptionCode; | |
590 switch (wde.dwDebugEventCode) { | |
591 case CREATE_PROCESS_DEBUG_EVENT: | |
592 case CREATE_THREAD_DEBUG_EVENT: | |
593 case EXCEPTION_DEBUG_EVENT: | |
594 case LOAD_DLL_DEBUG_EVENT: | |
595 case OUTPUT_DEBUG_STRING_EVENT: | |
596 case EXIT_THREAD_DEBUG_EVENT: | |
597 case UNLOAD_DLL_DEBUG_EVENT: { | |
598 rsp::StopReply reply(rsp::StopReply::SIGNALED); | |
599 reply.set_signal_number(GetSignalNumber(debug_event)); | |
600 return reply; | |
601 } | |
602 case RIP_EVENT: { | |
603 rsp::StopReply reply(rsp::StopReply::TERMINATED); | |
604 reply.set_signal_number(GetSignalNumber(debug_event)); | |
605 return reply; | |
606 } | |
607 case EXIT_PROCESS_DEBUG_EVENT: { | |
608 // NaClAppThread terminated or exited: | |
609 int ret_code = wde.u.ExitThread.dwExitCode; | |
610 if (ExitedNormally(ret_code)) { | |
611 rsp::StopReply reply(rsp::StopReply::EXITED); | |
612 reply.set_exit_code(ret_code); | |
613 return reply; | |
614 } else { | |
615 rsp::StopReply reply(rsp::StopReply::TERMINATED); | |
616 reply.set_signal_number(ret_code); | |
617 return reply; | |
618 } | |
619 } | |
620 } | |
621 return rsp::StopReply::SIGNALED; | |
622 } | |
623 | |
624 int GetSignalNumber(const debug::DebugEvent& debug_event) { | |
625 const int SIGSEGV = 11; | |
626 const int SIGSYS = 31; | |
627 const int SIGTRAP = 5; | |
628 const int SIGBUS = 7; | |
629 const int SIGFPE = 8; | |
630 const int SIGILL = 4; | |
631 const int SIGINT = 2; | |
632 const int SIGSTOP = 19; | |
633 | |
634 switch (debug_event.windows_debug_event().dwDebugEventCode) { | |
635 case CREATE_PROCESS_DEBUG_EVENT: | |
636 case CREATE_THREAD_DEBUG_EVENT: | |
637 case LOAD_DLL_DEBUG_EVENT: | |
638 case OUTPUT_DEBUG_STRING_EVENT: | |
639 case UNLOAD_DLL_DEBUG_EVENT: | |
640 case EXIT_THREAD_DEBUG_EVENT: | |
641 case EXIT_PROCESS_DEBUG_EVENT: | |
642 return SIGSTOP; | |
643 | |
644 case EXCEPTION_DEBUG_EVENT: { | |
645 switch (debug_event.windows_debug_event().u.Exception.ExceptionRecord.Exce
ptionCode) { | |
646 case EXCEPTION_ACCESS_VIOLATION: | |
647 case EXCEPTION_STACK_OVERFLOW: | |
648 return SIGSEGV; | |
649 case EXCEPTION_BREAKPOINT: | |
650 case EXCEPTION_SINGLE_STEP: | |
651 return SIGTRAP; | |
652 | |
653 case EXCEPTION_DATATYPE_MISALIGNMENT: return SIGBUS; | |
654 | |
655 case EXCEPTION_FLT_DENORMAL_OPERAND: | |
656 case EXCEPTION_FLT_DIVIDE_BY_ZERO: | |
657 case EXCEPTION_FLT_INEXACT_RESULT: | |
658 case EXCEPTION_FLT_INVALID_OPERATION: | |
659 case EXCEPTION_FLT_OVERFLOW: | |
660 case EXCEPTION_FLT_STACK_CHECK: | |
661 case EXCEPTION_FLT_UNDERFLOW: | |
662 case EXCEPTION_INT_DIVIDE_BY_ZERO: | |
663 case EXCEPTION_INT_OVERFLOW: | |
664 return SIGFPE; | |
665 | |
666 case EXCEPTION_ILLEGAL_INSTRUCTION: | |
667 case EXCEPTION_PRIV_INSTRUCTION: | |
668 return SIGILL; | |
669 case DBG_CONTROL_C: return SIGINT; | |
670 } | |
671 } | |
672 } | |
673 return SIGSYS; | |
674 } | |
675 | |
676 void PrintCONTEXT(const CONTEXT& ct) { | |
677 printf("CONTEXT = {\n"); | |
678 #define REG(name) printf("\t%s=0x%x\n", #name, ct.name) | |
679 #ifdef _WIN64 | |
680 X86_64_REGS; | |
681 #else | |
682 X86_32_REGS; | |
683 #endif | |
684 #undef REG | |
685 printf("}\n"); | |
686 } | |
687 | |
688 } // namespace | |
OLD | NEW |