Linux 用户空间问题调试:从基础工具到高级策略的进阶指南

Linux 用户空间问题调试:从基础工具到高级策略的进阶指南


下图显示了可用于调试与 Linux 用户空间应用程序相关的问题的开源工具、转储和日志。
图:用于调试 Linux 用户空间中问题的资源

图:用于调试 Linux 用户空间中问题的资源

支持的开源调试工具是使用 BitBake 文件启用的。此 BitBake 文件 可在以下网址获得: 。此处介绍了启用和使用开源工具(如 ltrace)的过程。packagegroup-core-tools-debug.bbappend``layers/meta-qcom-hwe/recipes-devtools/packagegroups/

使用 ltrace 进行调试

默认情况下,在构建中启用 ltrace。

先决条件

设置 SSH。

程序

要使用 ltrace 进行调试,请使用 SSH 运行以下命令:

  1. 运行 process status 命令:

    ps -ef
    

    输出示例:

339 rpc 0:00 /usr/sbin/rpcbind -w -f
345 root 0:00 /lib/systemd/systemd-journald
373 root 0:00 [kworker/3:6-mm_]
  1. 确定要调试的进程的进程 ID (PID)。

  2. 运行命令:ltrace

    ltrace -p 345
    

    在此示例中,是 PID。345

    输出示例:

journal_file_close(0x25e30170, -1, 0, 0 <unfinished ...>
sockaddr_un_unlink(0x25e30170, -1, 0, 0
<unfinished ...>
sd_journal_close(0x25e31c00, 1, 3, 0x409e70) = 0
sd_journal_close(0x25e31d50, 1, 0, 1) = 0
<... sockaddr_un_unlink resumed> ) = 1
<... journal_file_close resumed> ) = 1
journal_file_close(0x25e30170, -1, 0, 0 <unfinished ...>
sockaddr_un_unlink(0x25e30170, -1, 0, 0 <unfinished ...>
sd_event_now(15, 0x41ed20, 10, 64) = 10
openat64(2, 0x41ed20, 10, 64 <unfinished ...>
clock_gettime(2, 0x41ed20, 10, 64) = 6

使用 Valgrind 进行调试

Valgrind 工具可以检测 C 和 C++ 程序中常见的内存相关错误。这些错误会导致崩溃和不可预知的行为,例如内存泄漏和内存损坏。默认情况下,Valgrind 工具在构建中处于启用状态。

先决条件

设置 SSH。

程序

要使用 Valgrind 工具,请执行以下作:

  1. 将调试符号推送到设备。

  2. 在设备上运行 Valgrind 工具。

    valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes /usr/bin/tqftpserv
    

    输出示例:

==622== Memcheck, a memory error detector
==622== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==622== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==622== Command: /usr/bin/tqftpserv
==622==

^C==622==
==622== Process terminating with default action of signal 2 (SIGINT)
==622== at 0x498EF38: select (select.c:69)
==622== by 0x4013CB: ??? (in /usr/bin/tqftpserv)
==622== by 0x48DB1AF: (below main) (libc_start_call_main.h:58)
==622==
==622== FILE DESCRIPTORS: 4 open (3 std) at exit.
==622== Open pf-42 socket 3:
==622== at 0x49984CC: socket (syscall-template.S:120)
==622== by 0x4891293: qrtr_open (in /usr/lib/libqrtr.so.1.0)
==622== by 0x40129B: ??? (in /usr/bin/tqftpserv)
==622== by 0x48DB1AF: (below main) (libc_start_call_main.h:58)
==622==
==622==
==622== HEAP SUMMARY:
==622== in use at exit: 0 bytes in 0 blocks
==622== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==622==
==622== All heap blocks were freed -- no leaks are possible
==622==
==622== For lists of detected and suppressed errors, rerun with: -s
==622== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
==622== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

使用 GDB 进行调试

默认情况下,GNU 调试器 (GDB) 在构建中未启用。要启用 GDB,请在 Linux 主机上执行以下作:

  1. 导航到目录并打开文件。layers/meta-qcom-hwe/recipes-devtools/packagegroups/``packagegroup-core-tools-debug.bbappend

  2. 验证调试符号是否已启用。

    readelf --debug-dump=decodedline <BIN_FILE>
    

    objdump --syms <BIN_NAME> | grep -i ‘debug’
    

    如果未启用调试符号,请使用 CFLAG 编译所有必需的可执行文件或共享库。-g

  3. 修改要添加到包列表中的文件。如果软件包名称已在软件包列表中,请跳过此步骤。packagegroup-core-tools-debug.bbappend``gdb

  4. 在设备上重新编译并刷写 build。

要使用 GDB 进行调试,请在设备上运行以下命令:

gdb --pid 502

输出示例:

gdb: warning: Couldn't determine a path for the index cache directory.
GNU gdb (GDB) 11.2
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-qcom-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Attaching to process 502
Reading symbols from /usr/bin/tqftpserv...
(No debugging symbols found in /usr/bin/tqftpserv)
Reading symbols from /usr/lib/libqrtr.so.1...
(No debugging symbols found in /usr/lib/libqrtr.so.1)
Reading symbols from /lib/libc.so.6...
Reading symbols from /lib/.debug/libc.so.6...
Reading symbols from /lib/ld-linux-aarch64.so.1...
Reading symbols from /lib/.debug/ld-linux-aarch64.so.1...
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
0x0000ffffab00ef34 in __GI___select (nfds=4, readfds=0xffffc2ec14f8, writefds=0x0, exceptfds=0x0, timeout=0x0) at ../sysdeps/unix/sysv/linux/select.c:69
69 ../sysdeps/unix/sysv/linux/select.c: No such file or directory.
(gdb)
(gdb)
(gdb)
(gdb)

下表列出了常用的 GDB 命令。

表:常见的 GDB 命令

命令描述
(gdb) bt提供当前线程的回溯。
(gdb) info threads列出当前已知线程的 ID。
(gdb) thread 2切换到线程 2。
(gdb) where显示当前行号和您所在的函数。
(gdb) thread apply all bt full提供所有线程的回溯。
(gdb) info sharedlibrary列出使用的共享库的名称。
(gdb) info reg列出 CPU 寄存器。

收集核心转储

核心转储是用户空间进程的内存快照,可用于分析进程崩溃的原因。

根据 Yocto Linux 标准收集所有用户空间进程崩溃的核心转储。默认情况下,核心转储在构建中处于启用状态。生成的核心转储保存在设备上的 。/var/coredump

要验证核心转储的位置,请运行以下命令:

cat /proc/sys/kernel/core_pattern

输出示例:

/var/coredump/%e.core

核心转储的大小必须大于 0 (零) 。要验证核心转储的大小,请运行以下命令:

ulimit -c

输出示例:

unlimited

如果未启用核心转储,请使用以下文件来启用它:

layers/meta-qcom-distro/recipes-products/packagegroups/packagegroup-qcom.bb.

RDEPENDS:packagegroup-support-utils = "\
   chrony \
   libinput \
   libinput-bin \
   libnl \
   libxml2 \
+++ procps \
   "

注意

使用此补丁启用核心转储时,必须重新构建并重新刷写设备。

在核心转储上使用 GDB

要生成核心转储,您需要强制终止进程。为此,请运行以下命令:

ps -ef | grep -i 'tqftp*'

输出示例:
root 1024 1 0 17:46 ? 00:00:00 /usr/bin/tqftpserv
root 1047 934 0 17:47 pts/0 00:00:00 grep -i tqftp*

kill -11 1024
cd /var/coredump
ls

输出示例:

tqftpserv.core

这是核心转储文件。tqftpserv.core

如果调试符号已推送到设备,请运行以下命令以在核心转储上使用 GDB 工具:

cd /usr/bin/
gdb tqftpserv /var/coredump/tqftpserv.core

输出示例:

gdb: warning: Couldn't determine a path for the index cache directory.
GNU gdb (GDB) 11.2
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
Type "apropos word" to search for commands related to "word"...
Reading symbols from tqftpserv...

warning: exec file is newer than core file.
[New LWP 1024]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Core was generated by `/usr/bin/tqftpserv'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000ffff8629ef34 in __GI___select (nfds=4,
readfds=readfds@entry=0xffffd04ccb28, writefds=writefds@entry=0x0,
--Type <RET> for more, q to quit, c to continue without paging--
exceptfds=exceptfds@entry=0x0, timeout=timeout@entry=0x0)
at ../sysdeps/unix/sysv/linux/select.c:69
69 ../sysdeps/unix/sysv/linux/select.c: No such file or directory.
(gdb) bt
#0 0x0000ffff8629ef34 in __GI___select (nfds=4,
readfds=readfds@entry=0xffffd04ccb28, writefds=writefds@entry=0x0,
exceptfds=exceptfds@entry=0x0, timeout=timeout@entry=0x0)
at ../sysdeps/unix/sysv/linux/select.c:69
#1 0x00000000004013cc in main (argc=<optimized out>, argv=<optimized out>)
at tqftpserv.c:552
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

使用 gdbserver 进行调试

gdbserver 实用程序允许您从 Linux 主机远程运行 GDB 工具。当设备上存在调试符号的存储限制时,此实用程序有助于调试问题。

在设备上启用 gdbserver

默认情况下,gdbserver 在构建中未启用。要启用 gdbserver,请执行以下作:

  1. 转到目录并打开文件。layers/meta-qcom-hwe/recipes-devtools/packagegroups/``packagegroup-core-tools-debug.bbappend

  2. 修改文件以添加到 package 列表中。packagegroup-core-tools-debug.bbappend``gdbserver

  3. 在设备上重新编译并刷写 build。

在设备上配置 gdbserver

要在设备上配置 gdbserver,请使用 SSH 运行以下命令:

mount -o rw,remount /
gdbserver :8888 <path-to-binary>

例如:

gdbserver :8888 /usr/bin/tqftpserv

输出示例:

在这里插入图片描述

示例输出指示设备已准备好与 Linux 主机通信。

在 Linux 主机上配置 gdb

要在 Linux 主机上配置 gdb 工具,请执行以下作:

  1. 安装 gdb 和 gdb-multiarch 工具。

    sudo apt-get install gdb gdb-multiarch
    
  2. 创建一个调试目录以捕获构建中的所有符号。

    mkdir test_gdbserver
    
  3. 将具有调试符号的 rootfs 从生成位置复制到调试目录。test_gdbserver

    cp -f <ENTER_PATH>/build-qcom-wayland/tmp-glibc/deploy/images/<chipset>/qcom-multimedia-image-<chipset>-dbg.rootfs.tar.bz2  test_gdbserver
    
    cd test_gdbserver
    
    tar -xvf qcom-multimedia-image-<chipset>-dbg.rootfs.tar.bz2
    

    注意

    运行这些命令时,请替换为下表中指定的适当值。<chipset>

    芯片组价值
    QCS6490qcm6490
    QCS5430qcm6490
    QCS8275qcs8300
    QCS9075qcs9100

    现在已准备好符号。test_gdbserver

  4. 使用命令启动 gdb-multiarch 工具。gdb-multiarch <EXECUTABLE_PATH>

    例如

    gdb-multiarch test_gdbserver/usr/bin/tqftpserv
    

    gdb-multiarch 工具将在 gdb 控制台上启动。

  5. 在 gdb 控制台上运行以下命令:

    set gnutarget elf64-littleaarch64
    

    设置 sysroot 。

    set sysroot <ENTER_PATH>/test_gdbserver
    
    target remote <target_ip>:8888
    
    bt
    
    b
    
    info threads
    

以下屏幕截图显示了配置过程的示例输出。
在这里插入图片描述

$ gdb-multiarch /test_gdbserver/usr/bin/.debug/tqftpserv
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.2) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/.
Find the GDB manual and other documentation resources online at:
http://www.gnu.org/software/gdb/documentation/.
Reading symbols from /test_gdbserver/usr/bin/.debug/tqftpserv...
(gdb) set gnutarget elf64-littleaarch64
(gdb) set sysroot /test_gdbserver
(gdb) target remote 10.92.168.78:8888
Remote debugging using 10.92.168.78:8888
warning: while parsing target description (at line 71): Vector "v8bf16" references undefined type "bfloat16"
warning: Could not load XML target description; ignoring
warning: Unable to find dynamic linker breakpoint function.
Reading symbols from /test_gdbserver/lib/ld-linux-aarch64.so.1...
(no debugging symbols found)...done.
Reading symbols from /test_gdbserver/lib/.debug/ld-linux-aarch64.so.1...
Loaded symbols for /test_gdbserver/lib/.debug/ld-linux-aarch64.so.1
warning: no loadable sections found in added symbol-file system-supplied DSO at 0xfffff7ffb000
0x0000fffff7fda870 in _start ()
from /test_gdbserver/lib/.debug/ld-linux-aarch64.so.1
(gdb) bt
#0 0x0000fffff7fda870 in _start ()
from /test_gdbserver/lib/.debug/ld-linux-aarch64.so.1
#1 0x0000000000000000 in ?? ()
(gdb) b
Breakpoint 1 at 0xfffff7fda870
(gdb) info threads
Id Target Id Frame
* 1 Thread 3212 0x0000fffff7fda870 in _start ()
(gdb)

使用用户空间日志进行调试

以下日志可用于调试在设备上使用 SSH 的用户空间中的问题。

系统日志

要验证是否生成了 syslog,请运行以下命令:

cat /var/log/user.log

如果未生成 syslog,请运行以下命令:

tail -f /var/log/messages

示例日志:



Apr 28 17:42:30 qcm6490 daemon.info avahi-daemon[516]: No service file found in /etc/avahi/services.
Apr 28 17:42:30 qcm6490 daemon.info avahi-daemon[516]: Joining mDNS multicast group on interface lo.IPv6 with address ::1.
Apr 28 17:42:30 qcm6490 daemon.info avahi-daemon[516]: New relevant interface lo.IPv6 for mDNS.
Apr 28 17:42:30 qcm6490 daemon.info avahi-daemon[516]: Joining mDNS multicast group on interface lo.IPv4 with address 127.0.0.1.
Apr 28 17:42:30 qcm6490 daemon.info avahi-daemon[516]: New relevant interface lo.IPv4 for mDNS.

journalctl 日志

要生成 systemd journalctl 日志,请运行以下命令:

journalctl -ef

示例日志:

Apr 28 17:42:28 qcm6490 kernel: spmi-temp-alarm c440000.spmi:pmic@2:temp-alarm@2400: error -ENXIO: IRQ index 0 not found
Apr 28 17:42:28 qcm6490 kernel: qcom-spmi-adc5 c440000.spmi:pmic@2:adc@3100: Invalid dig version read -19
Apr 28 17:42:28 qcm6490 kernel: qcom-spmi-adc5 c440000.spmi:pmic@2:adc@3100: error -ENODEV: adc get dt data failed
Apr 28 17:42:28 qcm6490 kernel: qcom-spmi-adc5 c440000.spmi:pmic@0:adc@3100: error -EINVAL: adc get dt data failed
Apr 28 17:42:28 qcm6490 kernel: qcom-spmi-adc5: probe of c440000.spmi:pmic@0:adc@3100 failed with error -22
Apr 28 17:42:28 qcm6490 kernel: dwc3 a600000.usb: Adding to iommu group
Apr 28 17:42:29 qcm6490 systemd[1]: First Boot Complete was skipped because of a failed condition check (ConditionFirstBoot=yes).
Apr 28 17:42:29 qcm6490 systemd[1]: Reached target Hardware activated USB gadget.

配置调试符号

需要调试符号来解析核心转储。Yocto Linux 在设计上编译一个包并将其拆分为多个包。例如,如果文件编译文件,则会生成多个包。hello_0.1.bb``hello.cpp

下表列出了与核心转储相关的软件包。

Table : 解析核心转储所需的软件包

描述
hello_0.1-r0_armv8-2a.ipk此包包含剥离的可执行文件。它是设备映像中包含的唯一软件包。
hello-dbg_0.1-r0_armv8-2a.ipk此包包含调试符号,并且永远不会打包到映像中。调试包 (-dbg) 会显著增加映像大小,这会导致在映像中包含此包时出现问题。此外,除了调试之外,此包没有运行时值。因此,作为一种策略,Yocto 不会在映像中包含任何 -dbg 包。
hello-dev_0.1-r0_armv8-2a.ipk此包包含从属模块在编译期间使用的导出头文件和库。

根据 Yocto Linux 标准,调试符号存储在构建位置路径中:。例如,package 包含目录的调试符号。tmp-glibc/deploy/ipk/armv8-2a``tqftpserv-dbg_0.0+0+de42697a24-r0_armv8-2a.ipk``/usr/bin/tqftpserv

要将调试符号推送到设备,请使用 SSH 执行以下作:

  1. 重新挂载 rootfs。

    mount -o rw,remount /
    
  2. 使用该命令,将调试符号 () 推送到设备中任何可用分区,例如 .scp``tqftpserv-dbg_0.0+0+de42697a24-r0_armv8-2a.ipk``/data/

    chmod 777 /data/tqftpserv-dbg_0.0+0+de42697a24-r0_armv8-2a.ipk
    
    cd data
    
  3. 在设备上安装调试符号。

    opkg install --nodeps tqftpserv-dbg_0.0+0+de42697a24-r0_armv8-2a.ipk
    

将调试符号推送到设备后,符号将保存在该目录下可执行目录的路径下。例如,对于目录,调试符号保存在该目录中。.debug``/usr/bin/tqftpserv``/usr/bin/.debug

要识别设备上可用的调试符号,请运行以下命令:

cd /usr/bin/.debug
ls

输出示例:


Gencat getent locale pcprofiledump sprof zdump

getconf iconv makedb pldd tqftpserv

重新启动命令

用户空间重启框架使用内核驱动程序 () 触发重启。可以使用 SSH 运行以下重启命令:drivers/firmware/psci/psci.c

表:重新启动命令

命令描述
reboot edl此命令将设备重启至紧急下载 (EDL) 模式。
reboot bootloader此命令将设备重启至 Fastboot 模式。

以下是可用于该命令的可选参数。reboot
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值