linux 使用 gdb

linux 使用 gdb,第1张

概述gdb 对于看系统内部是非常有用. 在这个级别精通调试器的使用要求对 gdb 命令有信心, 需要理解目标平台的汇编代码, 以及对应源码和优化的汇编码的能力.   调试器必须把内核作为一个应用程序来调用. 除了指定内核映象的文件名之外, 你需要在 命令行提供一个核心文件的名子. 对于一个运行的内核, 核心文件是内核核心映象, /proc/kcore. 一个典型的 gdb 调用看来如下:   gdb

gdb 对于看系统内部是非常有用. 在这个级别精通调试器的使用要求对 gdb 命令有信心,需要理解目标平台的汇编代码,以及对应源码和优化的汇编码的能力.

 

调试器必须把内核作为一个应用程序来调用. 除了指定内核映象的文件名之外,你需要在 命令行提供一个核心文件的名子. 对于一个运行的内核,核心文件是内核核心映象,

/proc/kcore. 一个典型的 gdb 调用看来如下:

 

gdb /usr/src/linux/vmlinux /proc/kcore

 

第一个参数是非压缩的 ELF 内核可执行文件的名子,不是 zImage 或者 bzImage 或者给 启动环境特别编译的任何东东.

 

gdb 命令行的第二个参数是核心文件的名子. 如同任何 /proc 中的文件,/proc/kcore 是在被读的时候产生的. 当 read 系统调用在 /proc 文件系统中执行时,它映射到一个 数据产生函数,而不是一个数据获取函数; 我们已经在本章"使用 /proc 文件系统"一节中 利用了这个特点. kcore 用来代表内核"可执行文件",以一个核心文件的形式; 它是一个 巨大的文件,因为他代表整个的内核地址空间,对应于所有的物理内存. 从 gdb 中,你 可查看内核变量,通过发出标准 gdb 命令. 例如,p jiffIEs 打印时钟的从启动到当前时 间的嘀哒数.

 

当你从 gdb 打印数据,内核仍然在运行,各种数据项在不同时间有不同的值; 然而,gdb 通过缓存已经读取的数据来优化对核心文件的存取. 如果你试图再次查看 jiffIEs 变量,你会得到和以前相同的答案. 缓存值来避免额外的磁盘存取对传统核心文件是正确的做法,但是在使用一个"动态"核心映象时就不方便. 解决方法是任何时候你需要刷新 gdb 缓存 时发出命令 core-file /proc/kcore; 调试器准备好使用新的核心文件并且丢弃任何旧信 息. 然而,你不会一直需要发出 core-file 在读取一个新数据时; gdb 读取核心以多个 几 KB 的块的方式,并且只缓存它已经引用的块.

 

gdb 通常提供的不少功能在你使用内核时不可用. 例如,gdb 不能修改内核数据; 它希望 在 *** 作内存前在它自己的控制下运行一个被调试的程序. 也不可能设置断点或观察点,或 者单步过内核函数.

 

注意,为了给 gdb 符号信息,你必须设置 CONfig_DEBUG_INFO 来编译你的内核. 结果是 一个很大的内核映象在磁盘上,但是,没有这个信息,深入内核变量几乎不可能.

 

有了调试信息,你可以知道很多内核内部的事情. gdb 愉快地打印出结构,跟随指针,等 等. 而有一个事情比较难,然而,是检查 modules. 因为模块不是传递给 gdb 的 vmlinux 映象,调试器对它们一无所知. 幸运的是,作为 2.6.7 内核,有可能教给 gdb 需要如何 检查可加载模块.

 

linux 可加载模块是 ELF 格式的可执行映象; 这样,它们被分成几个节. 一个典型的模 块可能包含一打或更多节,但是有 3 个典型的与一次调试会话相关:

 

.text

 

这个节包含有模块的可执行代码. 调试器必须知道在哪里以便能够给出回溯或者设 置断点.( 这些 *** 作都不相关,当运行一个调试器在 /proc/kcore 上,但是它们在 使用 kgdb 时可能有用,下面描述).

 

.bss

 

.data

 

这 2 个节持有模块的变量. 在编译时不初始化的任何变量在 .bss 中,而那些要 初始化的在 .data 里.

 

使 gdb 能够处理可加载模块需要通知调试器一个给定模块的节加载在哪里. 这个信息在 sysfs 中,在 /sys/module 下. 例如,在加载 scull 模块后,目录

/sys/module/scull/sections 包含名子为 .text 的文件; 每个文件的内容是那个节的基 地址.

 

我们现在该发出一个 gdb 命令来告诉它关于我们的模块. 我们需要的命令是 add- symble-flile; 这个命令使用模块目标文件名,.text 基地址作为参数,以及一系列描述 任何其他感兴趣的节安放在哪里的参数. 在深入位于 sysfs 的模块节数据后,我们可以 构建这样一个命令:

 

(gdb) add-symbol-file .../scull.ko 0xd0832000 \

-s .bss 0xd0837100 \

-s .data 0xd0836be0

 

我们已经包含了一个小脚本在例子代码里( gdbline ),它为给定的模块可以创建这个命 令.

 

我们现在使用 gdb 检查我们的可加载模块中的变量. 这是一个取自 scull 调试会话的快 速例子:

 

(gdb) add-symbol-file scull.ko 0xd0832000 \

-s .bss 0xd0837100 \

-s .data 0xd0836be0

add symbol table from file "scull.ko" at

.text_addr = 0xd0832000

.bss_addr = 0xd0837100

.data_addr = 0xd0836be0 (y or n) y

Reading symbols from scull.ko...done.

(gdb) p scull_devices[0]

$1 = {data = 0xcfd66c50,quantum = 4000,

qset = 1000,

size = 20881,

access_key = 0,

...}

 

这里我们看到第一个 scull 设备当前持有 20881 字节. 如果我们想,我们可以跟随数据 链,或者查看其他任何感兴趣的模块中的东东.

 

这是另一个值得知道的有用技巧:

 

(gdb) print *(address)

 

这里,填充 address 指向的一个 16 进制地址; 输出是对应那个地址的代码的文件和行 号. 这个技术可能有用,例如,来找出一个函数指针真正指向哪里.

 

我们仍然不能进行典型的调试任务,如设置断点或者修改数据; 为进行这些 *** 作,我们需 要使用象 kdb( 下面描述 ) 或者 kgdb ( 我们马上就到 )这样的工具.

总结

以上是内存溢出为你收集整理的linux 使用 gdb全部内容,希望文章能够帮你解决linux 使用 gdb所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1019103.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存