release版本core推导与相应工具学习(待更新)


一般进行开发工作时,会有debug版本和release版本之分,debug版本方便调试,但与release版本相比,体积臃肿,运行速度慢。一般debug版本会带有符号表与调试信息,而release版本会把符号表和调试信息等strip掉。这时候,如果release版本出现core,而又不具备在debug版本复现的条件,就需要直接在release版本定位,由于没有符号表与调试信息,定位起来会比较麻烦。
先补充一下基础知识,涉及以下几个方面:
1.常用命令
2.obj文件与可执行文件段结构
3.进程内存映像
4.符号表与调试信息
5.gdb命令

一、常用命令

以下介绍的命令都是gnu binutils套件的一部分,手册地址链接。包含工具的概览如下:

命令用处
ar创建、修改和提取存档
nm列出对象文件中的符号
objcopy复制和翻译对象文件
objdump显示对象文件中的信息
ranlib生成索引以存档内容
size列出节大小和总大小
strings列出文件中的可打印字符串
strip丢弃符号
c++filt用于对编码C++符号进行反处理的筛选器,其实就是反编译
cxxfiltMS-DOS name for c++filt
addr2line将地址转换为文件和行
windmcWindows 消息资源的生成器
windres操作Windows 资源
dlltool创建生成和使用 DLL 所需的文件
readelf显示 ELF 格式文件的内容
elfedit更新 ELF 文件的 ELF 标头和属性

1.ar

ar - create, modify, and extract from archives

ar命令最常见的用法是将目标文件打包为静态链接库。

指令参数:

-d 删除备存文件中的成员文件。
-r 将文件插入备存文件中。
-t 显示备存文件中所包含的文件。
-x 自备存文件中取出成员文件。

选项参数:

c 建立备存文件。
v 程序执行时显示详细的信息。

使用实例:
1.创建静态库

$ ar -crv libmakefile_test.a cli.o lib.o resource.o
r - cli.o
r - lib.o
r - resource.o

2.使用静态库编译

$ gcc -o app_test_static  ./app/main.c -I ./include -L ./ -lmakefile_test -static
$ gcc -o app_test_dynamic ./app/main.c -I ./include -L ./ -lmakefile_test

-I选项指定头文件搜索路径
-L选项指定库文件搜索路径
-l选项指明需要链接库文件路径下的哪一个库
-static 在支持动态链接的系统,这个参数将覆盖-pie选项并且防止链接到共享库。在其他系统,这个参数无用。
查看编译的文件:

$ file app_test_static
app_test_static: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=2f7ba0b5feb0bee3acd3113608215c8b3fa25c43, for GNU/Linux 3.2.0, not stripped
$ file app_test_dynamic
app_test_dynamic: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=b8f4aae218ee51b8559f737609d156d4dccd111c, for GNU/Linux 3.2.0, not stripped

关于静态库和动态库编译及使用,可查看这篇文章

2.nm

nm - list symbols from object files

常用参数:
-A: 在输出时每行前加上文件名;
-a: 输出所有符号,包含debugger-only symbols;
-B: BSD码显示,兼容MIPS nm;
-C: 将低级符号名解析为用户级名字,可以使得C++函数名更具可读性;
-D: 显示动态符号。该选项只对动态目标(如特定类型的共享库)有意义;
-f format/–format=format 使用format格式输出。format可以选取bsd、sysv或posix,该选项在GNU的nm中有用。默认为bsd
-g: 只显示外部符号;
-l: 对于每个符号,使用debug信息找到文件名和行号;
-n: 按符号对应地址的顺序排序,而非按符号名字字符顺序排序;
-P: 按照POSIX2.0标准格式输出,等同于使用 -f posix;
-p: 按照目标文件中遇到的符号顺序显示,不排序;
-r: 反转排序;
-s: 当列出库成员符号时,包含索引。索引的内容:模块和其包含名字的映射;
-u: 只显示未定义符号;
–defined-only: 只显示定义了的符号。

$ cat app/main.c
#include<stdio.h>
#include"../include/cli.h"
#include"../include/lib.h"
#include"../include/resource.h"

