• 调试工具记录


    一、运行阶段调试

    1、GDB调试

    1)显示代码:list 1,100list GdbTest.c:1,100
    2)设置断点
    break 文件名 行号,b file.c:33,在文件file.c的33行设置断点
    break 行号,b 44,在当前文件的44行设置断点
    break 函数名,b fun1,在函数的入口设置断点
    break break_args if cond,b fun1 if argc > 1,有cond为true时的断点

    3)打印变量:print 文件名/函数名 变量名,p fun1::a1,如果要打印某个线程的变量,要先切到上下文,见第7点。
    4)监控变量:
    watch 文件名/函数名 变量名,watch fun1::a1
    char *p; watch *p,监控指针p指向的内容,watch p,监控指针p变量本身;
    cha a[16]; watch a,监控a的16个数据
    5)查看线程信息,info thread
    6)查看断点信息,info break
    7)切换线程:thread threadId,如thread 2
    8)运行:run,r
    9)单步运行:next,n
    10)继续运行:continue,c
    11)指定源码路径:dir /mnt/xxx/yyy/zzz/,当执行文件和源码不在同一路径时,gdb查看代码会出现找不到文件,指定源码路径可解决;多个源码路径用“:”分隔;清空源码路径命令:dir
    12)指定加载失败的so的搜索路径:set solib-search-path /var:/home,solib-search-path可以指定多个路径。在linux上,路径之间用冒号分隔
    13)查看源码路径:show dir
    14)查看内存 x/nfu addr
    n是要显示的内存单元个数
    f是显示方式:x16进制、d 10进制、u 6进制无符号、c 字符格式、f 浮点数格式
    u是一种地址的单元长度:b 单字节、h 双字节、w 四字节、g 八字节;
    eg.x/128xw 0xffff1234,从0xffff1234开始以16进制显示128个word
    举例:

    Reading symbols from /data1/hongmiao/work/Code/MyCode/GDB/a.out...done.
    (gdb) l 1,100	#--->显示代码
     1  #include 
     2  #include 
     3  #include 
     4  #include 
     5
     6  int g_val = 0;
     7  void *fun1(void *arg)
     8  {
     9      prctl(PR_SET_NAME, __func__);
    10      int a1 = 0;
    11      while(1)
    12      {
    13          a1++;
    14          printf("---%d, %d\n", a1, g_val);
    15          sleep(1);
    16      }
    17  }
    18
    19  void *fun2(void *arg)
    20  {
    21      prctl(PR_SET_NAME, __func__);
    22      int a2 = 0;
    23      while(1)
    24      {
    25          a2++;
    26                  g_val++;
    27          sleep(5);
    28      }
    29  }
    30
    31  int main(int argc, char *argv[])
    32  {
    33      prctl(PR_SET_NAME, __func__);
    34      int m = 0;
    35      pthread_t th1;
    36      pthread_t th2;
    37      pthread_create(&th1, NULL, fun1, NULL);
    38      pthread_create(&th2, NULL, fun2, NULL);
    39      while(1)
    40      {
    41          m++;
    42          sleep(1);
    43      }
    44      return 0;
    45  }
    (gdb) b 10							#--->设置断点
    Breakpoint 1 at 0x400654: file GdbTest.c, line 10.
    (gdb) r								#--->运行程序
    Starting program: /data1/hongmiao/work/Code/MyCode/GDB/./GdbTest
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    [New Thread 0x7ffff77fe700 (LWP 2990)]
    [Switching to Thread 0x7ffff77fe700 (LWP 2990)]
    
    Breakpoint 1, fun1 (arg=0x0) at GdbTest.c:10
    10          int a1 = 0;
    (gdb) watch g_val					#--->观察变量,继续运行后,变量变化才会在断点停下
    Hardware watchpoint 2: g_val
    (gdb) c								#--->继续运行
    Continuing.
    [New Thread 0x7ffff6ffd700 (LWP 2991)]
    ---1, 0
    [Switching to Thread 0x7ffff6ffd700 (LWP 2991)]
    Hardware watchpoint 2: g_val
    
    Old value = 0
    New value = 1
    fun2 (arg=0x0) at GdbTest.c:27		# 变量变化,停在g_val修改的位置
    27              sleep(5);
    (gdb) c								#--->继续运行
    Continuing.
    ---2, 1
    ---3, 1
    ---4, 1
    ---5, 1
    ---6, 1
    Hardware watchpoint 2: g_val
    
    Old value = 1
    New value = 2
    fun2 (arg=0x0) at GdbTest.c:27		# 变量变化,停在g_val修改的位置
    27              sleep(5);
    (gdb)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    2、top、mpstat、vmstat

    mpstat 可以显示每个处理器的统计,而 vmstat 显示所有处理器的统计,但可以看到内存。

    top - 14:41:26 up 4 days,  5:01, 69 users,  load average: 0.36, 1.06, 1.70
    Tasks: 509 total,   1 running, 498 sleeping,  10 stopped,   0 zombie
    Cpu(s):  0.7%us,  0.6%sy,  0.0%ni, 98.4%id,  0.1%wa,  0.0%hi,  0.3%si,  0.0%st
    Mem:  16434584k total, 15672516k used,   762068k free,   682876k buffers
    Swap:  4192252k total,   686288k used,  3505964k free, 11550948k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
     4327 xxx       20   0 73864  23m  17m S   13  0.1  40:48.02 smbd
     1994 xxx       20   0 71064  20m  17m D    3  0.1  13:39.96 smbd
     3092 xxx       20   0 69580  19m  17m S    2  0.1  37:37.00 smbd
       10 root      20   0     0    0    0 S    0  0.0  12:17.32 ksoftirqd/1
     1172 root      20   0  386m 1388 1044 S    0  0.0   1:04.45 samba
    12911 xxx       20   0 17600 1664  976 R    0  0.0   0:00.02 top
    22338 root      20   0  201m 5796 1388 S    0  0.0   5:19.85 Xorg
        1 root      20   0 24552 2128 1112 S    0  0.0   0:01.10 init
        2 root      20   0     0    0    0 S    0  0.0   0:00.08 kthreadd
        3 root      20   0     0    0    0 S    0  0.0   1:38.59 ksoftirqd/0
    
    tomato-pc:~/work/Code/MyCode/valgrind-pmem-3.19$ mpstat
    Linux 3.5.0-23-generic (Cpl-AVI-General-74-178)         2022年11月19日  _x86_64_        (12 CPU)
    
    14时38分56秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest   %idle
    14时38分56秒  all    2.45    0.00    0.77    0.62    0.00    0.14    0.00    0.00   96.01
    
    tomato-pc:~/work/Code/MyCode/valgrind-pmem-3.19$ vmstat
    procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
     r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
     1  0 686288 795908 668428 11530436    0    0    55   208    1    3  2  1 96  1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3、strace

    Linux下,进程不能直接访问硬件设备。当进程需要访问硬件设备时(读取磁盘文件、接收网络数据等),则必须由用户态切换为内核态,然后通过系统调用来访问硬件设备。strace是跟踪进程执行时的系统调用和所接收的信号(即它跟踪到一个进程产生的系统调用,包括参数、返回值、执行消耗的时间)。strace最简单的用法是执行一个指定的命令(过程中,starce会记录和解析命令进程的所有系统调用及这个进程的所有的信号值),在指定命令结束后立即退出。参考[strace的简单用法]。(https://blog.csdn.net/mijichui2153/article/details/85229307)
    参数:

    • -c 统计每一系统调用的所执行的时间,次数和出错的次数等.
    • -d 输出strace关于标准错误的调试信息.
    • -f 跟踪由fork调用所产生的子进程.
    • -ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
    • -F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
    • -h 输出简要的帮助信息.
    • -i 输出系统调用的入口指针.
    • -q 禁止输出关于脱离的消息.
    • -r 打印出相对时间关于,每一个系统调用.
    • -t 在输出中的每一行前加上时间信息.
    • -tt 在输出中的每一行前加上时间信息,微秒级.
    • -ttt 微秒级输出.
    • -T 显示每一调用所耗的时间.
    • -v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
    • -V 输出strace的版本信息.
    • -x 以十六进制形式输出非标准字符串
    • -xx 所有字符串以十六进制形式输出.
    • -a column 设置返回值的输出位置.默认 为40.
    • -e expr 指定一个表达式,用来控制如何跟踪.格式:[qualifier=][!]value1[,value2]… qualifier只能是trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的qualifier是 trace.感叹号是否定符号.例如:-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open 表示跟踪除了open以外的其他调用.有两个特殊的符号 all和none. 注意有些shell使用!来执行历史记录里的命令,所以要使用\.
    • -e trace=set 只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
    • -e trace=file 只跟踪有关文件操作的系统调用.
    • -e trace=process 只跟踪有关进程控制的系统调用.
    • -e trace=network 跟踪与网络有关的所有系统调用.
    • -e strace=signal 跟踪所有与系统信号有关的系统调用.
    • -e trace=ipc 跟踪所有与进程通讯有关的系统调用.
    • -e abbrev=set 设定strace输出的系统调用的结果集.-v 等于abbrev=none.默认为abbrev=all.
    • -e raw=set 将指定的系统调用的参数以十六进制显示.
    • -e signal=set 指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
    • -e read=set 输出从指定文件中读出 的数据.例如: -e read=3,5 -e write=set 输出写入到指定文件中的数据.
    • -o filename 将strace的输出写入文件filename
    • -p pid 跟踪指定的进程pid.
    • -s strsize 指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
    • -u username 以username的UID和GID执行被跟踪的命令

    4、coredump

    coredump是指当程序出错而异常中断时,OS会把程序工作的当前状态存储成一个coredunmp文件。
    通常情况下coredump文件包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息等。

    • ulimit -a 查看core文件生成是否开启
    • ulimit -c 0 关闭core文件生成
    • ulimit -c 4096 打开core文件生成,大小限制4096blocks,一般1block=512bytes
    • ulimit -c unlimited 打开core文件生成且不限制大小
    • echo “/data/coredump/core” > /proc/sys/kernel/core_pattern 更改coredump文件的存储位置为/data/coredump/core
    • echo “/data/coredump/core.%e.%p.%t” > /proc/sys/kernel/core_pattern 指定内核所生成的coredump文件的文件名,产生的core文件中将带有崩溃的程序名、以及它的进程ID,上面的%e和%p会被替换成程序文件名、进程ID和时间。
    • echo 1 > /proc/sys/kernel/core_uses_pid 如果这个文件的内容被配置成1,那么即使core_pattern中没有设置%p,最后生成的core dump文件名仍会加上进程ID。
    • gdb ./main ./coredump 使用GDB调试coredump

    5、 valgrind

    Valgrind是一款用于内存调试、内存泄漏检测以及性能分析、检测线程错误的软件开发工具。主要包括Memcheck、Callgrind、Cachegrind 等工具,每个工具都能完成一项任务调试、检测或分析。可以检测内存泄露、线程违例和Cache 的使用等。在Valgrind下运行的程序运行速度要慢得多,而且使用的内存要多得多。例如,Memcheck工具下的程序是正常情况的两倍多。因此,最好在性能好的机器上使用Valgrind。参考valgrind简介与使用
    例子:

    tomato-pc:~/work/Code/MyCode/GDB$ cat valgrindTest.c -n
         1  #include 
         2
         3  int main()
         4  {
         5      int x = 10;
         6      int y = 0;
         7      char a[10] = {0};
         8      a[10]=1;//栈内存越界
         9      char *b = malloc(10);
        10      b[10]=1;//栈内存越界
        11      memset(b, 0, 11);//栈内存越界
        12      while(1);
        13      return 0;
        14  }
        15
    tomato-pc:~/work/Code/MyCode/GDB$ valgrind ./valgrindTest
    ==4743== Memcheck, a memory error detector
    ==4743== Copyright (C) 2002-2015, and GNU GPL''d, by Julian Seward et al.
    ==4743== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
    ==4743== Command: ./valgrindTest
    ==4743==
    ==4743== Invalid write of size 1
    ==4743==    at 0x400541: main (valgrindTest.c:10)
    ==4743==  Address 0x51f404a is 0 bytes after a block of size 10 alloc''d
    ==4743==    at 0x4C2D027: malloc (vg_replace_malloc.c:299)
    ==4743==    by 0x400534: main (valgrindTest.c:9)
    ==4743==
    ==4743== Invalid write of size 1
    ==4743==    at 0x400555: main (valgrindTest.c:11)
    ==4743==  Address 0x51f404a is 0 bytes after a block of size 10 alloc'd
    ==4743==    at 0x4C2D027: malloc (vg_replace_malloc.c:299)
    ==4743==    by 0x400534: main (valgrindTest.c:9)
    ==4743==
    ==4743==
    ==4743== Process terminating with default action of signal 2 (SIGINT)
    ==4743==    at 0x400559: main (valgrindTest.c:12)
    ==4743==
    ==4743== HEAP SUMMARY:
    ==4743==     in use at exit: 10 bytes in 1 blocks
    ==4743==   total heap usage: 1 allocs, 0 frees, 10 bytes allocated
    ==4743==
    ==4743== LEAK SUMMARY:
    ==4743==    definitely lost: 0 bytes in 0 blocks
    ==4743==    indirectly lost: 0 bytes in 0 blocks
    ==4743==      possibly lost: 0 bytes in 0 blocks
    ==4743==    still reachable: 10 bytes in 1 blocks
    ==4743==         suppressed: 0 bytes in 0 blocks
    ==4743== Rerun with --leak-check=full to see details of leaked memory
    ==4743==
    ==4743== For counts of detected and suppressed errors, rerun with: -v
    ==4743== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    6、mtrace

    mtrace(memory trace),是 GNU Glibc 自带的内存问题检测工具,它可以用来协助定位内存泄露问题。它的实现源码在glibc源码的malloc目录下,其基本设计原理为设计一个函数 void mtrace (),函数对 libc 库中的 malloc/free 等函数的调用进行追踪,由此来检测内存是否存在泄漏的情况。
    在使用之前,需要修改我们的源码,用来跟踪内存分配和释放,其中需要使用两个函数

    #include 
    /* 开启内存分配跟踪 */
    void mtrace(void);
    /* 取消内存分配跟踪 */
    void muntrace(void);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    mtrace() 函数中会为那些和动态内存分配有关的函数(譬如 malloc()、realloc()、memalign() 以及 free())安装 “钩子(hook)” 函数,这些 hook 函数会为我们记录所有有关内存分配和释放的跟踪信息,而 muntrace() 则会卸载相应的 hook 函数。基于这些 hook 函数生成的调试跟踪信息,我们就可以分析是否存在 “内存泄露” 这类问题了。
    例子:

    tomato-pc:~/work/Code/MyCode/GDB$ export MALLOC_TRACE=./test.log
    tomato-pc:~/work/Code/MyCode/GDB$ cat -n mtraceTest.c
         1  #include 
         2  #include 
         3
         4  int main()
         5  {
         6          mtrace();
         7          setenv("MALLOC_TRACE", "/data1/hongmiao/work/Code/MyCode/GDB/mem.txt", 1);//实际没有生效
         8          system("export MALLOC_TRACE=./test.log");
         9          int x = 10;
        10          int y = 0;
        11          char a[10] = {0};
        12          a[10]=1;
        13          char *b = malloc(10);
        14          b[10]=1;
        15          memset(b, 0, 11);
        16          muntrace();
        17          //while(1);
        18          return 0;
        19  }
        20
    tomato-pc:~/work/Code/MyCode/GDB$ gcc -g -o mtraceTest mtraceTest.c
    mtraceTest.c: 在函数‘main’中:
    mtraceTest.c:13:12: 警告: 隐式声明与内建函数‘malloc’不兼容 [默认启用]
    mtraceTest.c:15:2: 警告: 隐式声明与内建函数‘memset’不兼容 [默认启用]
    tomato-pc:~/work/Code/MyCode/GDB$ ./mtraceTest
    tomato-pc:~/work/Code/MyCode/GDB$ ls
    addr2lineTest  addr2lineTest.c  a.out  core  corefile  GdbTest.c  mtraceTest  mtraceTest.c  test.log  valgrindTest  valgrindTest.c
    tomato-pc:~/work/Code/MyCode/GDB$ cat test.log
    = Start
    @ /lib/x86_64-linux-gnu/libc.so.6:[0x7f0dffe04099] + 0x2477460 0x3a
    @ /lib/x86_64-linux-gnu/libc.so.6:(tsearch+0xbb)[0x7f0dffeb94bb] + 0x24774b0 0x20
    @ ./mtraceTest:[0x4006a3] + 0x24774e0 0xa
    = End
    tomato-pc:~/work/Code/MyCode/GDB$ addr2line -e ./mtraceTest 0x4006a3
    /data1/hongmiao/work/Code/MyCode/GDB/mtraceTest.c:13
    tomato-pc:~/work/Code/MyCode/GDB$
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    解读:
    export MALLOC_TRACE=./test.log设置生成日志文件的路径。
    ./mtraceTest指的是我们执行的程序名字,[0x4006a3] 是第一次调用 malloc 函数机器码中的地址信息,+ 表示申请内存( - 表示释放),0x24774e0 是 malloc 函数申请到的地址信息,0xa 表示的是申请的内存大小。由此分析第一次申请已经释放,第二次申请没有释放,存在内存泄漏的问题。

    7、dump_stack函数

    要知道某个函数由谁调用,比较困难。可以通过内核提供的接口dump_stack()来跟踪,回溯打印调用栈信息。当内核发生panic时候,也会主动调用该接口,所以我们可以在调试过程中主动调用该接口来进行测试。

    8、dladdr函数

    获取某个地址的符号信息概要。

    9、SP、LR、PC寄存器

    FP:帧指针r11
    IP:内部暂用寄存器r12
    SP:堆栈指针r13,指向栈当前的位置。
    LR:连接寄存器r14,保存函数返回的地址,当异常发生时,异常模式的r14用来保存异常返回地址。
    PC:程序计数器r15

    二、编译阶段调试

    1、addr2line根据地址查找代码行

    参数:

    • -a --addresses:在函数名、文件和行号信息之前,显示地址,以十六进制形式。
    • -b --target=:指定目标文件的格式为bfdname。
    • -e --exe=:指定需要转换地址的可执行文件名。
    • -i --inlines : 如果需要转换的地址是一个内联函数,则输出的信息包括其最近范围内的一个非内联函数的信息。
    • -j --section=:给出的地址代表指定section的偏移,而非绝对地址。
    • -p --pretty-print:使得该函数的输出信息更加人性化:每一个地址的信息占一行。
    • -s --basenames:仅仅显示每个文件名的基址(即不显示文件的具体路径,只显示文件名)。
    • -f --functions:在显示文件名、行号输出信息的同时显示函数名信息。
    • -C --demangle[=style]:将低级别的符号名解码为用户级别的名字。
    • -h --help:输出帮助信息。
    • -v --version:输出版本号。

    如果没有coredump,可以通过dmesg查看出错时的内核日志,然后通过addr2line将地址转换成出错程序的位置,如:addr2line -e addr2lineTest 000000000040052d
    例子:

    tomato@pc:~/work/Code/MyCode/GDB$ cat -n addr2lineTest.c
       1  #include 
       2
       3  int func(int a, int b)
       4  {
       5  	return a / b;
       6  }
       7
       8  int main()
       9  {
      10		int x = 10;
      11      int y = 0;
      12      char *p = NULL;
      13      memset(p, 0, 4); //空指针错误
      14      printf("%d / %d = %d\n", x, y, func(x, y));//除0错误
      15      return 0;
      16  }
      17
    tomato@pc:~/work/Code/MyCode/GDB$ gcc -g -o addr2lineTest addr2lineTest.c
    addr2lineTest.c: 在函数‘main’中:
    addr2lineTest.c:13:4: 警告: 隐式声明与内建函数‘memset’不兼容 [默认启用]
    tomato@pc:~/work/Code/MyCode/GDB$ ./addr2lineTest
    段错误 (核心已转储)
    tomato@pc:~/work/Code/MyCode/GDB$ dmesg | tail -1
    [125201.960808] addr2lineTest[2739]: segfault at 0 ip 000000000040052d sp 00007fff0b5d9370 error 6 in addr2lineTest[400000+1000]
    tomato@pc:~/work/Code/MyCode/GDB$
    tomato@pc:~/work/Code/MyCode/GDB$ addr2line -e addr2lineTest 000000000040052d
    /data1/hongmiao/work/Code/MyCode/GDB/addr2lineTest.c:13
    tomato@pc:~/work/Code/MyCode/GDB$
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    2、其他

    1)nm:linux下自带的特定文件分析工具,一般用来检查分析二进制文件、库文件、可执行文件中的符号表,返回二进制文件中各段的信息。
    2)readelf:一般用于查看ELF格式的文件信息,常见的文件如在Linux上的可执行文件,动态库(.so)或者静态库(.a) 等包含ELF格式的文件。
    3)objdump:用来查看编译后目标文件的组成

  • 相关阅读:
    一个bug引发的对大端小端的深入思考
    项目篇——java文档搜索引擎
    有趣的数学 积分符号∫ (integration)简述
    uniapp 常见的问题以及解决办法
    [lca][思维]Ancestor 2022牛客多校第3场 A
    leetcode 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
    13.从架构设计角度分析AAC源码-Room源码解析第2篇:RoomCompilerProcessing源码解析
    LeetCode 周赛 341 场,模拟 / 树上差分 / Tarjan 离线 LCA / DFS
    1149 Dangerous Goods Packaging
    浅谈JVM(面试常考)
  • 原文地址:https://blog.csdn.net/SanShuiGeGe/article/details/127882103