内核工具KGDB调试环境需要为Linux 内核加上 kgdb补丁,补丁实现GDB远程调试所需要的功能,包括命令处理、陷阱处理及串口通信3个主要的部分。KGDB补丁的主要作用是在Linux 内核中添加了一个调试Stub。调试Stub是Linux 内核中的一小段代码,是运行GDB的开发机和所调试内核之间的一个媒介。GDB和调试stub之间通过GDB串行协议进行通信。GDB串行协议是-种基于消息的ASCII 码协议,包含了各种调试命令。当设置断点时,KGDB将断点的指令替换为一条 trap指令,当执行到断点时控制权就转移到调试 stub中去。此时,调试stub 的任务就是使用远程串行通信协议将当前环境传送给GDB,然后从GDB处接收命令。GDB命令告诉stub 下一步该做什么,当stub收到继续执行的命令时,将恢复程序的运行环境,把对 CPU的控制权重新交还给内核。KGDB补丁给内核添加以下3个部件:
为爱辉等地区用户提供了全套网页设计制作服务,及爱辉网站建设行业解决方案。主营业务为网站设计制作、做网站、爱辉网站设计,以传统方式定制建设网站,并提供域名空间备案等一条龙服务,秉承以专业、用心的态度为用户提供真诚的服务。我们深信只要达到每一位用户的要求,就会得到认可,从而选择与我们长期合作。这样,我们也可以走得更远!
(1 ) GDB stub
GDB stub被称为调试插桩(简称为stub),是KGDB调试器的核心。它是Linux内核中的一小段代码,用来处理主机上: GDB发来的各种请求;并且在内核处于被调试状态时,控制目标机板上的处理器。
(2)修改异常处理函数
当这个异常发生时,内核将控制权交给KGDB调试器,程序进入KGDB提供的异常处理函数中。在里面,可以分析程序的各种情况。
(3)串口通信
GDB和 stub之间通过GDB串行协议进行通信。它是一种基于消息的ASCII 码协议,包含了各种调试命令。除串口外,也可以使用网卡进行通信。以设置内核断点为例说明KGDB与GDB之间的工作过程。设置断点时,KGDB修改内核代码,将断点位置的指令替换成一条异常指令(在ARM中这是一条未定义的指令)。当执行到断点时发生异常,控制权转移到stub 的异常处理函数中。此时,stub的任务就是使用GDB串行通信协议将当前环境传送给GDB,然后从GDB处接收命令,GDB命令告诉stub下一步该做什么。当stub收到继续执行的命令时,将恢复原来替换的指令、恢复程序的运行环境,把对CPU的控制权重新交还给内核。
中断与定时器:
中断的概念:指CPU在执行过程中,出现某些突发事件急待处理,CPU暂停执行当前程序,转去处理突发事件
,处理完后CPU又返回原程序被中断的位置继续执行
中断的分类:内部中断和外部中断
内部中断:中断源来自CPU内部(软件中断指令、溢出、触发错误等)
外部中断:中断源来自CPU外部,由外设提出请求
屏蔽中断和不可屏蔽中断:
可屏蔽中断:可以通过屏蔽字被屏蔽,屏蔽后,该中断不再得到响应
不可平布中断:不能被屏蔽
向量中断和非向量中断:
向量中断:CPU通常为不同的中断分配不同的中断号,当检测到某中断号的中断到来后,就自动跳转到与该中断号对应的地址执行
非向量中断:多个中断共享一个入口地址。进入该入口地址后再通过软件判断中断标志来识别具体哪个是中断
也就是说向量中断由软件提供中断服务程序入口地址,非向量中断由软件提供中断入口地址
/*典型的非向量中断首先会判断中断源,然后调用不同中断源的中断处理程序*/
irq_handler()
{
...
int int_src = read_int_status();/*读硬件的中断相关寄存器*/
switch(int_src){//判断中断标志
case DEV_A:
dev_a_handler();
break;
case DEV_B:
dev_b_handler();
break;
...
default:
break;
}
...
}
定时器中断原理:
定时器在硬件上也以来中断,PIT(可编程间隔定时器)接收一个时钟输入,
当时钟脉冲到来时,将目前计数值增1并与已经设置的计数值比较,若相等,证明计数周期满,产生定时器中断,并
复位计数值。
如下图所示:
Linux中断处理程序架构:
Linux将中断分为:顶半部(top half)和底半部(bottom half)
顶板部:完成尽可能少的比较紧急的功能,它往往只是简单的读取寄存器中的中断状态并清除中断标志后就进行
“登记中断”(也就是将底半部处理程序挂在到设备的底半部执行队列中)的工作
特点:响应速度快
底半部:中断处理的大部分工作都在底半部,它几乎做了中断处理程序的所有事情。
特点:处理相对来说不是非常紧急的事件
小知识:Linux中查看/proc/interrupts文件可以获得系统中断的统计信息。
如下图所示:
第一列是中断号 第二列是向CPU产生该中断的次数
介绍完相关基础概念后,让我们一起来探讨一下Linux中断编程
Linux中断编程:
1.申请和释放中断
申请中断:
int request_irq(unsigned int irq,irq_handler_t handler,
unsigned long irqflags,const char *devname,void *dev_id)
参数介绍:irq是要申请的硬件中断号
handler是向系统登记的中断处理程序(顶半部),是一个回调函数,中断发生时,系统调用它,将
dev_id参数传递给它
irqflags:是中断处理的属性,可以指定中断的触发方式和处理方式:
触发方式:IRQF_TRIGGER_RISING、IRQF_TRIGGER_FALLING、IRQF_TRIGGER_HIGH、IRQF_TRIGGER_LOW
处理方式:IRQF_DISABLE表明中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断
IRQF_SHARED表示多个设备共享中断,dev_id在中断共享时会用到,一般设置为NULL
返回值:为0表示成功,返回-EINVAL表示中断号无效,返回-EBUSY表示中断已经被占用,且不能共享
顶半部的handler的类型irq_handler_t定义为
typedef irqreturn_t (*irq_handler_t)(int,void*);
typedef int irqreturn_t;
2.释放IRQ
有请求当然就有释放了
void free_irq(unsigned int irq,void *dev_id);
参数定义与request_irq类似
3.使能和屏蔽中断
void disable_irq(int irq);//等待目前中断处理完成(最好别在顶板部使用,你懂得)
void disable_irq_nosync(int irq);//立即返回
void enable_irq(int irq);//
4.屏蔽本CPU内所有中断:
#define local_irq_save(flags)...//禁止中断并保存状态
void local_irq_disable(void);//禁止中断,不保存状态
下面来分别介绍一下顶半部和底半部的实现机制
底半部机制:
简介:底半部机制主要有tasklet、工作队列和软中断
1.底半部是想方法之一tasklet
(1)我们需要定义tasklet机器处理器并将两者关联
例如:
void my_tasklet_func(unsigned long);/*定义一个处理函数*/
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);
/*上述代码定义了名为my_tasklet的tasklet并将其余
my_tasklet_func()函数绑定,传入的参数为data*/
(2)调度
tasklet_schedule(my_tasklet);
//使用此函数就能在是当的时候进行调度运行
tasklet使用模板:
/*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0);
/*中断处理底半部*/
void xxx_do_tasklet(unsigned long)
{
...
}
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
tasklet_schedule(xxx_tasklet);//调度地板部
...
}
/*设备驱动模块加载函数*/
int __init xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq,xxx_interrupt,
IRQF_DISABLED,"xxx",NULL);
...
return IRQ_HANDLED;
}
/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
2.底半部实现方法之二---工作队列
使用方法和tasklet类似
相关操作:
struct work_struct my_wq;/*定义一个工作队列*/
void my_wq_func(unsigned long);/*定义一个处理函数*/
通过INIT_WORK()可以初始化这个工作队列并将工作队列与处理函数绑定
INIT_WORK(my_wq,(void (*)(void *))my_wq_func,NULL);
/*初始化工作队列并将其与处理函数绑定*/
schedule_work(my_wq);/*调度工作队列执行*/
/*工作队列使用模板*/
/*定义工作队列和关联函数*/
struct work_struct(unsigned long);
void xxx_do_work(unsigned long);
/*中断处理底半部*/
void xxx_do_work(unsigned long)
{
...
}
/*中断处理顶半部*/
/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
schedule_work(my_wq);//调度底半部
...
return IRQ_HANDLED;
}
/*设备驱动模块加载函数*/
int xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq,xxx_interrupt,
IRQF_DISABLED,"xxx",NULL);
...
/*初始化工作队列*/
INIT_WORK(my_wq,(void (*)(void *))xxx_do_work,NULL);
}
/*设备驱动模块卸载函数*/
void xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq,xxx_interrupt);
...
}
SNMP一般指简单网络管理协议,简单网络管理协议(SNMP)是专门设计用于在IP网络管理网络节点(服务器、工作站、路由器、交换机及HUBS等)的一种标准协议,它是一种应用层协议。
trap为Linux命令,bash内置命令,可以查看shell环境信号和设置信号的处理方式。
使用格式(commands为命令,signals为信号的指代):
1):$trap"commands"signals#接收到signals指定的信号时,执行commands命令。
2):$trapsignals#如果没有指定命令就是恢复signals的动作。比如trapINT就是恢复Ctrl+C。
3):$trap""signals#忽略信号signals
4):$trap-l#列出所有的信号
扩展资料:
SNMP协议种类:
目前,SNMP有3种:SNMPV1、SNMPV2、SNMPV3。第1版和第2版没有太大差距,但SNMPV2是增强版本,包含了其它协议操作。与前两种相比,SNMPV3则包含更多安全和远程配置。为了解决不同SNMP版本间的不兼容问题,RFC3584中定义了三者共存策略。
SNMP还包括一组由RMON、RMON2、MTB、MTB2、OCDS及OCDS定义的扩展协议。
参考资料来源:百度百科-SNMP
参考资料来源:百度百科-trap
安装snmp服务
CentOS/RedHat下可以只用yum命令进行安装。
$ yum –y install net-snmp net-snmp-devel
若要使用snmpwalk进行安装检测,则还需要安装net-snmp-utils包
$ yum –y install net-snmp-utils
Ubuntu可以通过apt-get install snmp snmpd 进行安装
设置安全的验证方式
将SNMP代理程序暴露给网络上的所有主机是很危险的,为了防止其它主机访问您的SNMP代理程序,我们需要在SNMP代理程序上加入身份验证机制。SNMP支持不同的验证机制,这取决于不同的SNMP协议版本,云监控目前支持v2c和v3两个版本,其中v2c版本的验证机制比较简单,它基于明文密码和授权IP来进行身份验证,而v3版本则通过用户名和密码的加密传输来实现身份验证,我们建议使用v3,当然,只要按照以下的介绍进行配置,不论是v2c版本还是v3版本,都可以保证一定的安全性,您可以根据情况来选择。
注意一点,SNMP协议版本和SNMP代理程序版本是两回事,刚才说的v2c和v3是指SNMP协议的版本,而Net-SNMP是用来实现SNMP协议的程序套件,目前它的最新版本是刚才提到的5.4.2.1。
v2c
先来看如何配置v2c版本的SNMP代理,我们来创建snmpd的配置文件,默认情况下它是不存在的,我们来创建它,如下:
sdo:~ # vi /usr/local/snmp/share/snmp/snmpd.conf
然后我们需要创建一个只读帐号,也就是read-only community,在snmpd.conf中添加以下内容:
rocommunity sdomonitor 114.80.132.9 rocommunity sdomonitor 58.215.169.26 rocommunity sdomonitor 58.215.169.27
如果想要检测服务是否成功开启,则还需要在snmpd.conf中添加:
rocommunity sdomonitor 127.0.0.1
注意,这里的"rocommunity"表示这是一个只读的访问权限,云监控只可以从您的服务器上获取信息,而不能对服务器进行任何设置。
紧接着的"sdomonitor"相当于密码,很多平台喜欢使用"public"这个默认字符串。这里的"sdomonitor"只是一个例子,您可以设置其它字符串作为密码。
最右边的"60.195.249.83"代表指定的监控点IP,这个IP地址是云监控专用的监控点,这意味着只有云监控有权限来访问您的SNMP代理程序。
所以,以上这段配置中,只有"sdomonitor"是需要您进行修改的,同时在云监控上添加服务器的时候,需要提供这个字符串。
v3
当然,我们建议您使用v3版本来进行身份验证。对于一些早期版本的Linux分发版,其内置的SNMP代理程序可能并不支持v3,所以我们建议您按照前边介绍的方法,编译和安装最新的Net-Snmp。
v3支持另一种验证方式,需要创建一个v3的帐号,我们同样修改以下配置文件:
sdo:~ # vi /usr/local/snmp/share/snmp/snmpd.conf
然后添加一个只读帐号,如下:
rouser sdomonitor auth
可以看到,在v3中,"rouser"用于表示只读帐号类型,随后的"sdomonitor"是指定的用户名,后边的"auth"指明需要验证。
接下来,我们还要添加"sdomonitor"这个用户,这就是v3中的特殊机制,我们打开以下配置文件:
sdo:~ # vi /var/net-snmp/snmpd.conf
这个文件会在snmpd启动的时候被自动调用,我们需要在它里边添加创建用户的指令,如下:
createUser sdomonitor MD5 mypassword
这行配置的意思是创建一个名为"sdomonitor"的用户,密码为"mypassword",并且用MD5进行加密传输。这里要提醒的是:
密码至少要有8个字节
这是SNMP协议的规定,如果小于8个字节,通信将无法进行。
值得注意的是,一旦snmpd启动后,出于安全考虑,以上这行配置会被snmpd自动删除,当然,snmpd会将这些配置以密文的形式记录在其它文件中,重新启动snmpd是不需要再次添加这些配置的,除非您希望创建新的用户。
以上配置中的用户名、密码和加密方式,在云监控添加服务器的时候需要添加。
启动snmp服务
$ service snmpd start
用以下命令检查服务是否启动成功
$ snmpwalk -v 2c -c sdomonitor 127.0.0.1 system
如果要关闭,则可以直接kill这个进程,如下:
$ killall -9 snmpd 或者$ service snmpd stop