stabs: c语言如何使用stabs存放debug信息,以及如何使用stabs查找函数, stacktrace 如何实现

stabs 已经被 DWARF 替代......

stabs是什么

Stabs (Symbol Table String) refers to a format for information that describes a program to a debugger.

GNU C compiler如何使用stabs

overview

The GNU C compiler compiles C source in a .c file into assembly language in a .s file, which the assembler translates into a .o file, which the linker combines with other .o files and libraries to produce an executable file.

With the ‘-g’ option, GCC puts in the .s file additional debugging information, which is slightly transformed by the assembler and linker, and carried through into the final executable. This debugging information describes features of the source file like line numbers, the types and scopes of variables, and function names, parameters, and scopes.

The assembler adds the information from stabs to the symbol information it places by default in the symbol table and the string table of the .o file it is building. The linker consolidates the .o files into one executable file, with one symbol table and one string table. Debuggers use the symbol and string tables in the executable as a source of debugging information about the program.

To generate stabs now, we need -gstabs option since DWARF has been used for debug information by default now.

$ gcc -gstabs tst.c  # generate stabs debug info
$ gcc -g tst.c # generate DWARF

$ readelf --debug-dump=info a.out  # check which version is used in executable file
Contents of the .debug_info section:

  Compilation Unit @ offset 0x0:
   Length:        0x7f (32-bit)
   Version:       4
   Abbrev Offset: 0x0
   Pointer Size:  8
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)

The format of stab

.stabs "string",type,other,desc,value

The number in the type field gives some basic information about which type of stab this is (or whether it is a stab, as opposed to an ordinary symbol). Each valid type number defines a different stab type; further, the stab type defines the exact interpretation of, and possible values for, any remaining string, desc, or value fields present in the stab.

the format of symbol table entries and how stab assembler directives map to them

Each time the assembler encounters a stab directive, it puts each field of the stab into a corresponding field in a symbol table entry of its output file. If the stab contains a string field, the symbol table entry for that stab points to a string table entry containing the string data from the stab. Assembler labels become relocatable addresses. Symbol table entries in a.out have the format:

struct internal_nlist {
  unsigned long n_strx;         /* index into string table of name */
  unsigned char n_type;         /* type of symbol */
  unsigned char n_other;        /* misc info (usually empty) */
  unsigned short n_desc;        /* description field */
  bfd_vma n_value;              /* value of symbol */
};

If the stab has a string, the n_strx field holds the offset in bytes of the string within the string table. The string is terminated by a NUL character. If the stab lacks a string (for example, it was produced by a .stabn or .stabd directive), the n_strx field is zero.

Symbol table entries with n_type field values greater than 0x1f originated as stabs generated by the compiler (with one random exception). The other entries were placed in the symbol table of the executable by the assembler or the linker.

picture for stabs workflow

example

source code

-----------------------
# tst.h

#ifndef INC_TST_H
#define INC_TST_H

static inline int inb()
{
        return 5;
}
#endif
-----------------------
# tst.c

#include <tst.h>

void func3()
{
        int a = 2;
        a = inb();
        a += 1;
}

int func2(char c)
{
        int a = 1;
        a += c;
        func3();
        a = 2;
}

char func(int i)
{
        char c = 'a';
        func2(c);
        c = 'b';
}

int main()
{
        int a;

        a = 1;
        func(a);
        a = 2;

        return 0;
}

-----------------------
# tst2.c

char t2_func(int i)
{
        char c = 'a';
        func2(c);
}


-----------------------
# tst3.c

char t3_func(int i)
{
        char c = 'a';
        func2(c);
}

stabs

$ gcc -gstabs -I./ tst*.c -S

$ cat tst.s # each tst*.c has its own .s file
	.file	"tst.c"
	.stabs	"tst.c",100,0,2,.Ltext0
	.text
.Ltext0:
	.stabs	"gcc2_compiled.",60,0,0,0
	.stabs	"int:t(0,1)=r(0,1);-2147483648;2147483647;",128,0,0,0
	.stabs	"char:t(0,2)=r(0,2);0;127;",128,0,0,0
	.stabs	"long int:t(0,3)=r(0,3);-0;4294967295;",128,0,0,0
	.stabs	"unsigned int:t(0,4)=r(0,4);0;4294967295;",128,0,0,0
	.stabs	"long unsigned int:t(0,5)=r(0,5);0;-1;",128,0,0,0
	.stabs	"__int128:t(0,6)=r(0,6);0;-1;",128,0,0,0
	.stabs	"__int128 unsigned:t(0,7)=r(0,7);0;-1;",128,0,0,0
	.stabs	"long long int:t(0,8)=r(0,8);-0;4294967295;",128,0,0,0
	.stabs	"long long unsigned int:t(0,9)=r(0,9);0;-1;",128,0,0,0
	.stabs	"short int:t(0,10)=r(0,10);-32768;32767;",128,0,0,0
	.stabs	"short unsigned int:t(0,11)=r(0,11);0;65535;",128,0,0,0
	.stabs	"signed char:t(0,12)=r(0,12);-128;127;",128,0,0,0
	.stabs	"unsigned char:t(0,13)=r(0,13);0;255;",128,0,0,0
	.stabs	"float:t(0,14)=r(0,1);4;0;",128,0,0,0
	.stabs	"double:t(0,15)=r(0,1);8;0;",128,0,0,0
	.stabs	"long double:t(0,16)=r(0,1);16;0;",128,0,0,0
	.stabs	"_Float32:t(0,17)=r(0,1);4;0;",128,0,0,0
	.stabs	"_Float64:t(0,18)=r(0,1);8;0;",128,0,0,0
	.stabs	"_Float128:t(0,19)=r(0,1);16;0;",128,0,0,0
	.stabs	"_Float32x:t(0,20)=r(0,1);8;0;",128,0,0,0
	.stabs	"_Float64x:t(0,21)=r(0,1);16;0;",128,0,0,0
	.stabs	"_Decimal32:t(0,22)=r(0,1);4;0;",128,0,0,0
	.stabs	"_Decimal64:t(0,23)=r(0,1);8;0;",128,0,0,0
	.stabs	"_Decimal128:t(0,24)=r(0,1);16;0;",128,0,0,0
	.stabs	"void:t(0,25)=(0,25)",128,0,0,0
	.stabs	"inb:f(0,1)",36,0,0,inb
	.type	inb, @function
inb:
	.stabs	"./tst.h",132,0,0,.Ltext1
.Ltext1:
	.stabn	68,0,5,.LM0-.LFBB1
.LM0:
.LFBB1:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	.stabn	68,0,6,.LM1-.LFBB1
.LM1:
	movl	$5, %eax
	.stabn	68,0,7,.LM2-.LFBB1
.LM2:
	popq	%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	inb, .-inb
.Lscope1:
	.stabs	"func3:F(0,25)",36,0,0,func3
	.globl	func3
	.type	func3, @function
func3:
	.stabs	"tst.c",132,0,0,.Ltext2
.Ltext2:
	.stabn	68,0,4,.LM3-.LFBB2
.LM3:
.LFBB2:
.LFB1:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	.stabn	68,0,5,.LM4-.LFBB2
.LM4:
	movl	$2, -4(%rbp)
	.stabn	68,0,6,.LM5-.LFBB2
.LM5:
	movl	$0, %eax
	call	inb
	movl	%eax, -4(%rbp)
	.stabn	68,0,7,.LM6-.LFBB2
.LM6:
	addl	$1, -4(%rbp)
	.stabn	68,0,8,.LM7-.LFBB2
.LM7:
	nop
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1:
	.size	func3, .-func3
	.stabs	"a:(0,1)",128,0,0,-4
	.stabn	192,0,0,.LFBB2-.LFBB2
	.stabn	224,0,0,.Lscope2-.LFBB2
.Lscope2:
	.stabs	"func2:F(0,1)",36,0,0,func2
	.stabs	"c:p(0,2)",160,0,0,-20
	.globl	func2
	.type	func2, @function
func2:
	.stabn	68,0,11,.LM8-.LFBB3
.LM8:
.LFBB3:
.LFB2:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$24, %rsp
	movl	%edi, %eax
	movb	%al, -20(%rbp)
	.stabn	68,0,12,.LM9-.LFBB3
.LM9:
	movl	$1, -4(%rbp)
	.stabn	68,0,13,.LM10-.LFBB3
.LM10:
	movsbl	-20(%rbp), %eax
	addl	%eax, -4(%rbp)
	.stabn	68,0,14,.LM11-.LFBB3
.LM11:
	movl	$0, %eax
	call	func3
	.stabn	68,0,15,.LM12-.LFBB3
.LM12:
	movl	$2, -4(%rbp)
	.stabn	68,0,16,.LM13-.LFBB3
.LM13:
	nop
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE2:
	.size	func2, .-func2
	.stabs	"a:(0,1)",128,0,0,-4
	.stabn	192,0,0,.LFBB3-.LFBB3
	.stabn	224,0,0,.Lscope3-.LFBB3
.Lscope3:
	.stabs	"func:F(0,2)",36,0,0,func
	.stabs	"i:p(0,1)",160,0,0,-20
	.globl	func
	.type	func, @function
func:
	.stabn	68,0,19,.LM14-.LFBB4
.LM14:
.LFBB4:
.LFB3:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$24, %rsp
	movl	%edi, -20(%rbp)
	.stabn	68,0,20,.LM15-.LFBB4
.LM15:
	movb	$97, -1(%rbp)
	.stabn	68,0,21,.LM16-.LFBB4
.LM16:
	movsbl	-1(%rbp), %eax
	movl	%eax, %edi
	call	func2
	.stabn	68,0,22,.LM17-.LFBB4
.LM17:
	movb	$98, -1(%rbp)
	.stabn	68,0,23,.LM18-.LFBB4
.LM18:
	nop
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE3:
	.size	func, .-func
	.stabs	"c:(0,2)",128,0,0,-1
	.stabn	192,0,0,.LFBB4-.LFBB4
	.stabn	224,0,0,.Lscope4-.LFBB4
.Lscope4:
	.stabs	"main:F(0,1)",36,0,0,main
	.globl	main
	.type	main, @function
main:
	.stabn	68,0,26,.LM19-.LFBB5
.LM19:
.LFBB5:
.LFB4:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	.stabn	68,0,29,.LM20-.LFBB5
.LM20:
	movl	$1, -4(%rbp)
	.stabn	68,0,30,.LM21-.LFBB5
.LM21:
	movl	-4(%rbp), %eax
	movl	%eax, %edi
	call	func
	.stabn	68,0,31,.LM22-.LFBB5
.LM22:
	movl	$2, -4(%rbp)
	.stabn	68,0,33,.LM23-.LFBB5
.LM23:
	movl	$0, %eax
	.stabn	68,0,34,.LM24-.LFBB5
.LM24:
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE4:
	.size	main, .-main
	.stabs	"a:(0,1)",128,0,0,-4
	.stabn	192,0,0,.LFBB5-.LFBB5
	.stabn	224,0,0,.Lscope5-.LFBB5
.Lscope5:
	.stabs	"",100,0,0,.Letext0
.Letext0:
	.ident	"GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0"
	.section	.note.GNU-stack,"",@progbits

stabs in executable (symbol table)

$ objdump -G a.out


a.out:     file format elf64-x86-64

Contents of .stab section:

Symnum n_type n_othr n_desc n_value  n_strx String

-1     HdrSym 0      148    00000000000003fa 1     
0      SO     0      2      00000000000005fa 1      tst2.c
1      OPT    0      0      0000000000000000 8      gcc2_compiled.
2      LSYM   0      0      0000000000000000 23     int:t(0,1)=r(0,1);-2147483648;2147483647;
3      LSYM   0      0      0000000000000000 65     char:t(0,2)=r(0,2);0;127;
4      LSYM   0      0      0000000000000000 91     long int:t(0,3)=r(0,3);-0;4294967295;
5      LSYM   0      0      0000000000000000 129    unsigned int:t(0,4)=r(0,4);0;4294967295;
6      LSYM   0      0      0000000000000000 170    long unsigned int:t(0,5)=r(0,5);0;-1;
7      LSYM   0      0      0000000000000000 208    __int128:t(0,6)=r(0,6);0;-1;
8      LSYM   0      0      0000000000000000 237    __int128 unsigned:t(0,7)=r(0,7);0;-1;
9      LSYM   0      0      0000000000000000 275    long long int:t(0,8)=r(0,8);-0;4294967295;
10     LSYM   0      0      0000000000000000 318    long long unsigned int:t(0,9)=r(0,9);0;-1;
11     LSYM   0      0      0000000000000000 361    short int:t(0,10)=r(0,10);-32768;32767;
12     LSYM   0      0      0000000000000000 401    short unsigned int:t(0,11)=r(0,11);0;65535;
13     LSYM   0      0      0000000000000000 445    signed char:t(0,12)=r(0,12);-128;127;
14     LSYM   0      0      0000000000000000 483    unsigned char:t(0,13)=r(0,13);0;255;
15     LSYM   0      0      0000000000000000 520    float:t(0,14)=r(0,1);4;0;
16     LSYM   0      0      0000000000000000 546    double:t(0,15)=r(0,1);8;0;
17     LSYM   0      0      0000000000000000 573    long double:t(0,16)=r(0,1);16;0;
18     LSYM   0      0      0000000000000000 606    _Float32:t(0,17)=r(0,1);4;0;
19     LSYM   0      0      0000000000000000 635    _Float64:t(0,18)=r(0,1);8;0;
20     LSYM   0      0      0000000000000000 664    _Float128:t(0,19)=r(0,1);16;0;
21     LSYM   0      0      0000000000000000 695    _Float32x:t(0,20)=r(0,1);8;0;
22     LSYM   0      0      0000000000000000 725    _Float64x:t(0,21)=r(0,1);16;0;
23     LSYM   0      0      0000000000000000 756    _Decimal32:t(0,22)=r(0,1);4;0;
24     LSYM   0      0      0000000000000000 787    _Decimal64:t(0,23)=r(0,1);8;0;
25     LSYM   0      0      0000000000000000 818    _Decimal128:t(0,24)=r(0,1);16;0;
26     LSYM   0      0      0000000000000000 851    void:t(0,25)=(0,25)
27     FUN    0      0      00000000000005fa 871    t2_func:F(0,2)
28     PSYM   0      0      00000000ffffffec 886    i:p(0,1)
29     SLINE  0      2      0000000000000000 0      
30     SLINE  0      3      000000000000000b 0      
31     SLINE  0      4      000000000000000f 0      
32     SLINE  0      5      000000000000001f 0      
33     LSYM   0      0      00000000ffffffff 895    c:(0,2)
34     LBRAC  0      0      0000000000000000 0      
35     RBRAC  0      0      0000000000000022 0      
36     SO     0      0      000000000000061c 0      
37     SO     0      2      000000000000061c 903    tst3.c
38     OPT    0      0      0000000000000000 8      gcc2_compiled.
39     LSYM   0      0      0000000000000000 23     int:t(0,1)=r(0,1);-2147483648;2147483647;
40     LSYM   0      0      0000000000000000 65     char:t(0,2)=r(0,2);0;127;
41     LSYM   0      0      0000000000000000 91     long int:t(0,3)=r(0,3);-0;4294967295;
42     LSYM   0      0      0000000000000000 129    unsigned int:t(0,4)=r(0,4);0;4294967295;
43     LSYM   0      0      0000000000000000 170    long unsigned int:t(0,5)=r(0,5);0;-1;
44     LSYM   0      0      0000000000000000 208    __int128:t(0,6)=r(0,6);0;-1;
45     LSYM   0      0      0000000000000000 237    __int128 unsigned:t(0,7)=r(0,7);0;-1;
46     LSYM   0      0      0000000000000000 275    long long int:t(0,8)=r(0,8);-0;4294967295;
47     LSYM   0      0      0000000000000000 318    long long unsigned int:t(0,9)=r(0,9);0;-1;
48     LSYM   0      0      0000000000000000 361    short int:t(0,10)=r(0,10);-32768;32767;
49     LSYM   0      0      0000000000000000 401    short unsigned int:t(0,11)=r(0,11);0;65535;
50     LSYM   0      0      0000000000000000 445    signed char:t(0,12)=r(0,12);-128;127;
51     LSYM   0      0      0000000000000000 483    unsigned char:t(0,13)=r(0,13);0;255;
52     LSYM   0      0      0000000000000000 520    float:t(0,14)=r(0,1);4;0;
53     LSYM   0      0      0000000000000000 546    double:t(0,15)=r(0,1);8;0;
54     LSYM   0      0      0000000000000000 573    long double:t(0,16)=r(0,1);16;0;
55     LSYM   0      0      0000000000000000 606    _Float32:t(0,17)=r(0,1);4;0;
56     LSYM   0      0      0000000000000000 635    _Float64:t(0,18)=r(0,1);8;0;
57     LSYM   0      0      0000000000000000 664    _Float128:t(0,19)=r(0,1);16;0;
58     LSYM   0      0      0000000000000000 695    _Float32x:t(0,20)=r(0,1);8;0;
59     LSYM   0      0      0000000000000000 725    _Float64x:t(0,21)=r(0,1);16;0;
60     LSYM   0      0      0000000000000000 756    _Decimal32:t(0,22)=r(0,1);4;0;
61     LSYM   0      0      0000000000000000 787    _Decimal64:t(0,23)=r(0,1);8;0;
62     LSYM   0      0      0000000000000000 818    _Decimal128:t(0,24)=r(0,1);16;0;
63     LSYM   0      0      0000000000000000 851    void:t(0,25)=(0,25)
64     FUN    0      0      000000000000061c 910    t3_func:F(0,2)
65     PSYM   0      0      00000000ffffffec 886    i:p(0,1)
66     SLINE  0      2      0000000000000000 0      
67     SLINE  0      3      000000000000000b 0      
68     SLINE  0      4      000000000000000f 0      
69     SLINE  0      5      000000000000001f 0      
70     LSYM   0      0      00000000ffffffff 895    c:(0,2)
71     LBRAC  0      0      0000000000000000 0      
72     RBRAC  0      0      0000000000000022 0      
73     SO     0      0      000000000000063e 0      
74     SO     0      2      000000000000063e 925    tst.c
75     OPT    0      0      0000000000000000 8      gcc2_compiled.
76     LSYM   0      0      0000000000000000 23     int:t(0,1)=r(0,1);-2147483648;2147483647;
77     LSYM   0      0      0000000000000000 65     char:t(0,2)=r(0,2);0;127;
78     LSYM   0      0      0000000000000000 91     long int:t(0,3)=r(0,3);-0;4294967295;
79     LSYM   0      0      0000000000000000 129    unsigned int:t(0,4)=r(0,4);0;4294967295;
80     LSYM   0      0      0000000000000000 170    long unsigned int:t(0,5)=r(0,5);0;-1;
81     LSYM   0      0      0000000000000000 208    __int128:t(0,6)=r(0,6);0;-1;
82     LSYM   0      0      0000000000000000 237    __int128 unsigned:t(0,7)=r(0,7);0;-1;
83     LSYM   0      0      0000000000000000 275    long long int:t(0,8)=r(0,8);-0;4294967295;
84     LSYM   0      0      0000000000000000 318    long long unsigned int:t(0,9)=r(0,9);0;-1;
85     LSYM   0      0      0000000000000000 361    short int:t(0,10)=r(0,10);-32768;32767;
86     LSYM   0      0      0000000000000000 401    short unsigned int:t(0,11)=r(0,11);0;65535;
87     LSYM   0      0      0000000000000000 445    signed char:t(0,12)=r(0,12);-128;127;
88     LSYM   0      0      0000000000000000 483    unsigned char:t(0,13)=r(0,13);0;255;
89     LSYM   0      0      0000000000000000 520    float:t(0,14)=r(0,1);4;0;
90     LSYM   0      0      0000000000000000 546    double:t(0,15)=r(0,1);8;0;
91     LSYM   0      0      0000000000000000 573    long double:t(0,16)=r(0,1);16;0;
92     LSYM   0      0      0000000000000000 606    _Float32:t(0,17)=r(0,1);4;0;
93     LSYM   0      0      0000000000000000 635    _Float64:t(0,18)=r(0,1);8;0;
94     LSYM   0      0      0000000000000000 664    _Float128:t(0,19)=r(0,1);16;0;
95     LSYM   0      0      0000000000000000 695    _Float32x:t(0,20)=r(0,1);8;0;
96     LSYM   0      0      0000000000000000 725    _Float64x:t(0,21)=r(0,1);16;0;
97     LSYM   0      0      0000000000000000 756    _Decimal32:t(0,22)=r(0,1);4;0;
98     LSYM   0      0      0000000000000000 787    _Decimal64:t(0,23)=r(0,1);8;0;
99     LSYM   0      0      0000000000000000 818    _Decimal128:t(0,24)=r(0,1);16;0;
100    LSYM   0      0      0000000000000000 851    void:t(0,25)=(0,25)
101    FUN    0      0      000000000000063e 931    inb:f(0,1)
102    SOL    0      0      000000000000063e 942    ./tst.h
103    SLINE  0      5      0000000000000000 0      
104    SLINE  0      6      0000000000000004 0      
105    SLINE  0      7      0000000000000009 0      
106    FUN    0      0      0000000000000649 950    func3:F(0,25)
107    SOL    0      0      0000000000000649 925    tst.c
108    SLINE  0      4      0000000000000000 0      
109    SLINE  0      5      0000000000000008 0      
110    SLINE  0      6      000000000000000f 0      
111    SLINE  0      7      000000000000001c 0      
112    SLINE  0      8      0000000000000020 0      
113    LSYM   0      0      00000000fffffffc 964    a:(0,1)
114    LBRAC  0      0      0000000000000000 0      
115    RBRAC  0      0      0000000000000023 0      
116    FUN    0      0      000000000000066c 972    func2:F(0,1)
117    PSYM   0      0      00000000ffffffec 985    c:p(0,2)
118    SLINE  0      11     0000000000000000 0      
119    SLINE  0      12     000000000000000d 0      
120    SLINE  0      13     0000000000000014 0      
121    SLINE  0      14     000000000000001b 0      
122    SLINE  0      15     0000000000000025 0      
123    SLINE  0      16     000000000000002c 0      
124    LSYM   0      0      00000000fffffffc 964    a:(0,1)
125    LBRAC  0      0      0000000000000000 0      
126    RBRAC  0      0      000000000000002f 0      
127    FUN    0      0      000000000000069b 994    func:F(0,2)
128    PSYM   0      0      00000000ffffffec 886    i:p(0,1)
129    SLINE  0      19     0000000000000000 0      
130    SLINE  0      20     000000000000000b 0      
131    SLINE  0      21     000000000000000f 0      
132    SLINE  0      22     000000000000001a 0      
133    SLINE  0      23     000000000000001e 0      
134    LSYM   0      0      00000000ffffffff 895    c:(0,2)
135    LBRAC  0      0      0000000000000000 0      
136    RBRAC  0      0      0000000000000021 0      
137    FUN    0      0      00000000000006bc 1006   main:F(0,1)
138    SLINE  0      26     0000000000000000 0      
139    SLINE  0      29     0000000000000008 0      
140    SLINE  0      30     000000000000000f 0      
141    SLINE  0      31     0000000000000019 0      
142    SLINE  0      33     0000000000000020 0      
143    SLINE  0      34     0000000000000025 0      
144    LSYM   0      0      00000000fffffffc 964    a:(0,1)
145    LBRAC  0      0      0000000000000000 0      
146    RBRAC  0      0      0000000000000027 0      
147    SO     0      0      00000000000006e3 0      

stabs 在symbol table中的组织/排序

Some stab types are arranged in increasing order by instruction address (n_value field).  For example, N_FUN stabs (stab entries with n_type ==  N_FUN), which mark functions, and N_SO stabs, which mark source files, and N_SLINE for code line number.

N_SO order in a.out symbol table

the string field contains the name of the file. The value of the symbol is the start address of the portion of the text section corresponding to that file.

An N_SOL symbol specifies which include file subsequent symbols refer to. The string field is the name of the file and the value is the text address corresponding to the end of the previous include file and the start of this one. To specify the main source file again, use an N_SOL symbol with the name of the main source file.

Symnum n_type n_othr n_desc n_value  n_strx String
0      SO     0      2      00000000000005fa 1      tst2.c
36     SO     0      0      000000000000061c 0      
37     SO     0      2      000000000000061c 903    tst3.c
73     SO     0      0      000000000000063e 0      
74     SO     0      2      000000000000063e 925    tst.c
102    SOL    0      0      000000000000063e 942    ./tst.h
107    SOL    0      0      0000000000000649 925    tst.c
147    SO     0      0      00000000000006e3 0      

N_FUN order

Symnum n_type n_othr n_desc n_value  n_strx String
27     FUN    0      0      00000000000005fa 871    t2_func:F(0,2)
27     FUN    0      0      00000000000005fa 871    t2_func:F(0,2)
64     FUN    0      0      000000000000061c 910    t3_func:F(0,2)
64     FUN    0      0      000000000000061c 910    t3_func:F(0,2)
101    FUN    0      0      000000000000063e 931    inb:f(0,1)
106    FUN    0      0      0000000000000649 950    func3:F(0,25)
106    FUN    0      0      0000000000000649 950    func3:F(0,25)
116    FUN    0      0      000000000000066c 972    func2:F(0,1)
116    FUN    0      0      000000000000066c 972    func2:F(0,1)
127    FUN    0      0      000000000000069b 994    func:F(0,2)
127    FUN    0      0      000000000000069b 994    func:F(0,2)
137    FUN    0      0      00000000000006bc 1006   main:F(0,1)

N_SLINE order in a function

Symnum n_type n_othr n_desc n_value  n_strx String
27     FUN    0      0      00000000000005fa 871    t2_func:F(0,2)
28     PSYM   0      0      00000000ffffffec 886    i:p(0,1)
29     SLINE  0      2      0000000000000000 0      
30     SLINE  0      3      000000000000000b 0      
31     SLINE  0      4      000000000000000f 0      
32     SLINE  0      5      000000000000001f 0      
33     LSYM   0      0      00000000ffffffff 895    c:(0,2)
34     LBRAC  0      0      0000000000000000 0      
35     RBRAC  0      0      0000000000000022 0   

如何查找IP(instruction pointer)对应的文件名、文件里的行号、和函数名

例如,对于IP=0x00005555555546b5,

1)找对应的函数,通过N_FUN顺序查找,找到下面这行(再下一个FUN开始的地址已经大于6b5),所以是函数func()

116    FUN    0      0      000000000000066c 972    func2:F(0,1)
127    FUN    0      0      000000000000069b 994    func:F(0,2)
127    FUN    0      0      000000000000069b 994    func:F(0,2)
137    FUN    0      0      00000000000006bc 1006   main:F(0,1)

2)找对应的行号,在找到的函数func这里找行号,里面的地址是相对于函数开始的偏移,6b5-69b=1a,找到对应的行(22是行号),

