【小白进阶】Linux 调试大法——gdb

初衷

        gdb调试是每一个后端开发工程师所必备的技能,我们工作总是会用gdb协助我们去分析和调试问题。但是大部分同学的技能仅停留在最基础的查看问题。即gdb program -->r --> 问题复现 --> bt 查看源码中的哪一行出现了错误。再稍微熟练点的,可能就是p var查看一下变量的值,进一步协助排查。

        我想说的是,这点能力是完全不够的,身边一些同事稍微遇到一点问题,就不知道如何进行调试了。比如:

  • 目标平台没有gdb 工具
  • 程序及动态库符号被strip了,bt 查看不到详细信息
  • 问题不是必现,一直等待会耗费人力

        一旦遇到这些问题,大部分肯定都会一脸懵逼,不知道该怎么办了。但是我认为:作为后端开发工程师,gdb 调试是必备技能,这个技能应该是一个能力集,不仅仅是会几个gdb 调试指令即可,而是在这个过程中,遇到任何问题,都应该能够独立分析解决。这也是我写本篇文章的初心。

目标平台没有gdb怎么办

        嵌入式平台的资源有限,很多厂家并不会将gdb 等工具集成到设备中。这就导致很多新手同学,不知道该怎么办了。犹记得刚毕业,我天马行空的居然尝试将虚拟机中的gdb copy 到目标设备中,期待能够正常使用(现在想想,真心觉得傻得可爱。【申明一下哈,有可能会成功哦,前提是你的开发设备和目标设备都是相同的架构】)。

        遇到这种情况,我们一般都需要重新编译gdb 工具。有兴趣的同学可以参考这篇文章,应该算是较为详细。工作中如何编译开源工具(gdb)_gdb编译_谢艺华的博客-CSDN博客。

coredump

        我们在开发调试过程中,若一直使用gdb进行调试,这对于测试和开发而言会不太方便,影响效率。特别是在压力测试的场景中。如何解决这一难题呢?我们可以使用linux自带的coredump机制。

        Coredump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照。操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里

        但是这个机制默认可能是没有开启的,因为一旦开启后,会对系统赞成较大的压力。开启方式有两种:

系统设置

一、开启 coredump

执行ulimit -c查看coredump 是否开启,若结果为0,则认为没有启动coredump文件生成。需要进行打开。

1. 临时启用:ulimit -c 1024ulimit -c unlimited

前一种是限制core dump的文件大小不超过1024K,后一种是不限制core dump文件的大小。建议根据实际情况进行设置大小,因为coredump是将程序崩溃的那一刻的内存进行快照,因此越占用内存的进程,其生成的core文件,也就会越大。因此动辄几个G的core文件,也就不再稀奇。很有可能把磁盘占满了,导致程序异常。

2. 永久有效:打开/etc/profile文件, 增加如下以下并生使其生效:ulimit -S -c unlimited > /dev/null 2>&1

二、设置coredump文件名

        设备里面可能同时运行多个应用,不同的应用可能都会发生crash,若core文件名不做特殊识别,可能无法在多个core文件中,找到我们需要的那一个。因此对core文件进行文件名设置,就显得很有必要。

echo '/corefiles/core-%e-%p-%t' > /proc/sys/kernel/core_pattern,其中:

  • /corefiles是core文件的保存路径。
  • core-%e-%p-%t是core 文件名,以core-开头。
  • %p 所dump进程的进程ID
  • %u 所dump进程的实际用户ID
  • %g 所dump进程的实际组ID
  • %s 导致本次core dump的信号
  • %t core dump的时间 (由1970年1月1日计起的秒数)
  • %h 主机名
  • %e 程序文件名

一般默认就设置为core-%e-%p-%t

