進程間通訊之——信號復現(1~5)(二)

普通訊號的復現

1)SIGHUP

  該信號在終端掛起或控制進程終止時發出,那能夠經過在終端中運行進程,而後關閉終端來實現。linux

  代碼以下:函數

 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 }

操做步驟:spa

  1. 編譯程序,生成可執行文件a.out;3d

  2. 執行a.out;指針

  3. 另開一個終端,輸入ps -aux命令,能夠看到有一個經過a.out命令建立的進程,進程ID爲3991調試

  

   4. 用鼠標關掉開啓進程的終端,點擊窗口左上角的「X」,而後Close Terminal,以下圖:code

  

  5. 在剛剛使用ps -aux命令的終端上再次執行ps -aux命令,能夠看到該進程還在;orm

  6. 進到程序指定的路徑中,用ls命令能夠看到裏面多了一個test.txt文件,用vi查看能夠發現裏面的內容正是程序寫入的內容blog

  

   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調試機制並不熟悉,暫時先放一放。

相關文章
相關標籤/搜索