int main()
{
    installcmd();
    openlib();
    initresource();
    return 0;
}
$ nm -n main.o
                 U _GLOBAL_OFFSET_TABLE_
                 U initresource
                 U installcmd
                 U openlib
0000000000000000 T main

3.objcopy

objcopy - copy and translate object files
常用参数:
–set-start val
设定新文件的起始地址为val,并不是所有格式的目标文件都支持设置起始地址。

–change-start incr
–adjust-start incr
通过增加incr量来调整起始地址,并不是所有格式的目标文件都支持设置起始地址。

–change-address incr
–adjust-vma incr
通过增加incr量调整所有sections的VMA(virtual memory address)和LMA(linear memory address),以及起始地址。

–only-keep-debug
对文件进行strip,移走所有不会被–strip-debug移走的section,并且保持调试相关的section原封不动。

$ objcopy --only-keep-debug a.out a.out.dbg
$ ls
a.out  a.out.dbg  test.c

4.objdump

objdump - display information from object files
常用参数:
-a :显示档案库的成员信息,类似ls -l将lib*.a的信息列出。
-C :将底层的符号名解码成用户级名字,除了去掉所开头的下划线之外,还使得C++函数名以可理解的方式显示出来。
-g :显示调试信息。企图解析保存在文件中的调试信息并以C语言的语法显示出来。仅仅支持某些类型的调试信息。有些其他的格式被readelf -w支持。
-e :类似-g选项,但是生成的信息是和ctags工具相兼容的格式。
-d :从objfile中反汇编那些特定指令机器码的section。可用于查看对应汇编的行号。
-D :与 -d 类似,但反汇编所有section.
–endian={big|little} :指定目标文件的大小端。这个项将影响反汇编出来的指令。在反汇编的文件没描述小端信息的时候用。例如S-records.
-f :显示objfile中每个文件的整体头部摘要信息。
-h :显示目标文件各个section的头部摘要信息。
-i :显示对于 -b 或者 -m 选项可用的架构和目标格式列表。
-I, --include=DIR 将指定文件夹添加到源文件搜索列表
-j name:仅仅显示指定名称为name的section的信息
-l:用文件名和行号标注相应的目标代码,仅仅和-d、-D或者-r一起使用使用-ld和使用-d的区别不是很大,在源码级调试的时候有用,要求编译时使用了-g之类的调试编译选项。
-m machine :指定反汇编目标文件时使用的架构,当待反汇编文件本身没描述架构信息的时候(比如S-records),这个选项很有用。可以用-i选项列出这里能够指定的架构.
-r :显示文件的重定位入口。如果和-d或者-D一起使用,重定位部分以反汇编后的格式显示出来。
-R :显示文件的动态重定位入口,仅仅对于动态目标文件意义,比如某些共享库。
-s :显示指定section的完整内容。默认所有的非空section都会被显示。
-S :尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
–show-raw-insn :反汇编的时候,显示每条汇编指令对应的机器码,如不指定–prefix-addresses,这将是缺省选项。
–no-show-raw-insn :反汇编时,不显示汇编指令的机器码,如指定–prefix-addresses,这将是缺省选项。
–start-address=address :从指定地址开始显示数据,该选项影响-d、-r和-s选项的输出。
–stop-address=address :显示数据直到指定地址为止,该项影响-d、-r和-s选项的输出。
-t :显示文件的符号表入口。类似于nm -s提供的信息
-T :显示文件的动态符号表入口,仅仅对动态目标文件意义,比如某些共享库。它显示的信息类似于 nm -D|–dynamic 显示的信息。
-x :显示所可用的头信息,包括符号表、重定位入口。-x 等价于-a -f -h -r -t 同时指定。
-z :一般反汇编输出将省略大块的零,该选项使得这些零块也被反汇编。
@file 可以将选项集中到一个文件中,然后使用这个@file将选项载入。

5.strip

strip - discard symbols and other data from object files
常用参数:
-s:去除所有符号表
-g:只去除debug符号表
-o:将strip的内容存储到另外的指定文件

$ strip a.out -o a_strip.out
$ ls
a.out  a.out.dbg  a_strip.out  test.c

6.addr2line