三、设置coredump文件保存位置

        我们知道嵌入式平台的磁盘空间一般也是有限的,但是它会通过挂载不同的磁盘分区,实现扩容。比如:

        如上图,我的环境中,默认core文件保存的路径是/usr/share/apport/apport/,若/usr所挂载的分区磁盘空间不足怎么办,那么此时就可以通过修改core文件保存路径实现。

        同理,同样通过修改/proc/sys/kernel/core_pattern

代码设置

        有时候,我们也可以通过程序开启coredump,这样测试人员就不用在意系统环境的设置了。但是前提是程序必须以root权限运行。代码示例如下:

#include <stdio.h>
#include<stdlib.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <string.h>
#include<fcntl.h>
#include <time.h>

#define CORE_FILE_SIZE 1024*1024*5    /** core文件大小,可根据实际情况设置*/
#define KERNEL_PATTERN_FILE  "/proc/sys/kernel/core_pattern"
void coredump_file_set(char *name)
{
        struct rlimit rlim;
        getrlimit(RLIMIT_CORE, &rlim);
        rlim.rlim_cur = rlim.rlim_max = CORE_FILE_SIZE;
        int32_t ret = setrlimit(RLIMIT_CORE, &rlim);
        if(ret < 0){
                perror("setrlimit");
                return;
        }
        
        char path[256] = {'0'};
        sprintf(path, "/ota_master_data/%sCore_%t", name);

        int32_t core_pattern_fd = open(KERNEL_PATTERN_FILE, O_RDWR|O_NDELAY|O_TRUNC, 0666);
        if(core_pattern_fd < 0){
                perror("open");
                free(localtime);
                return;
        }

        ret = write(core_pattern_fd, path, strlen(path));
        if(ret < 0){
                perror("write");
        }
                free(localtime);
        close(core_pattern_fd);
}

int32_t main(int32_t argc, char* argv[])
{
    coredump_file_set("App");      
    return 0;
}

调试

        程序异常之后,我们就可以在设置的路径下生成对应的coredump文件,通过对应编译链中的gdb工具可分析coredump文件。为什么要用工具链中的gdb工具呢?这个可以思考一下,可以在评论区回答哦~~~。

调试程序步骤:

1. 启动gdb,进入core文件。命令格式:gdb [exec file] [core file]。如下:

yihua@ubuntu:~/coredump/core$ /opt/corbos-linux/2.30.0/sysroots/x86_64-pokysdk-linux/usr/bin/aarch64-poky-linux/aarch64-poky-linux-gdb otamaster  otaMasterCore_1699106821.8
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 "--host=x86_64-pokysdk-linux --target=aarch64-poky-linux".
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 otamaster...
.....

