当前位置: 首页 > 编程日记 > 正文

使用sigaction处理内核信号

文章目录

        • 函数描述
        • 函数使用
        • 抓取发送信号的进程信息

mark一次获取内核信号,并作相应处理的手段
linux内核中断机制的一个重要实现就是信号。信号使得内核和用户态的交互更加便捷,这个便捷对开发者来说可以更好的利用系统原生内核来处理信息。

《深入理解unix内核》中对信号作用的描述如下:

  • 让进程知道已经发生了一个特定事件
  • 强迫进程执行它自己代码中的信号处理程序

这里主要描述一下借用sigaction系统调用,对信号进行注册并做出相应的处理

函数描述

包含头文件:#include <signal.h>
函数原型:int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
参数含义如下:

  • signum 表示特例化信号代表的数字,其中SIGKILLSIGSTOP信号不能被注册
  • struct sigaction 该数据结构如下
    struct sigaction {void     (*sa_handler)(int); /*表示要执行操作的类型,它的值可以是指向信号处理程序的一个指针,SIG_DFL(值为0,指定缺省操作, 或者SIG_IBN(值为1,指定忽略信号)*/void     (*sa_sigaction)(int, siginfo_t *, void *);sigset_t   sa_mask; /*这是一个标志集,制定必须怎样处理信号。*/int        sa_flags; /*这个是类型为sigset_t的变量,指定当运行信号处理程序时要屏蔽的信号,一般为SA_SIGINFO,来获取处理程序的附件信息*/void     (*sa_restorer)(void);
    };
    
    这里一般是我们在程序中封装该sigaction数据结构,将我们想要的参数封装好传入进去,再通过系统调用执行处理。
    其中SA_SIGINFO数据结构包含如下参数,直接通过siginfo_t 的结构体变量来获取
     siginfo_t {int      si_signo;    /* Signal number */int      si_errno;    /* An errno value */int      si_code;     /* Signal code */int      si_trapno;   /* Trap number that causedhardware-generated signal(unused on most architectures) */pid_t    si_pid;      /* Sending process ID */uid_t    si_uid;      /* Real user ID of sending process */int      si_status;   /* Exit value or signal */clock_t  si_utime;    /* User time consumed */clock_t  si_stime;    /* System time consumed */sigval_t si_value;    /* Signal value */int      si_int;      /* POSIX.1b signal */void    *si_ptr;      /* POSIX.1b signal */int      si_overrun;  /* Timer overrun count; POSIX.1b timers */int      si_timerid;  /* Timer ID; POSIX.1b timers */void    *si_addr;     /* Memory location which caused fault */long     si_band;     /* Band event (was int inglibc 2.3.2 and earlier) */int      si_fd;       /* File descriptor */short    si_addr_lsb; /* Least significant bit of address(since Linux 2.6.32) */
    }
    
  • const struct sigaction *act 该参数非空的,存储最新的一个action的信息的数据结构
  • struct sigaction *oldact 该参数也为空,同时存储上一个action的信息的数据结构

函数使用

查看如下代码

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h> 
#include <time.h>  
void get_unlegal_memory()  
{  char *a = NULL;/*未分配空间,模拟非法访问内存*/printf("get the unmalloc memmory %c!\n",a[0]);
}
void print_stacktrace()                  
{int size = 16,i=0;void * array[16];int stack_num = backtrace(array, size);                   char ** stacktrace = backtrace_symbols(array, stack_num);                                                                                                                                                                                                         for (; i < stack_num; ++i)                       {printf("%s\n", stacktrace[i]);                           }free(stacktrace);                                         
}
void sig_op(int signo, siginfo_t* info, void* context)
{print_stacktrace();printf("get the kernel signal\n");printf("sig signo is %d\n",info->si_signo);exit(0);
}
int main(int argc,char** argv)
{struct sigaction act;struct sigaction oact;pid_t pid;pid=getpid();sigemptyset(&act.sa_mask);/*注册信号处理函数如下,sig_op,用来打印函数调用栈以及信号集中发出该信号的进程详细信息*/act.sa_handler=sig_op; act.sa_flags=SA_SIGINFO;/*注册了信号SIGSEGV用来获取非法内存访问*/if(sigaction(SIGSEGV,&act,&oact)== -1)printf("%d","install error~!\n",SIGSEGV);printf("the pid is %d\n",pid);get_unlegal_memory();return 0;
}

编译方式如下
gcc test.c -rdynamic -g -o test
这里增加了打印函数调用栈,需要将所有符号连接到二进制文件,所以需要-rdynamic参数,这里想要进一步了解打印函数调用栈,可以参考关于ceph源码 backtrace 打印函数调用栈

