首页 > 其他分享 >关于使用gdb调试c代码的简单教程

关于使用gdb调试c代码的简单教程

时间:2023-01-05 15:25:51浏览次数:59  
标签:教程 .. adas 编译 gdb 输入 调试

因个人此前调试c代码的时候只会在代码中加打印信息,然后编译代码,运行程序,搜索打印信息,查找问题...因此代码的调试效率很慢,经大佬提示使用gdb调试后,代码的调试效率提高了不少。因此对gdb调试的过程进行记录形成一个学习笔记,加强记忆,也方便大家的学习和交流。故本文档仅针对那些对于gdb调试一无所知的小白同学,当然也欢迎大佬们指正文档中的纰漏之处。大家相互学习,共同进步!

1. gdb介绍

gdb是GNU开源组织发布的一个强大的UNIX下的程序调试工具。一般来说,gdb主要完成下面四个方面的功能:

(1) 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。 (2) 可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式) (3) 当程序被停住时,可以检查此时你的程序中所发生的事。 (4) 动态的改变你程序的执行环境。

2. 基本操作

以c2_adas项目为例。

  • 编译层面,在编译的时候需要在Makefile(CMakelists也是一样)里使用debug模式对程序进行编译,如下所示:

    **************************************************
    Makefile文件里的设定的变量,dbg,用来设置编译模式
    export dbg:=release
    **************************************************
    Makefile.param.mk文件里,设定编译选项,如release模式下执行-o2的优化选项
    ifeq ($(dbg),release)
    $(warning release version)
    DBG_FLG := -DGLOBAL_RELEASE_EN=1
    OPTZM_FLG := -O2
    else

    ifdef g_release
    _DEFS := -DGLOBAL_RELEASE_EN=$(g_release)
    endif
    DBG_FLG := -g
    OPTZM_FLG := -O0
    endif

    说明:

    -O0: 不做任何优化,这是默认的编译选项。

    -O和-O1: 对程序做部分编译优化,对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化。

    -O2: 是比O1更高级的选项,进行更多的优化。Gcc将执行几乎所有的不包含时间和空间折中的优化。当设置O2选项时,编译器并不进行循环打开()loop unrolling以及函数内联。与O1比较而言,O2优化增加了编译时间的基础上,提高了生成代码的执行效率。

    -g 选项:将调试信息加入到可执行文件,这个是关键的一步。

  • 编译完成后,在板子上执行程序,输入如下命令:

    ./gdb --args ./jimu_adas.elf 1 #若可执行文件不需要参数,则不用加--args选项

    板子终端会打印如下信息:

    # ./gdb --args ./jimu_adas.elf 1
    GNU gdb (GDB) 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 "aarch64-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/>.

    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from ./jimu_adas.elf...
    1. 常规的调试步骤是,开始打断点调试,例如,我想在adas.c文件的DetectFunc2函数,或者1451行输入断点,则可在gdb模式下输入如下命令:

    break adas.c:DetectFunc2 #按tab键可以自动补全,在adas.c文件里的DetectFunc2函数入口打上断点

    break adas.c:1451 #或者写入如下命令,在adas.c文件中的1451行处打上断点
    1. 输入n或next单步调试,实际信息是1414 in../../adas/.//adas.c,除了行号和文件名,并无其他有用的信息。

    (gdb) n
    1414    in ../../adas/.//adas.c

    若将文件路径添加进gdb中,执行如下命令:

    dir /mnt/hewen/work/03_jmu_adas/c2_adas_src2/adas/

    输入list file:N 查看指定文件的代码,list adas.c:1414得到如下信息:

    (gdb) list adas.c:1414                                  
    1409           //ptCameraProc = (TCameraProc *)ptThread->ptArg;
    1410           s32RdFd = PipeGetReadDescriptor(&ptThread->tPipe);
    1411           SimpleThreadLog_construct(&threadLog, 0, 1000);
    1412            while (ptThread->s32Status != CMD_EXIT)
    1413           {
    1414                   run_time = now_ms();
    1415                   tWaitTime.tv_sec = 0;
    1416                   tWaitTime.tv_usec = WAIT_UTIME;
    1417                    if (FdSelectOneSocket(s32RdFd, &tWaitTime, FD_SET_READ) > 0)
    1418                   {

    备注:打印出adas.c文件,1414行的前5行后5行的源码

    此时再次执行n命令,单步调试,则会打印行数和源码,方便查看变量信息,如下所示:

    (gdb) n                                                 
    1416                   tWaitTime.tv_usec = WAIT_UTIME;
    1. 输入p 变量名,则可打印变量的值,如下所示:

    (gdb) p tWaitTime 
    $1 = {tv_sec = 0, tv_usec = 0}

    备注:对于指针变量,则可在变量前加*来打印指针变量指向的内存的值,若指针变量为void类型,则需要加上指针类型的强制转换来打印指针变量指向的内存的值,否则打印出来的也是无效的内容;

    1. 输入finish可以跳出函数,但不结束程序,如下所示:

    (gdb) finish 
    Run till exit from #0 CnnDetect_run (pHandle=0xbf4280, detInput=0x7fde48c850) at ../../adas/.//cnn_detect.c:468

    当前执行的行数为cnn_detect.c文件的468行,执行完函数后跳出去。

    1. 输入info breakpoints命令可以查看当前gdb环境打的断点,如下所示:

    (gdb) info breakpoints 
    Num     Type           Disp Enb Address           What
    1       breakpoint     keep y   0x00000000004363d8 in DetectFunc2 at ../../adas/.//adas.c:1396
          breakpoint already hit 1 time
    1. 输入c或continue命令,可以执行到下一个断点;

    2. 如果函数的循环次数很多,可以输入until命令,执行完当前的循环;

    3. 输入bt或backtrace命令,打印当前的函数调用栈的所有信息,如下所示:

    (gdb) bt
    #0 0x0000000000436510 in DetectFunc2 (ptArg=0xe13a60) at ../../adas/.//adas.c:1444
    #1 0x0000007ff7bb5648 in ?? () from /lib/libpthread.so.0
    #2 0x0000007ff77e3f0c in ?? () from /lib/libc.so.6

    输入frame n(n指的是栈的编号)命令查看栈详细信息,如

    (gdb) frame 0
    #0 0x0000000000436510 in DetectFunc2 (ptArg=0xe13a60) at ../../adas/.//adas.c:1444
    1444                                   ptPicture->detOut = CnnDetect_run(g_ptAdas->ptCnnDetectCtx, &detInput);
    (gdb) frame 1
    #1 0x0000007ff7bb5648 in ?? () from /lib/libpthread.so.0

    备注:输入1号和2号栈对应的是系统的库文件,如多线程相关的库和基础的c库等,无法得到有效的信息。bt命令是在程序运行报错的情况下很有效果,可以定位到最后崩溃时刻的函数。

    1. 输入info locals命令,可以查看当前的函数的变量,如下所示:

      (gdb) info locals 
      cx = <optimized out>
      cy = <optimized out>
      detInput = {imageWidth = 1920, imageHeight = 1080, dataFormat = 0, src_phy_mem = {virt = 0x7fd6107000, phys = 1696645120, size = 3110400}}
      tWaitTime = {tv_sec = 0, tv_usec = 9994}
      s32RdFd = 10
      i = <optimized out>
      ptThread = 0xe13a60
      ptPicture = 0x7fe28b8018
      s32FrameNum = 0
      dtime0 = 10608187.375065999
      dtime1 = 0
      run_time = 10983210.168804999
      total_time = 0
      time_stamp = 0
      time_start = 0
      time_end = 0
      threadLog = {cameraId = 0, printIntervalTime = 1000, startTime = 0, frameNum = 0, totalTime = 0, runTime = 11746464.414445, checkRun = 1}
      __func__ = "DetectFunc2"
    2. 输入q命令,退出gdb调试模式

      退出后,此前设定的gdb调试的参数,如断点信息都不会存在,慎重退出。

    3. 总结

    当前文档总结的是gdb的基本操作,其他的更复杂的一些操作命令这里并未提及,若有兴趣自行查阅资料。需要强调的是gdb调试用熟练了,比在代码中加打印信息的调试方式要快一万倍。

    4. 参考资料

    Linux学习--gdb调试

    --by Nero 20221230

     

     

  •  

标签:教程,..,adas,编译,gdb,输入,调试
From: https://www.cnblogs.com/hewen0901/p/17027630.html

相关文章

  • Zynq PS之UART调试
    在创建应用工程时,选择HelloWorld模板即可,以XCZU21DR开发。硬件原理图如下:Vivado中添加&配置IP添加ZynqUltraScale+MPSoc IP。UART设置DDR配置硬件设计中选择的DDR4型号......
  • Openpyxl教程-基础操作
    1.openpyxl简介openpyxl是用于读取/写入Excel2010xlsx/xlsm文件的Python库,也就是说openpyxl这个Python库不支持xls文件的读取和操作,如果在工作中遇到xls文件我们就不能......
  • ThinkPHP多语言模块文件包含RCE复现详细教程
    漏洞描述:ThinkPHP在开启多语言功能的情况下存在文件包含漏洞,攻击者可以通过get、header、cookie等位置传入参数,实现目录穿越+文件包含,通过pearcmd文件包含这个trick即可实......
  • oh-my-zsh离线配置傻瓜教程-不需要修改install.sh文件
    前提系统里已经安装zsh离线安装oh-my-zsh下载github的zipoh-my-zsh,上传到服务器并解压下载github的ziphmyzsh-offline,上传到服务器并解压将offline_install.diff放......
  • JNI详细教程
    一、创建java文件首先创建需要调用jni的java文件。如:packagecom.rg.serialPort;publicclassSerialPort{...publicSerialPort(Filedevice,intbaudRate,......
  • 推荐一个设计师的宝藏网站羽兔网-设计师的软件下载安装和教程都有非常全
    1、有所有设计相关软件下载2、设计软件安装步骤和过程3、设计软件使用方法和教程真的非常全。网站连接:羽兔网  比如下面以blender软件下载和安装为例: 关键是......
  • OpenHarmony系统使用gdb调试init
     前言OpenAtomOpenHarmony(简称“OpenHarmony”)适配新的开发板时,启动流程init大概率会出现问题,其为内核直接拉起的第一个用户态进程,问题定位手段只能依赖代码走读和......
  • OpenHarmony系统使用gdb调试init
    OpenHarmony系统使用gdb调试init前言OpenAtomOpenHarmony(简称“OpenHarmony”)适配新的开发板时,启动流程init大概率会出现问题,其为内核直接拉起的第一个用户态进程,问题定位......
  • 草图大师(SketchUp)2022安装图文教程
    ​草图大师(SketchUp)是一个非常受欢迎并且易于使用的3D设计软件,它被比喻为电子设计中的“铅笔”。它的主要特点就是使用简便,人人都可以快速上手。并且可以将使用SketchUp创建......
  • 使用Let's Encrypt 安装配置免费SSL 证书教程
    一、Let'sEncrypt简介Let'sEncrypt是一个由非营利性组织互联网安全研究小组(ISRG)提供的免费、自动化和开放的证书颁发机构(CA)。简单的说,借助Let'sEncrypt颁发的证......