1 #include "traceback.h"
2 #include <common/printk.h>
3 #include <process/process.h>
4
lookup_kallsyms(uint64_t addr,int level)5 static int lookup_kallsyms(uint64_t addr, int level)
6 {
7 const char *str = (const char *)&kallsyms_names;
8
9 // 暴力查找符合要求的symbol
10 // todo: 改用二分搜索。
11 // 由于符号表使用nm -n生成,因此是按照地址升序排列的,因此可以二分
12 uint64_t index = 0;
13 for (index = 0; index < kallsyms_num - 1; ++index)
14 {
15 if (addr > kallsyms_address[index] && addr <= kallsyms_address[index + 1])
16 break;
17 }
18
19 if (index < kallsyms_num) // 找到对应的函数
20 {
21 // 依次输出函数名称、rip离函数起始处的偏移量、函数执行的rip
22 printk("function:%s() \t(+) %04d address:%#018lx\n", &str[kallsyms_names_index[index]], addr - kallsyms_address[index], addr);
23 return 0;
24 }
25 else
26 return -1;
27 }
28
29 /**
30 * @brief 追溯内核栈调用情况
31 *
32 * @param regs 内核栈结构体
33 */
traceback(struct pt_regs * regs)34 void traceback(struct pt_regs *regs)
35 {
36 // 先检验是否为用户态出错,若为用户态出错,则直接返回
37 if (verify_area(regs->rbp, 0))
38 {
39 printk_color(YELLOW, BLACK, "Kernel traceback: Fault in userland. pid=%ld, rbp=%#018lx\n", current_pcb->pid, regs->rbp);
40 return;
41 }
42
43 uint64_t *rbp = (uint64_t *)regs->rbp;
44 printk_color(YELLOW, BLACK, "======== Kernel traceback =======\n");
45 // printk("&kallsyms_address:%#018lx,kallsyms_address:%#018lx\n", &kallsyms_address, kallsyms_address);
46 // printk("&kallsyms_syms_num:%#018lx,kallsyms_syms_num:%d\n", &kallsyms_num, kallsyms_num);
47 // printk("&kallsyms_index:%#018lx\n", &kallsyms_names_index);
48 // printk("&kallsyms_names:%#018lx,kallsyms_names:%s\n", &kallsyms_names, &kallsyms_names);
49
50 uint64_t ret_addr = regs->rip;
51 // 最大追踪10层调用栈
52 for (int i = 0; i < 10; ++i)
53 {
54 if (lookup_kallsyms(ret_addr, i) != 0)
55 break;
56
57 // 当前栈帧的rbp的地址大于等于内核栈的rbp的时候,表明调用栈已经到头了,追踪结束。
58 // 当前rbp的地址为用户空间时,直接退出
59 if((uint64_t)(rbp) >= current_pcb->thread->rbp || ((uint64_t)rbp<regs->rsp))
60 break;
61
62 printk_color(ORANGE, BLACK, "rbp:%#018lx,*rbp:%#018lx\n", rbp, *rbp);
63
64 // 由于x86处理器在执行call指令时,先将调用返回地址压入栈中,然后再把函数的rbp入栈,最后将rsp设为新的rbp。
65 // 因此,此处的rbp就是上一层的rsp,那么,*(rbp+1)得到的就是上一层函数的返回地址
66 ret_addr = *(rbp + 1);
67 rbp = (uint64_t *)(*rbp);
68 printk("\n");
69 }
70 printk_color(YELLOW, BLACK, "======== Kernel traceback end =======\n");
71 }