]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/ia32/jdb_bt-ia32-ux.cpp
update
[l4.git] / kernel / fiasco / src / jdb / ia32 / jdb_bt-ia32-ux.cpp
1 IMPLEMENTATION[ia32,amd64,ux]:
2
3 #include <cstdio>
4 #include <cctype>
5
6 #include "config.h"
7 #include "jdb.h"
8 #include "jdb_input.h"
9 #include "jdb_kobject.h"
10 #include "jdb_lines.h"
11 #include "jdb_module.h"
12 #include "jdb_symbol.h"
13 #include "mem_layout.h"
14 #include "keycodes.h"
15 #include "thread_object.h"
16 #include "task.h"
17
18 class Jdb_bt : public Jdb_module, public Jdb_input_task_addr
19 {
20 public:
21   Jdb_bt() FIASCO_INIT;
22 private:
23   static char     dummy;
24   static char     first_char;
25   static char     first_char_addr;
26   static Address  addr;
27   static Thread * tid;
28   static Kobject *ko_tid;
29   static Space *  task;
30 };
31
32 char      Jdb_bt::dummy;
33 char      Jdb_bt::first_char;
34 char      Jdb_bt::first_char_addr;
35 Address   Jdb_bt::addr;
36 Thread *  Jdb_bt::tid;
37 Space    *Jdb_bt::task;
38 Kobject *Jdb_bt::ko_tid;
39
40 // determine the user level ebp and eip considering the current thread state
41 static void
42 Jdb_bt::get_user_eip_ebp(Address &eip, Address &ebp)
43 {
44   if (!task)
45     {
46       // kernel thread doesn't execute user code -- at least we hope so :-)
47       ebp = eip = 0;
48       return;
49     }
50
51   Thread *t        = tid;
52   Address tcb_next = (Address)context_of(t->get_kernel_sp()) + Context::size;
53   Mword *ktop      = (Mword *)(Cpu::stack_align(tcb_next));
54   Jdb::Guessed_thread_state state = Jdb::guess_thread_state(t);
55
56   eip = ktop[-5];
57
58   if (state == Jdb::s_ipc)
59     {
60       // If thread is in IPC, EBP lays on the stack (see C-bindings). EBP
61       // location is by now dependent from ipc-type, maybe different for
62       // other syscalls, maybe unstable during calls but only for user EBP.
63       Mword entry_esp = ktop[-2];
64       Mword entry_ss  = ktop[-1];
65
66       if (entry_ss & 3)
67         {
68           // kernel entered from user level
69           if (eip >= Mem_layout::Syscalls)
70             {
71               if ((entry_esp & (sizeof(Mword)-1))
72                   || !Jdb::peek((Address*)entry_esp, task, eip))
73                 {
74                   printf("\n esp page invalid");
75                   ebp = eip = 0;
76                   return;
77                 }
78               entry_esp += sizeof(Mword);
79             }
80
81           if ((entry_esp & (sizeof(Mword)-1))
82               ||!Jdb::peek((Mword*)entry_esp, task, ebp))
83             {
84               printf("\n esp page invalid");
85               ebp = eip = 0;
86               return;
87             }
88         }
89     }
90   else if (state == Jdb::s_pagefault)
91     {
92       // see pagefault handler gate stack layout
93       ebp = ktop[-6];
94     }
95   else if (state == Jdb::s_slowtrap)
96     {
97       // see slowtrap handler gate stack layout
98       ebp = ktop[-13];
99     }
100   else
101     {
102       // Thread is doing (probaly) no IPC currently so we guess the
103       // user ebp by following the kernel ebp upwards. Some kernel
104       // entry pathes (e.g. timer interrupt) push the ebp register
105       // like gcc.
106       ebp = get_user_ebp_following_kernel_stack();
107     }
108
109 }
110
111 static Mword
112 Jdb_bt::get_user_ebp_following_kernel_stack()
113 {
114   if (!Config::Have_frame_ptr)
115     return 0;
116
117   Mword ebp, dummy;
118
119   get_kernel_eip_ebp(dummy, dummy, ebp);
120
121   for (int i=0; i<30 /* sanity check */; i++)
122     {
123       Mword m1, m2;
124
125       if (  (ebp == 0) || (ebp & (sizeof(Mword)-1))
126           || !Jdb::peek((Address*)ebp, 0 /*kernel*/, m1)
127           || !Jdb::peek((Address*)ebp+1, 0 /*kernel*/, m2))
128         // invalid ebp -- leaving
129         return 0;
130
131       ebp = m1;
132
133       if (!Mem_layout::in_kernel_code(m2))
134         {
135           if (m2 < Kmem::mem_user_max)
136             // valid user ebp found
137             return m1;
138           else
139             // invalid ebp
140             return 0;
141         }
142     }
143
144   return 0;
145 }
146
147 struct Is_current 
148 {
149   Thread *tid;
150   mutable Thread *c;
151   mutable unsigned cpu;
152
153   void operator () (unsigned _cpu) const
154   {
155     Thread *t = Jdb::get_thread(_cpu);
156     if (t == tid)
157       { c = t; cpu = _cpu; }
158   }
159
160 };
161
162 static void
163 Jdb_bt::get_kernel_eip_ebp(Mword &eip1, Mword &eip2, Mword &ebp)
164 {
165   if (tid == Jdb::get_current_active())
166     {
167       ebp  = (Mword)__builtin_frame_address(3);
168       eip1 = eip2 = 0;
169     }
170   else
171     {
172       Is_current is_current;
173
174       is_current.tid = tid;
175       is_current.c = 0;
176       is_current.cpu = 0;
177
178       Jdb::foreach_cpu(is_current);
179
180       Mword *ksp;
181       Mword tcb;
182
183       if (is_current.c)
184         {
185           ksp = (Mword*)Jdb::entry_frame.cpu(is_current.cpu)->sp();
186           tcb = (Mword)is_current.c;
187           printf("\n current on cpu %u\n", is_current.cpu);
188         }
189       else
190         {
191           ksp = (Mword*) tid->get_kernel_sp();
192           tcb  = Mword(tid); //Mem_layout::Tcbs + tid.gthread()*Context::size;
193         }
194
195       Mword tcb_next = tcb + Context::size;
196
197       // search for valid ebp/eip
198       for (int i=0; (Address)(ksp+i+1)<tcb_next-20; i++)
199         {
200           if (Mem_layout::in_kernel_code(ksp[i+1]) &&
201               ksp[i] >= tcb+0x180 && 
202               ksp[i] <  tcb_next-20 &&
203               ksp[i] >  (Address)(ksp+i))
204             {
205               // valid frame pointer found
206               ebp  = ksp[i  ];
207               eip1 = ksp[i+1];
208               eip2 = ksp[0]; 
209               return;
210             }
211         }
212       ebp = eip1 = eip2 = 0;
213     }
214 }
215
216 /** Show one backtrace item we found. Add symbol name and line info */
217 static void
218 Jdb_bt::show_item(int nr, Address ksp, Address addr, Address_type user)
219 {
220   char buffer[74];
221
222   printf(" %s#%d "L4_PTR_FMT" "L4_PTR_FMT"", nr<10 ? " ": "", nr, ksp, addr);
223
224   Address sym_addr = addr;
225   if (Jdb_symbol::match_addr_to_symbol_fuzzy(&sym_addr, 
226                                              user == ADDR_KERNEL ? 0 : task, 
227                                              buffer,
228                                              56 < sizeof(buffer) 
229                                                     ? 56 : sizeof(buffer))
230       // if the previous symbol is to far away assume that there is no
231       // symbol for that entry
232       && (addr-sym_addr < 1024))
233     {
234       printf(" : %s", buffer);
235       if (addr-sym_addr)
236         printf(" %s+ 0x%lx\033[m", Jdb::esc_line, addr-sym_addr);
237     }
238
239   // search appropriate line backwards starting from addr-1 because we
240   // don't want to see the line info for the next statement after the
241   // call but the line info for the call itself
242   Address line_addr = addr-1;
243   if (Jdb_lines::match_addr_to_line_fuzzy(&line_addr, 
244                                           user == ADDR_KERNEL ? 0 : task,
245                                           buffer, sizeof(buffer)-1, 0)
246       // if the previous line is to far away assume that there is no
247       // line for that entry
248       && (addr-line_addr < 128))
249     printf("\n%6s%s%s\033[m", "", Jdb::esc_line, buffer);
250
251   putchar('\n');
252 }
253
254 static void
255 Jdb_bt::show_without_ebp()
256 {
257   Mword *ksp      = (Mword*) tid->get_kernel_sp();
258   Mword tcb_next  = Mword(tid) + Context::size;
259
260   // search for valid eip
261   for (int i=0, j=1; (Address)(ksp+i)<tcb_next-20; i++)
262     {
263       if (Mem_layout::in_kernel_code(ksp[i])) 
264         show_item(j++, (Address)(ksp+i), ksp[i], ADDR_KERNEL);
265     }
266 }
267
268 static void
269 Jdb_bt::show(Mword ebp, Mword eip1, Mword eip2, Address_type user)
270 {
271   for (int i=0; i<40 /*sanity check*/; i++)
272     {
273       Mword m1, m2;
274
275       if (i > 1)
276         {
277           if (  (ebp == 0) || (ebp & (sizeof(Mword)-1))
278               || !Jdb::peek((Address*)ebp, task, m1)
279               || !Jdb::peek((Address*)ebp+1, task, m2))
280             // invalid ebp -- leaving
281             return;
282
283           ebp = m1;
284
285           if (  (user==ADDR_KERNEL && !Mem_layout::in_kernel_code(m2))
286               ||(user==ADDR_USER   && (m2==0 || m2>Kmem::mem_user_max)))
287             // no valid eip found -- leaving
288             return;
289         }
290       else if (i == 1)
291         {
292           if (eip1 == 0)
293             continue;
294           m2 = eip1;
295         }
296       else
297         {
298           if (eip2 == 0)
299             continue;
300           m2 = eip2;
301         }
302
303       show_item(i, ebp, m2, user);
304     }
305 }
306
307 PUBLIC
308 Jdb_module::Action_code
309 Jdb_bt::action(int cmd, void *&args, char const *&fmt, int &next_char)
310 {
311   if (cmd == 0)
312     {
313       Address eip, ebp;
314
315       if (args == &dummy)
316         {
317           // default value for thread
318           tid  = Jdb::get_current_active();
319           fmt  = "%C";
320           args = &first_char;
321           return EXTRA_INPUT;
322         }
323       else if (args == &first_char)
324         {
325           if (first_char == 't')
326             {
327               putstr("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\033[K");
328               fmt  = " thread=%q";
329               args = &ko_tid;
330               return EXTRA_INPUT;
331             }
332           else if (first_char == 'a')
333             {
334               putstr("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\033[K");
335               fmt  = " addr=%C";
336               args = &Jdb_input_task_addr::first_char;
337               return EXTRA_INPUT;
338             }
339           else if (first_char != KEY_RETURN && first_char != ' ')
340             {
341               // ignore wrong input
342               fmt  = "%C";
343               return EXTRA_INPUT;
344             }
345           else
346             // backtrace from current thread
347             goto start_backtrace;
348         }
349       else if (args == &ko_tid)
350         {
351             {
352               tid = 0;
353               Kobject* o = ko_tid;
354
355               if (o)
356                 tid = Kobject::dcast<Thread_object*>(o);
357
358               if (!tid)
359                 {
360                   puts(" Invalid thread id");
361                   return NOTHING;
362                 }
363             }
364
365 start_backtrace:
366           task = tid->space();
367           get_user_eip_ebp(eip, ebp);
368
369 start_backtrace_known_ebp:
370           printf("\n\nbacktrace (thread %lx, fp="L4_PTR_FMT
371                  ", pc="L4_PTR_FMT"):\n",
372               tid->dbg_info()->dbg_id(), ebp, eip);
373           if (task != 0)
374             show(ebp, eip, 0, ADDR_USER);
375           if (!Config::Have_frame_ptr)
376             {
377               puts("\n --kernel-bt-follows-- "
378                    "(don't trust w/o frame pointer!!)");
379               task = 0;
380               show_without_ebp();
381             }
382           else
383             {
384               Mword eip2;
385               puts("\n --kernel-bt-follows--");
386               get_kernel_eip_ebp(eip, eip2, ebp);
387               task = 0;
388               show(ebp, eip, eip2, ADDR_KERNEL);
389             }
390           putchar('\n');
391         }
392       else
393         {
394           Jdb_module::Action_code code;
395
396           switch ((code = Jdb_input_task_addr::action(args, fmt, next_char)))
397             {
398             case ERROR:
399               return ERROR;
400             case NOTHING:
401               task = Jdb_input_task_addr::space();
402               eip  = 0;
403               ebp  = Jdb_input_task_addr::addr();
404               goto start_backtrace_known_ebp;
405             default:
406               return code;
407             }
408         }
409     }
410   return NOTHING;
411 }
412
413 PUBLIC
414 Jdb_module::Cmd const *
415 Jdb_bt::cmds() const
416 {
417   static Cmd cs[] =
418     {
419         { 0, "bt", "backtrace", " [a]ddr/[t]hread",
420           "bt[t<threadid>][<addr>]\tshow backtrace of current/given "
421           "thread/addr",
422           &dummy },
423     };
424   return cs;
425 }
426
427 PUBLIC
428 int
429 Jdb_bt::num_cmds() const
430 {
431   return 1;
432 }
433
434 IMPLEMENT
435 Jdb_bt::Jdb_bt()
436   : Jdb_module("INFO")
437 {}
438
439 static Jdb_bt jdb_bt INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
440