在C或C++中,这通常可以通过访问未分配的内存、除以零、解引用空指针等方式来实现
为了诊断这类问题,开发者会使用调试器如NDB来生成和分析core文件。下面将详细介绍这一过程,包括代码编写、编译、运行以生成core文件,以及使用NDB分析core文件。仅供参考

步骤 1: 编写导致崩溃的代码

首先,你需要一个会导致程序崩溃的代码示例。以下是一个简单的C程序,它通过解引用一个空指针来触发崩溃:

// example2.c

#include <stdio.h>
int main() {
int *ptr = NULL;
printf(“The NULL pointer…\n”);
*ptr = 42;
return 0;
}

步骤 2: 编译代码

使用gcc编译器并启用调试信息来编译程序:

命令:gcc -g -o gendb example2.c

-g选项告诉gcc生成调试信息,这对于后续使用NDB分析core文件非常关键。

步骤 3: 启动ndb来调试名为gendb的可执行程序

命令:ndb ./gendb

步骤 4: 生成用户模式或内核模式的崩溃转储(crash dump)文件

命令:g

输出:
0807144727E#8969:[rbp] set pc of thread 8972 from 7faed7f370 to 7faed7f374
0807144727E#8969:[rbp] set pc of thread 8972 from 7faed7f374 to 7faed7f370
0807144727E#8969:[ibp]fail to eat step out signal for thread 8972 1th time
0807144727E#8969:[rbp] set pc of thread 8972 from 7faed7f370 to 7faed7f374
0807144727E#8969:[rbp] set pc of thread 8972 from 7faed7f374 to 7faed7f370
0807144727E#8969:[ibp]failed to read name @0x7faedbe930 or null name. ret 0, read 256
0807144727E#8969:[ufzt]bad condition on thread 8972, suspend_cnt=0, state 0x4
ModLoad: 0000007faeba0000 0000007faed5e000 /lib/aarch64-linux-gnu/libc.so.6
(230c.230c): Access violation - code c0000005 (first chance)
This is the first round of exception dispatching. The exception might be expected.
然后,运行编译后的程序。由于程序中存在错误,它将崩溃并生成core文件:

命令:.dump a.dmp

输出:
echo: ‘.dump a.dmp’
.dump a.dmp
此操作用于将生成的crash dump 文件命名为a.dmp的文件名

步骤 5: 验证是否成功

命令:!ls

输出:
echo: ‘!ls’
a.dmp example2.c gendb ‘ndb..\config\ndb.cfg’
‘..\config\ndb.cfg’ example.c gendb1.c
example1.c geadd.c history.txt
!ls

步骤6:现在,打开一个新的窗口用于打开由ndb产生的dump文件

命令:./ndb -z a.dmp

输出:
echo: ‘./ndb -z a.dmp’
在NDB中,你可以使用以下命令来分析崩溃:

命令:k(显示当前线程的函数调用堆栈)

输出:
echo: ‘k’
0807135510E#8303:readv in 8306, @0x0 L8, got 0
0807135510E#8303:readv in 8306, @0x8 L8, got 0
0807135510E#8303:readv in 8306, @0x0 L8, got 0
0807135510E#8303:readv in 8306, @0x8 L8, got 0
k
Child-SP RetAddr Call Site
0000000000000000 0000000000000000 ld!_start [../sysdeps/aarch64/dl-start.S @ 22]

命令:r(查看和修改寄存器的值)

输出:
echo: ‘r’
r
x0=0x0000000000000000 x1=0x0000000000000000 x2=0x0000000000000000 x3=0x0000000000000000
x4=0x0000000000000000 x5=0x0000000000000000 x6=0x0000000000000000 x7=0x0000000000000000
x8=0x0000000000000000 x9=0x0000000000000000 x10=0x0000000000000000 x11=0x0000000000000000
x12=0x0000000000000000 x13=0x0000000000000000 x14=0x0000000000000000 x15=0x0000000000000000
x16=0x0000000000000000 x17=0x0000000000000000 x18=0x0000000000000000 x19=0x0000000000000000
x20=0x0000000000000000 x21=0x0000000000000000 x22=0x0000000000000000 x23=0x0000000000000000
x24=0x0000000000000000 x25=0x0000000000000000 x26=0x0000000000000000 x27=0x0000000000000000
x28=0x0000000000000000 fp=0x0000000000000000 lr=0x0000000000000000 sp=0x0000007fcaec7420
pc=0x0000007f91182a40 pstate=0x0000000000001000 - - - - - - - - S - - - - EL0
ld!_start:
7f91182a40 d503201f nop
dv (显示或修改变量的值)

命令:dv ptr

输出:
echo: ‘dv ptr’
0807163249E#8969:readv in 8972, @0x83c823ab10 L8, got 0
0807163249E#8969:readv in 8972, @0x82c823ab18 L8, got 0
dv ptr
ptr = 00000000`00000000
说明:显示的是该指针所存储的内存地址

命令:dv *ptr

输出:
echo: ‘dv *ptr’
dv *ptr
ptr = 00000000`00000000
说明:显示的是该地址所存储的数据
.frame(切换当前堆栈的活动帧)

命令:.frame 1

输出:
echo: ‘.frame 1’
0807164603E#8969:readv in 8972, @0x83c823ab10 L8, got 0
0807164603E#8969:readv in 8972, @0x82c823ab18 L8, got 0
.frame 1
Cannot find frame 0x1, previous scope unchanged
说明:Cannot find frame 0x1, previous scope unchanged表明调试器无法找到编号为1的栈帧。这是因为:
当前函数是程序的入口点,栈上根本没有第1帧
.lastevent(显示最近的事件信息)

命令:.lastevent

这个命令可能用于查看最近一次系统或应用程序中发生的重要事件,比如错误、警告或用户操作。这对于故障排查和审计跟踪非常有用
输出:
echo: ‘.lastevent’
.lastevent
Last event: 230c.230c: Access violation - code c0000005 (first chance)
t(显示当前调试会话中的所有线程以及其状态)

命令:t

输出:
echo: ‘t’
t
(230c.230c): Access violation - code c0000005 (first chance)
This is the first round of exception dispatching. The exception might be expected.
说明:列出所有线程的信息,包括线程ID和当前执行的函数。这有助于分析多线程程序中的崩溃问题

作者:涂滨晶  创建时间:2024-08-07 16:09
最后编辑:涂滨晶  更新时间:2024-08-07 17:29