请选择 进入手机版 | 继续访问电脑版

[LINUX] Linux 体系 内核的调试详解

[复制链接]
查看61 | 回复5 | 2021-9-5 02:16:15 | 显示全部楼层 |阅读模式

调试是软件开辟 过程中一个必不可少的环节,在 Linux 内核开辟 的过程中也不可避免地会面对 怎样 调试内核的标题 。但是,Linux 体系 的开辟 者出于保证内核代码准确 性的思量 ,不乐意 在 Linux 内核源代码树中加入一个调试器。他们以为 内核中的调试器会误导开辟 者,从而引入不良的修正[1]。以是 对 Linux 内核举行 调试不停 是个令内核程序员感到棘手的标题 ,调试工作的艰苦性是内核级的开辟 区别于用户级开辟 的一个明显 特点。

只管 缺乏一种内置的调试内核的有用 方法,但是 Linux 体系 在内核发展的过程中也渐渐 形成了一些监视内核代码和错误跟踪的技术。同时,很多 的补丁程序应运而生,它们为标准内核附加了内核调试的支持。只管 这些补丁有些并不被 Linux 官方构造 承认 ,但他们确实功能美满 ,非常 强盛 。调试内核标题 时,利用 这些工具与方法跟踪内核实行 环境 ,并查看其内存和数据布局 将黑白 常有用 的。

本文将起首 先容 Linux 内核上的一些内核代码监视和错误跟踪技术,这些调试和跟踪方法因所要求的利用 环境和利用 方法而各有不同,然后重点先容 三种 Linux 内核的源代码级的调试方法。

1. Linux 体系 内核级软件的调试技术

printk() 是调试内核代码时最常用的一种技术。在内核代码中的特定位置加入printk() 调试调用,可以直接把所关心的信息打打印到屏幕上,从而可以观察程序的实行 路径和所关心的变量、指针等信息。 Linux 内核调试器(Linux kernel debugger,kdb)是 Linux 内核的补丁,它提供了一种在体系 能运行时对内核内存和数据布局 举行 检查的办法。Oops、KDB在文章把握 Linux 调试技术有详细 先容 ,大家可以参考。 Kprobes 提供了一个强行进入任何内核例程,并从制止 处理器无干扰地网络 信息的接口。利用 Kprobes 可以轻松地网络 处理器寄存器和全局数据布局 等调试信息,而无需对Linux内核频仍 编译和启动,详细 利用 方法,请参考利用 Kprobes 调试内核。

以上先容 了举行 Linux内核调试和跟踪时的常用技术和方法。当然,内核调试与跟踪的方法还不止以上提到的这些。这些调试技术的一个共同的特点在于,他们都不能提供源代码级的有用 的内核调试本领 ,有些只能称之为错误跟踪技术,因此这些方法都只能提供有限的调试本领 。下面将先容 三种实用的源代码级的内核调试方法。

回页首

2. 利用 KGDB构建Linux内核调试环境

kgdb提供了一种利用 gdb调试 Linux 内核的机制。利用 KGDB可以象调试平凡 的应用程序那样,在内核中举行 设置断点、检查变量值、单步跟踪程序运行等操作。利用 KGDB调试时必要 两台机器,一台作为开辟 机(Development Machine),另一台作为目的 机(Target Machine),两台机器之间通过串口或者以太网口相连。串口毗连 线是一根RS-232接口的电缆,在其内部两端 的第2脚(TXD)与第3脚(RXD)交叉相连,第7脚(接地脚)直接相连。调试过程中,被调试的内核运行在目的 机上,gdb调试器运行在开辟 机上。

如今 ,kgdb发布支持i386、x86_64、32-bit PPC、SPARC等几种体系布局 的调试器。有关kgdb补丁的下载地址见参考资料[4]。

2.1 kgdb的调试原理

安装kgdb调试环境必要 为Linux内核应用kgdb补丁,补丁实现的gdb长途 调试所必要 的功能包括下令 处理、陷阱处理及串口通讯3个紧张 的部分。kgdb补丁的紧张 作用是在Linux内核中添加了一个调试Stub。调试Stub是Linux内核中的一小段代码,提供了运行gdb的开辟 机和所调试内核之间的一个前言 。gdb和调试stub之间通过gdb串行协议举行 通讯。gdb串行协议是一种基于消息的ASCII码协议,包含了各种调试下令 。当设置断点时,kgdb负责在设置断点的指令前增长 一条trap指令,当实行 到断点时控制权就转移到调试stub中去。此时,调试stub的使命 就是利用 长途 串行通讯 协议将当前环境传送给gdb,然后从gdb处接奉命 令。gdb下令 告诉stub下一步该做什么,当stub收到继续实行 的下令 时,将恢复程序的运行环境,把对CPU的控制权重新交还给内核。