执行结果如下可以看到函数调用栈如下,sig_op函数是由系统c库发出

./test
the pid is 7754
./test_memory(print_stacktrace+0x32) [0x400b2b]
./test_memory(sig_op+0x1d) [0x400ba5]
/lib64/libc.so.6(+0x35a00) [0x7f470de32a00]
./test_memory(get_unlegal_memory+0x20) [0x400ae0]
./test_memory(main+0x9c) [0x400c6c]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f470de1eaf5]
./test_memory() [0x4009f9]
get the kernel signal
sig signo is 11

抓取发送信号的进程信息

使用以上获取内核命令的方式,我们可以在今后抓取终止当前进程的某个进程(/proc/p_id/status 文件)信息,举例如下
改代码注册了键盘中断信号(SIGINT)以及终止信号(SIGTERM),同时将发送该信号的进程信息打印出来(包括进程名称,进程p_id,占用内存,所处内存地址等信息)

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h> 
#include <time.h>  /*打印当前时间*/
void printDatetime()  
{  time_t now;struct tm *tm_now;time(&now);tm_now = localtime(&now);printf("now datetime: %d-%d-%d %d:%d:%d\n", tm_now->tm_year, tm_now->tm_mon, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);fflush(stdout);
}#define BUF_SIZE 1024
/*打印发送信号进程的详细信息,即从/proc/p_id/status 文件目录下获取*/
void printTaskStatusByPid(int pid) {  char proc_pid_path[BUF_SIZE]={0};  char buf[BUF_SIZE]={0};  sprintf(proc_pid_path, "/proc/%d/status", pid);  FILE* fp = fopen(proc_pid_path, "r");  if(NULL != fp){while(fgets(buf, BUF_SIZE-1, fp)!= NULL){printf("%s\n",buf);}         fclose(fp);  }else{printf("NULL\n");}
}  /*打印函数调用栈*/
void print_stacktrace()                  
{int size = 16,i=0;void * array[16];int stack_num = backtrace(array, size);                   char ** stacktrace = backtrace_symbols(array, stack_num);                                                                                                                                                                                                         for (; i < stack_num; ++i)                       {printf("%s\n", stacktrace[i]);                          }free(stacktrace);                                         
}/*内核信号处理函数,打印发送该信号的进程信息*/
void sig_op(int signo, siginfo_t* info, void* context)
{print_stacktrace();printf("the signo is %d\n",signo);printf("sig pid is %d\n", (int)(info->si_pid));printf("sig uid is %d\n", (int)(info->si_uid));printf("sig signo is %d\n",info->si_signo);printTaskStatusByPid((int)(info->si_pid));fflush(stdout);
}int main(int argc,char** argv)
{struct sigaction act;struct sigaction oact;pid_t pid;pid=getpid();printDatetime(); printf("the pid is %d\n",pid);fflush(stdout);/*初始化sigset_t变量中的位*/sigemptyset(&act.sa_mask);act.sa_handler=sig_op; act.sa_flags=SA_SIGINFO;/*注册信号*/if(sigaction(SIGINT,&act,&oact)==-1)printf("%s","install error~!\n");if(sigaction(SIGTERM,&act,&oact)==-1)printf("%s","install error~!\n");if(sigaction(SIGSEGV,&act,&oact)== -1)printf("%d","install error~!\n",SIGSEGV);/*死循环来打印时间,当遇到注册的内核信息,此时打印出进程详细信息*/while(1){sleep(1);printDatetime();fflush(stdout);}return 0;
}

输出结果如下:

