├── debuggee.c ├── Makefile ├── tdb.h └── tdb.c /debuggee.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | static int graph = 0; 7 | 8 | int test(); 9 | 10 | int main(int argc, char *argv[]) { 11 | test(); 12 | exit(0); 13 | } 14 | 15 | int test() { 16 | while(1) { 17 | printf(" hello world\n"); 18 | sleep(1); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | LD = gcc 3 | CFLAGS = -Wall -g 4 | LDFLAGS = -g -ldisasm 5 | SRC = tdb.c 6 | OBJ = tdb.o 7 | 8 | .c.o: 9 | $(CC) $(CFLAGS) -c $< 10 | 11 | tdb: $(OBJ) 12 | $(LD) $(LDFLAGS) -o $@ $(OBJ) 13 | 14 | debuggee: debuggee.o 15 | $(CC) $(CFLAGS) -o $@ $< 16 | 17 | clean: 18 | rm -f tdb 19 | rm -f *.obj 20 | rm -f *.o 21 | rm -f *.BAK 22 | rm -f *.asm 23 | -------------------------------------------------------------------------------- /tdb.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _TDB_H 3 | #define _TDB_H 4 | 5 | union u_data { 6 | unsigned long val; 7 | char bytes[sizeof(unsigned long)]; 8 | }; 9 | 10 | #ifdef __USE_SOFTWARE_BP 11 | struct tdb_breakpoint { 12 | long address_mask[0x1000 / sizeof(unsigned long)]; 13 | }; 14 | #endif 15 | #ifdef __USE_HARDWARE_BP 16 | struct tdb_breakpoint { 17 | int valid; 18 | int backupcode_size; 19 | union u_data backupcode; 20 | unsigned long address; 21 | }; 22 | #endif 23 | 24 | #endif 25 | 26 | -------------------------------------------------------------------------------- /tdb.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | //#define __USE_SOFTWARE_BP 17 | #define __USE_HARDWARE_BP 18 | 19 | #include "tdb.h" 20 | 21 | #define DEBUGGER_BANNER "tdb" 22 | #define CMDLINE_LEN 256 23 | 24 | #define TDBG_CONTINUE 1 25 | #define TDBG_STEP 2 26 | #define TDBG_DONOTHING 3 27 | #define TDBG_EXIT -1 28 | 29 | static const char *delim = " "; 30 | 31 | #ifdef __USE_SOFTWARE_BP 32 | void set_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table); 33 | void clear_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table); 34 | int check_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table); 35 | 36 | int set_break_point(unsigned long address); 37 | int clear_break_point(unsigned long address); 38 | int check_break_point(unsigned long address); 39 | 40 | void print_address_mask(unsigned long bptable_num, 41 | struct tdb_breakpoint *bp); 42 | 43 | void enum_bp_list(void); 44 | void init_bptable(void); 45 | void free_all_bptable(void); 46 | #endif 47 | 48 | #ifdef __USE_HARDWARE_BP 49 | int set_break_point(pid_t child, unsigned long address); 50 | void clear_break_point(pid_t child, int bp_num); 51 | struct tdb_breakpoint *check_break_point(unsigned long address); 52 | 53 | void enum_bp_list(void); 54 | void init_bptable(pid_t child); 55 | void free_all_bptable(pid_t child); 56 | #endif 57 | 58 | void readdata(pid_t child, unsigned long addr, char *str, int len); 59 | void writedata(pid_t child, unsigned long addr, char *str, int len); 60 | 61 | int dump_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 62 | int exit_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 63 | int step_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 64 | int cont_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 65 | int show_help(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 66 | int break_point(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 67 | int enum_bp(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 68 | int disasm_range(pid_t child, int status, struct user_regs_struct *regs, char **tkptr); 69 | 70 | struct tdb_commands { 71 | char *command_name; 72 | char *alias; 73 | char *guide; 74 | int (*func)(pid_t, int, struct user_regs_struct*, char**); 75 | } cmd_resources[] = { 76 | {"c", 77 | "continue", 78 | "Continue executing until next break point/watchpoint.", 79 | cont_debug 80 | }, 81 | {"s", 82 | "step", 83 | "Step to next line of code. Will step into a function.", 84 | step_debug 85 | }, 86 | {"r", 87 | "register", 88 | "List registers in use.", 89 | dump_debug 90 | }, 91 | {"h", 92 | "help", 93 | "List tdb command topics.", 94 | show_help 95 | }, 96 | {"q", 97 | "quit", 98 | "Exit tdb debugger.", 99 | exit_debug 100 | }, 101 | {"b", 102 | "break", 103 | "Making program stop at certain points.", 104 | break_point 105 | }, 106 | {"l", 107 | "listbp", 108 | "List breakpoints in valid.", 109 | enum_bp 110 | }, 111 | {"d", 112 | "disasm", 113 | "Disassemble a specified section of memory.", 114 | disasm_range 115 | } 116 | }; 117 | 118 | static int numofcmd = 119 | sizeof(cmd_resources) / sizeof(struct tdb_commands); 120 | 121 | static const int long_size = sizeof(unsigned long); 122 | 123 | #define DUMP_GENREG(name, val) \ 124 | printf("%s 0x%08lx %15ld\n", #name, (val), (val)); 125 | 126 | #define DUMP_SEGREG(name, val) \ 127 | printf("%s 0x%04x %15d\n", #name, (val), (val)); 128 | 129 | int dump_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 130 | { 131 | DUMP_GENREG(eax, regs->eax); DUMP_GENREG(ecx, regs->ecx); 132 | DUMP_GENREG(edx, regs->edx); DUMP_GENREG(ebp, regs->ebx); 133 | DUMP_GENREG(esp, regs->esp); DUMP_GENREG(ebp, regs->ebp); 134 | DUMP_GENREG(esi, regs->esi); DUMP_GENREG(edi, regs->edi); 135 | 136 | printf("eip 0x%04lx 0x%04lx <>\n", regs->eip, regs->eip); 137 | printf("eflags 0x%lx\n", regs->eflags); 138 | 139 | DUMP_SEGREG(cs, regs->cs); DUMP_SEGREG(ss, regs->ss); 140 | DUMP_SEGREG(ds, regs->ds); DUMP_SEGREG(es, regs->es); 141 | DUMP_SEGREG(fs, regs->fs); DUMP_SEGREG(gs, regs->gs); 142 | 143 | return TDBG_DONOTHING; 144 | } 145 | 146 | int exit_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 147 | { 148 | return TDBG_EXIT; 149 | } 150 | 151 | int step_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 152 | { 153 | return TDBG_STEP; 154 | } 155 | 156 | int cont_debug(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 157 | { 158 | return TDBG_CONTINUE; 159 | } 160 | 161 | int show_help(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 162 | { 163 | int i; 164 | 165 | for (i = 0 ; i < numofcmd ; i++) { 166 | printf(" %s %s -- %s\n", 167 | cmd_resources[i].command_name, 168 | cmd_resources[i].alias, 169 | cmd_resources[i].guide); 170 | } 171 | 172 | return TDBG_DONOTHING; 173 | } 174 | 175 | int break_point(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 176 | { 177 | char *tp = strtok_r(NULL, delim, tkptr); 178 | 179 | int radix = 10; 180 | unsigned long bp_address; 181 | 182 | if (tp == NULL) { 183 | goto error; 184 | } 185 | 186 | if (strlen(tp) > 2) { 187 | if (tp[0] == '0' && tp[1] == 'x') { 188 | radix = 16; 189 | tp += 2; 190 | } 191 | } 192 | 193 | bp_address = strtoul(tp, NULL, radix); 194 | // if (errno == ERANGE) { 195 | // goto error; 196 | // } 197 | 198 | #ifdef __USE_SOFTWARE_BP 199 | set_break_point(bp_address); 200 | #endif 201 | 202 | #ifdef __USE_HARDWARE_BP 203 | set_break_point(child, bp_address); 204 | #endif 205 | 206 | return TDBG_DONOTHING; 207 | 208 | error: 209 | printf("invalid address\n"); 210 | return TDBG_DONOTHING; 211 | } 212 | 213 | int enum_bp(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 214 | { 215 | enum_bp_list(); 216 | return TDBG_DONOTHING; 217 | } 218 | 219 | int disasm_range(pid_t child, int status, struct user_regs_struct *regs, char **tkptr) 220 | { 221 | } 222 | 223 | #ifdef __USE_SOFTWARE_BP 224 | 225 | #define BPTABLE_SHIFT 12 226 | #define BPTABLE_SIZE (1UL << BPTABLE_SHIFT) 227 | #define BPTABLE_MASK (~(BPTABLE_SIZE - 1)) 228 | 229 | #define BPTABLE_PDE(x) ((x) >> 22) 230 | #define BPTABLE_PTE(x) (((x) >> 12) & 0x3ff) 231 | #define PAGE_NUM(pde, pte) (((pde) << 22) | ((pte) << 12)) 232 | 233 | static int enable_bp = 0; 234 | static struct tdb_breakpoint *tdb_bp_table[1024] = { NULL }; 235 | static const int bpte_of_num = sizeof(tdb_bp_table) / sizeof(struct tdb_breakpoint*); 236 | 237 | void set_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table) 238 | { 239 | unsigned long val = 1 << (address % sizeof(unsigned long)); 240 | bp_table->address_mask[(address & ~BPTABLE_MASK) / sizeof(unsigned long)] |= val; 241 | } 242 | 243 | void clear_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table) 244 | { 245 | unsigned long val = 1 << (address % sizeof(unsigned long)); 246 | bp_table->address_mask[(address & ~BPTABLE_MASK) / sizeof(unsigned long)] &= ~val; 247 | } 248 | 249 | int check_tdbp_bit(unsigned long address, struct tdb_breakpoint *bp_table) 250 | { 251 | unsigned long val = 1 << (address % sizeof(unsigned long)); 252 | return bp_table->address_mask[(address & ~BPTABLE_MASK) / sizeof(unsigned long)] & val; 253 | } 254 | 255 | int set_break_point(unsigned long address) 256 | { 257 | struct tdb_breakpoint *bp = tdb_bp_table[BPTABLE_PDE(address)]; 258 | 259 | enable_bp = 1; 260 | 261 | if (bp == NULL) { 262 | tdb_bp_table[BPTABLE_PDE(address)] = malloc(sizeof(struct tdb_breakpoint) * 1024); 263 | bp = tdb_bp_table[BPTABLE_PDE(address)]; 264 | memset(bp, 0, sizeof(struct tdb_breakpoint) * 1024); 265 | } 266 | 267 | set_tdbp_bit(address, &bp[BPTABLE_PTE(address)]); 268 | 269 | return 1; 270 | } 271 | 272 | int clear_break_point(unsigned long address) 273 | { 274 | struct tdb_breakpoint *bp = tdb_bp_table[BPTABLE_PDE(address)]; 275 | 276 | if (bp == NULL) { 277 | return 0; 278 | } else { 279 | clear_tdbp_bit(address, &bp[BPTABLE_PTE(address)]); 280 | } 281 | 282 | return 1; 283 | } 284 | 285 | int check_break_point(unsigned long address) 286 | { 287 | struct tdb_breakpoint *bp = tdb_bp_table[BPTABLE_PDE(address)]; 288 | if (bp == NULL) { 289 | return 0; 290 | } 291 | return check_tdbp_bit(address, &bp[BPTABLE_PTE(address)]); 292 | } 293 | 294 | void print_address_mask(unsigned long bptable_num, 295 | struct tdb_breakpoint *bp) 296 | { 297 | int i, j; 298 | unsigned long bp_address, mask; 299 | 300 | for (i = 0 ; i < (0x1000 / sizeof(unsigned long)) ; i++) { 301 | if (bp->address_mask[i]) { 302 | mask = bp->address_mask[i]; 303 | for (j = 0 ; j < (sizeof(unsigned long) * 8) ; j++) { 304 | if ((mask >> j) & 1) { 305 | bp_address = bptable_num | (sizeof(unsigned long) * i + j); 306 | printf(" 0x%08lx\n", bp_address); 307 | } 308 | } 309 | } 310 | } 311 | } 312 | 313 | void enum_bp_list(void) 314 | { 315 | int i = 0; 316 | for ( ; i < bpte_of_num ; i++ ) { 317 | if (tdb_bp_table[i] != NULL) { 318 | struct tdb_breakpoint *bp = tdb_bp_table[i]; 319 | int j = 0; 320 | for ( ; j < 1024 ; j++ ) { 321 | print_address_mask(PAGE_NUM(i, j), &bp[j]); 322 | } 323 | } 324 | } 325 | } 326 | 327 | void init_bptable(void) 328 | { 329 | int i = 0; 330 | 331 | for ( ; i < bpte_of_num ; i++ ) { 332 | if (tdb_bp_table[i] != NULL) { 333 | free(tdb_bp_table[i]); 334 | } else { 335 | tdb_bp_table[i] = NULL; 336 | } 337 | } 338 | 339 | return; 340 | } 341 | 342 | void free_all_bptable(void) 343 | { 344 | int i = 0; 345 | 346 | for ( ; i < bpte_of_num ; i++ ) { 347 | if (tdb_bp_table[i] != NULL) { 348 | free(tdb_bp_table[i]); 349 | } 350 | } 351 | 352 | return; 353 | } 354 | #endif 355 | #ifdef __USE_HARDWARE_BP 356 | static struct tdb_breakpoint tdb_bp_table[1024]; 357 | static const int bpte_of_num = sizeof(tdb_bp_table) / sizeof(struct tdb_breakpoint); 358 | static int enable_bp = 0; 359 | 360 | /* int3 */ 361 | static char dbg_code[] = {0xcc}; 362 | 363 | int inject_int3(pid_t child, unsigned long addr, 364 | char *backup_code, int backupcode_size) 365 | { 366 | 367 | readdata(child, addr, backup_code, backupcode_size); 368 | writedata(child, addr, dbg_code, sizeof(dbg_code)); 369 | 370 | return 1; 371 | } 372 | 373 | int set_break_point(pid_t child, unsigned long address) 374 | { 375 | int i; 376 | 377 | enable_bp = 1; 378 | 379 | for (i = 0 ; i < bpte_of_num ; i++) { 380 | if (tdb_bp_table[i].valid == -1) { 381 | tdb_bp_table[i].valid = 1; 382 | tdb_bp_table[i].address = address; 383 | tdb_bp_table[i].backupcode.val = 0; 384 | tdb_bp_table[i].backupcode_size = sizeof(dbg_code); 385 | 386 | inject_int3(child, address, 387 | tdb_bp_table[i].backupcode.bytes, 388 | tdb_bp_table[i].backupcode_size); 389 | 390 | printf("Setting break point 0x%08lx -- 0x%08lx\n", 391 | tdb_bp_table[i].address, 392 | tdb_bp_table[i].backupcode.val); 393 | 394 | return i; 395 | } 396 | } 397 | return -1; 398 | } 399 | 400 | void clear_break_point(pid_t child, int bp_num) 401 | { 402 | if (tdb_bp_table[bp_num].valid > 0) { 403 | writedata(child, 404 | tdb_bp_table[bp_num].address, 405 | tdb_bp_table[bp_num].backupcode.bytes, 406 | tdb_bp_table[bp_num].backupcode_size); 407 | tdb_bp_table[bp_num].valid = -1; 408 | } 409 | } 410 | 411 | struct tdb_breakpoint *check_break_point(unsigned long address) 412 | { 413 | int i; 414 | 415 | for (i = 0 ; i < bpte_of_num ; i++) { 416 | if (tdb_bp_table[i].valid > 0 && 417 | tdb_bp_table[i].address == address) { 418 | return &tdb_bp_table[i]; 419 | } 420 | } 421 | 422 | return NULL; 423 | } 424 | 425 | void enum_bp_list(void) 426 | { 427 | int i; 428 | for (i = 0 ; i < bpte_of_num ; i++) { 429 | if (tdb_bp_table[i].valid > 0) { 430 | printf(" [%d] -- 0x%08lx\n", i, tdb_bp_table[i].address); 431 | } 432 | } 433 | } 434 | 435 | void init_bptable(pid_t child) 436 | { 437 | int i; 438 | for (i = 0 ; i < bpte_of_num ; i++ ) { 439 | if (tdb_bp_table[i].valid > 0) { 440 | writedata(child, 441 | tdb_bp_table[i].address, 442 | tdb_bp_table[i].backupcode.bytes, 443 | tdb_bp_table[i].backupcode_size); 444 | } 445 | tdb_bp_table[i].valid = -1; 446 | } 447 | 448 | enable_bp = 0; 449 | 450 | return; 451 | } 452 | 453 | void free_all_bptable(pid_t child) 454 | { 455 | enable_bp = 0; 456 | } 457 | 458 | void restore_breakpoint(pid_t child, int bp_num) 459 | { 460 | 461 | if (bp_num < 0) { 462 | return; 463 | } 464 | 465 | if (tdb_bp_table[bp_num].valid > 0) { 466 | inject_int3(child, tdb_bp_table[bp_num].address, 467 | tdb_bp_table[bp_num].backupcode.bytes, 468 | tdb_bp_table[bp_num].backupcode_size); 469 | } 470 | } 471 | 472 | void restore_inst(pid_t child, struct tdb_breakpoint *bp) 473 | { 474 | writedata(child, bp->address, bp->backupcode.bytes, 475 | bp->backupcode_size); 476 | } 477 | #endif 478 | 479 | void readdata(pid_t child, unsigned long addr, char *str, int len) 480 | { 481 | int i = 0; 482 | int j = len / long_size; 483 | char *laddr = str; 484 | union u_data data; 485 | 486 | while (i < j) { 487 | data.val = ptrace(PTRACE_PEEKDATA, child, addr + i * 4, NULL); 488 | memcpy(laddr, data.bytes, long_size); 489 | ++i; 490 | laddr += long_size; 491 | } 492 | 493 | j = len % long_size; 494 | if (j != 0) { 495 | data.val = ptrace(PTRACE_PEEKDATA, child, addr + i * 4, NULL); 496 | memcpy(laddr, data.bytes, j); 497 | } 498 | 499 | str[len] = '\0'; 500 | } 501 | 502 | /* bug */ 503 | void writedata(pid_t child, unsigned long addr, char *str, int len) 504 | { 505 | int i = 0; 506 | int j = len / long_size; 507 | char *laddr = str; 508 | union u_data data; 509 | 510 | while (i < j) { 511 | memcpy(data.bytes, laddr, long_size); 512 | ptrace(PTRACE_POKEDATA, child, addr + i * 4, data.val); 513 | ++i; 514 | laddr += long_size; 515 | } 516 | 517 | j = len % long_size; 518 | if (j != 0) { 519 | union u_data mask; 520 | mask.val = ptrace(PTRACE_PEEKDATA, child, addr + i * 4, NULL); 521 | memcpy(mask.bytes, laddr, j); 522 | ptrace(PTRACE_POKEDATA, child, addr + i * 4, mask.val); 523 | } 524 | } 525 | 526 | int x86_dump_asm(pid_t child, unsigned long address, int view) 527 | { 528 | char line[CMDLINE_LEN]; 529 | char buf[20]; 530 | int pos = 0; 531 | int size; 532 | x86_insn_t insn; 533 | 534 | readdata(child, address, buf, sizeof(buf)); 535 | 536 | x86_init(opt_none, NULL, NULL); 537 | 538 | size = x86_disasm(buf, sizeof(buf), 0, pos, &insn); 539 | if (size) { 540 | x86_format_insn(&insn, line, CMDLINE_LEN, intel_syntax); 541 | if (view) { 542 | printf("<0x%08lx> - %s\n", address, line); 543 | } 544 | pos += size; 545 | } 546 | 547 | x86_cleanup(); 548 | 549 | return pos; 550 | } 551 | 552 | int dbg_repl(pid_t child, int status, struct user_regs_struct *regs) 553 | { 554 | char cmdline[CMDLINE_LEN]; 555 | char *tp; 556 | int ret, i; 557 | char *saveptr; 558 | 559 | do { 560 | ret = TDBG_DONOTHING; 561 | 562 | if (fgets(cmdline, CMDLINE_LEN, stdin) == NULL) { 563 | perror("fgets"); 564 | return 0; 565 | } 566 | 567 | if (cmdline[0] == '\n') { 568 | continue; 569 | } 570 | 571 | cmdline[strlen(cmdline)-1] = '\0'; 572 | tp = strtok_r(cmdline, delim, &saveptr); 573 | 574 | for (i = 0 ; i < numofcmd ; i++) { 575 | char *cmd = cmd_resources[i].command_name; 576 | char *alias = cmd_resources[i].alias; 577 | 578 | if (strcmp(cmd, tp) == 0 || strcmp(alias, tp) == 0) { 579 | printf("Command: %s\n", tp); 580 | ret = cmd_resources[i].func(child, status, regs, &saveptr); 581 | break; 582 | } 583 | } 584 | 585 | if (i >= numofcmd) { 586 | printf("Can't recognize command: %s\n", cmdline); 587 | } 588 | 589 | } while (ret == TDBG_DONOTHING); 590 | 591 | return ret; 592 | } 593 | 594 | void signal_handler(int sig) 595 | { 596 | //printf("Process %ld received signal %d\n", (long)getpid(), sig); 597 | } 598 | 599 | int set_next_action(pid_t child, int action_type) 600 | { 601 | switch (action_type) { 602 | case TDBG_CONTINUE: 603 | #ifdef __USE_SOFTWARE_BP 604 | ptrace(PTRACE_SINGLESTEP, child, NULL, NULL); 605 | #endif 606 | #ifdef __USE_HARDWARE_BP 607 | ptrace(PTRACE_CONT, child, NULL, NULL); 608 | #endif 609 | break; 610 | 611 | case TDBG_STEP: 612 | ptrace(PTRACE_SINGLESTEP, child, NULL, NULL); 613 | break; 614 | 615 | case TDBG_EXIT: 616 | break; 617 | 618 | default: 619 | break; 620 | } 621 | 622 | return 0; 623 | } 624 | 625 | void execute_debugger(void) 626 | { 627 | int status = 0; 628 | int next_action = TDBG_STEP; 629 | pid_t child; 630 | struct user_regs_struct regs; 631 | 632 | printf("In debugger process %ld\n", (long)getpid()); 633 | 634 | /* if (signal(SIGCHLD, signal_handler) == SIG_ERR) { */ 635 | /* perror("signal"); */ 636 | /* exit(-1); */ 637 | /* } */ 638 | 639 | do { 640 | int need_console = 0; 641 | 642 | static int inst_size = 0; 643 | #ifdef __USE_HARDWARE_BP 644 | struct tdb_breakpoint *bp = NULL; 645 | static struct tdb_breakpoint *reset_bp = NULL; 646 | static struct tdb_breakpoint restore_bp; 647 | static int need_restore = 0; 648 | #endif 649 | 650 | child = wait(&status); 651 | ptrace(PTRACE_GETREGS, child, NULL, ®s); 652 | 653 | if (WIFSTOPPED(status)) { 654 | if (WSTOPSIG(status) == SIGTRAP) { 655 | need_console = (next_action == TDBG_STEP) ? 1 : 0; 656 | #ifdef __USE_SOFTWARE_BP 657 | if (enable_bp && check_break_point(regs.eip)) { 658 | printf("Hit break point (eip: 0x%08lx)\n", regs.eip); 659 | need_console = 1; 660 | } 661 | #endif 662 | #ifdef __USE_HARDWARE_BP 663 | if (enable_bp) { 664 | need_console = 1; 665 | regs.eip -= 1; /* int3 */ 666 | bp = check_break_point(regs.eip); 667 | 668 | if (bp != NULL) { 669 | printf("Hit break point (eip: 0x%08lx)\n", regs.eip); 670 | /* write back old instruction */ 671 | restore_inst(child, bp); 672 | 673 | reset_bp = bp; 674 | need_restore = 1; 675 | } else if (need_restore && restore_bp.valid) { 676 | /* ブレークポイント復帰用のブレークポイントを削除 */ 677 | restore_inst(child, &restore_bp); 678 | 679 | /* ブレークポイント復帰 */ 680 | inject_int3(child, 681 | reset_bp->address, 682 | reset_bp->backupcode.bytes, 683 | reset_bp->backupcode_size); 684 | 685 | restore_bp.valid = -1; 686 | need_console = need_restore = 0; 687 | inst_size = x86_dump_asm(child, regs.eip, 0); 688 | } 689 | } 690 | #endif 691 | } else if (WSTOPSIG(status) == SIGSEGV) { 692 | printf("Segmentation fault\n"); 693 | } else { 694 | printf("debuggee has stopped due to signal %d\n", WSTOPSIG(status)); 695 | } 696 | } 697 | 698 | if (WIFSIGNALED(status)) { 699 | printf("debuggee %d received signal %d\n", (int)child, WTERMSIG(status)); 700 | need_console = 1; 701 | } 702 | 703 | if (need_console) { 704 | printf("The process stopped, putting back debuggee\n"); 705 | printf("Enter to show manual\n"); 706 | inst_size = x86_dump_asm(child, regs.eip, 1); 707 | next_action = dbg_repl(child, status, ®s); 708 | } else { 709 | next_action = TDBG_CONTINUE; 710 | } 711 | 712 | #ifdef __USE_HARDWARE_BP 713 | if (need_restore) { 714 | /* ブレークポイント復帰用のブレークポイントを設定 */ 715 | restore_bp.valid = 1; 716 | restore_bp.address = regs.eip + inst_size; 717 | restore_bp.backupcode.val = 0; 718 | restore_bp.backupcode_size = sizeof(dbg_code); 719 | 720 | inject_int3(child, 721 | restore_bp.address, 722 | restore_bp.backupcode.bytes, 723 | restore_bp.backupcode_size); 724 | } 725 | #endif 726 | 727 | ptrace(PTRACE_SETREGS, child, NULL, ®s); 728 | 729 | /* set next action */ 730 | set_next_action(child, next_action); 731 | 732 | } while (!WIFEXITED(status)); 733 | 734 | if (WIFEXITED(status)) { 735 | int exit_status = WEXITSTATUS(status); 736 | printf("Program exited with status (%d)\n", exit_status); 737 | } 738 | 739 | return; 740 | } 741 | 742 | void execute_debuggee(void) 743 | { 744 | char* argv[] = { "/tmp", NULL }; 745 | char* envp[] = { NULL }; 746 | 747 | printf("In debuggie process %ld\n", (long)getpid()); 748 | 749 | if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) { 750 | perror("ptrace"); 751 | return; 752 | } 753 | 754 | execve("./debuggee", argv, envp); 755 | } 756 | 757 | void test_bp(void) 758 | { 759 | #ifdef __USE_SOFTWARE_BP 760 | printf("BPTABLE_SIZE: %ld\n", BPTABLE_SIZE); 761 | printf("BPTABLE_MASK: 0x%08lx\n", (~(BPTABLE_SIZE - 1))); 762 | 763 | printf("test init bp\n"); 764 | init_bptable(); 765 | printf("done\n"); 766 | 767 | printf("test setting bp\n"); 768 | set_break_point(0x10203040); 769 | set_break_point(0xffffffff); 770 | set_break_point(0x11111111); 771 | set_break_point(0x22222222); 772 | set_break_point(0x43dafe43); 773 | printf("done\n"); 774 | 775 | printf(" pretty print bp list\n"); 776 | enum_bp_list(); 777 | printf("done\n"); 778 | 779 | printf("all clear bp"); 780 | clear_break_point(0x10203040); 781 | clear_break_point(0xffffff00); 782 | clear_break_point(0x11111111); 783 | clear_break_point(0x22222220); 784 | clear_break_point(0x43dafe00); 785 | printf("done\n"); 786 | 787 | printf(" pretty print bp list\n"); 788 | enum_bp_list(); 789 | printf("done\n"); 790 | 791 | printf(" free al bp\n"); 792 | free_all_bptable(); 793 | printf("done\n"); 794 | #endif 795 | return; 796 | } 797 | 798 | int main(int argc, char *argv[]) 799 | { 800 | pid_t child; 801 | 802 | // test_bp(); 803 | 804 | child = fork(); 805 | if (child == 0) { 806 | /* child process */ 807 | execute_debuggee(); 808 | } else if (child > 0) { 809 | 810 | #ifdef __USE_SOFTWARE_BP 811 | init_bptable(); 812 | #endif 813 | #ifdef __USE_HARDWARE_BP 814 | init_bptable(child); 815 | #endif 816 | 817 | /* debugger process */ 818 | execute_debugger(); 819 | 820 | #ifdef __USE_SOFTWARE_BP 821 | free_all_bptable(); 822 | #endif 823 | #ifdef __USE_HARDWARE_BP 824 | free_all_bptable(child); 825 | #endif 826 | 827 | } else { 828 | perror("fork"); 829 | return -1; 830 | } 831 | 832 | return 0; 833 | } 834 | 835 | --------------------------------------------------------------------------------