在本节里边咱们就详细来讲一下如何用咱们自己完成的体系调用来调试使用程序.
一、原理
要想克己体系调用,当然辅弼要做的便是理解体系调用的进程:
咱们拿open函数来举个比方:当用户空间履行open函数时,会通过glibc函数库的效果终究去调用sys_open函数,sys_open函数终究又会调用咱们详细注册的open函数!那么这儿最主要的便是glibc函数库干了些什么呢?其实它的效果便是当用户空间履行open函数时,会去履行一条swi #val指令,这条指令会使cpu发生反常,并跳转到反常向量进口:vector_swi处去履行,之后的代码会依据引发反常的指令取出其间的参数,并依据这个参数调用对应的处理函数!sys_open、sys_read、sys_write这些函数是放在一个数组里边的,便是依据取出的这个val值为下标找到sys_open函数!
说的有点乱,咱们来理一理:app调用open-》swi #val-》引发cpu反常-》跳转到反常向量进口处-》依据引发反常的指令调用对应的处理函数!
那么咱们克己体系调用的话,需求完成两点:
1、写一个使用函数:swi #val
2、在内核里边仿sys_xxx写一个函数,放入数组!
前者用于引发反常,后者用于详细完成!
二、完成
1、内核函数
(1)在arch/arm/kernel/call.S文件里边的CALL()列表的终究增加一项,如:CALL(sys_hello)
这儿是用来调用sys_hello
(2)在fs/read_write.c文件里参加如下代码:
asmlinkage void sys_hello(const char __user * buf, size_t count)
{
char ker_buf[100];
if(buf)
{
// 意图是从用户空间复制数据到内核空间,失利回来没有被复制的字节数,成功回来0
三、进程
1、修正使用程序的可履行文件,替换某个方位的代码为swi val
2、履行程序
3、进入到sys_hello->在sys_hello里边打印信息->履行本来的指令->回来
四、详细完成
咱们的使用程序是:
//file:test_sc.c
#include
int cnt = 0;
void C(void)
{
int i = 0;
while (1)
{
printf("Hello, cnt = %d, i = %d\n", cnt, i);
cnt++;
i = i + 2;
sleep(5);
}
}
void B(void)
{
C();
}
void A(void)
{
B();
}
int main(int argc, char **argv)
{
A();
return 0;
}
详细进程:
(1)编译:arm-linux-gcc test_sc.c -o test_sc
(2)反汇编:arm-linux-objdump -D test_sc > test_sc.dis
(3)咱们翻开上面得到的可履行文件和反汇编文件
比方咱们想在C函数的i=i+2;处打断点的话,咱们先在反汇编文件里边找到对应的指令:
84d4: e2833002 add r3, r3, #2 ; 0x2
其间:e2833002是机器码,这是咱们所需求的!
咱们去可履行文件里边去查找这个机器码,在可履行文件里它对应的机器码应该是:02 30 83 e2
咱们将此机器码改为swi指令的机器码!
咱们能够将上一节里边的文件反汇编一下,然后得到swi的机器码为:ef900160
(4)通过上面的修正,当程序履行到i=i+2;这条指令时,会发生体系调用,终究履行sys_hello函数。
在sys_hello函数里边,咱们能够最一些必要的作业,详细程序如下:
此外还需求在:include/linux/syscalls.h 文件里将函数声明改为:asmlinkage void sys_hello(const char __user * buf, int count);
(5)编译内核,用新内核发动
(6)运转测验程序(在此之前要修正测验程序的权限:chmod 777 test_sc_swi),输出信息如下:
Hello, cnt = 0, i = 0
sys_hello: cnt = 1
sys_hello: i = 0
Hello, cnt = 1, i = 2
sys_hello: cnt = 2
sys_hello: i = 2
Hello, cnt = 2, i = 4
sys_hello: cnt = 3
sys_hello: i = 4
测验成功!
本节讲的调试办法比较不流畅,一般不会选用!