Linux 体系
内核的调试详解

2.2 Kgdb的安装与设置

下面我们将以Linux 2.6.7内核为例详细 先容 kgdb调试环境的建立过程。

2.2.1软硬件准备

以下软硬件设置 取自笔者举行 试验的体系 设置 环境 :

Linux 体系
内核的调试详解

kgdb补丁的版本遵照 如下定名 模式:Linux-A-kgdb-B,此中 A表示Linux的内核版本号,B为kgdb的版本号。以试验利用 的kgdb补丁为例,linux内核的版本为linux-2.6.7,补丁版本为kgdb-2.2。

物理毗连 好串口线后,利用 以下下令 来测试两台机器之间串口毗连 环境 ,stty下令 可以对串口参数举行 设置:

在development机上实行 :

stty ispeed 115200 ospeed 115200 -F /dev/ttyS0

在target机上实行 :

stty ispeed 115200 ospeed 115200 -F /dev/ttyS0

在developement机上实行 :

echo hello > /dev/ttyS0

在target机上实行 :

cat /dev/ttyS0

假如 串口毗连 没标题 的话在将在target机的屏幕上表现 "hello"。

2.2.2 安装与设置

下面我们必要 应用kgdb补丁到Linux内核,设置内核选项并编译内核。这方面的资料相对较少,笔者这里给出详细 的先容 。下面的工作在开辟 机(developement)上举行 ,以上面先容 的试验环境为例,某些详细 步骤在实际 的环境中大概 要做得当 的改动:

I、内核的设置 与编译

[root@lisl tmp]# tar -jxvf linux-2.6.7.tar.bz2 [root@lisl tmp]#tar -jxvf linux-2.6.7-kgdb-2.2.tar.tar [root@lisl tmp]#cd inux-2.6.7

请参照目次 补丁包中文件README给出的阐明 ,实行 对应体系布局 的补丁程序。由于试验在i386体系布局 上完成,以是 只必要 安装一下补丁:core-lite.patch、i386-lite.patch、8250.patch、eth.patch、core.patch、i386.patch。应用补丁文件时,请遵照 kgdb软件包内series文件所指定的次序 ,否则大概 会带来预想不到的标题 。eth.patch文件是选择以太网口作为调试的毗连 端口时必要 运用的补丁。

应用补丁的下令 如下所示:

[root@lisl tmp]#patch -p1 <../linux-2.6.7-kgdb-2.2/core-lite.patch

假如 内核准确 ,那么应用补丁时应该不会出现任何标题 (不会产生*.rej文件)。为Linux内核添加了补丁之后,必要 举行 内核的设置 。内核的设置 可以按照你的风俗 选择设置 Linux内核的恣意 一种方式。

[root@lisl tmp]#make menuconfig

在内核设置 菜单的Kernel hacking选项中选择kgdb调试项,比方 :

  • KGDB: kernel debugging with remote gdb Method for KGDB communication (KGDB: On generic serial port (8250)) --->
  • KGDB: Thread analysis
  • KGDB: Console messages through gdb [root@lisl tmp]#make

    编译内核之前请留意 Linux目次 下Makefile中的优化选项,默认的Linux内核的编译都以-O2的优化级别举行 。在这个优化级别之下,编译器要对内核中的某些代码的实行 次序 举行 改动,以是 在调试时会出现程序运行与代码次序 不划一 的环境 。可以把Makefile中的-O2选项改为-O,但不可去掉-O,否则编译会出标题 。为了使编译后的内核带有调试信息,留意 在编译内核的时间 必要 加上-g选项。

    不过,当选择"Kernel debugging->Compile the kernel with debug info"选项后设置 体系 将主动 打开调试选项。别的 ,选择"kernel debugging with remote gdb"后,设置 体系 将主动 打开"Compile the kernel with debug info"选项。

    内核编译完成后,利用 scp下令 举行 将相干 文件拷贝到target机上(当然也可以利用 别的 的网络工具,如rcp)。

    [root@lisl tmp]#scp arch/i386/boot/bzImage root@192.168.6.13:/boot/vmlinuz-2.6.7-kgdb [root@lisl tmp]#scp System.map root@192.168.6.13:/boot/System.map-2.6.7-kgdb

    假如 体系 启动使所必要 的某些装备 驱动没有编译进内核的环境 下,那么还必要 实行 如下操作:

    [root@lisl tmp]#mkinitrd /boot/initrd-2.6.7-kgdb 2.6.7 [root@lisl tmp]#scp initrd-2.6.7-kgdb root@192.168.6.13:/boot/ initrd-2.6.7-kgdb

    II、kgdb的启动

    在将编译出的内核拷贝的到target机器之后,必要 设置 体系 引导程序,加入内核的启动选项。以下是kgdb内核引导参数的阐明 :

    Linux 体系
