您的位置:首页 > 运维架构 > Linux

Linux驱动开发(3):调试技术

2015-01-11 11:45 316 查看
主要的调试有3种:打印调试(printk),查询调试(/proc),监视调试(strace)。

即使采取了以上三种调试技术有时候驱动程序依然会出错,这样驱动程序在执行时候就会产生系统故障,这些错误通常会产生一个oops消息。

最后就是使用相关的调试器(gdb和kdb)跟踪代码,查看变量和计算机寄存器的值。

综上所述总共有5种调试技术:打印,查询,监视,系统故障,调试器。

这里我测试了打印调试和调试器gdb调试。

1.打印调试

printk是内核级别的打印命令,通过不同日志级别(loglevel),或者说“消息优先级”,可以让printk根据这些级别所表示的严重程度对消息进行分类。

在linux2.6内核头文件<linux/kernel.h>中定义了8种可用的日志级别字符串,消息优先级由高到低依次为:

#define KERN_EMERG "<0>" 紧急事件,一般在系统崩溃之前

#define KERN_ALERT "<1>" 立即采取行动

#define KERN_CRIT "<2>" 临界状态,严重的硬件或软件操作失败

#define KERN_ERR "<3>" 报告错误状态,一般用于硬件错误

#define KERN_WARNING "<4>" 警告

#define KERN_NOTICE "<5>" 提示

#define KERN_INFO "<6>" 提示性信息

#define KERN_DEBUG "<7>" 调试信息

例如:printk(KERN_ALERT "Here I am:%s:%i \n",_ _FILE_ _,_ _LINE_ _);

只有高于控制台日志级别的消息才能打印到控制台,而且值得注意的是,消息只能打印到控制台,linux系统有6个控制台tty1~tty6,Ctrl+Alt+F1~F6即可进入相

应的控制台,进入输入用户名lyj和linux密码(用户名是通过终端输入who查到的)。在其中编译make后装载和卸载hello模块时候可以看到打印信息,由于控制

台不能截图,所以网上对于终端不能打印出消息的原因介绍的含糊不清,其实原因就在于内核的消息是无法打印在终端的,只能通过文本控制台打印。

如果想要所有的信息都显示在控制台上可以执行:

# echo 8 > /proc/sys/kernel/printk

原因在于我们可以通过对文本文件/proc/sys/kernel/printk的访问来读取和修改控制台日志级别,里面包含的4个整数值分别为:当前日志级别,未明确指定日志级

别时的默认消息级别,最小允许日志级别,引导时默认日志级别,一般为 4 4 1 7。

2.gdb调试

模块会被划分为许多代码段,一个典型的模块可能包含十多个或者更多的代码段,但对于调试会话来讲,相关的代码段只有下面3个:

.text 模块的可执行代码

.bss

.data 这两个代码段保存模块的变量

获取模块的以上代码段的基地址的方法:

# grep 0 /sys/module/scull/sections/.text

# grep 0 /sys/module/scull/sections/.bss

# grep 0 /sys/module/scull/sections/.data

接下来打开gdb调试:

# gdb /usr/src/linux-source-3.2.0/vmlinux /proc/kcore

GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2) 7.4-2012.04

Copyright (C) 2012 Free Software Foundation, Inc.

License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law. Type "show copying"

and "show warranty" for details.

This GDB was configured as "x86_64-linux-gnu".

For bug reporting instructions, please see:

<http://bugs.launchpad.net/gdb-linaro/>...

Reading symbols from /usr/src/linux-source-3.2.0/vmlinux...(no debugging symbols found)...done.

[New process 1]

Core was generated by `BOOT_IMAGE=/vmlinuz-3.2.0-29-generic root=UUID=ff29c6ce-02ea-4394-884e-2eb5d083c'.

#0 0x0000000000000000 in ?? ()

(gdb)

然后就可以通过gdb检查可装载模块的变量:

(gdb) add-symbol-file /home/lyj/scull/scull.ko 0xffffffffa047a000 -s .bss 0xffffffffa047d840 -s .data 0xffffffffa047d000


add symbol table from file "/home/lyj/scull/scull.ko" at

.text_addr = 0xffffffffa047a000

.bss_addr = 0xffffffffa047d840

.data_addr = 0xffffffffa047d000

(y or n) y

Reading symbols from /home/lyj/scull/scull.ko...done. (这里我修改了scull的Makefile文件中的DEBUD else中-O2后加-g)

(gdb) p scull_devices[0]

$1 = {data = 0x0, quantum = 4000, qset = 1000, size = 0, access_key = 0,

sem = {lock = {raw_lock = {{head_tail = 0, tickets = {head = 0,

tail = 0}}}}, count = 1, wait_list = {next = 0xffff8801232cc028,

prev = 0xffff8801232cc028}}, cdev = {kobj = {name = 0x0, entry = {

next = 0xffff8801232cc040, prev = 0xffff8801232cc040}, parent = 0x0,

kset = 0x0, ktype = 0xffffffff81c41f20, sd = 0x0, kref = {refcount = {

counter = 1}}, state_initialized = 1, state_in_sysfs = 0,

state_add_uevent_sent = 0, state_remove_uevent_sent = 0,

uevent_suppress = 0}, owner = 0xffffffffa047d5e0,

ops = 0xffffffffa047d000, list = {next = 0xffff8801232cc088,

prev = 0xffff8801232cc088}, dev = 261095424, count = 1}}

由此我们可以查看模块中各种感兴趣的数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: