MIT6.828 lab1/Exercise12

Exercise12

要求

在11的基础上打印出当前eip所指向地址的文件信息,行号,距离上一个eip的地址距离。

K> backtrace
Stack backtrace:
  ebp f010ff78  eip f01008ae  args 00000001 f010ff8c 00000000 f0110580 00000000
         kern/monitor.c:143: monitor+106
  ebp f010ffd8  eip f0100193  args 00000000 00001aac 00000660 00000000 00000000
         kern/init.c:49: i386_init+59
  ebp f010fff8  eip f010003d  args 00000000 00000000 0000ffff 10cf9a00 0000ffff
         kern/entry.S:70: +0
K> 

分析

可以根据eip的地址在symbol table中获取这些信息。简称为stab。
symbol table(符号表): 在编译程序中符号表用来存放语言程序中出现的有关标识符的属性信息,这些信息集中反映了标识符的语义特征属性。
Stab汇编指导命令有3种格式:'.stabs'(string), '.stabn'(number)和'.stabd'(dot)。 在MIPS机器上, GCC采用 '.stabn' 输出源程序语句行号的 Stab 调试信息, 而未使用 '.stabd' , 因此, 在MIPS机器上, GCC生成的带有 Stab 调试信息的汇编代码中只含 '.stabs' 和 '.stabn' 两种汇编指导命令, '.stabs' 和 '.stabn' 命令格式如下:

.stabs "STRING", TYPE, OTHER, DESC, VALUE
 
.stabn TYPE, OTHER, DESC, VALUE

TYPE类型:

#define N_GSYM      0x20    // global symbol
#define N_FNAME     0x22    // F77 function name
#define N_FUN       0x24    // procedure name
#define N_STSYM     0x26    // data segment variable
#define N_LCSYM     0x28    // bss segment variable
#define N_MAIN      0x2a    // main function name
#define N_PC        0x30    // global Pascal symbol
#define N_RSYM      0x40    // register variable
#define N_SLINE     0x44    // text segment line number
#define N_DSLINE    0x46    // data segment line number
#define N_BSLINE    0x48    // bss segment line number
#define N_SSYM      0x60    // structure/union element
#define N_SO        0x64    // main source file name
#define N_LSYM      0x80    // stack variable
#define N_BINCL     0x82    // include file beginning
#define N_SOL       0x84    // included source file name
#define N_PSYM      0xa0    // parameter variable
#define N_EINCL     0xa2    // include file end
#define N_ENTRY     0xa4    // alternate entry point
#define N_LBRAC     0xc0    // left bracket
#define N_EXCL      0xc2    // deleted include file
#define N_RBRAC     0xe0    // right bracket
#define N_BCOMM     0xe2    // begin common
#define N_ECOMM     0xe4    // end common
#define N_ECOML     0xe8    // end common (local name)
#define N_LENG      0xfe    // length of preceding entry

使用Exercise11中的例子,加上--gstabs参数,可以得出源代码中的stab信息,其中100代表0x64,对应type的#define N_SO 0x64 // main source file name代表是源文件的名字。

.stabs  "test_stack.c",100,0,2,.Ltext0

68代表0x44,对应#define N_SLINE 0x44 // text segment line number代表bar的行号,其中DESC = 3就代表bar函数在文件中的第三行。

bar:
    .stabn  68,0,3,.LM0-.LFBB1

在程序中stab其实就是一个数据结构,在inc/stab.h下

// Entries in the STABS table are formatted as follows.
struct Stab {
    uint32_t n_strx;    // index into string table of name
    uint8_t n_type;         // type of symbol
    uint8_t n_other;        // misc info (usually empty)
    uint16_t n_desc;        // description field
    uintptr_t n_value;  // value of symbol
};

在程序中是一个stabs[]数组。
在kern/kdebug.c的stab_binsearch函数中,根据eip的地址addr和类型type使用二分查找,找到对应的stabs,然后获取对应的行号的文件信息存入到Eipdebuginfo的数据结构中。

struct Eipdebuginfo {
    const char *eip_file;       // Source code filename for EIP
    int eip_line;           // Source code linenumber for EIP

    const char *eip_fn_name;    // Name of function containing EIP
                    //  - Note: not null terminated!
    int eip_fn_namelen;     // Length of function name
    uintptr_t eip_fn_addr;      // Address of start of function
    int eip_fn_narg;        // Number of function arguments
};

代码

在kern/kdebug.c的debuginfo_eip中添加获取行号的代码

stab_binsearch(stabs, &lline, &rline, N_SLINE ,addr);
    if (lline > rline) 
        return -1;
    info->eip_line = stabs[rline].n_desc;

在kern/monitor.c中添加信息打印

while(ebp) {
        struct Eipdebuginfo debug_info;
        eip = *(ebp+1);
        debuginfo_eip(eip, &debug_info);
        cprintf("ebp %x eip %x args", ebp, eip);
        uint32_t* args = ebp+2;
        for(int i = 0; i < 5; ++i) {
            uint32_t argv = args[i];
            cprintf(" %08x ", argv);
        }
        cprintf("\n");
        cprintf("\t%s:%d: %.*s+%d\n",
            debug_info.eip_file, debug_info.eip_line, debug_info.eip_fn_namelen,
            debug_info.eip_fn_name, eip - debug_info.eip_fn_addr);
        ebp = (uint32_t*)*ebp;
    }

参考

http://caobeixingqiu.is-programmer.com/posts/12361.html
https://github.com/shishujuan/mit6.828-2017/blob/master/docs/lab1-exercize.md

你可能感兴趣的:(MIT6.828 lab1/Exercise12)