addr2line - convert addresses into file names and line numbers
常用参数:
-a:在函数名、文件名和行号信息之前,以十六进制形式显示地址。
-C:将低级别的符号名解码为用户级别的名字。
-e:指定需要转换地址的可执行文件名,默认文件是a.out。
-f:在显示文件名、行号信息的同时显示函数名。
-s:仅显示每个文件名(the base of each file name)去除目录名。
-i:如果需要转换的地址是一个内联函数,则还将打印返回第一个非内联函数的信息。
-j:读取指定section的偏移而不是绝对地址。
-p:使打印更加人性化:每个地址(location)的信息都打印在一行上。
-r:启用或禁用递归量限制。
编译进程如下,执行后段错误:

int main()
{
	int *p = NULL;
	*p=0;
	printf("hello world!\n");
}

dmesg信息如下:

[ 2022.242578] a.out[6050]: segfault at 0 ip 0000558c30b8f161 sp 00007ffd40f0e6f0 error 6 in a.out[558c30b8f000+1000]
[ 2022.242606] Code: 00 c3 0f 1f 80 00 00 00 00 f3 0f 1e fa e9 77 ff ff ff f3 0f 1e fa 55 48 89 e5 48 83 ec 10 48 c7 45 f8 00 00 00 00 48 8b 45 f8 <c7> 00 00 00 00 00 48 8d 3d 96 0e 00 00 e8 dd fe ff ff b8 00 00 00
[ 2022.242619] potentially unexpected fatal signal 11.

0000558c30b8f161 - 558c30b8f000 = 0x161

7.readelf

-a 显示全部信息,等价于 -h -l -S -s -r -d -V -A -I.
-h 显示elf文件开始的文件头信息.
-l - 显示程序头(段头)信息(如果有的话)。
-S 显示节头信息(如果有的话)。
-g 显示节组信息(如果有的话)。
-t 显示节的详细信息(-S的)。
-s 显示符号表段中的项(如果有的话)。
-e 显示全部头信息,等价于: -h -l -S -n --notes 显示note段(内核注释)的信息。
-r 显示可重定位段的信息。
-u 显示unwind段信息。当前只支持IA64 ELF的unwind段信息。
-d 显示动态段的信息。 .dynamic段
-V 显示版本段的信息。
-A 显示CPU构架信息。
-D 使用动态段中的符号表显示符号,而不是使用符号段。
-x 以16进制方式显示指定段内内容。number指定段表中段的索引,或字符串指定文件中的段名。
-w[liaprmfFsoR] or --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges] 显示调试段中指定的内容。
-I 显示符号的时候,显示bucket list长度的柱状图。
-W 宽行输出。
@file 可以将选项集中到一个文件中,然后使用这个@file选项载入。

二、obj文件与可执行文件段结构

linux下的obj文件和可执行文件都是elf格式,其结构如下:

ELF头部(ELF Header):ELF头部是ELF文件的第一个部分,包含了文件类型、机器类型、入口地址、程序头表偏移量、节头表偏移量等信息。

程序头表(Program Header Table):程序头表描述了可执行文件或共享库的段信息,包括段类型、段的虚拟地址、文件偏移量、段大小等信息。

节头表(Section Header Table):节头表描述了ELF文件中的所有节,包括代码段、数据段、符号表、重定位表等。每个节头表项包含了节的名称、类型、大小、偏移量等信息。

节区(Section):ELF文件的数据被组织成许多节,每个节都有一个唯一的名称和类型。常见的节区包括.text(代码段)、.data(数据段)、.bss(未初始化的数据段)等。

符号表(Symbol Table):符号表包含了ELF文件中的所有符号信息,包括函数名、变量名、常量等。每个符号表项包含了符号的名称、类型、值、大小等信息。

字符串表(String Table):字符串表包含了ELF文件中使用的所有字符串,包括节名、符号名、库名等。

重定位表(Relocation Table):重定位表包含了ELF文件中的所有重定位信息,用于修正代码和数据的地址。每个重定位表项包含了需要修正的地址、修正方式等信息。

三、进程内存映像

调试core时加载带调试信息so时需要加地址的原因:

参见《深入理解计算机系统笔记–备忘》:代码段与数据段之间有空隙(为了对齐要求),而栈,共享模块,堆由于安全性还会使用地址空间布局随机化,每次程序运行时,他们的地址都会改变。

core中info proc mappings得到地址为当时动态库加载的地址,而add-symbol-file需要指定文件的text段地址,因此我们的目标是调试时加载的地址就是当时动态库.text段的地址,debug信息也要加载在这。

四、符号表与调试信息

符号表包含.dynsym节和.symtab节
.dynsym保存了引用来自外部文件符号的全局符号。如printf库函数。.dynsym保存的符号是.symtab所保存符合的子集,.symtab中还保存了可执行文件的本地符号。如全局变量,代码中定义的本地函数等。
.dynsym对于动态链接可执行文件的执行是必需的,而.symtab只是用来进行调试和链接的。

Symbol table '.dynsym' contains 7 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND _[...]@GLIBC_2.34 (2)
     2: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
     3: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5 (3)
     4: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     5: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
     6: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND [...]@GLIBC_2.2.5 (3)

Symbol table '.symtab' contains 36 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS Scrt1.o
     2: 000000000000038c    32 OBJECT  LOCAL  DEFAULT    4 __abi_tag
     3: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
     4: 0000000000001090     0 FUNC    LOCAL  DEFAULT   16 deregister_tm_clones
     5: 00000000000010c0     0 FUNC    LOCAL  DEFAULT   16 register_tm_clones
     6: 0000000000001100     0 FUNC    LOCAL  DEFAULT   16 __do_global_dtors_aux
     7: 0000000000004010     1 OBJECT  LOCAL  DEFAULT   26 completed.0
     8: 0000000000003dc0     0 OBJECT  LOCAL  DEFAULT   22 __do_global_dtor[...]
     9: 0000000000001140     0 FUNC    LOCAL  DEFAULT   16 frame_dummy
    10: 0000000000003db8     0 OBJECT  LOCAL  DEFAULT   21 __frame_dummy_in[...]
    11: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c
    12: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    13: 00000000000020f0     0 OBJECT  LOCAL  DEFAULT   20 __FRAME_END__
    14: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS
    15: 0000000000003dc8     0 OBJECT  LOCAL  DEFAULT   23 _DYNAMIC
    16: 0000000000002014     0 NOTYPE  LOCAL  DEFAULT   19 __GNU_EH_FRAME_HDR
    17: 0000000000003fb8     0 OBJECT  LOCAL  DEFAULT   24 _GLOBAL_OFFSET_TABLE_
    18: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_mai[...]
    19: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
    20: 0000000000004000     0 NOTYPE  WEAK   DEFAULT   25 data_start
    21: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.2.5
    22: 0000000000004010     0 NOTYPE  GLOBAL DEFAULT   25 _edata
    23: 0000000000001168     0 FUNC    GLOBAL HIDDEN    17 _fini
    24: 0000000000004000     0 NOTYPE  GLOBAL DEFAULT   25 __data_start
    25: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    26: 0000000000004008     0 OBJECT  GLOBAL HIDDEN    25 __dso_handle
    27: 0000000000002000     4 OBJECT  GLOBAL DEFAULT   18 _IO_stdin_used
    28: 0000000000004018     0 NOTYPE  GLOBAL DEFAULT   26 _end
    29: 0000000000001060    38 FUNC    GLOBAL DEFAULT   16 _start
    30: 0000000000004010     0 NOTYPE  GLOBAL DEFAULT   26 __bss_start
    31: 0000000000001149    30 FUNC    GLOBAL DEFAULT   16 main
    32: 0000000000004010     0 OBJECT  GLOBAL HIDDEN    25 __TMC_END__
    33: 0000000000000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
    34: 0000000000000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@G[...]
    35: 0000000000001000     0 FUNC    GLOBAL HIDDEN    12 _init

Linux进程的调试信息包含在ELF文件中的多个段中,这些段通常以.debug开头,例如:

.debug_info:包含了程序的调试信息,例如类型定义、变量定义、函数定义等。
.debug_line:包含了程序的源代码行号信息,用于在调试器中显示源代码。
.debug_str:包含了程序中使用的所有字符串,例如变量名、函数名等。
.debug_abbrev:包含了调试信息的缩写表,用于压缩调试信息。
.debug_loc:包含了程序中局部变量的地址信息,用于在调试器中显示局部变量的值。
.debug_ranges:包含了程序中全局变量和静态变量的地址范围信息,用于在调试器中显示变量的值。

五、GLibc版本查看

有时排查问题需要明确c库的版本,方法列举如下:

ldd --version
strings /lib/x86_64-linux-gnu/libc.so.6 | grep GLIBC
getconf GNU_LIBC_VERSION
/lib/x86_64-linux-gnu/libc.so.6 #直接执行

六、gdb相关命令

1.add-symbol-file

(gdb) help add-symbol-file
从FILE中加载符号,并假定FILE已经被动态加载。
用法:add-symbol-file FILE [-readnow | -readnever] [-o OFF] [ADDR] [-s SECT-NAME SECT-ADDR]…
ADDR是文件.text的起始地址。
每个-s,参数指定了一个段名和段地址,如果数据段和bss段与文本不连续,则应指定该参数。
SECT-NAME 是一个被加载在 SECT-ADDR的段的名字.
OFF是一个可选的偏移量,它被添加到默认加载地址中未指定其他地址的所有节的。
(OFF is an optional offset which is added to the default load addresses of all sections for which no other address was specified.)
'-readnow’选项将导致GDB立即读取整个符号文件。这可能使命令执行变慢,但可能使未来的操作更快。
'-readnever’选项将阻止GDB读取符号文件的符号调试信息。

2.info proc mappings

List memory regions mapped by the specified process.
列出特定进程的内存区域

3. info sharedlibrary

Status of loaded shared object libraries.
已加载共享库的状态

4.info proc mappings和info sharedlibrary的差异

wsl@My-win:~/project/algorithm$ objdump -h /usr/local/lib/libparallelmenu.so.0.0.0

/usr/local/lib/libparallelmenu.so.0.0.0:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .note.gnu.property 00000020  00000000000002a8  00000000000002a8  000002a8  2**3
...
...
 13 .text         00000928  00000000000012c0  00000000000012c0  000012c0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE

通过上述命令可以看到.text段相对于动态库的偏移是0x12c0.
如果直接运行进程,然后attach,查看命令:

(gdb) info proc mappings
process 9775
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x561bf6f6f000     0x561bf6f70000     0x1000        0x0 /usr/local/bin/algorithm
      ...
      ...
      0x561bf6f73000     0x561bf6f74000     0x1000     0x3000 /usr/local/bin/algorithm
      0x561bf7300000     0x561bf7321000    0x21000        0x0 [heap]
      0x7fe23e052000     0x7fe23e055000     0x3000        0x0
      0x7fe23e055000     0x7fe23e07d000    0x28000        0x0 /usr/lib/x86_64-linux-gnu/libc.so.6
      ...
      ...
      0x7fe23e26e000     0x7fe23e270000     0x2000   0x218000 /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7fe23e270000     0x7fe23e27d000     0xd000        0x0
      0x7fe23e27d000     0x7fe23e27e000     0x1000        0x0 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7fe23e27e000     0x7fe23e27f000     0x1000     0x1000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7fe23e27f000     0x7fe23e280000     0x1000     0x2000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7fe23e280000     0x7fe23e281000     0x1000     0x2000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7fe23e281000     0x7fe23e282000     0x1000     0x3000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7fe23e287000     0x7fe23e289000     0x2000        0x0
      0x7fe23e289000     0x7fe23e28b000     0x2000        0x0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
      ...
      ...
      0x7fe23e2c3000     0x7fe23e2c5000     0x2000    0x39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
      0x7ffd49381000     0x7ffd493a2000    0x21000        0x0 [stack]
      0x7ffd493d9000     0x7ffd493dd000     0x4000        0x0 [vvar]
      0x7ffd493dd000     0x7ffd493df000     0x2000        0x0 [vdso]
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007fe23e27e2c0  0x00007fe23e27ebe8  Yes         /usr/local/lib/libparallelmenu.so.0
0x00007fe23e07d700  0x00007fe23e20fabd  Yes (*)     /lib/x86_64-linux-gnu/libc.so.6
0x00007fe23e28b090  0x00007fe23e2b4335  Yes (*)     /lib64/ld-linux-x86-64.so.2
(*): Shared library is missing debugging information.

