如何在linux-arm系统下查找crash堆栈对应代码

编译

编译选项中需要有 -g选项,可以与-O2… 同时存在
例如生成测试文件test

$ file test
test: ELF 32-bit LSB  executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 4.1.0, not stripped

表明test是一个没有strip过的文件,包含有调试符号

查看符号表及代码地址

查看执行程序的符号表

$ arm-ca53-linux-gnueabihf-nm test
         U abort@@GLIBC_2.4
         U __aeabi_unwind_cpp_pr0@@GCC_3.5
00021048 B __bss_end__
00021048 B _bss_end__
00021044 B __bss_start
00021044 B __bss_start__
00010830 t call_weak_fn
00021044 b completed.10368
00010694 T main
.....

显示执行程序的汇编信息,其中第一列为后面addr2line将要用到的地址

$ arm-ca53-linux-gnueabihf-objdump -d test

Disassembly of section .text:

00010694 <main>:
   10694:       e92d47f0        push    {r4, r5, r6, r7, r8, r9, sl, lr}
   10698:       e3045b40        movw    r5, #19264      ; 0x4b40
   1069c:       e340504c        movt    r5, #76 ; 0x4c
   106a0:       e59f4128        ldr     r4, [pc, #296]  ; 107d0 <main+0x13c>
   106a4:       e24dd0a8        sub     sp, sp, #168    ; 0xa8
   106a8:       e59f7124        ldr     r7, [pc, #292]  ; 107d4 <main+0x140>
   106ac:       e3a09f4b        mov     r9, #300        ; 0x12c
   106b0:       e08f4004        add     r4, pc, r4
   106b4:       e28d6008        add     r6, sp, #8
   106b8:       e08f7007        add     r7, pc, r7
   106bc:       e28d8050        add     r8, sp, #80     ; 0x50
   106c0:       e28da004        add     sl, sp, #4
   106c4:       e1a00005        mov     r0, r5
   106c8:       ebffffdc        bl      10640 <usleep@plt>
   106cc:       e1a01006        mov     r1, r6
   106d0:       e1a00004        mov     r0, r4
   106d4:       ebffffd3        bl      10628 <statvfs@plt>
   106d8:       e3500000        cmp     r0, #0
   106dc:       1a000011        bne     10728 <main+0x94>
   106e0:       e59d2008        ldr     r2, [sp, #8]
   106e4:       e3a01000        mov     r1, #0
   106e8:       e59d3010        ldr     r3, [sp, #16]
   106ec:       e3e00103        mvn     r0, #-1073741824        ; 0xc0000000
   106f0:       e0832392        umull   r2, r3, r2, r3
   106f4:       e1530001        cmp     r3, r1

使用addr2line查地址对应的代码

$ arm-ca53-linux-gnueabihf-addr2line -Cfe test
106d8
main
/home/test/test.cpp:19

注意64位的库,需要使用64位的addr2line
aarch64-linux-android-addr2line

打印堆栈

参考Android的 debuggerd/libbacktrace和开源的libunwind

使用命令debuggerd pgrep test打印堆栈如下
···
$ debuggerd 580
I 2019-12-31 09:16:00.448786 [800]/Backtrace:

----- pid 580 at 2019-12-31 09:16:00 -----

I 2019-12-31 09:16:00.449454 [800]/Backtrace: Cmd line: test

D 2019-12-31 09:16:00.449744 [800]/Backtrace: “test” sysTid=580

I 2019-12-31 09:16:00.478072 [800]/Backtrace: #00 pc 000992d0 /lib/libc-2.26.so (nanosleep+28)

I 2019-12-31 09:16:00.478704 [800]/Backtrace: #01 pc 000c6d60 /lib/libc-2.26.so (usleep+68)

I 2019-12-31 09:16:00.478810 [800]/Backtrace: #02 pc 00000804 /bin/test (_init+504)

I 2019-12-31 09:16:00.478889 [800]/Backtrace: #03 pc 00016b1c /lib/libc-2.26.so (__libc_start_main+276)

I 2019-12-31 09:16:00.478962 [800]/Backtrace: #04 pc 000006e8 /bin/test (_init+220)

I 2019-12-31 09:16:00.479068 [800]/Backtrace: dump_thread exit
I 2019-12-31 09:16:00.479485 [800]/Backtrace:
···

查找对应代码

正常的话,使用toolchain中的addr2line -Cfe xxx crashaddr
可以得到对应的代码行数

debug遇到的问题

进程处于T状态,即STOP状态,可以发送信号SIGCONT恢复执行状态
kill -s SIGCONT 578

FIXME:貌似执行程序是直接加载到对应的地址的,不需要减去map当中的便宜地址,否则addr2line会找不到代码

<think>我们正在讨论如何查找系统崩溃的具体原因。根据之前的引用和用户的问题,我们需要提供查找系统崩溃原因的方法。由于系统崩溃可能涉及不同平台(如iOS、Android、Linux等),我们将分别讨论。 引用[1]提到:当遇到系统库相关的崩溃时,可以通过崩溃日志获取对应系统库源码来定位问题。在iOS中,可以通过崩溃日志中的地址信息,使用`atos`命令将地址转换为对应的函数名和行号(如果符号化信息可用)。 引用[2]介绍了NDK崩溃的查找方法:使用Testin平台的SDK收集崩溃时的堆栈信息(包括函数指针),然后通过云服务平台进行归一化处理,方便开发者分析。 引用[3]指出:在Linux系统中,程序崩溃(如段错误)会产生coredump文件,通过`gdb`分析coredump可以查找原因。同时需要设置`ulimit -c`来确保生成coredump。 引用[4]详细说明了iOS崩溃信息的分析方法:将崩溃地址减去基地址,然后使用`atos`命令定位到具体的代码位置。 引用[5]则是关于Java中的崩溃(如SIGTRAP)可能的原因,例如空指针或类型转换错误。 因此,我们可以按照不同平台来总结查找系统崩溃具体原因的方法: ### Windows系统崩溃排查 1. **查看事件查看器**:打开事件查看器(Event Viewer),在“Windows日志”->“系统”中查找错误事件,特别是来源为“BugCheck”的事件,通常包含蓝屏错误代码(如STOP Code)和相关参数。 2. **分析内存转储文件(Dump文件)**:Windows在崩溃时通常会生成内存转储文件(位于`%SystemRoot%\MEMORY.DMP`或`%SystemRoot%\Minidump`目录下)。使用WinDbg工具(Debugging Tools for Windows)可以分析这些文件,命令如: ``` !analyze -v ``` 可以自动分析崩溃原因。 ### Linux系统崩溃排查 1. **启用coredump**:在终端执行`ulimit -c unlimited`(当前会话有效)或修改配置文件(永久生效),以确保程序崩溃时生成coredump文件。 2. **使用gdb分析coredump**: ```bash gdb <可执行文件> <coredump文件> ``` 在gdb中使用`bt`(backtrace)命令查看崩溃时的堆栈信息。 ### Android系统崩溃(Native层,如NDK) 1. **使用logcat查看崩溃信息**:通过`adb logcat`可以查看崩溃时的堆栈信息(通常带有`signal`信息,如SIGSEGV)。 2. **使用addr2line或ndk-stack定位**: - 将崩溃时的堆栈地址(来自logcat)通过`addr2line`命令转换为代码行: ```bash addr2line -e <带符号的可执行文件> <崩溃地址> ``` - 或者使用`ndk-stack`工具: ```bash adb logcat | ndk-stack -sym <带符号的库文件所在目录> ``` 3. **第三方平台(如Testin)**:集成SDK后,崩溃信息会自动上报并归一化展示,便于分析[^2]。 ### iOS系统崩溃 1. **获取崩溃日志**:通过Xcode的“Devices and Simulators”查看设备上的崩溃日志,或从设备设置中导出。 2. **符号化崩溃日志**:如果崩溃日志未符号化,需要使用Xcode的符号化工具。将崩溃日志(.crash文件)、对应的.dSYM文件(带调试符号)和可执行文件放在同一目录下,使用命令行工具`atos`进行符号化: ```bash atos -arch <架构> -o <应用程序二进制文件> -l <基地址> <崩溃地址> ``` 例如引用[4]中的例子:`atos -arch armv7 -o mengmengdai.app/mengmengdai -l 0xf9000 0x000fdf7f`[^4]。 ### Java虚拟机的崩溃(如Android Java层、Java应用) 1. **查看崩溃堆栈**:通常崩溃时会打印异常堆栈(如NullPointerException),可以直接定位到出错代码行。 2. **分析日志**:查看日志中是否有明确的异常信息。 总的来说,查找系统崩溃原因的关键步骤包括: 1. 获取崩溃时的日志或转储文件(如coredump、Windows dump文件、iOS崩溃日志)。 2. 使用相应的工具(如gdb、WinDbg、atos、addr2line)分析这些文件,定位到具体的代码位置。 3. 分析崩溃原因(如空指针访问、内存越界、多线程竞争等)。 如果崩溃是由第三方库引起,可能需要该库的符号文件(如.dSYM文件)才能进行符号化。 §§相关问题§§ 1. 如何分析Windows蓝屏(BSOD)的dump文件? 2. 在Linux中如何配置系统使其在程序崩溃时自动生成coredump文件? 3. 如何获取iOS应用的dSYM文件? </think>### 查找系统崩溃具体原因的方法 #### 1. **分析崩溃日志(通用方法)** - **获取日志**: - Windows:事件查看器 → Windows日志 → 系统 - Linux:`dmesg | grep -i error` 或 `/var/log/syslog` - Android/iOS:设备日志(Android Studio/Xcode)或第三方平台(如Testin)[^2] - **关键信息**: - 错误代码(如 `0x0000007B`) - 崩溃模块(如 `kernel32.dll`) - 堆栈调用轨迹(如 `#00 pc 000fdf7f libapp.so`) #### 2. **符号化堆栈地址(iOS/Android NDK)** - **iOS**:使用 `atos` 转换地址[^4] ```bash atos -arch arm64 -o AppBinary -l 基地址 崩溃地址 ``` 例如引用示例: $$ \text{基地址} = \text{崩溃地址}_{16进制} - \text{偏移量}_{10进制} \to 0xf9000 $$ - **Android NDK**: ```bash addr2line -e libapp.so 崩溃地址 # 需带符号的.so文件 ``` #### 3. **调试核心转储文件(Linux/Unix)** - 启用 coredump: ```bash ulimit -c unlimited # 临时生效 echo "kernel.core_pattern=/tmp/core-%e" >> /etc/sysctl.conf # 永久配置 ``` - 使用 GDB 分析: ```bash gdb 可执行文件 coredump文件 (gdb) bt # 查看堆栈 (gdb) info registers # 检查寄存器 ``` #### 4. **常见崩溃类型与诊断工具** | 崩溃类型 | 诊断工具 | 关键操作 | |----------------|------------------------------|------------------------------| | **内存越界** | Valgrind (Linux) | `valgrind --tool=memcheck` | | **空指针解用** | GDB/Lldb | 检查寄存器是否为 `0x0` [^5] | | **堆栈溢出** | 静态分析工具(Coverity) | 检查递归深度/缓冲区大小 | | **多线程竞争** | ThreadSanitizer (TSan) | 编译时添加 `-fsanitize=thread` | #### 5. **第三方平台集成** - **Testin/友盟等**:自动归并 NDK 崩溃,归一化不同设备/ROM 的堆栈[^2] - **Firebase Crashlytics**:实时符号化 iOS/Android 原生崩溃日志 > 提示:80% 的崩溃源于内存问题(越界/泄漏)或空指针,优先检查动态内存操作和指针校验[^3][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值