Shi*_*nok 52 linux debugging kernel linux-kernel
用于在Linux内核上进行实时调试的最常见和不常见的方法和工具是什么?我知道Linus比如说.为防止这种调试Linux内核,或者至少是,因此什么都没有在这个意义上在这些年已经完成,但老实说,自2000年以来大量的时间已经过去了,我很感兴趣,如果这种心态已经改变了有关Linux的项目以及目前使用哪些方法在Linux内核上进行实时调试(本地或远程)?
欢迎参考有关所提及的技术和工具的演练和教程.
Kev*_*vin 28
另一种选择是使用ICE/JTAG控制器和GDB.这种"硬件"解决方案特别适用于嵌入式系统,
但是例如Qemu提供类似的功能:
与侦听":1234本地主机":一个GDB"远程"存根启动QEMU qemu -s ...,
然后使用GDB打开vmlinux使用调试信息编译的内核文件(您可以查看这个邮件列表线程,讨论内核的优化).
连接GDB和Qemu: target remote localhost:1234
看到你是活的内核:
(gdb) where
#0 cpu_v7_do_idle () at arch/arm/mm/proc-v7.S:77
#1 0xc0029728 in arch_idle () atarm/mach-realview/include/mach/system.h:36
#2 default_idle () at arm/kernel/process.c:166
#3 0xc00298a8 in cpu_idle () at arch/arm/kernel/process.c:199
#4 0xc00089c0 in start_kernel () at init/main.c:713
Run Code Online (Sandbox Code Playgroud)遗憾的是,到目前为止,使用GDB无法进行用户空间调试(没有任务列表信息,没有MMU重新编程以查看不同的进程上下文,...),但是如果你留在内核空间,这是非常方便的.
info threads将为您提供不同CPU的列表和状态编辑:
您可以在此PDF中获得有关该过程的更多详细信息:
Md *_*man 21
在调试Linux内核时,我们可以使用多种工具,例如,调试器(KDB,KGDB),崩溃时转储(LKCD),跟踪工具包(LTT,LTTV,LTTng),定制内核工具(dprobes,kprobes).在下一节中,我试图总结其中的大多数,希望这些将有所帮助.
LKCD(Linux Kernel Crash Dump)工具允许Linux系统在发生崩溃时写入其内存的内容.可以进一步分析这些日志以查找崩溃的根本原因.关于LKCD的资源
哎呀,当内核检测到问题,它将打印Oops消息.这样的消息是由错误处理程序(arch/*/kernel/traps.c)中的printk语句生成的.内核中的专用环形缓冲区由printk语句使用.Oops包含诸如发生Oops的CPU,CPU寄存器的内容,Oops的数量,描述,堆栈跟踪跟踪等信息.有关内核Oops的资源
Dynamic Probes是由IBM开发的流行的Linux调试工具之一.此工具允许在用户和内核空间中的系统中的几乎任何位置放置"探针".探针由一些代码(用专门的,面向堆栈的语言编写)组成,当控制命中给定点时执行.有关下面列出的Dynamic Probe的资源
Linux Trace Toolkit是一个内核补丁和一组相关的实用程序,允许跟踪内核中的事件.该跟踪包括定时信息,并且可以创建在给定时间段内发生的事情的相当完整的图像.LTT,LTT Viewer和LTT Next Generation的资源
MEMWATCH是一个开源内存错误检测工具.它的工作原理是在gcc语句中定义MEMWATCH,并在代码中添加头文件.通过这个,我们可以跟踪内存泄漏和内存损坏.有关MEMWATCH的资源
ftrace是一个很好的Linux内核跟踪框架.ftrace跟踪内核的内部操作.该工具包含在2.6.27的Linux内核中.通过其各种跟踪器插件,ftrace可以针对不同的静态跟踪点,例如调度事件,中断,内存映射I/O,CPU电源状态转换以及与文件系统和虚拟化相关的操作.此外,可以使用动态跟踪内核函数调用,可选地通过使用glob限制函数子集,并且可以生成调用图并提供堆栈使用.你可以在 https://events.linuxfoundation.org/slides/2010/linuxcon_japan/linuxcon_jp2010_rostedt.pdf找到一个很好的ftrace教程.
ltrace是Linux中的一个调试实用程序,用于显示用户空间应用程序对共享库的调用.此工具可用于跟踪任何动态库函数调用.它拦截并记录由执行过程调用的动态库调用以及该进程接收的信号.它还可以拦截和打印程序执行的系统调用.
KDB是Linux内核的内核调试器.KDB遵循简单的shell风格接口.我们可以用它来检查内存,寄存器,进程列表,dmesg,甚至设置断点以在某个位置停止.通过KDB,我们可以设置断点并执行一些基本的内核运行控制(尽管KDB不是源代码级调试器).关于KDB的几个方便的资源
KGDB旨在用作Linux内核的源代码级调试器.它与gdb一起用于调试Linux内核.使用kgdb需要两台机器.其中一台机器是开发机器,另一台是目标机器.要调试的内核在目标计算机上运行.期望gdb可用于"闯入"内核以检查内存,变量并查看调用堆栈信息,类似于应用程序开发人员使用gdb调试应用程序的方式.可以在内核代码中放置断点并执行一些有限的执行步进.关于KGDB的几个方便的资源
小智 20
根据维基,在过去的几年内kgdb被合并到内核中2.6.26.kgdb是一个远程调试器,所以你在内核中激活它然后以某种方式将gdb附加到它.我不知怎的说,似乎有很多选择 - 请参阅连接gdb.鉴于kgdb现在已经在源代码树中,我会说这是您想要使用的内容.
所以看起来Linus屈服了.但是,我会强调他的论点 - 你应该知道你在做什么并且很了解系统.这是核心土地.如果出现任何问题,你就不会得到segfault,你可以从后来的一些模糊问题中得到任何东西.这里是龙.小心谨慎,你已被警告过.
Bra*_*rad 14
"实时"调试的另一个好工具是kprobes/dynamic probe.
这使您可以动态构建在执行某些地址时运行的小型模块 - 有点像断点.
它们的最大优点是:
最好是做一些事情,比如打一个断点,查看什么是数据值,或检查是否有事情被改变/覆盖等.如果你想"逐步执行代码" - 它不会这样做.
增加 - 2018年:
另一个非常强大的方法是一个简单称为"perf"的程序,它可以汇总许多工具(如动态探测器),并替换/删除其他工具(如oprofile).
特别是,该perf probe命令可用于轻松地创建/添加动态探测到系统,之后perf record可以通过perf report(或perf script)命中探测器来探测系统并报告信息(和回溯).如果你在内核中有很好的调试符号,你甚至可以在没有内核的情况下从系统中获得出色的知识.请在man perf(在Google或您的系统上)获取有关此工具的更多信息,或查看其中的精彩页面:
http://www.brendangregg.com/perf.html
在 Ubuntu 16.10 主机上测试的 QEMU + GDB 分步程序
为了快速从头开始,我制作了一个最小的全自动 QEMU + Buildroot 示例:https : //github.com/cirosantilli/linux-kernel-module-cheat下面介绍了主要步骤。
首先获得一个根文件系统rootfs.cpio.gz。如果您需要,请考虑:
init可执行映像:https : //unix.stackexchange.com/questions/122717/custom-linux-distro-that-runs-just-one-program-nothing-else/238579#238579然后在 Linux 内核上:
git checkout v4.9
make mrproper
make x86_64_defconfig
cat <<EOF >.config-fragment
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_KERNEL=y
CONFIG_GDB_SCRIPTS=y
EOF
./scripts/kconfig/merge_config.sh .config .config-fragment
make -j"$(nproc)"
qemu-system-x86_64 -kernel arch/x86/boot/bzImage \
-initrd rootfs.cpio.gz -S -s
Run Code Online (Sandbox Code Playgroud)
在另一个终端上,假设您想从start_kernel以下位置开始调试:
gdb \
-ex "add-auto-load-safe-path $(pwd)" \
-ex "file vmlinux" \
-ex 'set arch i386:x86-64:intel' \
-ex 'target remote localhost:1234' \
-ex 'break start_kernel' \
-ex 'continue' \
-ex 'disconnect' \
-ex 'set arch i386:x86-64' \
-ex 'target remote localhost:1234'
Run Code Online (Sandbox Code Playgroud)
我们完成了!!
有关内核模块,请参阅:如何使用 QEMU 调试 Linux 内核模块?
对于 Ubuntu 14.04,hbreak需要GDB 7.7.1 ,break软件断点被忽略。在 16.10 中不再是这种情况。另见:https : //bugs.launchpad.net/ubuntu/+source/qemu-kvm/+bug/901944
凌乱的disconnect以及它之后的内容是解决错误:
Remote 'g' packet reply is too long: 000000000000000017d11000008ef4810120008000000000fdfb8b07000000000d352828000000004040010000000000903fe081ffffffff883fe081ffffffff00000000000e0000ffffffffffe0ffffffffffff07ffffffffffffffff9fffff17d11000008ef4810000000000800000fffffffff8ffffffffff0000ffffffff2ddbf481ffffffff4600000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f0300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000801f0000
Run Code Online (Sandbox Code Playgroud)
相关主题:
也可以看看:
已知限制:
-O0:How to de-optimize the Linux kernel to and compile it with -O0?max-completions修复之后,GDB 7.11 也会在某些类型的选项卡完成时让您记忆犹新:大型二进制文件的选项卡完成中断可能是该补丁中未涵盖的某些极端情况。所以ulimit -Sv 500000在调试之前an是明智的操作。当我完成file<tab>如下filename参数的选项卡时,特别爆炸sys_execve:https : //stackoverflow.com/a/42290593/895245KGDB + QEMU逐步
KGDB是内核子系统,允许您从主机GDB逐步调试内核本身。
我的QEMU + Buildroot示例是在没有实际硬件的情况下品尝它的好方法:https : //github.com/cirosantilli/linux-kernel-module-cheat/tree/1969cd6f8d30dace81d9848c6bacbb8bad9dacd8#kgdb
优缺点与其他方法:
主要步骤是:
使用以下命令编译内核:
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_INFO=y
CONFIG_CONSOLE_POLL=y
CONFIG_KDB_CONTINUE_CATASTROPHIC=0
CONFIG_KDB_DEFAULT_ENABLE=0x1
CONFIG_KDB_KEYBOARD=y
CONFIG_KGDB=y
CONFIG_KGDB_KDB=y
CONFIG_KGDB_LOW_LEVEL_TRAP=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_TESTS=y
CONFIG_KGDB_TESTS_ON_BOOT=n
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x1
CONFIG_SERIAL_KGDB_NMI=n
Run Code Online (Sandbox Code Playgroud)
其中大多数不是强制性的,但这是我测试过的。
添加到您的QEMU命令:
-append 'kgdbwait kgdboc=ttyS0,115200' \
-serial tcp::1234,server,nowait
Run Code Online (Sandbox Code Playgroud)使用以下命令从Linux内核源树的根目录运行GDB:
gdb -ex 'file vmlinux' -ex 'target remote localhost:1234'
Run Code Online (Sandbox Code Playgroud)在GDB中:
(gdb) c
Run Code Online (Sandbox Code Playgroud)
并且启动应该完成。
在QEMU中:
echo g > /proc/sysrq-trigger
Run Code Online (Sandbox Code Playgroud)
GDB应该崩溃了。
现在我们完成了,您可以照常使用GDB:
b sys_write
c
Run Code Online (Sandbox Code Playgroud)在Ubuntu 14.04中测试。
KGDB +树莓派
与上面完全相同的设置几乎可以在Raspberry Pi 2,Raspbian Jessie 2016-05-27上运行。
您只需要学习在Pi上执行QEMU步骤即可,这些步骤很容易实现。
按照https://www.raspberrypi.org/documentation/linux/kernel/building.md的说明添加配置选项并重新编译内核。不幸的是,默认内核构建中缺少选项,尤其是没有调试符号,因此重新编译是需要。
编辑cmdline.txt启动分区并添加:
kgdbwait kgdboc=ttyAMA0,115200
Run Code Online (Sandbox Code Playgroud)通过以下方式连接gdb到串行:
arm-linux-gnueabihf-gdb -ex 'file vmlinux' -ex 'target remote /dev/ttyUSB0'
Run Code Online (Sandbox Code Playgroud)
如果您不熟悉该序列号,请查看以下内容:https : //www.youtube.com/watch?v= da5Q7xL_OTo您所需要的只是一个像这样的廉价适配器。在尝试KGDB之前,请确保您可以通过序列获得Shell以确保其正常工作。
做:
echo g | sudo tee /proc/sysrq-trigger
Run Code Online (Sandbox Code Playgroud)
从SSH会话内部进行,因为串行已由GDB进行。
通过此设置,我能够在其中设置断点sys_write,暂停程序执行,列出源并继续。
但是,有时当我next在sys_writeGDB中进行操作时,它只是挂起并多次打印此错误消息:
Ignoring packet error, continuing...
Run Code Online (Sandbox Code Playgroud)
因此,我不确定我的设置是否有问题,还是因为某些后台进程在更复杂的Raspbian图像中正在执行操作而导致出现这种情况。
还告诉我尝试使用Linux引导选项禁用多处理,但是我还没有尝试过。
| 归档时间: |
|
| 查看次数: |
38989 次 |
| 最近记录: |