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的更多相关文章

  1. 使用linux的GDB打印STL(vector,map,set..................)

    在linux用gdb或者cgdb计较不爽的地方是无法打印STL的东西,所有啊去网上找了找解决方案https://www.douban.com/note/182826844/?qq-pf-to=pcqq ...

  2. Linux之GDB学习

    Linux之GDB学习 GDB是一款优秀的调试工具,懂的人自然懂,一直以来用它都没有好好整理过使用方法,我用的也是皮毛,目前先整理一下皮毛,日后再更新 使用方法 编译C++ 从编译的角度上来说,需要在 ...

  3. linux中gdb的可视化调试

    今天get到一个在linux下gdb调试程序的技巧和大家分享一下!平时我们利用gcc进行编程,进行程序调试时,观察程序的跳转等不是这么直观.都是入下的界面! 但是如果我们在编译连接时上加了-g命令生成 ...

  4. Linux知识(5)----LINUX下GDB调试

    命令 解释 示例   file 加载被调试的可执行程序文件.因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径. (gdb) file gdb-sample     r c Run的简 ...

  5. 一文入门Linux下gdb调试(二)

    作者:良知犹存 转载授权以及围观:欢迎添加微信号:Conscience_Remains 总述     今天我们介绍一下core dump文件,Core dump叫做核心转储,它是进程运行时在突然崩溃的 ...

  6. linux下gdb如何处理coredump错误

    linux下gdb如何处理coredump错误 在编写C++程序中,我们经常会遇到一种错误,segment fault, 这种coredump错误 会导致程序运行时异常退出或者终止,这种错误没有明显错 ...

  7. 【转载】Linux之gdb

    转载自:http://blog.chinaunix.net/uid-22312037-id-3812061.html 一.常规调试         gdb是Linux下常用的程序调试工具,当然前提是用 ...

  8. 【Linux】gdb调试core文件

    编写服务器端程序,很容易遇到Crash问题,比较幸运的是Linux提供了core file,保留了Crash的现场.有时候,根据当前的调用栈,并且打印出当前栈的变量就可以分析出crash的原因,但是, ...

  9. linux之gdb使用

    gdb是linux下用来调试的一款软件,在这里,我只记录平常经常会用到的知识点,用到什么,就记录什么,在调试环境中去熟悉调试方法和调试工具,这才会加深理解. gdb能够做什么?它可以按照你的定义,随心 ...

  10. linux之GDB常用命令汇总

    查看gdb的版本号 (1)rpm -q gdb 会显示是否安装gdb及版本号 (2)gdb --version也可以 breakpoint b main; b 20; 设置断点 breakpoint ...

随机推荐

  1. var与let循环中经典问题

    循环1: 下面代码运行结果是输出10   <script> var a =[]; for(var i = 0;i<10;i++){ a[i] = function(){ consol ...

  2. jreble for eclipse配置

    1 下载安装jrebel for eclipse  安装方法不再赘述.常规方式Install via Eclipse Marketplace->earch for JRebel 2 安装之后替换 ...

  3. java 使用poi导出Excel,设置单元格保护不可编辑

    //sheet表加密:等效excel的审阅菜单下的保护工作表 sheet.protectSheet(new String("333"));//333是密码 更多设置请参考:http ...

  4. Person Re-identification 系列论文笔记(八):SPReID

    Human Semantic Parsing for Person Re-identification Kalayeh M M, Basaran E, Gokmen M, et al. Human S ...

  5. 小爬爬5:scrapy介绍3持久化存储

    一.两种持久化存储的方式 1.基于终端指令的吃持久化存储: 特点:终端指令的持久化存储,只可以将parse方法的返回值存储到磁盘文件 因此我们需要将上一篇文章中的author和content作为返回值 ...

  6. 【windows系统下的navicat与ubuntu中的mysql的连接方法】

    ##红色代码直接复制到终端 1.首先,终端上mysql -u root -p,进入你的mysql数据库,操作数据库use mysql.2.切换root权限:sudo -i3.对root授权,输入:gr ...

  7. 设置PHP最长运行时间

    通常来说,默认的PHP程序最大运行时间是30s,如果你的程序运行超过这个时间限制,那么会有类似Maximum execution time of 30 seconds exceeded的报错. 有几种 ...

  8. Cython保护Python代码

    注:.pyc也有一定的保护性,容易被反编译出源码... 项目发布时,为防止源码泄露,需要对源码进行一定的保护机制,本文使用Cython将.py文件转为.so进行保护.这一方法,虽仍能被反编译,但难度会 ...

  9. Flask_Migrate数据库迁移

    migrate数据库迁移 有models,没有迁移仓库.本地新建数据库:首次创建迁移仓库.迁移脚本:执行迁移脚本生成数据库表: python manage.py db init python mana ...

  10. @bzoj - 4356@ Ceoi2014 Wall

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给出一个N*M的网格图,有一些方格里面存在城市,其中首都位于网格 ...