173b1cd09d0d14b57d60d748f4297b011ff87d12
[lunaix-os.git] / lunaix-os / kernel / debug / trace.c
1 #include <lunaix/mm/page.h>
2 #include <lunaix/process.h>
3 #include <lunaix/spike.h>
4 #include <lunaix/syslog.h>
5 #include <lunaix/trace.h>
6
7 #include <sys/abi.h>
8 #include <sys/mm/mm_defs.h>
9 #include <sys/trace.h>
10
11 #include <klibc/string.h>
12
13 #define NB_TRACEBACK 16
14
15 LOG_MODULE("TRACE")
16
17 static struct trace_context trace_ctx;
18
19 void
20 trace_modksyms_init(struct boot_handoff* bhctx)
21 {
22     struct boot_modent* modents = bhctx->mods.entries;
23     for (size_t i = 0; i < bhctx->mods.mods_num; i++) {
24         struct boot_modent* mod = &bhctx->mods.entries[i];
25         if (streq(mod->str, "modksyms")) {
26             assert(!va_offset(mod->start));
27
28             pte_t pte = mkpte(mod->start, KERNEL_DATA);
29             size_t n = pfn(mod->end) - pfn(mod->start);
30             
31             ptr_t ksym_va = vmap_leaf_ptes(pte, n);
32
33             assert(ksym_va);
34             trace_ctx.ksym_table = (struct ksyms*)ksym_va;
35         }
36     }
37 }
38
39 struct ksym_entry*
40 trace_sym_lookup(ptr_t addr)
41 {
42     int c = trace_ctx.ksym_table->ksym_count;
43     struct ksym_entry* ksent = trace_ctx.ksym_table->syms;
44
45     int i = c - 1, j = 0, m = 0;
46
47     if (addr > ksent[i].pc || addr < ksent[j].pc || !kernel_addr(addr)) {
48         return NULL;
49     }
50
51     while (i - j != 1) {
52         m = (i + j) / 2;
53         if (ksent[m].pc > addr) {
54             i = m;
55         } else if (ksent[m].pc < addr) {
56             j = m;
57         } else {
58             break;
59         }
60     }
61
62     struct ksym_entry* result = &ksent[MIN(i, j)];
63     if (result->pc > addr) {
64         return NULL;
65     }
66
67     return result;
68 }
69
70 static char*
71 ksym_getstr(struct ksym_entry* sym)
72 {
73     if (!sym) {
74         return "???";
75     }
76
77     return (char*)((ptr_t)trace_ctx.ksym_table +
78                    trace_ctx.ksym_table->ksym_label_off + sym->label_off);
79 }
80
81 static inline bool valid_fp(ptr_t ptr) {
82     ptr_t start = ROUNDUP(current_thread->kstack - KSTACK_SIZE, MEM_PAGE);
83
84     return (start < ptr && ptr < current_thread->kstack) 
85            || arch_valid_fp(ptr);
86 }
87
88 int
89 trace_walkback(struct trace_record* tb_buffer,
90                ptr_t fp,
91                int limit,
92                ptr_t* last_fp)
93 {
94     ptr_t* frame = (ptr_t*)fp;
95     struct ksym_entry* current = NULL;
96     int i = 0;
97
98     while (valid_fp((ptr_t)frame) && i < limit) {
99         ptr_t pc = abi_get_retaddrat((ptr_t)frame);
100
101         current = trace_sym_lookup(pc);
102         tb_buffer[i] =
103           (struct trace_record){ .pc = pc,
104                                  .sym_pc = current ? current->pc : 0,
105                                  .symbol = ksym_getstr(current) };
106
107         frame = (ptr_t*)*frame;
108         i++;
109     }
110
111     if (!valid_fp((ptr_t)frame)) {
112         frame = NULL;
113     }
114
115     if (last_fp) {
116         *last_fp = (ptr_t)frame;
117     }
118
119     return i;
120 }
121
122 static inline void
123 trace_print_code_entry(ptr_t sym_pc, ptr_t inst_pc, char* sym)
124 {
125     if (sym_pc) {
126         DEBUG("%p+%p: %s", sym_pc, inst_pc - sym_pc, sym);
127     } else {
128         DEBUG("%p+%p: %s", inst_pc, sym_pc, sym);
129     }
130 }
131
132 void
133 trace_printstack_of(ptr_t fp)
134 {
135     struct trace_record tbs[NB_TRACEBACK];
136
137     // Let's get our Stackwalker does his job ;)
138     int n = trace_walkback(tbs, fp, NB_TRACEBACK, &fp);
139
140     if (fp) {
141         DEBUG("...<truncated>");
142     }
143
144     for (int i = 0; i < n; i++) {
145         struct trace_record* tb = &tbs[i];
146         trace_print_code_entry(tb->sym_pc, tb->pc, tb->symbol);
147     }
148 }
149
150 void
151 trace_printstack()
152 {
153     if (current_thread) {
154         trace_printstack_isr(current_thread->intr_ctx);
155     }
156     else {
157         trace_printstack_of(abi_get_callframe());
158     }
159 }
160
161 static void
162 trace_printswctx(const isr_param* p, bool from_usr, bool to_usr)
163 {
164
165     struct ksym_entry* sym = trace_sym_lookup(p->execp->eip);
166
167     DEBUG("^^^^^ --- %s", to_usr ? "user" : "kernel");
168     DEBUG("  interrupted on #%d, ecode=%p",
169           p->execp->vector,
170           p->execp->err_code);
171     DEBUG("vvvvv --- %s", from_usr ? "user" : "kernel");
172
173     ptr_t sym_pc = sym ? sym->pc : p->execp->eip;
174     trace_print_code_entry(sym_pc, p->execp->eip, ksym_getstr(sym));
175 }
176
177 void
178 trace_printstack_isr(const isr_param* isrm)
179 {
180     isr_param* p = isrm;
181     ptr_t fp = abi_get_callframe();
182     int prev_usrctx = 0;
183
184     DEBUG("stack trace (pid=%d)\n", __current->pid);
185
186     trace_printstack_of(fp);
187
188     while (p) {
189         if (!prev_usrctx) {
190             if (!kernel_context(p)) {
191                 trace_printswctx(p, true, false);
192             } else {
193                 trace_printswctx(p, false, false);
194             }
195         } else {
196             trace_printswctx(p, false, true);
197         }
198
199         fp = saved_fp(p);
200         if (!valid_fp(fp)) {
201             DEBUG("??? invalid frame: %p", fp);
202             break;
203         }
204
205         trace_printstack_of(fp);
206
207         prev_usrctx = !kernel_context(p);
208
209         p = p->execp->saved_prev_ctx;
210     }
211
212     DEBUG("----- [trace end] -----\n");
213 }