Skip to content

Commit a943d10

Browse files
committed
修复调用栈回溯打印不完整的问题
1 parent 082a558 commit a943d10

File tree

1 file changed

+124
-27
lines changed

1 file changed

+124
-27
lines changed

src/arch/x86_64/backtrace.c

Lines changed: 124 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "limine.h"
44
#include "mem/heap.h"
55
#include "ptrace.h"
6+
#include "task/task.h"
67
#include "term/klog.h"
78

89
typedef struct {
@@ -14,15 +15,90 @@ LIMINE_REQUEST struct limine_kernel_file_request kfile_request = {
1415
.id = LIMINE_KERNEL_FILE_REQUEST,
1516
};
1617
extern char _kernel_start[];
17-
static ksym_t static_ksyms[8192];
1818
ksym_t *kallsyms = NULL;
1919
size_t kallsyms_num = 0;
2020
void *eh_frame_start = NULL;
2121
size_t eh_frame_size = 0;
22+
static uint64_t kernel_text_start = 0;
23+
static uint64_t kernel_text_end = 0;
24+
25+
const char *kallsyms_lookup(uint64_t addr, uint64_t *sym_addr);
26+
27+
static bool addr_in_kernel_text(uint64_t addr) {
28+
if (kernel_text_start && kernel_text_end) {
29+
return addr >= kernel_text_start && addr < kernel_text_end;
30+
}
31+
return addr >= 0xffffffff80000000UL && addr < 0xfffffffffffff000UL;
32+
}
33+
34+
static void get_stack_bounds(uint64_t rsp, uint64_t *stack_low, uint64_t *stack_high) {
35+
tcb_t task = get_current_task();
36+
if (task != NULL) {
37+
uint64_t k_low = (uint64_t)task;
38+
uint64_t k_high = task->context.kernel_stack;
39+
if (k_high == 0) { k_high = k_low + STACK_SIZE; }
40+
if (rsp >= k_low && rsp < k_high) {
41+
*stack_low = k_low;
42+
*stack_high = k_high;
43+
return;
44+
}
45+
46+
if (task->syscall_stack != 0) {
47+
uint64_t s_high = task->syscall_stack;
48+
uint64_t s_low = s_high - MAX_STACK_SIZE;
49+
if (rsp >= s_low && rsp < s_high) {
50+
*stack_low = s_low;
51+
*stack_high = s_high;
52+
return;
53+
}
54+
}
55+
56+
if (task->signal_stack != 0) {
57+
uint64_t s_high = task->signal_stack;
58+
uint64_t s_low = s_high - STACK_SIZE;
59+
if (rsp >= s_low && rsp < s_high) {
60+
*stack_low = s_low;
61+
*stack_high = s_high;
62+
return;
63+
}
64+
}
65+
}
66+
67+
*stack_low = rsp;
68+
*stack_high = rsp + MAX_STACK_SIZE;
69+
}
70+
71+
static int backtrace_from_rbp(uint64_t rbp, uint64_t stack_low, uint64_t stack_high,
72+
int max_frames) {
73+
int count = 0;
74+
uint64_t sym_addr = 0;
75+
76+
while (count < max_frames) {
77+
if (rbp < stack_low || rbp + 16 > stack_high) { break; }
78+
79+
uint64_t next_rbp = *(uint64_t *)rbp;
80+
uint64_t ret_addr = *((uint64_t *)rbp + 1);
81+
82+
if (!addr_in_kernel_text(ret_addr)) { break; }
83+
84+
const char *name = kallsyms_lookup(ret_addr, &sym_addr);
85+
if (name) {
86+
printk(" [<0x%lx>] %s+0x%lx\n", ret_addr, name, ret_addr - sym_addr);
87+
} else {
88+
printk(" [<0x%lx>] ???\n", ret_addr);
89+
}
90+
count++;
91+
92+
if (next_rbp <= rbp) { break; }
93+
rbp = next_rbp;
94+
}
95+
96+
return count;
97+
}
2298

2399
static int ksym_cmp(const void *a, const void *b) {
24-
const ksym_t *sym_a = (const ksym_t *)a;
25-
const ksym_t *sym_b = (const ksym_t *)b;
100+
const ksym_t *sym_a = a;
101+
const ksym_t *sym_b = b;
26102

27103
if (sym_a->addr < sym_b->addr) return -1;
28104
if (sym_a->addr > sym_b->addr) return 1;
@@ -64,17 +140,22 @@ void kallsyms_init_from_elf() {
64140
eh_frame_size = shdrs[i].sh_size;
65141
break;
66142
}
143+
if (strcmp(sec_name, ".text") == 0) {
144+
kernel_text_start = shdrs[i].sh_addr;
145+
kernel_text_end = shdrs[i].sh_addr + shdrs[i].sh_size;
146+
break;
147+
}
148+
default:break;
67149
}
68150
}
69151