如果从gdb启动,显示如下:

(gdb) info proc mappings
process 9789
Mapped address spaces:

          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555555000     0x1000        0x0 /usr/local/bin/algorithm
      ...
      ...
      0x555555558000     0x555555559000     0x1000     0x3000 /usr/local/bin/algorithm
      0x7ffff7d86000     0x7ffff7d89000     0x3000        0x0
      0x7ffff7d89000     0x7ffff7db1000    0x28000        0x0 /usr/lib/x86_64-linux-gnu/libc.so.6
      ...
      ...
      0x7ffff7fa2000     0x7ffff7fa4000     0x2000   0x218000 /usr/lib/x86_64-linux-gnu/libc.so.6
      0x7ffff7fa4000     0x7ffff7fb1000     0xd000        0x0
      0x7ffff7fb1000     0x7ffff7fb2000     0x1000        0x0 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7ffff7fb2000     0x7ffff7fb3000     0x1000     0x1000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7ffff7fb3000     0x7ffff7fb4000     0x1000     0x2000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7ffff7fb4000     0x7ffff7fb5000     0x1000     0x2000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7ffff7fb5000     0x7ffff7fb6000     0x1000     0x3000 /usr/local/lib/libparallelmenu.so.0.0.0
      0x7ffff7fbb000     0x7ffff7fbd000     0x2000        0x0
      0x7ffff7fbd000     0x7ffff7fc1000     0x4000        0x0 [vvar]
      0x7ffff7fc1000     0x7ffff7fc3000     0x2000        0x0 [vdso]
      0x7ffff7fc3000     0x7ffff7fc5000     0x2000        0x0 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
      ...
      ...
      0x7ffff7ffd000     0x7ffff7fff000     0x2000    0x39000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
(gdb) info sharedlibrary
From                To                  Syms Read   Shared Object Library
0x00007ffff7fc5090  0x00007ffff7fee335  Yes (*)     /lib64/ld-linux-x86-64.so.2
0x00007ffff7fb22c0  0x00007ffff7fb2be8  Yes         /usr/local/lib/libparallelmenu.so.0
0x00007ffff7db1700  0x00007ffff7f43abd  Yes (*)     /lib/x86_64-linux-gnu/libc.so.6
(*): Shared library is missing debugging information.

总结:
info proc mappings查看的是动态库运行时加载的地址,如果是直接启动的,这个地址是随机的,如果是gdb启动的,这个地址是固定的。
info sharedlibrary 命令查看的是动态库代码段的起始地址。

4.x与disassemble的异同

(gdb) help x
检查内存:x/FMT ADDRESS。
ADDRESS是要检查的内存地址的表达式。
FMT是一个重复计数,后面跟着一个格式字母和一个大小字母。
格式字母有o(八进制),x(十六进制),d(十进制),u(无符号十进制),
T(二进制),f(浮点),a(地址),i(指令),c(char), s(字符串)
z(十六进制,0在左边填充)
大小字母是b(字节),h(半字),w(字),g(巨型,8字节)。
打印指定大小的指定数量的对象
根据格式。如果指定的是负数,则内存为从地址往后查。
字母的格式和大小的默认值是以前使用的。
默认计数为1。默认地址在最后打印的内容后面用这个命令或者"print"。
(gdb) help disassemble
反汇编内存的指定部分。
默认是所选帧的pc周围的函数。

如果使用/m修饰符,那么将包括源代码行(如果可用)。
这种视图是“以源代码为中心”的:输出按源行顺序排列,而不是优化的代码。只有主源文件
被显示,而不是别的,例如,任何内联函数。这个修饰符在实践中没有被证明是有用的,因此不建议使用

使用/s修饰符,那么将包括源代码行(如果可用)。这与/m在两个重要方面不同:
-输出仍然是PC地址顺序
-显示所有相关源文件的文件名和内容。

使用/r修饰符,将包括十六进制的原始指令。

