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