stabs: c语言如何使用stabs存放debug信息,已经如何使用stabs查找函数
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),得出的确实正确的地址,怎么做到的???
$ 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)
参考
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/