0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

嵌入式C代码调试利器backtrace介绍

lilihe92 来源:最后一个bug 2023-03-08 16:55 次阅读

1

backtrace基本原理

backtrace英译为回溯的意思,这听起来有点专业了,其实大部分搞嵌入式的朋友都有听说过函数调用栈callstack。而backtrace说白了就是我们呈现函数调用关系的一项功能。

所以backtrace调试功能的实现原理基于函数调用栈的概念。

那什么是函数调用栈呢?

函数调用栈是一个记录程序中函数调用关系的数据结构,它在程序运行时动态生成和维护。当程序执行函数调用时,它将当前函数的返回地址和一些其他信息压入堆栈中,并跳转到被调用的函数执行。当被调用函数执行完毕后,它将返回地址弹出堆栈,并跳回到调用函数继续执行。

backtrace调试功能的实现原理就是利用函数调用栈中的信息来追踪程序执行的路径和调用关系。当程序出现错误或崩溃时,backtrace可以通过分析函数调用栈信息来确定出错的位置和原因。

Linux系统中,backtrace通常是通过使用调试器比如我们常用的gdb来实现的。调试器会在程序执行时,动态地获取函数调用栈信息,并将其保存在调试器的内部数据结构中。当程序出现错误或崩溃时,调试器就可以利用保存的函数调用栈信息来进行backtrace操作。

2

backtrace功能

而对于backtrace这个功能在不同的平台和开发环境中的使用是不同的.

比如在我们平时的linux环境中:可以使用glibc提供的backtrace()函数实现backtrace功能。该函数通过解析函数调用栈信息获取函数名、参数和返回地址等信息,并将其打印到标准输出或指定的文件中。

此外,还可以使用gdb或libunwind库来实现backtrace功能。gdb是一个强大的调试器,可以实时追踪程序的执行,获取程序的调用栈信息,并提供各种调试工具和命令。

而其中的libunwind则是一个开源的C/C++库,也可以用于在运行时获取当前程序的调用栈信息,并且在不同的平台和架构上运行,并提供了简单易用的API接口,同样也是非常方便的。

3

glibc下的backtrace功能使用

glibc提供了backtrace函数,可以用来获取当前程序的调用栈信息,使用方法如下:

包含头文件:

#include

定义一个数组,用于存储回溯信息:

#defineBT_BUF_SIZE100
void*bt_buffer[BT_BUF_SIZE];

该数组用于存储backtrace信息,数组大小可以根据需要进行调整。

3. 调用backtrace函数:

intbt_size=backtrace(bt_buffer,BT_BUF_SIZE);

该函数会获取当前程序的调用栈信息,并将其存储在bt_buffer数组中。bt_size表示实际获取到的调用栈信息的条数,该值不会超过BT_BUF_SIZE。

4. 使用backtrace_symbols函数将backtrace信息转换成字符串:

char**bt_strings=backtrace_symbols(bt_buffer,bt_size);

该函数将backtrace信息转换成字符串数组,每个字符串表示一个调用栈信息。bt_strings指向字符串数组的首地址,需要在使用完毕后手动释放内存。

5. 打印回溯信息:

for(inti=0;i< bt_size; i++) {
    printf("%!s(MISSING)n", bt_strings[i]);
}

该代码会将回溯信息打印到标准输出中,可以根据需要进行调整。完整的使用示例代码如下:

#include
#include
#include
#defineBT_BUF_SIZE100
voidprint_backtrace(){
void*bt_buffer[BT_BUF_SIZE];
intbt_size=backtrace(bt_buffer,BT_BUF_SIZE);
char**bt_strings=backtrace_symbols(bt_buffer,bt_size);
printf("backtrace:
");
for(inti=0;i< bt_size; i++) {
        printf("%!s(MISSING)
", bt_strings[i]);
    }
    free(bt_strings);
}
int func_c() {
    print_backtrace();
    return 0;
}
int func_b() {
    return func_c();
}
int func_a() {
    return func_b();
}
int main() {
    return func_a();
}

该程序会输出调用栈信息,格式如下:

backtrace:
./backtrace_demo(func_c+0x16)[0x40069a]
./backtrace_demo(func_b+0xd)[0x4006c5]
./backtrace_demo(func_a+0xd)[0x4006e0]
./backtrace_demo(main+0xe)[0x4006f6]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f6a69e2b1c1]
./backtrace_demo(_start+0x2a)[0x400529]

其中每一行表示一个调用栈信息,格式为"函数名+偏移量+[地址]"。

4

gdb的backtrace功能

在Linux下进行嵌入式开发,backtrace通常是通过使用调试器来实现的,这样的话,gdb都跟你封装成了相应的命令,使用起来也简单很多。

下面以gdb为例来介绍如何使用backtrace:

1、编译程序时添加-g选项,以在可执行文件中包含调试信息。因为backtrace函数需要获取调用栈信息,因此需要包含符号信息。如果使用了-g选项进行编译,则可以保证符号信息的完整性,如果没有使用-g选项编译程序,则可能会出现获取不到符号信息的情况,导致backtrace函数无法正常工作。

例如,使用gcc编译时可以添加-g选项:

gcc-g-oprogramprogram.c
2、使用gdb启动程序并暂停程序的执行。例如,可以使用以下命令启动程序:然后使用以下命令在程序执行时暂停程序的执行:这将在程序的main函数处设置断点,并启动程序的执行。
gdbprogram
(gdb)breakmain
(gdb)run
3、当程序崩溃或出现错误时,gdb会自动暂停程序的执行,并显示当前程序的调用栈信息。可以使用以下命令查看调用栈信息:这将显示当前程序的调用栈信息,包括每个函数的名称、参数和返回值等信息,以及每个函数在调用栈中的位置。
(gdb)backtrace
4、最后可以使用其他gdb命令来查看每个函数的参数和局部变量等信息,以帮助定位代码崩溃或错误的原因。

5

跟踪的准确性

在实现backtrace功能时,还需要注意一些细节问题。例如,需要注意函数调用栈的深度和堆栈溢出等问题,以及需要保证backtrace操作的可靠性和准确性,下面简单聊聊如下三个值得注意的方面:

优化选项:程序使用了-O选项进行优化时,可能会改变函数调用栈的结构,从而使backtrace函数获取到的信息不完整或不准确。因此,在使用backtrace函数时,建议关闭优化选项,以保证其可靠性。

栈溢出:如果程序发生栈溢出,可能会破坏调用栈信息,导致backtrace函数获取到的信息不完整或不准确。因此,在程序中应该避免出现栈溢出的情况,以保证backtrace函数的可靠性。

线程安全:如果程序使用多线程,每个线程都有自己的调用栈,因此需要在每个线程中分别调用backtrace函数来获取相应的调用栈信息。此外,在多线程环境下,需要注意避免竞争条件的出现,以保证backtrace函数的可靠性。

总之,在使用glibc提供的backtrace函数时,需要注意编译选项、优化选项、栈溢出和线程安全等因素,以保证其可靠性。此外,不同的硬件平台和操作系统可能有不同的backtrace实现方式和接口,需要使用相应的工具和API来实现。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5068

    文章

    19014

    浏览量

    303230
  • Linux系统
    +关注

    关注

    4

    文章

    591

    浏览量

    27352
  • 调试器
    +关注

    关注

    1

    文章

    300

    浏览量

    23689
  • API接口
    +关注

    关注

    1

    文章

    82

    浏览量

    10427
  • GDB调试
    +关注

    关注

    0

    文章

    24

    浏览量

    1437

原文标题:嵌入式C代码调试利器---backtrace

文章出处:【微信号:最后一个bug,微信公众号:最后一个bug】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    嵌入式程序基于源代码仿真调试

    前面一课设计了51单片机最小系统电路,使用51单片机的I/O口控制发光二极管的状态,并装载运行了使用keil编写的嵌入式程序。本次实验应用proteus结合keil对嵌入式C程序进行源代码
    的头像 发表于 11-01 09:24 1166次阅读
    <b class='flag-5'>嵌入式</b>程序基于源<b class='flag-5'>代码</b>仿真<b class='flag-5'>调试</b>

    如何调试嵌入式代码

    我们在进行嵌入式系统开发调试时,受限于嵌入式芯片资源和性能,一般采用远程调试。在调试嵌入式底层
    发表于 12-17 06:32

    嵌入式实时程序设计中C/C++代码的优化

    本文简单介绍嵌入式实时程序设计的特点和嵌入式系统设计中语言的选择,着重介绍了以下几种在嵌入式实时程序设计中优化
    发表于 08-07 08:47 15次下载

    嵌入式程序设计中C/C++代码的优化

    本文介绍了在嵌入式程序设计中几种提高C/C++代码效率的方法,通过对例子的分析,探讨了影响程序效率的原因。关键词:
    发表于 08-14 08:53 25次下载

    嵌入式系统的远程调试

      1 基本方法   图1(a)是传统的嵌入式调试方法:主机PC通过串口与从机嵌入式系统相连,接收从嵌入式系统发来的调试信息并向
    发表于 08-30 10:23 1004次阅读
    <b class='flag-5'>嵌入式</b>系统的远程<b class='flag-5'>调试</b>

    嵌入式应用中的能耗调试技术

    嵌入式应用中的能耗调试技术
    发表于 02-12 17:28 891次阅读
    <b class='flag-5'>嵌入式</b>应用中的能耗<b class='flag-5'>调试</b>技术

    Monitor C语言源代码调试器设计

    为解决嵌入式系统不支持本地调试且开发周期较长的问题,使用了一种通过PC机去控制嵌入式系统的远程调试方案。该方案针对32位嵌入式设备,设计并实
    发表于 12-01 15:52 56次下载
    Monitor <b class='flag-5'>C</b>语言源<b class='flag-5'>代码</b><b class='flag-5'>调试</b>器设计

    嵌入式C编程

    嵌入式C编程,非常有用的资料,介绍嵌入式C语言编程
    发表于 12-29 17:29 0次下载

    两种远程调试嵌入式系统的介绍

    调试嵌入式系统与桌面操作系统差别很大,本文向您介绍调试嵌入式系统的两种推荐方案,插桩和片上调试
    发表于 04-14 07:43 2570次阅读
    两种远程<b class='flag-5'>调试</b><b class='flag-5'>嵌入式</b>系统的<b class='flag-5'>介绍</b>

    嵌入式软件的开发流程_嵌入式软件的调试

    本文首先介绍嵌入式软件的发展,其次阐述了嵌入式软件的开发流程,最后介绍嵌入式软件的调试
    发表于 08-31 16:02 6238次阅读

    如何实现嵌入式系统远程调试

    介绍。注意,本文中的嵌入式系统远程调试方案仅仅代表一种方式,仅提供一种参考。如果你对嵌入式系统抑或是嵌入式系统的远程
    的头像 发表于 11-22 11:55 5298次阅读
    如何实现<b class='flag-5'>嵌入式</b>系统远程<b class='flag-5'>调试</b>

    嵌入式系统如何进行远程调试

    嵌入式系统随着目前科技的发展,正逐步融入人们的生活中。对于嵌入式系统,我们应该有所了解。就专业人员而言,他们对嵌入式系统早已驾轻就熟。为增进大家对嵌入式系统的认识,本文将对
    发表于 12-23 10:39 7次下载

    嵌入式外中断c语言代码

    嵌入式外中断c语言代码(arm嵌入式开发实例)-嵌入式外中断c语言
    发表于 07-30 11:29 4次下载
    <b class='flag-5'>嵌入式</b>外中断<b class='flag-5'>c</b>语言<b class='flag-5'>代码</b>

    嵌入式LINUX系统内核和内核模块调试

    嵌入式LINUX系统内核和内核模块调试(嵌入式开发和硬件开发)-嵌入式LINUX系统内核和内核模块调试                 
    发表于 07-30 13:55 10次下载
    <b class='flag-5'>嵌入式</b>LINUX系统内核和内核模块<b class='flag-5'>调试</b>

    嵌入式C++编程

    编程特性来构建嵌入式系统您将了解如何将您的系统与外部外围设备以及使用驱动程序的有效方式集成指导您测试和优化代码以获得更好的性能并实现有用的设计模式将了解如何使用 Qt,这是用于构建嵌入式系统的流行 GUI 库。内容
    发表于 11-04 10:36 10次下载
    <b class='flag-5'>嵌入式</b><b class='flag-5'>C</b>++编程