debug
本文最后更新于:2025年4月28日 下午
debug
调试工具
fadd2line
Binutils
addr2line
nm
symbols
内核符号表
strip
strings
在当前目录下递归查找so文件中的目标字符串
1
find . -type f -name "*.so*" -exec sh -c 'strings "$0" | grep "target_string" && echo "$0"' {} \;
1
2
3
4
5
6
7这个命令会在当前目录下递归查找所有后缀名为 .so 或者 .so.* 的文件,并使用 strings 命令提取其中的字符串,然后使用 grep 命令在字符串中查找目标字符串,如果目标字符串出现了,就输出包含目标字符串的文件名。
具体来说,该命令使用 find 命令在当前目录下查找所有类型为文件(-type f)且文件名匹配 *.so* 的文件,然后使用 -exec 选项执行后面的命令。
后面的命令使用 sh -c 执行,将每个匹配到的文件名({})传递给了 $0 变量。在命令中,先使用 strings 命令提取文件中的字符串,然后使用 grep 命令查找目标字符串是否存在,如果存在,就使用 echo 命令输出包含目标字符串的文件名。
需要注意的是,命令中使用了单引号包围命令,以避免 Shell 解析命令中的 $0 变量和 {} 字符。同时,在命令的末尾需要使用 \; 来表示命令的结束,而不是使用分号 ;,因为分号 ; 是 Shell 的保留字符。
objdump
objdump 反汇编代码带行号:
1
objdump -d -l -S your_binary_file
这个命令中的参数含义如下:
-d:表示进行反汇编。
-l:表示生成包含行号信息的输出。
-S:表示同时输出源代码。
-C:如果二进制文件包含 C++ 符号,使用 C++ 符号名进行显示,而不是使用原始符号名。
将 your_binary_file 替换为你要反汇编的二进制文件的路径。
这将生成一个包含反汇编代码和源代码行号信息的输出。你可以查看这个输出来分析程序的汇编代码。
- 注意事项:cmake-objdump
- cmake中使用参数-DCMAKE_BUILD_TYPE=Release编译出来的版本在coredump时生成的dmesg报错中的ip地址与使用-DCMAKE_BUILD_TYPE=Debug编出来的版本再使用objdump反汇编得到的汇编代码对不上。
- cmkke中-DCMAKE_BUILD_TYPE=Release编译出来的版本在coredump时生成的dmesg报错中的ip地址与在CMakeLists.txt中额外添加set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")编译选项后再使用objdump反汇编得到的汇编代码对应的上。
- cmake中-DCMAKE_BUILD_TYPE=Debug编译出来的版本后用strip得到的不含调试包的版本在coredump时生成的dmesg报错中的ip地址与使用-DCMAKE_BUILD_TYPE=Debug编出来的版本再使用objdump反汇编得到的汇编代码对应的上。
- 注意事项:cmake-objdump
gdb
gef
continue
ptype
查看某个结构体或变量的类型定义:
1 |
|
查看某个结构体或变量的类型定义且包含偏移量信息:
1 |
|
打印内存值
C++对象布局
list
多进程
gdb tui
gdb assembly
-
1
(gdb) disassemble /m main
gdb设置源码路径
https://sourceware.org/gdb/current/onlinedocs/gdb/Source-Path.html#index-set-substitute_002dpath
替换查找源文件的目录 set substitute-path from-path to-path
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26cd lshw-02.18.85.3
gdb lshw
b main
gef➤ l
75 in lshw.cc
gef➤ info source
Current source file is lshw.cc
Compilation directory is /build/lshw-02.18.85.3/src
Located in /build/lshw-02.18.85.3/src/lshw.cc
Source language is c++.
Producer is GNU C++14 8.3.0 -mtune=generic -march=x86-64 -g -O2.
Compiled with DWARF 2 debugging format.
Does not include preprocessor macro info.
gef➤ set substitute-path /build/lshw-02.18.85.3/src ./src
gef➤ l
warning: Source file is more recent than executable.
75 int main(int argc,
76 char **argv)
77 {
78
79 #ifndef NONLS
80 setlocale (LC_ALL, "");
81 bindtextdomain (PACKAGE, LOCALEDIR);
82 bind_textdomain_codeset (PACKAGE, "UTF-8");
83 textdomain (PACKAGE);
84 #endif
gdb打印qt数据类型
gdb print errno
- errno全局变量及使用细则,C语言errno全局变量完全攻略
- Linux(程序设计):08-perror、strerror函数(errno全局变量)
- Linux errno 错误对照表
- 【博客272】errno错误对照表
- gcc 7.1.0下gdb无法prinf查看errno解决
gdb远程调试
- 40.Linux应用调试-使用gdb和gdbserver
- 使用gdbserver远程调试
- 服务/软件管理:38-gdb+gdbserver的使用
- gdb远程及本地调试的一些技巧
- 使用GDB进行嵌入式远程调试
gcc
libtool
vscode gdb
vscode调试linux内核
- 调试 Linux 最早期的代码
- https://github.com/yuan-xy/Linux-0.11
- Linux 0.11 vscode + gdb调试环境搭建
- 利用vscode远程调试Linux内核
串口
Linux下常用的串口助手 —— minicom、putty、cutecom
主机上执行:
1
sudo minicom -s -D /dev/ttyUSB0
ls -l /dev/ttyUSB0
找不到设备时可以尝试手动添加:1
lsusb
1
echo '067b 23a3' > /sys/bus/usb-serial/drivers/generic/new_id
被调式机上执行:
1
sudo cutecom
查询串口波特率:
1
stty -F /dev/ttyS0
其中 /dev/ttyS0 是串口设备文件的路径。你可以将路径更改为你所关心的特定串口。
这将返回串口的配置,包括波特率、数据位、校验位、停止位等。通常,波特率会显示在配置输出中,如下所示:
1
speed 9600 baud; line = 0;
设置串口波特率
1
stty -F /dev/ttyS0 9600
在上面的命令中:
/dev/ttyS0 是串口设备文件的路径,你可以根据需要更改为你使用的串口。
9600 是所需的波特率。你可以将其替换为你想要的任何波特率。
运行此命令后,串口 /dev/ttyS0 的波特率将设置为 9600。确保串口没有被其他程序占用,以便成功设置波特率。
kgdb
kgdboe
ptrace
- Linux GDB的实现原理
- 一文带你看透 GDB 的 实现原理 ptrace真香
- 断点原理与实现
- 硬件断点和软件断点的区别
- ROM, FLASH和RAM的区别
- 调试器工作原理CPU软件断点/硬件断点/单步执行标识
- 硬件断点
- 内存断点
- 软件断点
- Linux ptrace系统调用详解:利用 ptrace 设置硬件断点
- watch 命令实现监控机制的方式有 2 种,一种是为目标变量(表达式)设置硬件观察点,另一种是为目标变量(表达式)设置软件观察点。
- Linux内核:自己动手写一个GDB设置断点(原理篇)
core文件
-
1
core[1161856]: segfault at 0 ip 0000000000401136 sp 00007ffcdbaf3240 error 6 in core[401000+1000] likely on CPU 2 (core 2, socket 0)
core[1161856]: 这可能是指示生成的 core dump 文件名。在这里,core 文件名为 "core",后缀为 "1161856",这可能是一个进程 ID 或其他唯一标识符。
segfault at 0: 这表示一个段错误(Segmentation Fault)发生在地址 0 处。这通常是因为程序试图访问一个无效的内存地址。
ip 0000000000401136: 这是导致段错误的指令的地址。在这里,ip(Instruction Pointer)指向地址 0000000000401136 的指令。
sp 00007ffcdbaf3240: 这是栈指针(Stack Pointer),指向栈的当前顶部。在这里,sp 指向地址 00007ffcdbaf3240。
error 6: 这是一个错误代码,表示导致段错误的原因。在 Linux 中,错误代码 6 通常表示尝试执行非法的指令。
core[401000+1000]: 这表示 core dump 文件的内存范围。在这里,core 文件捕获了从地址 401000 开始的 1000 个字节的内存内容,1000一般指向了_init符号。
likely on CPU 2 (core 2, socket 0): 这是指示错误可能发生在第二个 CPU 核心上,该核心位于第一个物理 CPU 插槽上。
coredumpctl
- coredumpctl - Retrieve and process saved core dumps and metadata
- 使用systemd的coredump工具分析程序崩溃问题
- 18 使用 systemd-coredump 针对应用程序崩溃进行调试
dmesg
dump_stack
sysctl
oops
panic
- [linux][异常检测] hung task, soft lockup, hard lockup, workqueue stall
- Softlockup与hardlockup检测机制(又名:nmi_watchdog)
- 一起学习64位ARM平台稳定性分析:遇见内核 panic
- Linux内核故障分类和排查
- 这是你了解的空指针吗?
- Linux内核panic核心执行逻辑
更改 sysctl 中的某些内核参数可能导致系统不稳定,甚至触发 panic。以下是一些可能会导致系统问题的内核参数,慎重修改:
kernel.panic
作用: 设置系统 panic 的延迟时间。
潜在风险: 如果将其设置得太低,系统可能会在不必要的情况下触发 panic。
1
sysctl -w kernel.panic=10
内核编译选项:CONFIG_PANIC_TIMEOUT=0
kernel.panic_on_oops
作用: 控制在发生内核 oops(可修复的内核错误)时是否触发 panic。
潜在风险: 如果启用,系统在 oops 时会触发 panic。
1
sysctl -w kernel.panic_on_oops=1
内核编译选项:PANIC_ON_OOPS=y
kernel.hung_task_panic
作用: 控制在系统检测到“挂起”任务(可能是由于死锁)时是否触发 panic。
潜在风险: 如果启用,系统在检测到挂起任务时会触发 panic。
1
sysctl -w kernel.hung_task_panic=1
内核编译选项:CONFIG_DETECT_HUNG_TASK=y CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
kernel.hung_task_timeout_secs:
作用: 该参数用于设置系统在检测到任务挂起(hanging task)的超时时间。如果系统中的某个任务在指定的时间内没有恢复正常运行,内核将记录信息并采取相应的措施。
默认值: 通常情况下,kernel.hung_task_timeout_secs 的默认值是 120 秒(2 分钟)。
潜在风险: 如果将其设置得太低,系统可能会对一些正常但需要一定时间来完成的任务误报为挂起状态。
1
sysctl -w kernel.hung_task_timeout_secs=60
内核编译选项:CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
vm.panic_on_oom
作用: 控制在发生内存耗尽(OOM)时是否触发 panic。
潜在风险: 如果启用,系统在内存不足时会触发 panic。
1
sysctl -w vm.panic_on_oom=1
kernel.softlockup_panic
作用: 软死锁是指内核中的一个任务(线程)由于长时间未能释放CPU而导致系统失去响应时是否触发 panic。
潜在风险: 如果启用,系统在检测到软锁定时会触发 panic。
1
sysctl -w kernel.softlockup_panic=1
内核编译选项:CONFIG_SOFTLOCKUP_DETECTOR=y BOOTPARAM_SOFTLOCKUP_PANIC=y
kernel.panic_on_warn
作用: 这个参数控制内核在遇到某些非致命性错误(例如警告)时是否触发 panic。
0: 禁用自动重启。内核在遇到警告时不会触发系统重启,而是继续正常运行。
1: 启用自动重启。当内核发生某些警告时,系统会自动重启。
1
sysctl -w kernel.panic_on_warn=1
在调试或特殊情况下,禁用自动重启可能有助于保留内核警告的信息以进行故障排除。在生产环境中,通常将其设置为非0,以确保系统在遇到某些严重问题时能够自动重启,尽早恢复正常运行状态。
sysctl -w kernel.hung_task_panic=1
、echo 1 > /proc/sys/kernel/hung_task_panic
这两种方法都是在运行时直接生效的,而且都是暂时性的修改。
如果你希望修改是持久的,可以将相应的配置写入
/etc/sysctl.conf
文件,并使用 sysctl -p
命令使其生效。
1 |
|
1 |
|
任务挂起和睡眠的区别?
任务挂起(hanging task)和睡眠(sleep)是两个概念,涉及到系统中运行的进程和线程的状态。
任务挂起(Hanging Task):
定义: 任务挂起指的是系统中的某个任务(通常是一个进程或线程)由于某种原因而无法继续正常执行,长时间处于一种不响应的状态。
原因: 挂起可能是由于死锁、资源争用、错误的程序行为或其他系统问题引起的。
检测: 内核通过监视任务的执行状态和超时机制来检测是否有任务挂起。
处理: 一旦检测到任务挂起,系统可能会采取相应的措施,例如记录相关信息、触发系统 panic,以及尝试恢复任务的正常执行。
睡眠(Sleep):
定义: 睡眠指的是一个任务主动放弃 CPU 并进入一种等待状态,等待某个事件的发生。在睡眠期间,任务通常不占用 CPU 时间,并允许其他任务执行。
原因: 任务可能进入睡眠状态以等待外部事件,例如等待 I/O 操作完成、等待定时器触发、等待信号量或锁的释放等。
检测: 睡眠通常是由任务自己通过系统调用(如 sleep、wait)或内核操作引起的,不同于挂起的 passivity(被动性)。
处理: 睡眠是一种正常的任务状态,系统不会像在检测到挂起时那样采取紧急措施。任务会在等待的事件发生时被唤醒,继续执行。
总的来说,任务挂起通常是一种异常状态,可能导致系统不稳定,而睡眠是一种正常的、被控制的状态,允许任务在需要时主动放弃 CPU 并等待特定条件的发生。
watchdog
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15nmi_watchdog= [KNL,BUGS=X86] Debugging features for SMP kernels
Format: [panic,][nopanic,][num]
Valid num: 0 or 1
0 - turn hardlockup detector in nmi_watchdog off
1 - turn hardlockup detector in nmi_watchdog on
When panic is specified, panic when an NMI watchdog
timeout occurs (or 'nopanic' to not panic on an NMI
watchdog, if CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is set)
To disable both hard and soft lockup detectors,
please see 'nowatchdog'.
This is useful when you use a panic=... timeout and
need the box quickly up again.
These settings can be accessed at runtime via
the nmi_watchdog and hardlockup_panic sysctls.
kdump
Documentation for Kdump - The kexec-based Crash Dumping Solution
-
1
sudo apt install kdump-tools crash kexec-tools makedumpfile linux-image-$(uname -r)-dbg
1
2
3
4uname -a
Linux wujing-PC 5.15.77-amd64-desktop #2 SMP Thu Jun 15 16:06:18 CST 2023 x86_64 GNU/Linux
cat /etc/default/grub.d/kdump-tools.cfg
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT crashkernel=384M-:128M"1
2
3
4uname -a
Linux wujing-PC 4.19.0-arm64-desktop-tyy-5312 #5312 SMP Tue Dec 12 10:52:22 CST 2023 aarch64 GNU/Linux
cat /etc/default/grub.d/kdump-tools.cfg
GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT crashkernel=2G-4G:320M,4G-32G:512M,32G-64G:1024M,64G-128G:2048M,128G-:4096M"1
2echo 1 > /proc/sys/kernel/sysrq
echo c > /proc/sysrq-trigger
carsh
crash 是一个用于分析 Linux 内核转储文件(core dump)的工具,允许在不中断系统运行的情况下进行诊断。以下是 crash 的一些基本原理:
核心文件: crash 的核心原理是基于核心文件的分析。内核转储文件(core dump)记录了系统在发生关键错误时的内存和寄存器状态。crash 使用这些核心文件进行分析。
调试信息: 为了正确解析核心文件,crash 需要访问内核二进制文件(通常是 vmlinux)。这个文件包含有关内核符号、数据结构和函数的调试信息。在使用 crash 之前,你需要确保有匹配正在运行内核的 vmlinux 文件。
在线调试: crash 允许在线调试运行中的内核,而无需停止系统。它通过访问 /proc/kcore 文件获取正在运行内核的内存映像,结合核心文件和调试信息,提供了对内核状态的深入分析。
命令式界面: crash 提供了一个交互式的命令行界面,用户可以在其中运行各种命令以查看内核状态、进程信息、调度器信息等。这样用户可以动态地检查系统状态。
插件系统: crash 具有可扩展的插件系统,可以通过插件添加额外的命令和功能。这使得用户可以根据需要定制分析环境。
安全性和谨慎使用: 尽管 crash 在不中断系统的情况下进行诊断,但仍需注意,对于生产环境,谨慎使用是很重要的。某些 crash 命令可能会对系统产生影响,因此建议在测试环境中使用。
总的来说,crash 提供了一种非常强大的工具,用于在不影响系统运行的情况下进行 Linux 内核的调试和分析。
1 |
|
- 【调试】crash使用方法
- Linux crash 调试环境搭建
- linux内核学习-Linux内核程序调试工具Crash的安装
- dump分析工具_ubantu18.04内核奔溃调试工具Crash的搭建
- 用crash tool观察ARM64 Linux地址转换
- CRASH安装和调试
- Linux crash Dump分析
fedora
仅为一个命令启用存储库:
1 |
|
永久启用存储库(可能不是您想要的):
1 |
|
禁用存储库:
1 |
|
推荐使用sudo dnf debuginfo-install kernel
安装内核调试包:
1 |
|
eval命令
有时我们想知道一个数字的那些位是1,那么需要在数字前面使用-b参数:
1 |
|
kmem
查看内存的使用统计信息:
1 |
|
查看slab的信息:
1 |
|
按slabs降序:
1 |
|
percpu变量
查看percpu变量在每个cpu上的基地址
1 |
|
查看一个全局的percpu变量的具体值
以下面这个全局percpu变量call_single_queue为例:
1 |
|
1 |
|
查看其在某些CPU上的具体内容:
1 |
|
根据结构体中percpu变量的偏移地址得到绝对地址
1 |
|
以16进制方式查看 kmem_cache 的 per-CPU 缓存指针(cpu_slab)的偏移量:
1 |
|
上面cpu_slab的偏移量是0x5fc135c77b40
假如想知道这个成员在cpu10上的地址,下面有2种方法:
绝对值相加
首先获取percpu变量在cpu10上的基地址:
1
2crash> kmem -o | grep "CPU 10"
CPU 10: ffff88debfd00000然后相加即可:
1
2
3
4
5crash> eval ffff88debfd00000 + 0x5fc135c77b40
hexadecimal: ffffe89ff5977b40
decimal: 18446718372450630464 (-25701258921152)
octal: 1777777211776545675500
binary: 1111111111111111111010001001111111110101100101110111101101000000上面将相加后的结果分别按16进制,10进制,8进制以及2进制进行了输出。
使用ptov
1
2
3
4crash> ptov 0x5fc135c77b40:10
PER-CPU OFFSET: 5fc135c77b40
CPU VIRTUAL
[10] ffffe89ff5977b40这种方法更加方便。
读取percpu变量的内容
还是以kmem_cache为例:
1 |
|
如果想读取cpu_slab的内容,之前的办法是先得到绝对地址,然后再读取(用*代替struct),其实也可以直接读取,下面的例子读取cpu2上的cpu_slab的内容:
1 |
|
sysrq-trigger
“Alt+PrtSc+C”:手动触发kdump,触发后服务器会自动重启。(正常情况下勿按该组合键。)