内核的调试详解

    如表中所述,在kgdb 2.0版本之后内核的引导参数已经与从前 的版本有所不同。利用 grub引导程序时,直接将kgdb参数作为内核vmlinuz的引导参数。下面给出引导器的设置 示例。

    title 2.6.7 kgdb root (hd0,0) kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdb8250=1,115200

    在利用 lilo作为引导程序时,必要 把kgdb参放在由append修饰的语句中。下面给出利用 lilo作为引导器时的设置 示例。

    image=/boot/vmlinuz-2.6.7-kgdb label=kgdb read-only root=/dev/hda3 append="gdb gdbttyS=1 gdbbaud=115200"

    保存好以上设置 后重新启动计算机,选择启动带调试信息的内核,内核将在短暂的运行后在创建init内核线程之前停下来,打印出以下信息,并等待开辟 机的毗连 。

    Waiting for connection from remote gdb...

    在开辟 机上实行 :

    gdb file vmlinux set remotebaud 115200 target remote /dev/ttyS0

    此中 vmlinux是指向源代码目次 下编译出来的Linux内核文件的链接,它是没有颠末 压缩的内核文件,gdb程序从该文件中得到各种符号地址信息。

    如许 ,就与目的 机上的kgdb调试接口建立了接洽 。一旦建立联接之后,对Linux内的调试工作与对平凡 的运用程序的调试就没有什么区别了。任何时间 都可以通过键入ctrl+c打断目的 机的实行 ,举行 详细 的调试工作。

    在kgdb 2.0之前的版本中,编译内核后在arch/i386/kernel目次 下还会天生 可实行 文件gdbstart。将该文件拷贝到target机器的/boot目次 下,此时无需更改内核的启动设置 文件,直接利用 下令 :

    [root@lisl boot]#gdbstart -s 115200 -t /dev/ttyS0

    可以在KGDB内核引导启动完成后建立开辟 机与目的 机之间的调试接洽 。

    2.2.3 通过网络接口举行 调试

    kgdb也支持利用 以太网接口作为调试器的毗连 端口。在对Linux内核应用补丁包时,需应用eth.patch补丁文件。设置 内核时在Kernel hacking中选择kgdb调试项,设置 kgdb调试端口为以太网接口,比方 :

  • KGDB: kernel debugging with remote gdb Method for KGDB communication (KGDB: On ethernet) ---> ( ) KGDB: On generic serial port (8250) (X) KGDB: On ethernet

    别的 利用 eth0网口作为调试端口时,grub.list的设置 如下:

    title 2.6.7 kgdb root (hd0,0) kernel /boot/vmlinuz-2.6.7-kgdb ro root=/dev/hda1 kgdbwait kgdboe=@192.168. 5.13/,@192.168. 6.13/

    其他的过程与利用 串口作为毗连 端口时的设置过程类似 。

    留意 :只管 可以利用 以太网口作为kgdb的调试端口,利用 串口作为毗连 端口更加简单易行,kgdb项目组保举 利用 串口作为调试端口。

    2.2.4 模块的调试方法

    内核可加载模块的调试具有其特别 性。由于内核模块中各段的地址是在模块加载进内核的时间 才终极 确定的,以是 develop机的gdb无法得到各种符号地址信息。以是 ,利用 kgdb调试模块所必要 办理 的一个标题 是,必要 通过某种方法获得可加载模块的终极 加载地址信息,并把这些信息加入到gdb环境中。

    I、在Linux 2.4内核中的内核模块调试方法

    在Linux2.4.x内核中,可以利用 insmod -m下令 输出模块的加载信息,比方 :

    [root@lisl tmp]# insmod -m hello.ko >modaddr

    查看模块加载信息文件modaddr如下:

    .this 00000060 c88d8000 2**2 .text 00000035 c88d8060 2**2 .rodata 00000069 c88d80a0 2**5 …… .data 00000000 c88d833c 2**2 .bss 00000000 c88d833c 2**2 ……

    在这些信息中,我们关心的只有4个段的地址:.text、.rodata、.data、.bss。在development机大将 以上地址信息加入到gdb中,如许 就可以举行 模块功能的测试了。

    (gdb) Add-symbol-file hello.o 0xc88d8060 -s .data 0xc88d80a0 -s .rodata 0xc88d80a0 -s .bss 0x c88d833c

    这种方法也存在肯定 的不足,它不能调试模块初始化的代码,由于 此时模块初始化代码已经实行 过了。而假如 不实行 模块的加载又无法获得模块插入地址,更不大概 在模块初始化之前设置断点了。对于这种调试要求可以采用以下更换 方法。

    在target机上用上述方法得到模块加载的地址信息,然后再用rmmod卸载模块。在development机大将 得到的模块地址信息导入到gdb环境中,在内核代码的调用初始化代码之前设置断点。如许 ,在target机上再次插入模块时,代码将在实行 模块初始化之前停下来,如许 就可以利用 gdb下令 调试模块初始化代码了。

    别的 一种调试模块初始化函数的方法是:当插入内核模块时,内核模块机制将调用函数sys_init_module(kernel/modle.c)实行 对内核模块的初始化,该函数将调用所插入模块的初始化函数。程序代码片断如下:

    …… …… if (mod->init != NULL) ret = mod->init(); …… ……

    在该语句上设置断点,也能在实行 模块初始化之前停下来。

    II、在Linux 2.6.x内核中的内核模块调试方法

    Linux 2.6之后的内核中,由于module-init-tools工具的更改,insmod下令 不再支持-m参数,只有采取其他的方法来获取模块加载到内核的地址。通过分析ELF文件格式,我们知道程序中各段的意义如下:

    .text(代码段):用来存放可实行 文件的操作指令,也就是说是它是可实行 程序在内存种的镜像。

    .data(数据段):数据段用来存放可实行 文件中已初始化全局变量,也就是存放程序静态分配的变量和全局变量。

    .bss(BSS段):BSS段包含了程序中未初始化全局变量,在内存中 bss段全部置零。

    .rodata(只读段):该段保存着只读数据,在进程 映象中构造不可写的段。

    通过在模块初始化函数中放置一下代码,我们可以很容易 地获得模块加载到内存中的地址。

    …… int bss_var; static int hello_init(void) { printk(KERN_ALERT "Text location .text(Code Segment):%p\n",hello_init); static int data_var=0; printk(KERN_ALERT "Data Location .data(Data Segment):%p\n",&data_var); printk(KERN_ALERT "BSS Location: .bss(BSS Segment):%p\n",&bss_var); …… } Module_init(hello_init);

    这里,通过在模块的初始化函数中添加一段简单的程序,使模块在加载时打印出在内核中的加载地址。.rodata段的地址可以通过实行 下令 readelf -e hello.ko,取得.rodata在文件中的偏移量并加上段的align值得出。

    为了使读者可以或许 更好地举行 模块的调试,kgdb项目还发布了一些脚本程序可以或许 主动 探测模块的插入并主动 更新gdb中模块的符号信息。这些脚本程序的工作原理与前面表明 的工作过程相似,更多的信息请阅读参考资料[4]。

    2.2.5 硬件断点

    kgdb提供对硬件调试寄存器的支持。在kgdb中可以设置三种硬件断点:实行 断点(Execution Breakpoint)、写断点(Write Breakpoint)、访问断点(Access Breakpoint)但不支持I/O访问的断点。如今 ,kgdb对硬件断点的支持是通过宏来实现的,最多可以设置4个硬件断点,这些宏的用法如下:

    Linux 体系