now datetime: 119-6-13 19:44:29
now datetime: 119-6-13 19:44:30
#执行了killall操作,获取到了SIGTERM信号,打印出来的信息
./test(print_stacktrace+0x32) [0x400e86]
./test(sig_op+0x1d) [0x400f00]
/lib64/libc.so.6(+0x35a00) [0x7f18223b9a00]
/lib64/libc.so.6(nanosleep+0x10) [0x7f1822441890]
/lib64/libc.so.6(sleep+0xd4) [0x7f1822441744]
./test(main+0x109) [0x401083]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f18223a5af5]
./test() [0x400c49]
the signo is 15
sig pid is 20863
sig uid is 0
sig signo is 15
#可以看到发送SIGTERM信号的进程名称如下
Name:	killall
State:	R (running)
Tgid:	20863
Ngid:	0
Pid:	20863
PPid:	15099
TracerPid:	0
Uid:	0	0	0	0
Gid:	0	0	0	0
FDSize:	256
Groups:	0 
VmPeak:	  116760 kB
VmSize:	  116760 kB
VmLck:	       0 kB
VmPin:	       0 kB
VmHWM:	     924 kB
VmRSS:	     924 kB
VmData:	     212 kB
VmStk:	     136 kB
VmExe:	      20 kB
VmLib:	    2508 kB
VmPTE:	      64 kB
VmSwap:	       0 kB
Threads:	1
SigQ:	1/125771
SigPnd:	0000000000000000
ShdPnd:	0000000000000000
SigBlk:	0000000000000000
SigIgn:	0000000000000000
SigCgt:	0000000180000000
CapInh:	0000000000000000
CapPrm:	0000001fffffffff
CapEff:	0000001fffffffff
CapBnd:	0000001fffffffff
Seccomp:	0
Cpus_allowed:	ff
Cpus_allowed_list:	0-7
Mems_allowed:	00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
Mems_allowed_list:	0
voluntary_ctxt_switches:	1
nonvoluntary_ctxt_switches:	1
now datetime: 119-6-13 19:44:30
now datetime: 119-6-13 19:46:45
now datetime: 119-6-13 19:46:46
#执行键盘中断获取到信号信息,但是该执行并不是一个进程,所以并不会打印调用栈
^C./test(print_stacktrace+0x32) [0x400e86]
./test(sig_op+0x1d) [0x400f00]
/lib64/libc.so.6(+0x35a00) [0x7f18223b9a00]
/lib64/libc.so.6(nanosleep+0x10) [0x7f1822441890]
/lib64/libc.so.6(sleep+0xd4) [0x7f1822441744]
./test(main+0x109) [0x401083]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f18223a5af5]
./test() [0x400c49]
the signo is 2
sig pid is 0
sig uid is 0
sig signo is 2
NULL
now datetime: 119-6-13 19:46:47
now datetime: 119-6-13 19:48:10
now datetime: 119-6-13 19:48:11
#当执行了kill -9 命令时,即发送SIGKILL信号,会彻底终止当前进程。(SIGKILL信号不允许被注册,抓取)
Killed

相关文章:

ios share extension 真机不显示_ios企业签名:APPGroups实现App之间数据共享

一、认识App GroupsAppGroup allows data sharing between two different apps or even app and widgets by creating one common shared path (like document directory). Data saved over there can be accessed by any app which is associated with that particular AppGro…

处理 JSON null 和空数组及对象

描述了对 JSON 数据中使用的 null 和空数组及对象的处理。 JSON 数据具有 null 和空数组及对象的概念。此部分说明其中每个概念如何映射到 null 和未设置的数据对象概念。 Null 值 JSON 具有特殊值 null&#xff0c;可以对任何数据类型设置该值&#xff0c;包括数组、对象、数字…

xml file too big to import to wordpress website

xml文件太大无法上传到wordpress 原因&#xff1a;从一个wordpress上导出了自己所有的文章&#xff0c;大概6~7MB&#xff0c;准备导入到本机自建的一个wordpress&#xff0c;不过上传文件有限制&#xff0c;最大2MB。 解决方法&#xff1a; 1. 网上很多关于修改配置文件的…

亚麻 面经_ml

Ds -如何预测一个人会不会在下一个月在Amazon买东西&#xff0c;有什么模型。https://mlwave.com/predicting-repeat-buyers-vowpal-wabbit/https://www.researchgate.net/post/How_can_I_study_the_past_spending_behaviour_of_a_customer_in_a_banking_perspective_and_predi…

ceph bluestore源码分析:C++ 获取线程id

阅读ceph源码过程中需要明确当前操作是由哪个线程发出&#xff0c;此时需要根据线程id来确认线程名称 C获取线程id是通过系统调用来直接获取 函数描述 头文件:<sys/syscall.h> 函数名称:syscall(SYS_gettid) 该函数直接返回了一个pid_t int类型的数字&#xff0c;即为当…

判断两直线段是否相交

转自&#xff1a;http://www.cnblogs.com/shengshouzhaixing/archive/2013/03/17/2964950.html //功能&#xff1a;求点在有向直线左边还是右边 //返回&#xff1a;0共线、1左边、-1右边 int left_right(point a,point b,double x,double y) { d…

led显示屏建设标准_户外LED显示屏3大防护标准_显示屏应对恶劣天气?

