linux GDB多进程调试 exec函数族
父子进程之间的关系:
区别:
1.fork()函数的返回值不同
父进程中: >0(栈内存) 返回的子进程ID
子进程中: =0(栈内存)
2.PCB中的一些数据不同
当前进程的PID
当前进程的父进程的ID PPID
信号集不同
共同点:
某些状态下:子进程刚被创建出来,还没有执行任何的写数据的操作
- 用户区的数据
- 文件描述符表
父子进程对变量是不是共享的?
- 刚开始的时候,是一样的,共享的。如果修改了数据,就不共享了
- 读时共享(子进程被创建,父子进程没有做任何写的操作),写时拷贝。
GDB多进程调试
使用 GDB调试的时候,GDB默认只能跟踪一个进程,可以在fork 函数调用之前,通过指令设置 GBD调试工具跟踪父进程或者是跟踪子进程,默认跟踪父进程。
设置调试父进程或者子进程: set follow-fork-mode [ parent(默认) | child]
设置调试模式: set detach-on-fork [on | off]
默认为 on,表示调试当前进程的时候,其他的进程继续运行,如果为 off ,调试当前进程的时候,其他进程 被 GDB挂起
查看调试的进程: info inferiors
切换当前调试的进程: inferior id
使进程脱离 GDB 调试: detach inferiors id
exec函数族
exec 函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用过程的内容,换句话说,就是在调用进程内部执行一个可执行文件。
exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程 ID 等一些表面上的信息仍保持原样。看上去还是旧的躯壳,却已经注入了新的灵魂。只有调用失败了,它们才会返回 -1 ,从原程序的调用点接着往下执行。
内核区不变,用户区调换为新程序的内容
***execl***
1 /* 2 exec函数族: man 3 execl 3 #include <unistd.h> 4 标准C库: 5 ***int execl(const char* path, const char* arg,.../- (char *) NULL -/);*** 6 - 参数: 7 - path:需要指定的执行的文件的路径或者名称 8 a.out(相对路径) | /home/ubuntu/a.out(推荐使用绝对路径) 9 ./a.out hello world 10 - arg:是执行可执行文件所需要的参数列表 11 第一个参数一般没什么作用,为了方便,一般写的是执行的程序的名称 12 从第二个参数开始往后,就是程序执行所需要的参数列表 13 参数最后需要以 NULL 结束(哨兵) 14 - 返回值: 15 只有档调用失败,才会有返回值,返回 -1 并且设置 errno 16 如果调用成功,没有返回值 17 ***int execlp(const char* file, const char* arg,... /- (char *) NULL -/ );*** 18 int execle(const char* path, const char* arg,... /- (char *) NULL, char* const envp[] -/ ); 19 int execv(const char* path, char* const arg[]); 20 int execvp(const char* file, char* const arg[]); 21 int execvpe(const char* file, char* const arg[], char* const envp[]); 22 Linux/Unix: 23 int execve(const char* filename, char* const argv[], char* const envp[]); 24 l(list) 参数地址列表,以空指针结尾 25 v(vector) 存有各参数跌至的指针数组的地址 26 p(path) 按 PATH 环境遍历指定的目录搜索可执行文件 27 e(environment) 存有环境遍历字符串地址的指针数组的地址 28 */ 29 #include <unistd.h> 30 #include <stdio.h> 31 32 int main() 33 { 34 //创建一个子进程,在子进程中执行exec函数族中的函数 35 __pid_t pid = fork(); 36 if(pid > 0) 37 { 38 //父进程 39 printf("i am parent process, pid: %d\n",getpid()); 40 sleep(1); 41 } 42 else if(pid == 0) 43 { 44 //子进程 45 //execl("hello","hello",NULL);//执行了hello可执行程序 46 execl("/usr/bin/ps","ps","aux",NULL);//执行 ps aux 命令 47 printf("i am child process, pid: %d\n",getpid());//不会执行 48 //which ps 找到ps指令的绝对路径 49 } 50 for(int i = 0; i < 3; i++) 51 { 52 printf("i = %d, pid = %d\n",i,getpid()); 53 } 54 return 0; 55 }
***execlp***
1 /* 2 #include <unistd.h> 3 int execlp(const char* file, const char* arg,... /- (char *) NULL -/ ); 4 - 会到环境变量中查找指定的可执行文件,如果找到了就执行,找不到就执行不成功 5 - 参数: 6 - file:需要执行的可执行文件的文件名 7 a.out 8 ps 9 - arg:是执行可执行文件所需要的参数列表 10 第一个参数一般没什么作用,为了方便,一般写的是执行的程序的名称 11 从第二个参数开始往后,就是程序执行所需要的参数列表 12 参数最后需要以 NULL 结束(哨兵) 13 - 返回值: 14 只有档调用失败,才会有返回值,返回 -1 并且设置 errno 15 如果调用成功,没有返回值 16 int execv(const char* path, char* const argv[]); 17 argv是需要的参数的一个字符串数组 18 char* argv[] = {"ps","aux",NULL}; 19 execv("/bin/ps",argv); 20 21 int execve(const char* filename, char* const argv[], char* const envp[]); 22 char* envp[] = {"/home/ubuntu","/home/aaa","home/bbb"}; 23 按顺序找环境变量 24 */ 25 #include <unistd.h> 26 #include <stdio.h> 27 28 int main() 29 { 30 //env 查询环境变量 31 //创建一个子进程,在子进程中执行exec函数族中的函数 32 __pid_t pid = fork(); 33 if(pid > 0) 34 { 35 //父进程 36 printf("i am parent process, pid: %d\n",getpid()); 37 sleep(1); 38 } 39 else if(pid == 0) 40 { 41 //子进程 42 execlp("ps","ps","aux",NULL);//正常执行 43 } 44 for(int i = 0; i < 3; i++) 45 { 46 printf("i = %d, pid = %d\n",i,getpid()); 47 } 48 return 0; 49 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)