相当于shell的cd命令,pwd显示当前所在目录
(4)程序输出
info terminal用于显示程序用到的终端模式
3.break命令
在GDB中用break命令来设置断点,设置断点方法如下:
(1)break ,指定在函数function处设置断点(停止)
(2)break ,指定行号停止
(3)break+offset / break - offset ,在当前行号前面或后面的offset行停止
(4)break filename:linenum在源文件filename的linenum行处停止
(5)break filename:function,在源文件filename的function函数入口处停止
(6)break *address,在程序运行的内存地址处停止
(7)break,没有指定参数,表示在下一条指令处停止
(8)break ... if,其中...可以是上述的break
,break+offset / break - offset,break
等,在条件成立时停止
4.单步命令
(1)step 单步跟踪,如果由函数调用,则进入该函数,step后面不加count 表示一条条地执行
(2)next 单步跟踪,如果由函数调用,它不会进入该函数,同样地,next后面不加count表示一条条地执行
(3)set step-mode,set step-mode
on用于打开step-mode模式,这样,在进行单步调试时,程序不会因为没有debug信息而不停止,set step-mode
off用于关闭step-mode模式
(4)finish,运行程序,直到当前函数完成返回
(5)until(缩写u),一直在循环体内执行单步,不会退出来
(6)stepi(缩写si)和nexti(缩写ni),用于单步跟踪一条机器码
5.continue命令
当程序被停止后,可以使用continue命令恢复程序的运行直到程序结束或到达下一个断点
6.print命令
在调试程序时,当程序被停止时,可以使用print命令(缩写p),来查看当前程序的运行数据,如下:
(gdb) print sum
$3 = {133, 0, 0, 0, 0, 0, 0, 0, 0, 0}
(gdb) next
Breakpoint 1, add (a=56, b=99) at gdb.c:4
4 return a+b;
(gdb) next
5 }
(gdb) next
main () at gdb.c:24
24 printf("TQ2440 : %d",sum[i]);
(gdb) next
21 for(i = 0;i < 10;i++)
(gdb) next
23 sum[i] = add(array1[i],array2[i]);
(gdb) print sum
$4 = {133, 155, 0, 0, 0, 0, 0, 0, 0, 0}
(gdb)
7.watch命令
watch一般用来观察某个表达式的值是否有变化,如果有变化,马上停止程序执行(比如程序中的i等)
8.examine命令
该命令用来查看内存中地址的值
9.jump命令
一般来说,被调试的程序会按照程序代码的运行顺序依次执行,但是GDB也提供了乱序执行的功能,从而可以让程序随意跳跃
10.signal命令
使用singal命令,可以产生一个信号给调试程序,如中断信号,这非常方便程序的调试,signal的语法为signal
11.return命令
如果在函数中设置了调试断点,在断点后还有语句没有被执行,这是可以调用return命令来强制函数忽略没有执行的语句返回
return //立即返回
return
12.call命令
用于强制调用某函数
call
13.info命令
info命令可以在调试时查看寄存器,断点,观察点和信号等信息
info registers (查看除了否点寄存器以外的寄存器)
info all-registers(查看所有寄存器)
info break(查看断点)
info watchpoints(查看当前社会自的观察点)
info signal(查看那些信号被gdb检测)
14.disassemble命令
disassemble命令用与反汇编,它可以用来查看当前执行时源代码的机器码
disassemble func
(gdb) disassemble add
Dump of assembler code for function add:
0x08048374 <+0>: push ?p
0x08048375 <+1>: mov %esp,?p
0x08048377 <+3>: mov 0xc(?p),?x
0x0804837a <+6>: add 0x8(?p),?x
=> 0x0804837d <+9>: pop ?p
0x0804837e <+10>: ret
End of assembler dump.
(gdb)
Linux内核调试
调试嵌入式Linux内核的方法如下:
1.目标机“插桩”,如打上KGDB补丁,这样主机上的GDB可与目标机的KGDB通过串口或网口通信
2.使用仿真器,仿真器可直接连接目标的JTAG/BDM,这样主机GDB就可以通过与仿真器的通信来控制目标机
3.在目标板上通过printk(),oops,strace等软件方法进行“观察”调试
内核打印信息
在Linux中,内核打印语句printk()会将内核信息输出到内核信息缓冲区,内核信息缓冲区是一个环形缓冲区(ring
buffer),因此,如果塞入的消息过多,就会将之前的消息冲刷掉
printk()定义了8个消息级别,分别为0-7,越低级别(数值越大)的消息越不重要,第0级是紧急事件级,printk()级别定义如下:
#define KERN_EMERG "<0>" /system is
unusable
#define KERN_ALERT "<1>" /action
must be taken
immediately
#define KERN_CRIT "<2>" /critical
conditions
#define KERN_ERR "<3>" /error
conditions
#define KERN_WARNING "<4>" /warning
conditions
#define KERN_NOTICE "<5>" /normal
but significant
condition
#define KERN_INFO "<6>" /informational
#define KERN_DEBUG "<7>"
通过/proc/sys/kernel/printk文件可以调节printk的输出低级
控制台日志级别:优先级高于该值的消息将被打印至控制台
默认的消息日志级别
最低控制台日志级别
默认的控制台日志级别
上述4个值的默认值设置为6,4,1,7
在设备驱动中我们经常需要输出调试或系统的信息,可以直接采用printk(<7>...)输出
使用/proc
在Linux系统中,/proc文件系统十分有用,它用于内核向用户导出信息,而且Linux中很多命令本身通过分析/proc下的文件来完成的,如ps,top等
在Linux系统中,可以用如下函数创建/proc节点:
static inline struct proc_dir_entry *create_proc_entry(const char
*name,
mode_t mode, struct proc_dir_entry *parent);
static inline struct proc_dir_entry *create_proc_read_entry(const char
*name,
mode_t mode, struct proc_dir_entry *base,
read_proc_t
*read_proc, void * data);
create_proc_entry()函数用于创建/proc节点,而create_proc_read_entry()调用create_proc_entry()创建只读的/proc节点,参数name为/proc节点的名称,mode_t
为创建了节点(文件)的权限,parent/base为父目录节点,如果为NULL。则指proc目录
下列函数用于创建/proc目录
struct proc_dir_entry *proc_mkdir(const char *name,struct proc_dir_entry
*parent);
下面是上述两个创建目录和创建节点的一个例子
//创建/proc下的目录
example_dir = proc_mkdir("procfs_example",NULL);
if(ecample_dir == NULL){
rv = -ENOMEM;
goto out;
}
example_dir->owner = THIS_MODULE;
//创建一个例子/proc文件
example_file = create_proc_entry("example_file",0666,example_dir);
if(example_file == NULL){
rv = -ENOMEM;
goto out;
}
...
作为上述函数各返回值proc_dir_entry结构体中包含了/proc节点的度汗还是指针(read_proc_t
*read_proc),写函数指针(write_proc_t *write_proc)以及父节点,子节点信息等.
Linux系统中可用如下函数删除/proc节点
void remove_proc_entry(const char *name,struct proc_dir_entry
*parent);
监视工具
在Linux系统中,strace是一个相当有效的跟踪工具,它的主要特点是可以被用来监视系统调用,我们不仅可以用strace调试一个新开始的程序,也可以调试一个已经在运行的程序,它会得到各调用函数的返回值,如打开函数open(),成功时它会返回一个3(不一定是3),这时我们就可以通过这个返回值就可以知道函数成功与否(之后对fd为3的文件会就行的read(),write()等系统调用)。
内核调试器
kcore
GDB调试器可以把内核作为一个应用程序来调试,在这种方式中,需要给GDB指定未经压缩的内核镜像的文件名和"core"文件,对于一个正在运行的内核,"core文件"就是运行时的内存映像/proc/kcore,因此,使用GDB和kcore调试内核的典型命令如下:
gdb /usr/src/linux/vmlinux /proc/kcore
在gdb
/vmlinux
/proc/kcore这种调试方式中,GDB的绝大多数功能都不能使用,如修改内核变量的值,设置断点,单步执行等,可加载模块的symbol并没有包含在vmlinux中,必须使用一些辅助方法才能调试模块,Linux可加载模块是ELF格式的可执行映像,它们被分成几个段
.text:这个段包含模块可执行代码
.bss/.data:这两个段包含模块的变量,在编译时未初始化的变量在.bss段,而被初始化的段在.data段
当一个模块被加载后,在/sys/module目录下会新增一个对应模块的目录,下面是一个例子
[root@cgyl2010 ~]#ls
New0001.ko
devgecho hello.c
myhello signal.ko
wed
backlight
etc
hello.ko myled.ko
sixqd.ko
yg.ko
bin
fb
home
myzd
sy
yubu
cgy
fb_test
leds
opt
sys
yueyi.ko
cgyled
fost.ko
lib
poll thirdzd.ko
yy.ko
cs
gui.ko linuxrc
proc
tmp
zd
dev
gy
mnt
root
usr
devg
hello