户外LED显示屏是现在LED显示屏应用最棺广泛的领域。面积巨大&#xff0c;显示效果震撼。同时为了更好的宣传效果&#xff0c;通常安装余楼顶&#xff0c;道路等空旷无遮挡地带。由于面积大且处于露天状态&#xff0c;LED显示屏面临巨大的环境挑战。经常要面对大风、暴雨、冰雹等…

转载 Sqlerver 计算 MD5

2019独角兽企业重金招聘Python工程师标准>>> 在SQl2005下自带的函数hashbytes() &#xff0c;此函数是微软在SQL SERVER 2005中提供的&#xff0c;可以用来计算一个字符串的 MD5 和 SHA1 值&#xff0c;使用方法如下&#xff1a; --获取123456的MD5加密串 select ha…

vim使用说明

模式 命令 操作 开始 vim 文件路径 打开|新建文件 命令模式 i 切换到输入模式 x 删除当前光标所在处的字符 : 切换到底线命令模式 shiftzz 保存并退出 移动光标的方法 h|← 左 j|↓ 下 k|↑ 上 l|→ 右 [Ctrl] [f] 输入模式下的page down [Ctrl] […

g++编译c++11特性 的.cc文件

写一个.cc文件&#xff0c;其中抱哈std::lock_guard以及std::thread等c11特性&#xff0c;开始使用gcc编译,过程中出现如下问题 gcc test_lock.cc -o test_lock This file requires compiler and library support for the ISO C 2011 standard. This support is currently ex…

联想r720内存频率_联想 IdeaPad14s 2020 轻薄本双十一促销

IT之家11月10日消息 作为一款主打轻薄的笔记本电脑&#xff0c;联想 IdeaPad14s 2020 自推出以来便受到不少办公学习用户的青睐。如今&#xff0c;这款联想 IdeaPad14s 2020 轻薄笔记本已开启双十一促销&#xff0c;搭载第十代酷睿处理器&#xff0c;采用 14 英寸双侧窄边框屏幕…

HDU 1273 漫步森林

比赛的时候是看见人家A得很快&#xff0c;但是一看的时候觉得没什么头绪&#xff0c;画了一个六边形的灵感来了&#xff0c;就YY一下 第一次提交写错了结束条件&#xff0c;之后意淫下公式交上去A了。 用五边形来解释&#xff1a; 1.设有五个点1&#xff0c;2,3,4,5, 2.从1开始…

在请求完成后回调delegate的方法。然而回调时经常遇到这种情况:delegate已经被释放...

最近的项目遇到了网络请求&#xff0c;需要在请求完成后回调delegate的方法。然而回调时经常遇到这种情况&#xff1a;delegate已经被释放&#xff0c;这时调用其方法则会引起crash。 objc的runtime中有两种判断类型的方式比较靠谱&#xff0c;他们可以直接取得任意一个objc_ob…

C++ 学习笔记之——文件操作和文件流

1. 文件的概念 对于用户来说&#xff0c;常用到的文件有两大类&#xff1a;程序文件和数据文件。而根据文件中数据的组织方式&#xff0c;则可以将文件分为 ASCII 文件和二进制文件。 ASCII 文件&#xff0c;又称字符文件或者文本文件&#xff0c;它的每一个字节放一个 ASCII 代…

利用blktrace分析磁盘I/O

原文&#xff1a;https://blog.csdn.net/ygtlovezf/article/details/80528300 blktrace对于分析block I/O是个非常好的工具&#xff0c;本篇文章记录了如何使用blktrace。 blktrace原理 blktrace是对通用块层&#xff08;block layer&#xff09;的I/O跟踪机制&#xff0c;它…

shiro 同时实现url和按钮的拦截_一个“保存”按钮同时存在“增删改”三种操作,该如何去实现?...

一般情况下&#xff0c;对表格中的数据进行“增删改”操作&#xff0c;都是直接操作数据库。现在有些项目因为设计或者优化的缘故&#xff0c;不对表格中的数据进行“增删改”&#xff0c;而是通过最后“保存”按钮的操作&#xff0c;一次性将数据传至服务器&#xff0c;由服务…

在网络通讯中,如何自己分配可用的端口号和获取自己的ip地址

在编写一些程序时&#xff0c;为了程序可以在其他电脑上也可以使用&#xff0c;而不用手动去更改ip,或者碰到端口不可用的情况。在这里找到了一个好的方法&#xff0c;实际使用也没有问题&#xff01;故此推荐给大家! 方案&#xff1a; 在构建网络时&#xff0c;使用&#xff1…

【翻译】ASP.NET WEB API异常处理

当一个web api抛出一个异常后 此异常会被转化成一个HTTP响应 错误代码为500的服务错误 但是如果你不想让客户端看到500的错误码 你也可以自定义错误码 如下代码当用户输入的ID没有与之相关的数据 则返回了错误码为404的错误 &#xff08;页面未找到&#xff09; public Product…

hook NtTerminateProcess进行应用的保护

这段时间在学习驱动&#xff0c;然后看到hook ssdt的代码&#xff0c;找了一个写的清晰的学习了一下&#xff1a;http://www.netfairy.net/?post218 这里是hook NtOpenProcess&#xff0c;但是想自己练手所以hook NtTerminateProcess&#xff0c;经过多次蓝屏后&#xff0c;然…

linux系统 长久记录所有用户所有操作记录

在linux系统中想要记录所有登录过当前系统的用户操作&#xff0c;排查有人对当前系统做的何种操作导致系统问题&#xff0c;可以按照如下方法进行。 前言 在描述操作步骤之前&#xff0c;先说一下系统环境变量的相关配置文件 ~/.bashrc和~/.bash_file&#xff0c;这两个文件…

jquery图片播放切换插件

点击这里查看效果可自定义数字样式和左右点击按钮这个更好&#xff1a;移入按钮切换版本更多图片轮播以下是HTML文件代码&#xff1a; 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transiti…

安卓饼状图设置软件_话单及银行卡交易智能分析软件

一、产品概况&#xff1a; 思迈奥SMILE数据智能分析软件是由我司自主设计与研发的一款结合在公安和检察院的侦查业务经验而定制研发的数据智能分析系统&#xff0c;包含于话单、电子银行账单、及其它数据(个人出行数据、社会资源数据、微信数据及其它聊天数据)等的数据导入、检…

跨区域MPLS TE

拓扑&#xff1a; R1配置&#xff1a; mpls label range 100 199 mpls traffic-eng tunnels interface Loopback0 ip address 192.168.1.1 255.255.255.255 ! interface Tunnel1 ip unnumbered Loopback0 tunnel mode mpls traffic-eng tunnel destination 192.168.1.4 tunnel …

C++智能指针: shared_ptr 实现详解

文章目录shared_ptr描述声明作用原理实现函数使用关于shared_ptr循环引用问题shared_ptr描述 声明 shared_ptr属于C11特性中新加的一种智能指针&#xff0c;它的实现方式是模版类&#xff0c;头文件<memory> template <class T> class shared_ptr 所以使用shared…

linux文本处理常用命令

linux文本处理常用命令 linux文本处理命令&#xff1a;grep、sed、printf、awk 1.grep grep的作用是按行查找字符&#xff0c;输出包含字符的行。 #从文件查询 grep hello filename.txt #从管道的输入查询 cat filename.txt|grep hello grep使用示例&#xff1a; grep的查找主要…

arduino 控制无刷电机_智能控制轮椅来了,残疾人的福音!

传统的轮椅已被证明是非常宝贵的工具&#xff0c;为残疾人提供了很多便利&#xff0c;但其只能限制坐在一个位置。外国的一个研究团队通过开发一个功能强大的多功能轮椅&#xff0c;使用户能够通过手机应用程序轻松地在各种各样的位置之间进行切换。(图片来自 IC photo)这是一种…

python科学计算整理

网站&#xff1a; http://bokeh.pydata.org/gallery.html 转载于:https://www.cnblogs.com/gogly/p/3453341.html

TP-link 841N 刷DD-WRT固件

2012年4月20号 今天&#xff0c;笔者逛“太平洋”的时候&#xff0c;发现了一个关于TP-Link 840N刷DD-WRT的帖子&#xff0c;进去逛了一会&#xff0c;突然记得自己家中的那个路由好像也是这个型号的&#xff0c;二话不说&#xff0c;果断收录这条资料&#xff0c;并把所需要的…

网格的铺设问题——骨牌

Problem Description 有一个大小是 2 x n 的网格&#xff0c;现在需要用2种规格的骨牌铺满&#xff0c;骨牌规格分别是 2 x 1 和 2 x 2&#xff0c;请计算一共有多少种铺设的方法。 Input 输入的第一行包含一个正整数T&#xff08;T<20&#xff09;&#xff0c;表示一共有 T…

C++智能指针:weak_ptr实现详解

文章目录weak_ptr描述声明作用原理实现函数成员使用总结weak_ptr描述 声明 头文件&#xff1a;<memory> 模版类&#xff1a;template <class T> class weak_ptr 声明方式&#xff1a;std::weak_ptr<type_id> statement 作用 根据boost库的官方描述&#…