1. pstack ------ 瞬间定位进程卡死、死锁、卡住不动
作用
打印正在运行的进程的线程栈,不用打断程序,不用 gdb,1 秒看到卡在哪。
最常用命令
bash
运行
pstack <PID>
你能看到什么?
- 程序卡在哪个函数
- 死锁(多个线程都在 pthread_mutex_lock)
- 死循环
- 阻塞在 read /write/poll /sleep
嵌入式场景
- 应用程序卡死
- 服务不响应
- CPU 100%
- 驱动阻塞导致应用卡住
pstack 是排查卡死最快工具。
2. gdb ------ 应用 + 内核调试全能王(嵌入式必用)
2.1 直接 attach 正在运行的进程
bash
运行
gdb -p <PID>
然后:
bt看栈info threads看所有线程thread 2切换线程p 变量打印值
2.2 分析段错误崩溃(core dump)
bash
运行
ulimit -c unlimited
gdb ./app core.1234
输入 bt 直接定位哪一行崩溃。
2.3 嵌入式 ARM 远程调试
bash
运行
# 板端
gdbserver :1234 ./app
# PC端
arm-linux-gnueabihf-gdb ./app
target remote 192.168.1.10:1234
3. valgrind ------ 嵌入式用户态内存问题神器
作用
检测:
- 内存泄漏
- 越界读写
- 野指针
- use-after-free
- 重复释放
最常用命令
bash
运行
valgrind --leak-check=full --show-reachable=yes ./app
能直接告诉你
- 泄漏多少字节
- 在哪分配的
- 哪行代码没释放
嵌入式内存问题 90% 靠它定位。
4. strace ------ 看应用到底在跟内核要什么
作用
跟踪所有系统调用,应用 → 内核 的所有行为全部暴露。
最常用
bash
运行
strace -p <PID>
strace -f ./app
能定位的问题
- 打开文件失败
- 驱动 ioctl 报错
- 连接失败
- 权限被拒绝
- 设备节点不存在
- 驱动卡住导致应用阻塞
strace 是 "应用和内核之间的翻译官"。
5. ltrace ------ 跟踪库函数调用
bash
运行
ltrace ./app
看:
- malloc / free
- pthread
- 第三方库
- 驱动库接口
6. lsof ------ 看进程打开了哪些文件、设备、socket
bash
运行
lsof -p <PID>
能查:
- 设备节点被占用
- 驱动文件被打开
- socket 未关闭
- 文件句柄泄漏
7. pstack + strace + valgrind 组合实战(嵌入式最常用三连)
场景 1:程序卡死
bash
运行
pstack <PID> # 看卡在哪一行
strace -p <PID> # 看内核是否卡住
场景 2:段错误
bash
运行
gdb -c core ./app
bt
场景 3:内存越来越大
bash
运行
valgrind --leak-check=full ./app
场景 4:驱动调用异常
bash
运行
strace -f ./app | grep ioctl
问题排查一览表
| 调试场景 | 核心工具 | 最常用命令 | 核心用途(嵌入式重点) | 关键说明 |
|---|---|---|---|---|
| 系统启动/卡死(U-Boot+内核) | 串口工具(minicom/xshell) | minicom -s(配置串口) | 查看启动日志、U-Boot/内核打印,嵌入式排错核心 | 必须配置正确波特率(如115200) |
| 系统启动/卡死(U-Boot+内核) | U-Boot命令 | printenv/setenv/tftpboot/md/mw | 修改启动参数、读写寄存器、下载内核/dtb调试 | 解决内核启动卡死、根文件系统挂载失败 |
| 系统启动/卡死(U-Boot+内核) | dtc(设备树工具) | dtc -I dts -O dtb -o xxx.dtb xxx.dts(编译);dtc -I dtb -O dts xxx.dtb(反编译) | 调试设备树配置错误(compatible、reg、中断等) | 配合cat /proc/device-tree/查看内核识别的设备树 |
| 系统启动/卡死(U-Boot+内核) | earlyprintk | 启动参数添加:earlyprintk=ttySAC0,115200 | 解决内核启动黑屏、无输出,开启早期打印 | 需内核配置CONFIG_EARLY_PRINTK=y |
| 内核崩溃(Oops/Panic/重启) | dmesg | dmesg / dmesg -w / dmesg | grep -i panic | 查看内核日志、Oops信息、Panic原因 | 核心排查内核崩溃、驱动加载失败 |
| 内核崩溃(Oops/Panic/重启) | addr2line | arm-linux-gnueabihf-addr2line -e vmlinux 0xffffff8000321234 | 将Oops中的PC地址转为具体代码行 | 需内核开启CONFIG_DEBUG_INFO=y |
| 内核崩溃(Oops/Panic/重启) | kdump+crash | crash vmlinux vmcore | 捕获内核崩溃转储,分析Panic/软锁死原因 | 产品级排查内核崩溃的核心工具 |
| 内核崩溃(Oops/Panic/重启) | kgdb | 板端:echo ttySAC0 > /sys/kernel/debug/kgdboc;PC端:arm-linux-gdb vmlinux + target remote | 内核源码级调试,单步跟踪内核函数 | 适用于内核死机、驱动初始化异常 |
| 内核崩溃(Oops/Panic/重启) | JTAG/DSTREAM | 硬件调试器操作(无固定命令) | 板子完全死机、无法进内核时的终极调试手段 | 需硬件支持,定位底层硬件/内核BUG |
| 驱动开发(加载/中断/GPIO/总线) | lsmod/insmod/rmmod/modinfo | insmod xxx.ko;rmmod xxx;lsmod | grep xxx | 驱动加载、卸载、查看驱动信息,排查加载失败 | 加载失败后用dmesg看错误码(-1/-2/-16/-22) |
| 驱动开发(加载/中断/GPIO/总线) | proc/interrupts | cat /proc/interrupts;watch -n1 cat /proc/interrupts | 查看中断计数、中断号,排查中断风暴、中断不触发 | 计数不动=未触发;暴涨=中断风暴 |
| 驱动开发(加载/中断/GPIO/总线) | libgpiod(GPIO工具) | gpioinfo;gpioset gpiochip0 4=1;gpioget gpiochip0 5 | 查看GPIO配置、设置GPIO电平,排查GPIO复用/电平问题 | 替代传统GPIO调试方式,嵌入式首选 |
| 驱动开发(加载/中断/GPIO/总线) | I2C工具(i2cdetect等) | i2cdetect -y 0;i2cdump -y 0 0x48;i2cset -y 0 0x48 0x10 0xFF | 扫描I2C设备、读写I2C寄存器,排查I2C通信异常 | 无ACK=硬件/地址/电平问题 |
| 驱动开发(加载/中断/GPIO/总线) | devmem | devmem 0x12340000 32(读);devmem 0x12340000 32 0x1234ABCD(写) | 直接读写物理寄存器,排查时钟、复位、引脚配置 | 嵌入式底层硬件调试神器,需root权限 |
| 驱动开发(加载/中断/GPIO/总线) | spi-tools | spi-poll;spi-read;spi-write | 调试SPI总线通信,排查SPI时序、设备连接问题 | 与I2C工具用法类似,适配SPI外设 |
| 内存问题(泄漏/越界/OOM) | valgrind(用户态) | valgrind --leak-check=full --show-reachable=yes ./app | 检测用户态内存泄漏、越界、野指针、use-after-free | 嵌入式用户态内存问题90%靠它,需编译时开启调试信息 |
| 内存问题(泄漏/越界/OOM) | kmemleak(内核态) | echo scan > /sys/kernel/debug/kmemleak;cat /sys/kernel/debug/kmemleak | 检测内核内存泄漏,显示泄漏大小、调用栈 | 需内核开启CONFIG_DEBUG_KMEMLEAK=y |
| 内存问题(泄漏/越界/OOM) | KASAN(内核态) | 内核配置CONFIG_KASAN=y,启动后直接看日志 | 检测内核内存越界、野指针、use-after-free,直接定位代码行 | 内核内存问题最强工具,轻微占用性能 |
| 内存问题(泄漏/越界/OOM) | top/htop/free | top;free -h;ps aux --sort=-rss | 查看系统内存、进程内存占用,排查OOM、内存暴涨 | RES字段=进程实际占用物理内存 |
| 内存问题(泄漏/越界/OOM) | slabtop/cat /proc/slabinfo | slabtop;cat /proc/slabinfo | grep kmalloc | 查看内核slab分配,排查内核内存泄漏(某slab持续上涨) | 内核内存泄漏核心排查手段 |
| 内存问题(泄漏/越界/OOM) | pmap | pmap <PID> | 查看进程内存分布,排查内存碎片、mmap失败 | 适配嵌入式内存紧张场景 |
| CPU/性能问题(高负载/卡顿/死锁) | pstack | pstack <PID> | 快速打印线程栈,定位进程卡死、死锁、死循环,无需打断程序 | 排查卡死最快工具,嵌入式首选 |
| CPU/性能问题(高负载/卡顿/死锁) | perf | perf top;perf record -g -p <PID>;perf report | 查看内核/用户态热点函数,排查CPU高负载、性能瓶颈 | 需内核开启CONFIG_PERF_EVENTS=y |
| CPU/性能问题(高负载/卡顿/死锁) | ftrace/trace-cmd | cd /sys/kernel/debug/tracing;echo function > current_tracer;cat trace | 跟踪内核函数调用顺序,排查软锁死、调度延迟、函数卡死 | 嵌入式内核性能排查神器,轻量无侵入 |
| CPU/性能问题(高负载/卡顿/死锁) | pidstat/mpstat | pidstat -u 1;mpstat -P ALL 1 | 按进程/线程/CPU核心查看CPU占用,定位高CPU进程/线程 | 排查单核CPU 100%、多核负载不均 |
| CPU/性能问题(高负载/卡顿/死锁) | cyclictest | cyclictest -t 1 -p 99 | 测试RT-Linux实时性,排查调度延迟、优先级反转 | 适配实时嵌入式场景 |
| 文件系统/存储(EMMC/NAND/UBI) | df/du | df -h;df -i;du -sh /* | 查看磁盘空间、inode占用,排查磁盘满、大文件 | df -i排查inode耗尽(常见于小文件过多) |
| 文件系统/存储(EMMC/NAND/UBI) | mount/umount | mount;mount -o remount,rw /;umount /mnt | 查看挂载情况、重新挂载(解决根文件系统只读) | 只读多为存储错误,内核自动保护 |
| 文件系统/存储(EMMC/NAND/UBI) | UBI工具 | ubidetach -p /dev/mtdblockX;ubiattach -p /dev/mtdblockX;ubiformat | 调试UBIFS挂载、UBI卷管理、Flash坏块 | 适配嵌入式NAND/EMMC存储场景 |
| 文件系统/存储(EMMC/NAND/UBI) | fsck | fsck /dev/mmcblk0p2 | 检查并修复文件系统错误,排查挂载失败 | 修复前建议备份数据 |
| 网络问题(以太网/Wi-Fi/4G) | ip/ifconfig/route | ip addr;ip link;route -n;ip route | 查看网卡状态、IP地址、路由表,排查网卡未启动 | ip命令替代传统ifconfig,功能更全 |
| 网络问题(以太网/Wi-Fi/4G) | ping/mtr/tcpdump | ping xxx.xxx.xxx.xxx;mtr xxx.xxx.xxx.xxx;tcpdump -i eth0 port 8080 | 排查网络连通性、丢包、端口通信,抓包分析异常 | tcpdump需root权限,配合wireshark分析包 |
| 网络问题(以太网/Wi-Fi/4G) | ethtool | ethtool eth0;ethtool -s eth0 speed 100 duplex full | 查看/设置网卡速率、双工模式,排查网卡硬件问题 | 适配以太网调试,Wi-Fi用iwconfig/iwlist |
| 网络问题(以太网/Wi-Fi/4G) | ss/netstat | ss -tulnp;netstat -tulnp;ss -s | 查看端口占用、TCP连接统计,排查端口被占用、TIME_WAIT过多 | ss比netstat更快,适配嵌入式轻量场景 |
| 用户态应用调试(崩溃/卡死) | gdb | gdb -p <PID>;gdb ./app core;bt;info threads | 应用崩溃调试(core文件)、运行时调试、线程调试 | 远程调试:板端gdbserver,PC端交叉编译gdb连接 |
| 用户态应用调试(崩溃/卡死) | strace | strace -p <PID>;strace -f ./app;strace -e ioctl ./app | 跟踪应用系统调用,排查文件打开失败、驱动ioctl异常、权限问题 | 应用与内核之间的"翻译官",定位跨层问题 |
| 用户态应用调试(崩溃/卡死) | ltrace | ltrace ./app;ltrace -f ./app | 跟踪应用库函数调用(malloc/free/pthread等),排查库调用异常 | 区别于strace(只跟踪系统调用) |
| 用户态应用调试(崩溃/卡死) | lsof | lsof -p <PID>;lsof | grep deleted | 查看进程打开的文件、设备、socket,排查文件句柄泄漏、已删未释放文件 | 解决"磁盘满但找不到大文件"问题 |
| 内核高级调试 | lockdep | 内核配置CONFIG_LOCKDEP=y,启动后查看dmesg | 检测内核锁依赖、死锁风险、锁顺序倒置 | 内核并发/锁问题排查核心工具 |
| 内核高级调试 | regmap-debugfs | cat /sys/kernel/debug/regmap/xxx/registers | 查看寄存器映射,排查驱动寄存器操作异常 | 需内核开启CONFIG_REGMAP_DEBUGFS=y |
嵌入式Linux排错万能流程
-
先抓串口完整日志,看是否有Oops/Panic/启动卡死;
-
用dmesg排查驱动加载、中断、设备树异常;
-
top/vmstat/iostat定位CPU/内存/IO高负载;
-
应用卡死:pstack → strace → gdb;
-
应用崩溃:gdb+core → valgrind;
-
驱动异常:dmesg → devmem/i2cdetect → 寄存器排查;
-
内核崩溃:addr2line → kdump+crash → KASAN/kmemleak;
-
完全起不来:JTAG + U-Boot调试。