#include <defs.h>
#include <x86.h>
#include <stab.h>
#include <stdio.h>
#include <string.h>
#include <kdebug.h>
#define STACKFRAME_DEPTH 20
extern const struct stab __STAB_BEGIN__[]; // beginning of stabs table
extern const struct stab __STAB_END__[]; // end of stabs table
extern const char __STABSTR_BEGIN__[]; // beginning of string table
extern const char __STABSTR_END__[]; // end of string table
/* debug information about a particular instruction pointer */
struct eipdebuginfo {
const char *eip_file; // source code filename for eip
int eip_line; // source code line number for eip
const char *eip_fn_name; // name of function containing eip
int eip_fn_namelen; // length of function's name
uintptr_t eip_fn_addr; // start address of function
int eip_fn_narg; // number of function arguments
};
void
print_debuginfo(uintptr_t eip) {
struct eipdebuginfo info;
if (debuginfo_eip(eip, &info) != 0) {
cprintf(" <unknow>: -- 0x%08x --\n", eip);
}
else {
char fnname[256];
int j;
for (j = 0; j < info.eip_fn_namelen; j ++) {
fnname[j] = info.eip_fn_name[j];
}
fnname[j] = '\0';
cprintf(" %s:%d: %s+%d\n", info.eip_file, info.eip_line,
fnname, eip - info.eip_fn_addr);
}
}
static __noinline uint32_t
read_eip(void) {
uint32_t eip;
asm volatile("movl 4(%%ebp), %0" : "=r" (eip));
return eip;
}
void
print_stackframe(void) {
/* LAB1 YOUR CODE : STEP 1 */
/* (1) call read_ebp() to get the value of ebp. the type is (uint32_t);
* (2) call read_eip() to get the value of eip. the type is (uint32_t);
* (3) from 0 .. STACKFRAME_DEPTH
* (3.1) printf value of ebp, eip
* (3.2) (uint32_t)calling arguments [0..4] = the contents in address (uint32_t)ebp +2 [0..4]
* (3.3) cprintf("\n");
* (3.4) call print_debuginfo(eip-1) to print the C calling function name and line number, etc.
* (3.5) popup a calling stackframe
* NOTICE: the calling funciton's return addr eip = ss:[ebp+4]
* the calling funciton's ebp = ss:[ebp]
*/
uint32_t ebp = read_ebp(), eip = read_eip(), args[4];
int cnt = STACKFRAME_DEPTH;
//使用ebx用于跟踪调用栈 存各级调用的ebp
asm volatile (
"movl %0, %%ebx"
:
: "a"(ebp)
);
while (ebp && cnt--)
{
//假设栈段和数据段不同使用了段超越前缀
//实际在ucore中共享同一个段 可简化
asm volatile (
"movl %%ss: 8(%%ebx), %0"
: "=a" (args[0])
);
asm volatile (
"movl %%ss: 16(%%ebx), %0"
: "=a" (args[1])
);
asm volatile (
"movl %%ss: 24(%%ebx), %0"
: "=a" (args[2])
);
asm volatile (
"movl %%ss: 32(%%ebx), %0"
: "=a" (args[3])
);
cprintf("ebp:0x%08x eip:0x%08x args:0x%08x", ebp, eip, args[0]);
int i = 1;
for (; i < 4; i++)
cprintf(" 0x%08x", args[i]);
cprintf("\n");
//eip为被调函数返回地址
//eip - 1 处于调用指令call的内部,具体位置不能确定
//kdebug.c内使用二分搜索确定包含地址eip - 1的函数,即主调函数,并找到调用发生的行
print_debuginfo(eip - 1);
ebp = *((uint32_t*)ebp);
eip = *((uint32_t*)ebp + 1);
asm volatile (
"movl %0, %%ebx"
:
: "a"(ebp)
);
}
}
kern/debug/kdebug.c: 306: print_stackframe +21
函数调用发生的文件
调用行
主调函数
调用相对主调函数的offset