127    FUN    0      0      000000000000069b 994    func:F(0,2)
128    PSYM   0      0      00000000ffffffec 886    i:p(0,1)
129    SLINE  0      19     0000000000000000 0      
130    SLINE  0      20     000000000000000b 0      
131    SLINE  0      21     000000000000000f 0      
132    SLINE  0      22     000000000000001a 0      
133    SLINE  0      23     000000000000001e 0  

3)找对应的文件,从行号或者函数对应的那一行往上找,第一个N_SO或者N_SOL就是文件了,N_SOL是因为inline的头文件里的函数,

102    SOL    0      0      000000000000063e 942    ./tst.h  #这里开始是tst.h中的函数
103    SLINE  0      5      0000000000000000 0      
104    SLINE  0      6      0000000000000004 0      
105    SLINE  0      7      0000000000000009 0      
106    FUN    0      0      0000000000000649 950    func3:F(0,25)
107    SOL    0      0      0000000000000649 925    tst.c #这里tst.h结束,后面是tst.c的函数

...

132    SLINE  0      22     000000000000001a 0      
133    SLINE  0      23     000000000000001e 0

c语言的backtrace是如何实现的

c语言函数调用的规则是,对应stack的使用(如下图):

调用函数的时候:先压入参数,再压入函数调用后的返回地址,

