zoukankan      html  css  js  c++  java
  • linux 使用 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 ( 我们马上就到 )这样的工具.

  • 相关阅读:
    office2007/2010/2013输入公式的正确方式
    寻找与网页内容相关的图片(三)网易新闻与qq空间的做法
    寻找与网页内容相关的图片(二)reddit的做法
    用matplotlib绘制漫画风格的图表
    Monty Hall悖论
    天气中的概率 | 连续两天的天气独立吗?
    寻找与网页内容相关的图片(一) 开放图谱计划
    识别验证码:寻找数字的位置(三)
    识别验证码:寻找数字的位置(二)
    识别验证码:寻找数字的位置(一)
  • 原文地址:https://www.cnblogs.com/fanweisheng/p/11141586.html
Copyright © 2011-2022 走看看