内核的调试详解

    在有些环境 下,硬件断点的利用 对于内核的调试黑白 常方便的。有关硬件断点的定义和详细 的利用 阐明 见参考资料[4]。

    2.3.在VMware中搭建调试环境

    kgdb调试环境必要 利用 两台微机分别充当development机和target机,利用 VMware后我们只利用 一台计算机就可以顺遂 完成kgdb调试环境的搭建。以windows下的环境为例,创建两台假造 机,一台作为开辟 机,一台作为目的 机。

    2.3.1假造 机之间的串口毗连

    假造 机中的串口毗连 可以采用两种方法。一种是指定假造 机的串口毗连 到实际 的COM上,比方 开辟 机毗连 到COM1,目的 机毗连 到COM2,然后把两个串口通过串口线相毗连 。另一种更为简便的方法是:在较高一些版本的VMware中都支持把串口映射到定名 管道,把两个假造 机的串口映射到同一个定名 管道。比方 ,在两个假造 机中都选定同一个定名 管道 \\.\pipe\com_1,指定target机的COM口为server端,并选择"The other end is a virtual machine"属性;指定development机的COM口端为client端,同样指定COM口的"The other end is a virtual machine"属性。对于IO mode属性,在target上选中"Yield CPU on poll"复选择框,development机不选。如许 ,可以无需附加任何硬件,利用 假造 机就可以搭建kgdb调试环境。即降低了利用 kgdb举行 调试的硬件要求,也简化了建立调试环境的过程。

    Linux 体系
