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:       4Abbrev Offset: 0x0Pointer 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_Hstatic 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.cchar t2_func(int i)
{char c = 'a';func2(c);
}-----------------------
# tst3.cchar 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_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %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, 8ret.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_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq   $16, %rsp.stabn 68,0,5,.LM4-.LFBB2
.LM4:movl   $2, -4(%rbp).stabn  68,0,6,.LM5-.LFBB2
.LM5:movl   $0, %eaxcall    inbmovl %eax, -4(%rbp).stabn    68,0,7,.LM6-.LFBB2
.LM6:addl   $1, -4(%rbp).stabn  68,0,8,.LM7-.LFBB2
.LM7:nopleave.cfi_def_cfa 7, 8ret.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_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq   $24, %rspmovl   %edi, %eaxmovb  %al, -20(%rbp).stabn    68,0,12,.LM9-.LFBB3
.LM9:movl   $1, -4(%rbp).stabn  68,0,13,.LM10-.LFBB3
.LM10:movsbl    -20(%rbp), %eaxaddl %eax, -4(%rbp).stabn    68,0,14,.LM11-.LFBB3
.LM11:movl  $0, %eaxcall    func3.stabn 68,0,15,.LM12-.LFBB3
.LM12:movl  $2, -4(%rbp).stabn  68,0,16,.LM13-.LFBB3
.LM13:nopleave.cfi_def_cfa 7, 8ret.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_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq   $24, %rspmovl   %edi, -20(%rbp).stabn   68,0,20,.LM15-.LFBB4
.LM15:movb  $97, -1(%rbp).stabn 68,0,21,.LM16-.LFBB4
.LM16:movsbl    -1(%rbp), %eaxmovl  %eax, %edicall  func2.stabn 68,0,22,.LM17-.LFBB4
.LM17:movb  $98, -1(%rbp).stabn 68,0,23,.LM18-.LFBB4
.LM18:nopleave.cfi_def_cfa 7, 8ret.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_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq   $16, %rsp.stabn 68,0,29,.LM20-.LFBB5
.LM20:movl  $1, -4(%rbp).stabn  68,0,30,.LM21-.LFBB5
.LM21:movl  -4(%rbp), %eaxmovl  %eax, %edicall  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, 8ret.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.outa.out:     file format elf64-x86-64Contents 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/

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

  1. 【示例】C语言中利用数组存放函数指针

    C语言中利用数组存放函数指针,增加函数使用的灵活性.使用时只需提供数组索引,即可调用不同函数. 预备知识: 1.指向函数的指针 一个函数在编译时被分配一个入口地址,这个地址就被称为函数的指针. 例如: ...

  2. DWARF格式对于debug信息的支持

    DWARF格式对于debug信息的支持 by Peter 4 YEARS AGO 4 MINUTEREAD http://tsecer.blog.163.com/blog/static/1501817 ...

  3. c语言限制字符数,C语言中“不受限制”的字符串函数总结.pdf

    C语语言言中中"不不受受限限制制"的的字字符符串串函函数数总总结结 "不不受受限限制制的的"字字符符串串函函数数 按 <C和指针>中所说,那些常用的 ...

  4. R语言gganimate包创建可视化gif动图、并使用anim_save函数保存可视化gif动图(gganimate export to gif)

    R语言gganimate包创建可视化gif动图.并使用anim_save函数保存可视化gif动图(gganimate export to gif) 目录

  5. R语言使用random包生成随机数或者随机字符串实战:randomNumbers函数创建随机整数的数据集(包含重复项)、randomSequence函数创建不含重复项的随机序列数据集、创建随机字符串

    R语言使用random包生成随机数或者随机字符串实战:randomNumbers函数创建随机整数的数据集(包含重复项).randomSequence函数创建不含重复项的随机序列数据集.创建随机字符串 ...

  6. R语言ggplot2可视化:将dataframe和数据列名称传递给函数通过函数进行ggplot2可视化输出

    R语言ggplot2可视化:将dataframe和数据列名称传递给函数通过函数进行ggplot2可视化输出 目录

  7. R语言将dataframe长表转化为宽表实战:使用reshape函数、使用tidyr包的spread函数、使用data.table

    R语言将dataframe长表转化为宽表实战:使用reshape函数.使用tidyr包的spread函数.使用data.table 目录

  8. R语言apropos函数查找包含特定字符的函数、find函数查找函数所在的位置实战

    R语言apropos函数查找包含特定字符的函数.find函数查找函数所在的位置实战 目录 R语言apropos函数实战 # 基本语法 #apropos函数 # find函数 apropos函数返回一个 ...

  9. cocos2d-x 输出debug信息

    在Classes目录下添加文件AppDef.h #ifndef _APP_DEF_H_ #define _APP_DEF_H_ #include <android/log.h> #defi ...

最新文章

  1. 云职教课堂计算机文化基础,2020智慧职教云课堂计算机文化基础答案最新最全单元测试答案...
  2. html文本框填充颜色逐渐减少,web前端面试题之htmlcss篇
  3. Windows 10第四个大补丸来啦
  4. 如何清除aspx网页中的flash缓存
  5. FANUC常用CNC诊断数据表
  6. LINUX中常用操作命令
  7. java的传值调用什么_Java的传值调用
  8. java 反射 内存_Java 反射
  9. 一位工作了10年的C++程序员总结出这些忠告
  10. 主从复制中忽略库的参数
  11. 数字化转型鸿沟如何消除?ROMA Connect融合集成,联接企业应用现在与未来
  12. 纯Java代码 图片压缩
  13. LeetCode-108将有序数组转换为二叉搜索树
  14. CSS3的几个标签速记3
  15. php装箱,PHP实现的装箱算法示例
  16. 酒店管理系统需求获取分析——G001-186-17
  17. xmlspy使用必备的技巧
  18. 通俗的解释机器学习的预测原理
  19. 程序员生活_程序员,请您不要老是熬夜
  20. 【软考系统架构设计师】2015年下系统架构师案例分析历年真题

热门文章

  1. 成都平面设计培训学校那家好,平面设计培训班学费一般多少:夏雨老师
  2. 前端基础--DW的使用
  3. EDA技术的概念及范畴
  4. python gdb调试
  5. JSON数据解析生成一个每行10列,行数不固定的表格
  6. python pygam小鱼游玩动画
  7. 复盘?没错就是你理解的复盘,来看看几种复盘模型吧
  8. kali linux 破解wifi
  9. Ubuntu密码忘记怎么办
  10. 批处理bat万能删除文件/夹