]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/jdb/ia32/jdb_bp-ia32-ux.cpp
94ffab90ba03c1a2057327f1a41d17e2c2520e02
[l4.git] / kernel / fiasco / src / jdb / ia32 / jdb_bp-ia32-ux.cpp
1 INTERFACE[ia32,amd64,ux]:
2
3 #include "initcalls.h"
4 #include "l4_types.h"
5
6 class Thread;
7 class Task;
8 class Space;
9
10 class Breakpoint
11 {
12 public:
13   enum Mode { INSTRUCTION=0, WRITE=1, PORTIO=2, ACCESS=3 };
14   enum Log  { BREAK=0, LOG=1 };
15
16 private:
17   typedef struct 
18     {
19       int other;
20       Mword thread; 
21     } Bp_thread_res;
22
23   typedef struct
24     {
25       int other;
26       Mword task;
27     } Bp_task_res;
28
29   typedef struct 
30     {
31       char reg;
32       Address y, z;
33     } Bp_reg_res;
34
35   typedef struct 
36     {
37       unsigned char len;
38       Address addr;
39       Address y, z;
40     } Bp_mem_res;
41   
42   typedef struct 
43     {
44       Bp_thread_res thread;
45       Bp_task_res   task;
46       Bp_reg_res    reg;
47       Bp_mem_res    mem;
48     } Restriction;
49
50   Address      addr;
51   Unsigned8    len;
52   Address_type user;
53   Mode         mode;
54   Log          log;
55   Restriction  restrict;
56   static char const * const mode_names[4];
57 };
58
59 class Jdb_bp 
60 {
61 public:
62   static int            global_breakpoints();
63   static void           init_arch();
64
65 private:
66   static void           at_jdb_enter();
67   static void           at_jdb_leave();
68   static Breakpoint     bps[4];
69 };
70
71
72 IMPLEMENTATION[ia32,amd64,ux]:
73
74 #include <cstdio>
75
76 #include "jdb.h"
77 #include "jdb_input.h"
78 #include "jdb_module.h"
79 #include "jdb_handler_queue.h"
80 #include "jdb_screen.h"
81 #include "jdb_tbuf.h"
82 #include "l4_types.h"
83 #include "static_init.h"
84 #include "task.h"
85 #include "thread.h"
86
87 class Jdb_set_bp : public Jdb_module, public Jdb_input_task_addr
88 {
89 public:
90   Jdb_set_bp() FIASCO_INIT;
91 private:
92   static char     breakpoint_cmd;
93   static char     breakpoint_restrict_cmd;
94   static Mword    breakpoint_number;
95   static Mword    breakpoint_length;
96   static Mword    breakpoint_restrict_task;
97   static Mword    breakpoint_restrict_thread;
98   typedef struct
99     {
100       char        reg;
101       Mword       low;
102       Mword       high;
103     } Restrict_reg;
104   static Restrict_reg breakpoint_restrict_reg;
105   typedef struct
106     {
107       Address     addr;
108       Mword       low;
109       Mword       high;
110     } Restrict_addr;
111   static Restrict_addr breakpoint_restrict_addr;
112   static int      state;
113 };
114
115 Breakpoint Jdb_bp::bps[4];
116
117 char const * const Breakpoint::mode_names[4] =
118 {
119   "instruction", "write access", "i/o access", "r/w access"
120 };
121
122 char     Jdb_set_bp::breakpoint_cmd;
123 char     Jdb_set_bp::breakpoint_restrict_cmd;
124 Mword    Jdb_set_bp::breakpoint_number;
125 Mword    Jdb_set_bp::breakpoint_length;
126 Mword    Jdb_set_bp::breakpoint_restrict_task;
127 Mword    Jdb_set_bp::breakpoint_restrict_thread;
128 Jdb_set_bp::Restrict_reg  Jdb_set_bp::breakpoint_restrict_reg;
129 Jdb_set_bp::Restrict_addr Jdb_set_bp::breakpoint_restrict_addr;
130 int      Jdb_set_bp::state;
131
132 PUBLIC
133 Breakpoint::Breakpoint()
134 {
135   restrict.thread.thread = 0;
136   restrict.task.task     = 0;
137 }
138
139 PUBLIC inline NOEXPORT
140 void
141 Breakpoint::kill()
142 {
143   addr = 0;
144 }
145
146 PUBLIC inline NOEXPORT
147 int
148 Breakpoint::unused()
149 {
150   return addr == 0;
151 }
152
153 PUBLIC inline NOEXPORT
154 int
155 Breakpoint::break_at_instruction()
156 {
157   return mode == INSTRUCTION;
158 }
159
160 PUBLIC inline NOEXPORT
161 int
162 Breakpoint::match_addr(Address virt, Mode m)
163 {
164   return !unused() && addr == virt && mode == m;
165 }
166
167 PUBLIC inline NOEXPORT
168 void
169 Breakpoint::set_logmode(char m)
170 {
171   log = (m == '*') ? LOG : BREAK;
172 }
173
174 PUBLIC inline NOEXPORT
175 int
176 Breakpoint::is_break()
177 {
178   return !unused() && log == BREAK;
179 }
180
181 PUBLIC inline
182 void
183 Breakpoint::restrict_task(int other, Mword task)
184 {
185   restrict.task.other = other;
186   restrict.task.task  = task;
187 }
188
189 PUBLIC inline NOEXPORT
190 void
191 Breakpoint::restrict_thread(int other, Mword thread)
192 {
193   restrict.thread.other  = other;
194   restrict.thread.thread = thread;
195 }
196
197 PUBLIC inline NOEXPORT
198 void
199 Breakpoint::restrict_register(char reg, Mword y, Mword z)
200 {
201   restrict.reg.reg = reg;
202   restrict.reg.y   = y;
203   restrict.reg.z   = z;
204 }
205
206 PUBLIC inline NOEXPORT
207 void
208 Breakpoint::restrict_memory(Mword addr, Mword len, Mword y, Mword z)
209 {
210   restrict.mem.addr = addr;
211   restrict.mem.len  = len;
212   restrict.mem.y    = y;
213   restrict.mem.z    = z;
214 }
215
216 PUBLIC inline NOEXPORT
217 void 
218 Breakpoint::clear_restriction()
219 {
220   restrict.thread.thread = 0;
221   restrict.task.task     = 0;
222   restrict.reg.reg       = 0;
223   restrict.mem.len       = 0;
224 }
225
226 PUBLIC
227 void
228 Breakpoint::show()
229 {
230   if (addr)
231     {
232       printf("%5s on %12s at " L4_PTR_FMT,
233              log ? "LOG" : "BREAK", mode_names[mode & 3], addr);
234       if (mode != INSTRUCTION)
235         printf(" len %d", len);
236       else
237         putstr("      ");
238
239       if (   restrict.thread.thread == 0
240           && restrict.task.task == 0
241           && restrict.reg.reg == 0
242           && restrict.mem.len == 0)
243         puts(" (not restricted)");
244       else
245         {
246           int j = 0;
247 #if 0
248           printf("\n%32s", "restricted to ");
249           if (restrict.thread.thread != (GThread_num)-1)
250             {
251               j++;
252               printf("thread%s %x.%x\n",
253                      restrict.thread.other ? " !=" : "",
254                      L4_uid::task_from_gthread (restrict.thread.thread),
255                      L4_uid::lthread_from_gthread (restrict.thread.thread));
256             }
257           if (restrict.task.task)
258             {
259               if (j++)
260                 printf("%32s", "and ");
261               printf("task%s %p\n",
262                      restrict.task.other ? " !=" : "",
263                      restrict.task.task);
264             }
265 #endif
266           if (restrict.reg.reg != 0)
267             {
268               if (j++)
269                 printf("%32s", "and ");
270               printf("register %s in [" L4_PTR_FMT ", " L4_PTR_FMT "]\n",
271                   (restrict.reg.reg > 0) && (restrict.reg.reg < 10) 
272                       ? Jdb_screen::Reg_names[restrict.reg.reg-1] 
273                       : "???",
274                    restrict.reg.y, restrict.reg.z);
275             }
276           if (restrict.mem.len != 0)
277             {
278               if (j++)
279                 printf("%32s", "and ");
280               printf("%d-byte var at " L4_PTR_FMT " in [" L4_PTR_FMT ", "
281                      L4_PTR_FMT "]\n", 
282                   restrict.mem.len, restrict.mem.addr, 
283                   restrict.mem.y,   restrict.mem.z);
284             }
285         }
286     }
287   else
288     puts("disabled");
289 }
290
291 // return TRUE  if the breakpoint does NOT match
292 // return FALSE if all restrictions do match
293 PUBLIC
294 int
295 Breakpoint::restricted(Thread *t)
296 {
297   Jdb_entry_frame *e = Jdb::get_entry_frame(Jdb::current_cpu);
298
299   Space *task = t->space();
300 #if 0
301   // investigate for thread restriction
302   if (restrict.thread.thread != (GThread_num)-1)
303     {
304       if (restrict.thread.other ^ (restrict.thread.thread != t->id().gthread()))
305         return 1;
306     }
307
308   // investigate for task restriction
309   if (restrict.task.task)
310     {
311       if (restrict.task.other ^ (restrict.task.task != task))
312         return 1;
313     }
314 #endif
315   // investigate for register restriction
316   if (restrict.reg.reg)
317     {
318       Mword val = e->get_reg(restrict.reg.reg);
319       Mword y   = restrict.reg.y;
320       Mword z   = restrict.reg.z;
321
322       // return true if rules do NOT match
323       if (  (y <= z && (val <  y || val >  z))
324           ||(y >  z && (val >= z || val <= y)))
325         return 1;
326     }
327
328   // investigate for variable restriction
329   if (restrict.mem.len)
330     {
331       Mword val = 0;
332       Mword y   = restrict.mem.y;
333       Mword z   = restrict.mem.z;
334
335       if (Jdb::peek_task(restrict.mem.addr, task, &val, restrict.mem.len) != 0)
336         return 0;
337
338       // return true if rules do NOT match
339       if (  (y <= z && (val <  y || val >  z))
340           ||(y >  z && (val >= z || val <= y)))
341         return 1;
342     }
343
344   return 0;
345 }
346
347 PUBLIC
348 int
349 Breakpoint::test_break(Thread *t, char *errbuf, size_t bufsize)
350 {
351   if (restricted(t))
352     return 0;
353
354   Space *task = t->space();
355
356   snprintf(errbuf, bufsize, "break on %s at " L4_PTR_FMT,
357            mode_names[mode], addr);
358   if (mode==WRITE || mode==ACCESS)
359     {
360       // If it's a write or access (read) breakpoint, we look at the
361       // appropriate place and print the bytes we find there. We do
362       // not need to look if the page is present because the x86 CPU
363       // enters the debug exception immediately _after_ the memory
364       // access was performed.
365       size_t size = strlen(errbuf);
366       errbuf  += size;
367       bufsize -= size;
368       Mword val = 0;
369       if (len > sizeof(Mword))
370         return 0;
371
372       if (Jdb::peek_task(addr, task, &val, len) != 0)
373         return 0;
374
375       snprintf(errbuf, bufsize, " [%08lx]", val);
376     }
377   return 1;
378 }
379
380 // Create log entry if breakpoint matches
381 PUBLIC
382 void
383 Breakpoint::test_log(Thread *t)
384 {
385   Jdb_entry_frame *e = Jdb::get_entry_frame(Jdb::current_cpu);
386
387   if (log && !restricted(t))
388     {
389       Space *task = t->space();
390       // log breakpoint
391       Mword value = 0;
392
393       if (mode == WRITE || mode == ACCESS)
394         {
395           // If it's a write or access (read) breakpoint, we look at the
396           // appropriate place and print the bytes we find there. We do
397           // not need to look if the page is present because the x86 CPU
398           // enters the debug exception immediately _after_ the memory
399           // access was performed.
400           if (len > sizeof(Mword))
401             return;
402
403           if (Jdb::peek_task(addr, task, &value, len) != 0)
404             return;
405         }
406
407       // is called with disabled interrupts
408       Tb_entry_bp *tb = static_cast<Tb_entry_bp*>(Jdb_tbuf::new_entry());
409       tb->set(t, e->ip(), mode, len, value, addr);
410       Jdb_tbuf::commit_entry();
411     }
412 }
413
414
415 STATIC_INITIALIZE_P(Jdb_bp, JDB_MODULE_INIT_PRIO);
416
417 PUBLIC static FIASCO_INIT
418 void
419 Jdb_bp::init()
420 {
421   static Jdb_handler enter(at_jdb_enter);
422   static Jdb_handler leave(at_jdb_leave);
423
424   Jdb::jdb_enter.add(&enter);
425   Jdb::jdb_leave.add(&leave);
426
427   init_arch();
428 }
429
430 static inline
431 void
432 Jdb_bp::clr_dr7(int num, Mword &dr7)
433 {
434   dr7 &= ~(((3 + (3 <<2)) << (16 + 4*num)) + (3 << (2*num)));
435 }
436
437 static inline
438 void
439 Jdb_bp::set_dr7(int num, Mword len, Breakpoint::Mode mode, Mword &dr7)
440 {
441   // the encoding of length 8 is special
442   if (len == 8)
443     len = 3;
444
445   dr7 |= ((((mode & 3) + ((len-1)<<2)) << (16 + 4*num)) + (2 << (2*num)));
446   dr7 |= 0x200; /* exact breakpoint enable (not available on P6 and below) */
447 }
448
449 PUBLIC static
450 int
451 Jdb_bp::set_breakpoint(int num, Address addr, Mword len,
452                        Breakpoint::Mode mode, Breakpoint::Log log,
453                        Task *task)
454 {
455   if (set_debug_address_register(num, addr, len, mode, task))
456     {
457       bps[num].set(addr, len, mode, log);
458       return 1;
459     }
460
461   return 0;
462 }
463
464 PUBLIC static 
465 void 
466 Jdb_bp::clr_breakpoint(int num)
467 {
468   clr_debug_address_register(num);
469   bps[num].kill();
470 }
471
472 PUBLIC static inline NOEXPORT
473 void
474 Jdb_bp::logmode_breakpoint(int num, char mode)
475 {
476   bps[num].set_logmode(mode);
477 }
478
479 PUBLIC static
480 int
481 Jdb_bp::first_unused()
482 {
483   int i;
484
485   for (i=0; i<4 && !bps[i].unused(); i++)
486     ;
487
488   return i;
489 }
490
491 // Return 1 if a breakpoint hits
492 PUBLIC static
493 int
494 Jdb_bp::test_break(Mword dr6, char *errbuf, size_t bufsize)
495 {
496   Thread *t = Jdb::get_thread(0);
497   Jdb_entry_frame *e = Jdb::get_entry_frame(0);
498
499   for (int i=0; i<4; i++)
500     if (dr6 & (1<<i))
501       {
502         if (bps[i].break_at_instruction())
503           e->flags(e->flags() | EFLAGS_RF);
504         if (bps[i].test_break(t, errbuf, bufsize))
505           return 1;
506       }
507
508   return 0;
509 }
510
511 // Create log entry if breakpoint matches.
512 // Return 1 if debugger should stop
513 PUBLIC static
514 void
515 Jdb_bp::test_log(Mword &dr6)
516 {
517   Thread *t = Jdb::get_thread(0);
518   Jdb_entry_frame *e = Jdb::get_entry_frame(0);
519
520   for (int i=0; i<4; i++)
521     if (dr6 & (1<<i))
522       {
523         if (!bps[i].is_break())
524           {
525             // create log entry
526             bps[i].test_log(t);
527             // consider instruction breakpoints
528             if (bps[i].break_at_instruction())
529               e->flags(e->flags() | EFLAGS_RF);
530             // clear condition
531             dr6 &= ~(1<<i);
532           }
533       }
534 }
535
536 PUBLIC static
537 Mword
538 Jdb_bp::test_match(Address addr, Breakpoint::Mode mode)
539 {
540   for (int i=0; i<4; i++)
541     if (bps[i].match_addr(addr, mode))
542       return i+1;
543
544   return 0;
545 }
546
547 PUBLIC static
548 int
549 Jdb_bp::instruction_bp_at_addr(Address addr)
550 { return test_match(addr, Breakpoint::INSTRUCTION); }
551
552
553 PUBLIC static inline NOEXPORT
554 void
555 Jdb_bp::restrict_task(int num, int other, Mword task)
556 {
557   bps[num].restrict_task(other, task);
558 }
559
560 PUBLIC static inline NOEXPORT
561 void
562 Jdb_bp::restrict_thread(int num, int other, Mword thread)
563 {
564   bps[num].restrict_thread(other, thread);
565 }
566
567 PUBLIC static inline NOEXPORT
568 void
569 Jdb_bp::restrict_register(int num, char reg, Mword y, Mword z)
570 {
571   bps[num].restrict_register(reg, y, z);
572 }
573
574 PUBLIC static inline NOEXPORT
575 void
576 Jdb_bp::restrict_memory(int num, Mword addr, Mword len, Mword y, Mword z)
577 {
578   bps[num].restrict_memory(addr, len, y, z);
579 }
580
581 PUBLIC static inline NOEXPORT
582 void
583 Jdb_bp::clear_restriction(int num)
584 {
585   bps[num].clear_restriction();
586 }
587
588 PUBLIC static
589 void 
590 Jdb_bp::list()
591 {
592   putchar('\n');
593
594   for(int i=0; i<4; i++)
595     {
596       printf("  #%d: ", i+1);
597       bps[i].show();
598     }
599
600   putchar('\n');
601 }
602
603
604 //---------------------------------------------------------------------------//
605
606 IMPLEMENT
607 Jdb_set_bp::Jdb_set_bp()
608   : Jdb_module("DEBUGGING")
609 {}
610
611 PUBLIC
612 Jdb_module::Action_code
613 Jdb_set_bp::action(int cmd, void *&args, char const *&fmt, int &next_char)
614 {
615   Jdb_module::Action_code code;
616   Breakpoint::Mode mode;
617
618   if (cmd == 0)
619     {
620       if (args == &breakpoint_cmd)
621         {
622           switch (breakpoint_cmd)
623             {
624             case 'p':
625               if (!(Cpu::boot_cpu()->features() & FEAT_DE))
626                 {
627                   puts(" I/O breakpoints not supported by this CPU");
628                   return NOTHING;
629                 }
630               // fall through
631             case 'a':
632             case 'i':
633             case 'w':
634               if ((breakpoint_number = Jdb_bp::first_unused()) < 4)
635                 {
636                   fmt   = " addr=%C";
637                   args  = &Jdb_input_task_addr::first_char;
638                   state = 1; // breakpoints are global for all tasks
639                   return EXTRA_INPUT;
640                 }
641               puts(" No breakpoints available");
642               return NOTHING;
643             case 'l':
644               // show all breakpoints
645               Jdb_bp::list();
646               return NOTHING;
647             case '-':
648               // delete breakpoint
649             case '+':
650               // set logmode of breakpoint to <STOP>
651             case '*':
652               // set logmode of breakpoint to <LOG>
653             case 'r':
654               // restrict breakpoint
655               fmt   = " bpn=%1x";
656               args  = &breakpoint_number;
657               state = 2;
658               return EXTRA_INPUT;
659             case 't':
660               Jdb::execute_command("bt");
661               break;
662             default:
663               return ERROR;
664             }
665         }
666       else switch (state)
667         {
668         case 1:
669           code = Jdb_input_task_addr::action(args, fmt, next_char);
670           if (code == ERROR)
671             return ERROR;
672           if (code == NOTHING)
673             // ok, continue
674             goto got_address;
675           // more input for Jdb_input_task_addr
676           return code;
677         case 2:
678           if (breakpoint_number < 1 || breakpoint_number > 4)
679             return ERROR;
680           // input is 1..4 but numbers are 0..3
681           breakpoint_number -= 1;
682           // we know the breakpoint number
683           switch (breakpoint_cmd)
684             {
685             case '-':
686               Jdb_bp::clr_breakpoint(breakpoint_number);
687               putchar('\n');
688               return NOTHING;
689             case '+':
690             case '*':
691               Jdb_bp::logmode_breakpoint(breakpoint_number, breakpoint_cmd);
692               putchar('\n');
693               return NOTHING;
694             case 'r':
695               fmt   = " %C";
696               args  = &breakpoint_restrict_cmd;
697               state = 5;
698               return EXTRA_INPUT;
699             default:
700               return ERROR;
701             }
702           break;
703         case 3:
704 got_address:
705           // address/task read
706           if (breakpoint_cmd != 'i')
707             {
708               fmt   = " len (1, 2, 4...)=%1x";
709               args  = &breakpoint_length;
710               state = 4;
711               return EXTRA_INPUT;
712             }
713           breakpoint_length = 1; // must be 1 for instruction breakpoints
714           // fall through
715         case 4:
716           // length read
717           if (breakpoint_length & (breakpoint_length - 1))
718             break;
719           if (breakpoint_length > sizeof(Mword))
720             break;
721           switch (breakpoint_cmd)
722             {
723             default : return ERROR;
724             case 'i': mode = Breakpoint::INSTRUCTION; break;
725             case 'w': mode = Breakpoint::WRITE;       break;
726             case 'p': mode = Breakpoint::PORTIO;      break;
727             case 'a': mode = Breakpoint::ACCESS;      break;
728             }
729           // abort if no address was given
730           if (Jdb_input_task_addr::addr() == (Address)-1)
731             return ERROR;
732           Jdb_bp::set_breakpoint(breakpoint_number, Jdb_input_task_addr::addr(),
733                                  breakpoint_length, mode, Breakpoint::BREAK,
734                                  Jdb_input_task_addr::task());
735           putchar('\n');
736           break;
737         case 5:
738           // restrict command read
739           switch (breakpoint_restrict_cmd)
740             {
741             case 'a':
742             case 'A':
743               fmt   = (breakpoint_restrict_cmd=='A')
744                         ? "task!=" L4_ADDR_INPUT_FMT "\n"
745                         : "task==" L4_ADDR_INPUT_FMT "\n";
746               args  = &breakpoint_restrict_task;
747               state = 6;
748               return EXTRA_INPUT;
749             case 't':
750             case 'T':
751               fmt   = (breakpoint_restrict_cmd=='T')
752                         ? "thread!=%t\n" : "thread==%t\n";
753               args  = &breakpoint_restrict_thread;
754               state = 7;
755               return EXTRA_INPUT;
756             case 'e':
757               if (!Jdb::get_register(&breakpoint_restrict_reg.reg))
758                 return NOTHING;
759               fmt  = " in [" L4_ADDR_INPUT_FMT "-" L4_ADDR_INPUT_FMT "]\n";
760               args = &breakpoint_restrict_reg.low;
761               state = 8;
762               return EXTRA_INPUT;
763             case '1':
764             case '2':
765             case '4':
766               putchar(breakpoint_restrict_cmd);
767               fmt   = "-byte addr=" L4_ADDR_INPUT_FMT
768                       " between[" L4_ADDR_INPUT_FMT "-" L4_ADDR_INPUT_FMT "]\n";
769               args  = &breakpoint_restrict_addr;
770               state = 9;
771               return EXTRA_INPUT;
772             case '-':
773               Jdb_bp::clear_restriction(breakpoint_number);
774               putchar('\n');
775               break;
776             default:
777               return ERROR;
778             }
779           break;
780         case 6:
781           // breakpoint restrict task read
782           Jdb_bp::restrict_task(breakpoint_number,
783                                 breakpoint_restrict_cmd == 'A',
784                                 breakpoint_restrict_task);
785           break;
786         case 7:
787           // breakpoint restrict thread read
788           Jdb_bp::restrict_thread(breakpoint_number,
789                                   breakpoint_restrict_cmd == 'T',
790                                   breakpoint_restrict_thread);
791           break;
792         case 8:
793           // breakpoint restrict register in range
794           Jdb_bp::restrict_register(breakpoint_number,
795                                     breakpoint_restrict_reg.reg,
796                                     breakpoint_restrict_reg.low,
797                                     breakpoint_restrict_reg.high);
798           break;
799         case 9:
800           // breakpoint restrict x-byte-value in range
801           Jdb_bp::restrict_memory(breakpoint_number,
802                                   breakpoint_restrict_addr.addr,
803                                   breakpoint_restrict_cmd - '0',
804                                   breakpoint_restrict_addr.low,
805                                   breakpoint_restrict_addr.high);
806           break;
807         }
808     }
809   return NOTHING;
810 }
811
812 PUBLIC
813 Jdb_module::Cmd const *
814 Jdb_set_bp::cmds() const
815 {
816   static Cmd cs[] = 
817     {
818         { 0, "b", "bp", "%c",
819           "b{i|a|w|p}<addr>\tset breakpoint on instruction/access/write/io "
820           "access\n"
821           "b{-|+|*}<num>\tdisable/enable/log breakpoint\n"
822           "bl\tlist breakpoints\n"
823           "br<num>{t|T|a|A|e|1|2|4}\trestrict breakpoint to "
824           "(!)thread/(!)task/reg/mem",
825           &breakpoint_cmd },
826     };
827
828   return cs;
829 }
830
831 PUBLIC
832 int
833 Jdb_set_bp::num_cmds() const
834 {
835   return 1;
836 }
837
838 static Jdb_set_bp jdb_set_bp INIT_PRIORITY(JDB_MODULE_INIT_PRIO);