warning: Could not load shared library symbols for 43 libraries, e.g. /usr/library/libvdi_main.so.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
--Type <RET> for more, q to quit, c to continue without paging--
Core was generated by `otamaster -c ../etc/otamasterConfig.json'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x0000007f9b14ef90 in ?? ()
[Current thread is 1 (LWP 25)]
(gdb)

2. 设置库的加载路径。可执行程序运行时会加载很多动态库,core文件中的一些代码段很有可能就是在这些库中,若不加载这些依赖库,就无法观察相应的符号及堆栈信息。

3. 将设备中程序依赖的库拷贝出来。lddobjdump -x programe | grep NEEDED查看依赖库。

4. 在GDB中设置动态库寻找路径。set solib-search-path如:

(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
                                        No          /usr/library/libvdi_main.so
                                        No          /usr/library/libabupFoundation.so
                                        No          /adaptive/usr/lib/libdlt.so.2
                                        No          /usr/library/libjson-c.so.5
                                        No          /usr/lib/libcrypto.so.1.1
                                        No          /usr/library/libota.so
                                        No          /hostLibrary/lib/libMI_VCCD_MISESDK.so
                                        No          /usr/library/libdiagSecurityAccess.so
                                        No          /usr/library/libOTAMasterService.so
                                        No          /usr/library/libOTAMasterVehCloudApi.so
                                        No          /usr/library/libotamaster_api_vehicle_info.so
                                        No          /xmiLibrary/usr/lib/libotaapi_shared.so
                                        No          /usr/library/libota_delta.so
                                        No          /xmiLibrary/usr/lib/libHostSecurityLog.so
                                        No          /adaptive/lib/libpthread.so.0
                                        No          /adaptive/usr/lib/libstdc++.so.6
                                        No          /adaptive/lib/libgcc_s.so.1
                                        No          /adaptive/lib/libc.so.6
                                        No          /lib/ld-linux-aarch64.so.1
                                        No          /adaptive/lib/libdl.so.2
                                        No          /usr/library/libvdi_convert.so
                                        No          /xmiLibrary/usr/lib/libdoipequip.so
                                        No          /hostLibrary/lib/libcn_x509_proxy.so
                                        No          /usr/lib/libssl.so.1.1
                                        No          /adaptive/lib/librt.so.1
                                        No          /adaptive/lib/libm.so.6
                                        No          /hostLibrary/lib/libhse_wrapper.so
                                        No          /hostLibrary/lib/libcert.so
                                        No          /hostLibrary/lib/libnddscpp2.so
                                        No          /hostLibrary/lib/libnddsc.so
                                        No          /hostLibrary/lib/libnddscore.so
                                        No          /hostLibrary/lib/librticonnextmsgcpp2.so
                                        No          /xmiLibrary/usr/lib/libdoipcommon.so
                                        No          /adaptive/usr/lib/libz.so.1
                                        No          /hostLibrary/lib/libcn_x509_crypto.so
                                        No          /hostLibrary/lib/libcn_x509_common.so
                                        No          /usr/lib/libhse-libclient.so
                                        No          /xmiLibrary/usr/lib/libPersistencyCommon.so
--Type <RET> for more, q to quit, c to continue without paging--

刚开始,exec file 依赖这些动态库,但是都没有加载到。执行set solib-search-path后。

(gdb) set solib-search-path .
Reading symbols from /home/yihua/coredump/core/libvdi_main.so...
Reading symbols from /home/yihua/coredump/core/libabupFoundation.so...
Reading symbols from /home/yihua/coredump/core/libjson-c.so.5...
Reading symbols from /home/yihua/coredump/core/libota.so...
Reading symbols from /home/yihua/coredump/core/libdiagSecurityAccess.so...
Reading symbols from /home/yihua/coredump/core/libOTAMasterService.so...
(No debugging symbols found in /home/yihua/coredump/core/libOTAMasterService.so)
Reading symbols from /home/yihua/coredump/core/libOTAMasterVehCloudApi.so...
Reading symbols from /home/yihua/coredump/core/libotamaster_api_vehicle_info.so...
Reading symbols from /home/yihua/coredump/core/libota_delta.so...
Reading symbols from /home/yihua/coredump/core/libvdi_convert.so...
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x0000007f9d32cbe0  0x0000007f9d34a87c  Yes         /home/yihua/coredump/core/libvdi_main.so
0x0000007f9c5d2230  0x0000007f9c8154e0  Yes         /home/yihua/coredump/core/libabupFoundation.so
                                        No          /adaptive/usr/lib/libdlt.so.2
0x0000007f9c443b60  0x0000007f9c44c2e4  Yes         /home/yihua/coredump/core/libjson-c.so.5
                                        No          /usr/lib/libcrypto.so.1.1
0x0000007f9c198600  0x0000007f9c199e04  Yes         /home/yihua/coredump/core/libota.so
                                        No          /hostLibrary/lib/libMI_VCCD_MISESDK.so
0x0000007f9c163950  0x0000007f9c1649f0  Yes         /home/yihua/coredump/core/libdiagSecurityAccess.so
0x0000007f9be0db20  0x0000007f9bff69b0  Yes (*)     /home/yihua/coredump/core/libOTAMasterService.so
0x0000007f9b539fc0  0x0000007f9b56132c  Yes         /home/yihua/coredump/core/libOTAMasterVehCloudApi.so
0x0000007f9b5136b0  0x0000007f9b51e568  Yes         /home/yihua/coredump/core/libotamaster_api_vehicle_info.so
                                        No          /xmiLibrary/usr/lib/libotaapi_shared.so
0x0000007f9b477cd0  0x0000007f9b47fbf8  Yes         /home/yihua/coredump/core/libota_delta.so
                                        No          /xmiLibrary/usr/lib/libHostSecurityLog.so
                                        No          /adaptive/lib/libpthread.so.0
                                        No          /adaptive/usr/lib/libstdc++.so.6
                                        No          /adaptive/lib/libgcc_s.so.1
                                        No          /adaptive/lib/libc.so.6
                                        No          /lib/ld-linux-aarch64.so.1
                                        No          /adaptive/lib/libdl.so.2
0x0000007f9b05bd40  0x0000007f9b08c42c  Yes         /home/yihua/coredump/core/libvdi_convert.so

如上,设置动态库寻找路径后,就可以正常加载动态库了。

5. 在进入gdb后,查找段错误位置:where或者bt。

gdb 常用调试命令

        通过上面流程,我们已经能够正式进入gdb调试阶段了。在这里我分享一下,我常用的一些命令。

  • backtrace 与 frame

backtrace 可简写成 bt,用于查看当前所在线程的调用堆栈。如果我们想切换到其他堆栈处,则可以使用frame命令。frame命令可被简写成f,f 堆栈编号

  • info 用于查看一些信息,我经常的搭配是
  • info locals 查看当前栈中的局部变量。
  • info threads 查看当前线程信息。
  • info b 查看当前断点信息。
  • info registers 查看当前寄存器值,比如常见栈顶寄存器,PC寄存器
  • print 打印或修改变量,寄存器的值。
  • x 打印内存值 x /nfu <address>
  • n:是一个正整数,表示显示内存的长度,也就是说从当前地址向后显示几个地址(units)的内容。
  • f: 表示显示的格式(format)

                x (hexadecimal)按十六进制格式显示变量。
                d (signed decimal)按十进制格式显示变量。
                u (unsigned decimal)按十进制格式显示无符号整型。
                o (octal)按八进制格式显示变量。
                t (binary)按二进制格式显示变量。
                a (address)按十六进制格式显示地址,并显示距离前继符号的偏移量(offset)。常用于定位未知地址(变量)。
                c (character)按字符格式显示变量。
                f (floating)按浮点数格式显示变量。

  • u   表示(the unit size)从当前地址往后请求的位宽大小。如果不指定的话,GDB默认是4个bytes。u参数可以用下面的字符来代替,b表示单字节h表示双字节w表示四字 节g表示八字节

例如,打印当前栈顶地址开始,4字节为单位,以16进制输出,共输出16个。即输出栈顶64字节内容。

  • info  proc  mappings 。查看当前进程的maps,即动态库和可执行程序,加载到虚拟地址的maps。在某些场景下,作用非常大。可参考

案例实践

        关于gdb的实际案例分析,可参考我的gdb调试专栏。后续也会持续更新案例。

linux gdb 调试_谢艺华的博客-CSDN博客

技巧

一、 如何修改正在运行的程序的标准输出

场景:有些情况下,我们需要查看一个程序的日志输出,但苦于这个程序并不是我们开发的。默认情况下,该程序的输出默认是到/dev/null中的。如何查看它的输出呢?

  1. 获取正在运行的进程pid。ps -ef | grep MCM_atcop_svr
  2. 运行gdb命令。gdb -p pid
  3. 通过close系统调用关闭标准输出(STDOUT)或者标准错音误(STDERR): call close(1)
  4. 通过create系统调用打开一个文件并将其文件描述符通过dup2系统调用复制给标准输出或者标准错误:call dup2(creat("/tmp/log",0600),1)
  5. 退出调试器:quit

总结

        上述便是本文的分享,如果能给各位看客带来一点帮助,还请三连支持一下。您的支持就是我的动力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/178229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

抖音视频如何无水印下载,怎么批量保存主页所有视频没水印?

现在最火的短视频平台莫过于抖音&#xff0c;当我们刷到一个视频想下载下来怎么办&#xff1f;我们知道可以通过保存到相册的方式下载&#xff0c;但用这种方法下载的视频带有水印&#xff0c;而且有些视频不能保存到相册&#xff08;这是视频作者设置了禁止下载&#xff09;。…

Unity 关于SpriteRenderer 和正交相机缩放

float oldWidth 750f;float oldHeight 1334f;float newWidth Screen.width;float newHeight Screen.height;float oldAspect oldWidth / oldHeight;float newAspect newWidth / newHeight;//水平方向缩放float horizontalCompressionRatio newAspect / oldAspect;//垂直…

IDEA插件推荐

今天给大家推荐一款IDEA插件&#xff1a;Apipost-Helper-2.0&#xff0c;支持三大功能&#xff1a;写完代码IDEA内一键生成API文档&#xff1b;写完代码IDEA内一键调试&#xff1b;生成API目录树&#xff0c;双击即可快速定位API定义的代码…非常好用&#xff01;而且完全免费&…

找免费4K高清图片素材,就上这6个网站

使用图片素材怕侵权&#xff1f;那就上这6个网站&#xff0c;免费下载&#xff0c;4K高清无水印&#xff0c;赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYxMjky 一个很大的素材库&#xff0c;站内主要还是以设计素材为主&#xff0c;像图片素材就有上百…

免费SSL证书服务——加密通信,零成本体验

你的网站是否安全无忧&#xff1f;我们为你提供免费SSL证书服务&#xff0c;让你的用户数据和信息传输更安全可靠。 安全保障&#xff1a; 全面升级你的网站安全性&#xff0c;通过SSL加密技术&#xff0c;确保用户数据传输隐私无忧。 零成本&#xff1a; 免费SSL证书服务&…

【影刀RPA_写入日期到飞书表格】

飞书将日期写入多维表格&#xff0c;日期格式需要时毫秒级的时间戳才行。

常见面试题-Netty中ByteBuf类

了解 Netty 中的 ByteBuf 类吗&#xff1f; 答&#xff1a; 在 Java NIO 编程中&#xff0c;Java 提供了 ByteBuffer 作为字节缓冲区类型&#xff08;缓冲区可以理解为一段内存区域&#xff09;&#xff0c;来表示一个连续的字节序列。 Netty 中并没有使用 Java 的 ByteBuff…

MySQL主从同步延迟原因与解决方案

一、MySQL数据库主从同步延迟产生的原因 MySQL的主从复制都是单线程的操作&#xff0c;主库对所有DDL和DML产生的日志写进binlog&#xff0c;由于binlog是顺序写&#xff0c;所以效率很高。 Slave的SQL Thread线程将主库的DDL和DML操作事件在slave中重放。DML和DDL的IO操作…

08 木谷博客系统RBAC权限设计

这节内容说一下木谷博客系统的权限设计,采用现在主流的权限模型RBAC,对应关系如下: 以上5张表都在mugu_auth_server这个库中 该部分的服务单独定义在user-boot这个模块中。 将角色、权限对应关系加载到Redis 木谷博客系统在认证中心颁发令牌的时候是将用户的角色保存到令牌…

MySQL用得好好的,为何要转ES?

MySQL是一种关系型数据库&#xff0c;它可以高效地存储和查询结构化的数据。 ES是一种分布式搜索引擎&#xff0c;它可以快速地对海量的非结构化或半结构化的数据进行全文检索和分析。 MySQL 和 ES 的数据存储方式也不同。MySQL 中的数据通常是以关系型表的形式存储在磁盘上&…

EOCR-PFZ数码型产品与控制柜主回路的连接方式

上海韩施电气自动化设备有限公司 施耐德EOCR新一代数码型电动机保护器具有体积小、精度高、抗干扰能力强等特点。为方便安装&#xff0c;EOCR数码型产品与控制柜主回路的连接具有多种方式&#xff0c;分别是&#xff1a;窗口型、贯穿性和端子型。 窗口型&#xff08;韩施电气…

vue3中shallowReactive与shallowRef

shallowReactive与shallowRef shallowReactive: 只处理了对象内最外层属性的响应式(也就是浅响应式) shallowRef: 只处理了value的响应式, 不进行对象的reactive处理 总结: reactive与ref实现的是深度响应式, 而shallowReactive与shallowRef是浅响应式。 什么时候用浅响应…

万字解析设计模式之观察者模式、中介者模式、访问者模式

一、观察者模式 1.1概述 观察者模式是一种行为型设计模式&#xff0c;它允许一个对象&#xff08;称为主题或可观察者&#xff09;在其状态发生改变时&#xff0c;通知它的所有依赖对象&#xff08;称为观察者&#xff09;并自动更新它们。这种模式提供了一种松耦合的方式&…

园区智能配电系统(电力智能监控系统)

园区智能配电系统是一种针对园区电力配送和管理的智能化系统。它的主要功能是实时监控设备运行情况&#xff0c;进行电能质量分析&#xff0c;监控电能损耗&#xff0c;以及分时段用电统计等。 具体来说&#xff0c;园区智能配电系统可以利用现代技术如RS-485总线通信、数据库管…

Android Studio 添加so无法打包进apk问题

1.开发环境&#xff1a; Android Studio 2022.3.1 Patch 2 jdk 17 gradle-7.4 2.build.grade配置检查 首先查看build.gradle中是否设置sourceSets &#xff0c;如果设置的话&#xff0c;打包的时候so是被指导libs目录下的&#xff0c;所有就不能把jnilibs下。 sourceSets {mai…

计算机视觉面试题-03

1、简单介绍一下sigmoid&#xff0c;relu&#xff0c;softplus&#xff0c;tanh&#xff0c;RBF及其应用场景 这里简单介绍几个激活函数及其应用场景&#xff1a; Sigmoid 函数&#xff08;Logistic 函数&#xff09;&#xff1a; 公式&#xff1a; s i g m a ( x ) 1 1 e …

2023仿聚合搜索程序源码/轻量级搜狗泛站群程序源码/PHP整站源码+完美SEO优化+符合搜狗算法

源码简介&#xff1a; 2023仿聚合搜索/轻量级搜狗泛站群程序整站源码&#xff0c;作为PHP源码&#xff0c;可以完美SEO优化&#xff0c;符合搜狗搜索引擎算法。 轻量级的PHP搜狗泛站群程序源码&#xff0c;完美SEO优化符合搜狗搜索引擎算法&#xff0c;无需任何采集&#xff…

【Unity细节】为什么加载精灵图集直接导致Unity引擎崩溃

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

Oracle Linux 9.3 发布

导读Oracle Linux 9 系列发布了第 3 个版本更新&#xff0c;支持 64 位 Intel 和 AMD (x86_64) 以及 64 位 Arm (aarch64) 平台。与所有的 Oracle Linux 版本一样&#xff0c;此版本与相应 RHEL 版本 100% 应用二进制兼容。 对于 x86_64 和 aarch64 架构&#xff0c;Oracle Li…

Unity - Graphic解析

Gpahic 的作用 Graphic 是 Unity最基础的图形基类。主要负责UGUI的显示部分。 由上图可以看你出我们经常使用的Image&#xff0c;Text&#xff0c;都是继承自Graphic。 Graphic的渲染流程 在Graphic的源码中有以下属性 [NonSerialized] private CanvasRenderer m_CanvasRend…