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 <fcntl.h> | |
5 | |
6 #ifndef _WIN32 | |
7 #include <sys/types.h> | |
8 #include <pthread.h> | |
9 #include <signal.h> | |
10 #include <termios.h> | |
11 #include <unistd.h> | |
12 #include <mach/mach_vm.h> | |
13 #include <mach/mach.h> | |
14 #else | |
15 #include <conio.h> | |
16 #pragma warning(disable : 4996 4267 4244 4800 4101) | |
17 #define snprintf _snprintf | |
18 #endif | |
19 | |
20 #include <stdio.h> | |
21 #include <stdlib.h> | |
22 #include <string.h> | |
23 | |
24 #include <deque> | |
25 #include <string> | |
26 #include <map> | |
27 | |
28 #include "debug_api_mac.h" | |
29 #include "debug_blob.h" | |
30 #include "debug_command_line.h" | |
31 | |
32 extern "C" kern_return_t catch_exception_raise(mach_port_t exception_port, | |
33 mach_port_t thread, | |
34 mach_port_t task, | |
35 exception_type_t exception, | |
36 exception_data_t code, | |
37 mach_msg_type_number_t code_count);
| |
38 void* atoptr(const char* str) { | |
39 void* ptr = 0; | |
40 sscanf(str, "%p", &ptr); // NOLINT | |
41 return ptr; | |
42 } | |
43 | |
44 uint64_t glb_mem_base = 0; | |
45 | |
46 struct Breakpoint { | |
47 Breakpoint() : addr_(0), instr_length_(0), id_(0), ip_(0) {} | |
48 Breakpoint(uint64_t ip, int instr_length) : ip_(ip), addr_(ip + glb_mem_base),
instr_length_(instr_length) { | |
49 id_ = next_id_; | |
50 next_id_ = ++next_id_ % 4; | |
51 } | |
52 | |
53 uint64_t addr_; | |
54 int instr_length_; | |
55 int id_; | |
56 int ip_; | |
57 static int next_id_; | |
58 }; | |
59 | |
60 int Breakpoint::next_id_ = 0; | |
61 | |
62 std::map<uint64_t, Breakpoint> glb_breakpoints; | |
63 uint64_t glb_continue_from_br_addr = 0; | |
64 | |
65 #ifndef _WIN32 | |
66 int kbhit() { | |
67 termios oldt; | |
68 tcgetattr(STDIN_FILENO, &oldt); | |
69 termios newt = oldt; | |
70 newt.c_lflag &= ~(ICANON | ECHO); | |
71 tcsetattr(STDIN_FILENO, TCSANOW, &newt); | |
72 int oldf = fcntl(STDIN_FILENO, F_GETFL, 0); | |
73 fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); | |
74 | |
75 int ch = getchar(); | |
76 | |
77 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); | |
78 fcntl(STDIN_FILENO, F_SETFL, oldf); | |
79 | |
80 if (EOF != ch) { | |
81 ungetc(ch, stdin); | |
82 return 1; | |
83 } | |
84 return 0; | |
85 } | |
86 #endif | |
87 | |
88 void Split(const char* str_in, | |
89 const char* delimiters, | |
90 std::deque<std::string>* out) { | |
91 char c = 0; | |
92 std::string str; | |
93 while (c = *str_in++) { | |
94 if (strchr(delimiters, c)) { | |
95 if (str.size()) { | |
96 out->push_back(str); | |
97 str.clear(); | |
98 } | |
99 } else if ((c != '\r') && (c != '\n')) { | |
100 str.push_back(c); | |
101 } | |
102 } | |
103 if (str.size()) | |
104 out->push_back(str); | |
105 } | |
106 | |
107 void printList(const std::deque<std::string>& list) { | |
108 printf("list {\n"); | |
109 size_t num = list.size(); | |
110 for (size_t i = 0; i < num; i++) | |
111 printf("[%s]\n", list[i].c_str()); | |
112 printf("}\n"); | |
113 } | |
114 | |
115 int main(int argc, char *argv[]) { | |
116 printf("Version 0.006 Build: %s %s\n", __DATE__, __TIME__); | |
117 debug::DebugAPI deb_api; | |
118 pid_t child_pid = 0; | |
119 | |
120 // catch_exception_raise(0, 0, 0, 0, 0, 0); | |
121 | |
122 const char* cmd = "/Users/garianov/Documents/chromium/src/xcodebuild/Rel
ease/Chromium.app/Contents/MacOS/Chromium"; | |
123 #define CHROMEEE | |
124 #ifdef CHROMEEE | |
125 bool sp_res = deb_api.StartProcess( | |
126 //"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", | |
127 cmd, | |
128 true, | |
129 &child_pid); | |
130 #else | |
131 cmd = "../../../test/build/Debug/test"; | |
132 bool sp_res = deb_api.StartProcess( | |
133 cmd, | |
134 true, | |
135 &child_pid); | |
136 #endif | |
137 | |
138 printf("Process [%s] %s. Pid = 0x%x == %d\n", cmd, sp_res ? "started" : "faile
d to start", child_pid, child_pid); | |
139 | |
140 bool show_events = true; | |
141 int nacl_pid = 0; | |
142 bool animate = false; | |
143 FILE* file = fopen("anim.txt", "wt"); | |
144 bool first = true; | |
145 #ifdef CHROMEEE | |
146 static bool iterative = true; //false; | |
147 #else | |
148 static bool iterative = true; | |
149 #endif | |
150 | |
151 while (true) { | |
152 if (kbhit()) { | |
153 char buff[100] = { 0 }; | |
154 fgets(buff, sizeof(buff) -1, stdin); | |
155 | |
156 std::deque<std::string> words; | |
157 Split(buff, " \t", &words); | |
158 printList(words); | |
159 if (words.size() ==0) | |
160 continue; | |
161 if ((words[0] == "break") && (words.size() >= 2)) { | |
162 int pid = atoi(words[1].c_str()); | |
163 bool res = deb_api.DebugBreak(pid); | |
164 if (!res) | |
165 printf("Error\n"); | |
166 continue; | |
167 } else if ((words[0] == "H") && (words.size() >= 2)) { | |
168 int pid = atoi(words[1].c_str()); | |
169 deb_api.HookupDebugeeProcess(pid); | |
170 | |
171 } else if ((words[0] == "h") && (words.size() >= 2)) { | |
172 int pid = atoi(words[1].c_str()); | |
173 | |
174 mach_port_t target_task; | |
175 int res = 0; | |
176 if (0 != (res = ::task_for_pid(mach_task_self(), pid, &target_task))) { | |
177 printf("task_for_pid(%d) -> %d\n", pid, res); | |
178 } else { | |
179 const int kMaxExcNum = 20; | |
180 exception_mask_t masks[kMaxExcNum]; | |
181 mach_msg_type_number_t masksCnt = kMaxExcNum; | |
182 mach_port_t ports[kMaxExcNum]; | |
183 exception_behavior_t bhv[kMaxExcNum]; | |
184 thread_state_flavor_t flv[kMaxExcNum]; | |
185 res = ::task_get_exception_ports(target_task, EXC_MASK_ALL, masks, &ma
sksCnt, ports, bhv, flv); | |
186 if (0 == res) { | |
187 printf("%d ports\n", masksCnt); | |
188 for (int i = 0; i < masksCnt; i++) { | |
189 printf("port=0x%x mask=0x%x\n", ports[i], masks[i]); | |
190 } | |
191 } else { | |
192 printf("task_get_exception_ports -> %d\n", res); | |
193 } | |
194 } | |
195 } else if (words[0] == "e-") { | |
196 printf("show_events = false\n"); | |
197 show_events = false; | |
198 continue; | |
199 } | |
200 } | |
201 | |
202 bool do_continue = false; | |
203 debug::DebugEvent de; | |
204 if (deb_api.WaitForDebugEvent(1000, &de)) { | |
205 if (de.signal_no_ == MACH_BREAKPOINT) { | |
206 // OutputDebugString? | |
207 std::string msg; | |
208 if (deb_api.ReadDebugString(de, &msg)) { | |
209 // parse it | |
210 debug::CommandLine debug_info(msg); | |
211 std::string event = debug_info.GetStringSwitch("-event", ""); | |
212 if ("AppCreate" == event) { | |
213 void* mem_base = debug_info.GetAddrSwitch("-mem_start"); | |
214 void* user_entry_point = debug_info.GetAddrSwitch("-user_entry_pt"); | |
215 printf("NaClAppCreate mem_base=%p entry_point=%p\n", | |
216 mem_base, | |
217 user_entry_point); | |
218 glb_mem_base = (uint64_t)mem_base; | |
219 deb_api.ContinueDebugEvent(de, 0); | |
220 continue; | |
221 } | |
222 } | |
223 | |
224 unsigned int ip = 0; | |
225 if (!deb_api.ReadIP(de.thread_, &ip)) { | |
226 printf("Error reading ip\n"); | |
227 } else { | |
228 if (0 != glb_continue_from_br_addr) { | |
229 printf("Continuing from or breakpoint at 0x%llx\n", glb_continue_fro
m_br_addr); | |
230 Breakpoint br = glb_breakpoints[glb_continue_from_br_addr]; | |
231 glb_continue_from_br_addr = 0; | |
232 deb_api.SetHwBreakpoint(de.thread_, br.addr_, br.id_); | |
233 deb_api.ContinueDebugEvent(de, 0); | |
234 continue; | |
235 } | |
236 } | |
237 } | |
238 | |
239 if (0) { //debug::DebugEvent::OUTPUT_DEBUG_STRING == de.event_code_) { | |
240 iterative = true; | |
241 nacl_pid = de.pid_; | |
242 printf("Got OUTPUT_DEBUG_STRING: "); | |
243 std::string string; | |
244 if (deb_api.ReadDebugString(de, &string)) | |
245 printf("[%s]", string.c_str()); | |
246 printf("\n"); | |
247 // deb_api.ContinueDebugEvent(de.pid_); | |
248 // do_continue = true; | |
249 } | |
250 | |
251 //if (show_events || (nacl_pid == de.pid_) || | |
252 // (SIGTRAP == de.signal_no_)) | |
253 de.Print(); | |
254 | |
255 if (animate && (nacl_pid == de.pid_) && | |
256 (SIGTRAP == de.signal_no_)) { | |
257 printf("SIGTRAP == de.signal_no_\n"); | |
258 fflush(file); | |
259 // deb_api.EnableSingleStep(de.pid_, false); | |
260 // deb_api.SingleStep(nacl_pid); | |
261 continue; | |
262 } | |
263 | |
264 while (!do_continue) { | |
265 char buff[100] = { 0 }; | |
266 | |
267 if (iterative) { | |
268 printf("\n[%d]>", de.pid_); | |
269 fflush(stdout); | |
270 fgets(buff, sizeof(buff) -1, stdin); | |
271 } else { | |
272 snprintf(buff, sizeof(buff), "c"); | |
273 } | |
274 // test only: end | |
275 | |
276 static bool first = true; | |
277 if (first) { | |
278 first = false; | |
279 // deb_api.SetupProc(de.pid_); | |
280 } | |
281 | |
282 std::deque<std::string> words; | |
283 Split(buff, " \t", &words); | |
284 // printList(words); | |
285 if (words.size() < 1) | |
286 continue; | |
287 if (words[0] == "c") { | |
288 if (de.signal_no_ == MACH_BREAKPOINT) { | |
289 unsigned int ip = 0; | |
290 if (!deb_api.ReadIP(de.thread_, &ip)) { | |
291 printf("Error reading ip\n"); | |
292 } else if (glb_breakpoints.end() != glb_breakpoints.find(ip)) { | |
293 printf("Our breakpoint hit at 0x%x\n", ip); | |
294 Breakpoint br = glb_breakpoints[ip]; | |
295 glb_continue_from_br_addr = br.ip_; | |
296 deb_api.SetHwBreakpoint(de.thread_, br.addr_ + br.instr_length_, b
r.id_); | |
297 deb_api.ContinueDebugEvent(de, 0); | |
298 break; | |
299 } | |
300 } | |
301 int signo = de.signal_no_; | |
302 if (signo == SIGTRAP) | |
303 signo = 0; | |
304 deb_api.ContinueDebugEvent(de, 0); | |
305 break; | |
306 } else if (words[0] == "e-") { | |
307 printf("show_events = false\n"); | |
308 show_events = false; | |
309 continue; | |
310 } else if (words[0] == "ce") { | |
311 // deb_api.EnableSingleStep(de.pid_, false); | |
312 deb_api.ContinueDebugEvent(de, de.signal_no_); | |
313 break; | |
314 } else if (words[0] == "cn") { | |
315 // deb_api.EnableSingleStep(de.pid_, false); | |
316 deb_api.ContinueDebugEvent(de, 0); | |
317 break; | |
318 } else if (words[0] == "si") { | |
319 deb_api.EnableSingleStep(de.thread_, true); | |
320 // deb_api.ContinueDebugEvent(de, 0); | |
321 printf("si %d\n", de.pid_); | |
322 // deb_api.SingleStep(de.pid_); | |
323 // break; | |
324 } else if (words[0] == "si-") { | |
325 deb_api.EnableSingleStep(de.thread_, false); | |
326 printf("si- %d\n", de.pid_); | |
327 } else if (words[0] == "cb") { | |
328 // continue and break immediately | |
329 // deb_api.EnableSingleStep(de.pid_, false); | |
330 deb_api.ContinueDebugEvent(de, 0); | |
331 bool res = deb_api.DebugBreak(de.pid_); | |
332 if (!res) | |
333 printf("Error\n"); | |
334 break; | |
335 } else if (words[0] == "th") { | |
336 mach_port_t target_thread =de.thread_; | |
337 const int kMaxExcNum = 20; | |
338 exception_mask_t masks[kMaxExcNum]; | |
339 mach_msg_type_number_t masksCnt = kMaxExcNum; | |
340 mach_port_t ports[kMaxExcNum]; | |
341 exception_behavior_t bhv[kMaxExcNum]; | |
342 thread_state_flavor_t flv[kMaxExcNum]; | |
343 int res = ::thread_get_exception_ports(target_thread, EXC_MASK_ALL, ma
sks, &masksCnt, ports, bhv, flv); | |
344 if (0 == res) { | |
345 printf("%d ports\n", masksCnt); | |
346 for (int i = 0; i < masksCnt; i++) { | |
347 printf("port=0x%x mask=0x%x\n", ports[i], masks[i]); | |
348 } | |
349 } else { | |
350 printf("task_get_exception_ports -> %d\n", res); | |
351 } | |
352 } else if (words[0] == "h") { | |
353 mach_port_t target_task = de.task_; | |
354 int res = 0; | |
355 const int kMaxExcNum = 20; | |
356 exception_mask_t masks[kMaxExcNum]; | |
357 mach_msg_type_number_t masksCnt = kMaxExcNum; | |
358 mach_port_t ports[kMaxExcNum]; | |
359 exception_behavior_t bhv[kMaxExcNum]; | |
360 thread_state_flavor_t flv[kMaxExcNum]; | |
361 res = ::task_get_exception_ports(target_task, EXC_MASK_ALL, masks, &
masksCnt, ports, bhv, flv); | |
362 if (0 == res) { | |
363 printf("%d ports\n", masksCnt); | |
364 for (int i = 0; i < masksCnt; i++) { | |
365 printf("port=0x%x mask=0x%x\n", ports[i], masks[i]); | |
366 } | |
367 } else { | |
368 printf("task_get_exception_ports -> %d\n", res); | |
369 } | |
370 } else if ((words[0] == "at") && (words.size() >= 2)) { | |
371 int pid = atoi(words[1].c_str()); | |
372 int res = ptrace(PT_ATTACHEXC, pid, 0, 0); | |
373 printf("attach to %d -> %d\n", pid, res); | |
374 | |
375 } else if ((words[0] == "m") && (words.size() >= 3)) { | |
376 uint64_t addr = 0; | |
377 sscanf(words[1].c_str(), "%llx", &addr); | |
378 printf("addr:0x%llx\n", addr); | |
379 int len = atoi(words[2].c_str()); | |
380 size_t rd = 0; | |
381 char buff[1024]; | |
382 bool res = deb_api.ReadProcessMemory(de.pid_, | |
383 addr, | |
384 buff, | |
385 len, | |
386 &rd); | |
387 if (res) { | |
388 printf("ReadProcessMemory -> %ld\n", rd); | |
389 fflush(stdout); | |
390 debug::Blob blob(buff, rd); | |
391 printf("zz1\n"); | |
392 fflush(stdout); | |
393 std::string str = blob.ToHexString(false); | |
394 printf("zz2\n"); | |
395 fflush(stdout); | |
396 printf("[%s]\n", str.c_str()); | |
397 printf("zz3\n"); | |
398 fflush(stdout); | |
399 } else { | |
400 printf("Error\n"); | |
401 } | |
402 } else if ((words[0] == "M") && (words.size() >= 3)) { | |
403 uint64_t addr = 0; //atoi(words[1].c_str()); | |
404 sscanf(words[1].c_str(), "%llx", &addr); | |
405 printf("addr:0x%llx\n", addr); | |
406 debug::Blob blob; | |
407 blob.LoadFromHexString(words[2]); | |
408 | |
409 void* data = blob.ToCBuffer(); | |
410 debug::Blob blob2(data, blob.Size()); | |
411 std::string str = blob2.ToHexString(false); | |
412 printf("recv[%s] sz=%d\n", str.c_str(), blob.Size()); | |
413 | |
414 if (NULL != data) { | |
415 size_t wr = 0; | |
416 int sz = blob.Size(); | |
417 printf(" sz = %d\n", sz); | |
418 bool res = deb_api.WriteProcessMemory(de.pid_, | |
419 addr, | |
420 data, | |
421 sz, | |
422 &wr); | |
423 if (!res) | |
424 printf("Error\n"); | |
425 free(data); | |
426 } | |
427 } else if ((words[0] == "mem_base") && (words.size() >= 2)) { | |
428 uint64_t addr = 0; //atoi(words[1].c_str()); | |
429 sscanf(words[1].c_str(), "%llx", &addr); | |
430 glb_mem_base = addr; | |
431 } else if ((words[0] == "br") && (words.size() > 2)) { | |
432 uint64_t ip = 0; //atoi(words[1].c_str()); | |
433 sscanf(words[1].c_str(), "%llx", &ip); | |
434 int len = atoi(words[2].c_str()); | |
435 printf("ip:0x%llx\n", ip); | |
436 Breakpoint br(ip, len); | |
437 glb_breakpoints[ip] = br; | |
438 | |
439 deb_api.SetHwBreakpoint(de.thread_, br.addr_, br.id_); | |
440 | |
441 | |
442 } else if (words[0] == "g") { | |
443 x86_thread_state context; | |
444 memset(&context, 0, sizeof(context)); | |
445 bool res = deb_api.ReadThreadContext(de.thread_, &context); | |
446 if (res) { | |
447 printf("tsh = %d\n", context.tsh.flavor); | |
448 if (context.tsh.flavor == x86_THREAD_STATE32) { | |
449 #define AAS(x) printf("\t%s = 0x%x\n", #x, context.uts.ts32.__##x) | |
450 AAS(eax); | |
451 AAS(ebx); | |
452 AAS(ecx); | |
453 AAS(edx); | |
454 AAS(edi); | |
455 AAS(esi); | |
456 AAS(ebp); | |
457 AAS(esp); | |
458 AAS(ss); | |
459 AAS(eflags); | |
460 AAS(eip); | |
461 AAS(cs); | |
462 AAS(ds); | |
463 AAS(es); | |
464 AAS(fs); | |
465 AAS(gs); | |
466 | |
467 } | |
468 } | |
469 } else if (words[0] == "ip") { | |
470 unsigned int ip = 0; | |
471 deb_api.ReadIP(de.thread_, &ip); | |
472 printf("IP = 0x%x\n", ip); | |
473 } else if (words[0] == "ip--") { | |
474 unsigned int ip = 0; | |
475 if (deb_api.ReadIP(de.thread_, &ip)) { | |
476 ip--; | |
477 deb_api.WriteIP(de.thread_, ip); | |
478 printf("IP = 0x%x\n", ip); | |
479 } | |
480 } else if (words[0] == "ip++") { | |
481 unsigned int ip = 0; | |
482 if (deb_api.ReadIP(de.thread_, &ip)) { | |
483 ip++; | |
484 deb_api.WriteIP(de.thread_, ip); | |
485 printf("IP = 0x%x\n", ip); | |
486 } | |
487 } else if ((words[0] == "break") && (words.size() >= 2)) { | |
488 int pid = atoi(words[2].c_str()); | |
489 bool res = deb_api.DebugBreak(pid); | |
490 if (!res) | |
491 printf("Error\n"); | |
492 } | |
493 } | |
494 } | |
495 } | |
496 return 1; | |
497 } | |
498 | |
499 /* | |
500 #include "debugger_front_end.h" | |
501 #include "debugger_back_end.h" | |
502 | |
503 int main2(int argc, char *argv[]) { | |
504 debug::BackEnd back_end; | |
505 debug::FrontEnd debugger(&back_end); | |
506 int ret_code = 0; | |
507 if (!debugger.Init(argc, argv, &ret_code)) | |
508 return ret_code; | |
509 | |
510 return debugger.Run(); | |
511 } | |
512 */ | |
OLD | NEW |