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