| 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 |  |