OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 #include "debug_api_linux.h" | |
5 | |
6 #include <errno.h> | |
7 #include <memory.h> | |
8 #include <signal.h> | |
9 #include <stdio.h> | |
10 #include <stdlib.h> | |
11 #include <sys/syscall.h> | |
12 #include <sys/types.h> | |
13 #include <sys/user.h> | |
14 #include <sys/wait.h> | |
15 #include <unistd.h> | |
16 | |
17 #include <deque> | |
18 #include <string> | |
19 | |
20 typedef int64_t ptrace_result_t; | |
21 | |
22 void Split(const char* str_in, | |
23 const char* delimiters, | |
24 std::deque<std::string>* out) { | |
25 char c = 0; | |
26 std::string str; | |
27 while (c = *str_in++) { | |
28 if (strchr(delimiters, c)) { | |
29 if (str.size()) { | |
30 out->push_back(str); | |
31 str.clear(); | |
32 } | |
33 } else if ((c != '\r') && (c != '\n')) { | |
34 str.push_back(c); | |
35 } | |
36 } | |
37 if (str.size()) | |
38 out->push_back(str); | |
39 } | |
40 | |
41 std::string GetAppPathOutOfCmdLine(const char* cmd_line) { | |
42 std::deque<std::string> words; | |
43 Split(cmd_line, " \t", &words); | |
44 if (words.size() > 0) | |
45 return words[0]; | |
46 return cmd_line; | |
47 } | |
48 | |
49 std::string GetAppNameOutOfCmdLine(const char* cmd_line) { | |
50 std::string path = GetAppPathOutOfCmdLine(cmd_line); | |
51 std::deque<std::string> words; | |
52 Split(path.c_str(), "/", &words); | |
53 if (words.size() > 0) | |
54 return words[words.size() - 1]; | |
55 return cmd_line; | |
56 } | |
57 | |
58 namespace { | |
59 const int kOutputDebugStringSignal = SIGUSR1; | |
60 const int kOutputDebugStringSize = 4 * 1024; | |
61 } // namespace | |
62 | |
63 namespace debug { | |
64 bool DebugApi::PostASignal(pid_t pid, int signo, int sig_value) { | |
65 sigval val; | |
66 val.sival_int = sig_value; | |
67 return (0 == sigqueue(pid, signo, val)); | |
68 } | |
69 | |
70 bool DebugApi::PostASignal(pid_t pid, int signo, void* sig_value) { | |
71 sigval val; | |
72 val.sival_ptr = sig_value; | |
73 return (0 == sigqueue(pid, signo, val)); | |
74 } | |
75 | |
76 bool DebugApi::ReadDebugString(DebugEvent* de, std::string* string) { | |
77 if (DebugEvent::OUTPUT_DEBUG_STRING != de->event_code_) | |
78 return false; | |
79 | |
80 char buff[kOutputDebugStringSize + 1]; | |
81 memset(buff, 'c', sizeof(buff)); | |
82 void* addr = reinterpret_cast<void*>(de->signal_value_.sival_ptr); | |
83 size_t readed_bytes = 0; | |
84 bool res = ReadProcessMemory(de->process_id_, | |
85 addr, | |
86 buff, | |
87 sizeof(buff) - 1, | |
88 &readed_bytes); | |
89 // printf("ReadProcessMemory->%s readed_bytes = %d\n", | |
90 // res ? "ok" : "err", (int)readed_bytes); | |
91 if (0 == readed_bytes) | |
92 return false; | |
93 | |
94 buff[readed_bytes] = 0; | |
95 if (NULL != string) | |
96 *string = buff; | |
97 return true; | |
98 } | |
99 | |
100 bool DebugApi::ContinueDebugEvent(pid_t process_id, int signo) { | |
101 ptrace_result_t res = ptrace(PTRACE_CONT, process_id, 0, signo); | |
102 // printf("ptrace(PTRACE_CONT(pid=%d signo=%d) -> %ld\n", | |
103 // process_id, signo, res); | |
104 return (0 == res); | |
105 } | |
106 | |
107 bool DebugApi::GetNewChildPid(pid_t pid, pid_t* child_pid_out) { | |
108 // PTRACE_GETEVENTMSG | |
109 // TODO(garianov): implement | |
110 ptrace_result_t res = ptrace(PTRACE_GETEVENTMSG, pid, 0, 0); | |
111 return (0 == res); | |
112 } | |
113 | |
114 bool DebugApi::StartProcess(const char* cmd_line, | |
115 bool trace, | |
116 pid_t* child_pid_out) { | |
117 std::string path = GetAppPathOutOfCmdLine(cmd_line); | |
118 std::string app_name = GetAppNameOutOfCmdLine(cmd_line); | |
119 | |
120 pid_t child_pid = fork(); | |
121 printf("fork -> %d\n", child_pid); | |
122 if (-1 == child_pid) | |
123 return false; | |
124 | |
125 if (0 == child_pid) { | |
126 // in child | |
127 if (trace) | |
128 ptrace(PTRACE_TRACEME, 0, NULL, NULL); | |
129 | |
130 printf("In child: pid=%d ppid=%d\n", getpid(), getppid()); | |
131 fflush(stdout); | |
132 | |
133 int res = execl(path.c_str(), app_name.c_str(), "", NULL); | |
134 | |
135 // TODO(garianov): how to communicate failure of execl to the debugger | |
136 // process? | |
137 // My guess is parent proc/debugger will get SIGTERM signal or TERM debug ev
ent... | |
138 exit(13); | |
139 } else { | |
140 // in parent | |
141 if (NULL != child_pid_out) | |
142 *child_pid_out = child_pid; | |
143 } | |
144 return true; | |
145 } | |
146 | |
147 bool DebugApi::SetupProc(pid_t pid) { | |
148 intptr_t mask = | |
149 PTRACE_O_TRACEFORK | | |
150 PTRACE_O_TRACEVFORK | | |
151 PTRACE_O_TRACECLONE ; | |
152 // PTRACE_O_TRACEEXEC | | |
153 // PTRACE_O_TRACEEXIT; | |
154 void* data = reinterpret_cast<void*>(mask); | |
155 ptrace_result_t res = ptrace(PTRACE_SETOPTIONS, pid, 0, data); | |
156 printf("Setup PTRACE_O_TRACEFORK option (0x%p) on pid=%d -> %ld\n", | |
157 data, | |
158 pid, | |
159 res); | |
160 fflush(stdout); | |
161 if (0 != res) { | |
162 printf("Error: ptrace(PTRACE_SETOPTIONS(pid=%d) -> %ld\n", pid, res); | |
163 printf("Errno: %s\n", strerror(errno)); | |
164 } | |
165 return (0 != res); | |
166 } | |
167 | |
168 bool DebugApi::DebugBreak(pid_t pid) { | |
169 bool res = (0 == kill(pid, SIGSTOP)); | |
170 if (!res) { | |
171 printf("kill failed\n"); | |
172 printf("Errno: %s\n", strerror(errno)); | |
173 fflush(stdout); | |
174 } | |
175 return res; | |
176 } | |
177 | |
178 bool DebugApi::SingleStep(pid_t pid) { | |
179 printf("SingleStep(%d)\n", pid); | |
180 ptrace_result_t res = ptrace(PTRACE_SINGLESTEP, pid, 0, 0); | |
181 return (0 == res); | |
182 } | |
183 | |
184 | |
185 bool DebugApi::WriteProcessMemory(pid_t pid, | |
186 void* addr, | |
187 void* src, | |
188 size_t size, | |
189 size_t* written_bytes_out) { | |
190 size_t written_bytes = 0; | |
191 size_t left_bytes = size; | |
192 ptrace_result_t res = 0; | |
193 const size_t bundle_sz = sizeof(res); | |
194 unsigned char* ptr_src = reinterpret_cast<unsigned char*>(src); | |
195 unsigned char* ptr_addr = reinterpret_cast<unsigned char*>(addr); | |
196 | |
197 // Read first few bytes that rea not aligned on 4 (or 8 on 64-bit) | |
198 // bytes, if any. | |
199 size_t offset = reinterpret_cast<size_t>(addr); | |
200 size_t offset_from_4bytes = offset % bundle_sz; | |
201 if (0 != offset_from_4bytes) { | |
202 // printf("offset_from_4bytes = %d\n", (int)offset_from_4bytes); | |
203 unsigned char* beg_addr = | |
204 reinterpret_cast<unsigned char*>(offset - offset_from_4bytes); | |
205 res = ptrace(PTRACE_PEEKDATA, pid, beg_addr, 0); | |
206 // printf("ptrace(PTRACE_PEEKDATA(%p) -> 0x%lX\n", beg_addr, res); | |
207 if (0 != errno) { | |
208 // printf("%d ptrace -> %d\n", __LINE__, errno); | |
209 return false; | |
210 } | |
211 unsigned char* p = | |
212 reinterpret_cast<unsigned char*>(&res) + offset_from_4bytes; | |
213 written_bytes = bundle_sz - offset_from_4bytes; | |
214 if (written_bytes > size) | |
215 written_bytes = size; | |
216 | |
217 memcpy(p, ptr_src, written_bytes); | |
218 ptrace_result_t res2 = ptrace(PTRACE_POKEDATA, pid, beg_addr, res); | |
219 // printf("ptrace(PTRACE_POKEDATA(%p, 0x%lX) -> 0x%lX\n", | |
220 // beg_addr, | |
221 // res, | |
222 // res2); | |
223 if (0 != res2) { | |
224 // printf("%d ptrace(PTRACE_POKEDATA) -> %d\n", errno, __LINE__); | |
225 return false; | |
226 } | |
227 | |
228 ptr_src += written_bytes; | |
229 ptr_addr += written_bytes; | |
230 left_bytes -= written_bytes; | |
231 } | |
232 | |
233 while (left_bytes) { | |
234 size_t wr_bytes = bundle_sz; | |
235 if (wr_bytes > left_bytes) | |
236 wr_bytes = left_bytes; | |
237 | |
238 ptrace_result_t data = 0; | |
239 if (left_bytes < bundle_sz) { | |
240 data = ptrace(PTRACE_PEEKDATA, pid, ptr_addr, 0); | |
241 if (0 != errno) { | |
242 // printf("%d ptrace(PTRACE_PEEKDATA) -> 0x%lX\n", __LINE__, data); | |
243 return false; | |
244 } | |
245 // printf("ptrace(PTRACE_PEEKDATA(%p) -> 0x%lX\n", ptr_addr, data); | |
246 } | |
247 memcpy(&data, ptr_src, wr_bytes); | |
248 // printf("memcpy... %X\n", (unsigned int)(*ptr_src)); | |
249 // printf("PTRACE_POKEDATA(%p) %lX\n", ptr_addr, data); | |
250 | |
251 ptrace_result_t res = ptrace(PTRACE_POKEDATA, pid, ptr_addr, data); | |
252 if (0 != res) { | |
253 printf("%d ptrace(PTRACE_POKEDATA) -> 0x%lX\n", __LINE__, res); | |
254 return false; | |
255 } | |
256 | |
257 written_bytes += wr_bytes; | |
258 ptr_src += written_bytes; | |
259 ptr_addr += written_bytes; | |
260 left_bytes -= wr_bytes; | |
261 } | |
262 | |
263 if (NULL != written_bytes_out) | |
264 *written_bytes_out = written_bytes; | |
265 return (size == written_bytes); | |
266 } | |
267 | |
268 bool DebugApi::ReadProcessMemory(pid_t pid, | |
269 void* addr, | |
270 void* dest, | |
271 size_t size, | |
272 size_t* readed_bytes_out) { | |
273 size_t readed_bytes = 0; | |
274 size_t left_bytes = size; | |
275 ptrace_result_t res = 0; | |
276 const size_t bundle_sz = sizeof(res); | |
277 char* ptr_dest = reinterpret_cast<char*>(dest); | |
278 char* ptr_addr = reinterpret_cast<char*>(addr); | |
279 //printf("DebugApi::ReadProcessMemory(%d, %p, %d)\n", pid, addr, (int)size); | |
280 //printf("left_bytes = %d\n", (int)left_bytes); | |
281 | |
282 // Read first few bytes that rea not aligned on 4 (or 8 on 64-bit) | |
283 // bytes, if any. | |
284 size_t offset = reinterpret_cast<size_t>(addr); | |
285 size_t offset_from_4bytes = offset % bundle_sz; | |
286 //printf("===>>>>> offset_from_4bytes=%ld\n", offset_from_4bytes); | |
287 fflush(stdout); | |
288 if (0 != offset_from_4bytes) { | |
289 char* beg_addr = reinterpret_cast<char*>(offset - offset_from_4bytes); | |
290 res = ptrace(PTRACE_PEEKDATA, pid, beg_addr, 0); | |
291 //printf("ptrace(PTRACE_PEEKDATA(%p) -> 0x%lX\n", beg_addr, res); | |
292 if (0 != errno) { | |
293 //printf("ptrace -> %d\n", errno); | |
294 //printf("Errno: %s\n", strerror(errno)); | |
295 return false; | |
296 } | |
297 char* src = reinterpret_cast<char*>(&res) + offset_from_4bytes; | |
298 readed_bytes = bundle_sz - offset_from_4bytes; | |
299 //printf("readed_bytes = %d\n", (int)readed_bytes); | |
300 memcpy(ptr_dest, src, readed_bytes); | |
301 ptr_dest += readed_bytes; | |
302 ptr_addr += readed_bytes; | |
303 if (readed_bytes > left_bytes) | |
304 left_bytes = 0; | |
305 else | |
306 left_bytes -= readed_bytes; | |
307 //printf("left_bytes = %d\n", (int)left_bytes); | |
308 } | |
309 | |
310 while (left_bytes) { | |
311 //printf("left_bytes = %d\n", (int)left_bytes); | |
312 res = ptrace(PTRACE_PEEKDATA, pid, ptr_addr, 0); | |
313 //printf("ptrace(PTRACE_PEEKDATA(%p) -> 0x%lX\n", ptr_addr, res); | |
314 if (0 != errno) { | |
315 //printf("Errno: %s\n", strerror(errno)); | |
316 break; | |
317 } | |
318 size_t rd_bytes = bundle_sz; | |
319 if (rd_bytes > left_bytes) | |
320 rd_bytes = left_bytes; | |
321 | |
322 //printf("rd_bytes = %d\n", (int)rd_bytes); | |
323 memcpy(ptr_dest, &res, rd_bytes); | |
324 readed_bytes += rd_bytes; | |
325 ptr_dest += rd_bytes; | |
326 ptr_addr += rd_bytes; | |
327 left_bytes -= rd_bytes; | |
328 } | |
329 if (NULL != readed_bytes_out) | |
330 *readed_bytes_out = readed_bytes; | |
331 //printf("size=%d readed_bytes=%d\n", (int)size, (int)readed_bytes); | |
332 return (size <= readed_bytes); | |
333 } | |
334 | |
335 bool DebugApi::GetRax(pid_t pid, char** rax) { | |
336 user_regs_struct context; | |
337 if (!ReadThreadContext(pid, &context)) | |
338 return false; | |
339 | |
340 if (NULL != rax) | |
341 *rax = reinterpret_cast<char*>(context.rax); | |
342 return true; | |
343 } | |
344 | |
345 bool DebugApi::GetIp(pid_t pid, char** ip) { | |
346 user_regs_struct context; | |
347 if (!ReadThreadContext(pid, &context)) | |
348 return false; | |
349 | |
350 if (NULL != ip) { | |
351 *ip = reinterpret_cast<char*>(context.rip); | |
352 printf("ReadThreadContext-> ip = %p, ip = 0x%lx\n", *ip, context.rip); | |
353 } | |
354 return true; | |
355 } | |
356 | |
357 bool DebugApi::SetIp(pid_t pid, char* ip) { | |
358 user_regs_struct context; | |
359 if (!ReadThreadContext(pid, &context)) | |
360 return false; | |
361 if (NULL != ip) | |
362 context.rip = reinterpret_cast<u_int64_t>(ip); | |
363 return WriteThreadContext(pid, &context); | |
364 } | |
365 | |
366 bool DebugApi::ReadThreadContext(pid_t pid, user_regs_struct* context) { | |
367 int ret = ptrace(PTRACE_GETREGS, pid, NULL, context); | |
368 // printf("ptrace(PTRACE_GETREGS, -> %d\n", ret); | |
369 return (0 == ret); | |
370 } | |
371 | |
372 bool DebugApi::WriteThreadContext(pid_t pid, user_regs_struct* context) { | |
373 printf("calling ptrace (PTRACE_SETREGS, pid=%d\n", pid); | |
374 fflush(stdout); | |
375 | |
376 int ret = ptrace(PTRACE_SETREGS, pid, NULL, context); | |
377 printf("ptrace (PTRACE_SETREGS, -> %d\n", ret); | |
378 fflush(stdout); | |
379 return (0 == ret); | |
380 } | |
381 | |
382 #define BBB(x) printf("\t\"" #x "\" = \"%lX\",\n", context.x) | |
383 | |
384 void DebugApi::PrintThreadContext(const user_regs_struct& context) { | |
385 printf("context = {\n"); | |
386 BBB(r15); | |
387 BBB(r14); | |
388 BBB(r13); | |
389 BBB(r12); | |
390 BBB(rbp); | |
391 BBB(rbx); | |
392 BBB(r11); | |
393 BBB(r10); | |
394 BBB(r9); | |
395 BBB(r8); | |
396 BBB(rax); | |
397 BBB(rcx); | |
398 BBB(rdx); | |
399 BBB(rsi); | |
400 BBB(rdi); | |
401 BBB(orig_rax); | |
402 BBB(rip); | |
403 BBB(cs); | |
404 BBB(eflags); | |
405 BBB(rsp); | |
406 BBB(ss); | |
407 BBB(fs_base); | |
408 BBB(gs_base); | |
409 BBB(ds); | |
410 BBB(es); | |
411 BBB(fs); | |
412 BBB(gs); | |
413 printf("}\n"); | |
414 } | |
415 | |
416 bool DebugApi::WaitForDebugEvent(DebugEvent* de) { | |
417 int status = 0; | |
418 int options = WNOHANG; // | WUNTRACED | WCONTINUED; | |
419 options |= __WALL; | |
420 int res = waitpid(-1, &status, options); | |
421 if (-1 == res) | |
422 return false; | |
423 | |
424 bool recv_event = (0 != res); | |
425 if (recv_event) { | |
426 de->Reset(); | |
427 de->process_id_ = res; | |
428 | |
429 user_regs_struct context; | |
430 if (ReadThreadContext(de->process_id_, &context)) { | |
431 de->ip_ = reinterpret_cast<char*>(context.rip); | |
432 } | |
433 siginfo_t si; | |
434 memset(&si, 0, sizeof(si)); | |
435 ptrace_result_t res = ptrace(PTRACE_GETSIGINFO, de->process_id_, 0, &si); | |
436 // printf("ptrace(PTRACE_GETSIGINFO -> %ld\n", res); | |
437 if (0 == res) { | |
438 de->signal_code_ = si.si_code; | |
439 de->signal_value_ = si.si_value; | |
440 if ((SIGTRAP == de->signal_no_) || | |
441 (SIGSEGV == de->signal_no_) || | |
442 (SIGILL == de->signal_no_) || | |
443 (SIGFPE == de->signal_no_) || | |
444 (SIGBUS == de->signal_no_)) | |
445 de->addr_ = reinterpret_cast<char*>(si.si_addr); | |
446 | |
447 if ((SIGTRAP == de->signal_no_) && (EVENT_CLONE == si.si_code)) { | |
448 // TODO(garianov): get children pid | |
449 // PTRACE_GETEVENTMSG | |
450 } | |
451 } | |
452 | |
453 | |
454 if (WIFEXITED(status)) { | |
455 de->event_code_ = DebugEvent::PROCESS_EXITED; | |
456 de->exit_code_ = WEXITSTATUS(status); | |
457 } else if (WIFSIGNALED(status)) { | |
458 de->event_code_ = DebugEvent::PROCESS_TERMINATED; | |
459 de->signal_no_ = WTERMSIG(status); | |
460 } else if (WIFSTOPPED(status)) { | |
461 de->event_code_ = DebugEvent::PROCESS_STOPPED; | |
462 de->signal_no_ = WSTOPSIG(status); | |
463 | |
464 if (SIGTRAP == de->signal_no_) { | |
465 de->event_code_ = DebugEvent::HIT_BREAKPOINT; | |
466 if (TRAP_TRACE == de->signal_code_) | |
467 de->event_code_ = DebugEvent::SINGLE_STEP_TRAP; | |
468 } else if (kOutputDebugStringSignal == de->signal_no_) { | |
469 de->event_code_ = DebugEvent::OUTPUT_DEBUG_STRING; | |
470 } | |
471 } else if (WIFCONTINUED(status)) { | |
472 de->event_code_ = DebugEvent::PROCESS_CONTINUED_WITH_SIGCONT; | |
473 } | |
474 } | |
475 return recv_event; | |
476 } | |
477 | |
478 bool DebugApi::EnableSingleStep(pid_t pid, bool enable) { | |
479 user_regs_struct context; | |
480 if (ReadThreadContext(pid, &context)) { | |
481 if (enable) | |
482 context.eflags |= 1 << 8; | |
483 else | |
484 context.eflags &= ~(1 << 8); | |
485 return WriteThreadContext(pid, &context); | |
486 } | |
487 return false; | |
488 } | |
489 | |
490 void DebugEvent::Reset() { | |
491 memset(this, 0, sizeof(*this)); | |
492 } | |
493 | |
494 #define BB(x, desc) case x: return #x ": " desc | |
495 | |
496 const char* GetSigCodeName(int signo, int sig_code) { | |
497 if (SIGILL == signo) { | |
498 switch (sig_code) { | |
499 BB(ILL_ILLOPC, "Illegal opcode"); | |
500 BB(ILL_ILLADR, "Illegal addressing mode"); | |
501 BB(ILL_ILLTRP, "Illegal trap"); | |
502 BB(ILL_PRVOPC, "Privileged opcode"); | |
503 BB(ILL_PRVREG, "Privileged register"); | |
504 BB(ILL_COPROC, "Coprocessor error"); | |
505 BB(ILL_BADSTK, "Internal stack error"); | |
506 } | |
507 } else if (SIGFPE == signo) { | |
508 switch (sig_code) { | |
509 BB(FPE_INTDIV, "Integer divide by zero"); | |
510 BB(FPE_INTOVF, "Integer overflow"); | |
511 BB(FPE_FLTDIV, "Floating point divide by zero"); | |
512 BB(FPE_FLTOVF, "Floating point overflow"); | |
513 BB(FPE_FLTUND, "Floating point underflow"); | |
514 BB(FPE_FLTRES, "Floating point inexact result"); | |
515 BB(FPE_FLTINV, "Floating point invalid operation"); | |
516 BB(FPE_FLTSUB, "Subscript out of range"); | |
517 } | |
518 } else if (SIGSEGV == signo) { | |
519 switch (sig_code) { | |
520 BB(SEGV_MAPERR, "Address not mapped to object"); | |
521 BB(SEGV_ACCERR, "Invalid permissions for mapped object"); | |
522 } | |
523 } else if (SIGBUS == signo) { | |
524 switch (sig_code) { | |
525 BB(BUS_ADRALN, "Invalid address alignment"); | |
526 BB(BUS_ADRERR, "Non-existant physical address"); | |
527 BB(BUS_OBJERR, "Object specific hardware error"); | |
528 } | |
529 } else if (SIGTRAP == signo) { | |
530 switch (sig_code) { | |
531 BB(TRAP_BRKPT, "Process breakpoint"); | |
532 BB(TRAP_TRACE, "Process trace trap, aka single step"); | |
533 BB(EVENT_FORK, ""); | |
534 BB(EVENT_VFORK, ""); | |
535 BB(EVENT_CLONE, ""); | |
536 BB(EVENT_EXEC, ""); | |
537 BB(EVENT_VFORK_DONE, ""); | |
538 BB(EVENT_EXIT, ""); | |
539 } | |
540 } else if (SIGCHLD == signo) { | |
541 switch (sig_code) { | |
542 BB(CLD_EXITED, "Child has exited"); | |
543 BB(CLD_KILLED, "Child was killed"); | |
544 BB(CLD_DUMPED, "Child terminated abnormally"); | |
545 BB(CLD_TRAPPED, "Traced child has trapped"); | |
546 BB(CLD_STOPPED, "Child has stopped"); | |
547 BB(CLD_CONTINUED, "Stopped child has continued"); | |
548 } | |
549 } else if (SIGPOLL == signo) { | |
550 switch (sig_code) { | |
551 BB(POLL_IN, "Data input available"); | |
552 BB(POLL_OUT, "Output buffers available"); | |
553 BB(POLL_MSG, "Input message available"); | |
554 BB(POLL_ERR, "I/O error"); | |
555 BB(POLL_PRI, "High priority input available"); | |
556 BB(POLL_HUP, "Device disconnected"); | |
557 } | |
558 } | |
559 switch (sig_code) { | |
560 BB(SI_ASYNCNL, "Sent by asynch name lookup completion"); | |
561 BB(SI_TKILL, "Sent by tkill"); | |
562 BB(SI_SIGIO, "Sent by queued SIGIO"); | |
563 BB(SI_ASYNCIO, "Sent by AIO completion"); | |
564 BB(SI_MESGQ, "Sent by real time mesq state change"); | |
565 BB(SI_TIMER, "Sent by timer expiration"); | |
566 BB(SI_QUEUE, "Sent by sigqueue"); | |
567 BB(SI_USER, "Sent by kill, sigsend, raise"); | |
568 BB(SI_KERNEL, "Send by kernel"); | |
569 } | |
570 return ""; | |
571 } | |
572 | |
573 const char* GetSignalName(int signo) { | |
574 switch (signo) { | |
575 BB(SIGHUP, "Hangup (POSIX)"); | |
576 BB(SIGINT, "Interrupt (ANSI)"); | |
577 BB(SIGQUIT, "Quit (POSIX)"); | |
578 BB(SIGILL, "Illegal instruction (ANSI)"); | |
579 BB(SIGTRAP, "Trace trap (POSIX)"); | |
580 BB(SIGABRT, "==SIGIOT. Abort (ANSI) == IOT trap (4.2 BSD)"); | |
581 BB(SIGBUS, "BUS error (4.2 BSD)"); | |
582 BB(SIGFPE, "Floating-point exception (ANSI)"); | |
583 BB(SIGKILL, "Kill, unblockable (POSIX)"); | |
584 BB(SIGUSR1, "User-defined signal 1 (POSIX)"); | |
585 BB(SIGSEGV, "Segmentation violation (ANSI)"); | |
586 BB(SIGUSR2, "User-defined signal 2 (POSIX)"); | |
587 BB(SIGPIPE, "Broken pipe (POSIX)"); | |
588 BB(SIGALRM, "Alarm clock (POSIX)"); | |
589 BB(SIGTERM, "Termination (ANSI)"); | |
590 BB(SIGSTKFLT, "Stack fault"); | |
591 BB(SIGCHLD, "Child status has changed (POSIX)"); | |
592 BB(SIGCONT, "Continue (POSIX)"); | |
593 BB(SIGSTOP, "Stop, unblockable (POSIX)"); | |
594 BB(SIGTSTP, "Keyboard stop (POSIX)"); | |
595 BB(SIGTTIN, "Background read from tty (POSIX)"); | |
596 BB(SIGTTOU, "Background write to tty (POSIX)"); | |
597 BB(SIGURG, "Urgent condition on socket (4.2 BSD)"); | |
598 BB(SIGXCPU, "CPU limit exceeded (4.2 BSD)"); | |
599 BB(SIGXFSZ, "File size limit exceeded (4.2 BSD)"); | |
600 BB(SIGVTALRM, "Virtual alarm clock (4.2 BSD)"); | |
601 BB(SIGPROF, "Profiling alarm clock (4.2 BSD)"); | |
602 BB(SIGWINCH, "Window size change (4.3 BSD, Sun)"); | |
603 BB(SIGIO, | |
604 "I/O now possible (4.2 BSD) /" | |
605 "Pollable event occurred (System V)"); | |
606 BB(SIGPWR, "Power failure restart (System V)"); | |
607 BB(SIGSYS, "Bad system call"); | |
608 } | |
609 return ""; | |
610 } | |
611 | |
612 #define AAA(x) case x: ev_name = #x; break | |
613 | |
614 void DebugEvent::Print() { | |
615 const char* ev_name = "UNKNOWN"; | |
616 switch (event_code_) { | |
617 AAA(HIT_BREAKPOINT); | |
618 AAA(OUTPUT_DEBUG_STRING); | |
619 AAA(SINGLE_STEP_TRAP); | |
620 AAA(PROCESS_TERMINATED); | |
621 AAA(PROCESS_EXITED); | |
622 AAA(PROCESS_STOPPED); | |
623 AAA(PROCESS_CONTINUED_WITH_SIGCONT); | |
624 } | |
625 | |
626 printf("\"DebugEvent\" : {\n"); | |
627 printf("\t\"process_id_\" : \"%d\",\n", process_id_); | |
628 printf("\t\"event_code_\" : \"%s\",\n", ev_name); | |
629 | |
630 printf("\t\"signal_no_\" : \"%d\",", signal_no_); | |
631 if (0 != signal_no_) | |
632 printf(" //%s", GetSignalName(signal_no_)); | |
633 printf("\n"); | |
634 | |
635 printf("\t\"signal_code_\" : \"%d\",", signal_code_); | |
636 const char* sig_code_name = GetSigCodeName(signal_no_, signal_code_); | |
637 if (strlen(sig_code_name) > 0 ) | |
638 printf(" //%s", sig_code_name); | |
639 printf("\n"); | |
640 | |
641 printf("\t\"exit_code_\" : \"%d\",\n", exit_code_); | |
642 printf("\t\"ip_\" : \"%p\",\n", ip_); | |
643 printf("\t\"addr_\" : \"%p\",\n", addr_); | |
644 printf("}\n"); | |
645 } | |
646 } // namespace debug | |
647 | |
OLD | NEW |