該信號在終端掛起或控制進程終止時發出,那能夠經過在終端中運行進程,而後關閉終端來實現。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號,根據實際狀況而定)進程
該信號在上篇博客中驗證了,在此再也不贅述。
該信號與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調試機制並不熟悉,暫時先放一放。