]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/jdb_tcb.cpp
update
[l4.git] / kernel / fiasco / src / jdb / jdb_tcb.cpp
1 INTERFACE:
2
3 #include "l4_types.h"
4
5 class Thread;
6
7
8 //-----------------------------------------------------------------
9 IMPLEMENTATION:
10
11 #include <cstdio>
12 #include <cstring>
13
14 #include "entry_frame.h"
15 #include "jdb.h"
16 #include "jdb_disasm.h"
17 #include "jdb_handler_queue.h"
18 #include "jdb_input.h"
19 #include "jdb_kobject.h"
20 #include "jdb_kobject_names.h"
21 #include "jdb_module.h"
22 #include "jdb_screen.h"
23 #include "jdb_thread.h"
24 #include "jdb_util.h"
25 #include "kernel_console.h"
26 #include "keycodes.h"
27 #include "l4_types.h"
28 #include "push_console.h"
29 #include "simpleio.h"
30 #include "static_init.h"
31 #include "task.h"
32 #include "thread.h"
33 #include "thread_state.h"
34 #include "types.h"
35
36 IMPLEMENTATION [32bit]:
37 #define ADDR_FMT "%08lx"
38
39 IMPLEMENTATION [64bit]:
40 #define ADDR_FMT "%016lx"
41
42
43 IMPLEMENTATION:
44
45 class Jdb_tcb_ptr
46 {
47 public:
48   Jdb_tcb_ptr(Address addr = 0)
49     : _base(addr & ~(Config::thread_block_size-1)),
50       _offs(addr &  (Config::thread_block_size-1))
51   {}
52
53   Jdb_tcb_ptr(Jdb_tcb_ptr const &p)
54     : _base(p.base()), _offs(p.offs())
55   {}
56
57   inline bool valid() const
58   { return _offs <= Config::thread_block_size-sizeof(Mword); }
59
60   bool operator > (int offs) const
61   {
62     return offs < 0 ? _offs > Config::thread_block_size + offs*sizeof(Mword)
63                     : _offs > offs*sizeof(Mword);
64   }
65
66   Jdb_tcb_ptr &operator += (int offs)
67   { _offs += offs*sizeof(Mword); return *this; }
68
69   inline Address addr() const
70   { return _base + _offs; }
71
72   inline Mword value() const
73   { return *(Mword*)(_base + _offs); }
74
75   inline void value(Mword v)
76   { *(Mword*)(_base + _offs) = v; }
77
78   inline bool is_user_value() const;
79
80   inline const char *user_value_desc() const;
81
82   inline Mword top_value(int offs) const
83   { return *((Mword*)(Cpu::stack_align(_base + Config::thread_block_size)) + offs); }
84
85   inline Address base() const
86   { return _base; }
87
88   inline Address offs() const
89   { return _offs; }
90
91   inline void offs(Address offs)
92   { _offs = offs; }
93
94   inline bool is_kern_code() const
95   { return (Address)&Mem_layout::image_start <= value()
96            && value() <= (Address)&Mem_layout::ecode;  };
97
98   inline bool is_kobject() const
99   { return Kobject_dbg::is_kobj(reinterpret_cast<void *>(value())); }
100
101 private:
102   Address  _base;
103   Address  _offs;
104 };
105
106 class Jdb_disasm_view
107 {
108 public:
109   unsigned _x, _y;
110 };
111
112
113 class Jdb_stack_view
114 {
115 public:
116   bool is_current;
117   Jdb_entry_frame *ef;
118   Jdb_tcb_ptr current;
119   unsigned start_y;
120   Address absy;
121   Address addy, addx;
122   bool memdump_is_colored;
123
124   bool edit_registers();
125 };
126
127
128 class Jdb_tcb : public Jdb_module, public Jdb_kobject_handler
129 {
130   static Kobject *threadid;
131   static Address address;
132   static char    first_char;
133   static char    auto_tcb;
134
135 private:
136   static void print_return_frame_regs(Jdb_tcb_ptr const &current, Mword ksp);
137   static void print_entry_frame_regs(Space *task);
138   static void info_thread_state(Thread *t);
139
140   static Jdb_disasm_view _disasm_view;
141   static Jdb_stack_view  _stack_view;
142 };
143
144
145
146 Kobject *Jdb_tcb::threadid;
147 Address Jdb_tcb::address;
148 char    Jdb_tcb::first_char;
149 char    Jdb_tcb::auto_tcb;
150 Jdb_disasm_view Jdb_tcb::_disasm_view(Jdb_tcb::Disasm_x, Jdb_tcb::Disasm_y);
151 Jdb_stack_view  Jdb_tcb::_stack_view (Jdb_tcb::Stack_y);
152
153
154 // available from jdb_dump module
155 extern int jdb_dump_addr_task (Address addr, Space *task, int level)
156   __attribute__((weak));
157
158 PUBLIC
159 Jdb_stack_view::Jdb_stack_view(unsigned y)
160 : start_y(y), absy(0), memdump_is_colored(true)
161 {}
162
163 PUBLIC static inline
164 Mword
165 Jdb_stack_view::cols()
166 {
167   return Jdb_screen::cols() - 1;
168 }
169
170 PUBLIC static inline
171 Mword
172 Jdb_stack_view::bytes_per_line()
173 { return cols() * sizeof(Mword); }
174
175 PUBLIC
176 void
177 Jdb_stack_view::init(Address ksp, Jdb_entry_frame *_ef, bool _is_current)
178 {
179   current = Jdb_tcb_ptr(ksp);
180
181   absy = current.offs() / bytes_per_line();
182   addx = (current.offs() % bytes_per_line()) / sizeof(Mword);
183   addy = 0;
184   ef = _ef;
185   is_current = _is_current;
186 }
187
188 PUBLIC
189 void
190 Jdb_stack_view::print_value(Jdb_tcb_ptr const &p, bool highl = false)
191 {
192   if (!p.valid() || !Jdb_util::is_mapped((void const*)p.addr()))
193     {
194       printf(" %.*s", Jdb_screen::Mword_size_bmode, Jdb_screen::Mword_not_mapped);
195       return;
196     }
197
198   const char *s1="", *s2="";
199   if (highl)
200     {
201       s1 = Jdb::esc_emph;
202       s2 = JDB_ANSI_END;
203     }
204   else if (p.is_user_value())
205     {
206       s1 = Jdb::esc_iret;
207       s2 = JDB_ANSI_END;
208     }
209   else if (memdump_is_colored)
210     {
211       if (p.is_kern_code())
212         {
213           s1 = JDB_ANSI_COLOR(lightblue);
214           s2 = JDB_ANSI_END;
215         }
216       else if (p.is_kobject())
217         {
218           s1 = JDB_ANSI_COLOR(lightgreen);
219           s2 = JDB_ANSI_END;
220         }
221       /* else if (p.in_backtrace(...
222          {
223          s1 = Jdb::esc_bt;
224          s2 = "\033[m";
225          } */
226     }
227
228   printf(" %s"ADDR_FMT"%s", s1, p.value(), s2);
229 }
230
231
232 PUBLIC
233 void
234 Jdb_stack_view::dump()//Jdb_tcb_ptr const &current)
235 {
236   Jdb_tcb_ptr p = current;
237   p.offs(absy * bytes_per_line());
238
239   Jdb::cursor(start_y, 1);
240
241   for (unsigned y = 0; y < Jdb_screen::height() - start_y; ++y)
242     {
243       Kconsole::console()->getchar_chance();
244
245       if (p.valid())
246         {
247           printf("    %03lx ", p.addr() & 0xfff);
248           for (unsigned x = 0; x < cols(); ++x, p+=1)
249             print_value(p);
250           putchar('\n');
251         }
252       else
253         puts("\033[K");
254     }
255 }
256
257 PRIVATE inline
258 unsigned
259 Jdb_stack_view::posx()
260 { return addx * (Jdb_screen::Mword_size_bmode + 1) + 9; }
261
262 PRIVATE inline
263 unsigned
264 Jdb_stack_view::posy()
265 { return addy + start_y; }
266
267 PUBLIC
268 void
269 Jdb_stack_view::highlight(bool highl)
270 {
271   current.offs(absy*bytes_per_line() + addy*bytes_per_line() + addx * sizeof(Mword));
272   Jdb_tcb_ptr first_col = current;
273   first_col.offs(absy*bytes_per_line() + addy*bytes_per_line());
274
275   if (!current.valid())
276     return;
277
278   Jdb::cursor(posy(), 1);
279   if (highl)
280     printf("%08lx", current.addr() & 0xffffffff);
281   else
282     printf("    %03lx ", first_col.addr() & 0xfff);
283   Jdb::cursor(posy(), posx());
284   print_value(current, highl);
285
286   char kobj_desc[120];
287   kobj_desc[0] = 0;
288
289   if (current.is_kern_code())
290     strcpy(kobj_desc, "Kernel code"); // todo: print kernel function name
291   else if (current.is_user_value())
292     snprintf(kobj_desc, sizeof(kobj_desc), "Return frame: %s",
293              current.user_value_desc());
294   else
295     if (Kobject *o = Kobject::pointer_to_obj(reinterpret_cast<void *>(current.value())))
296       {
297         Jdb_kobject::obj_description(kobj_desc, sizeof(kobj_desc), true, o);
298         kobj_desc[sizeof(kobj_desc) - 1] = 0;
299       }
300
301   Jdb::printf_statline("tcb", "<CR>=dump <Space>=Disas",
302                        "%s", kobj_desc);
303 }
304
305 PUBLIC
306 bool
307 Jdb_stack_view::handle_key(int key, bool *redraw)
308 {
309   Mword   lines    = Jdb_screen::height() - start_y;
310   Mword   max_lines = (Config::thread_block_size + bytes_per_line() - 1)/bytes_per_line();
311   Address max_absy = max_lines - lines;
312
313   if (lines > max_lines)
314     max_absy = 0;
315
316   if (lines > max_lines - absy)
317     lines = max_lines - absy;
318
319   if (key == 'e')
320     edit_stack(redraw);
321   else
322     return Jdb::std_cursor_key(key, this->cols(), lines, max_absy,
323       &absy, &addy, &addx, redraw);
324
325   return true;
326 }
327
328 PUBLIC
329 void
330 Jdb_stack_view::edit_stack(bool *redraw)
331 {
332   if (current.valid())
333     {
334       Mword value;
335       int c;
336
337       Jdb::cursor(posy(), posx());
338       printf(" %.*s", Jdb_screen::Mword_size_bmode, Jdb_screen::Mword_blank);
339       Jdb::printf_statline("tcb",
340           is_current ? "<Space>=edit registers" : 0,
341           "edit <"ADDR_FMT"> = "ADDR_FMT,
342           current.addr(), current.value());
343
344       Jdb::cursor(posy(), posx() + 1);
345       c = Jdb_core::getchar();
346
347       if (c==KEY_ESC)
348         {
349           *redraw = true;
350           return;
351         }
352
353       if (c != ' ' || !is_current)
354         {
355           // edit memory
356           putchar(c);
357           Jdb::printf_statline("tcb", 0, "edit <"ADDR_FMT"> = "ADDR_FMT,
358               current.addr(), current.value());
359           Jdb::cursor(posy(), posx() + 1);
360           if (!Jdb_input::get_mword(&value, c, 16))
361             {
362               Jdb::cursor(posy(), posx());
363               print_value(current);
364               return;
365             }
366           else
367             current.value(value);
368         }
369       else
370         {
371           // edit registers
372           Jdb::cursor(posy(), posx());
373           print_value(current);
374           edit_registers();
375           return;
376         }
377       *redraw = true;
378     }
379 }
380
381 PUBLIC
382 Jdb_disasm_view::Jdb_disasm_view(unsigned x, unsigned y)
383 : _x(x), _y(y)
384 {}
385
386 PUBLIC
387 void
388 Jdb_disasm_view::show(Jdb_tcb_ptr const &p, Space *s)
389 {
390   if (!Jdb_disasm::avail())
391     return;
392
393   Address disass_addr = p.top_value(-5);
394   Jdb::cursor(_y, _x);
395   putstr(Jdb::esc_emph);
396   Jdb_disasm::show_disasm_line(-40, disass_addr, 0, s);
397   putstr("\033[m");
398   Jdb::cursor(_y + 1, _x);
399   Jdb_disasm::show_disasm_line(-40, disass_addr, 0, s);
400 }
401
402
403 PUBLIC
404 Jdb_tcb::Jdb_tcb()
405   : Jdb_module("INFO"), Jdb_kobject_handler(Thread::static_kobj_type)
406 {
407   static Jdb_handler enter(at_jdb_enter);
408
409   Jdb::jdb_enter.add(&enter);
410   Jdb_kobject::module()->register_handler(this);
411 }
412
413 static void
414 Jdb_tcb::at_jdb_enter()
415 {
416   if (auto_tcb)
417     {
418       // clear any keystrokes in queue
419       Jdb::set_next_cmd(0);
420       Jdb::push_cons()->push('t');
421       Jdb::push_cons()->push(' ');
422     }
423 }
424
425
426 PUBLIC virtual
427 Kobject *
428 Jdb_tcb::parent(Kobject *o)
429 {
430   Thread *t = Kobject::dcast<Thread*>(o);
431   if (!t)
432     return 0;
433
434   return static_cast<Task*>(t->space());
435 }
436
437 PRIVATE static inline
438 char *
439 Jdb_tcb::vcpu_state_str(Mword state, char *s, int len)
440 {
441   snprintf(s, len, "%c%c%c%c%c%c",
442            (state & Vcpu_state::F_fpu_enabled) ? 'F' : 'f',
443            (state & Vcpu_state::F_user_mode)   ? 'U' : 'u',
444            (state & Vcpu_state::F_debug_exc)   ? 'D' : 'd',
445            (state & Vcpu_state::F_exceptions)  ? 'E' : 'e',
446            (state & Vcpu_state::F_page_faults) ? 'P' : 'p',
447            (state & Vcpu_state::F_irqs)        ? 'I' : 'i');
448   s[len - 1] = 0;
449   return s;
450 }
451
452 PUBLIC static
453 Jdb_module::Action_code
454 Jdb_tcb::show(Thread *t, int level)
455 {
456 new_tcb:
457
458   Thread *t_current      = Jdb::get_current_active();
459   bool is_current_thread;
460   bool redraw_screen     = true;
461   Jdb_entry_frame *ef    = Jdb::get_entry_frame(Jdb::current_cpu);
462 #if 0
463   Address bt_start       = 0;
464 #endif
465
466   if (!t && !t_current)
467     {
468 #if 0
469       const Mword mask
470         = (Config::thread_block_size * Mem_layout::max_threads()) - 1;
471       const Mword tsksz = Config::thread_block_size*L4_uid::threads_per_task();
472       LThread_num task = ((Address)Jdb::get_thread() & mask) / tsksz;
473 #endif
474 #if 0
475       putchar('\n');
476       print_entry_frame_regs(0);
477 #endif
478       return NOTHING;
479     }
480
481   if (!t)
482     t = t_current;
483
484   is_current_thread = t == t_current;
485
486 #if 0
487   if (!t->is_valid())
488     {
489       puts(" Invalid thread");
490       return NOTHING;
491     }
492 #endif
493
494   if (level==0)
495     {
496       Jdb::clear_screen(Jdb::FANCY);
497       redraw_screen = false;
498     }
499
500 whole_screen:
501
502   if (redraw_screen)
503     {
504       Jdb::clear_screen(Jdb::NOFANCY);
505       redraw_screen = false;
506     }
507
508   char time_str[12];
509
510   putstr("thread: ");
511   Jdb_kobject::print_uid(t, 3);
512   print_thread_uid_raw(t);
513   printf("CPU %3u ", t->cpu());
514
515   printf("\tprio: %02x  mode: %s\n",
516          t->sched()->prio(),
517          t->mode() & Context::Periodic  ?
518          t->mode() & Context::Nonstrict ? "Per (IRT)" : "Per (SP)" : "Con");
519
520   printf("state: %03lx ", t->state());
521   t->print_state_long();
522
523   putstr("\n\nwait for: ");
524   if (!t->partner())
525     putstr("--- ");
526   else
527     Jdb_thread::print_partner(t, 4);
528
529   putstr("   polling: ");
530   Jdb_thread::print_snd_partner(t, 3);
531
532   putstr("\trcv descr: ");
533
534   if (t->state() & Thread_ipc_receiving_mask)
535     printf("%08lx", t->rcv_regs()->from_spec());
536   else
537     putstr("        ");
538
539   putstr("\n"
540          "lcked by: ");
541   Jdb_kobject::print_uid(Thread::lookup(t->thread_lock()->lock_owner()), 3);
542
543   putstr("\t\t\ttimeout  : ");
544   if (t->_timeout && t->_timeout->is_set())
545     {
546       Signed64 diff = (t->_timeout->get_timeout(Kip::k()->clock)) * 1000;
547       if (diff < 0)
548         strcpy(time_str, "over");
549       else
550         Jdb::write_ll_ns(diff, time_str,
551                          11 < sizeof(time_str)-1 ? 11 : sizeof(time_str)-1,
552                          false);
553       printf("%-13s", time_str);
554     }
555
556   putstr("\ncpu time: ");
557   Jdb::write_ll_ns(t->consumed_time()*1000, time_str,
558                    11 < sizeof(time_str) ? 11 : sizeof(time_str), false);
559   printf("%-13s", time_str);
560
561   printf("\t\ttimeslice: %llu/%llu %cs\n"
562          "pager\t: ",
563          t->sched()->left(), t->sched()->quantum(), Config::char_micro);
564   print_kobject(t, t->_pager.raw());
565
566   putstr("\ttask: ");
567   if (t->space() == Kernel_task::kernel_task())
568     putstr(" kernel        ");
569   else
570     print_kobject(static_cast<Task*>(t->space()));
571
572   putstr("\tutcb: ");
573   printf("%08lx", (Mword)t->utcb());
574
575   putstr("\nexc-hndl: ");
576   print_kobject(t, t->_exc_handler.raw());
577
578 #if 0
579   putstr("\tready  lnk: ");
580   if (t->state() & Thread_ready)
581     {
582       if (t->_ready_next)
583         Jdb_kobject::print_uid(Thread::lookup(t->_ready_next), 3);
584       else if (is_current_thread)
585         putstr(" ???.??");
586       else
587         putstr("\033[31;1m???.??\033[m");
588       if (t->_ready_prev)
589         Jdb_kobject::print_uid(Thread::lookup(t->_ready_prev), 4);
590       else if (is_current_thread)
591         putstr(" ???.??");
592       else
593         putstr(" \033[31;1m???.??\033[m");
594       putchar('\n');
595     }
596   else
597     puts("--- ---");
598 #endif
599
600   putstr("\tprsent lnk: ");
601   if (t->Present_list_item::next())
602     Jdb_kobject::print_uid(static_cast<Thread*>(t->Present_list_item::next()), 3);
603   else
604     putstr("--- ");
605   if (t->Present_list_item::prev())
606     Jdb_kobject::print_uid(static_cast<Thread*>(t->Present_list_item::prev()), 4);
607   else
608     putstr("--- ");
609   putchar('\n');
610
611   putstr("vCPU  st: ");
612   if (t->state() & Thread_vcpu_enabled)
613     {
614       char st1[7];
615       char st2[7];
616       printf("c=%s s=%s e-ip=%08lx e-sp=%08lx S=",
617              vcpu_state_str(t->vcpu_state()->state, st1, sizeof(st1)),
618              vcpu_state_str(t->vcpu_state()->_saved_state, st2, sizeof(st2)),
619              t->vcpu_state()->_entry_ip, t->vcpu_state()->_entry_sp);
620       print_kobject(static_cast<Task*>(t->vcpu_user_space()));
621     }
622   else
623     putstr("---");
624   putchar('\n');
625
626   Address ksp  = is_current_thread ? ef->ksp()
627                                    : (Address)t->get_kernel_sp();
628
629 #if 0
630   Address tcb  = (Address)context_of((void*)ksp);
631 #endif
632   _stack_view.init(ksp, ef, is_current_thread);
633
634   if (is_current_thread)
635     print_entry_frame_regs(t->space());
636
637   else if (t->space() != Kernel_task::kernel_task())
638     {
639       Jdb::cursor(11, 1);
640       info_thread_state(t);
641       putchar('\n');
642       print_return_frame_regs(_stack_view.current, ksp);
643
644       _disasm_view.show(_stack_view.current, t->space());
645     }
646   else
647     {
648       // kernel thread
649       Jdb::cursor(15, 1);
650       printf("kernel SP="ADDR_FMT, ksp);
651     }
652
653 dump_stack:
654
655   // dump the stack from ksp bottom right to tcb_top
656   _stack_view.dump();
657
658   for (bool redraw=false; ; )
659     {
660       _stack_view.highlight(true);
661       int c=Jdb_core::getchar();
662       _stack_view.highlight(false);
663       Jdb::cursor(Jdb_screen::height(), 6);
664
665       if (c == KEY_CURSOR_HOME && level > 0)
666         return GO_BACK;
667
668       if (!_stack_view.handle_key(c, &redraw))
669         {
670           switch (c)
671             {
672             case KEY_RETURN:
673               if (jdb_dump_addr_task && _stack_view.current.valid())
674                 {
675                   if (!jdb_dump_addr_task(_stack_view.current.value(),
676                         _stack_view.current.is_user_value() ? t->space() : 0, level+1))
677                     return NOTHING;
678                   redraw_screen = true;
679                 }
680               break;
681             case KEY_TAB:
682               //bt_start = search_bt_start(tcb, (Mword*)ksp, is_current_thread);
683               redraw = true;
684               break;
685             case ' ':
686               if (Jdb_disasm::avail() && _stack_view.current.valid())
687                 {
688                   printf("V %lx\n", _stack_view.current.value());
689                   if (!Jdb_disasm::show(_stack_view.current.value(),
690                         _stack_view.current.is_user_value() ? t->space() : 0, level+1, true))
691                     return NOTHING;
692                   redraw_screen = true;
693                 }
694               break;
695             case 'u':
696               if (Jdb_disasm::avail() && _stack_view.current.valid())
697                 {
698                   Jdb::printf_statline("tcb", "<CR>=disassemble here",
699                                         "u[address=%08lx task=%lx] ",
700                                         _stack_view.current.value(),
701                                         Kobject_dbg::pointer_to_id(t->space()));
702                   int c1 = Jdb_core::getchar();
703                   if ((c1 != KEY_RETURN) && (c1 != ' '))
704                     {
705                       Jdb::printf_statline("tcb", 0, "u");
706                       Jdb::execute_command("u", c1);
707                       return NOTHING;
708                     }
709
710                   if (!Jdb_disasm::show(_stack_view.current.value(),
711                         _stack_view.current.is_user_value() ? t->space() : 0, level+1, true))
712                     return NOTHING;
713                   redraw_screen = true;
714                 }
715               break;
716 #if 0
717             case 'r': // ready-list
718               putstr("[n]ext/[p]revious in ready list?");
719               switch (Jdb_core::getchar())
720                 {
721                 case 'n':
722                   if (t->_ready_next)
723                     {
724                       t = static_cast<Thread*>(t->_ready_next);
725                       goto new_tcb;
726                     }
727                   break;
728                 case 'p':
729                   if (t->_ready_prev)
730                     {
731                       t = static_cast<Thread*>(t->_ready_prev);
732                       goto new_tcb;
733                     }
734                   break;
735                 }
736               break;
737 #endif
738             case 'p': // present-list or show_pages
739               putstr("[n]ext/[p]revious in present list?");
740               switch (c=Jdb_core::getchar()) 
741                 {
742                 case 'n':
743                   if (t->Present_list_item::next())
744                     {
745                       t = static_cast<Thread*>(t->Present_list_item::next());
746                       goto new_tcb;
747                     }
748                   break;
749                 case 'p':
750                   if (t->Present_list_item::prev())
751                     {
752                       t = static_cast<Thread*>(t->Present_list_item::prev());
753                       goto new_tcb;
754                     }
755                   break;
756                 default:
757                   Jdb::execute_command("p", c);
758                   return NOTHING;
759                 }
760               break;
761             case 'C':
762               _stack_view.memdump_is_colored = !_stack_view.memdump_is_colored;
763               redraw = true;
764               break;
765             case KEY_ESC:
766               Jdb::abort_command();
767               return NOTHING;
768             default:
769               if (Jdb::is_toplevel_cmd(c))
770                 return NOTHING;
771               break;
772             }
773         }
774       if (redraw_screen)
775         goto whole_screen;
776       if (redraw)
777         goto dump_stack;
778     }
779
780
781 /* --- original L4 screen ------------------------------------------------------
782 thread: 0081 (001.01) <00020401 00080000>                               prio: 10
783 state : 85, ready                            lists: 81                   mcp: ff
784
785 wait for: --                             rcv descr: 00000000   partner: 00000000
786 sndq    : 0081 0081                       timeouts: 00000000   waddr0/1: 000/000
787 cpu time: 0000000000 timeslice: 01/0a
788
789 pager   : --                            prsent lnk: 0080 0080
790 ipreempt: --                            ready link : 0080 0080
791 xpreempt: --
792                                         soon wakeup lnk: 
793 EAX=00202dfe  ESI=00020401  DS=0008     late wakeup lnk: 
794 EBX=00000028  EDI=00080000  ES=0008
795 ECX=00000003  EBP=e0020400
796 EDX=00000001  ESP=e00207b4
797
798 700:
799 720:
800 740:
801 760:
802 780:
803 7a0:                                                  0000897b 00000020 00240082
804 7c0:  00000000 00000000 00000000 00000000    00000000 00000000 00000000 00000000
805 7e0:  00000000 00000000 ffffff80 00000000    0000001b 00003200 00000000 00000013
806 L4KD: 
807 ------------------------------------------------------------------------------*/
808
809 PUBLIC
810 Jdb_module::Action_code
811 Jdb_tcb::action(int cmd, void *&args, char const *&fmt, int &next_char)
812 {
813   static Address tcb_addr = 0;
814   if (cmd == 0)
815     {
816       if (args == &first_char)
817         {
818           switch (first_char)
819             {
820               case '+':
821               case '-':
822                 printf("%c\n", first_char);
823                 auto_tcb = first_char == '+';
824                 break;
825               case '?':
826                 args      = &address;
827                 fmt       = " addr="ADDR_FMT" => ";
828                 putchar(first_char);
829                 return Jdb_module::EXTRA_INPUT;
830               case 'a':
831                 args      = &tcb_addr;
832                 fmt       = " tcb=%x => ";
833                 putchar(first_char);
834                 return Jdb_module::EXTRA_INPUT;
835               case KEY_RETURN:
836                 show(0, 0);
837                 return NOTHING;
838               default:
839                 args      = &threadid;
840                 fmt       = "%q";
841                 next_char = first_char;
842                 return Jdb_module::EXTRA_INPUT_WITH_NEXTCHAR;
843             }
844         }
845       else if (args == &address)
846         {
847           address &= ~(Config::thread_block_size-1);
848           Jdb_kobject::print_uid(reinterpret_cast<Thread*>(address), 3);
849           putchar('\n');
850         }
851       else if (args == &tcb_addr)
852         show((Thread*)tcb_addr, 0);
853       else
854         {
855           Thread *t = Kobject::dcast<Thread *>(threadid);
856           if (t)
857             show(t, 0);
858           else
859             printf("\nNot a thread\n");
860         }
861     }
862
863   return NOTHING;
864 }
865
866 PUBLIC
867 Kobject *
868 Jdb_tcb::follow_link(Kobject *o)
869 {
870   Thread *t = Kobject::dcast<Thread*>(o);
871   if (t->space() == Kernel_task::kernel_task())
872     return o;
873   return static_cast<Kobject*>(static_cast<Task*>(t->space()));
874 }
875
876 PUBLIC
877 bool
878 Jdb_tcb::show_kobject(Kobject *o, int level)
879 {
880   Thread *t = Kobject::dcast<Thread*>(o);
881   return show(t, level);
882 }
883
884 PUBLIC
885 int
886 Jdb_tcb::show_kobject_short(char *buf, int max, Kobject *o)
887 {
888   Thread *t = Kobject::dcast<Thread*>(o);
889   Thread *cur_t = Jdb::get_current_active();
890   int cnt = 0;
891   if (t->space() == Kernel_task::kernel_task())
892     {
893       cnt = snprintf(buf, max, " {KERNEL} C=%u", t->cpu());
894       max -= cnt;
895       buf += cnt;
896     }
897   if (t->space() == Kernel_task::kernel_task())
898     return cnt + snprintf(buf, max, " R=%ld%s", t->ref_cnt(),
899                           cur_t == t ? " "JDB_ANSI_COLOR(green)"current"JDB_ANSI_END : "");
900
901   return cnt + snprintf(buf, max, " C=%u S=D:%lx R=%ld %s", t->cpu(),
902                         Kobject_dbg::pointer_to_id(t->space()),
903                         t->ref_cnt(),
904                         cur_t == t ? " "JDB_ANSI_COLOR(green)"current"JDB_ANSI_END : "");
905 }
906
907 PUBLIC
908 char const *
909 Jdb_tcb::kobject_type() const
910 {
911   return JDB_ANSI_COLOR(green) "Thread" JDB_ANSI_COLOR(default);
912 }
913
914 PUBLIC
915 Jdb_module::Cmd const *
916 Jdb_tcb::cmds() const
917 {
918   static Cmd cs[] =
919     {
920         { 0, "t", "tcb", "%C",
921           "t[<threadid>]\tshow current/given thread control block (TCB)\n"
922           "t{+|-}\tshow current thread control block at Jdb every entry\n",
923           &first_char },
924     };
925   return cs;
926 }
927
928 PUBLIC
929 int
930 Jdb_tcb::num_cmds() const
931 { return 1; }
932
933 static Jdb_tcb jdb_tcb INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
934
935 int
936 jdb_show_tcb(Thread *t, int level)
937 { return Jdb_tcb::show(t, level); }
938
939 static inline
940 void
941 Jdb_tcb::print_thread_uid_raw(Thread *t)
942 {
943   printf(" <%p> ", t);
944 }
945
946 PRIVATE static
947 void
948 Jdb_tcb::print_kobject(Mword n)
949 {
950   printf("[C:%4lx]       ", n);
951 }
952
953 PRIVATE static
954 void
955 Jdb_tcb::print_kobject(Kobject *o)
956 {
957   printf("D:%4lx         ", o ? o->dbg_id() : 0);
958 }
959
960 PRIVATE static
961 void
962 Jdb_tcb::print_kobject(Thread *t, Mword capidx)
963 {
964   Space *space = t->space();
965   if (!space)
966     {
967       print_kobject(capidx);
968       return;
969     }
970
971   Obj_space::Capability *c = space->obj_space()->get_cap(capidx);
972   if (!c || !c->valid())
973     {
974       print_kobject(capidx);
975       return;
976     }
977
978   printf("[C:%4lx] D:%4lx", capidx, c->obj()->dbg_info()->dbg_id());
979 }
980
981 //
982 //-----------------------------------------------------------------------------
983 // prompt extension for thread names
984 class Jdb_thread_name_ext : public Jdb_prompt_ext
985 {
986 public:
987   void ext();
988   void update();
989 };
990
991 IMPLEMENT
992 void
993 Jdb_thread_name_ext::ext()
994 {
995   if (Jdb::get_current_active())
996     {
997       Jdb_kobject_name *nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(Jdb::get_current_active());
998       if (nx && nx->name()[0])
999         printf("[%*.*s] ", nx->max_len(), nx->max_len(), nx->name());
1000     }
1001 }
1002
1003 IMPLEMENT
1004 void
1005 Jdb_thread_name_ext::update()
1006 {
1007   Jdb::get_current(Jdb::current_cpu);
1008 }
1009
1010 static Jdb_thread_name_ext jdb_thread_name_ext INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
1011