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_mac.h" | |
5 | |
6 #include <errno.h> | |
7 #include <memory.h> | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 | |
11 #ifndef _WIN32 | |
12 #include <signal.h> | |
13 #include <sys/syscall.h> | |
14 #include <sys/types.h> | |
15 #include <sys/user.h> | |
16 #include <sys/wait.h> | |
17 #include <unistd.h> | |
18 //#include <osfmk/vm/vm_map.h> | |
19 #else | |
20 #include "mac_sys_mock.h" | |
21 #endif | |
22 | |
23 #include <deque> | |
24 #include <string> | |
25 | |
26 typedef int64_t ptrace_result_t; | |
27 extern "C" boolean_t exc_server(mach_msg_header_t* inhdr, mach_msg_header_t* out
hdr); | |
28 | |
29 #define CALL_KERN(x) do { int res = x; if (0 != res) {printf("%s error: %d\n", #
x, res); return false;}\ | |
30 else printf("%s ok!\n", #x);} while (false) | |
31 #define CALL_KERN2(x) do { int res = x; if (0 != res) {printf("%s error: %d\n",
#x, res); pthread_exit((void*)x);}\ | |
32 else printf("%s ok!\n", #x);} while (false) | |
33 | |
34 #define PAGE_MASK (page_size_ - 1) | |
35 #define vm_map_trunc_page(x) ((mach_vm_address_t)(x) & ~((signed int)PAGE_MASK)) | |
36 #define vm_map_round_page(x) (((mach_vm_address_t)(x) + PAGE_MASK) & (~(signed i
nt)PAGE_MASK)) | |
37 | |
38 extern "C" kern_return_t catch_exception_raise(mach_port_t exception_port, | |
39 mach_port_t thread, | |
40 mach_port_t task, | |
41 exception_type_t exceptio, | |
42 mach_exception_data_t code, | |
43 mach_msg_type_number_t code_cnt) | |
44 #ifndef _WIN32 | |
45 __attribute__((visibility("defaul
t"))) | |
46 #endif | |
47 ; | |
48 | |
49 debug::DebugEvent* glb_debug_event = NULL; | |
50 | |
51 extern "C" kern_return_t catch_exception_raise(mach_port_t exception_port, | |
52 mach_port_t thread, | |
53 mach_port_t task, | |
54 exception_type_t exceptio, | |
55 mach_exception_data_t code, | |
56 mach_msg_type_number_t code_cnt)
{ | |
57 int pid = 0; | |
58 pid_for_task(task, &pid); | |
59 printf("Got exception %d(0x%x):0x%p from task:thread 0x%d:0x%x pid=0x%x\n>>",
(int)exceptio, (int)exceptio, code, task, thread, pid); | |
60 if (0 == thread) | |
61 return KERN_SUCCESS; | |
62 if (NULL != glb_debug_event) { | |
63 glb_debug_event->pid_ = pid; | |
64 glb_debug_event->process_state_ = debug::PROCESS_STOPPED; | |
65 glb_debug_event->signal_no_ = MACH_EXCEPTIONS_START_CODE + exceptio; | |
66 glb_debug_event->exit_code_ = 0; | |
67 glb_debug_event->task_ = task; | |
68 glb_debug_event->thread_ = thread; | |
69 printf("Suspending task 0x%x\n", task); | |
70 if (exceptio != 10) { | |
71 CALL_KERN(::task_suspend(task)); | |
72 } | |
73 } | |
74 return (exceptio == 10) ? 1 : KERN_SUCCESS; | |
75 } | |
76 | |
77 struct exc_msg { | |
78 mach_msg_header_t header_; | |
79 NDR_record_t ndr_; | |
80 kern_return_t ret_code_; | |
81 char other_stuff[1024]; | |
82 }; | |
83 | |
84 namespace { | |
85 const int kMaxOutputDebugStringSize = 256; | |
86 const char kNexePrefix[] = "{7AA7C9CF-89EC-4ed3-8DAD-6DC84302AB11}"; | |
87 } // namespace | |
88 | |
89 namespace debug { | |
90 DebugAPI::DebugAPI() : page_size_(0), exception_port_(0) { | |
91 vm_size_t ps = 0; | |
92 ::host_page_size(::mach_host_self(), &ps); | |
93 printf("page size = %d\n", ps); | |
94 page_size_ = ps; | |
95 } | |
96 | |
97 bool DebugAPI::StartProcess(const char* cmd_line, | |
98 bool trace, | |
99 pid_t* child_pid_out) { | |
100 pid_t child_pid = fork(); | |
101 printf("fork -> %d\n", child_pid); | |
102 if (-1 == child_pid) | |
103 return false; | |
104 | |
105 if (0 == child_pid) { | |
106 // in child | |
107 if (trace) { | |
108 int res = ptrace(PT_TRACE_ME, 0, NULL, NULL); | |
109 printf("ptrace(PT_TRACE_ME, ... -> %d\n", res); | |
110 //ptrace(PT_SIGEXC, 0, NULL, NULL); | |
111 } | |
112 printf("calling execl (%s, ...)\n", cmd_line); | |
113 // int res = execl(cmd_line, "chrome", NULL); | |
114 // int res = execl(cmd_line, "chrome", "--disable-breakpad", "--incognito", "
--no-sandbox", NULL); | |
115 // char* args[] = {"chrome", "--disable-breakpad", "--incognito", "--no-sandb
ox", NULL}; | |
116 char* args[] = {"chrome", "--disable-breakpad", "--incognito", NULL}; | |
117 char* envs[] = {/*"NACL_DANGEROUS_IGNORE_VALIDATOR=1", */NULL}; | |
118 int res = execve(cmd_line, args, envs); | |
119 | |
120 printf("in child: execl -> %d errno=%d\n", res, errno); | |
121 exit(13); | |
122 } else { | |
123 // in parent | |
124 HookupDebugeeProcess(child_pid); | |
125 | |
126 if (NULL != child_pid_out) | |
127 *child_pid_out = child_pid; | |
128 } | |
129 return true; | |
130 } | |
131 | |
132 bool DebugAPI::HookupDebugeeProcess(pid_t pid) { | |
133 printf("DebugAPI::HookupRocess pid=%d\n", pid); | |
134 fflush(stdout); | |
135 | |
136 // Got the mach port for the current process | |
137 mach_port_t task_self = mach_task_self(); | |
138 | |
139 mach_port_t target_task; | |
140 CALL_KERN(::task_for_pid(task_self, pid, &target_task)); | |
141 | |
142 // Allocate an exception port that we will use to track our child process | |
143 CALL_KERN(::mach_port_allocate(task_self, | |
144 MACH_PORT_RIGHT_RECEIVE, | |
145 &exception_port_)); | |
146 | |
147 // Add the ability to send messages on the new exception port | |
148 CALL_KERN(::mach_port_insert_right(task_self, | |
149 exception_port_, | |
150 exception_port_, | |
151 MACH_MSG_TYPE_MAKE_SEND)); | |
152 | |
153 // Set the ability to get all exceptions from |target_task| on this port
. | |
154 CALL_KERN(::task_set_exception_ports( | |
155 target_task, | |
156 EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC
_MASK_BREAKPOINT | EXC_MASK_CRASH, | |
157 exception_port_, | |
158 EXCEPTION_DEFAULT, | |
159 THREAD_STATE_NONE)); | |
160 return true; | |
161 } | |
162 | |
163 bool DebugAPI::WaitForMachException(int wait_ms, DebugEvent* de) { | |
164 if (0 == exception_port_) | |
165 return false; | |
166 //printf("DebugAPI::WaitForMachException(%d ms) exception_port_ = 0x%x\n", wai
t_ms, exception_port_); | |
167 //fflush(stdout); | |
168 bool event_received = false; | |
169 exc_msg msg_recv; | |
170 msg_recv.header_.msgh_local_port = exception_port_; | |
171 msg_recv.header_.msgh_size = sizeof(msg_recv); | |
172 | |
173 kern_return_t res = ::mach_msg(&msg_recv.header_, | |
174 MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_TIME
OUT, | |
175 0, // send size | |
176 sizeof(msg_recv), | |
177 exception_port_, | |
178 wait_ms, | |
179 MACH_PORT_NULL); // no notify port | |
180 //printf("mach_msg -> %d\n", (int)res); | |
181 fflush(stdout); | |
182 | |
183 if (0 == res) { | |
184 printf("Got mach exception\n"); | |
185 fflush(stdout); | |
186 glb_debug_event = de; | |
187 exc_msg msg_send; | |
188 | |
189 // It calls our catch_mach_exception_raise(), | |
190 // and it pauses the task (aka process). | |
191 exc_server(&msg_recv.header_, &msg_send.header_); | |
192 glb_debug_event = NULL; | |
193 | |
194 CALL_KERN2(::mach_msg(&(msg_send.header_), | |
195 MACH_SEND_MSG, | |
196 msg_send.header_.msgh_size, | |
197 0, | |
198 MACH_PORT_NULL
, | |
199 MACH_MSG_TIMEO
UT_NONE, | |
200 MACH_PORT_NULL
)); // no notify port | |
201 event_received = true; | |
202 if (2010 == de->signal_no_) | |
203 event_received = false; | |
204 } | |
205 //printf(" %s\n", event_received ? "new event" : "nothing"); | |
206 //fflush(stdout); | |
207 return event_received; | |
208 } | |
209 | |
210 bool DebugAPI::WaitForDebugEvent(int wait_ms, DebugEvent* de) { | |
211 de->pid_ = 0; | |
212 de->signal_no_ = 0; | |
213 de->exit_code_ = 0; | |
214 de->process_state_ = PROCESS_STOPPED; | |
215 | |
216 int status = 0; | |
217 int options = WNOHANG | WUNTRACED | WCONTINUED; | |
218 int res = waitpid(-1, &status, options); | |
219 if ((-1 != res) && (0 != res)) { | |
220 de->pid_ = res; | |
221 if (WIFEXITED(status)) { | |
222 de->process_state_ = PROCESS_EXITED; | |
223 de->exit_code_ = WEXITSTATUS(status); | |
224 } else if (WIFSIGNALED(status)) { | |
225 de->process_state_ = PROCESS_TERMINATED; | |
226 de->signal_no_ = WTERMSIG(status); | |
227 } else if (WIFSTOPPED(status)) { | |
228 de->process_state_ = PROCESS_STOPPED; | |
229 de->signal_no_ = WSTOPSIG(status); | |
230 } else if (WIFCONTINUED(status)) { | |
231 de->process_state_ = PROCESS_STOPPED; | |
232 de->signal_no_ = 0; | |
233 } | |
234 return true; | |
235 } | |
236 return WaitForMachException(wait_ms, de); | |
237 } | |
238 | |
239 bool DebugAPI::PostSignal(pid_t pid, int signo) { | |
240 return (0 == kill(pid, signo)); | |
241 } | |
242 | |
243 bool DebugAPI::ReadDebugString(const DebugEvent& de, std::string* string) { | |
244 if ((MACH_BREAKPOINT != de.signal_no_) || (PROCESS_STOPPED != de.process_state
_)) | |
245 return false; | |
246 | |
247 x86_thread_state context; | |
248 if (!ReadThreadContext(de.thread_, &context)) | |
249 return false; | |
250 | |
251 uint64_t addr = context.uts.ts32.__eax; | |
252 char buff[kMaxOutputDebugStringSize]; | |
253 size_t rd = 0; | |
254 ReadProcessMemory(de.pid_, addr, buff, sizeof(buff) - 1, &rd); | |
255 if (rd < sizeof(kNexePrefix)) | |
256 return false; | |
257 if (strncmp(buff, kNexePrefix, sizeof(kNexePrefix) - 1) != 0) | |
258 return false; | |
259 | |
260 buff[sizeof(buff) - 1] = 0; | |
261 *string = &buff[sizeof(kNexePrefix) - 1]; | |
262 printf("DebugString-[%s]\n", string->c_str()); | |
263 return true; | |
264 } | |
265 | |
266 bool DebugAPI::ContinueDebugEvent(DebugEvent de, int signo) { | |
267 if (de.signal_no_ >= MACH_EXCEPTIONS_START_CODE) { | |
268 printf("Resuming task 0x%x", de.task_); | |
269 kern_return_t res = ::task_resume(de.task_); | |
270 printf("->%d\n", res); | |
271 //::mach_port_deallocate(::mach_host_self(), de.task_); | |
272 //::mach_port_deallocate(::mach_host_self(), de.thread_); | |
273 return (0 == res); | |
274 } | |
275 printf("calling ptrace(PTCONTINUE, %d, 1, %d)", de.pid_, signo); | |
276 ptrace_result_t res = ptrace(PT_CONTINUE, de.pid_, (char*)1, signo); | |
277 return (0 == res); | |
278 } | |
279 | |
280 bool DebugAPI::DebugBreak(pid_t pid) { | |
281 // TODO: really??? | |
282 return PostSignal(pid, SIGSTOP); | |
283 } | |
284 | |
285 bool DebugAPI::SingleStep(DebugEvent de) { | |
286 // TODO: how we can single-step from mach exception? | |
287 //ptrace_result_t res = ptrace(PT_STEP, pid, 0, 0); | |
288 //return (0 == res); | |
289 return true; | |
290 } | |
291 | |
292 bool DebugAPI::ReadProcessMemory(pid_t pid, | |
293 uint64_t addr, | |
294 void* dest, | |
295 size_t size, | |
296 size_t* readed_bytes_out) { | |
297 mach_port_t target_task; | |
298 CALL_KERN(::task_for_pid(mach_task_self(), pid, &target_task)); | |
299 // mach_vm_size_t rd = 0; | |
300 // CALL_KERN(::mach_vm_read_overwrite(target_task, (mach_vm_address_t)addr, siz
e, (mach_vm_address_t)dest, &rd)); | |
301 // if (NULL != readed_bytes_out) | |
302 // *readed_bytes_out = rd; | |
303 | |
304 uint64_t start_reg = vm_map_trunc_page(addr); | |
305 uint64_t reg_size = vm_map_round_page(size); | |
306 printf("start=0x%llx ", start_reg); | |
307 printf("reg_size=0x%llx ", reg_size); | |
308 uint64_t offset = addr - start_reg; | |
309 printf("roffset=0x%lld ", offset); | |
310 | |
311 //mach_vm_address_t address, | |
312 //mach_vm_size_t size, | |
313 vm_offset_t data = 0; | |
314 mach_msg_type_number_t dataCnt = 0; | |
315 kern_return_t res = ::mach_vm_read(target_task, | |
316 (mach_vm_size_t)start_reg, | |
317 (mach_vm_address_t)reg_size, | |
318 &data, | |
319 &dataCnt); | |
320 printf("mach_vm_read(0x%llx, %lld)-> res=%d, data=0x%p dataCnt=%d\n", start_re
g, reg_size, res, (void*)data, dataCnt); | |
321 if (0 == res) { | |
322 memcpy(dest, (void*)(data + offset), size); | |
323 printf("mm1"); | |
324 fflush(stdout); | |
325 | |
326 ::vm_deallocate(mach_task_self(), data, dataCnt); | |
327 printf("mm2\n"); | |
328 fflush(stdout); | |
329 if (readed_bytes_out) | |
330 *readed_bytes_out = size; | |
331 printf("mm3\n"); | |
332 fflush(stdout); | |
333 | |
334 return true; | |
335 } | |
336 | |
337 // TODO: shall we dealloc |target_task|? | |
338 return false; | |
339 } | |
340 | |
341 bool DebugAPI::WriteProcessMemory(pid_t pid, | |
342 uint64_t addr, | |
343 void* src, | |
344 size_t size, | |
345 size_t* written_bytes_out) { | |
346 printf("WrtMem: addr=0x%llx ", addr); | |
347 printf(" size=[%d]\n", (int)size); | |
348 mach_port_t target_task; | |
349 CALL_KERN(::task_for_pid(mach_task_self(), pid, &target_task)); | |
350 | |
351 uint64_t start_reg = vm_map_trunc_page(addr); | |
352 uint64_t reg_size = vm_map_round_page(size); | |
353 printf("start=0x%llx ", start_reg); | |
354 printf("reg_size=0x%llx ", reg_size); | |
355 uint64_t offset = addr - start_reg; | |
356 char* buff = reinterpret_cast<char*>(malloc((size_t)reg_size)); | |
357 size_t rd = 0; | |
358 bool rd_res = ReadProcessMemory(pid, start_reg, buff, (size_t)reg_size, &rd); | |
359 if (rd_res) { | |
360 memcpy(buff + offset, src, size); | |
361 | |
362 vm_address_t address = (int)start_reg; | |
363 vm_size_t ret_size = size; | |
364 | |
365 vm_region_basic_info info; | |
366 mach_msg_type_number_t infoCnt = sizeof(info) / sizeof(int); | |
367 mach_port_t object_name = 0; | |
368 kern_return_t res = ::vm_region(target_task, | |
369 &address, | |
370 &ret_size, | |
371 VM_REGION_BASIC_INFO, | |
372 (vm_region_info_t)&info, | |
373 &infoCnt, | |
374 &object_name); | |
375 | |
376 | |
377 printf("::vm_region(0x%X, 0x%X) -> res=%d prot=0x%X max_prot=0x%X\n", | |
378 (int)start_reg, (int)size, res, info.protection, info.max_protection)
; | |
379 | |
380 vm_prot_t new_protection = info.protection | VM_PROT_WRITE; | |
381 res = ::mach_vm_protect(target_task, | |
382 (mach_vm_address_t)start_reg, | |
383 (mach_vm_size_t)reg_size, | |
384 false, | |
385 new_protection); | |
386 printf("::mach_vm_protect-> %d\n", res); | |
387 | |
388 res = ::mach_vm_write(target_task, (int)start_reg, (vm_offset_t)buff, (int)r
eg_size); | |
389 printf ("::mach_vm_write-> %d\n", res); | |
390 | |
391 // Flush cashes. | |
392 //vm_machine_attribute_val_t flush_attr = MATTR_VAL_CACHE_FLUSH; | |
393 //res = ::vm_machine_attribute(target_task, (int)start_reg, (int)reg_size, M
ATTR_CACHE, &flush_attr); | |
394 //printf("::vm_machine_attribute -> %d\n", res); | |
395 | |
396 // Put back protection | |
397 res = ::mach_vm_protect(target_task, | |
398 (mach_vm_address_t)start_reg, | |
399 (mach_vm_size_t)reg_size, | |
400 false, | |
401 info.protection); | |
402 printf("::mach_vm_protect-> %d\n", res); | |
403 } | |
404 // TODO: shall we dealloc |target_task|? A: you can try & see what happens. | |
405 free(buff); | |
406 return true; | |
407 } | |
408 | |
409 bool DebugAPI::SetHwBreakpoint(int tid, uint64_t addr, int br_no) { | |
410 printf("DebugAPI::SetHwBreakpoint(tid=0x%x, addr=0x%llx, br_no=%d\n", tid, add
r, br_no); | |
411 x86_debug_state32_t inf; | |
412 mach_msg_type_number_t buff_sz = x86_DEBUG_STATE32_COUNT; // in ints??? | |
413 CALL_KERN(::thread_get_state(tid, | |
414 x86_DEBUG_STATE32, | |
415 reinterpret_cast<thread_state_t>(&inf), | |
416 &buff_sz)); | |
417 printf("sz=%d\n", buff_sz); | |
418 switch (br_no) { | |
419 case 0: inf.__dr0 = (unsigned int)addr; break; | |
420 case 1: inf.__dr1 = (unsigned int)addr; break; | |
421 case 2: inf.__dr2 = (unsigned int)addr; break; | |
422 case 3: inf.__dr3 = (unsigned int)addr; break; | |
423 } | |
424 inf.__dr7 |= (1 << 9) + (1 << 8) + (1 << (br_no * 2)); | |
425 | |
426 CALL_KERN(::thread_set_state(tid, | |
427 x86_DEBUG_STATE32, | |
428 reinterpret_cast<thread_state_t>(&inf), | |
429 buff_sz)); | |
430 return true; | |
431 } | |
432 | |
433 | |
434 bool DebugAPI::ReadThreadContext(int tid, x86_thread_state* context) { | |
435 | |
436 mach_msg_type_number_t buff_sz = x86_THREAD_STATE_COUNT; // in ints??? | |
437 CALL_KERN(::thread_get_state(tid, | |
438 x86_THREAD_STATE, | |
439 reinterpret_cast<thread_state_t>(context), | |
440 &buff_sz)); | |
441 return true; | |
442 } | |
443 | |
444 /* | |
445 _STRUCT_X86_EXCEPTION_STATE32 | |
446 { | |
447 unsigned int trapno; | |
448 unsigned int err; | |
449 unsigned int faultvaddr; | |
450 }; | |
451 */ | |
452 | |
453 | |
454 bool DebugAPI::WriteThreadContext(int tid, const x86_thread_state& context) { | |
455 mach_msg_type_number_t buff_sz = x86_THREAD_STATE_COUNT; // in ints??? | |
456 CALL_KERN(::thread_set_state(tid, | |
457 x86_THREAD_STATE, | |
458 (thread_state_t)(&context), | |
459 buff_sz)); | |
460 return true; | |
461 } | |
462 | |
463 bool DebugAPI::ReadIP(int tid, unsigned int* ip) { | |
464 x86_thread_state context; | |
465 memset(&context, 0, sizeof(context)); | |
466 if (ReadThreadContext(tid, &context)) { | |
467 *ip = context.uts.ts32.__eip; | |
468 return true; | |
469 } | |
470 return false; | |
471 } | |
472 | |
473 bool DebugAPI::WriteIP(int tid, unsigned int ip) { | |
474 x86_thread_state context; | |
475 memset(&context, 0, sizeof(context)); | |
476 if (ReadThreadContext(tid, &context)) { | |
477 context.uts.ts32.__eip = ip; | |
478 return WriteThreadContext(tid, context); | |
479 } | |
480 return false; | |
481 } | |
482 | |
483 bool DebugAPI::EnableSingleStep(int tid, bool enable) { | |
484 x86_thread_state context; | |
485 memset(&context, 0, sizeof(context)); | |
486 if (ReadThreadContext(tid, &context)) { | |
487 uint32_t trace_bit = 0x100u; | |
488 uint32_t resume_bit = 0x10000u; | |
489 if (enable) | |
490 context.uts.ts32.__eflags |= trace_bit; | |
491 else | |
492 context.uts.ts32.__eflags &= ~trace_bit; | |
493 //context.uts.ts32.__eflags &= ~resume_bit; | |
494 return WriteThreadContext(tid, context); | |
495 } | |
496 return false; | |
497 } | |
498 | |
499 bool DebugAPI::GetThreadList(pid_t pid, std::deque<int>* list) { | |
500 if (NULL == list) | |
501 return false; | |
502 list->clear(); | |
503 mach_port_t target_task; | |
504 CALL_KERN(::task_for_pid(mach_task_self(), pid, &target_task)); | |
505 | |
506 thread_array_t thread_list; | |
507 mach_msg_type_number_t thread_count = 0; | |
508 CALL_KERN(::task_threads(target_task, &thread_list, &thread_count)); | |
509 | |
510 for (int i = 0; i < thread_count; i++) { | |
511 mach_port_t thread = thread_list[i]; | |
512 list->push_back(thread); | |
513 ::mach_port_deallocate(mach_task_self(), thread); | |
514 } | |
515 return true; | |
516 } | |
517 | |
518 #define AAA(x) case x: return #x | |
519 const char* GetSignalName(int signal_no) { | |
520 switch (signal_no) { | |
521 AAA(SIGHUP); | |
522 AAA(SIGINT); | |
523 AAA(SIGQUIT); | |
524 AAA(SIGILL); | |
525 AAA(SIGTRAP); | |
526 AAA(SIGABRT); | |
527 AAA(SIGEMT); | |
528 AAA(SIGFPE); | |
529 AAA(SIGKILL); | |
530 AAA(SIGBUS); | |
531 AAA(SIGSEGV); | |
532 AAA(SIGSYS); | |
533 AAA(SIGPIPE); | |
534 AAA(SIGALRM); | |
535 AAA(SIGTERM); | |
536 AAA(SIGURG); | |
537 AAA(SIGSTOP); | |
538 AAA(SIGTSTP); | |
539 AAA(SIGCONT); | |
540 AAA(SIGCHLD); | |
541 AAA(SIGTTIN); | |
542 AAA(SIGTTOU); | |
543 AAA(SIGIO); | |
544 AAA(SIGXCPU); | |
545 AAA(SIGXFSZ); | |
546 AAA(SIGVTALRM); | |
547 AAA(SIGPROF); | |
548 AAA(SIGWINCH); | |
549 AAA(SIGINFO); | |
550 AAA(SIGUSR1); | |
551 AAA(SIGUSR2); | |
552 AAA(MACH_BAD_ACCESS); | |
553 AAA(MACH_BAD_INSTRUCTION); | |
554 AAA(MACH_ARITHMETIC); | |
555 AAA(MACH_BREAKPOINT); | |
556 } | |
557 return ""; | |
558 } | |
559 | |
560 const char* GetProcStateName(int process_state) { | |
561 switch (process_state) { | |
562 AAA(PROCESS_RUNNING); | |
563 AAA(PROCESS_STOPPED); | |
564 AAA(PROCESS_TERMINATED); | |
565 AAA(PROCESS_EXITED); | |
566 } | |
567 return ""; | |
568 } | |
569 | |
570 void DebugEvent::Print() { | |
571 printf("\"DebugEvent\" : {\n"); | |
572 printf("\t\"proc_state\" : \"%s\",\n", GetProcStateName(process_state_)); | |
573 printf("\t\"pid_\" : \"0x%x\", \\%d\n", pid_, pid_); | |
574 | |
575 printf("\t\"signal_no_\" : \"%d\",", signal_no_); | |
576 if (0 != signal_no_) | |
577 printf(" //%s", GetSignalName(signal_no_)); | |
578 printf("\n"); | |
579 // if (child_pid_) | |
580 // printf("\t\"child_pid_\" : \"0x%x\",\n", child_pid_); | |
581 | |
582 printf("\t\"exit_code_\" : \"%d\",\n", exit_code_); | |
583 printf("\t\"task_\" : \"0x%x\",\n", task_); | |
584 printf("\t\"thread_\" : \"0x%x\",\n", thread_); | |
585 printf("}\n"); | |
586 } | |
587 | |
588 } // namespace debug | |
589 | |
590 | |
591 //=========================================================================// | |
OLD | NEW |