内核的调试详解

    2.3.2 VMware的利用 技巧

    VMware假造 机是比较占用资源的,尤其是象上面那样在Windows中利用 两台假造 机。因此,最好为体系 配备512M以上的内存,每台假造 机至少分配128M的内存。如许 的硬件要求,对如今 主流设置 的PC而言并不是过高的要求。出于体系 性能的思量 ,在VMware中只管 利用 字符界面举行 调试工作。同时,Linux体系 默认环境 下开启了sshd服务,建议利用 SecureCRT登陆到Linux举行 操作,如许 可以有较好的用户利用 界面。

    2.3.3 在Linux下的假造 机中利用 kgdb

    对于在Linux下面利用 VMware假造 机的环境 ,笔者没有做过实际 的探索。从原理上而言,只必要 在Linux下只要创建一台假造 机作为target机,开辟 机的工作可以在实际 的Linux环境中举行 ,搭建调试环境的过程与上面所述的过程类似 。由于只必要 创建一台假造 机,以是 利用 Linux下的假造 机搭建kgdb调试环境对体系 性能的要求较低。(vmware已经推出了Linux下的版本)还可以在development机上共同 利用 一些其他的调试工具,比方 功能更强盛 的cgdb、图形界面的DDD调试器等,以方便内核的调试工作。

    Linux 体系
