码迷,mamicode.com
首页 > 系统相关 > 详细

进程间通信之——信号复现(1~5)(二)

时间:2021-02-18 13:07:16      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:gdb调试   写入   开始   kill   机制   auth   进程终止   clu   原因   

普通信号的复现

1)SIGHUP

  该信号在终端挂起或控制进程终止时发出,那可以通过在终端中运行进程,然后关闭终端来实现。

  代码如下:

 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号,根据实际情况而定)

2) SIGINT

  该信号在上篇博客中验证了,在此不再赘述。

3) SIGQUIT

  该信号与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配置是没问题的)。

4) SIGILL

  导致该信号的原因为非法指令,也就是说可执行文件的指令有问题,这个复现起来有点难,如果编译器没问题的话,编译出来的可执行文件就不会有问题。然鹅程序运行时的指令不一定就是它这个编译器编译出来的啊,这不是还有库文件吗,而且必须用动态库。那么复现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 }

按文件开始部分的注释操作,运行结果如下:

技术图片

 5) SIGTRAP

  该信号在调试时使用。我用了各种方法去复现它都没有办法实现,由于我对gdb调试机制并不熟悉,暂时先放一放。

  

进程间通信之——信号复现(1~5)(二)

标签:gdb调试   写入   开始   kill   机制   auth   进程终止   clu   原因   

原文地址:https://www.cnblogs.com/Suzkfly/p/14404005.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有
迷上了代码!