如果只有一个参数,围绕该地址的函数将被转储。两个参数(以逗号分隔)作为要转储的内存范围,以“start,end”或“start,+length”的形式。

注意,地址被解释为一个表达式,而不是一个位置,就像"break"命令一样。
因此,例如,如果你想在文件foo.c中反汇编函数bar,你必须输入“disassemble ‘foo.c’::bar”而不是“disassemble 'foo.c:bar”。

七、coredump

coredump是一个内存映像,可以是主动生成,也可以是崩溃自动生成。

查看coredump开启情况

查看coredump开启情况:

$ ulimit -c 
0

coredump功能在linux是默认关闭的。

打开 coredump 功能

(1)临时打开 coredump 功能
ulimit -c unlimited 命令:生成 coredump 文件,文件大小不受限制。 或ulimit -c 1024 命令: 生成固定大小的 coredump 文件,单位为 blocks(KB)。
注意:这种修改为临时限制,只存活于当前 shell 会话,仅影响当前 shell。

wsl@My-win:~$ ulimit -c unlimited
wsl@My-win:~$ ulimit -c
unlimited

(2)永久打开 coredump 功能
更改 /etc/security/limits.conf 文件中的内容。
去掉 soft core 0 一行前面的注释 ,同时,将 0 改为 unlimited

#/etc/security/limits.conf
...
#

#*               soft    core            0
#root            hard    core            100000
#*               hard    rss             10000

设置coredump路径

默认生成路径:输入可执行文件运行命令的同一路径下
默认生成名字:默认命名为core。新的core文件会覆盖旧的core文件
以下命令分别添加了进程号和日期作为core文件名字

echo 1 > /proc/sys/kernel/core_uses_pid
echo "/corefile/core-%e-%p-%t" > core_pattern

测试core文件生成情况

kill -s SIGSEGV $$

离线查看

离线查看core是很常见的,因为出问题的设备很可能资源有限。把源文件直接放到core文件同路径就可以看函数以及行号了。离线调试core文件需要对应的交付件与符号表,交付件可以是出问题的设备拷贝出来的,也可以是重编的带符号表的同参数编译的交付件,而符号表可以使用objcopy单独剥离的。

参考文章:
Linux环境Release版本的符号表剥离及调试方法
Why does the same shared library show up multiple times when using info proc mappings in gdb?
为什么 ‘ldd’ 和 ‘(gdb) info sharedlibrary’ 显示不同的动态库基地址?
Thread: addr2line doesn’t work - returns ??:0
如何在没有core文件的情况下用dmesg+addr2line定位段错误
Linux下离线调试之coredump文件介绍
计算机那些事(4)——ELF文件结构
strip,eu-strip 及其符号表,gdb调试strip过的程序

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
GDB是一种功能强大的调试器,用于帮助开发人员在软件开发过程中定位和修复程序中的错误。GDB有两个不同的版本:开发版本和发布版本。开发版本通常包含最新的功能和修复,而发布版本是为了稳定性和可靠性而经过测试和验证的版本。 发布版本的GDB是为了满足用户的需求而推出的。它经过详细的测试和验证,确保可以在各种操作系统和硬件平台上正常工作。发布版本通常是根据开发版本中的一些特定功能和修复进行选择和打包的。 发布版本的主要目的是向用户提供一个稳定可靠的调试器,以帮助用户更好地调试和优化他们的程序。这是通过从开发版本中选择和集成一些已经验证和稳定的功能和修复来实现的。此外,发布版本还提供了一些额外的文档,如用户手册和常见问题解答,以帮助用户更好地使用GDB。 发布版本的GDB通常以二进制形式提供,用户只需下载并安装即可使用。用户可以通过向开发者提供反馈来改善发布版本,并在后续的更新中获取新的功能和修复。发布版本的GDB可用于各种软件开发项目,包括嵌入式系统、服务器应用程序和桌面应用程序等。 总之,发布版本的GDB是一个经过测试和验证的稳定版本,旨在为用户提供一个可靠且功能丰富的调试器,以帮助他们调试和优化程序。用户可以下载并安装发布版本,然后从开发者那里获取反馈和更新,以进一步改进GDB的性能和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值