]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/jdb.cpp
update
[l4.git] / kernel / fiasco / src / jdb / jdb.cpp
1 INTERFACE:
2
3 #include "l4_types.h"
4 #include "jdb_core.h"
5 #include "jdb_handler_queue.h"
6 #include "per_cpu_data.h"
7
8 class Context;
9 class Thread;
10 class Push_console;
11
12 class Jdb_entry_frame;
13
14 class Jdb : public Jdb_core
15 {
16 public:
17   static Per_cpu<Jdb_entry_frame*> entry_frame;
18   static unsigned current_cpu;
19   static Per_cpu<void (*)(unsigned, void *)> remote_func;
20   static Per_cpu<void *> remote_func_data;
21   static Per_cpu<bool> remote_func_running;
22
23   static int FIASCO_FASTCALL enter_jdb(Jdb_entry_frame *e, unsigned cpu);
24   static void cursor_end_of_screen();
25   static void cursor_home();
26   static void printf_statline(const char *prompt, const char *help,
27                               const char *format, ...)
28   __attribute__((format(printf, 3, 4)));
29   static void save_disable_irqs(unsigned cpu);
30   static void restore_irqs(unsigned cpu);
31
32 private:
33   Jdb();                        // default constructors are undefined
34   Jdb(const Jdb&);
35
36   static char hide_statline;
37   static char last_cmd;
38   static char next_cmd;
39   static Per_cpu<char[81]> error_buffer;
40   static bool was_input_error;
41
42   static Thread  *current_active;
43
44   static const char *toplevel_cmds;
45   static const char *non_interactive_cmds;
46
47   // state for traps in JDB itself
48   static Per_cpu<bool> running;
49   static bool in_service;
50   static bool leave_barrier;
51   static unsigned long cpus_in_debugger;
52   static bool never_break;
53   static bool jdb_active;
54
55   static void enter_trap_handler(unsigned cpu);
56   static void leave_trap_handler(unsigned cpu);
57   static bool handle_conditional_breakpoint(unsigned cpu);
58   static void handle_nested_trap(Jdb_entry_frame *e);
59   static bool handle_user_request(unsigned cpu);
60   static bool handle_debug_traps(unsigned cpu);
61   static bool test_checksums();
62
63 public:
64   static Jdb_handler_queue jdb_enter;
65   static Jdb_handler_queue jdb_leave;
66
67   // esc sequences for highligthing
68   static char  esc_iret[];
69   static char  esc_bt[];
70   static char  esc_emph[];
71   static char  esc_emph2[];
72   static char  esc_mark[];
73   static char  esc_line[];
74   static char  esc_symbol[];
75
76 };
77
78 //---------------------------------------------------------------------------
79 IMPLEMENTATION:
80
81 #include <cstdio>
82 #include <cstring>
83 #include <simpleio.h>
84
85 #include "config.h"
86 #include "delayloop.h"
87 #include "feature.h"
88 #include "jdb_core.h"
89 #include "jdb_entry_frame.h"
90 #include "jdb_screen.h"
91 #include "kernel_console.h"
92 #include "processor.h"
93 #include "push_console.h"
94 #include "static_init.h"
95 #include "keycodes.h"
96
97 KIP_KERNEL_FEATURE("jdb");
98
99 Jdb_handler_queue Jdb::jdb_enter;
100 Jdb_handler_queue Jdb::jdb_leave;
101
102 DEFINE_PER_CPU Per_cpu<char[81]> Jdb::error_buffer;
103 char Jdb::next_cmd;                     // next global command to execute
104 char Jdb::last_cmd;
105
106 char Jdb::hide_statline;                // show status line on enter_kdebugger
107 DEFINE_PER_CPU Per_cpu<Jdb_entry_frame*> Jdb::entry_frame;
108 unsigned Jdb::current_cpu;              // current CPU JDB is running on
109 Thread *Jdb::current_active;            // current running thread
110 bool Jdb::was_input_error;              // error in command sequence
111
112 DEFINE_PER_CPU Per_cpu<void (*)(unsigned, void *)> Jdb::remote_func;
113 DEFINE_PER_CPU Per_cpu<void *> Jdb::remote_func_data;
114 DEFINE_PER_CPU Per_cpu<bool> Jdb::remote_func_running;
115
116 // holds all commands executable in top level (regardless of current mode)
117 const char *Jdb::toplevel_cmds = "j_";
118
119 // a short command must be included in this list to be enabled for non-
120 // interactive execution
121 const char *Jdb::non_interactive_cmds = "bEIJLMNOPSU^Z";
122
123 DEFINE_PER_CPU Per_cpu<bool> Jdb::running;      // JDB is already running
124 bool Jdb::never_break;          // never enter JDB
125 bool Jdb::jdb_active;
126 bool Jdb::in_service;
127 bool Jdb::leave_barrier;
128 unsigned long Jdb::cpus_in_debugger;
129
130
131 PUBLIC static
132 bool
133 Jdb::cpu_in_jdb(unsigned cpu)
134 { return Cpu::online(cpu) && running.cpu(cpu); }
135
136
137 PUBLIC static
138 template< typename Func >
139 void
140 Jdb::foreach_cpu(Func const &f)
141 {
142   for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
143     {
144       if (!Cpu::online(i) || !running.cpu(i))
145         continue;
146       f(i);
147     }
148 }
149
150 PUBLIC static
151 template< typename Func >
152 bool
153 Jdb::foreach_cpu(Func const &f, bool positive)
154 {
155   bool r = positive;
156   for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
157     {
158       if (!Cpu::online(i) || !running.cpu(i))
159         continue;
160
161       bool res = f(i);
162
163       if (positive)
164         r = r && res;
165       else
166         r = r || res;
167     }
168
169   return r;
170 }
171
172 PUBLIC static inline
173 void
174 Jdb::set_next_cmd(char cmd)
175 { next_cmd = cmd; }
176
177 PUBLIC static inline
178 int
179 Jdb::was_last_cmd()
180 { return last_cmd; }
181
182 PUBLIC static inline
183 int
184 Jdb::get_next_cmd()
185 { return next_cmd; }
186
187 /** Command aborted. If we are interpreting a debug command like
188  *  enter_kdebugger("*#...") this is an error
189  */
190 PUBLIC
191 static void
192 Jdb::abort_command()
193 {
194   cursor(Jdb_screen::height(), 6);
195   clear_to_eol();
196
197   was_input_error = true;
198 }
199
200
201 // go to bottom of screen and print some text in the form "jdb: ..."
202 // if no text follows after the prompt, prefix the current thread number
203 IMPLEMENT
204 void
205 Jdb::printf_statline(const char *prompt, const char *help,
206                      const char *format, ...)
207 {
208   cursor(Jdb_screen::height(), 1);
209   unsigned w = Jdb_screen::width();
210   prompt_start();
211   if (prompt)
212     {
213       putstr(prompt);
214       putstr(": ");
215       w -= strlen(prompt) + 2;
216     }
217   else
218     {
219       Jdb::prompt();
220       w -= Jdb::prompt_len();
221     }
222   prompt_end();
223   // work around for ealier gccs complaining about "empty format strings"
224   if (format && (format[0] != '_' || format[1] != '\0'))
225     {
226       char s[w];
227       va_list list;
228       va_start(list, format);
229       vsnprintf(s, sizeof(s), format, list);
230       va_end(list);
231       s[sizeof(s) - 1] = 0;
232       putstr(s);
233       w -= print_len(s);
234     }
235   if (help && print_len(help) < w)
236     printf("%*.*s", w, w, help);
237   else
238     clear_to_eol();
239 }
240
241 PUBLIC static
242 bool Jdb::is_toplevel_cmd(char c)
243 {
244   char cm[] = {c, 0};
245   Jdb_core::Cmd cmd = Jdb_core::has_cmd(cm);
246
247   if (cmd.cmd || (0 != strchr(toplevel_cmds, c)))
248     {
249       set_next_cmd(c);
250       return true;
251     }
252
253   return false;
254 }
255
256
257 PUBLIC static 
258 int
259 Jdb::execute_command(const char *s, int first_char = -1)
260 {
261   Jdb_core::Cmd cmd = Jdb_core::has_cmd(s);
262
263   if (cmd.cmd)
264     return Jdb_core::exec_cmd(cmd, 0, first_char) == 2 ? 1 : 0;
265
266   return 0;
267 }
268
269 PUBLIC static
270 Push_console *
271 Jdb::push_cons()
272 {
273   static Push_console c;
274   return &c;
275 }
276
277 // Interprete str as non interactive commands for Jdb. We allow mostly 
278 // non-interactive commands here (e.g. we don't allow d, t, l, u commands)
279 PRIVATE static
280 int
281 Jdb::execute_command_ni(Space *task, char const *str, int len = 1000)
282 {
283   char tmp = 0;
284   for (; len && peek(str, task, tmp) && tmp; ++str, --len)
285     if ((unsigned char)tmp != 0xff)
286       push_cons()->push(tmp);
287
288   if ((unsigned char)tmp != 0xff)
289     push_cons()->push('_'); // terminating return
290
291
292   // prevent output of sequences
293   Kconsole::console()->change_state(0, 0, ~Console::OUTENABLED, 0);
294
295   for (;;)
296     {
297       int c = getchar();
298
299       was_input_error = true;
300       if (0 != strchr(non_interactive_cmds, c))
301         {
302           char _cmd[] = {(char)c, 0};
303           Jdb_core::Cmd cmd = Jdb_core::has_cmd(_cmd);
304
305           if (cmd.cmd)
306             {
307               if (Jdb_core::exec_cmd (cmd, 0) != 3)
308                 was_input_error = false;
309             }
310         }
311
312       if (c == KEY_RETURN || c == ' ' || was_input_error)
313         {
314           push_cons()->flush();
315           // re-enable all consoles but GZIP
316           Kconsole::console()->change_state(0, Console::GZIP,
317                                             ~0U, Console::OUTENABLED);
318           return c == KEY_RETURN || c == ' ';
319         }
320     }
321 }
322
323 PRIVATE static
324 bool
325 Jdb::input_short_mode(Jdb::Cmd *cmd, char const **args, int &cmd_key)
326 {
327   *args = 0;
328   for (;;)
329     {
330       int c;
331       do
332         {
333           if ((c = get_next_cmd()))
334             set_next_cmd(0);
335           else
336             c = getchar();
337         }
338       while (c < ' ' && c != KEY_RETURN);
339
340       if (c == KEY_F1)
341         c = 'h';
342
343       printf("\033[K%c", c); // clreol + print key
344
345       char cmd_buffer[2] = { (char)c, 0 };
346
347       *cmd = Jdb_core::has_cmd(cmd_buffer);
348       if (cmd->cmd)
349         {
350           cmd_key = c;
351           return false; // do not leave the debugger
352         }
353       else if (!handle_special_cmds(c))
354         return true; // special command triggered a JDB leave
355       else if (c == KEY_RETURN)
356         {
357           hide_statline = false;
358           cmd_key = c;
359           return false;
360         }
361     }
362 }
363
364
365 class Cmd_buffer
366 {
367 private:
368   unsigned  _l;
369   char _b[256];
370
371 public:
372   Cmd_buffer() {}
373   char *buffer() { return _b; }
374   int len() const { return _l; }
375   void flush() { _l = 0; _b[0] = 0; }
376   void cut(int l) 
377   {
378     if (l < 0)
379       l = _l + l;
380
381     if (l >= 0 && (unsigned)l < _l)
382       {
383         _l = l;
384         _b[l] = 0;
385       }
386   }
387
388   void append(int c) { if (_l + 1 < sizeof(_b)) { _b[_l++] = c; _b[_l] = 0; } }
389   void append(char const *str, int len)
390   {
391     if (_l + len >= sizeof(_b))
392       len = sizeof(_b) - _l - 1;
393
394     memcpy(_b + _l, str, len);
395     _l += len;
396     _b[_l] = 0;
397   }
398
399   void overlay(char const *str, unsigned len)
400   {
401     if (len + 1 > sizeof(_b))
402       len = sizeof(_b) - 1;
403
404     if (len < _l)
405       return;
406
407     str += _l;
408     len -= _l;
409
410     memcpy(_b + _l, str, len);
411     _l = len + _l;
412   }
413
414 };
415
416
417 PRIVATE static
418 bool
419 Jdb::input_long_mode(Jdb::Cmd *cmd, char const **args)
420 {
421   static Cmd_buffer buf;
422   buf.flush();
423   for (;;)
424     {
425       int c = getchar();
426
427       switch (c)
428         {
429         case KEY_BACKSPACE:
430           if (buf.len() > 0)
431             {
432               cursor(Cursor_left);
433               clear_to_eol();
434               buf.cut(-1);
435             }
436           continue;
437
438         case ' ':
439           if (buf.len() == 0)
440             continue;
441           break;
442
443         case KEY_TAB:
444             {
445               bool multi_match = false;
446               *cmd = Jdb_core::complete_cmd(buf.buffer(), multi_match);
447               if (cmd->cmd && multi_match)
448                 {
449                   printf("\n");
450                   unsigned prefix_len = Jdb_core::print_alternatives(buf.buffer());
451                   print_prompt();
452                   buf.overlay(cmd->cmd->cmd, prefix_len);
453                   putnstr(buf.buffer(), buf.len());
454                 }
455               else if (cmd->cmd)
456                 {
457                   putstr(cmd->cmd->cmd + buf.len());
458                   putchar(' ');
459                   buf.overlay(cmd->cmd->cmd, strlen(cmd->cmd->cmd));
460                   buf.append(' ');
461                 }
462               continue;
463             }
464           break;
465
466         case KEY_RETURN:
467           puts("");
468           if (!buf.len())
469             {
470               hide_statline = false;
471               cmd->cmd = 0;
472               return false;
473             }
474           break;
475
476         default:
477           buf.append(c);
478           printf("\033[K%c", c);
479           continue;
480         }
481
482       *cmd = Jdb_core::has_cmd(buf.buffer());
483       if (cmd->cmd)
484         {
485           unsigned cmd_len = strlen(cmd->cmd->cmd);
486           *args = buf.buffer() + cmd_len;
487           while (**args == ' ')
488             ++(*args);
489           return false; // do not leave the debugger
490         }
491       else
492         {
493           printf("unknown command: '%s'\n", buf.buffer());
494           print_prompt();
495           buf.flush();
496         }
497     }
498 }
499
500 PRIVATE static
501 int
502 Jdb::execute_command()
503 {
504   char const *args;
505   Jdb_core::Cmd cmd(0,0);
506   bool leave;
507   int cmd_key;
508
509   if (short_mode)
510     leave = input_short_mode(&cmd, &args, cmd_key);
511   else
512     leave = input_long_mode(&cmd, &args);
513
514   if (leave)
515     return 0;
516
517   if (cmd.cmd)
518     {
519       int ret = Jdb_core::exec_cmd( cmd, args );
520
521       if (!ret)
522         hide_statline = false;
523
524       last_cmd = cmd_key;
525       return ret;
526     }
527
528   last_cmd = 0;
529   return 1;
530 }
531
532 PRIVATE static
533 bool
534 Jdb::open_debug_console(unsigned cpu)
535 {
536   in_service = 1;
537   save_disable_irqs(cpu);
538   if (cpu == 0)
539     jdb_enter.execute();
540
541   if (!stop_all_cpus(cpu))
542     return false; // CPUs other than 0 never become interacitve
543
544   if (!Jdb_screen::direct_enabled())
545     Kconsole::console()->
546       change_state(Console::DIRECT, 0, ~Console::OUTENABLED, 0);
547
548   return true;
549 }
550
551
552 PRIVATE static
553 void
554 Jdb::close_debug_console(unsigned cpu)
555 {
556   Proc::cli();
557   Mem::barrier();
558   if (cpu == 0)
559     {
560       running.cpu(cpu) = 0;
561       // eat up input from console
562       while (Kconsole::console()->getchar(false)!=-1)
563         ;
564
565       Kconsole::console()->
566         change_state(Console::DIRECT, 0, ~0UL, Console::OUTENABLED);
567
568       in_service = 0;
569       leave_wait_for_others();
570       jdb_leave.execute();
571     }
572
573   Mem::barrier();
574   restore_irqs(cpu);
575 }
576
577 PUBLIC static
578 void
579 Jdb::remote_work(unsigned cpu, void (*func)(unsigned, void *), void *data,
580                  bool sync = true)
581 {
582   if (cpu == 0)
583     func(cpu, data);
584   else
585     {
586       while (1)
587         {
588           Mem::barrier();
589           if (!Jdb::remote_func_running.cpu(cpu))
590             break;
591           Proc::pause();
592         }
593
594       Jdb::remote_func_running.cpu(cpu) = 1;
595       Jdb::remote_func_data.cpu(cpu) = data;
596       Mem::barrier();
597       set_monitored_address(&Jdb::remote_func.cpu(cpu), func);
598       Mem::barrier();
599
600       while (sync)
601         {
602           Mem::barrier();
603           if (!Jdb::remote_func_running.cpu(cpu))
604             break;
605           Proc::pause();
606         }
607     }
608 }
609
610 PUBLIC
611 static int
612 Jdb::getchar(void)
613 {
614   int res = Kconsole::console()->getchar();
615   check_for_cpus(false);
616   return res;
617 }
618
619 IMPLEMENT
620 void Jdb::cursor_home()
621 {
622   putstr("\033[H");
623 }
624
625 IMPLEMENT
626 void Jdb::cursor_end_of_screen()
627 {
628   putstr("\033[127;1H");
629 }
630
631 //-------- pretty print functions ------------------------------
632 PUBLIC static
633 void
634 Jdb::write_ll_ns(Signed64 ns, char *buf, int maxlen, bool sign)
635 {
636   Unsigned64 uns = (ns < 0) ? -ns : ns;
637
638   if (uns >= 3600000000000000ULL)
639     {
640       snprintf(buf, maxlen, ">999 h ");
641       return;
642     }
643
644   if (maxlen && sign)
645     {
646       *buf++ = (ns < 0) ? '-' : (ns == 0) ? ' ' : '+';
647       maxlen--;
648     }
649
650   if (uns >= 60000000000000ULL)
651     {
652       // 1000min...999h
653       Mword _h  = uns / 3600000000000ULL;
654       Mword _m  = (uns % 3600000000000ULL) / 60000000000ULL;
655       snprintf(buf, maxlen, "%3lu:%02lu h  ", _h, _m);
656       return;
657     }
658
659   if (uns >= 1000000000000ULL)
660     {
661       // 1000s...999min
662       Mword _m  = uns / 60000000000ULL;
663       Mword _s  = (uns % 60000000000ULL) / 1000ULL;
664       snprintf(buf, maxlen, "%3lu:%02lu M  ", _m, _s);
665       return;
666     }
667
668   if (uns >= 1000000000ULL)
669     {
670       // 1...1000s
671       Mword _s  = uns / 1000000000ULL;
672       Mword _ms = (uns % 1000000000ULL) / 1000000ULL;
673       snprintf(buf, maxlen, "%3lu.%03lu s ", _s, _ms);
674       return;
675     }
676
677   if (uns >= 1000000)
678     {
679       // 1...1000ms
680       Mword _ms = uns / 1000000UL;
681       Mword _us = (uns % 1000000UL) / 1000UL;
682       snprintf(buf, maxlen, "%3lu.%03lu ms", _ms, _us);
683       return;
684     }
685
686   if (uns == 0)
687     {
688       snprintf(buf, maxlen, "  0       ");
689       return;
690     }
691
692   Console* gzip = Kconsole::console()->find_console(Console::GZIP);
693   Mword _us = uns / 1000UL;
694   Mword _ns = uns % 1000UL;
695   snprintf(buf, maxlen, "%3lu.%03lu %c ", _us, _ns,
696            gzip && gzip->state() & Console::OUTENABLED
697              ? '\265' 
698              : Config::char_micro);
699 }
700
701 PUBLIC static
702 void
703 Jdb::write_ll_hex(Signed64 x, char *buf, int maxlen, bool sign)
704 {
705   // display 40 bits
706   Unsigned64 xu = (x < 0) ? -x : x;
707
708   if (sign)
709     snprintf(buf, maxlen, "%s%03lx" L4_PTR_FMT,
710                           (x < 0) ? "-" : (x == 0) ? " " : "+",
711                           (Mword)((xu >> 32) & 0xfff), (Mword)xu);
712   else
713     snprintf(buf, maxlen, "%04lx" L4_PTR_FMT,
714                           (Mword)((xu >> 32) & 0xffff), (Mword)xu);
715 }
716
717 PUBLIC static
718 void
719 Jdb::write_ll_dec(Signed64 x, char *buf, int maxlen, bool sign)
720 {
721   Unsigned64 xu = (x < 0) ? -x : x;
722
723   // display no more than 11 digits
724   if (xu >= 100000000000ULL)
725     {
726       snprintf(buf, maxlen, "%12s", ">= 10^11");
727       return;
728     }
729
730   if (sign && x != 0)
731     snprintf(buf, maxlen, "%+12lld", x);
732   else
733     snprintf(buf, maxlen, "%12llu", xu);
734 }
735
736 PUBLIC static inline
737 Thread*
738 Jdb::get_current_active()
739 {
740   return current_active;
741 }
742
743 PUBLIC static inline
744 Jdb_entry_frame*
745 Jdb::get_entry_frame(unsigned cpu)
746 {
747   return entry_frame.cpu(cpu);
748 }
749
750 /// handling of standard cursor keys (Up/Down/PgUp/PgDn)
751 PUBLIC static
752 int
753 Jdb::std_cursor_key(int c, Mword cols, Mword lines, Mword max_absy, Mword *absy,
754                     Mword *addy, Mword *addx, bool *redraw)
755 {
756   switch (c)
757     {
758     case KEY_CURSOR_LEFT:
759     case 'h':
760       if (addx)
761         {
762           if (*addx > 0)
763             (*addx)--;
764           else if (*addy > 0)
765             {
766               (*addy)--;
767               *addx = cols - 1;
768             }
769           else if (*absy > 0)
770             {
771               (*absy)--;
772               *addx = cols - 1;
773               *redraw = true;
774             }
775         }
776       else
777         return 0;
778       break;
779     case KEY_CURSOR_RIGHT:
780     case 'l':
781       if (addx)
782         {   
783           if (*addx < cols - 1)
784             (*addx)++;
785           else if (*addy < lines - 1)
786             {
787               (*addy)++; 
788               *addx = 0;
789             }
790           else if (*absy < max_absy)
791             {
792               (*absy)++;
793               *addx = 0;
794               *redraw = true;
795             }
796         }
797       else
798         return 0;
799       break;
800     case KEY_CURSOR_UP:
801     case 'k':
802       if (*addy > 0)
803         (*addy)--;
804       else if (*absy > 0)
805         {
806           (*absy)--;
807           *redraw = true;
808         }
809       break;
810     case KEY_CURSOR_DOWN:
811     case 'j':
812       if (*addy < lines-1)
813         (*addy)++;
814       else if (*absy < max_absy)
815         {
816           (*absy)++;
817           *redraw = true;
818         }
819       break;
820     case KEY_CURSOR_HOME:
821     case 'H':
822       *addy = 0;
823       if (addx)
824         *addx = 0;
825       if (*absy > 0)
826         {
827           *absy = 0;
828           *redraw = true;
829         }
830       break;
831     case KEY_CURSOR_END:
832     case 'L':
833       *addy = lines-1;
834       if (addx)
835         *addx = cols - 1;
836       if (*absy < max_absy)
837         {
838           *absy = max_absy;
839           *redraw = true;
840         }
841       break;
842     case KEY_PAGE_UP:
843     case 'K':
844       if (*absy >= lines)
845         {
846           *absy -= lines;
847           *redraw = true;
848         }
849       else
850         {
851           if (*absy > 0)
852             {
853               *absy = 0;
854               *redraw = true;
855             }
856           else if (*addy > 0)
857             *addy = 0;
858           else if (addx)
859             *addx = 0;
860         }
861       break;
862     case KEY_PAGE_DOWN:
863     case 'J':
864       if (*absy+lines-1 < max_absy)
865         {
866           *absy += lines;
867           *redraw = true;
868         }
869       else
870         {
871           if (*absy < max_absy)
872             {
873               *absy = max_absy;
874               *redraw = true;
875             }
876           else if (*addy < lines-1)
877             *addy = lines-1;
878           else if (addx)
879             *addx = cols - 1;
880         }
881       break;
882     default:
883       return 0;
884     }
885
886   return 1;
887 }
888
889 PUBLIC static inline
890 Space *
891 Jdb::get_task(unsigned cpu)
892 {
893   if (!get_thread(cpu))
894     return 0;
895   else
896     return get_thread(cpu)->space();
897 }
898
899
900 //
901 // memory access wrappers
902 //
903
904 PUBLIC static
905 template< typename T >
906 bool
907 Jdb::peek(T const *addr, Space *task, T &value)
908 {
909   // use an Mword here instead of T as some implementations of peek_task use
910   // an Mword in their operation which is potentially bigger than T
911   // XXX: should be fixed
912   Mword tmp;
913   bool ret = peek_task((Address)addr, task, &tmp, sizeof(T)) == 0;
914   value = tmp;
915   return ret;
916 }
917
918 PUBLIC static
919 template< typename T >
920 bool
921 Jdb::poke(T *addr, Space *task, T const &value)
922 { return poke_task((Address)addr, task, &value, sizeof(T)) == 0; }
923
924
925 class Jdb_base_cmds : public Jdb_module
926 {
927 public:
928   Jdb_base_cmds() FIASCO_INIT;
929 };
930
931 static Jdb_base_cmds jdb_base_cmds INIT_PRIORITY(JDB_MODULE_INIT_PRIO);
932
933 PUBLIC
934 Jdb_module::Action_code
935 Jdb_base_cmds::action (int cmd, void *&, char const *&, int &)
936 {
937   if (cmd!=0)
938     return NOTHING;
939
940   Jdb_core::short_mode = !Jdb_core::short_mode;
941   printf("\ntoggle mode: now in %s command mode (use %s) to switch back\n",
942          Jdb_core::short_mode ? "short" : "long",
943          Jdb_core::short_mode ? "*" : "mode");
944   return NOTHING;
945 }
946
947 PUBLIC
948 int
949 Jdb_base_cmds::num_cmds() const
950
951   return 1;
952 }
953
954 PUBLIC
955 Jdb_module::Cmd const *
956 Jdb_base_cmds::cmds() const
957 {
958   static Cmd cs[] =
959     { { 0, "*", "mode", "", "*|mode\tswitch long and short command mode",
960         (void*)0 } };
961
962   return cs;
963 }
964
965 IMPLEMENT
966 Jdb_base_cmds::Jdb_base_cmds()
967   : Jdb_module("GENERAL")
968 {}
969
970
971 //---------------------------------------------------------------------------
972 IMPLEMENTATION [ux]:
973
974 PRIVATE inline static void Jdb::rcv_uart_enable() {}
975
976 //---------------------------------------------------------------------------
977 IMPLEMENTATION [!ux]:
978
979 #include "kernel_uart.h"
980
981 PRIVATE inline static
982 void
983 Jdb::rcv_uart_enable()
984 {
985   if (Config::serial_esc == Config::SERIAL_ESC_IRQ)
986     Kernel_uart::enable_rcv_irq();
987 }
988
989 //---------------------------------------------------------------------------
990 IMPLEMENTATION:
991
992 #include "ipi.h"
993 #include "logdefs.h"
994
995 char Jdb::esc_iret[]     = "\033[36;1m";
996 char Jdb::esc_bt[]       = "\033[31m";
997 char Jdb::esc_emph[]     = "\033[33;1m";
998 char Jdb::esc_emph2[]    = "\033[32;1m";
999 char Jdb::esc_mark[]     = "\033[35;1m";
1000 char Jdb::esc_line[]     = "\033[37m";
1001 char Jdb::esc_symbol[]   = "\033[33;1m";
1002
1003
1004
1005
1006
1007 IMPLEMENT int
1008 Jdb::enter_jdb(Jdb_entry_frame *e, unsigned cpu)
1009 {
1010   if (e->debug_ipi())
1011     {
1012       if (!remote_work_ipi_process(cpu))
1013         return 0;
1014       if (!in_service)
1015         return 0;
1016     }
1017
1018   enter_trap_handler(cpu);
1019
1020   if (handle_conditional_breakpoint(cpu))
1021     {
1022       // don't enter debugger, only logged breakpoint
1023       leave_trap_handler(cpu);
1024       return 0;
1025     }
1026
1027   if (!running.cpu(cpu))
1028     entry_frame.cpu(cpu) = e;
1029
1030   volatile bool really_break = true;
1031
1032   static jmp_buf recover_buf;
1033   static Jdb_entry_frame nested_trap_frame;
1034
1035   if (running.cpu(cpu))
1036     {
1037       nested_trap_frame = *e;
1038
1039       // Since we entered the kernel debugger a second time,
1040       // Thread::nested_trap_recover
1041       // has a value of 2 now. We don't leave this function so correct the
1042       // entry counter
1043       Thread::nested_trap_recover.cpu(cpu)--;
1044
1045       longjmp(recover_buf, 1);
1046     }
1047
1048   // all following exceptions are handled by jdb itself
1049   running.cpu(cpu) = true;
1050
1051   if (!open_debug_console(cpu))
1052     { // not on the master CPU just wait
1053       close_debug_console(cpu);
1054       leave_trap_handler(cpu);
1055       return 0;
1056     }
1057
1058   Jdb::current_cpu = cpu;
1059   // check for int $3 user debugging interface
1060   if (foreach_cpu(&handle_user_request, true))
1061     {
1062       close_debug_console(cpu);
1063       leave_trap_handler(cpu);
1064       return 0;
1065     }
1066
1067   hide_statline = false;
1068
1069   // clear error message
1070   *error_buffer.cpu(cpu) = '\0';
1071
1072   really_break = foreach_cpu(&handle_debug_traps, false);
1073
1074   while (setjmp(recover_buf))
1075     {
1076       // handle traps which occured while we are in Jdb
1077       Kconsole::console()->end_exclusive(Console::GZIP);
1078       handle_nested_trap(&nested_trap_frame);
1079     }
1080
1081   if (!never_break && really_break) 
1082     {
1083       // determine current task/thread from stack pointer
1084       update_prompt();
1085
1086       LOG_MSG(current_active, "=== enter jdb ===");
1087
1088       do
1089         {
1090           screen_scroll(1, Jdb_screen::height());
1091           if (!hide_statline)
1092             {
1093               cursor(Jdb_screen::height(), 1);
1094               printf("\n%s%s    %.*s\033[m      \n",
1095                      esc_prompt,
1096                      test_checksums()
1097                        ? ""
1098                        : "    WARNING: Fiasco kernel checksum differs -- "
1099                          "read-only data has changed!\n",
1100                      Jdb_screen::width()-11,
1101                      Jdb_screen::Line);
1102               for (unsigned i = 0; i < Config::Max_num_cpus; ++i)
1103                 if (Cpu::online(i))
1104                   {
1105                     if (running.cpu(i))
1106                       printf("    CPU%2u [" L4_PTR_FMT "]: %s\n", i,
1107                              entry_frame.cpu(i)->ip(), error_buffer.cpu(i));
1108                     else
1109                       printf("    CPU%2u: is not in JDB (not responding)\n", i);
1110                   }
1111               hide_statline = true;
1112             }
1113
1114           printf_statline(0, 0, "_");
1115
1116         } while (execute_command());
1117
1118       // reset scrolling region of serial terminal
1119       screen_scroll(1,127);
1120
1121       // reset cursor
1122       blink_cursor(Jdb_screen::height(), 1);
1123
1124       // goto end of screen
1125       Jdb::cursor(127, 1);
1126     }
1127
1128   // reenable interrupts
1129   close_debug_console(cpu);
1130
1131   rcv_uart_enable();
1132
1133   leave_trap_handler(cpu);
1134   return 0;
1135 }
1136
1137
1138 //--------------------------------------------------------------------------
1139 IMPLEMENTATION [!mp]:
1140
1141 PRIVATE static
1142 bool
1143 Jdb::stop_all_cpus(unsigned /*current_cpu*/)
1144 { return true; }
1145
1146 PRIVATE
1147 static
1148 void
1149 Jdb::leave_wait_for_others()
1150 {}
1151
1152 PRIVATE static
1153 bool
1154 Jdb::check_for_cpus(bool)
1155 { return true; }
1156
1157 PRIVATE static inline
1158 int
1159 Jdb::remote_work_ipi_process(unsigned)
1160 { return 1; }
1161
1162
1163 //---------------------------------------------------------------------------
1164 INTERFACE [mp]:
1165
1166 #include "spin_lock.h"
1167
1168 EXTENSION class Jdb
1169 {
1170   // remote call
1171   static Spin_lock<> _remote_call_lock;
1172   static void (*_remote_work_ipi_func)(unsigned, void *);
1173   static void *_remote_work_ipi_func_data;
1174   static unsigned long _remote_work_ipi_done;
1175 };
1176
1177 //--------------------------------------------------------------------------
1178 IMPLEMENTATION [mp]:
1179
1180 void (*Jdb::_remote_work_ipi_func)(unsigned, void *);
1181 void *Jdb::_remote_work_ipi_func_data;
1182 unsigned long Jdb::_remote_work_ipi_done;
1183 Spin_lock<> Jdb::_remote_call_lock;
1184
1185 PRIVATE static
1186 bool
1187 Jdb::check_for_cpus(bool try_nmi)
1188 {
1189   enum { Max_wait_cnt = 1000 };
1190   for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1191     {
1192       if (Cpu::online(c) && !running.cpu(c))
1193         Ipi::send(Ipi::Debug, 0, c);
1194     }
1195   Mem::barrier();
1196 retry:
1197   unsigned long wait_cnt = 0;
1198   for (;;)
1199     {
1200       bool all_there = true;
1201       cpus_in_debugger = 0;
1202       // skip boot cpu 0
1203       for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1204         {
1205           if (Cpu::online(c))
1206             {
1207               if (!running.cpu(c))
1208                 all_there = false;
1209               else
1210                 ++cpus_in_debugger;
1211             }
1212         }
1213
1214       if (!all_there)
1215         {
1216           Proc::pause();
1217           Mem::barrier();
1218           if (++wait_cnt == Max_wait_cnt)
1219             break;
1220           Delay::delay(1);
1221           continue;
1222         }
1223
1224       break;
1225     }
1226
1227   bool do_retry = false;
1228   for (unsigned c = 1; c < Config::Max_num_cpus; ++c)
1229     {
1230       if (Cpu::online(c))
1231         {
1232           if (!running.cpu(c))
1233             {
1234               printf("JDB: CPU %d: is not responding ... %s\n",c,
1235                      try_nmi ? "trying NMI" : "");
1236               if (try_nmi)
1237                 {
1238                   do_retry = true;
1239                   send_nmi(c);
1240                 }
1241             }
1242         }
1243     }
1244   if (do_retry)
1245     {
1246       try_nmi = false;
1247       goto retry;
1248     }
1249   // All CPUs entered JDB, so go on and become interactive
1250   return true;
1251 }
1252
1253 PRIVATE static
1254 bool
1255 Jdb::stop_all_cpus(unsigned current_cpu)
1256 {
1257   enum { Max_wait_cnt = 1000 };
1258   // JDB allways runs on CPU 0, if any other CPU enters the debugger
1259   // CPU 0 is notified to do enter the debugger too
1260   if (current_cpu == 0)
1261     {
1262       // I'm CPU 0 stop all other CPUs and wait for them to enter the JDB
1263       jdb_active = 1;
1264       Mem::barrier();
1265       check_for_cpus(true);
1266       // All CPUs entered JDB, so go on and become interactive
1267       return true;
1268     }
1269   else
1270     {
1271       // Huh, not CPU 0, so notify CPU 0 to enter JDB too
1272       // The notification is ignored if CPU 0 is already within JDB
1273       jdb_active = true;
1274       Ipi::send(Ipi::Debug, current_cpu, 0);
1275
1276       unsigned long wait_count = Max_wait_cnt;
1277       while (!running.cpu(0) && wait_count)
1278         {
1279           Proc::pause();
1280           Delay::delay(1);
1281           Mem::barrier();
1282           --wait_count;
1283         }
1284
1285       if (wait_count == 0)
1286         send_nmi(0);
1287
1288       // Wait for messages from CPU 0
1289       while ((volatile bool)jdb_active)
1290         {
1291           Mem::barrier();
1292           void (**func)(unsigned, void *) = &remote_func.cpu(current_cpu);
1293           void (*f)(unsigned, void *);
1294
1295           if ((f = monitor_address(current_cpu, func)))
1296             {
1297               // Execute functions from queued from another CPU
1298               *func = 0;
1299               f(current_cpu, remote_func_data.cpu(current_cpu));
1300               Mem::barrier();
1301               remote_func_running.cpu(current_cpu) = 0;
1302               Mem::barrier();
1303             }
1304           Proc::pause();
1305         }
1306
1307       // This CPU defacto left JDB
1308       running.cpu(current_cpu) = 0;
1309
1310       // Signal CPU 0, that we are ready to leve the debugger
1311       // This is the second door of the airlock
1312       atomic_mp_add(&cpus_in_debugger, -1UL);
1313
1314       // Wait for CPU 0 to leave us out
1315       while ((volatile bool)leave_barrier)
1316         {
1317           Mem::barrier();
1318           Proc::pause();
1319         }
1320
1321       // CPU 0 signaled us to leave JDB
1322       return false;
1323     }
1324 }
1325
1326 PRIVATE
1327 static
1328 void
1329 Jdb::leave_wait_for_others()
1330 {
1331   leave_barrier = 1;
1332   jdb_active = 0;
1333   Mem::barrier();
1334   for (;;)
1335     {
1336       bool all_there = true;
1337       for (unsigned c = 0; c < Config::Max_num_cpus; ++c)
1338         {
1339           if (Cpu::online(c) && running.cpu(c))
1340             {
1341               // notify other CPU
1342               set_monitored_address(&Jdb::remote_func.cpu(c),
1343                                     (void (*)(unsigned, void *))0);
1344 //            printf("JDB: wait for CPU[%2u] to leave\n", c);
1345               all_there = false;
1346             }
1347         }
1348
1349       if (!all_there)
1350         {
1351           Proc::pause();
1352           Mem::barrier();
1353           continue;
1354         }
1355
1356       break;
1357     }
1358
1359   while ((volatile unsigned long)cpus_in_debugger)
1360     {
1361       Mem::barrier();
1362       Proc::pause();
1363     }
1364
1365   Mem::barrier();
1366   leave_barrier = 0;
1367 }
1368
1369 // The remote_work_ipi* functions are for the IPI round-trip benchmark (only)
1370 PRIVATE static
1371 int
1372 Jdb::remote_work_ipi_process(unsigned cpu)
1373 {
1374   if (_remote_work_ipi_func)
1375     {
1376       _remote_work_ipi_func(cpu, _remote_work_ipi_func_data);
1377       Mem::barrier();
1378       _remote_work_ipi_done = 1;
1379       return 0;
1380     }
1381   return 1;
1382 }
1383
1384 PUBLIC static
1385 bool
1386 Jdb::remote_work_ipi(unsigned this_cpu, unsigned to_cpu,
1387                      void (*f)(unsigned, void *), void *data, bool wait = true)
1388 {
1389   if (to_cpu == this_cpu)
1390     {
1391       f(this_cpu, data);
1392       return true;
1393     }
1394
1395   if (!Cpu::online(to_cpu))
1396     return false;
1397
1398   auto guard = lock_guard(_remote_call_lock);
1399
1400   _remote_work_ipi_func      = f;
1401   _remote_work_ipi_func_data = data;
1402   _remote_work_ipi_done      = 0;
1403
1404   Ipi::send(Ipi::Debug, this_cpu, to_cpu);
1405
1406   if (wait)
1407     while (!*(volatile unsigned long *)&_remote_work_ipi_done)
1408       Proc::pause();
1409
1410   _remote_work_ipi_func = 0;
1411
1412   return true;
1413 }