]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/ux/jdb-ux.cpp
update
[l4.git] / kernel / fiasco / src / jdb / ux / jdb-ux.cpp
1 INTERFACE [ux]:
2
3 #include "types.h"
4 #include "l4_types.h"
5
6 class Trap_state;
7 class Thread;
8 class Context;
9 class Jdb_entry_frame;
10 class Mem_space;
11
12 EXTENSION class Jdb
13 {
14 public:
15   static const char * const reg_names[];
16
17   typedef enum
18     {
19       s_unknown, s_ipc, s_syscall, s_pagefault, s_fputrap,
20       s_interrupt, s_timer_interrupt, s_slowtrap, s_user_invoke,
21     } Guessed_thread_state;
22
23   enum { MIN_SCREEN_HEIGHT = 20, MIN_SCREEN_WIDTH = 80 };
24
25   template < typename T > static T peek(T const *addr, Address_type user);
26
27   static int (*bp_test_log_only)();
28   static int (*bp_test_break)(char *errbuf, size_t bufsize);
29
30 private:
31   static unsigned short rows, cols;
32
33 };
34
35 IMPLEMENTATION [ux]:
36
37 #include <cstdio>
38 #include <sys/ioctl.h>
39 #include <termios.h>
40 #include <unistd.h>
41
42 #include "globals.h"
43 #include "initcalls.h"
44 #include "jdb_core.h"
45 #include "jdb_dbinfo.h"
46 #include "jdb_screen.h"
47 #include "kernel_console.h"
48 #include "kernel_task.h"
49 #include "kernel_thread.h"
50 #include "keycodes.h"
51 #include "kmem.h"
52 #include "libc_support.h"
53 #include "logdefs.h"
54 #include "mem_layout.h"
55 #include "push_console.h"
56 #include "simpleio.h"
57 #include "space.h"
58 #include "static_init.h"
59 #include "thread.h"
60 #include "thread_state.h"
61 #include "trap_state.h"
62 #include "usermode.h"
63 #include "vkey.h"
64
65 int (*Jdb::bp_test_log_only)();
66 int (*Jdb::bp_test_break)(char *errbuf, size_t bufsize);
67
68 unsigned short Jdb::rows, Jdb::cols;
69
70 const char * const Jdb::reg_names[] =
71 { "EAX", "EBX", "ECX", "EDX", "EBP", "ESI", "EDI", "EIP", "ESP", "EFL" };
72
73 static Proc::Status jdb_irq_state;
74
75 IMPLEMENT inline
76 void
77 Jdb::enter_trap_handler(unsigned /*cpu*/)
78 {
79   conf_screen();
80
81   // Set terminal raw mode
82   enter_getchar();
83
84   // Flush all output streams
85   fflush (NULL);
86 }
87
88 IMPLEMENT inline
89 void
90 Jdb::leave_trap_handler(unsigned)
91 {
92   // Restore terminal mode
93   leave_getchar();
94
95   // Flush all output streams
96   fflush (NULL);
97
98   if (!::running)
99     signal (SIGIO, SIG_IGN);            // Ignore hardware interrupts
100 }
101
102 PROTECTED static inline
103 void
104 Jdb::monitor_address(unsigned, void *)
105 {}
106
107 IMPLEMENT inline
108 bool
109 Jdb::handle_user_request(unsigned /*cpu*/)
110 { return false; }
111
112 IMPLEMENT inline
113 bool
114 Jdb::test_checksums()
115 { return true; }
116
117
118 // disable interrupts before entering the kernel debugger
119 IMPLEMENT
120 void
121 Jdb::save_disable_irqs(unsigned cpu)
122 {
123   assert(cpu == 0);
124   jdb_irq_state = Proc::cli_save();
125 }
126
127 // restore interrupts after leaving the kernel debugger
128 IMPLEMENT
129 void
130 Jdb::restore_irqs(unsigned cpu)
131 {
132   assert(cpu == 0);
133   Proc::sti_restore(jdb_irq_state);
134 }
135
136 STATIC_INITIALIZE_P(Jdb,JDB_INIT_PRIO);
137
138 PUBLIC static FIASCO_INIT
139 void
140 Jdb::init()
141 {
142   // Install JDB handler
143   Trap_state::base_handler = (Trap_state::Handler)enter_jdb;
144
145   // be sure that Push_console comes very first
146   static Push_console c;
147   Kconsole::console()->register_console(&c, 0);
148
149   register_libc_atexit(leave_getchar);
150
151   Thread::set_int3_handler(handle_int3_threadctx);
152 }
153
154 PRIVATE
155 static void
156 Jdb::conf_screen()
157 {
158   struct winsize win;
159   ioctl (fileno (stdin), TIOCGWINSZ, &win);
160   rows = win.ws_row;
161   cols = win.ws_col;
162
163   if (rows < MIN_SCREEN_HEIGHT || cols < MIN_SCREEN_WIDTH)
164     printf ("%sTerminal probably too small, should be at least %dx%d!\033[0m\n",
165             esc_emph, MIN_SCREEN_WIDTH, MIN_SCREEN_HEIGHT);
166
167   Jdb_screen::set_height(rows);
168   Jdb_screen::set_width(cols);
169 }
170
171 /** handle int3 debug extension */
172 PUBLIC static inline NOEXPORT
173 int
174 Jdb::int3_extension()
175 {
176   Jdb_entry_frame *entry_frame = Jdb::entry_frame.cpu(0);
177   Address      addr = entry_frame->ip();
178   Address_type user = (entry_frame->cs() & 3) ? ADDR_USER : ADDR_KERNEL;
179   Unsigned8    todo = peek ((Unsigned8 *) addr, user);
180   Space *space = NULL; //get_task_id(0);
181
182   if (todo == 0x3c && peek ((Unsigned8 *) (addr+1), user) == 13)
183     {
184       enter_getchar();
185       entry_frame->_ax = Vkey::get();
186       Vkey::clear();
187       leave_getchar();
188       return 1;
189     }
190   else if (todo != 0xeb)
191     {
192       snprintf (error_buffer.cpu(0), sizeof (error_buffer.cpu(0)), "INT 3");
193       return 0;
194     }
195
196   // todo == 0xeb => enter_kdebug()
197   Mword i;
198   Mword len = peek ((Unsigned8 *) ++addr, user);
199
200   if (len > 2 &&
201       peek (((Unsigned8 *) addr + 1), user) == '*' &&
202       peek (((Unsigned8 *) addr + 2), user) == '#')
203     {
204       char c = peek (((Unsigned8 *) addr + 3), user);
205
206       if ((c == '#')
207           ? execute_command_ni(space, (char const *) entry_frame->_ax)
208           : execute_command_ni(space, (char const *)(addr + 3), len-2))
209         return 1; // => leave Jdb
210     }
211
212   len = len < sizeof(error_buffer.cpu(0))-1 ? len : sizeof(error_buffer.cpu(0))-1;
213   for (i = 0; i < len; i++)
214     error_buffer.cpu(0)[i] = peek ((Unsigned8 *) ++addr, user);
215   error_buffer.cpu(0)[i] = 0;
216   return 0;
217 }
218
219 static
220 bool
221 Jdb::handle_special_cmds(int)
222 { return 1; }
223
224 IMPLEMENT
225 bool
226 Jdb::handle_debug_traps(unsigned cpu)
227 {
228   switch (entry_frame.cpu(cpu)->_trapno)
229     {
230       case 1:
231         snprintf (error_buffer.cpu(cpu), sizeof (error_buffer.cpu(cpu)), "Interception");
232         break;
233       case 3:
234         if (int3_extension())
235           return false;
236 #ifdef FIXME
237         if (get_thread(cpu)->d_taskno())
238           {
239             if (bp_test_log_only && bp_test_log_only())
240               return false;
241             if (bp_test_break
242                 && bp_test_break(error_buffer.cpu(cpu), sizeof(error_buffer.cpu(cpu))))
243               break;
244           }
245 #endif
246     }
247
248   return true;
249 }
250
251 IMPLEMENT
252 void
253 Jdb::handle_nested_trap(Jdb_entry_frame *e)
254 {
255   printf("Trap in JDB: IP:%08lx\n", e->ip());
256 }
257
258 IMPLEMENT inline
259 bool
260 Jdb::handle_conditional_breakpoint(unsigned /*cpu*/)
261 { return false; }
262
263
264 PUBLIC
265 static int
266 Jdb::get_register(char *reg)
267 {
268   char reg_name[4];
269   int i;
270
271   putchar(reg_name[0] = 'E');
272
273   for (i=1; i<3; i++)
274     {
275       int c = getchar();
276       if (c == KEY_ESC)
277         return false;
278       putchar(reg_name[i] = c & 0xdf);
279     }
280
281   reg_name[3] = '\0';
282
283   for (i=0; i<9; i++)
284     if (*((unsigned*)reg_name) == *((unsigned*)reg_names[i]))
285       break;
286
287   if (i==9)
288     return false;
289
290   *reg = i+1;
291   return true;
292 }
293
294
295 PUBLIC
296 static Space *
297 Jdb::translate_task(Address /*addr*/, Space *task)
298 {
299   // we have no idea if addr belongs to kernel or user space
300   // since kernel and user occupy different address spaces
301   return task;
302 }
303
304 PUBLIC
305 static Address
306 Jdb::virt_to_kvirt(Address virt, Mem_space* space)
307 {
308   Mem_space::Phys_addr phys;
309   Mem_space::Size size;
310
311   if (!space)
312     {
313       // Kernel address.
314       // We can directly access it via virtual addresses if it's kernel code
315       // (which is always mapped, but doesn't appear in the kernel pagetable)
316       //  or if we find a mapping for it in the kernel's master pagetable.
317       return (virt >= (Address)&Mem_layout::load && 
318               virt <  (Kernel_thread::init_done() 
319                                 ? (Address)&Mem_layout::end
320                                 : (Address)&Mem_layout::initcall_end)
321               || Kernel_task::kernel_task()->mem_space()->v_lookup (
322                 Mem_space::Addr::create(virt), 0, 0, 0))
323         ? virt
324         : (Address) -1;
325     }
326   else
327     {
328       // User address.
329       // We can't directly access it because it's in a different host process
330       // but if the task's pagetable has a mapping for it, we can translate
331       // task-virtual -> physical -> kernel-virtual address and then access.
332       return (space->v_lookup (Mem_space::Addr::create(virt), &phys, &size, 0))
333         ? (Address) Kmem::phys_to_virt (phys.value() + (virt & (size.value()-1)))
334         : (Address) -1;
335     }
336 }
337
338 IMPLEMENT inline NEEDS ["space.h"]
339 template <typename T>
340 T
341 Jdb::peek (T const *addr, Address_type user)
342 {
343   return current_mem_space()->peek(addr, user);
344 }
345
346 PUBLIC static
347 int
348 Jdb::peek_task(Address virt, Space *space, void *value, int width)
349 {
350   // make sure we don't cross a page boundary
351   if (virt & (width-1))
352     return -1;
353
354   Address kvirt = virt_to_kvirt(virt, space?space->mem_space():0);
355   if (kvirt == (Address)-1)
356     return -1;
357
358   memcpy(value, (void*)kvirt, width);
359   return 0;
360 }
361
362 PUBLIC static
363 int
364 Jdb::poke_task(Address virt, Space *space, void const *value, int width)
365 {
366   // make sure we don't cross a page boundary
367   if (virt & (width-1))
368     return -1;
369
370   Address kvirt = virt_to_kvirt(virt, space?space->mem_space():0);
371
372   if (kvirt == (Address)-1)
373     return -1;
374
375   memcpy((void*)kvirt, value, width);
376   return 0;
377 }
378
379 PUBLIC
380 static int
381 Jdb::is_adapter_memory(Address /*addr*/, Space * /*task*/)
382 {
383   return 0;
384 }
385
386 #define WEAK __attribute__((weak))
387 extern "C" char in_slowtrap, in_page_fault, in_handle_fputrap;
388 extern "C" char in_interrupt, in_timer_interrupt, in_timer_interrupt_slow;
389 extern "C" char i30_ret_switch WEAK, in_slow_ipc1 WEAK;
390 extern "C" char in_slow_ipc2 WEAK, in_slow_ipc4;
391 extern "C" char in_sc_ipc1 WEAK, in_sc_ipc2 WEAK, in_syscall WEAK;
392 #undef WEAK
393
394 /** Try to guess the thread state of t by walking down the kernel stack and
395  * locking at the first return address we find. */
396 PUBLIC
397 static Jdb::Guessed_thread_state
398 Jdb::guess_thread_state(Thread *t)
399 {
400   Guessed_thread_state state = s_unknown;
401   Mword *ktop = (Mword*)((Mword)context_of(t->get_kernel_sp()) +
402                          Config::thread_block_size);
403
404   for (int i=-1; i>-26; i--)
405     {
406       if (ktop[i] != 0)
407         {
408           if (ktop[i] == (Mword)&in_page_fault)
409             state = s_pagefault;
410           if ((ktop[i] == (Mword)&i30_ret_switch) ||// shortcut.S, int 0x30
411               (ktop[i] == (Mword)&in_slow_ipc1) ||  // shortcut.S, int 0x30
412               (ktop[i] == (Mword)&in_slow_ipc4) ||  // entry.S, int 0x30
413 #if !defined(CONFIG_ASSEMBLER_IPC_SHORTCUT)
414               (ktop[i] == (Mword)&in_sc_ipc1)   ||  // entry.S, int 0x30
415               (ktop[i] == (Mword)&in_sc_ipc2)   ||  // entry.S, sysenter
416 #endif
417              0)
418             state = s_ipc;
419           else if (ktop[i] == (Mword)&in_syscall)
420             state = s_syscall;
421           else if (ktop[i] == (Mword)&Thread::user_invoke)
422             state = s_user_invoke;
423           else if (ktop[i] == (Mword)&in_handle_fputrap)
424             state = s_fputrap;
425           else if (ktop[i] == (Mword)&in_interrupt)
426             state = s_interrupt;
427           else if ((ktop[i] == (Mword)&in_timer_interrupt) ||
428                    (ktop[i] == (Mword)&in_timer_interrupt_slow))
429             state = s_timer_interrupt;
430           else if (ktop[i] == (Mword)&in_slowtrap)
431             state = s_slowtrap;
432           if (state != s_unknown)
433             break;
434         }
435     }
436
437   if (state == s_unknown && (t->state() & Thread_ipc_mask))
438     state = s_ipc;
439
440   return state;
441 }
442
443 // Don't make these members of Jdb else we have to include <termios.h>
444 // into the Jdb interface ...
445 static struct termios raw, new_raw;
446 static int    getchar_entered;
447
448 /** prepare Linux console for raw input */
449 PUBLIC static
450 void
451 Jdb::enter_getchar()
452 {
453   if (!getchar_entered++)
454     {
455       tcgetattr (fileno (stdin), &raw);
456       memcpy(&new_raw, &raw, sizeof(new_raw));
457       new_raw.c_lflag    &= ~(ICANON|ECHO);
458       new_raw.c_cc[VMIN]  = 0;
459       new_raw.c_cc[VTIME] = 1;
460       tcsetattr (fileno (stdin), TCSAFLUSH, &new_raw);
461     }
462 }
463
464 /** restore Linux console. */
465 PUBLIC static
466 void
467 Jdb::leave_getchar()
468 {
469   if (!--getchar_entered)
470     tcsetattr (fileno (stdin), TCSAFLUSH, &raw);
471 }
472
473 PROTECTED static inline
474 template< typename T >
475 void
476 Jdb::set_monitored_address(T *dest, T val)
477 { *dest = val; }
478
479 PROTECTED static inline
480 template< typename T >
481 T Jdb::monitor_address(unsigned, T volatile *addr)
482 {
483   return *addr;
484 }
485
486 //----------------------------------------------------------------------------
487 IMPLEMENTATION [ux && mp]:
488
489 static
490 void
491 Jdb::send_nmi(unsigned /*cpu*/)
492 {
493 }