70-
size_t num_symbols = symtabsz / sizeof(Elf64_Sym);
152+
const size_t num_symbols = symtabsz / sizeof(Elf64_Sym);
71153

72154
kallsyms = calloc(num_symbols, sizeof(ksym_t));
73155

74156
for (size_t i = 0; i < num_symbols; i++) {
75157
Elf64_Sym *sym = &symtab[i];
76158
char *sym_name = &strtab[sym->st_name];
77-
uint64_t bind = ELF64_ST_BIND(sym->st_info);
78159
uint64_t type = ELF64_ST_TYPE(sym->st_info);
79160
if (sym->st_shndx == SHN_UNDEF) continue;
80161
if (type == STT_FUNC) {
@@ -107,7 +188,7 @@ const char *kallsyms_lookup(uint64_t addr, uint64_t *sym_addr) {
107188
}
108189

109190
void print_kernel_backtrace(struct interrupt_frame *frame, uint64_t saved_rbp) {
110-
printk("Call Trace (stack scanning):\n");
191+
printk("Call Trace:\n");
111192

112193
uint64_t sym_addr = 0;
113194
const char *name = kallsyms_lookup(frame->rip, &sym_addr);
@@ -117,29 +198,45 @@ void print_kernel_backtrace(struct interrupt_frame *frame, uint64_t saved_rbp) {
117198
printk(" [<0x%lx>] ??? (RIP)\n", frame->rip);
118199
}
119200

120-
// 从 RSP 开始向上扫描栈(限制范围防止越界)
121-
uint64_t *stack = (uint64_t *)frame->rsp;
122-
const uint64_t stack_top = frame->rsp + 0x2000; // 扫描最多 8KB
123-
int count = 0;
124-
const int max_frames = 20;
125-
126-
for (uint64_t *p = stack; p < (uint64_t *)stack_top && count < max_frames; p++) {
127-
uint64_t candidate = *p;
128-
129-
// 合法内核地址范围(根据你的链接脚本)
130-
if (candidate >= 0xffffffff80000000UL && candidate < 0xfffffffffffff000UL) {
131-
// 检查是否对齐(指令地址通常是 16 字节对齐)
132-
if ((candidate & 0xF) == 0) {
133-
const char *name = kallsyms_lookup(candidate, &sym_addr);
134-
if (name) {
135-
printk(" [<0x%lx>] %s+0x%lx\n", candidate, name, candidate - sym_addr);
136-
} else {
137-
printk(" [<0x%lx>] ???\n", candidate);
138-
}
139-
count++;
201+
const int max_frames = 20;
202+
int count = 0;
203+
204+
uint64_t stack_low = 0;
205+
uint64_t stack_high = 0;
206+
get_stack_bounds(frame->rsp, &stack_low, &stack_high);
207+
208+
if (saved_rbp >= stack_low && saved_rbp + 16 <= stack_high) {
209+
uint64_t rbp = 0;
210+
uint64_t ret = *((uint64_t *)saved_rbp + 1);
211+
if (ret == frame->rip) {
212+
rbp = *(uint64_t *)saved_rbp; // handler 栈帧,取中断前的 RBP
213+
} else {
214+
rbp = saved_rbp; // saved_rbp 本身就是中断前的 RBP
215+
}
216+
if (rbp >= stack_low && rbp + 16 <= stack_high) {
217+
count = backtrace_from_rbp(rbp, stack_low, stack_high, max_frames);
218+
}
219+
}
220+
221+
if (count == 0) {
222+
uint64_t start_rsp = frame->rsp;
223+
if (start_rsp < stack_low || start_rsp >= stack_high) { start_rsp = stack_low; }
224+
225+
for (uint64_t *p = (uint64_t *)start_rsp;
226+
(uint64_t)p + sizeof(uint64_t) <= stack_high && count < max_frames; p++) {
227+
const uint64_t candidate = *p;
228+
229+
if (!addr_in_kernel_text(candidate)) { continue; }
230+
231+
const char *name = kallsyms_lookup(candidate, &sym_addr);
232+
if (name) {
233+
printk(" [<0x%lx>] %s+0x%lx\n", candidate, name, candidate - sym_addr);
234+
} else {
235+
printk(" [<0x%lx>] ???\n", candidate);
140236
}
237+
count++;
141238
}
142239
}
143240

144-
if (count == 0) { printk(" (no valid return addresses found on stack)\n"); }
241+
if (count == 0) { printk(" (no valid return addresses found)\n"); }
145242
}

0 commit comments

Comments
 (0)