]> 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 & ~(Config::thread_block_size-1)),
51       _offs(addr &  (Config::thread_block_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 <= Config::thread_block_size-sizeof(Mword); }
60
61   bool operator > (int offs) const
62   {
63     return offs < 0 ? _offs > Config::thread_block_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 + Config::thread_block_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(Space *task);
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 PUBLIC
160 Jdb_stack_view::Jdb_stack_view(unsigned y)
161 : start_y(y), absy(0), memdump_is_colored(true)
162 {}
163
164 PUBLIC static inline
165 Mword
166 Jdb_stack_view::cols()
167 {
168   return Jdb_screen::cols() - 1;
169 }
170
171 PUBLIC static inline
172 Mword
173 Jdb_stack_view::bytes_per_line()
174 { return cols() * sizeof(Mword); }
175
176 PUBLIC
177 void
178 Jdb_stack_view::init(Address ksp, Jdb_entry_frame *_ef, bool _is_current)
179 {
180   current = Jdb_tcb_ptr(ksp);
181
182   absy = current.offs() / bytes_per_line();
183   addx = (current.offs() % bytes_per_line()) / sizeof(Mword);
184   addy = 0;
185   ef = _ef;
186   is_current = _is_current;
187 }
188
189 PUBLIC
190 void
191 Jdb_stack_view::print_value(Jdb_tcb_ptr const &p, bool highl = false)
192 {
193   if (!p.valid() || !Jdb_util::is_mapped((void const*)p.addr()))
194     {
195       printf(" %.*s", Jdb_screen::Mword_size_bmode, Jdb_screen::Mword_not_mapped);
196       return;
197     }
198
199   const char *s1="", *s2="";
200   if (highl)
201     {
202       s1 = Jdb::esc_emph;
203       s2 = JDB_ANSI_END;
204     }
205   else if (p.is_user_value())
206     {
207       s1 = Jdb::esc_iret;
208       s2 = JDB_ANSI_END;
209     }
210   else if (memdump_is_colored)
211     {
212       if (p.is_kern_code())
213         {
214           s1 = JDB_ANSI_COLOR(lightblue);
215           s2 = JDB_ANSI_END;
216         }
217       else if (p.is_kobject())
218         {
219           s1 = JDB_ANSI_COLOR(lightgreen);
220           s2 = JDB_ANSI_END;
221         }
222       /* else if (p.in_backtrace(...
223          {
224          s1 = Jdb::esc_bt;
225          s2 = "\033[m";
226          } */
227     }
228
229   printf(" %s"ADDR_FMT"%s", s1, p.value(), s2);
230 }
231
232
233 PUBLIC
234 void
235 Jdb_stack_view::dump()//Jdb_tcb_ptr const &current)
236 {
237   Jdb_tcb_ptr p = current;
238   p.offs(absy * bytes_per_line());
239
240   Jdb::cursor(start_y, 1);
241
242   for (unsigned y = 0; y < Jdb_screen::height() - start_y; ++y)
243     {
244       Kconsole::console()->getchar_chance();
245
246       if (p.valid())
247         {
248           printf("    %03lx ", p.addr() & 0xfff);
249           for (unsigned x = 0; x < cols(); ++x, p+=1)
250             print_value(p);
251           putchar('\n');
252         }
253       else
254         puts("\033[K");
255     }
256 }
257
258 PRIVATE inline
259 unsigned
260 Jdb_stack_view::posx()
261 { return addx * (Jdb_screen::Mword_size_bmode + 1) + 9; }
262
263 PRIVATE inline
264 unsigned
265 Jdb_stack_view::posy()
266 { return addy + start_y; }
267
268 PUBLIC
269 void
270 Jdb_stack_view::highlight(bool highl)
271 {
272   current.offs(absy*bytes_per_line() + addy*bytes_per_line() + addx * sizeof(Mword));
273   Jdb_tcb_ptr first_col = current;
274   first_col.offs(absy*bytes_per_line() + addy*bytes_per_line());
275
276   if (!current.valid())
277     return;
278
279   Jdb::cursor(posy(), 1);
280   if (highl)
281     printf("%08lx", current.addr() & 0xffffffff);
282   else
283     printf("    %03lx ", first_col.addr() & 0xfff);
284   Jdb::cursor(posy(), posx());
285   print_value(current, highl);
286
287   char kobj_desc[120];
288   kobj_desc[0] = 0;
289
290   if (current.is_kern_code())
291     strcpy(kobj_desc, "Kernel code"); // todo: print kernel function name
292   else if (current.is_user_value())
293     snprintf(kobj_desc, sizeof(kobj_desc), "Return frame: %s",
294              current.user_value_desc());
295   else
296     if (Kobject *o = Kobject::pointer_to_obj(reinterpret_cast<void *>(current.value())))
297       {
298         Jdb_kobject::obj_description(kobj_desc, sizeof(kobj_desc), true, o);
299         kobj_desc[sizeof(kobj_desc) - 1] = 0;
300       }
301
302   Jdb::printf_statline("tcb", "<CR>=dump <Space>=Disas",
303                        "%s", kobj_desc);
304 }
305
306 PUBLIC
307 bool
308 Jdb_stack_view::handle_key(int key, bool *redraw)
309 {
310   Mword   lines    = Jdb_screen::height() - start_y;
311   Mword   max_lines = (Config::thread_block_size + bytes_per_line() - 1)/bytes_per_line();
312   Address max_absy = max_lines - lines;
313
314   if (lines > max_lines)
315     max_absy = 0;
316
317   if (lines > max_lines - absy)
318     lines = max_lines - absy;
319
320   if (key == 'e')
321     edit_stack(redraw);
322   else
323     return Jdb::std_cursor_key(key, this->cols(), lines, max_absy,
324       &absy, &addy, &addx, redraw);
325
326   return true;
327 }
328
329 PUBLIC
330 void
331 Jdb_stack_view::edit_stack(bool *redraw)
332 {
333   if (current.valid())
334     {
335       Mword value;
336       int c;
337
338       Jdb::cursor(posy(), posx());
339       printf(" %.*s", Jdb_screen::Mword_size_bmode, Jdb_screen::Mword_blank);
340       Jdb::printf_statline("tcb",
341           is_current ? "<Space>=edit registers" : 0,
342           "edit <"ADDR_FMT"> = "ADDR_FMT,
343           current.addr(), current.value());
344
345       Jdb::cursor(posy(), posx() + 1);
346       c = Jdb_core::getchar();
347
348       if (c==KEY_ESC)
349         {
350           *redraw = true;
351           return;
352         }
353
354       if (c != ' ' || !is_current)
355         {
356           // edit memory
357           putchar(c);
358           Jdb::printf_statline("tcb", 0, "edit <"ADDR_FMT"> = "ADDR_FMT,
359               current.addr(), current.value());
360           Jdb::cursor(posy(), posx() + 1);
361           if (!Jdb_input::get_mword(&value, c, 16))
362             {
363               Jdb::cursor(posy(), posx());
364               print_value(current);
365               return;
366             }
367           else
368             current.value(value);
369         }
370       else
371         {
372           // edit registers
373           Jdb::cursor(posy(), posx());
374           print_value(current);
375           edit_registers();
376           return;
377         }
378       *redraw = true;
379     }
380 }
381
382 PUBLIC
383 Jdb_disasm_view::Jdb_disasm_view(unsigned x, unsigned y)
384 : _x(x), _y(y)
385 {}
386
387 PUBLIC
388 void
389 Jdb_disasm_view::show(Jdb_tcb_ptr const &p, Space *s)
390 {
391   if (!Jdb_disasm::avail())
392     return;
393
394   Address disass_addr = p.top_value(-5);
395   Jdb::cursor(_y, _x);
396   putstr(Jdb::esc_emph);
397   Jdb_disasm::show_disasm_line(-40, disass_addr, 0, s);
398   putstr("\033[m");
399   Jdb::cursor(_y + 1, _x);
400   Jdb_disasm::show_disasm_line(-40, disass_addr, 0, s);
401 }
402
403
404 PUBLIC
405 Jdb_tcb::Jdb_tcb()
406   : Jdb_module("INFO"), Jdb_kobject_handler(Thread_object::static_kobj_type)
407 {
408   static Jdb_handler enter(at_jdb_enter);
409
410   Jdb::jdb_enter.add(&enter);
411   Jdb_kobject::module()->register_handler(this);
412 }
413
414 static void
415 Jdb_tcb::at_jdb_enter()
416 {
417   if (auto_tcb)
418     {
419       // clear any keystrokes in queue
420       Jdb::set_next_cmd(0);
421       Jdb::push_cons()->push('t');
422       Jdb::push_cons()->push(' ');
423     }
424 }
425
426
427 PUBLIC virtual
428 Kobject *
429 Jdb_tcb::parent(Kobject *o)
430 {
431   Thread *t = Kobject::dcast<Thread_object*>(o);
432   if (!t)
433     return 0;
434
435   return static_cast<Task*>(t->space());
436 }
437
438 PRIVATE static inline
439 char *
440 Jdb_tcb::vcpu_state_str(Mword state, char *s, int len)
441 {
442   snprintf(s, len, "%c%c%c%c%c%c",
443            (state & Vcpu_state::F_fpu_enabled) ? 'F' : 'f',
444            (state & Vcpu_state::F_user_mode)   ? 'U' : 'u',
445            (state & Vcpu_state::F_debug_exc)   ? 'D' : 'd',
446            (state & Vcpu_state::F_exceptions)  ? 'E' : 'e',
447            (state & Vcpu_state::F_page_faults) ? 'P' : 'p',
448            (state & Vcpu_state::F_irqs)        ? 'I' : 'i');
449   s[len - 1] = 0;
450   return s;
451 }
452
453 PUBLIC static
454 Jdb_module::Action_code
455 Jdb_tcb::show(Thread *t, int level)
456 {
457   Thread *t_current      = Jdb::get_current_active();
458   bool is_current_thread;
459   bool redraw_screen     = true;
460   Jdb_entry_frame *ef    = Jdb::get_entry_frame(Jdb::current_cpu);
461 #if 0
462   Address bt_start       = 0;
463 #endif
464
465   if (!t && !t_current)
466     {
467 #if 0
468       const Mword mask
469         = (Config::thread_block_size * Mem_layout::max_threads()) - 1;
470       const Mword tsksz = Config::thread_block_size*L4_uid::threads_per_task();
471       LThread_num task = ((Address)Jdb::get_thread() & mask) / tsksz;
472 #endif
473 #if 0
474       putchar('\n');
475       print_entry_frame_regs(0);
476 #endif
477       return NOTHING;
478     }
479
480   if (!t)
481     t = t_current;
482
483   is_current_thread = t == t_current;
484
485 #if 0
486   if (!t->is_valid())
487     {
488       puts(" Invalid thread");
489       return NOTHING;
490     }
491 #endif
492
493   if (level==0)
494     {
495       Jdb::clear_screen(Jdb::FANCY);
496       redraw_screen = false;
497     }
498
499 whole_screen:
500
501   if (redraw_screen)
502     {
503       Jdb::clear_screen(Jdb::NOFANCY);
504       redraw_screen = false;
505     }
506
507   char time_str[12];
508
509   putstr("thread  : ");
510   Jdb_kobject::print_uid(t, 3);
511   print_thread_uid_raw(t);
512   printf("\tCPU: %u ", t->cpu());
513
514   printf("\tprio: %02x  mode: %s\n",
515          t->sched()->prio(),
516          t->mode() & Context::Periodic  ?
517          t->mode() & Context::Nonstrict ? "Per (IRT)" : "Per (SP)" : "Con");
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(" polling: ");
529   Jdb_thread::print_snd_partner(t, 3);
530
531   putstr("rcv descr: ");
532
533   if ((t->state(false) & Thread_ipc_mask) == Thread_receive_wait)
534     printf("%08lx", t->rcv_regs()->from_spec());
535   else
536     putstr("        ");
537
538   putstr("\n"
539          "lcked by: ");
540   if (t->thread_lock()->lock_owner())
541     Jdb_kobject::print_uid(static_cast<Thread*>(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("\nexc-hndl: ");
573   print_kobject(t, t->_exc_handler.raw());
574
575   printf("\tUTCB     : %08lx/%08lx",
576          (Mword)t->utcb().kern(), (Mword)t->utcb().usr().get());
577
578 #if 0
579   putstr("\tready  lnk: ");
580   if (t->state(false) & 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   putchar('\n');
601
602   putstr("vCPU    : ");
603   if (t->state(false) & Thread_vcpu_enabled)
604     {
605       char st1[7];
606       char st2[7];
607       Vcpu_state *v = t->vcpu_state().kern();
608       printf("%08lx/%08lx S=", (Mword)v, (Mword)t->vcpu_state().usr().get());
609       print_kobject(static_cast<Task*>(t->vcpu_user_space()));
610       putchar('\n');
611       printf("vCPU    : c=%s s=%s sf=%c e-ip=%08lx e-sp=%08lx\n",
612              vcpu_state_str(v->state, st1, sizeof(st1)),
613              vcpu_state_str(v->_saved_state, st2, sizeof(st2)),
614              (v->sticky_flags & Vcpu_state::Sf_irq_pending) ? 'P' : '-',
615              v->_entry_ip, v->_entry_sp);
616     }
617   else
618     putstr("---\nvCPU    : ---\n");
619
620   Address ksp  = is_current_thread ? ef->ksp()
621                                    : (Address)t->get_kernel_sp();
622
623 #if 0
624   Address tcb  = (Address)context_of((void*)ksp);
625 #endif
626   _stack_view.init(ksp, ef, is_current_thread);
627
628   if (is_current_thread)
629     print_entry_frame_regs(t->space());
630
631   else if (t->space() != Kernel_task::kernel_task())
632     {
633       Jdb::cursor(11, 1);
634       info_thread_state(t);
635       putchar('\n');
636       print_return_frame_regs(_stack_view.current, ksp);
637
638       _disasm_view.show(_stack_view.current, t->space());
639     }
640   else
641     {
642       // kernel thread
643       Jdb::cursor(15, 1);
644       printf("kernel SP="ADDR_FMT, ksp);
645     }
646
647 dump_stack:
648
649   // dump the stack from ksp bottom right to tcb_top
650   _stack_view.dump();
651
652   for (bool redraw=false; ; )
653     {
654       _stack_view.highlight(true);
655       int c=Jdb_core::getchar();
656       _stack_view.highlight(false);
657       Jdb::cursor(Jdb_screen::height(), 6);
658
659       if (c == KEY_CURSOR_HOME && level > 0)
660         return GO_BACK;
661
662       if (!_stack_view.handle_key(c, &redraw))
663         {
664           switch (c)
665             {
666             case KEY_RETURN:
667               if (jdb_dump_addr_task && _stack_view.current.valid())
668                 {
669                   if (!jdb_dump_addr_task(_stack_view.current.value(),
670                         _stack_view.current.is_user_value() ? t->space() : 0, level+1))
671                     return NOTHING;
672                   redraw_screen = true;
673                 }
674               break;
675             case KEY_TAB:
676               //bt_start = search_bt_start(tcb, (Mword*)ksp, is_current_thread);
677               redraw = true;
678               break;
679             case ' ':
680               if (Jdb_disasm::avail() && _stack_view.current.valid())
681                 {
682                   printf("V %lx\n", _stack_view.current.value());
683                   if (!Jdb_disasm::show(_stack_view.current.value(),
684                         _stack_view.current.is_user_value() ? t->space() : 0, level+1, true))
685                     return NOTHING;
686                   redraw_screen = true;
687                 }
688               break;
689             case 'u':
690               if (Jdb_disasm::avail() && _stack_view.current.valid())
691                 {
692                   Jdb::printf_statline("tcb", "<CR>=disassemble here",
693                                         "u[address=%08lx task=%lx] ",
694                                         _stack_view.current.value(),
695                                         Kobject_dbg::pointer_to_id(t->space()));
696                   int c1 = Jdb_core::getchar();
697                   if ((c1 != KEY_RETURN) && (c1 != ' '))
698                     {
699                       Jdb::printf_statline("tcb", 0, "u");
700                       Jdb::execute_command("u", c1);
701                       return NOTHING;
702                     }
703
704                   if (!Jdb_disasm::show(_stack_view.current.value(),
705                         _stack_view.current.is_user_value() ? t->space() : 0, level+1, true))
706                     return NOTHING;
707                   redraw_screen = true;
708                 }
709               break;
710 #if 0
711             case 'r': // ready-list
712               putstr("[n]ext/[p]revious in ready list?");
713               switch (Jdb_core::getchar())
714                 {
715                 case 'n':
716                   if (t->_ready_next)
717                     {
718                       t = static_cast<Thread*>(t->_ready_next);
719                       goto new_tcb;
720                     }
721                   break;
722                 case 'p':
723                   if (t->_ready_prev)
724                     {
725                       t = static_cast<Thread*>(t->_ready_prev);
726                       goto new_tcb;
727                     }
728                   break;
729                 }
730               break;
731 #endif
732             case 'C':
733               _stack_view.memdump_is_colored = !_stack_view.memdump_is_colored;
734               redraw = true;
735               break;
736             case KEY_ESC:
737               Jdb::abort_command();
738               return NOTHING;
739             default:
740               if (Jdb::is_toplevel_cmd(c))
741                 return NOTHING;
742               break;
743             }
744         }
745       if (redraw_screen)
746         goto whole_screen;
747       if (redraw)
748         goto dump_stack;
749     }
750
751
752 /* --- original L4 screen ------------------------------------------------------
753 thread: 0081 (001.01) <00020401 00080000>                               prio: 10
754 state : 85, ready                            lists: 81                   mcp: ff
755
756 wait for: --                             rcv descr: 00000000   partner: 00000000
757 sndq    : 0081 0081                       timeouts: 00000000   waddr0/1: 000/000
758 cpu time: 0000000000 timeslice: 01/0a
759
760 pager   : --                            prsent lnk: 0080 0080
761 ipreempt: --                            ready link : 0080 0080
762 xpreempt: --
763                                         soon wakeup lnk: 
764 EAX=00202dfe  ESI=00020401  DS=0008     late wakeup lnk: 
765 EBX=00000028  EDI=00080000  ES=0008
766 ECX=00000003  EBP=e0020400
767 EDX=00000001  ESP=e00207b4
768
769 700:
770 720:
771 740:
772 760:
773 780:
774 7a0:                                                  0000897b 00000020 00240082
775 7c0:  00000000 00000000 00000000 00000000    00000000 00000000 00000000 00000000
776 7e0:  00000000 00000000 ffffff80 00000000    0000001b 00003200 00000000 00000013
777 L4KD: 
778 ------------------------------------------------------------------------------*/
779
780 PUBLIC
781 Jdb_module::Action_code
782 Jdb_tcb::action(int cmd, void *&args, char const *&fmt, int &next_char)
783 {
784   static Address tcb_addr = 0;
785   if (cmd == 0)
786     {
787       if (args == &first_char)
788         {
789           switch (first_char)
790             {
791               case '+':
792               case '-':
793                 printf("%c\n", first_char);
794                 auto_tcb = first_char == '+';
795                 break;
796               case '?':
797                 args      = &address;
798                 fmt       = " addr="ADDR_FMT" => ";
799                 putchar(first_char);
800                 return Jdb_module::EXTRA_INPUT;
801               case 'a':
802                 args      = &tcb_addr;
803                 fmt       = " tcb=%x => ";
804                 putchar(first_char);
805                 return Jdb_module::EXTRA_INPUT;
806               case KEY_RETURN:
807                 show(0, 0);
808                 return NOTHING;
809               default:
810                 args      = &threadid;
811                 fmt       = "%q";
812                 next_char = first_char;
813                 return Jdb_module::EXTRA_INPUT_WITH_NEXTCHAR;
814             }
815         }
816       else if (args == &address)
817         {
818           address &= ~(Config::thread_block_size-1);
819           Jdb_kobject::print_uid(reinterpret_cast<Thread*>(address), 3);
820           putchar('\n');
821         }
822       else if (args == &tcb_addr)
823         show((Thread*)tcb_addr, 0);
824       else
825         {
826           Thread *t = Kobject::dcast<Thread_object *>(threadid);
827           if (t)
828             show(t, 0);
829           else
830             printf("\nNot a thread\n");
831         }
832     }
833
834   return NOTHING;
835 }
836
837 PUBLIC
838 Kobject_common *
839 Jdb_tcb::follow_link(Kobject_common *o)
840 {
841   Thread *t = Kobject::dcast<Thread_object *>(Kobject::from_dbg(o->dbg_info()));
842   if (t->space() == Kernel_task::kernel_task())
843     return o;
844   return static_cast<Kobject*>(static_cast<Task*>(t->space()));
845 }
846
847 PUBLIC
848 bool
849 Jdb_tcb::show_kobject(Kobject_common *o, int level)
850 {
851   Thread *t = Kobject::dcast<Thread_object *>(Kobject::from_dbg(o->dbg_info()));
852   return show(t, level);
853 }
854
855 PRIVATE static
856 bool
857 Jdb_tcb::is_current(Thread *t)
858 {
859   return t == Jdb::get_thread(t->cpu());
860 }
861
862 PUBLIC
863 int
864 Jdb_tcb::show_kobject_short(char *buf, int max, Kobject_common *o)
865 {
866   Thread *t = Kobject::dcast<Thread_object *>(Kobject::from_dbg(o->dbg_info()));
867   bool is_current = Jdb_tcb::is_current(t);
868   int cnt = 0;
869   if (t->space() == Kernel_task::kernel_task())
870     {
871       cnt = snprintf(buf, max, " {KERNEL} C=%u", t->cpu());
872       max -= cnt;
873       buf += cnt;
874     }
875   if (t->space() == Kernel_task::kernel_task())
876     return cnt + snprintf(buf, max, " R=%ld%s", t->ref_cnt(),
877                           is_current ? " "JDB_ANSI_COLOR(green)"current"JDB_ANSI_END : "");
878
879   return cnt + snprintf(buf, max, " C=%u S=D:%lx R=%ld %s", t->cpu(),
880                         Kobject_dbg::pointer_to_id(t->space()),
881                         t->ref_cnt(),
882                         is_current ? " "JDB_ANSI_COLOR(green)"current"JDB_ANSI_END : "");
883 }
884
885 PUBLIC
886 char const *
887 Jdb_tcb::kobject_type() const
888 {
889   return JDB_ANSI_COLOR(green) "Thread" JDB_ANSI_COLOR(default);
890 }
891
892 PUBLIC
893 Jdb_module::Cmd const *
894 Jdb_tcb::cmds() const
895 {
896   static Cmd cs[] =
897     {
898         { 0, "t", "tcb", "%C",
899           "t[<threadid>]\tshow current/given thread control block (TCB)\n"
900           "t{+|-}\tshow current thread control block at Jdb every entry\n",
901           &first_char },
902     };
903   return cs;
904 }
905
906 PUBLIC
907 int
908 Jdb_tcb::num_cmds() const
909 { return 1; }
910
911 static Jdb_tcb jdb_tcb INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
912
913 int
914 jdb_show_tcb(Thread *t, int level)
915 { return Jdb_tcb::show(t, level); }
916
917 static inline
918 void
919 Jdb_tcb::print_thread_uid_raw(Thread *t)
920 {
921   printf(" <%p> ", t);
922 }
923
924 PRIVATE static
925 void
926 Jdb_tcb::print_kobject(Mword n)
927 {
928   printf("[C:%4lx]       ", n);
929 }
930
931 PRIVATE static
932 void
933 Jdb_tcb::print_kobject(Kobject *o)
934 {
935   printf("D:%4lx         ", o ? o->dbg_info()->dbg_id() : 0);
936 }
937
938 PRIVATE static
939 void
940 Jdb_tcb::print_kobject(Thread *t, Mword capidx)
941 {
942   Space *space = t->space();
943   if (!space)
944     {
945       print_kobject(capidx);
946       return;
947     }
948
949   Obj_space::Capability *c = space->obj_space()->get_cap(capidx);
950   if (!c || !c->valid())
951     {
952       print_kobject(capidx);
953       return;
954     }
955
956   printf("[C:%4lx] D:%4lx", capidx, c->obj()->dbg_info()->dbg_id());
957 }
958
959 //
960 //-----------------------------------------------------------------------------
961 // prompt extension for thread names
962 class Jdb_thread_name_ext : public Jdb_prompt_ext
963 {
964 public:
965   void ext();
966   void update();
967 };
968
969 IMPLEMENT
970 void
971 Jdb_thread_name_ext::ext()
972 {
973   if (Jdb::get_current_active())
974     {
975       Jdb_kobject_name *nx = Jdb_kobject_extension::find_extension<Jdb_kobject_name>(Jdb::get_current_active());
976       if (nx && nx->name()[0])
977         printf("[%*.*s] ", nx->max_len(), nx->max_len(), nx->name());
978     }
979 }
980
981 IMPLEMENT
982 void
983 Jdb_thread_name_ext::update()
984 {
985   Jdb::get_current(Jdb::current_cpu);
986 }
987
988 static Jdb_thread_name_ext jdb_thread_name_ext INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
989