Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(65)

Side by Side Diff: experimental/mac_debugger/debug_api_mac.cc

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/mac_debugger/debug_api_mac.h ('k') | experimental/mac_debugger/debug_blob.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 //=========================================================================//
OLDNEW
« no previous file with comments | « experimental/mac_debugger/debug_api_mac.h ('k') | experimental/mac_debugger/debug_blob.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698