Linux内核与应用调试工具集¶
调试工具¶
fadd2line¶
Binutils¶
addr2line¶
nm¶
symbols¶
内核符号表¶
strip¶
strings¶
-
在当前目录下递归查找so文件中的目标字符串
这个命令会在当前目录下递归查找所有后缀名为 .so 或者 .so.* 的文件,并使用 strings 命令提取其中的字符串,然后使用 grep 命令在字符串中查找目标字符串,如果目标字符串出现了,就输出包含目标字符串的文件名。 具体来说,该命令使用 find 命令在当前目录下查找所有类型为文件(-type f)且文件名匹配 *.so* 的文件,然后使用 -exec 选项执行后面的命令。 后面的命令使用 sh -c 执行,将每个匹配到的文件名({})传递给了 $0 变量。在命令中,先使用 strings 命令提取文件中的字符串,然后使用 grep 命令查找目标字符串是否存在,如果存在,就使用 echo 命令输出包含目标字符串的文件名。 需要注意的是,命令中使用了单引号包围命令,以避免 Shell 解析命令中的 $0 变量和 {} 字符。同时,在命令的末尾需要使用 \; 来表示命令的结束,而不是使用分号 ;,因为分号 ; 是 Shell 的保留字符。
objdump¶
- objdump反汇编用法示例
-
objdump 反汇编代码带行号:
这个命令中的参数含义如下:
-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反汇编得到的汇编代码对应的上。
gdb¶
- gdb调试常用命令
- GDB调试
- 了解和使用GDB调试-基础
- GDB调试指南(入门,看这篇够了)
- 本文是一篇GDB学习笔记,总结了GDB常用命令,方便以后查阅。
- GDB实用命令
- GDB 调试指令
- Linux下GDB调试指令汇总
- linux gdb详解
- LINUX下GDB的使用方法(简单说说)_longfan的博客-CSDN博客_gdb
- Linux C/C++ 调试的那些“歪门邪道”
gef¶
continue¶
ptype¶
查看某个结构体或变量的类型定义:
查看某个结构体或变量的类型定义且包含偏移量信息:
print¶
打印内存值¶
C++对象布局¶
list¶
多进程¶
gdb tui¶
gdb assembly¶
gdb设置源码路径¶
-
https://sourceware.org/gdb/current/onlinedocs/gdb/Source-Path.html#index-set-substitute_002dpath
- GDB指定和修改搜素源码文件的路径(set substitute-path)
- 源码路径查看与设置
-
替换查找源文件的目录 set substitute-path from-path to-path
cd 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分析core文件找不到源码
- gdb调试解决找不到源代码的问题
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¶
- 一步一步学CMake 之 VSCode+CMakeLists 调试 C++ 工程_wanzew的博客-CSDN博客
- VSCode 无法打开 libc-start.c - Zijian/TENG - 博客园 (cnblogs.com)
- visualstudio-launch-json-reference
- CentOS下sudo免密配置
- VS Code 下以 root 用户调试程序
- VS Code 下以 root 用户调试程序
- Linux deepin下普通用户免密切换至root用户
- process - Visual Studio Code,调试子进程不起作用
- VSCode 同时调试2个或多个程序
vscode调试linux内核¶
- 调试 Linux 最早期的代码
- https://github.com/yuan-xy/Linux-0.11
- Linux 0.11 vscode + gdb调试环境搭建
- 利用vscode远程调试Linux内核
串口¶
-
Linux下常用的串口助手 —— minicom、putty、cutecom
主机上执行:
ls -l /dev/ttyUSB0找不到设备时可以尝试手动添加:
被调式机上执行:
-
查询串口波特率:
其中 /dev/ttyS0 是串口设备文件的路径。你可以将路径更改为你所关心的特定串口。
这将返回串口的配置,包括波特率、数据位、校验位、停止位等。通常,波特率会显示在配置输出中,如下所示:
-
设置串口波特率
在上面的命令中:
/dev/ttyS0 是串口设备文件的路径,你可以根据需要更改为你使用的串口。
9600 是所需的波特率。你可以将其替换为你想要的任何波特率。
运行此命令后,串口 /dev/ttyS0 的波特率将设置为 9600。确保串口没有被其他程序占用,以便成功设置波特率。
kgdb¶
- linux内核调试(七)使用kdb/kgdb调试内核
- Using kgdb, kdb and the kernel debugger internals
- 使用KGDB调试Linux驱动(以imx6ull开发板为例)
- 用 kGDB 调试 Linux 内核
- 内核调试- vmlinux-gdb.py无法在gdb上运行
- kgdb调试linux内核以及驱动模块
kgdboe¶
ptrace¶
- Linux GDB的实现原理
- 一文带你看透 GDB 的 实现原理 ptrace真香
- 断点原理与实现
- 硬件断点和软件断点的区别
- ROM, FLASH和RAM的区别
- 调试器工作原理CPU软件断点/硬件断点/单步执行标识
- 硬件断点
- 内存断点
- 软件断点
- Linux ptrace系统调用详解:利用 ptrace 设置硬件断点
- watch 命令实现监控机制的方式有 2 种,一种是为目标变量(表达式)设置硬件观察点,另一种是为目标变量(表达式)设置软件观察点。
- Linux内核:自己动手写一个GDB设置断点(原理篇)
core文件¶
- Linux下使用gdb调试core文件
- ulimit命令 用来限制系统用户对shell资源的访问
- linux:永久打开core文件功能
- Linux生成core文件、core文件路径设置
- golang-进程崩溃后如何输出错误日志?
- 【Linux】core文件存储位置和命名
- 一文读懂 | coredump文件是如何生成的
- linux下产生core文件以及不产生core文件的条件
-
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 插槽上。
- golang-进程崩溃后如何输出错误日志?core dump
coredumpctl¶
- coredumpctl - Retrieve and process saved core dumps and metadata
- 使用systemd的coredump工具分析程序崩溃问题
- 18 使用 systemd-coredump 针对应用程序崩溃进行调试
dmesg¶
dump_stack¶
sysctl¶
oops¶
- Linux 死机复位(oops、panic)问题定位指南
- Linux内核调试的方式以及工具集锦
- 如何开机进入Linux命令行
- kernel oops (Unable to handle kernel paging request at virtual address )三种内存访问异常
- ARM Linux 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。
内核编译选项:CONFIG_PANIC_TIMEOUT=0
-
kernel.panic_on_oops
作用: 控制在发生内核 oops(可修复的内核错误)时是否触发 panic。
潜在风险: 如果启用,系统在 oops 时会触发 panic。
内核编译选项:PANIC_ON_OOPS=y
-
kernel.hung_task_panic
作用: 控制在系统检测到“挂起”任务(可能是由于死锁)时是否触发 panic。
潜在风险: 如果启用,系统在检测到挂起任务时会触发 panic。
内核编译选项: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 分钟)。
潜在风险: 如果将其设置得太低,系统可能会对一些正常但需要一定时间来完成的任务误报为挂起状态。
内核编译选项:CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
-
vm.panic_on_oom
作用: 控制在发生内存耗尽(OOM)时是否触发 panic。
潜在风险: 如果启用,系统在内存不足时会触发 panic。
-
kernel.softlockup_panic
作用: 软死锁是指内核中的一个任务(线程)由于长时间未能释放CPU而导致系统失去响应时是否触发 panic。
潜在风险: 如果启用,系统在检测到软锁定时会触发 panic。
内核编译选项:CONFIG_SOFTLOCKUP_DETECTOR=y BOOTPARAM_SOFTLOCKUP_PANIC=y
-
kernel.panic_on_warn
作用: 这个参数控制内核在遇到某些非致命性错误(例如警告)时是否触发 panic。
0: 禁用自动重启。内核在遇到警告时不会触发系统重启,而是继续正常运行。
1: 启用自动重启。当内核发生某些警告时,系统会自动重启。
bash
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 命令使其生效。
sudo cat << EOF >> /etc/sysctl.conf
# sysrq
# CONFIG_MAGIC_SYSRQ=y
kernel.sysrq=1
# panic
# CONFIG_PANIC_TIMEOUT=0
kernel.panic=10
# CONFIG_PANIC_ON_OOPS=y
kernel.panic_on_oops=1
# CONFIG_DETECT_HUNG_TASK=y CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y
kernel.hung_task_panic=1
# CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=120
kernel.hung_task_timeout_secs=60
vm.panic_on_oom=1
# CONFIG_SOFTLOCKUP_DETECTOR=y BOOTPARAM_SOFTLOCKUP_PANIC=y
kernel.softlockup_panic=1
kernel.panic_on_warn=1
EOF
任务挂起和睡眠的区别?¶
任务挂起(hanging task)和睡眠(sleep)是两个概念,涉及到系统中运行的进程和线程的状态。
任务挂起(Hanging Task):
-
定义: 任务挂起指的是系统中的某个任务(通常是一个进程或线程)由于某种原因而无法继续正常执行,长时间处于一种不响应的状态。
-
原因: 挂起可能是由于死锁、资源争用、错误的程序行为或其他系统问题引起的。
-
检测: 内核通过监视任务的执行状态和超时机制来检测是否有任务挂起。
-
处理: 一旦检测到任务挂起,系统可能会采取相应的措施,例如记录相关信息、触发系统 panic,以及尝试恢复任务的正常执行。
睡眠(Sleep):
-
定义: 睡眠指的是一个任务主动放弃 CPU 并进入一种等待状态,等待某个事件的发生。在睡眠期间,任务通常不占用 CPU 时间,并允许其他任务执行。
-
原因: 任务可能进入睡眠状态以等待外部事件,例如等待 I/O 操作完成、等待定时器触发、等待信号量或锁的释放等。
-
检测: 睡眠通常是由任务自己通过系统调用(如 sleep、wait)或内核操作引起的,不同于挂起的 passivity(被动性)。
-
处理: 睡眠是一种正常的任务状态,系统不会像在检测到挂起时那样采取紧急措施。任务会在等待的事件发生时被唤醒,继续执行。
总的来说,任务挂起通常是一种异常状态,可能导致系统不稳定,而睡眠是一种正常的、被控制的状态,允许任务在需要时主动放弃 CPU 并等待特定条件的发生。
watchdog¶
nmi_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
- How to on enable kernel crash dump on Debian Linux
-
uname -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" - Linux内核转储-Kdump,Crash使用介绍
- Ubuntu 20.04 Kdump + Crash 初体验
- ubuntu 20.04 启用kdump服务及下载vmlinux
- Linux内核调试之kdump
- Linux Kdump内核崩溃转储部署详解
- Ubuntu的内核转储工具
- centos7 kdump、crash调试内核
- Linux Kdump 机制详解
修改sysconfig kdump参数,禁用某些驱动:
vim /etc/sysconfig/kdump
KDUMP_COMMANDLINE_APPEND="initcall_blacklist=mlx5_ib_init,mlx5_core_init module_blacklist=mlx5_ib,mlx5_core modprobe.blacklist=hisi_sas_v3_hw,hisi_sas_main"
carsh¶
crash 是一个用于分析 Linux 内核转储文件(core dump)的工具,允许在不中断系统运行的情况下进行诊断。以下是 crash 的一些基本原理:
-
核心文件: crash 的核心原理是基于核心文件的分析。内核转储文件(core dump)记录了系统在发生关键错误时的内存和寄存器状态。crash 使用这些核心文件进行分析。
-
调试信息: 为了正确解析核心文件,crash 需要访问内核二进制文件(通常是 vmlinux)。这个文件包含有关内核符号、数据结构和函数的调试信息。在使用 crash 之前,你需要确保有匹配正在运行内核的 vmlinux 文件。
-
在线调试: crash 允许在线调试运行中的内核,而无需停止系统。它通过访问 /proc/kcore 文件获取正在运行内核的内存映像,结合核心文件和调试信息,提供了对内核状态的深入分析。
-
命令式界面: crash 提供了一个交互式的命令行界面,用户可以在其中运行各种命令以查看内核状态、进程信息、调度器信息等。这样用户可以动态地检查系统状态。
-
插件系统: crash 具有可扩展的插件系统,可以通过插件添加额外的命令和功能。这使得用户可以根据需要定制分析环境。
-
安全性和谨慎使用: 尽管 crash 在不中断系统的情况下进行诊断,但仍需注意,对于生产环境,谨慎使用是很重要的。某些 crash 命令可能会对系统产生影响,因此建议在测试环境中使用。
总的来说,crash 提供了一种非常强大的工具,用于在不影响系统运行的情况下进行 Linux 内核的调试和分析。
git clone https://github.com/crash-utility/crash.git
cd crash/
git checkout -b 8.0.4 8.0.4
make -j16
sudo make install
- 【调试】crash使用方法
- Linux crash 调试环境搭建
- linux内核学习-Linux内核程序调试工具Crash的安装
- dump分析工具_ubantu18.04内核奔溃调试工具Crash的搭建
- 用crash tool观察ARM64 Linux地址转换
- CRASH安装和调试
- Linux crash Dump分析
fedora¶
仅为一个命令启用存储库:
永久启用存储库(可能不是您想要的):
禁用存储库:
推荐使用sudo dnf debuginfo-install kernel安装内核调试包:
eval命令¶
有时我们想知道一个数字的那些位是1,那么需要在数字前面使用-b参数:
crash> cpumask 0xffff88b48aa23f20 -x
struct cpumask {
bits = {0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90004000, 0x0, 0x1, 0xffffc9000d20c000, 0x420804000000002, 0x0, 0x0, 0x3700000000, 0x4, 0xfffb706a, 0xffff88ea8be9c000, 0x3700000037, 0x7800000000, 0x7800000078, 0x0, 0xffffffff82260540, 0x100000, 0x400000, 0x100000, 0x1, 0x0, 0x0, 0xffff88b48aa240b0, 0xffff88b48aa240b0, 0x0, 0xd4da92e6, 0x26554, 0xffffffffff3b4a54, 0x1fe63, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff88b492fe9a00, 0x0, 0x0, 0x0, 0x0, 0xd4da9000, 0x1a, 0x1a, 0x2a400006be6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xffff88b48aa24280, 0xffff88b48aa24280, 0x0, 0x0, 0x64, 0x0, 0x0, 0xffff88b492fe9bc0, 0x0, 0xffffffff83149580, 0xffff88b48aa242d0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
}
crash> eval -b 0x3 //vcpu0的SMT调度域包含vcpu0和vcpu1一对超线程
bits set: 1 0
crash>
list¶
# include/linux/swait.h
# 知道swait_queue_head地址,crash中怎么用list命令得到第62行的task地址
crash> p &(rcu_sched_state.gp_wq)
$96 = (struct swait_queue_head *) 0xffff3eb87f2132d8
crash> list -o swait_queue.task_list -s task_struct.pid,comm -O swait_queue_head.task_list -h 0xffff3eb87f2132d8
list: invalid option -- 'O'
Usage:
list [[-o] offset][-e end][-[s|S] struct[.member[,member] [-l offset]] -[x|d]]
[-r|-B] [-h|-H] start
Enter "help list" for details.
crash版本太低,改用-o选项:
crash> p &(rcu_sched_state.gp_wq.task_list)
$98 = (struct list_head *) 0xffff3eb87f2132e0
crash> list -o swait_queue.task -s task_struct.pid,comm -H 0xffff3eb87f2132e0
(empty)
kmem¶
查看内存的使用统计信息:
查看slab的信息:
按slabs降序:
cat kmem_s.log | sort -k5,5nr | head -n10
CACHE OBJSIZE ALLOCATED TOTAL SLABS SSIZE NAME
ffff8003ff689900 304 3563564 7039393 282756 16k kmemleak_object
ffff8003ad115800 192 1597195 1601956 51676 16k dentry(664:aTrustDaemon.service)
ffff80037d372700 1072 409123 409620 17826 32k ext4_inode_cache(904:session-1.scope)
ffff80037d375800 192 307034 310121 10007 16k dentry(904:session-1.scope)
ffff8003e87c8b00 128 332086 332185 9491 16k kernfs_node_cache
ffff80037d375480 144 147286 172328 5213 16k buffer_head(904:session-1.scope)
ffff8003ff688400 128 86102 86450 3458 16k kmalloc-128
ffff80037d375b80 192 63328 63365 2051 16k vm_area_struct(904:session-1.scope)
ffff80037d374680 64 37358 37400 1873 8k anon_vma_chain(904:session-1.scope)
ffff8003954a1580 40 34932 34944 1664 8k ext4_extent_status
percpu变量¶
查看percpu变量在每个cpu上的基地址¶
crash> kmem -o
PER-CPU OFFSET VALUES:
CPU 0: ffff88807f600000
CPU 1: ffff88807fa00000
CPU 2: ffff88813d600000
CPU 3: ffff88813da00000
CPU 4: ffff8881bd600000
CPU 5: ffff8881bda00000
CPU 6: ffff88823d600000
CPU 7: ffff88823da00000
查看一个全局的percpu变量的具体值¶
以下面这个全局percpu变量call_single_queue为例:
crash> p call_single_queue
PER-CPU DATA TYPE:
struct llist_head call_single_queue;
PER-CPU ADDRESSES:
[0]: ffff88807f800340
[1]: ffff88807fc00340
[2]: ffff88813d800340
[3]: ffff88813dc00340
[4]: ffff8881bd800340
[5]: ffff8881bdc00340
[6]: ffff88823d800340
[7]: ffff88823dc00340
查看其在某些CPU上的具体内容:
crash> p call_single_queue:0,2,5-7
per_cpu(call_single_queue, 0) = $5 = {
first = 0x0
}
per_cpu(call_single_queue, 2) = $6 = {
first = 0x0
}
per_cpu(call_single_queue, 5) = $7 = {
first = 0x0
}
per_cpu(call_single_queue, 6) = $8 = {
first = 0x0
}
per_cpu(call_single_queue, 7) = $9 = {
first = 0x0
}
根据结构体中percpu变量的偏移地址得到绝对地址¶
struct kmem_cache {
struct array_cache __percpu *cpu_cache;
/* 1) Cache tunables. Protected by slab_mutex */
unsigned int batchcount;
unsigned int limit;
unsigned int shared;
...
以16进制方式查看 kmem_cache 的 per-CPU 缓存指针(cpu_slab)的偏移量:
上面cpu_slab的偏移量是0x5fc135c77b40
假如想知道这个成员在cpu10上的地址,下面有2种方法:
- 绝对值相加
首先获取percpu变量在cpu10上的基地址:
然后相加即可:
crash> eval ffff88debfd00000 + 0x5fc135c77b40
hexadecimal: ffffe89ff5977b40
decimal: 18446718372450630464 (-25701258921152)
octal: 1777777211776545675500
binary: 1111111111111111111010001001111111110101100101110111101101000000
上面将相加后的结果分别按16进制,10进制,8进制以及2进制进行了输出。
- 使用ptov
这种方法更加方便。
读取percpu变量的内容¶
还是以kmem_cache为例:
如果想读取cpu_slab的内容,之前的办法是先得到绝对地址,然后再读取(用*代替struct),其实也可以直接读取,下面的例子读取cpu2上的cpu_slab的内容:
crash> *kmem_cache_cpu 0x5fc135c77b40:2
[2]: ffffe89ff5577b40
struct kmem_cache_cpu {
freelist = 0x0,
tid = 2,
page = 0x0,
partial = 0x0
}
sysrq-trigger¶
使能魔法键c:
魔法键c主动生成kdump:
等价于echo c > /proc/sysrq-trigger:
- 手动触发kdump,触发后服务器会自动重启。(正常情况下勿按该组合键)
ipmitool¶
IPMI可通过发送NMI(Non-Maskable Interrupt)强制触发内核崩溃,进而生成vmcore:
