标签:gdb调试 写入 开始 kill 机制 auth 进程终止 clu 原因
该信号在终端挂起或控制进程终止时发出,那可以通过在终端中运行进程,然后关闭终端来实现。
代码如下:
1 /** 2 * filename: signal_1.c 3 * author: Suzkfly 4 * date: 2021-02-15 5 * platform: Ubuntu 6 * 操作步骤: 7 * 1. 编译程序,生成可执行文件a.out; 8 * 2. 执行a.out; 9 * 3. 另开一个终端,输入ps -aux命令,可以看到有一个通过a.out命令创建的进程, 10 * 能看到进程ID,假设进程ID为3991(最后要通过这个ID来杀死进程); 11 * 4. 用鼠标关掉开启进程的终端,点击窗口左上角的“X”,然后Close Terminal; 12 * 5. 在刚刚使用ps -aux命令的终端上再次执行ps -aux命令,可以看到该进程还在; 13 * 6. 进到程序指定的路径中,用ls命令可以看到里面多了一个test.txt文件,用vi 14 * 查看可以发现里面的内容正是程序写入的内容; 15 * 7. 杀死进程,通过命令kill -9 3991 (这个3991是进程ID号,根据实际情况而定) 16 */ 17 #include <stdio.h> 18 #include <fcntl.h> 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 #include <signal.h> 22 #include <string.h> 23 24 #define PATH "/home/linux/zkf/test/signal/1/test.txt" 25 26 /* 自定义信号处理函数 */ 27 void func(int sig) 28 { 29 FILE *fp = NULL; 30 char buf[128] = { 0 }; 31 32 switch (sig) { 33 case SIGHUP : /* 将数据写入文件中 */ 34 sprintf(buf, "SIGHUP signal captured. value = %d\n", sig); 35 fp = fopen(PATH, "w"); 36 fwrite(buf, 1, strlen(buf), fp); 37 fclose(fp); 38 break; 39 } 40 } 41 42 int main(int argc, const char *argv[]) 43 { 44 int fd = 0; 45 void (*p)(int); /* 定义一个函数指针 */ 46 47 p = signal(SIGHUP, func); 48 printf("p = %p\n", p); 49 while (1) { 50 sleep(5); 51 } 52 53 return 0; 54 }
操作步骤:
1. 编译程序,生成可执行文件a.out;
2. 执行a.out;
3. 另开一个终端,输入ps -aux命令,可以看到有一个通过a.out命令创建的进程,进程ID为3991
4. 用鼠标关掉开启进程的终端,点击窗口左上角的“X”,然后Close Terminal,如下图:
5. 在刚刚使用ps -aux命令的终端上再次执行ps -aux命令,可以看到该进程还在;
6. 进到程序指定的路径中,用ls命令可以看到里面多了一个test.txt文件,用vi查看可以发现里面的内容正是程序写入的内容
7. 杀死进程,通过命令kill -9 3991 (这个3991是进程ID号,根据实际情况而定)
该信号在上篇博客中验证了,在此不再赘述。
该信号与SIGINT类似,但是由 Ctrl+\ 产生的,将SIGINT的代码稍微改一下,如下:
1 /** 2 * filename: signal_3.c 3 * author: Suzkfly 4 * date: 2021-02-15 5 * platform: Ubuntu 6 * 操作步骤: 7 * 修改MODE的值为1,2,3,执行程序时按下Ctrl+\,观察结果。 8 */ 9 #include <stdio.h> 10 #include <fcntl.h> 11 #include <sys/types.h> 12 #include <sys/stat.h> 13 #include <signal.h> 14 15 #define MODE 3 16 17 /* 自定义信号处理函数 */ 18 void func(int sig) 19 { 20 if (sig == SIGQUIT) { 21 printf("SIGQUIT signal captured\n"); 22 } 23 } 24 25 int main(int argc, const char *argv[]) 26 { 27 int fd = 0; 28 void (*p)(int); /* 定义一个函数指针 */ 29 30 printf("MODE = %d\n", MODE); 31 #if (MODE == 1) /* 忽略 */ 32 printf("SIG_IGN = %p\n", SIG_IGN); 33 p = signal(SIGQUIT, SIG_IGN); 34 printf("p = %p\n", p); 35 p = signal(SIGQUIT, SIG_IGN); 36 printf("p = %p\n", p); 37 #elif (MODE == 2) /* 默认 */ 38 printf("SIG_DFL = %p\n", SIG_DFL); 39 p = signal(SIGQUIT, SIG_DFL); 40 printf("p = %p\n", p); 41 p = signal(SIGQUIT, SIG_DFL); 42 printf("p = %p\n", p); 43 #elif (MODE == 3) /* 自定义 */ 44 printf("func = %p\n", func); 45 p = signal(SIGQUIT, func); 46 printf("p = %p\n", p); 47 p = signal(SIGQUIT, func); 48 printf("p = %p\n", p); 49 #endif 50 51 while (1) { 52 sleep(5); 53 printf("running...\n"); 54 } 55 56 return 0; 57 }
运行结果:
结果分析:
当MODE为1时,按下 Ctrl+\ 程序不会终止,需要按 Ctrl+C 才会终止,当MODE为2时按下 Ctrl+\ 程序就会终止,当MODE为3时,按下 Ctrl+\ 会执行自己定义的函数,同时能看到SIGQUIT信号也能唤醒进程。那么看上去SIGQUIT与SIGINT的区别就是SIGQUIT会进行Core dump,并且在MODE为2时按下 Ctrl+\ 也能看到提示了(core dumped),然而我在该路径下没有看到core文件,这就不知道为啥了,也许涉及到了我的知识盲区,暂时先搁一边。(已经配置过了ulimit,并且用操作空指针的方法造成段错误,这样在该路径下能够生成core文件,这应该能说明ulimit配置是没问题的)。
导致该信号的原因为非法指令,也就是说可执行文件的指令有问题,这个复现起来有点难,如果编译器没问题的话,编译出来的可执行文件就不会有问题。然鹅程序运行时的指令不一定就是它这个编译器编译出来的啊,这不是还有库文件吗,而且必须用动态库。那么复现SIGILL信号的思路就很清晰了,让一个程序链接到某个动态库,然后在运行程序的时候换掉那个动态库,这不就能导致非法指令了吗。我开始的思路是我在Ubuntu下运行程序,在运行过程中将库文件换成用arm-linux-gcc编译出来的库,但是并没有收到SIGILL信号,而是收到了SIGSEGV信号(无效的内存参考),那看来程序在运行时加载到了arm-linux-gcc的库,而那条指令刚好就是Ubuntu的内存操作指令,真是瞎猫碰上死耗子。为了确保收到SIGILL信号,我制作了一个6K的文件,该文件里面全是0xFF,全是0xFF的指令应该不存在吧。
生成该文件的代码如下:
1 #include <sys/types.h> 2 #include <sys/stat.h> 3 #include <signal.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 int main(int argc, const char *argv[]) 8 { 9 int fd = 0; 10 char buf[1024] = { 0 }; 11 int i = 0; 12 13 fd = open("libhello.so", O_RDWR | O_CREAT, 0777); 14 if (fd < 0) { 15 printf("open failed\n"); 16 return 0; 17 } 18 19 memset(buf, 0xff, sizeof(buf)); 20 for (i = 0; i < 6; i++) { 21 write(fd, buf, sizeof(buf)); 22 } 23 24 return 0; 25 }
执行完程序之后能生成libhello.so文件,但它里面的内容为6K的0XFF,将这个文件保存到别的文件夹中。然后编写真正的库文件,代码如下:
hello.c
1 #include <stdio.h> 2 3 void hello(void) 4 { 5 printf("Hello World\n"); 6 }
代码非常简单,就是打印Hello World,但是要将这个文件编译成动态库,使用如下指令:
gcc -fPIC -Wall -c hello.c
gcc -shared hello.o -o libhello.so
这样就生成了libhello.so文件,将改文件复制到/lib目录下,当前目录下的libhello.so文件不要删掉,编写程序:
signal_4.c
1 /** 2 * filename: signal_3.c 3 * author: Suzkfly 4 * date: 2021-02-15 5 * platform: Ubuntu 6 * 操作步骤: 7 * 1. 将可执行的libhello.so文件拷贝至/lib目录 8 * 2. 运行程序,每隔5秒打印Hello World 9 * 3. 在程序运行过程中将全是0xFF的libhello.so文件拷贝至/lib目录 10 * 4. 程序将收到SIGILL信号,并打印"SIGILL signal captured",然后退出。 11 */ 12 #include <stdio.h> 13 #include <fcntl.h> 14 #include <sys/types.h> 15 #include <sys/stat.h> 16 #include <signal.h> 17 #include <stdlib.h> 18 19 20 /* 自定义信号处理函数 */ 21 void func(int sig) 22 { 23 if (sig == SIGILL) { 24 printf("SIGILL signal captured\n"); 25 exit(0); /* 这里一定要退出,因为不知道程序运行会带来什么后果 */ 26 } 27 } 28 29 extern void hello(void); 30 31 typedef void (*func_t)(int); 32 33 int main(int argc, const char *argv[]) 34 { 35 func_t p; /* 定义一个函数指针 */ 36 37 p = signal(SIGILL, func); 38 if (p == (func_t)-1) { 39 printf("signal failed\n"); 40 return 0; 41 } 42 printf("p = %p\n", p); 43 44 while (1) { 45 sleep(5); 46 hello(); 47 } 48 49 return 0; 50 }
按文件开始部分的注释操作,运行结果如下:
该信号在调试时使用。我用了各种方法去复现它都没有办法实现,由于我对gdb调试机制并不熟悉,暂时先放一放。
标签:gdb调试 写入 开始 kill 机制 auth 进程终止 clu 原因
原文地址:https://www.cnblogs.com/Suzkfly/p/14404005.html