zoukankan      html  css  js  c++  java
  • 【应用】Linux内存调试工具:gdb+gdbserver

    一、测试环境:

    运行环境:server: arm64 linux-4.14(开发板)

         host: x86_64 ubuntu-20.04(主机)

    工具版本:gdb-10.1

    二、工具自我介绍:

    看看官方怎么说,

    GDB, the GNU Project debugger, allows you to see what is going on `inside' another program while it executes -- or what another program was doing at the moment it crashed.

    GDB can do four main kinds of things (plus other things in support of these) to help you catch bugs in the act:

    • Start your program, specifying anything that might affect its behavior.
    • Make your program stop on specified conditions.
    • Examine what has happened, when your program has stopped.
    • Change things in your program, so you can experiment with correcting the effects of one bug and go on to learn about another.

    Those programs might be executing on the same machine as GDB (native), on another machine (remote), or on a simulator. GDB can run on most popular UNIX and Microsoft Windows variants, as well as on Mac OS X.

    gdb 工具可谓是应用开发过程中最常用的伙伴了,解决执行崩溃问题那是手到擒来。可以用它来分析程序崩溃后产生的 coredump 文件,找出崩溃的原因;也可以用它来单步调试程序,详细的分析程序运行过程中的第一个元素的变化。

    coredump 方式相对来说比较简单,我一般的做就是:

    1)配置 coredump 相关,如大小、附加 pid、生成名称路径等

    ulimit -c unlimited
    echo "1" > /proc/sys/kernel/core_uses_pid
    echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

    2)配置库路径、查看栈回溯、查看反汇编等

    set solib-search-path
    info sharedlibrary
    bt
    disassemble
    objdump –S

    本篇还是以 gdbserver 为主,演示一下如何在主机上远程调试开发板上的程序。

    三、工具下载与编译安装:

    1. 下载

    进入官网即可通过 http 或 ftp 即可下载最新版工具。

    2. 编译

     ./configure --prefix=/tools/gdb/tmp/ CC=aarch64-linux-gnu-gcc --host=aarch64-linux-gnu LDFLAGS=-static 

     make -j24 

    尝试进行静态链接,这样的话 server 端就可以尽情的在远程运行,不依赖任何的库。

    但结果不尽人意,链接时会有类似这样的提示: warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking ,大概意思是说,getpwuid 是在一个动态库里,你想静态链接这个程序是可以,但你在运行的时候要给它提供这个动态库。

    关于这个问题,我找到一些讨论,这是一个比较有说服力的:

    glibc uses libnss to support a number of different providers for address resolution services. Unfortunately, you cannot statically link libnss, as exactly what providers it loads depends on the local system's configuration.

    然而这里可能大家可能有一个疑问,难道运行环境中没有这个动态库,程序就不能正常运行了?这个问题我们暂留到实验后讨论。

    3. 安装

     make install 

    一条命令,将可执行程序等安装至预设的路径,查看下成果物,

    root : /tools/gdb# ls tmp/bin/
    gcore  gdb  gdb-add-index  gdbserver  run

    可以,齐全了,将 gdbserver 拷贝至开发板端,开始测试。

    四、实际调试

    准备一个例程,就使用上面那个 API 吧,,

     1 #include <sys/types.h>
     2 #include <stdio.h>
     3 #include <pwd.h>
     4 
     5 int main()
     6 {
     7     struct passwd *info = NULL;
     8 
     9     info = getpwuid(getuid());
    10     printf("Name: %s
    ", info->pw_name);
    11 
    12     return 0;
    13 }

    在主机上运行一下,得到如下输出:

    Name: root

    OK,程序正常,交叉编译静态链接再传到开发板运行,结果:

    / # ./getname
    Segmentation fault

    What ?,别急有 gdb,让我们来挣扎一下,用 gdb 分析下崩溃的原因,注意主机侧的程序编译时要加 -g 参数,以打入调试信息。

    开发板端启动 gdbserver: ./gdbserver 10.25.206.228:1233 ./getname 

    主机侧进行连接并调试: aarch64-linux-gnu-gdb getname 

    在 main 处设个断点,单步运行,查看是不是 api 未定义或者是返回值是否为空,

    (gdb) b main
    Breakpoint 1 at 0x400b48: file test.c, line 7.
    (gdb) c
    Continuing.
    
    Breakpoint 1, main () at test.c:7
    7               struct passwd *info = NULL;
    (gdb) n
    9               info = getpwuid(getuid());
    (gdb) n
    10              printf("Name: %s
    ", info->pw_name);
    (gdb) p info
    $1 = (struct passwd *) 0x0

    哇,果然,getpwuid 返回了空指针,猜想一下应该是我的文件系统中没有登入用户导致的:

    / # whoami
    whoami: unknown uid 0

    到这里就用 gdb 完成了一次小型崩溃现场调试。

    其实实验结束后也得出了上面那个猜想的结论,我在交叉编译时所用的命令是: aarch64-linux-gnu-gcc -static -g -o getname test.c ,编译器提示:

    /tmp/ccCucfXo.o: In function `main':
    /tools/gdb/test.c:9: warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking

    而且开发板的运行环境中也并没有 nss 相关的动态库:

    / # find /lib -name "*nss*"
    / # find /usr/lib -name "*nss*"

    这一点是不是可以证明,虽然静态链接时有那个警告,但在实际的运行过程中不会去依赖相关的动态库了?其实不然,关于这个问题我深入到 glibc 简单的了解了一下流程,具体见下一篇

    简单使用和疑问解决到这里告一段落,后续深入再补充。

    文末福利:GDB命令大全

  • 相关阅读:
    联合索引和多个单列索引选择
    CentOS6.5 一台服务器同时安装多个Mysql数据库
    一次CentOS的服务器被攻击教训
    java版本的memcache静态化
    mysql存储空间满的处理方式
    MariaDB 10.0 和 MariaDB 10.1 存储过程中 PREPARE FROM EXECUTE 区别
    CentOS6.x 优化脚本
    Mysql 使用 “LOAD DATA INFILE”需要注意的问题
    Mysql 日期类型比较 TIMESTAMPDIFF
    CentOS6.x 源码安装Nginx
  • 原文地址:https://www.cnblogs.com/GyForever1004/p/13934272.html
Copyright © 2011-2022 走看看