3d712c04db4d97531d5af52064500709e90b71cd
[lunaix-os.git] / lunaix-os / kernel / debug / trace.c
1 #include <lunaix/mm/page.h>
2 #include <lunaix/mm/vmm.h>
3 #include <lunaix/process.h>
4 #include <lunaix/spike.h>
5 #include <lunaix/syslog.h>
6 #include <lunaix/trace.h>
7
8 #include <sys/cpu.h>
9 #include <sys/mm/mempart.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(PG_ALIGNED(mod->start));
27
28             ptr_t end = ROUNDUP(mod->end, PG_SIZE);
29             ptr_t ksym_va =
30               (ptr_t)vmap(mod->start, (end - mod->start), PG_PREM_R, 0);
31
32             assert(ksym_va);
33             trace_ctx.ksym_table = (struct ksyms*)ksym_va;
34         }
35     }
36 }
37
38 struct ksym_entry*
39 trace_sym_lookup(ptr_t addr)
40 {
41     int c = trace_ctx.ksym_table->ksym_count;
42     struct ksym_entry* ksent = trace_ctx.ksym_table->syms;
43
44     int i = c - 1, j = 0, m = 0;
45
46     if (addr > ksent[i].pc || addr < ksent[j].pc || addr < KERNEL_EXEC) {
47         return NULL;
48     }
49
50     while (i - j != 1) {
51         m = (i + j) / 2;
52         if (ksent[m].pc > addr) {
53             i = m;
54         } else if (ksent[m].pc < addr) {
55             j = m;
56         } else {
57             break;
58         }
59     }
60
61     struct ksym_entry* result = &ksent[MIN(i, j)];
62     if (result->pc > addr) {
63         return NULL;
64     }
65
66     return result;
67 }
68
69 static char*
70 ksym_getstr(struct ksym_entry* sym)
71 {
72     if (!sym) {
73         return "???";
74     }
75
76     return (char*)((ptr_t)trace_ctx.ksym_table +
77                    trace_ctx.ksym_table->ksym_label_off + sym->label_off);
78 }
79
80 int
81 trace_walkback(struct trace_record* tb_buffer,
82                ptr_t fp,
83                int limit,
84                ptr_t* last_fp)
85 {
86     ptr_t* frame = (ptr_t*)fp;
87     struct ksym_entry* current = NULL;
88     int i = 0;
89
90     while (frame && i < limit) {
91         ptr_t pc = *(frame + 1);
92
93         current = trace_sym_lookup(pc);
94         tb_buffer[i] = (struct trace_record){ .pc = current ? current->pc : pc,
95                                               .symbol = ksym_getstr(current) };
96
97         frame = (ptr_t*)*frame;
98         i++;
99     }
100
101     if (last_fp) {
102         *last_fp = (ptr_t)frame;
103     }
104
105     return i;
106 }
107
108 void
109 trace_printstack_of(ptr_t fp)
110 {
111     struct trace_record tbs[NB_TRACEBACK];
112
113     int n = trace_walkback(tbs, fp, NB_TRACEBACK, &fp);
114
115     if (fp) {
116         kprintf(KDEBUG "...<truncated>\n");
117     }
118
119     for (int i = 0; i < n; i++) {
120         kprintf(KDEBUG "%p: %s\n", tbs[i].pc, tbs[i].symbol);
121     }
122 }
123
124 void
125 trace_printstack()
126 {
127     trace_printstack_of(cpu_get_fp());
128 }
129
130 static void
131 trace_printswctx(const isr_param* p, char* direction)
132 {
133
134     struct ksym_entry* sym = trace_sym_lookup(p->execp->eip);
135
136     kprintf(KDEBUG ">> (sw:%s) iv:%d, errno:%p <<\n",
137             direction,
138             p->execp->vector,
139             p->execp->err_code);
140     kprintf(KDEBUG "%p:%s\n", p->execp->eip, ksym_getstr(sym));
141 }
142
143 void
144 trace_printstack_isr(const isr_param* isrm)
145 {
146     isr_param* p = isrm;
147     ptr_t fp = cpu_get_fp();
148     int prev_fromusr = uspace_context(p);
149
150     kprintf(KDEBUG "\n");
151     kprintf(KDEBUG "stack trace (pid=%d)\n", __current->pid);
152
153     trace_printstack_of(fp);
154
155     while (p) {
156         if (!prev_fromusr) {
157             if (uspace_context(p)) {
158                 trace_printswctx(p, "s/u");
159             } else {
160                 trace_printswctx(p, "s/s");
161             }
162         } else {
163             trace_printswctx(p, "u/s");
164         }
165
166         fp = saved_fp(p);
167         trace_printstack_of(fp);
168
169         prev_fromusr = uspace_context(p);
170
171         p = p->execp->saved_prev_ctx;
172     }
173     kprintf(KDEBUG "\n");
174 }