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