]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/jdb_tbuf_show.cpp
update
[l4.git] / kernel / fiasco / src / jdb / jdb_tbuf_show.cpp
1 IMPLEMENTATION:
2
3 #include <cstdio>
4 #include <cstring>
5
6 #include "config.h"
7 #include "cpu.h"
8 #include "jdb.h"
9 #include "jdb_disasm.h"
10 #include "jdb_input.h"
11 #include "jdb_module.h"
12 #include "jdb_screen.h"
13 #include "jdb_symbol.h"
14 #include "jdb_regex.h"
15 #include "jdb_tbuf.h"
16 #include "jdb_tbuf_output.h"
17 #include "kern_cnt.h"
18 #include "kernel_console.h"
19 #include "keycodes.h"
20 #include "perf_cnt.h"
21 #include "simpleio.h"
22 #include "static_init.h"
23 #include "thread.h"
24
25 class Jdb_tbuf_show : public Jdb_module
26 {
27 public:
28   Jdb_tbuf_show() FIASCO_INIT;
29
30 private:
31   static char  _search_str[40];
32   static char  _filter_str[40];
33   static char  _buffer_str[512];
34   static Mword _status_type;
35   static Mword _absy;
36   static Mword _nr_cur;
37   static Mword _nr_ref;
38   static Mword _nr_pos[10];
39   static Mword y_offset;
40
41   enum
42   {
43     Index_mode        = 0, // number of event
44     Tsc_delta_mode    = 1, // tsc ticks starting from last event
45     Tsc_ref_mode      = 2, // tsc ticks starting from reference event
46     Tsc_start_mode    = 3, // tsc ticks starting from 0
47     Kclock_ref_mode   = 4, // kernel clock units (us) since reference event
48     Kclock_start_mode = 5, // kernel clock units (us) since start of system
49     Pmc1_delta_mode   = 6, // ticks of ctr 1 starting from last event
50     Pmc2_delta_mode   = 7, // ticks of ctr 2 starting from last event
51     Pmc1_ref_mode     = 8, // ticks of ctr 1 starting from reference event
52     Pmc2_ref_mode     = 9, // ticks of ctr 2 starting from reference event
53   };
54
55   enum
56   {
57     Tbuf_start_line   = 3,
58   };
59
60   enum
61   {
62     Status_ok         = 0,
63     Status_redraw     = 1,
64     Status_error      = 2,
65   };
66
67   enum
68   {
69     Nil               = (Mword)-1,
70   };
71 };
72
73 char  Jdb_tbuf_show::_search_str[40];
74 char  Jdb_tbuf_show::_filter_str[40];
75 char  Jdb_tbuf_show::_buffer_str[512];
76 Mword Jdb_tbuf_show::_status_type;
77 Mword Jdb_tbuf_show::_absy;
78 Mword Jdb_tbuf_show::_nr_cur;
79 Mword Jdb_tbuf_show::_nr_ref;
80 Mword Jdb_tbuf_show::_nr_pos[10] = { Nil, Nil, Nil, Nil, Nil,
81                                      Nil, Nil, Nil, Nil, Nil };
82
83 Mword Jdb_tbuf_show::y_offset = 0;
84
85 static void
86 Jdb_tbuf_show::error(const char * const msg)
87 {
88   Jdb::printf_statline("tbuf", 0, "\033[31;1m=== %s! ===\033[m", msg);
89   _status_type = Status_error;
90 }
91
92 static int
93 Jdb_tbuf_show::get_string(char *string, unsigned size)
94 {
95   for (unsigned pos=strlen(string); ; )
96     {
97       switch(int c=Jdb_core::getchar())
98         {
99         case KEY_BACKSPACE:
100           if (pos)
101             {
102               putstr("\b \b");
103               string[--pos] = '\0';
104             }
105           break;
106         case KEY_RETURN:
107           return 1;
108         case KEY_ESC:
109           Jdb::abort_command();
110           return 0;
111         default:
112           if (c >= ' ')
113             {
114               if (pos < size-1)
115                 {
116                   putchar(c);
117                   string[pos++] = c;
118                   string[pos  ] = '\0';
119                 }
120             }
121         }
122     }
123 }
124
125 static void
126 Jdb_tbuf_show::show_perf_event_unit_mask_entry(Mword nr, Mword idx,
127                                                Mword unit_mask, int exclusive)
128 {
129   const char *desc;
130   Mword value;
131
132   Perf_cnt::get_unit_mask_entry(nr, idx, &value, &desc);
133   if (!desc || !*desc)
134     desc = "(no description?)";
135   printf("  %c %02lx %.59s\033[K",
136       exclusive ? unit_mask == value ? '+' : ' '
137                 : unit_mask  & value ? '+' : ' ',
138       value, desc);
139 }
140
141 static void
142 Jdb_tbuf_show::show_perf_event(Mword nr)
143 {
144   const char *name, *desc;
145   unsigned evntsel;
146   Mword add_kcnt = Config::Jdb_accounting ? Kern_cnt_max : 0;
147
148   if (nr < add_kcnt)
149     {
150       const char * const s = Kern_cnt::get_str(nr);
151       printf("   %-26.26s %.49s\033[K", s, "(kernel event counter)");
152       return;
153     }
154
155   Perf_cnt::get_perf_event(nr - add_kcnt, &evntsel, &name, &desc);
156   if (!name || !*name)
157     name = "(no name?)";
158   if (!desc || !*desc)
159     desc = "(no description)";
160
161   printf("%02x %-26.26s %.49s\033[K", evntsel, name, desc);
162 }
163
164 static Mword
165 Jdb_tbuf_show::select_perf_event_unit_mask(Mword nr, Mword unit_mask)
166 {
167   Mword absy     = 0;
168   Mword addy     = 0;
169   Mword max_absy = 0;
170   Mword lines    = 10;
171   Mword cols     = Jdb_screen::cols() - 1;
172
173   Mword default_value, nvalues, value;
174   Perf_cnt::Unit_mask_type type;
175   const char *desc;
176
177   Perf_cnt::get_unit_mask(nr, &type, &default_value, &nvalues);
178   int  exclusive = (type == Perf_cnt::Exclusive);
179
180   if (type == Perf_cnt::None)
181     return 0;
182
183   if (type == Perf_cnt::Fixed || (nvalues < 1))
184     return default_value;
185
186   if (nvalues == 1)
187     {
188       Perf_cnt::get_unit_mask_entry(nr, 0, &value, &desc);
189       return value;
190     }
191
192   if (nvalues < lines)
193     lines = nvalues;
194
195   Jdb::printf_statline("tbuf", "<Space>=set mask <CR>=done", "P?");
196
197   Jdb::cursor(Tbuf_start_line, 1);
198   putstr("\033[32m");
199   show_perf_event(nr + (Config::Jdb_accounting ? Kern_cnt_max : 0));
200   printf("\033[m\033[K\n"
201          "\033[K\n"
202          "  \033[1;32mSelect Event Mask (%s):\033[m\033[K\n"
203          "\033[K\n", exclusive ? "exclusive" : "bitmap");
204
205   for (;;)
206     {
207       Mword i;
208
209       Jdb::cursor(Tbuf_start_line+4, 1);
210       for (i=0; i<lines; i++)
211         {
212           show_perf_event_unit_mask_entry(nr, i, unit_mask, exclusive);
213           putchar('\n');
214         }
215       for (; i<Jdb_screen::height()-Tbuf_start_line-5; i++)
216         puts("\033[K");
217
218       for (bool redraw=false; !redraw; )
219         {
220           int c;
221           const char *dummy;
222           Mword value;
223
224           Jdb::cursor(addy+Tbuf_start_line+4, 1);
225           putstr(Jdb::esc_emph);
226           show_perf_event_unit_mask_entry(nr, absy+addy, unit_mask, exclusive);
227           putstr("\033[m");
228           Jdb::cursor(addy+Tbuf_start_line+4, 1);
229           c = Jdb_core::getchar();
230           show_perf_event_unit_mask_entry(nr, absy+addy, unit_mask, exclusive);
231           Perf_cnt::get_unit_mask_entry(nr, absy+addy, &value, &dummy);
232
233           if (Jdb::std_cursor_key(c, cols, lines, max_absy,
234                                   &absy, &addy, 0, &redraw))
235             continue;
236
237           switch (c)
238             {
239             case ' ':
240               if (exclusive)
241                 {
242                   unit_mask = value;
243                   redraw = true;
244                 }
245               else
246                 unit_mask ^= value;
247               break;
248             case KEY_RETURN:
249               return unit_mask;
250             case KEY_ESC:
251               return Nil;
252             default:
253               if (Jdb::is_toplevel_cmd(c)) 
254                 return Nil;
255             }
256         }
257     }
258 }
259
260 static Mword
261 Jdb_tbuf_show::select_perf_event(Mword event)
262 {
263   Mword absy     = 0;
264   Mword addy     = 0;
265   Mword add_kcnt = Config::Jdb_accounting ? Kern_cnt_max : 0;
266   Mword nevents  = Perf_cnt::get_max_perf_event() + add_kcnt;
267   Mword lines    = (nevents < Jdb_screen::height()-6) 
268                             ? nevents 
269                             : Jdb_screen::height()-6;
270   Mword cols     = Jdb_screen::cols() - 1;
271   Mword max_absy = nevents-lines;
272
273   if (nevents == 0)
274     // libperfctr not linked
275     return Nil;
276
277   unsigned evntsel;
278   Mword unit_mask;
279
280   Jdb::printf_statline("tbuf", "<CR>=select", "P?");
281
282   Jdb::cursor(Tbuf_start_line, 1);
283   printf("%sSelect Performance Counter\033[m\033[K\n\033[K", Jdb::esc_emph2);
284
285   if (event & 0x80000000)
286     addy = event & 0xff;
287   else
288     {
289       Perf_cnt::split_event(event, &evntsel, &unit_mask);
290       addy = Perf_cnt::lookup_event(evntsel);
291       if (addy == Nil)
292         addy = 0;
293       else
294         addy += add_kcnt;
295     }
296
297   if (addy > lines-1)
298     {
299       absy += (addy-lines+1);
300       addy = lines-1;
301     }
302
303   for (;;)
304     {
305       Mword i;
306
307       Jdb::cursor(Tbuf_start_line+2, 1);
308       for (i=0; i<lines; i++)
309         {
310           show_perf_event(absy+i);
311           putchar('\n');
312         }
313       for (; i<Jdb_screen::height()-Tbuf_start_line-2; i++)
314         puts("\033[K");
315
316       for (bool redraw=false; !redraw; )
317         {
318           const char *dummy;
319
320           Jdb::cursor(addy+Tbuf_start_line+2, 1);
321           putstr(Jdb::esc_emph);
322           show_perf_event(absy+addy);
323           putstr("\033[m");
324           Jdb::cursor(addy+Tbuf_start_line+2, 1);
325           int c = Jdb_core::getchar();
326           show_perf_event(absy+addy);
327           if (Jdb::std_cursor_key(c, cols, lines, max_absy, 
328                                   &absy, &addy, 0, &redraw))
329             continue;
330
331           switch (c)
332             {
333             case KEY_RETURN:
334               absy += addy;
335               if (absy < add_kcnt)
336                 return absy | 0x80000000;
337
338               absy -= add_kcnt;
339               Perf_cnt::get_perf_event(absy, &evntsel, &dummy, &dummy);
340               unit_mask = select_perf_event_unit_mask(absy, unit_mask);
341               if (unit_mask != Nil)
342                 {
343                   Perf_cnt::combine_event(evntsel, unit_mask, &event);
344                   return event;
345                 }
346               // else fall through
347             case KEY_ESC:
348               return Nil;
349             default:
350               if (Jdb::is_toplevel_cmd(c)) 
351                 return Nil;
352             }
353         }
354     }
355 }
356
357
358 static void
359 Jdb_tbuf_show::show_events(Mword n, Mword ref, Mword count, Unsigned8 mode,
360                            Unsigned8 time_mode, int long_output)
361 {
362   Unsigned64 ref_tsc;
363   Unsigned32 ref_kclock, ref_pmc1, ref_pmc2;
364   Mword dummy, i;
365
366   Jdb_tbuf::event(ref, &dummy, &ref_kclock, &ref_tsc, &ref_pmc1, &ref_pmc2);
367
368   for (i=0; i<count; i++)
369     {
370       Mword number;
371       Signed64 dtsc;
372       Signed32 dpmc;
373       Unsigned64 utsc;
374       Unsigned32 kclock, upmc1, upmc2;
375
376       Kconsole::console()->getchar_chance();
377
378       if (!Jdb_tbuf::event(n, &number, &kclock, &utsc, &upmc1, &upmc2))
379         break;
380
381       if (long_output)
382         {
383           char s[3];
384           Jdb_tbuf_output::print_entry(n, _buffer_str, sizeof(_buffer_str));
385
386           if (!Jdb_tbuf::diff_tsc(n, &dtsc))
387             dtsc = 0;
388
389           strcpy(s, "  ");
390           if (n == ref)
391             {
392               s[0] = 'R';
393               s[1] = ' ';
394             }
395           else
396             {
397               for (int i=0; i<10; i++)
398                 if (number == _nr_pos[i])
399                   {
400                     s[0] = 'M';
401                     s[1] = i+'0';
402                     break;
403                   }
404             }
405
406           char s_tsc_dc[13], s_tsc_ds[15], s_tsc_sc[13], s_tsc_ss[15];
407           Jdb::write_ll_dec(dtsc, s_tsc_dc, sizeof(s_tsc_dc), false);
408           Jdb::write_tsc_s (dtsc, s_tsc_ds, sizeof(s_tsc_ds), false);
409           Jdb::write_ll_dec(utsc, s_tsc_sc, sizeof(s_tsc_sc), false);
410           Jdb::write_tsc_s (utsc, s_tsc_ss, sizeof(s_tsc_ss), false);
411
412           printf("%-3s%10lu.  %120.120s %13.13s (%14.14s)  %13.13s (%14.14s) kclk=%d\n",
413                  s, number, _buffer_str+y_offset, s_tsc_dc, s_tsc_ds, s_tsc_sc, s_tsc_ss, kclock);
414         }
415       else
416         {
417           char s[13];
418           Jdb_tbuf_output::print_entry(n, _buffer_str, sizeof(_buffer_str));
419           switch (mode)
420             {
421             case Index_mode:
422               snprintf(s, sizeof(s), "%12lu", number);
423               break;
424             case Tsc_delta_mode:
425               if (!Jdb_tbuf::diff_tsc(n, &dtsc))
426                 dtsc = 0;
427               switch (time_mode)
428                 {
429                 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), false); break;
430                 case 1: Jdb::write_tsc   (dtsc, s, sizeof(s), false); break;
431                 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), false); break;
432                 }
433               break;
434             case Tsc_ref_mode:
435               dtsc = (n == ref) ? 0 : utsc - ref_tsc;
436               switch (time_mode)
437                 {
438                 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), true); break;
439                 case 1: Jdb::write_tsc   (dtsc, s, sizeof(s), true); break;
440                 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), true); break;
441                 }
442               break;
443             case Tsc_start_mode:
444               dtsc = utsc;
445               switch (time_mode)
446                 {
447                 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), true); break;
448                 case 1: Jdb::write_tsc   (dtsc, s, sizeof(s), false); break;
449                 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), true); break;
450                 }
451               break;
452             case Kclock_ref_mode:
453               if (kclock == ref_kclock)
454                 snprintf(s, sizeof(s), "%12u", 0);
455               else
456                 {
457                   if (time_mode != 1)
458                     Jdb::write_ll_hex((Unsigned64)kclock-ref_kclock,
459                                       s, sizeof(s), true);
460                   else
461                     snprintf(s, sizeof(s), "%+12d", kclock-ref_kclock);
462                 }
463               break;
464             case Kclock_start_mode:
465               snprintf(s, sizeof(s), time_mode != 1 ? "%012x" : "%12u", 
466                        kclock);
467               break;
468             case Pmc1_delta_mode:
469             case Pmc2_delta_mode:
470               if (!Jdb_tbuf::diff_pmc(n, (mode-Pmc1_delta_mode), &dpmc))
471                 dpmc = 0;
472               Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), false);
473               break;
474             case Pmc1_ref_mode:
475               dpmc = (n == ref) ? 0 : upmc1 - ref_pmc1;
476               Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), true);
477               break;
478             case Pmc2_ref_mode:
479               dpmc = (n == ref) ? 0 : upmc2 - ref_pmc2;
480               Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), true);
481               break;
482             }
483
484           const char *c = "";
485           if (n == ref)
486             c = Jdb::esc_emph2;
487           else
488             {
489               for (int i=0; i<10; i++)
490                 if (number == _nr_pos[i])
491                   {
492                     c = Jdb::esc_mark;
493                     break;
494                   }
495             }
496           printf("%s%-*.*s %12s\033[m%s",
497                  c, Jdb_screen::width()-13, (int)Jdb_screen::width()-13,
498                  _buffer_str+y_offset, s, count != 1 ? "\n" : "");
499         }
500        n++;
501     }
502 }
503
504 // search in tracebuffer
505 static Mword
506 Jdb_tbuf_show::search(Mword start, Mword entries, const char *str, 
507                       Unsigned8 direction)
508 {
509   Mword found = Nil;
510
511   if (!entries)
512     return found;
513
514   if (Jdb_regex::avail() && !Jdb_regex::start(str))
515     {
516       error("Error in regular expression");
517       return found;
518     }
519
520   for (Mword n=direction==1 ? start-1 : start+1; ; (direction==1) ? n-- : n++)
521     {
522       static char buffer[120];
523
524       // don't cycle through entries more than once 
525       // (should not happen due to the following check)
526       if (n == start)
527         break;
528       // don't wrap around
529       if (!Jdb_tbuf::event_valid(n))
530         {
531           error(direction ? "Begin of tracebuffer reached"
532                           : "End of tracebuffer reached");
533           return found;
534         }
535
536       if (!Jdb_tbuf::event_valid(n))
537         n = (direction==1) ? entries-1 : 0;
538
539       Jdb_tbuf_output::print_entry(n, buffer, sizeof(buffer));
540
541       // progress bar
542       if ((n & 0x7f) == 0)
543         {
544           static int progress;
545           Jdb::cursor(Jdb_screen::height(), 79);
546           putchar("|/-\\"[progress++]);
547           progress &= 3;
548         }
549
550       if (Jdb_regex::avail() && Jdb_regex::find(buffer, 0, 0))
551         {
552           found = n;
553           break;
554         }
555       else if (strstr(buffer, str))
556         {
557           found = n;
558           break;
559         }
560     }
561
562   // restore screen
563   Jdb::cursor(Jdb_screen::height(), 79);
564   putchar('t');
565
566   return found;
567 }
568
569 static void
570 Jdb_tbuf_show::show()
571 {
572   static Unsigned8 mode      = Index_mode;
573   static Unsigned8 time_mode = 1;
574   static Unsigned8 direction = 0;
575   Mword  entries;
576
577   Jdb_tbuf_output::set_filter(_filter_str, &entries);
578   Jdb::clear_screen();
579
580 restart:
581   Mword refy;                    // idx of reference event
582   Mword posy[10];                // idx of mark{0..9}
583   Mword addy;                    // cursor position starting from top of screen
584   Mword lines = Jdb_screen::height()-4;
585   Mword cols  = Jdb_screen::cols() - 1;
586   Mword n;
587   Tb_entry *e;
588
589   if (Jdb_tbuf::max_entries() < lines)
590     lines = Jdb_tbuf::max_entries();
591   if (entries < lines)
592     lines = entries;
593   if (lines < 1)
594     lines = 1;
595
596   Mword max_absy = entries > lines ? entries - lines : 0;
597
598   // Search reference element. If not found, use last entry.
599   if ((refy = Jdb_tbuf::search_to_idx(_nr_ref)) >= (Mword)-2)
600     if (entries)
601       refy = entries-1;
602     else
603       refy = Nil;
604
605   // Search mark {0..9}. If not found, set Nil.
606   for (n=0; n<10; n++)
607     posy[n] = Jdb_tbuf::search_to_idx(_nr_pos[n]);
608
609   // Search current position. If beyond buffer, goto first entry.
610   if ((addy = Jdb_tbuf::search_to_idx(_nr_cur)))
611     addy -= _absy;
612   else
613     addy = _absy = 0;
614   if (addy >= lines-1)
615     addy = _absy = 0;
616
617   for (;;)
618     {
619       Mword count, perf_event[2];
620       Mword perf_user[2] = { 0, 0 };
621       Mword perf_kern[2] = { 0, 0 };
622       Mword perf_edge[2] = { 0, 0 };
623       const char *perf_mode[2], *perf_name[2];
624
625       for (Mword i=0; i<2; i++)
626         if (Kern_cnt::mode (i, &perf_mode[i], &perf_name[i], &perf_event[i]) ||
627             Perf_cnt::mode (i, &perf_mode[i], &perf_name[i], &perf_event[i],
628                                &perf_user[i], &perf_kern[i], &perf_edge[i])) {}
629
630       static const char * const mode_str[] =
631         { "index", "tsc diff", "tsc rel", "tsc start", "kclock rel",
632           "kclock", "pmc1 diff", "pmc2 diff", "pmc1 rel", "pmc2 rel" };
633
634       const char *perf_type = Perf_cnt::perf_type();
635
636       Jdb::cursor();
637       printf("%3lu%% of %-6lu Perf:%-4s 1="L4_PTR_FMT
638              "(%s%s\033[m%s%s%s\033[m)\033[K",
639           Jdb_tbuf::unfiltered_entries()*100/Jdb_tbuf::max_entries(), 
640           Jdb_tbuf::max_entries(),
641           perf_type, perf_event[0], Jdb::esc_emph, perf_mode[0], 
642           perf_name[0] && *perf_name[0] ? ":" : "",
643           mode==Pmc1_delta_mode || mode==Pmc1_ref_mode ? Jdb::esc_emph : "",
644           perf_name[0]);
645
646       Jdb::cursor(1, 71);
647       printf("%10s\n"
648              "%24s 2="L4_PTR_FMT"(%s%s\033[m%s%s%s\033[m)\033[K\n",
649           mode_str[(int)mode], "",
650           perf_event[1], Jdb::esc_emph, perf_mode[1],
651           perf_name[1] && *perf_name[1] ? ":" : "", 
652           mode==Pmc2_delta_mode || mode==Pmc2_ref_mode ? Jdb::esc_emph : "",
653           perf_name[1]);
654       if (_filter_str[0])
655         {
656           Jdb::cursor(2, 1);
657           printf("\033[31m%3lu%% filtered\033[m\n",
658               entries*100/Jdb_tbuf::max_entries());
659         }
660       for (Mword i=3; i<Tbuf_start_line; i++)
661         puts("\033[K");
662
663       show_events(_absy, refy, lines, mode, time_mode, 0);
664       if (lines == 1)
665         puts("\033[K");
666
667       for (Mword i=Tbuf_start_line+lines; i<Jdb_screen::height(); i++)
668         puts("\033[K");
669
670       _status_type = Status_redraw;
671
672  status_line:
673       for (bool redraw=false; !redraw;)
674         {
675           Tb_entry *pair_event = 0;
676           Mword pair_y = 0;
677           Smword c;
678           Unsigned8 type;
679           Unsigned8 d = 0; // default search direction is forward
680
681           if (_status_type == Status_redraw)
682             {
683               Jdb::printf_statline("tbuf", "/?nN=search sj=mark c=clear r=ref "
684                                    "F=filter D=dump P=perf <CR>=select", "_");
685               _status_type = Status_ok;
686             }
687           else if (_status_type == Status_error)
688             _status_type = Status_redraw;
689
690           if (!_filter_str[0])
691             {
692               // search for paired ipc event
693               pair_event = Jdb_tbuf::ipc_pair_event(_absy+addy, &type);
694               if (!pair_event)
695                 // search for paired pagefault event
696                 pair_event = Jdb_tbuf::pf_pair_event(_absy+addy, &type);
697               if (pair_event)
698                 {
699                   pair_y = Jdb_tbuf::idx(pair_event);
700                   if (pair_y < _absy || pair_y >= _absy+lines)
701                     pair_event = 0;
702                 }
703               if (pair_event)
704                 {
705                   Jdb::cursor(pair_y-_absy+Tbuf_start_line, 1);
706                   putstr(Jdb::esc_emph);
707                   switch (type)
708                     {
709                     case Jdb_tbuf::Result: putstr("+++>"); break;
710                     case Jdb_tbuf::Event:  putstr("<+++"); break;
711                     }
712                   putstr("\033[m");
713                 }
714             }
715
716           Jdb::cursor(addy+Tbuf_start_line, 1);
717           putstr(Jdb::esc_emph);
718           show_events(_absy+addy, refy, 1, mode, time_mode, 0);
719           putstr("\033[m");
720           Jdb::cursor(addy+Tbuf_start_line, 1);
721           c=Jdb_core::getchar();
722           show_events(_absy+addy, refy, 1, mode, time_mode, 0);
723           if (pair_event)
724             {
725               Jdb::cursor(pair_y-_absy+Tbuf_start_line, 1);
726               show_events(pair_y, refy, 1, mode, time_mode, 0);
727             }
728
729           if (Jdb::std_cursor_key(c, cols, lines, max_absy, 
730                                   &_absy, &addy, 0, &redraw))
731             continue;
732
733           switch (c)
734             {
735             case 'h':
736               if (y_offset>10)
737                 y_offset -= 10;
738               else
739                 y_offset = 0;
740
741               redraw = true;
742               break;
743             case 'l':
744               if (y_offset<sizeof(_buffer_str)-82)
745                 y_offset += 10;
746               else
747                 y_offset = sizeof(_buffer_str)-72;
748
749               redraw = true;
750               break;
751             case 'F': // filter view by regex
752               Jdb::printf_statline("tbuf", 0, "Filter(%s)=%s",
753                                    Jdb_regex::avail() ? "regex" : "instr",
754                                    _filter_str);
755               _status_type = Status_redraw;
756               Jdb::cursor(Jdb_screen::height(), 21+strlen(_filter_str));
757               if (!get_string(_filter_str, sizeof(_filter_str)))
758                 goto status_line;
759               if (!Jdb_tbuf_output::set_filter(_filter_str, &entries))
760                 {
761                   error("Error in regular expression");
762                   goto status_line;
763                 }
764               _absy   = 0;
765               _nr_cur = Nil;
766               goto restart;
767             case 'D': // dump to console
768               if (!Kconsole::console()->find_console(Console::GZIP))
769                 break;
770               Jdb::cursor(Jdb_screen::height(), 10);
771               Jdb::clear_to_eol();
772               printf("Count=");
773               if (Jdb_input::get_mword(&count, 7, 10))
774                 {
775                   if (count == 0)
776                     count = lines;
777                   Kconsole::console()->start_exclusive(Console::GZIP);
778                   show_events(_absy, refy, count, mode, time_mode, 1);
779                   Kconsole::console()->end_exclusive(Console::GZIP);
780                   redraw = true;
781                   break;
782                 }
783               _status_type = Status_redraw;
784               goto status_line;
785             case 'P': // set performance counter
786                 {
787                   Mword event, e;
788                   int user, kern, edge, nr;
789
790                   Jdb::printf_statline("tbuf", "1..2=select counter", "P");
791                   Jdb::cursor(Jdb_screen::height(), 8);
792                   for (;;)
793                     {
794                       nr = Jdb_core::getchar();
795                       if (nr == KEY_ESC)
796                         goto exit;
797                       if (nr >= '1' && nr <= '2')
798                         {
799                           nr -= '1';
800                           break;
801                         }
802                     }
803
804                   event = perf_event[nr];
805                   user  = perf_user[nr];
806                   kern  = perf_kern[nr];
807                   edge  = perf_edge[nr];
808                   Jdb::printf_statline("tbuf", "d=duration e=edge u=user "
809                                        "k=kern +=both -=none ?=event",
810                                        "P%c", (char)'1'+nr);
811
812                   Jdb::cursor(Jdb_screen::height(), 9);
813                   switch(c=Jdb_core::getchar())
814                     {
815                     case '+': user = 1; kern = 1;            break;
816                     case '-': user = 0; kern = 0; event = 0; break;
817                     case 'u': user = 1; kern = 0;            break;
818                     case 'k': user = 0; kern = 1;            break;
819                     case 'd': edge = 0;                      break;
820                     case 'e': edge = 1;                      break;
821                     case '?':
822                     case '_': if ((e = select_perf_event(event)) == Nil)
823                                 {
824                                   redraw = true;
825                                   break;
826                                 }
827                               event = e;
828                               redraw = true;
829                               break;
830                     default:  Jdb_input::get_mword(&event, 4, 16, c);
831                               break;
832                     }
833                 
834                   if (!Kern_cnt::setup_pmc(nr, event) &&
835                       !Perf_cnt::setup_pmc(nr, event, user, kern, edge))
836                     Tb_entry::set_rdcnt(nr, 0);
837
838                   redraw = true;
839                 }
840               break;
841             case KEY_RETURN: // disassemble eip of current entry
842                 {
843                   Thread const *t = 0;
844                   Mword eip;
845                   if (Jdb_tbuf_output::thread_ip(_absy+addy, &t, &eip))
846                     {
847                       if (Jdb_disasm::avail())
848                         {
849                           if (!Jdb_disasm::show(eip, t->space(), 1, 1))
850                             goto exit;
851                         }
852                       else
853                         { // hacky, we should get disasm working for arm too
854                           // (at least without the disassembly itself)
855                           printf("\n==========================\n"
856                                  "   ip=%lx                 \n"
857                                  "==========================\n", eip);
858                           Jdb_core::getchar();
859                         }
860                       redraw = true;
861                     }
862                 }
863               break;
864             case KEY_TAB:
865               Jdb_tbuf_output::toggle_names();
866               redraw = true;
867               break;
868             case KEY_CURSOR_LEFT: // mode switch
869               if (mode == Index_mode)
870                 mode = Pmc2_ref_mode;
871               else
872                 mode--;
873               redraw = true;
874               break;
875             case KEY_CURSOR_RIGHT: // mode switch
876               mode++;
877               if (mode > Pmc2_ref_mode)
878                 mode = Index_mode;
879               redraw = true;
880               break;
881             case ' ': // mode switch
882               if (mode != Index_mode)
883                 {
884                   time_mode = (time_mode+1) % 3;
885                   redraw = true;
886                 }
887               break;
888             case 'c': // clear tracebuffer
889               Jdb_tbuf::clear_tbuf();
890               _absy   = 0;
891               _nr_cur = Nil;
892               _nr_ref = Nil;
893               entries = 0;
894               for (n=0; n<10; n++)
895                 _nr_pos[n] = Nil;
896               goto restart;
897             case 's': // set mark
898               Jdb::printf_statline("tbuf", 0, "set mark [0-9] ");
899               _status_type = Status_redraw;
900               c = Jdb_core::getchar();
901               if (!entries || c < '0' || c > '9')
902                 {
903                   error("Invalid marker");
904                   goto status_line;
905                 }
906               n = c - '0';
907               posy[n]    = _absy + addy;
908               _nr_pos[n] = Jdb_tbuf::lookup(_absy+addy)->number();
909               redraw     = true;
910               break;
911             case 'r': // set reference entry
912               if (!entries)
913                 break;
914               refy       = _absy + addy;
915               _nr_ref    = Jdb_tbuf::lookup(_absy+addy)->number();
916               redraw     = true;
917               break;
918             case 'j': // jump to mark or reference element
919               Jdb::printf_statline("tbuf", 0, "jump to mark [0-9] or ref [r] ");
920               _status_type = Status_redraw;
921               c = Jdb_core::getchar();
922               if ((c < '0' || c > '9') && c != 'r')
923                 {
924                   error("Invalid marker");
925                   goto status_line;
926                 }
927               n = (c == 'r') ? refy : posy[c-'0'];
928               if (n == Nil)
929                 {
930                   error("Mark unset");
931                   goto status_line;
932                 }
933               else if (n == (Mword)-2)
934                 {
935                   error("Mark not visible within current filter");
936                   goto status_line;
937                 }
938               goto jump_index;
939             case '?': // search backward
940               d = 1;
941               // fall through
942             case '/': // search forward
943               direction = d;
944               // search in tracebuffer events
945               Jdb::printf_statline("tbuf", 0, "%s=%s",
946                                    Jdb_regex::avail() ? "Regexp" : "Search", 
947                                    _search_str);
948               _status_type = Status_redraw;
949               Jdb::cursor(Jdb_screen::height(), 14+strlen(_search_str));
950               if (!get_string(_search_str, sizeof(_search_str)) ||
951                   !_search_str[0])
952                 goto status_line;
953               // fall through
954             case 'n': // search next
955             case 'N': // search next reverse
956               n = search(_absy+addy, entries, _search_str,
957                          c == 'N' ? !direction : direction);
958               if (n != Nil)
959                 {
960                   // found
961  jump_index:
962                   if (n < _absy || n > _absy+lines-1)
963                     {
964                       // screen crossed
965                       addy = 4;
966                       _absy = n - addy;
967                       if (n < addy)
968                         {
969                           addy = n;
970                           _absy = 0;
971                         }
972                       if (_absy > max_absy)
973                         {
974                           _absy = max_absy;
975                           addy = n - _absy;
976                         }
977                       redraw = true;
978                       break;
979                     }
980                   else
981                     addy = n - _absy;
982                 }
983               goto status_line;
984             case KEY_ESC:
985               Jdb::abort_command();
986               goto exit;
987             default:
988               if (Jdb::is_toplevel_cmd(c)) 
989                 goto exit;
990             }
991         }
992     }
993
994  exit:
995   _nr_cur = (e = Jdb_tbuf::lookup(_absy+addy)) ? e->number() : 0;
996 }
997
998 PUBLIC
999 Jdb_module::Action_code
1000 Jdb_tbuf_show::action(int cmd, void *&, char const *&, int &)
1001 {
1002   switch (cmd)
1003     {
1004     case 0:
1005       show();
1006       break;
1007
1008     case 1:
1009       if (Kconsole::console()->find_console(Console::GZIP))
1010         {
1011           Jdb_tbuf_output::set_filter(_filter_str, 0);
1012           Kconsole::console()->start_exclusive(Console::GZIP);
1013           show_events(0, 0, 1000000, 0, 0, 1);
1014           Kconsole::console()->end_exclusive(Console::GZIP);
1015         }
1016       break;
1017     }
1018
1019   return NOTHING;
1020 }
1021
1022 PUBLIC
1023 Jdb_module::Cmd const *
1024 Jdb_tbuf_show::cmds() const
1025 {
1026   static Cmd cs[] =
1027     { 
1028         { 0, "T", "tbuf", "",
1029           "T{P{+|-|k|u|<event>}}\tenter tracebuffer, on/off/kernel/user perf",
1030           0 },
1031          { 1, "Tgzip", "", "", 0 /* invisible */, 0 },
1032     };
1033
1034   return cs;
1035 }
1036
1037 PUBLIC
1038 int
1039 Jdb_tbuf_show::num_cmds() const
1040 {
1041   return 2;
1042 }
1043
1044 IMPLEMENT
1045 Jdb_tbuf_show::Jdb_tbuf_show()
1046     : Jdb_module("MONITORING")
1047 {}
1048
1049 static Jdb_tbuf_show jdb_tbuf_show INIT_PRIORITY(JDB_MODULE_INIT_PRIO);