函数开始执行的时候:先压入bp(base pointer register),再保存当前的bp = sp

所以,从当前的bp可以得到调用者的bp和ip(instruction pointer,返回地址),一直找到最开始的函数。找到

所有的ip后,再把ip用上面的方法转变成函数名、文件名就得到了详细的trace。

疑问:

stack里面的ip(返回地址)都是调用函数的下一条地址,所以通过ip得到的应该也是下一条地址的信息,而不是当前正在调用的函数那一行的地址。但是gdb之类的(下图的#2),得出的却是正确的地址,怎么做到的???另外,这些地址如果用addr2line去查询的话,得到的同样是调用函数的下一条地址(如图中addr2line输出)。猜测2种可能,1)用ip地址计算行号的时候,用ip-1去计算;2)用ip地址找到行号的那个stabs entry之后,取这个entry上面的那个entry对应的行号。

$ gdb a.out 
Reading symbols from a.out...done.
(gdb) b func3
Breakpoint 1 at 0x651: file tst.c, line 5.
(gdb) r
Starting program: /home/hfyin/projects/6.828/others/a.out 

Breakpoint 1, func3 () at tst.c:5
5	        int a = 2;
(gdb) bt
#0  func3 () at tst.c:5
#1  0x0000555555554691 in func2 (c=97 'a') at tst.c:14
#2  0x00005555555546b5 in func (i=1) at tst.c:21
#3  0x00005555555546d5 in main () at tst.c:30
(gdb) i r rip
rip            0x555555554651	0x555555554651 <func3+8>
(gdb) 


# addr2line得到的行号和手工计算得到的一样,是ip对应的行号,而不是当前正在进行调用的函数对应的行号
$ addr2line -e a.out 0x00005555555546b5 
??:0
$ addr2line -e a.out 0x6b5 
tst.c:22
$ addr2line -e a.out 0x6d5 
tst.c:31
$ addr2line -e a.out 0x691
tst.c:15
$ addr2line -e a.out 0x651
tst.c:5
$ 

# 使用ip-1计算行号,得到的是正在进行函数调用的代码行号;手工计算的时候,取ip对应的entry上面的那个entry,行号应该和用ip-1计算的一样
$ addr2line -e a.out 0x650
tst.c:4
$ addr2line -e a.out 0x690
tst.c:14
$ addr2line -e a.out 0x6d4
tst.c:30
$

参考

1. https://sourceware.org/gdb/current/onlinedocs/stabs.html#Line-Numbers

2. https://en.wikipedia.org/wiki/Stabs

3. https://en.wikipedia.org/wiki/DWARF

4. https://jiyou.github.io/blog/2018/04/15/mit.6.828/jos-lab1/

发布了34 篇原创文章 · 获赞 0 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/hfyinsdu/article/details/104359578