内核的调试详解

    2.4 kgdb的一些特点和不足

    利用 kgdb作为内核调试环境最大的不足在于对kgdb硬件环境的要求较高,必须利用 两台计算机分别作为target和development机。只管 利用 假造 机的方法可以只用一台PC即能搭建调试环境,但是对体系 其他方面的性能也提出了肯定 的要求,同时也增长 了搭建调试环境时复杂程度。别的 ,kgdb内核的编译、设置 也比较复杂,必要 肯定 的技巧,笔者当时做的时间 也是费了很多周折。当调试过程竣事 后时,还必要 重新制作所要发布的内核。利用 kgdb并不能举行 全程调试,也就是说kgdb并不能用于调试体系 一开始的初始化引导过程。

    不过,kgdb是一个不错的内核调试工具,利用 它可以举行 对内核的全面调试,以致 可以调试内核的制止 处理程序。假如 在一些图形化的开辟 工具的帮助下,对内核的调试将更方便。

    回页首

    3. 利用 SkyEye构建Linux内核调试环境

    SkyEye是一个开源软件项目(OPenSource Software),SkyEye项目的 目的 是在通用的Linux和Windows平台上模仿 常见的嵌入式计算机体系 。SkyEye实现了一个指令级的硬件模仿 平台,可以模仿 多种嵌入式开辟 板,支持多种CPU指令集。SkyEye 的核心是 GNU 的 gdb 项目,它把gdb和 ARM Simulator很好地连合 在了一起。加入ARMulator 的功能之后,它就可以来仿真嵌入式开辟 板,在它上面不仅可以调试硬件驱动,还可以调试操作体系 。Skyeye项目如今 已经在嵌入式体系 开辟 范畴 得到了很大的推广。

    3.1 SkyEye的安装和μcLinux内核编译

    3.1.1 SkyEye的安装

    SkyEye的安装不是本文要先容 的重点,如今 已经有大量的资料对此举行 了先容 。有关SkyEye的安装与利用 的内容请查阅参考资料[11]。由于skyeye面目 紧张 用于嵌入式体系 范畴 ,以是 在skyeye上常常 利用 的是μcLinux体系 ,当然利用 Linux作为skyeye上运行的体系 也是可以的。由于先容 μcLinux 2.6在skyeye上编译的相干 资料并不多,以是 下面举行 详细 先容 。

    3.1.2 μcLinux 2.6.x的编译

    要在SkyEye中调试操作体系 内核,起首 必须使被调试内核能在SkyEye所模仿 的开辟 板上准确 运行。因此,准确 编译待调试操作体系 内核并设置 SkyEye是举行 内核调试的第一步。下面我们以SkyEye模仿 基于Atmel AT91X40的开辟 板,并运行μcLinux 2.6为例先容 SkyEye的详细 调试方法。

    I、安装交叉编译环境

    先安装交叉编译器。只管 在一些资料中阐明 利用 工具链arm-elf-tools-20040427.sh ,但是由于arm-elf-xxx与arm-linux-xxx对宏及链接处理的不同,履历 证实 利用 arm-elf-xxx工具链在链接vmlinux的末了 阶段将会出错。以是 这里我们利用 的交叉编译工具链是:arm-uclinux-tools-base-gcc3.4.0-20040713.sh,关于该交叉编译工具链的下载地址请参见[6]。留意 以下步骤最好用root用户来实行 。

    [root@lisl tmp]#chmod +x arm-uclinux-tools-base-gcc3.4.0-20040713.sh [root@lisl tmp]#./arm-uclinux-tools-base-gcc3.4.0-20040713.sh

    安装交叉编译工具链之后,请确保工具链安装路径存在于体系 PATH变量中。

    II、制作μcLinux内核

    得到μcLinux发布包的一个最容易 的方法是直接访问uClinux.org站点[7]。该站点发布的内核版本大概 不是最新的,但你能找到一个最新的μcLinux补丁以及找一个对应的Linux内核版本来制作一个最新的μcLinux内核。这里,将利用 这种方法来制作最新的μcLinux内核。如今 (笔者记录编写此文章时),所能得到的发布包的最新版本是uClinux-dist.20041215.tar.gz。

    下载uClinux-dist.20041215.tar.gz,文件的下载地址请参见[7]。

    下载linux-2.6.9-hsc0.patch.gz,文件的下载地址请参见[8]。

    下载linux-2.6.9.tar.bz2,文件的下载地址请参见[9]。

    如今 我们得到了整个的linux-2.6.9源代码,以及所需的内核补丁。请准备 一个有2GB空间的目次 里来完成以下制作μcLinux内核的过程。

    [root@lisl tmp]# tar -jxvf uClinux-dist-20041215.tar.bz2 [root@lisl uClinux-dist]# tar -jxvf linux-2.6.9.tar.bz2 [root@lisl uClinux-dist]# gzip -dc linux-2.6.9-hsc0.patch.gz | patch -p0

    或者利用 :

    [root@lisl uClinux-dist]# gunzip linux-2.6.9-hsc0.patch.gz [root@lisl uClinux-dist]patch -p0 < linux-2.6.9-hsc0.patch

    实行 以上过程后,将在linux-2.6.9/arch目次 下天生 一个补丁目次 -armnommu。删除原来μcLinux目次 里的linux-2.6.x(即谁人 linux-2.6.9-uc0),并将我们打好补丁的Linux内核目次 更名为linux-2.6.x。

    [root@lisl uClinux-dist]# rm -rf linux-2.6.x/ [root@lisl uClinux-dist]# mv linux-2.6.9 linux-2.6.x

    III、设置 和编译μcLinux内核

    由于 只是出于调试μcLinux内核的目的 ,这里没有天生 uClibc库文件及romfs.img文件。在发布μcLinux时,已经预置了某些常用嵌入式开辟 板的设置 文件,因此这里直接利用 这些设置 文件,过程如下:

    [root@lisl uClinux-dist]# cd linux-2.6.x [root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux- atmel_ deconfig

    atmel_deconfig文件是μcLinux发布时提供的一个设置 文件,存放于目次 linux-2.6.x /arch/armnommu/configs/中。

    [root@lisl linux-2.6.x]#make ARCH=armnommu CROSS_COMPILE=arm-uclinux- oldconfig

    下面编译设置 好的内核:

    [root@lisl linux-2.6.x]# make ARCH=armnommu CROSS_COMPILE=arm-uclinux- v=1

    一样寻常 环境 下,编译将顺遂 竣事 并在Linux-2.6.x/目次 下天生 未经压缩的μcLinux内核文件vmlinux。必要 留意 的是为了调试μcLinux内核,必要 打开内核编译的调试选项-g,使编译后的内核带有调试信息。打开编译选项的方法可以选择:

    "Kernel debugging->Compile the kernel with debug info"后将主动 打开调试选项。也可以直接修改linux-2.6.x目次 下的Makefile文件,为其打开调试开关。方法如下:。

    CFLAGS += -g

    最容易 出现的标题 是找不到arm-uclinux-gcc下令 的错误,紧张 缘故原由 是PATH变量中没有包含arm-uclinux-gcc下令 地点 目次 。在arm-linux-gcc的缺省安装环境 下,它的安装目次 是/root/bin/arm-linux-tool/,利用 以下下令 将路径加到PATH环境变量中。

    Export PATH=$PATH:/root/bin/arm-linux-tool/bin

    IV、根文件体系 的制作

    Linux内核在启动的时的末了 操作之一是加载根文件体系 。根文件体系 中存放了嵌入式体系 利用 的全部 应用程序、库文件及其他一些必要 用到的服务。出于文章篇幅的思量 ,这里不打算先容 根文件体系 的制作方法,读者可以查阅一些其他的相干 资料。值得留意 的是,由设置 文件skyeye.conf指定了装载到内核中的根文件体系 。

    3.2 利用 SkyEye调试

    编译完μcLinux内核后,就可以在SkyEye中调试该ELF实行 文件格式的内核了。前面已经说过利用 SkyEye调试内核与利用 gdb调试运用程序的方法类似 。

    必要 提示 读者的是,SkyEye的设置 文件-skyeye.conf记录了模仿 的硬件设置 和模仿 实行 举动 。该设置 文件是SkyEye体系 中一个及其紧张 的文件,很多错误和非常 环境 的发生都和该文件有关。在安装设置 SkyEye出错时,请起首 检查该设置 文件然后再举行 其他的工作。此时,全部 的准备 工作已经完成,就可以举行 内核的调试工作了。

    3.3利用 SkyEye调试内核的特点和不足

    在SkyEye中可以举行 对Linux体系 内核的全程调试。由于SkyEye如今 紧张 支持基于ARM内核的CPU,因此一样寻常 而言必要 利用 交叉编译工具编译待调试的Linux体系 内核。别的 ,制作SkyEye中利用 的内核编译、设置 过程比较复杂、繁琐。不过,当调试过程竣事 后无需重新制作所要发布的内核。

    SkyEye只是对体系 硬件举行 了肯定 程度上的模仿 ,以是 在SkyEye与真实硬件环境相比较而言还是有肯定 的差距,这对一些与硬件精密 相干 的调试大概 会有肯定 的影响,比方 驱动程序的调试。不过对于大部分软件的调试,SkyEye已经提供了精度充足 的模仿 了。

    SkyEye的下一个目的 是和eclipse连合 ,有了图形界面,能为调试和查看源码提供一些方便。

    回页首

    4. 利用 UML调试Linux内核

    User-mode Linux(UML)简单说来就是在Linux内运行的Linux。该项目是使Linux内核成为一个运行在 Linux 体系 之上单独的、用户空间的进程 。UML并不是运行在某种新的硬件体系布局 之上,而是运行在基于 Linux 体系 调用接口所实现的假造 机。正是由于UML是一个将Linux作为用户空间进程 运行的特性,可以利用 UML来举行 操作体系 内核的调试。有关UML的先容 请查阅参考资料[10]、[12]。

    4.1 UML的安装与调试

    UML的安装必要 一台运行Linux 2.2.15以上,或者2.3.22以上的I386机器。对于2.6.8及其从前 版本的UML,采用两种情势 发布:一种是以RPM包的情势 发布,一种是以源代码的情势 提供UML的安装。按照UML的阐明 ,以RPM情势 提供的安装包比较陈旧且会有很多 标题 。以二进制情势 发布的UML包并不包含所必要 的调试信息,这些代码在发布时已经做了程度不同的优化。以是 ,要想利用 UML调试Linux体系 内核,必要 利用 最新的UML patch代码和对应版本的Linux内核编译、安装UML。完成UML的补丁之后,会在arch目次 下产生一个um目次 ,紧张 的UML代码都放在该目次 下。

    从2.6.9版本之后(包含2.6.9版本的Linux),User-Mode Linux已经随Linux内核源代码树一起发布,它存放于arch/um目次 下。

    编译好UML的内核之后,直接利用 gdb运行已经编译好的内核即可举行 调试。

    4.2利用 UML调试体系 内核的特点和不足

    如今 ,用户模式 Linux 假造 机也存在肯定 的范围 性。由于UML假造 机是基于Linux体系 调用接口的方式实现的假造 机,以是 用户模式内核不能访问主机体系 上的硬件装备 。因此,UML并不得当 于调试那些处理实际 硬件的驱动程序。不过,假如 所编写的内核程序不是硬件驱动,比方 Linux文件体系 、协议栈等环境 ,利用 UML作为调试工具还是一个不错的选择。

    回页首

    5. 内核调试设置 选项

    为了方便调试和测试代码,内核提供了很多 与内核调试相干 的设置 选项。这些选项大部分都在内核设置 编辑器的内核开辟 (kernel hacking)菜单项中。在内核设置 目次 树菜单的其他地方也还有一些可设置 的调试选项,下面将对他们作肯定 的先容 。

    Page alloc debugging :CONFIG_DEBUG_PAGEALLOC:

    不利用 该选项时,开释 的内存页将从内核地址空间中移出。利用 该选项后,内核推迟移出内存页的过程,因此可以或许 发现内存走漏 的错误。

    Debug memory allocations :CONFIG_DEBUG_SLAB:

    该打开该选项时,在内核实行 内存分配之前将实行 多种范例 检查,通过这些范例 检查可以发现诸如内核过量分配或者未初始化等错误。内核将会在每次分配内存前后时设置一些警戒值,假如 这些值发生了变化那么内核就会知道内存已经被操作过并给出明确 的提示,从而使各种隐晦的错误变得容易 被跟踪。

    Spinlock debugging :CONFIG_DEBUG_SPINLOCK:

    打开此选项时,内核将可以或许 发现spinlock未初始化及各种其他的错误,能用于清除 一些死锁引起的错误。

    Sleep-inside-spinlock checking:CONFIG_DEBUG_SPINLOCK_SLEEP:

    打开该选项时,当spinlock的持有者要就寝 时会实行 相应的检查。实际 上即使调用者如今 没有就寝 ,而只是存在就寝 的大概 性时也会给出提示。

    Compile the kernel with debug info :CONFIG_DEBUG_INFO:

    打开该选项时,编译出的内核将会包含全部的调试信息,利用 gdb时必要 这些调试信息。

    Stack utilization instrumentation :CONFIG_DEBUG_STACK_USAGE:

    该选项用于跟踪内核栈的溢出错误,一个内核栈溢出错误的显着 的征象 是产生oops错误却没有列出体系 的调用栈信息。该选项将使内核举行 栈溢出检查,并使内核举行 栈利用 的统计。

    Driver Core verbose debug messages:CONFIG_DEBUG_DRIVER:

    该选项位于"Device drivers-> Generic Driver Options"下,打开该选项使得内核驱动核心产生大量的调试信息,并将他们记录到体系 日志 中。

    Verbose SCSI error reporting (kernel size +=12K) :CONFIG_SCSI_CONSTANTS:

    该选项位于"Device drivers/SCSI device support"下。当SCSI装备 出错时内核将给出详细 的出错信息。

    Event debugging:CONFIG_INPUT_EVBUG:

    打开该选项时,会将输入子体系 的错误及全部 变乱 都输出到体系 日志 中。该选项在产生了详细 的输入报告的同时,也会导致肯定 的安全标题 。

    以上内核编译选项必要 读者根据本身 所举行 的内核编程的实际 环境 ,机动 选取。在利用 以上先容 的三种源代码级的内核调试工具时,一样寻常 必要 选取CONFIG_DEBUG_INFO选项,以使编译的内核包含调试信息。

    回页首

    6. 总结

    上面先容 了一些调试Linux内核的方法,特别 是详细 先容 了三种源代码级的内核调试工具,以及搭建这些内核调试环境的方法,读者可以根据本身 的环境 从中作出选择。

    调试工具(比方 gdb)的运行都必要 操作体系 的支持,而此时内核由于一些错误的代码而不能准确 实行 对体系 的管理功能,以是 对内核的调试必须采取一些特别 的方法举行 。以上先容 的三种源代码级的调试方法,可以归纳为以下两种策略:

    I、为内核增长 调试Stub,利用 调试Stub举行 长途 调试,这种调试策略必要 target及development机器才能完成调试使命 。

    II、将假造 机技术与调试工具相连合 ,使Linux内核在假造 机中运行从而利用 调试器对内核举行 调试。这种策略必要 制作得当 在假造 机中运行的体系 内核。

    由不同的调试策略决定了举行 调试时不同的工作原理,同时也形成了各种调试方法不同的软硬件需求和各自的特点。

    别的 ,必要 阐明 的是内核调试本领 的把握 很大程度上取决于履历 和对整个操作体系 的深入明确 。对体系 内核的全面深入的明确 ,将能在很大程度上加快对Linux体系 内核的开辟 和调试。

    对体系 内核的调试技术和方法绝不止上面先容 所涉及的内容,这里只是先容 了一些常常 看到和听到方法。在Linux内核向前发展的同时,内核的调试技术也在不断的进步。盼望 以上先容 的一些方法能对读者开辟 和学习Linux有所帮助。


    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
  • 本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    回复

    使用道具 举报

    avatar 温柔老虎 | 2021-9-16 23:44:33 | 显示全部楼层
    大神就是大神,这么经典!
    回复

    使用道具 举报

    avatar 掘金入眠刈 | 2021-9-20 02:35:18 | 显示全部楼层
    最近压力山大啊!
    回复

    使用道具 举报

    avatar 因醉鞭名马幌 | 2021-9-26 05:33:46 | 显示全部楼层
    哥回复的不是帖子,是寂寞!
    回复

    使用道具 举报

    avatar 李墨285 | 2021-10-6 03:16:54 | 显示全部楼层
    admin楼主的头像能辟邪啊!
    回复

    使用道具 举报

    在哪里跌倒,就在那里多爬一会儿!
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则