|
|
发生段错误原因就是访问了不该访问的地址,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等。
下面根据Oops信息来分析一下段错误
first_drv.c
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- static struct class *segment_class;
- static struct device *segment_class_dev;
- unsigned char *c = NULL;
- int major;
- static int segment_test_open(struct inode *inode, struct file *file)
- {
- *c = 0x34;
- //printk("segment_test_open success!\n");
- return 0;
- }
- static struct file_operations segment_test_fops = {
- .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
- .open = segment_test_open,
- };
- static int segment_drv_init(void)
- {
- major = register_chrdev(0, "segment_test", &segment_test_fops); // 注册, 告诉内核
- segment_class = class_create(THIS_MODULE, "segment_test");
- segment_class_dev = device_create(segment_class, NULL, MKDEV(major, 0), NULL, "segment");
- c = (unsigned char *)0x48000000;
- printk("segment_drv_init success!\n");
- return 0;
- }
- static void segment_drv_exit(void)
- {
- device_destroy(segment_class, MKDEV(major,0));
- class_destroy(segment_class);
- unregister_chrdev(major, "segment_test");
- }
- module_init(segment_drv_init);
- module_exit(segment_drv_exit);
- MODULE_LICENSE("GPL");
firstdrvtest.c
#include
#include
#include
#include
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/segment", O_RDWR);
if (fd first_drv.dis
打开first_drv.dis有下面这一段:
00000000 :
0: e1a0c00d mov ip, sp
4: e92dd800 push {fp, ip, lr, pc}
8: e24cb004 sub fp, ip, #4 ; 0x4
c: e59f3010 ldr r3, [pc, #16] ; 24
10: e3a00000 mov r0, #0 ; 0x0
14: e5932000 ldr r2, [r3]
18: e3a03034 mov r3, #52 ; 0x34
1c: e5c23000 strb r3, [r2]
20: e89da800 ldm sp, {fp, sp, pc}
24: 00000000 .word 0x00000000
这里代码的实际地址都要加上偏移地址 bf0d7000,发生错误的那句代码是:
1c: e5c23000 strb r3, [r2]
根据我们的C语言代码可以看出这里是把0x34赋给变量时产生错误,产生错误的原因是加载模块初始化时赋给的一个地址非法:
c = (unsigned char *)0x48000000;
我们这里的程序比较短,可以一眼看出来,如果代码很长,就可以根据发生错误的位置,大概确定代码的位置,
然后再去看代码和汇编,这里要求比较高的汇编阅读能力
2. 如果发生的错误函数是属于内核的
这个时候和发生在模块里类似,不过这里要反汇编整个内核:
# arm-none-linux-gnueabi-objdump -D vmlinux > vmlinux.dis
打开vmlinux.dis,然后直接查找地址bf0d7000,接下来像上面一样分析代码
关于上面的打印信息,还有栈那一段没有讲,放到下一篇博文说
|
|
|