ucore程序怎么能够打印堆栈

这个是一个能够读取标准输入的程序

/*
1. 读取这个字符
if (char 可显示) {
    记录下来
} else (删除字符) {
    打印删除字符
} else if (换行或者回车) {
    打印,不做记录,然后记录结束
}
*/
char *
readline(const char *prompt) {
    if (prompt != NULL) {
        cprintf("%s", prompt);
    }
    int i = 0, c;
    while (1) {
        c = getchar();
        if (c < 0) {
            return NULL;
        }//否则c > 0
        else if (c >= ' ' && i < BUFSIZE - 1) {//将 c 保存下来 ,如果是可显示的字符的话
            cputchar(c);
            buf[i ++] = c;
        }
        else if (c == '\b' && i > 0) {//退格符号
            cputchar(c);
            i --;
        }
        else if (c == '\n' || c == '\r') {//遇到回车或者换行符就退出
            cputchar(c);
            buf[i] = '\0';
            return buf;
        }
    }
}

对command的定义

struct command {
    const char *name;
    const char *desc;
    // return -1 to force monitor to exit
    int(*func)(int argc, char **argv, struct trapframe *tf);
};

static struct command commands[] = {
    {"help", "Display this list of commands.", mon_help},
    {"kerninfo", "Display information about the kernel.", mon_kerninfo},
    {"backtrace", "Print backtrace of stack frame.", mon_backtrace},
};

上面的这个结构体定义的很有意思

struct command {
    const char *name;
    const char *desc;
    // return -1 to force monitor to exit
    int(*func)(int argc, char **argv, struct trapframe *tf);
};

从标准输入取出来读取的字符串,然后和commands的结构体的name成员比较,成功则调用其func函数

    for (i = 0; i < NCOMMANDS; i ++) {
        if (strcmp(commands[i].name, argv[0]) == 0) {
            return commands[i].func(argc - 1, argv + 1, tf);
        }
    }

backtrace打印堆栈的情况

K> backtrace
ebp:0x00007ae8 eip:0x0010086b args:0x00000000 0x00000001 0x00007b68 0x00100a58 
    kern/debug/kdebug.c:295: print_stackframe+21
ebp:0x00007af8 eip:0x00100b49 args:0x00000000 0x00007b1c 0x00000000 0x0000000a 
    kern/debug/monitor.c:121: mon_backtrace+10
ebp:0x00007b68 eip:0x00100a58 args:0x00108560 0x00000000 0x00007b98 0x00101314 
    kern/debug/monitor.c:71: runcmd+137
ebp:0x00007b98 eip:0x00100ac5 args:0x00000000 0x00101eec 0x0000065c 0x00000000 
    kern/debug/monitor.c:88: monitor+68
ebp:0x00007bc8 eip:0x0010005c args:0x00000000 0x00000000 0x00000000 0x00010094 
    kern/init/init.c:25: kern_init+91
ebp:0x00007bf8 eip:0x00007d47 args:0xc031fcfa 0xc08ed88e 0x64e4d08e 0xfa7502a8 
    <unknow>: -- 0x00007d46 --

总结一下,大概实现的过程

  1. 读取ebp的值,读取eip的值
  2. ebp的地方上一个函数的堆栈,ebp+4的地方是当前函数的返回地址
    for (i = 0; ebp != 0 && i < STACKFRAME_DEPTH; i ++) {
        cprintf("ebp:0x%08x eip:0x%08x args:", ebp, eip);
        /*现在堆栈是 esp, 返回地址*/
        uint32_t *args = (uint32_t *)ebp + 2;//这个地方跳过esp,和调用print_stackframe的返回地址
        for (j = 0; j < 4; j ++) {
            cprintf("0x%08x ", args[j]);
        }
        cprintf("\n");
        print_debuginfo(eip - 1);
        eip = ((uint32_t *)ebp)[1];//这个是调用print_stackframe的返回地址
        ebp = ((uint32_t *)ebp)[0];//这个是上一个堆栈
    }

我觉得完全可以自己解析函数调用堆栈

http://hutaow.com/blog/2013/10/15/dump-stack/
发布了17 篇原创文章 · 获赞 3 · 访问量 3544

猜你喜欢

转载自blog.csdn.net/sgy1993/article/details/90301569