调试器加载被调试程序
1 程序可调试状态
1 程序可调试状态
从调试器的视角来看,正在运行的程序可以分为两类,一类是正常运行的,不受调试器干扰的程序。另一类是处于调试状态的程序,它的每一步运行都在调试器的掌控之下。
让程序处于调试状态大有2种方式,一种是静态加载,即由调试器来启动程序,告知系统,这个程序将要被调试。
第二种是动态加载,即程序正在运行,调试器通过一些系统调用来迫使使得程序处于调试状态。
1.2 gdb 加载被调试程序操作
1) 静态加载,由gdb来启动被调试程序,这种方式常常用在程序还在开发的过程中。
1 | #gdb ./a.out |
2) 动态加载,使用gdb attach子命令 + 调试程序的进程号(每个正在运行的程序在系统中都有一个唯一的标号标识)
假设要调试程序的进程号为 2333 ,则可以使用如下命令进行操作.
1 2 | #gdb (gdb) attach 2333 |
2 MyGdb 实现应用程序代码
Ptrace 暂时就不在这里介绍了,大家可以去看下本博客转载的”玩转ptrace“系列文章。
”玩转ptrace(一)“,”玩转ptrace(二)“.
2.1 MyGdb静态加载应用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /* inferior.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/ptrace.h> int mygdb_inferior(char *program, char **allargs) { int pid = fork(); if (pid < 0) return pid; if (pid == 0) { ptrace(PTRACE_TRACEME, 0, 0, 0); setpgid(0, 0); execv(program, allargs); if (errno == ENOENT) execvp(program, allargs); fprintf(stderr, "Cannot exec %s: %s.\n", program, strerror(errno)); fflush(stderr); exit(0177); } return pid; } int mygdb_attach(unsigned long pid) { if (ptrace(PTRACE_ATTACH, pid, 0, 0) != 0) { /* If we fail to attach to a process, report an error. */ error("Cannot attach to process %ld: %s (%d)\n", pid, strerror(errno), errno); return -1; } return 0; } int mygdb_continue(unsigned long pid) { if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) { /* If we fail to continue to a process, report an error. */ error("Cannot continue process %ld: %s (%d)\n", pid, strerror(errno), errno); return -1; } return 0; } int main(int argc, char *argv[]) { pid_t child; if (argc <= 1) { printf("Usage: ./inferior your_programme\r\n"); printf("Example: ./inferior ./a.out\r\n"); exit(0); } child = mygdb_inferior(argv[1], NULL); if (child < 0) { error("mygdb_inferior: fork error.\r\n"); exit(0); } printf("inferior process success.\r\n"); printf("will run process after sleep 10s.\r\n"); sleep(10); if (mygdb_continue(child) != -1) printf("run process.\r\n"); return 0; } |
将上诉代码保存到本地文件,并取名为inferior.c,使用如下命令编译程序:
1 | gcc inferior.c -o inferior |
2.2 MyGdb动态加载应用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | /* attach.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/ptrace.h> int mygdb_attach(unsigned long pid) { if (ptrace(PTRACE_ATTACH, pid, 0, 0) != 0) { /* If we fail to attach to a process, report an error. */ error("Cannot attach to process %ld: %s (%d)\n", pid, strerror(errno), errno); return -1; } return 0; } int mygdb_continue(unsigned long pid) { if (ptrace(PTRACE_CONT, pid, NULL, NULL) != 0) { /* If we fail to continue to a process, report an error. */ error("Cannot continue process %ld: %s (%d)\n", pid, strerror(errno), errno); return -1; } return 0; } int main(int argc, char *argv[]) { int pid = 0; if (argc <= 1) { printf("Usage: ./attach pid_number\r\n"); printf("Example: ./attach 1111\r\n"); exit(0); } /* get the pid number from arg2 */ pid = strtoul(argv[1], NULL, 0); if (pid <= 0) { printf("please input the valid pid number.\r\n"); exit(0); } if (mygdb_attach(pid) == -1) exit(0); printf("attach process success.\r\n"); printf("will reusme process after sleep 10s.\r\n"); sleep(10); if (mygdb_continue(pid) != -1) printf("reusme process.\r\n"); return 0; } |
将上诉代码保存到本地文件,并取名为attach.c,使用如下命令编译程序:
1 | gcc attach.c -o attach |