1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include <assert.h> |
6 | #include <fnmatch.h> |
7 | #include <limits.h> |
8 | #include <linux/net.h> |
9 | #include <sys/socket.h> |
10 | #include <sys/types.h> |
11 | #include <sys/ptrace.h> |
12 | #include <sys/syscall.h> |
13 | #include <sys/mman.h> |
14 | #include <sys/wait.h> |
15 | #include <sys/un.h> |
16 | #include <sys/user.h> |
17 | |
18 | #if !defined(__sw_64) && !defined(__aarch64__) |
19 | #include <capstone/capstone.h> |
20 | #endif |
21 | |
22 | #if defined(__i386__) || defined(__x86_64__) |
23 | #include <libunwind-ptrace.h> |
24 | #endif |
25 | |
26 | #include <string> |
27 | #include <memory> |
28 | |
29 | #include "cpu.h" |
30 | #include "debug.h" |
31 | #include "elf_helper.h" |
32 | |
33 | using namespace std; |
34 | |
35 | int write_mem(int pid, uintptr_t addr, const void* buf, int buf_size) |
36 | { |
37 | int nwritten = 0; |
38 | // ptrace operates on the word size of the host, so we really do want |
39 | // to use sizes of host types here. |
40 | uintptr_t word_size = sizeof(long); |
41 | |
42 | errno = 0; |
43 | |
44 | // Only write aligned words. This ensures we can always write the last |
45 | // byte before an unmapped region. |
46 | while (nwritten < buf_size) { |
47 | uintptr_t start = addr + nwritten; |
48 | uintptr_t start_word = start & ~(word_size - 1); |
49 | uintptr_t end_word = start_word + word_size; |
50 | uintptr_t length = min(end_word - start, uintptr_t(buf_size - nwritten)); |
51 | |
52 | long v; |
53 | if (length < word_size) { |
54 | v = ptrace(PTRACE_PEEKDATA, pid, start_word, nullptr); |
55 | if (errno) { |
56 | break; |
57 | } |
58 | } |
59 | |
60 | memcpy(reinterpret_cast<uint8_t*>(&v) + (start - start_word), |
61 | static_cast<const uint8_t*>(buf) + nwritten, length); |
62 | ptrace(PTRACE_POKEDATA, pid, start_word, reinterpret_cast<void*>(v)); |
63 | nwritten += length; |
64 | } |
65 | |
66 | return nwritten; |
67 | } |
68 | |
69 | int read_mem(int tid, uintptr_t addr, void* buf, int buf_size) |
70 | { |
71 | int nread = 0; |
72 | // ptrace operates on the word size of the host, so we really do want |
73 | // to use sizes of host types here. |
74 | uintptr_t word_size = sizeof(long); |
75 | // Only read aligned words. This ensures we can always read the last |
76 | // byte before an unmapped region. |
77 | uintptr_t start_word = addr & ~(word_size - 1); |
78 | uintptr_t end_word = (addr + buf_size) & ~(word_size - 1); |
79 | |
80 | errno = 0; |
81 | if (start_word < addr) { |
82 | // the first unaligned part |
83 | long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr); |
84 | long offset = (addr - start_word); |
85 | start_word += word_size; |
86 | nread = start_word - addr; |
87 | if (nread > buf_size) nread = buf_size; |
88 | memcpy(static_cast<uint8_t*>(buf), |
89 | reinterpret_cast<uint8_t*>(&v) + offset, nread); |
90 | } |
91 | |
92 | while (start_word < end_word) { |
93 | long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr); |
94 | if (errno) { |
95 | break; |
96 | } |
97 | start_word += word_size; |
98 | memcpy(static_cast<uint8_t*>(buf) + nread, |
99 | reinterpret_cast<uint8_t*>(&v), word_size); |
100 | nread += word_size; |
101 | } |
102 | |
103 | if (nread < buf_size) { |
104 | // the last unaligned part |
105 | long v = ptrace(PTRACE_PEEKDATA, tid, start_word, nullptr); |
106 | memcpy(static_cast<uint8_t*>(buf) + nread, |
107 | reinterpret_cast<uint8_t*>(&v), buf_size - nread); |
108 | nread = buf_size; |
109 | } |
110 | |
111 | return nread; |
112 | } |
113 | |
114 | int gdb_disass(int pid, void* base, int len) |
115 | { |
116 | #if defined(__sw_64) || defined(__aarch64__) |
117 | return -1; |
118 | #else |
119 | csh handle; |
120 | cs_insn* insn = NULL; |
121 | uintptr_t address = (uintptr_t)base; |
122 | string codestr('0', len); |
123 | uint8_t* code = (uint8_t*)codestr.data(); |
124 | size_t code_size = len; |
125 | |
126 | int got = read_mem(pid, address, code, code_size); |
127 | if (got < (int)code_size) { |
128 | return -1; |
129 | } |
130 | |
131 | #if defined(__x86_64__) |
132 | if (cs_open(CS_ARCH_X86, cs_mode(CS_MODE_64), &handle) != CS_ERR_OK) { |
133 | #elif defined(__mips64) |
134 | if (cs_open(CS_ARCH_MIPS, cs_mode(CS_MODE_MIPS64|CS_MODE_LITTLE_ENDIAN), |
135 | &handle) != CS_ERR_OK) { |
136 | #else |
137 | if (1) { |
138 | #endif |
139 | return -2; |
140 | } |
141 | |
142 | // allocate memory cache for 1 instruction, to be used by cs_disasm_iter later. |
143 | insn = cs_malloc(handle); |
144 | |
145 | /*Some mips struction on loonson not support by libcapstone |
146 | use this statement maybe better decode*/ |
147 | cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); |
148 | |
149 | // disassemble one instruction a time & store the result into @insn variable above |
150 | while(cs_disasm_iter(handle, (const uint8_t**)&code, &code_size, &address, insn)) |
151 | { |
152 | // analyze disassembled instruction in @insn variable ... |
153 | // NOTE: @code, @code_size & @address variables are all updated |
154 | // to point to the next instruction after each iteration. |
155 | |
156 | printf("0x%" PRIx64 ":\t%s\t%s\n" , |
157 | insn->address, insn->mnemonic, insn->op_str); |
158 | |
159 | // print implicit registers used by this instruction |
160 | cs_detail* detail = insn->detail; |
161 | if (!detail) continue; |
162 | |
163 | if (detail->regs_read_count > 0) { |
164 | printf("\tImplicit registers read: " ); |
165 | for (int n = 0; n < detail->regs_read_count; n++) { |
166 | printf("%s " , cs_reg_name(handle, detail->regs_read[n])); |
167 | } |
168 | printf("\n" ); |
169 | } |
170 | |
171 | // print implicit registers modified by this instruction |
172 | if (detail->regs_write_count > 0) { |
173 | printf("\tImplicit registers modified: " ); |
174 | for (int n = 0; n < detail->regs_write_count; n++) { |
175 | printf("%s " , cs_reg_name(handle, detail->regs_write[n])); |
176 | } |
177 | printf("\n" ); |
178 | } |
179 | |
180 | // print the groups this instruction belong to |
181 | if (detail->groups_count > 0) { |
182 | printf("\tThis instruction belongs to groups: " ); |
183 | for (int n = 0; n < detail->groups_count; n++) { |
184 | printf("%s " , cs_group_name(handle, detail->groups[n])); |
185 | } |
186 | printf("\n" ); |
187 | } |
188 | } |
189 | |
190 | // release the cache memory when done |
191 | cs_free(insn, 1); |
192 | cs_close(&handle); |
193 | return 0; |
194 | #endif |
195 | } |
196 | |
197 | int gdb_pause(pid_t pid) |
198 | { |
199 | int ret = ptrace(PTRACE_INTERRUPT, pid, nullptr, nullptr); |
200 | if (ret < 0) { |
201 | return -errno; |
202 | } |
203 | |
204 | return 0; |
205 | } |
206 | |
207 | // used by gdb console to debug dead-lock in recording |
208 | int gdb_cont(pid_t pid) |
209 | { |
210 | int ret = ptrace(PTRACE_CONT, pid, nullptr, nullptr); |
211 | if (ret < 0) { |
212 | return -errno; |
213 | } |
214 | |
215 | return 0; |
216 | } |
217 | |
218 | int gdb_step(int pid) |
219 | { |
220 | int ret = ptrace(PTRACE_SINGLESTEP, pid, nullptr, nullptr); |
221 | if (ret < 0) { |
222 | return -errno; |
223 | } |
224 | |
225 | return 0; |
226 | } |
227 | |
228 | int gdb_bt(int tid) |
229 | { |
230 | #if defined(__i386__) || defined(__x86_64__) |
231 | #define MAX_STACK_FRAME 64 |
232 | |
233 | unw_addr_space_t unwind_as; |
234 | struct UPT_info* ui = nullptr; |
235 | int n = 0, ret; |
236 | unw_cursor_t cursor; |
237 | unw_proc_info_t pi; |
238 | unw_word_t ip, sp, start_ip = 0, off; |
239 | char buf[512]; |
240 | |
241 | unwind_as = unw_create_addr_space (&_UPT_accessors, 0); |
242 | if (!unwind_as) { |
243 | printf("libunwind.unw_create_addr_space() failed\n" ); |
244 | return -1; |
245 | } |
246 | |
247 | ui = reinterpret_cast<struct UPT_info*>(_UPT_create(tid)); |
248 | ret = unw_init_remote (&cursor, unwind_as, ui); |
249 | if (ret < 0) { |
250 | printf("unw_init_remote() failed: pause first then try again, ret=%d\n" , ret); |
251 | _UPT_destroy (ui); |
252 | return -2; |
253 | } |
254 | |
255 | do { |
256 | if ((ret = unw_get_reg (&cursor, UNW_REG_IP, &ip)) < 0 || |
257 | (ret = unw_get_reg (&cursor, UNW_REG_SP, &sp)) < 0) { |
258 | printf("unw_get_reg failed: ret=%d\n" , ret); |
259 | break; |
260 | } |
261 | |
262 | if (n == 0) start_ip = ip; |
263 | |
264 | buf[0] = '\0'; |
265 | unw_get_proc_name (&cursor, buf, sizeof (buf), &off); |
266 | |
267 | if ((ret = unw_get_proc_info (&cursor, &pi)) < 0) { |
268 | printf("unw_get_proc_info(%lx)failed: ret=%d\n" , ip, ret); |
269 | break; |
270 | } |
271 | printf("\t[%d \t]ip=%-16lx\tsp=%-16lx\t%s+%lx\n" , n, ip, sp, buf, off); |
272 | |
273 | ret = unw_step (&cursor); |
274 | if (ret < 0) { |
275 | unw_get_reg (&cursor, UNW_REG_IP, &ip); |
276 | printf("FAILURE: unw_step() returned %d, for ip=%lx\n" , ret, ip); |
277 | break; |
278 | } |
279 | |
280 | if (++n > MAX_STACK_FRAME) { |
281 | /* guard against bad unwind info in old libraries... */ |
282 | printf("too deeply nested---assuming bogus unwind (start ip=%lx)\n" , start_ip); |
283 | break; |
284 | } |
285 | } |
286 | while (ret > 0); |
287 | |
288 | _UPT_destroy (ui); |
289 | if (unwind_as) { |
290 | unw_destroy_addr_space (unwind_as); |
291 | unwind_as = nullptr; |
292 | } |
293 | #elif defined(__mips__) || defined(__sw_64) || defined(__aarch64__) |
294 | USER_REGS regs; |
295 | printf("\ndump register:\n" ); |
296 | gdb_reg(tid, ®s); |
297 | printf("\ndump memory of pc:\n" ); |
298 | gdb_mem(tid, (void*)regs.pc, 256, 1); |
299 | printf("\ndump memory of sp:\n" ); |
300 | gdb_mem(tid, (void*)regs.sp, 256, 1); |
301 | #else |
302 | printf("not implement in your arch\n" ); |
303 | #endif |
304 | |
305 | return 0; |
306 | } |
307 | |
308 | static unsigned int copy_print_char (char* out, const unsigned char* buf, unsigned int count) |
309 | { |
310 | unsigned int i = 0; |
311 | while (i<count) |
312 | { |
313 | if (buf[i] < 0x20 || buf[i] > 0x7f) |
314 | { |
315 | out[i] = '.'; |
316 | } |
317 | else |
318 | { |
319 | out[i] = buf[i]; |
320 | } |
321 | ++i; |
322 | } |
323 | out[i++] = '\n'; |
324 | |
325 | return i; |
326 | } |
327 | |
328 | static void print_bytes(const void* buffer, int total) |
329 | { |
330 | char* str = NULL; |
331 | int i = 0; |
332 | int j = 0; |
333 | unsigned char* buf = (unsigned char*)buffer; |
334 | int count = total; |
335 | unique_ptr<char[]> outbuf = make_unique<char[]>(count*4 + (count+15)/16*2 + 48); |
336 | |
337 | str = outbuf.get(); |
338 | |
339 | while ( i<count ) |
340 | { |
341 | j += sprintf(str+j, "%02x " , buf[i] ); |
342 | |
343 | ++i; |
344 | if ( !( i&15 ) ) |
345 | { |
346 | str[j++] = ' '; |
347 | j += copy_print_char (str+j, buf+i-16, 16); |
348 | } |
349 | } |
350 | |
351 | if ( count&15 ) |
352 | { |
353 | i = count&15; //left |
354 | memset (str+j, 0x20, (16-i)*3 + 1 ); |
355 | j += (16-i)*3 + 1; |
356 | j += copy_print_char (str+j, buf+count-i, i); |
357 | } |
358 | str[j] = 0; |
359 | |
360 | printf("%s" , str); |
361 | } |
362 | |
363 | static char hex2char(unsigned char hex) |
364 | { |
365 | if (hex<0xa) return hex+'0'; |
366 | else return hex-0xa+'a'; |
367 | } |
368 | |
369 | static void hex2str2(unsigned char* hex, int size, char* str) |
370 | { |
371 | int i = 0; |
372 | char* walk = str; |
373 | for (;i<size;) |
374 | { |
375 | walk[0] = hex2char(hex[2*i+1]>>4); |
376 | walk[1] = hex2char(hex[2*i+1]&0xf); |
377 | walk[2] = hex2char(hex[2*i]>>4); |
378 | walk[3] = hex2char(hex[2*i]&0xf); |
379 | walk[4] = 0x20; |
380 | ++i; |
381 | walk += 5; |
382 | if (!(i & 7)) { |
383 | *walk++ = '\n'; |
384 | } |
385 | } |
386 | |
387 | *walk = 0; |
388 | } |
389 | |
390 | static void hex2str4(unsigned char* hex, int size, char* str) |
391 | { |
392 | int i = 0; |
393 | char* walk = str; |
394 | for (;i<size;) |
395 | { |
396 | walk[0] = hex2char(hex[4*i+3]>>4); |
397 | walk[1] = hex2char(hex[4*i+3]&0xf); |
398 | walk[2] = hex2char(hex[4*i+2]>>4); |
399 | walk[3] = hex2char(hex[4*i+2]&0xf); |
400 | walk[4] = hex2char(hex[4*i+1]>>4); |
401 | walk[5] = hex2char(hex[4*i+1]&0xf); |
402 | walk[6] = hex2char(hex[4*i]>>4); |
403 | walk[7] = hex2char(hex[4*i]&0xf); |
404 | walk[8] = 0x20; |
405 | ++i; |
406 | walk += 9; |
407 | if (!(i&3)) { |
408 | *walk++ = '\n'; |
409 | } |
410 | } |
411 | |
412 | *walk = 0; |
413 | } |
414 | |
415 | static void hex2str8(unsigned char* hex, int size, char* str) |
416 | { |
417 | int i = 0; |
418 | char* walk = str; |
419 | for (;i<size;) |
420 | { |
421 | walk[0 ] = hex2char(hex[8*i+7]>>4); |
422 | walk[1 ] = hex2char(hex[8*i+7]&0xf); |
423 | walk[2 ] = hex2char(hex[8*i+6]>>4); |
424 | walk[3 ] = hex2char(hex[8*i+6]&0xf); |
425 | walk[4 ] = hex2char(hex[8*i+5]>>4); |
426 | walk[5 ] = hex2char(hex[8*i+5]&0xf); |
427 | walk[6 ] = hex2char(hex[8*i+4]>>4); |
428 | walk[7 ] = hex2char(hex[8*i+4]&0xf); |
429 | walk[8 ] = hex2char(hex[8*i+3]>>4); |
430 | walk[9 ] = hex2char(hex[8*i+3]&0xf); |
431 | walk[10] = hex2char(hex[8*i+2]>>4); |
432 | walk[11] = hex2char(hex[8*i+2]&0xf); |
433 | walk[12] = hex2char(hex[8*i+1]>>4); |
434 | walk[13] = hex2char(hex[8*i+1]&0xf); |
435 | walk[14] = hex2char(hex[8*i]>>4); |
436 | walk[15] = hex2char(hex[8*i]&0xf); |
437 | walk[16] = 0x20; |
438 | ++i; |
439 | walk += 17; |
440 | if (!(i&1)) { |
441 | *walk++ = '\n'; |
442 | } |
443 | } |
444 | |
445 | *walk = 0; |
446 | } |
447 | |
448 | static void print_short(const void* buffer, int total) |
449 | { |
450 | int count = total/sizeof(short); |
451 | unique_ptr<char[]> outbuf = make_unique<char[]>(count*5 + count/8 + 32); |
452 | hex2str2((unsigned char*)buffer, count, outbuf.get()); |
453 | printf("%s" , outbuf.get()); |
454 | } |
455 | |
456 | static void print_word(const void* buffer, int total) |
457 | { |
458 | int count = total/sizeof(int); |
459 | unique_ptr<char[]> outbuf = make_unique<char[]>(count*9 + count/4 + 32); |
460 | hex2str4((unsigned char*)buffer, count, outbuf.get()); |
461 | printf("%s" , outbuf.get()); |
462 | } |
463 | |
464 | static void print_dword(const void* buffer, int total) |
465 | { |
466 | int count = total/sizeof(long); |
467 | unique_ptr<char[]> outbuf = make_unique<char[]>(count*17 + count/2 + 32); |
468 | hex2str8((unsigned char*)buffer, count, outbuf.get()); |
469 | printf("%s" , outbuf.get()); |
470 | } |
471 | |
472 | int gdb_mem(int pid, void* base, int len, int group) |
473 | { |
474 | uintptr_t address = (uintptr_t)base; |
475 | unique_ptr<char[]> buffer = make_unique<char[]>(len); |
476 | void* code = buffer.get(); |
477 | int got = read_mem(pid, address, code, len); |
478 | if (got < 1) { |
479 | printf("failed to read memory from:%lx,%d\n" , address, len); |
480 | return -1; |
481 | } |
482 | |
483 | len = got; |
484 | switch(group) { |
485 | case 1: |
486 | print_bytes(code, len); |
487 | break; |
488 | case 2: |
489 | print_short(code, len); |
490 | break; |
491 | case 4: |
492 | print_word(code, len); |
493 | break; |
494 | case 8: |
495 | print_dword(code, len); |
496 | break; |
497 | default: |
498 | break; |
499 | } |
500 | |
501 | return len; |
502 | } |
503 | |
504 | int gdb_reg(int tid, USER_REGS* out) |
505 | { |
506 | USER_REGS regs; |
507 | |
508 | #if defined(__aarch64__) |
509 | static struct iovec io = { |
510 | .iov_base = ®s, |
511 | .iov_len = sizeof(regs) |
512 | }; |
513 | if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &io) < 0) { |
514 | #else |
515 | if (ptrace(PTRACE_GETREGS, tid, nullptr, ®s) < 0) { |
516 | #endif |
517 | return -errno; |
518 | } |
519 | |
520 | #if defined(__i386__) |
521 | #error unspport get_cpu_context |
522 | #elif defined(__x86_64__) |
523 | printf("\trip=%-16llx\n" , regs.rip); |
524 | printf("\trbp=%-16llx\n" , regs.rbp); |
525 | printf("\trsp=%-16llx\n" , regs.rsp); |
526 | |
527 | printf("\trax=%-16llx\n" , regs.rax); |
528 | printf("\trbx=%-16llx\n" , regs.rbx); |
529 | |
530 | printf("\trdi=%-16llx\n" , regs.rdi); |
531 | printf("\trsi=%-16llx\n" , regs.rsi); |
532 | printf("\trdx=%-16llx\n" , regs.rdx); |
533 | printf("\trcx=%-16llx\n" , regs.rcx); |
534 | printf("\tr8=%-16llx\n" , regs.r8); |
535 | printf("\tr9=%-16llx\n" , regs.r9); |
536 | |
537 | printf("\tr10=%-16llx\n" , regs.r10); |
538 | printf("\tr11=%-16llx\n" , regs.r11); |
539 | printf("\tr12=%-16llx\n" , regs.r12); |
540 | printf("\tr13=%-16llx\n" , regs.r13); |
541 | printf("\tr14=%-16llx\n" , regs.r14); |
542 | printf("\tr15=%-16llx\n" , regs.r15); |
543 | #elif defined(__mips__) || defined(__mips64) |
544 | printf("\tat=%-16lx\n" , regs.at); |
545 | printf("\tv0=%-16lx\n" , regs.v0); |
546 | printf("\tv1=%-16lx\n" , regs.v1); |
547 | printf("\ta0=%-16lx\n" , regs.a0); |
548 | printf("\ta1=%-16lx\n" , regs.a1); |
549 | printf("\ta2=%-16lx\n" , regs.a2); |
550 | printf("\ta3=%-16lx\n" , regs.a3); |
551 | |
552 | #if _MIPS_SIM != _ABIO32 |
553 | printf("\ta4=%-16lx\n" , regs.a4); |
554 | printf("\ta5=%-16lx\n" , regs.a5); |
555 | printf("\ta6=%-16lx\n" , regs.a6); |
556 | printf("\ta7=%-16lx\n" , regs.a7); |
557 | printf("\tt0=%-16lx\n" , regs.t0); |
558 | printf("\tt1=%-16lx\n" , regs.t1); |
559 | printf("\tt2=%-16lx\n" , regs.t2); |
560 | printf("\tt3=%-16lx\n" , regs.t3); |
561 | #else /* if _MIPS_SIM == _ABIO32 */ |
562 | printf("\tt0=%-16lx\n" , regs.t0); |
563 | printf("\tt1=%-16lx\n" , regs.t1); |
564 | printf("\tt2=%-16lx\n" , regs.t2); |
565 | printf("\tt3=%-16lx\n" , regs.t3); |
566 | printf("\tt4=%-16lx\n" , regs.t4); |
567 | printf("\tt5=%-16lx\n" , regs.t5); |
568 | printf("\tt6=%-16lx\n" , regs.t6); |
569 | printf("\tt7=%-16lx\n" , regs.t7); |
570 | #endif /* _MIPS_SIM == _ABIO32 */ |
571 | printf("\ts0=%-16lx\n" , regs.s0); |
572 | printf("\ts1=%-16lx\n" , regs.s1); |
573 | printf("\ts2=%-16lx\n" , regs.s2); |
574 | printf("\ts3=%-16lx\n" , regs.s3); |
575 | printf("\ts4=%-16lx\n" , regs.s4); |
576 | printf("\ts5=%-16lx\n" , regs.s5); |
577 | printf("\ts6=%-16lx\n" , regs.s6); |
578 | printf("\ts7=%-16lx\n" , regs.s7); |
579 | printf("\tt8=%-16lx\n" , regs.t8); |
580 | printf("\tt9=%-16lx\n" , regs.t9); |
581 | printf("\tk0=%-16lx\n" , regs.k0); |
582 | printf("\tk1=%-16lx\n" , regs.k1); |
583 | printf("\tgp=%-16lx\n" , regs.gp); |
584 | printf("\tsp=%-16lx\n" , regs.sp); |
585 | printf("\tfp=%-16lx\n" , regs.fp); |
586 | printf("\tra=%-16lx\n" , regs.ra); |
587 | |
588 | /* Saved special registers. */ |
589 | printf("\tlo=%-16lx\n" , regs.lo); |
590 | printf("\thi=%-16lx\n" , regs.hi); |
591 | printf("\tpc=%-16lx\n" , regs.pc); |
592 | printf("\tbadvaddr=%-16lx\n" , regs.cp0_badvaddr); |
593 | printf("\tstatus=%-16lx\n" , regs.cp0_status); |
594 | printf("\tcause=%-16lx\n" , regs.cp0_cause); |
595 | #elif defined(__sw_64) |
596 | printf("\tgp=%-16lx\n" , regs.gp); |
597 | printf("\tsp=%-16lx\n" , regs.sp); |
598 | printf("\tfp=%-16lx\n" , regs.s6); |
599 | printf("\tra=%-16lx\n" , regs.ra); |
600 | printf("\tpc=%-16lx\n" , regs.pc); |
601 | printf("\tt12=%-16lx\n" , regs.t12); |
602 | |
603 | printf("\tv0=%-16lx\n" , regs.v0); |
604 | printf("\ta0=%-16lx\n" , regs.a0); |
605 | printf("\ta1=%-16lx\n" , regs.a1); |
606 | printf("\ta2=%-16lx\n" , regs.a2); |
607 | printf("\ta3=%-16lx\n" , regs.a3); |
608 | printf("\ta4=%-16lx\n" , regs.a4); |
609 | printf("\ta5=%-16lx\n" , regs.a5); |
610 | #elif defined(__aarch64__) |
611 | printf("\tsp=%-16lx\n" , regs.sp); |
612 | printf("\tpc=%-16lx\n" , regs.pc); |
613 | |
614 | printf("\tx0=%-16lx\n" , regs.x0); |
615 | printf("\tx1=%-16lx\n" , regs.x1); |
616 | printf("\tx2=%-16lx\n" , regs.x2); |
617 | printf("\tx3=%-16lx\n" , regs.x3); |
618 | printf("\tx4=%-16lx\n" , regs.x4); |
619 | printf("\tx5=%-16lx\n" , regs.x5); |
620 | #else |
621 | #error unspport get_cpu_context |
622 | #endif |
623 | |
624 | if (out) { |
625 | memcpy(out, ®s, sizeof(regs)); |
626 | } |
627 | |
628 | return 0; |
629 | } |
630 | |
631 | #if defined(__i386__) || defined(__x86_64__) |
632 | #define BREAKPOINT_INSTRUCTION 0xcc |
633 | #define BREAKPOINT_SIZE 1 |
634 | #elif defined(__mips__) |
635 | #define BREAKPOINT_INSTRUCTION 0x0000000d |
636 | #define BREAKPOINT_SIZE 4 |
637 | #elif defined(__sw_64) |
638 | #define BREAKPOINT_INSTRUCTION 0x00000080 |
639 | #define BREAKPOINT_SIZE 4 |
640 | #elif defined(__aarch64__) |
641 | #define BREAKPOINT_INSTRUCTION 0xd4200000 |
642 | #define BREAKPOINT_SIZE 4 |
643 | #else |
644 | #error need implement in new arch |
645 | #endif |
646 | |
647 | int gdb_break(int tid, uintptr_t addr, uint32_t* value) |
648 | { |
649 | uint32_t ret; |
650 | uint32_t cc = BREAKPOINT_INSTRUCTION; |
651 | if (read_mem(tid, addr, &ret, BREAKPOINT_SIZE) != BREAKPOINT_SIZE) { |
652 | return -1; |
653 | } |
654 | if (write_mem(tid, addr, &cc, BREAKPOINT_SIZE) != BREAKPOINT_SIZE) { |
655 | return -2; |
656 | } |
657 | |
658 | if (value) *value = ret; |
659 | |
660 | return 0; |
661 | } |
662 | |
663 | int gdb_delete(int tid, uintptr_t addr, uint32_t old_value) |
664 | { |
665 | return write_mem(tid, addr, &old_value, BREAKPOINT_SIZE); |
666 | } |
667 | |
668 | // gdb_print(pid, base, "/usr/lib/x86_64-linux-gnu/ld-2.24.so", addr, "struct link_map"); |
669 | int gdb_print(int pid, uintptr_t module_base, const char* filename, |
670 | uintptr_t var_address, const char* type_name) |
671 | { |
672 | (void)pid; |
673 | (void)module_base; |
674 | (void)filename; |
675 | (void)var_address; |
676 | (void)type_name; |
677 | SymbolFile helper(module_base, filename, true); |
678 | /* |
679 | http://www.dwarfstd.org/doc/Debugging%20using%20DWARF-2012.pdf |
680 | |
681 | .debug_abbrev Abbreviations used in the .debug_info section |
682 | .debug_aranges A mapping between memory address and compilation |
683 | .debug_frame Call Frame Information |
684 | .debug_info The core DWARF data containing DWARF Information Entries (DIEs) |
685 | .debug_line Line Number Program |
686 | .debug_loc Location descriptions |
687 | .debug_macinfo Macro descriptions |
688 | .debug_pubnames A lookup table for global objects and functions |
689 | .debug_pubtypes A lookup table for global types |
690 | .debug_ranges Address ranges referenced by DIEs |
691 | .debug_str String table used by .debug_info |
692 | .debug_types Type descriptions |
693 | |
694 | for (const auto& cu : helper.m_dwarf.compilation_units()) { |
695 | for (const auto& die : cu.root()) { |
696 | if (die.has(dwarf::DW_AT::name) && at_name(die) == type_name) { |
697 | } |
698 | } |
699 | } |
700 | */ |
701 | |
702 | return 0; |
703 | } |
704 | |