The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_break.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1991,1990 Carnegie Mellon University
    4  * All Rights Reserved.
    5  * 
    6  * Permission to use, copy, modify and distribute this software and its
    7  * documentation is hereby granted, provided that both the copyright
    8  * notice and this permission notice appear in all copies of the
    9  * software, derivative works or modified versions, and any portions
   10  * thereof, and that both notices appear in supporting documentation.
   11  * 
   12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   15  * 
   16  * Carnegie Mellon requests users of this software to return to
   17  * 
   18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   19  *  School of Computer Science
   20  *  Carnegie Mellon University
   21  *  Pittsburgh PA 15213-3890
   22  * 
   23  * any improvements or extensions that they make and grant Carnegie Mellon
   24  * the rights to redistribute these changes.
   25  */
   26 /*
   27  * HISTORY
   28  * $Log:        db_break.c,v $
   29  * Revision 2.17  93/05/17  10:26:24  rvb
   30  *      Type casts, etc to quiet gcc 2.3.3 warnings
   31  * 
   32  * Revision 2.16  93/01/14  17:24:29  danner
   33  *      64bit cleanup.
   34  *      [92/11/30            af]
   35  * 
   36  * Revision 2.15  92/08/03  17:30:33  jfriedl
   37  *      removed silly prototypes
   38  *      [92/08/02            jfriedl]
   39  * 
   40  * Revision 2.14  92/05/21  17:06:24  jfriedl
   41  *      Removed unused variable from db_delete_cmd().
   42  *      Added declaration for arg 'count' of db_add_thread_breakpoint().
   43  *      [92/05/18            jfriedl]
   44  * 
   45  * Revision 2.13  92/05/04  11:23:49  danner
   46  *      Fixed b/tu to b/Tu work if the specified address is valid in the
   47  *       target address space but not the current user space. Explicit
   48  *       user space breakpoints (b/u, b/Tu, etc) will no longer get
   49  *       inserted into the kernel if the specified address is invalid. 
   50  *      [92/04/18            danner]
   51  * 
   52  * Revision 2.12  92/02/19  16:46:24  elf
   53  *      Removed one of the many user-unfriendlinesses.
   54  *      [92/02/10  17:48:25  af]
   55  * 
   56  * Revision 2.11  91/11/12  11:50:24  rvb
   57  *      Fixed db_delete_cmd so that just "d" works in user space.
   58  *      [91/10/31            rpd]
   59  *      Fixed db_delete_thread_breakpoint for zero task_thd.
   60  *      [91/10/30            rpd]
   61  * 
   62  * Revision 2.10  91/10/09  15:57:41  af
   63  *      Supported thread-oriented break points.
   64  *      [91/08/29            tak]
   65  * 
   66  * Revision 2.9  91/07/09  23:15:39  danner
   67  *      Conditionalized db_map_addr to work right on the luna. Used a
   68  *      ifdef luna88k. This is evil, and needs to be fixed.
   69  *      [91/07/08            danner]
   70  *
   71  * Revision 2.2  91/04/10  22:54:50  mbj
   72  *      Grabbed 3.0 copyright/disclaimer since ddb comes from 3.0.
   73  *      [91/04/09            rvb]
   74  * 
   75  * Revision 2.7  91/02/05  17:06:00  mrt
   76  *      Changed to new Mach copyright
   77  *      [91/01/31  16:17:01  mrt]
   78  * 
   79  * Revision 2.6  91/01/08  15:09:03  rpd
   80  *      Added db_map_equal, db_map_current, db_map_addr.
   81  *      [90/11/10            rpd]
   82  * 
   83  * Revision 2.5  90/11/05  14:26:32  rpd
   84  *      Initialize db_breakpoints_inserted to TRUE.
   85  *      [90/11/04            rpd]
   86  * 
   87  * Revision 2.4  90/10/25  14:43:33  rwd
   88  *      Added map field to breakpoints.
   89  *      Added map argument to db_set_breakpoint, db_delete_breakpoint,
   90  *      db_find_breakpoint.  Added db_find_breakpoint_here.
   91  *      [90/10/18            rpd]
   92  * 
   93  * Revision 2.3  90/09/28  16:57:07  jsb
   94  *      Fixed db_breakpoint_free.
   95  *      [90/09/18            rpd]
   96  * 
   97  * Revision 2.2  90/08/27  21:49:53  dbg
   98  *      Reflected changes in db_printsym()'s calling seq.
   99  *      [90/08/20            af]
  100  *      Clear breakpoints only if inserted.
  101  *      Reduce lint.
  102  *      [90/08/07            dbg]
  103  *      Created.
  104  *      [90/07/25            dbg]
  105  * 
  106  */
  107 /*
  108  *      Author: David B. Golub, Carnegie Mellon University
  109  *      Date:   7/90
  110  */
  111 
  112 /*
  113  * Breakpoints.
  114  */
  115 #include <mach/boolean.h>
  116 #include <machine/db_machdep.h>
  117 #include <ddb/db_lex.h>
  118 #include <ddb/db_break.h>
  119 #include <ddb/db_access.h>
  120 #include <ddb/db_sym.h>
  121 #include <ddb/db_variables.h>
  122 #include <ddb/db_command.h>
  123 #include <ddb/db_task_thread.h>
  124 
  125 #define NBREAKPOINTS    100
  126 #define NTHREAD_LIST    (NBREAKPOINTS*3)
  127 
  128 struct db_breakpoint    db_break_table[NBREAKPOINTS];
  129 db_breakpoint_t         db_next_free_breakpoint = &db_break_table[0];
  130 db_breakpoint_t         db_free_breakpoints = 0;
  131 db_breakpoint_t         db_breakpoint_list = 0;
  132 
  133 static struct db_thread_breakpoint      db_thread_break_list[NTHREAD_LIST];
  134 static db_thread_breakpoint_t           db_free_thread_break_list = 0;
  135 static boolean_t                        db_thread_break_init = FALSE;
  136 static int                              db_breakpoint_number = 0;
  137 
  138 db_breakpoint_t
  139 db_breakpoint_alloc()
  140 {
  141         register db_breakpoint_t        bkpt;
  142 
  143         if ((bkpt = db_free_breakpoints) != 0) {
  144             db_free_breakpoints = bkpt->link;
  145             return (bkpt);
  146         }
  147         if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
  148             db_printf("All breakpoints used.\n");
  149             return (0);
  150         }
  151         bkpt = db_next_free_breakpoint;
  152         db_next_free_breakpoint++;
  153 
  154         return (bkpt);
  155 }
  156 
  157 void
  158 db_breakpoint_free(bkpt)
  159         register db_breakpoint_t        bkpt;
  160 {
  161         bkpt->link = db_free_breakpoints;
  162         db_free_breakpoints = bkpt;
  163 }
  164 
  165 static int
  166 db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt)
  167         register db_breakpoint_t bkpt;
  168         vm_offset_t task_thd;
  169         boolean_t task_bpt;
  170 {
  171         register db_thread_breakpoint_t tp;
  172 
  173         if (db_thread_break_init == FALSE) {
  174             for (tp = db_thread_break_list; 
  175                 tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
  176                 tp->tb_next = tp+1;
  177             tp->tb_next = 0;
  178             db_free_thread_break_list = db_thread_break_list;
  179             db_thread_break_init = TRUE;
  180         }
  181         if (db_free_thread_break_list == 0)
  182             return (-1);
  183         tp = db_free_thread_break_list;
  184         db_free_thread_break_list = tp->tb_next;
  185         tp->tb_is_task = task_bpt;
  186         tp->tb_task_thd = task_thd;
  187         tp->tb_count = count;
  188         tp->tb_init_count = count;
  189         tp->tb_cond = 0;
  190         tp->tb_number = ++db_breakpoint_number;
  191         tp->tb_next = bkpt->threads;
  192         bkpt->threads = tp;
  193         return(0);
  194 }
  195 
  196 static int
  197 db_delete_thread_breakpoint(bkpt, task_thd)
  198         register db_breakpoint_t bkpt;
  199         vm_offset_t task_thd;
  200 {
  201         register db_thread_breakpoint_t tp;
  202         register db_thread_breakpoint_t *tpp;
  203         void     db_cond_free();
  204 
  205         if (task_thd == 0) {
  206             /* delete all the thread-breakpoints */
  207 
  208             for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
  209                 db_cond_free(tp);
  210 
  211             *tpp = db_free_thread_break_list;
  212             db_free_thread_break_list = bkpt->threads;
  213             bkpt->threads = 0;
  214             return 0;
  215         } else {
  216             /* delete the specified thread-breakpoint */
  217 
  218             for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
  219                 if (tp->tb_task_thd == task_thd) {
  220                     db_cond_free(tp);
  221                     *tpp = tp->tb_next;
  222                     tp->tb_next = db_free_thread_break_list;
  223                     db_free_thread_break_list = tp;
  224                     return 0;
  225                 }
  226 
  227             return -1;  /* not found */
  228         }
  229 }
  230 
  231 static db_thread_breakpoint_t
  232 db_find_thread_breakpoint(bkpt, thread)
  233         db_breakpoint_t bkpt;
  234         thread_t thread;
  235 {
  236         register db_thread_breakpoint_t tp;
  237         register task_t task = (thread == THREAD_NULL)? TASK_NULL: thread->task;
  238 
  239         for (tp = bkpt->threads; tp; tp = tp->tb_next) {
  240             if (tp->tb_is_task) {
  241                 if (tp->tb_task_thd == (vm_offset_t)task)
  242                     break;
  243                 continue;
  244             }
  245             if (tp->tb_task_thd == (vm_offset_t)thread || tp->tb_task_thd == 0)
  246                 break;
  247         }
  248         return(tp);
  249 }
  250 
  251 db_thread_breakpoint_t
  252 db_find_thread_breakpoint_here(task, addr)
  253         task_t          task;
  254         db_addr_t       addr;
  255 {
  256         db_breakpoint_t bkpt;
  257 
  258         bkpt = db_find_breakpoint(task, (db_addr_t)addr);
  259         if (bkpt == 0)
  260             return(0);
  261         return(db_find_thread_breakpoint(bkpt, current_thread()));
  262 }
  263 
  264 db_thread_breakpoint_t
  265 db_find_breakpoint_number(num, bkptp)
  266         int num;
  267         db_breakpoint_t *bkptp;
  268 {
  269         register db_thread_breakpoint_t tp;
  270         register db_breakpoint_t bkpt;
  271 
  272         for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
  273             for (tp = bkpt->threads; tp; tp = tp->tb_next) {
  274                 if (tp->tb_number == num) {
  275                     if (bkptp)
  276                         *bkptp = bkpt;
  277                     return(tp);
  278                 }
  279             }
  280         }
  281         return(0);
  282 }
  283 
  284 static void
  285 db_force_delete_breakpoint(bkpt, task_thd, is_task)
  286         db_breakpoint_t bkpt;
  287         vm_offset_t  task_thd;
  288         boolean_t is_task;
  289 {
  290         db_printf("deleted a stale breakpoint at ");
  291         if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
  292            db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
  293         else
  294            db_printf("%#X", bkpt->address);
  295         if (bkpt->task)
  296            db_printf(" in task %X", bkpt->task);
  297         if (task_thd)
  298            db_printf(" for %s %X", (is_task)? "task": "thread", task_thd);
  299         db_printf("\n");
  300         db_delete_thread_breakpoint(bkpt, task_thd);
  301 }
  302 
  303 void
  304 db_check_breakpoint_valid()
  305 {
  306         register db_thread_breakpoint_t tbp, tbp_next;
  307         register db_breakpoint_t bkpt, *bkptp;
  308 
  309         bkptp = &db_breakpoint_list;
  310         for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
  311             if (bkpt->task != TASK_NULL) {
  312                 if (db_lookup_task(bkpt->task) < 0) {
  313                     db_force_delete_breakpoint(bkpt, 0, FALSE);
  314                     *bkptp = bkpt->link;
  315                     db_breakpoint_free(bkpt);
  316                     continue;
  317                 }
  318             } else {
  319                 for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
  320                     tbp_next = tbp->tb_next;
  321                     if (tbp->tb_task_thd == 0)
  322                         continue;
  323                     if ((tbp->tb_is_task && 
  324                          db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
  325                         (!tbp->tb_is_task && 
  326                          db_lookup_thread((thread_t)(tbp->tb_task_thd)) < 0)) {
  327                         db_force_delete_breakpoint(bkpt, 
  328                                         tbp->tb_task_thd, tbp->tb_is_task);
  329                     }
  330                 }
  331                 if (bkpt->threads == 0) {
  332                     db_put_task_value(bkpt->address, BKPT_SIZE,
  333                                  bkpt->bkpt_inst, bkpt->task);
  334                     *bkptp = bkpt->link;
  335                     db_breakpoint_free(bkpt);
  336                     continue;
  337                 }
  338             }
  339             bkptp = &bkpt->link;
  340         }
  341 }
  342 
  343 void
  344 db_set_breakpoint(task, addr, count, thread, task_bpt)
  345         task_t          task;
  346         db_addr_t       addr;
  347         int             count;
  348         thread_t        thread;
  349         boolean_t       task_bpt;
  350 {
  351         register db_breakpoint_t bkpt;
  352         db_breakpoint_t alloc_bkpt = 0;
  353         vm_offset_t task_thd;
  354 
  355         bkpt = db_find_breakpoint(task, addr);
  356         if (bkpt) {
  357             if (thread == THREAD_NULL
  358                 || db_find_thread_breakpoint(bkpt, thread)) {
  359                 db_printf("Already set.\n");
  360                 return;
  361             }
  362         } else {
  363             if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
  364                 db_printf("Cannot set break point at %X\n", addr);
  365                 return;
  366             }
  367             alloc_bkpt = bkpt = db_breakpoint_alloc();
  368             if (bkpt == 0) {
  369                 db_printf("Too many breakpoints.\n");
  370                 return;
  371             }
  372             bkpt->task = task;
  373             bkpt->flags = (task && thread == THREAD_NULL)?
  374                                 (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
  375             bkpt->address = addr;
  376             bkpt->threads = 0;
  377         }
  378         if (db_breakpoint_list == 0)
  379             db_breakpoint_number = 0;
  380         task_thd = (task_bpt)? (vm_offset_t)(thread->task): (vm_offset_t)thread;
  381         if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) {
  382             if (alloc_bkpt)
  383                 db_breakpoint_free(alloc_bkpt);
  384             db_printf("Too many thread_breakpoints.\n");
  385         } else {
  386             db_printf("set breakpoint #%d\n", db_breakpoint_number);
  387             if (alloc_bkpt) {
  388                 bkpt->link = db_breakpoint_list;
  389                 db_breakpoint_list = bkpt;
  390             }
  391         }
  392 }
  393 
  394 void
  395 db_delete_breakpoint(task, addr, task_thd)
  396         task_t  task;
  397         db_addr_t       addr;
  398         vm_offset_t     task_thd;
  399 {
  400         register db_breakpoint_t        bkpt;
  401         register db_breakpoint_t        *prev;
  402 
  403         for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
  404                                              prev = &bkpt->link) {
  405             if ((bkpt->task == task
  406                    || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
  407                 && bkpt->address == addr)
  408                 break;
  409         }
  410         if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
  411             db_printf("cannot delete it now.\n");
  412             return;
  413         }
  414         if (bkpt == 0
  415             || db_delete_thread_breakpoint(bkpt, task_thd) < 0) {
  416             db_printf("Not set.\n");
  417             return;
  418         }
  419         if (bkpt->threads == 0) {
  420             *prev = bkpt->link;
  421             db_breakpoint_free(bkpt);
  422         }
  423 }
  424 
  425 db_breakpoint_t
  426 db_find_breakpoint(task, addr)
  427         task_t  task;
  428         db_addr_t       addr;
  429 {
  430         register db_breakpoint_t        bkpt;
  431 
  432         for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
  433             if ((bkpt->task == task
  434                   || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
  435                 && bkpt->address == addr)
  436                 return (bkpt);
  437         }
  438         return (0);
  439 }
  440 
  441 boolean_t
  442 db_find_breakpoint_here(task, addr)
  443         task_t          task;
  444         db_addr_t       addr;
  445 {
  446         register db_breakpoint_t        bkpt;
  447 
  448         for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
  449             if ((bkpt->task == task
  450                    || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
  451                 && bkpt->address == addr)
  452                 return(TRUE);
  453             if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
  454                   DB_PHYS_EQ(task, (vm_offset_t)addr, bkpt->task, (vm_offset_t)bkpt->address))
  455                 return (TRUE);
  456         }
  457         return(FALSE);
  458 }
  459 
  460 boolean_t       db_breakpoints_inserted = TRUE;
  461 
  462 void
  463 db_set_breakpoints()
  464 {
  465         register db_breakpoint_t bkpt;
  466         register task_t task;
  467         db_expr_t       inst;
  468         task_t          cur_task;
  469 
  470         cur_task = (current_thread())? current_thread()->task: TASK_NULL;
  471         if (!db_breakpoints_inserted) {
  472             for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
  473                 if (bkpt->flags & BKPT_SET_IN_MEM)
  474                     continue;
  475                 task = bkpt->task;
  476                 if (bkpt->flags & BKPT_USR_GLOBAL) {
  477                     if ((bkpt->flags & BKPT_1ST_SET) == 0) {
  478                         if (cur_task == TASK_NULL)
  479                             continue;
  480                         task = cur_task;
  481                     } else
  482                         bkpt->flags &= ~BKPT_1ST_SET;
  483                 }
  484                 if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
  485                     inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
  486                                                                 task);
  487                     if (inst == BKPT_SET(inst))
  488                         continue;
  489                     bkpt->bkpt_inst = inst;
  490                     db_put_task_value(bkpt->address,
  491                                 BKPT_SIZE,
  492                                 BKPT_SET(bkpt->bkpt_inst), task);
  493                     bkpt->flags |= BKPT_SET_IN_MEM;
  494                 } else {
  495                     db_printf("Warning: cannot set breakpoint at %X ", 
  496                                 bkpt->address);
  497                     if (task)
  498                         db_printf("in task %X\n", task);
  499                     else
  500                         db_printf("in kernel space\n");
  501                 }
  502             }
  503             db_breakpoints_inserted = TRUE;
  504         }
  505 }
  506 
  507 void
  508 db_clear_breakpoints()
  509 {
  510         register db_breakpoint_t bkpt, *bkptp;
  511         register task_t task;
  512         task_t          cur_task;
  513         db_expr_t       inst;
  514 
  515         cur_task = (current_thread())? current_thread()->task: TASK_NULL;
  516         if (db_breakpoints_inserted) {
  517             bkptp = &db_breakpoint_list;
  518             for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
  519                 task = bkpt->task;
  520                 if (bkpt->flags & BKPT_USR_GLOBAL) {
  521                     if (cur_task == TASK_NULL) {
  522                         bkptp = &bkpt->link;
  523                         continue;
  524                     }
  525                     task = cur_task;
  526                 }
  527                 if ((bkpt->flags & BKPT_SET_IN_MEM)
  528                     && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
  529                     inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE, 
  530                                                                 task);
  531                     if (inst != BKPT_SET(inst)) {
  532                         if (bkpt->flags & BKPT_USR_GLOBAL) {
  533                             bkptp = &bkpt->link;
  534                             continue;
  535                         }
  536                         db_force_delete_breakpoint(bkpt, 0, FALSE);
  537                         *bkptp = bkpt->link;
  538                         db_breakpoint_free(bkpt);
  539                         continue;
  540                     }
  541                     db_put_task_value(bkpt->address, BKPT_SIZE,
  542                                  bkpt->bkpt_inst, task);
  543                     bkpt->flags &= ~BKPT_SET_IN_MEM;
  544                 }
  545                 bkptp = &bkpt->link;
  546             }
  547             db_breakpoints_inserted = FALSE;
  548         }
  549 }
  550 
  551 /*
  552  * Set a temporary breakpoint.
  553  * The instruction is changed immediately,
  554  * so the breakpoint does not have to be on the breakpoint list.
  555  */
  556 db_breakpoint_t
  557 db_set_temp_breakpoint(task, addr)
  558         task_t          task;
  559         db_addr_t       addr;
  560 {
  561         register db_breakpoint_t        bkpt;
  562 
  563         bkpt = db_breakpoint_alloc();
  564         if (bkpt == 0) {
  565             db_printf("Too many breakpoints.\n");
  566             return 0;
  567         }
  568         bkpt->task = task;
  569         bkpt->address = addr;
  570         bkpt->flags = BKPT_TEMP;
  571         bkpt->threads = 0;
  572         if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) {
  573             if (bkpt)
  574                 db_breakpoint_free(bkpt);
  575             db_printf("Too many thread_breakpoints.\n");
  576             return 0;
  577         }
  578         bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE, 
  579                                                 FALSE, task);
  580         db_put_task_value(bkpt->address, BKPT_SIZE, 
  581                                 BKPT_SET(bkpt->bkpt_inst), task);
  582         return bkpt;
  583 }
  584 
  585 void
  586 db_delete_temp_breakpoint(task, bkpt)
  587         task_t          task;
  588         db_breakpoint_t bkpt;
  589 {
  590         db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
  591         db_delete_thread_breakpoint(bkpt, 0);
  592         db_breakpoint_free(bkpt);
  593 }
  594 
  595 /*
  596  * List breakpoints.
  597  */
  598 void
  599 db_list_breakpoints()
  600 {
  601         register db_breakpoint_t        bkpt;
  602 
  603         if (db_breakpoint_list == 0) {
  604             db_printf("No breakpoints set\n");
  605             return;
  606         }
  607 
  608         db_printf(" No  Space    Thread      Cnt  Address(Cond)\n");
  609         for (bkpt = db_breakpoint_list;
  610              bkpt != 0;
  611              bkpt = bkpt->link)
  612         {
  613             register    db_thread_breakpoint_t tp;
  614             int         task_id;
  615             int         thread_id;
  616 
  617             if (bkpt->threads) {
  618                 for (tp = bkpt->threads; tp; tp = tp->tb_next) {
  619                     db_printf("%3d  ", tp->tb_number);
  620                     if (bkpt->flags & BKPT_USR_GLOBAL)
  621                         db_printf("user     ");
  622                     else if (bkpt->task == TASK_NULL)
  623                         db_printf("kernel   ");
  624                     else if ((task_id = db_lookup_task(bkpt->task)) < 0)
  625                         db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
  626                     else
  627                         db_printf("task%-3d  ", task_id);
  628                     if (tp->tb_task_thd == 0) {
  629                         db_printf("all         ");
  630                     } else {
  631                         if (tp->tb_is_task) {
  632                             task_id = db_lookup_task((task_t)(tp->tb_task_thd));
  633                             if (task_id < 0)
  634                                 db_printf("%0*X    ", 2*sizeof(vm_offset_t),
  635                                            tp->tb_task_thd);
  636                             else
  637                                 db_printf("task%03d     ", task_id);
  638                         } else {
  639                             thread_t thd = (thread_t)(tp->tb_task_thd);
  640                             task_id = db_lookup_task(thd->task);
  641                             thread_id = db_lookup_task_thread(thd->task, thd);
  642                             if (task_id < 0 || thread_id < 0)
  643                                 db_printf("%0*X    ", 2*sizeof(vm_offset_t),
  644                                            tp->tb_task_thd);
  645                             else        
  646                                 db_printf("task%03d.%-3d ", task_id, thread_id);
  647                         }
  648                     }
  649                     db_printf("%3d  ", tp->tb_init_count);
  650                     db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
  651                     if (tp->tb_cond > 0) {
  652                         db_printf("(");
  653                         db_cond_print(tp);
  654                         db_printf(")");
  655                     }
  656                     db_printf("\n");
  657                 }
  658             } else {
  659                 if (bkpt->task == TASK_NULL)
  660                     db_printf("  ?  kernel   ");
  661                 else
  662                     db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
  663                 db_printf("(?)              ");
  664                 db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
  665                 db_printf("\n");
  666             }
  667         }
  668 }
  669 
  670 /* Delete breakpoint */
  671 /*ARGSUSED*/
  672 void
  673 db_delete_cmd()
  674 {
  675         register n;
  676         thread_t thread;
  677         vm_offset_t task_thd;
  678         boolean_t user_global = FALSE;
  679         boolean_t task_bpt = FALSE;
  680         boolean_t user_space = FALSE;
  681         boolean_t thd_bpt = FALSE;
  682         db_expr_t addr;
  683         int t;
  684         
  685         t = db_read_token();
  686         if (t == tSLASH) {
  687             t = db_read_token();
  688             if (t != tIDENT) {
  689                 db_printf("Bad modifier \"%s\"\n", db_tok_string);
  690                 db_error(0);
  691             }
  692             user_global = db_option(db_tok_string, 'U');
  693             user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
  694             task_bpt = db_option(db_tok_string, 'T');
  695             thd_bpt = db_option(db_tok_string, 't');
  696             if (task_bpt && user_global)
  697                 db_error("Cannot specify both 'T' and 'U' option\n");
  698             t = db_read_token();
  699         }
  700         if (t == tHASH) {
  701             db_thread_breakpoint_t tbp;
  702             db_breakpoint_t bkpt;
  703 
  704             if (db_read_token() != tNUMBER) {
  705                 db_printf("Bad break point number #%s\n", db_tok_string);
  706                 db_error(0);
  707             }
  708             if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
  709                 db_printf("No such break point #%d\n", db_tok_number);
  710                 db_error(0);
  711             }
  712             db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
  713             return;
  714         }
  715         db_unread_token(t);
  716         if (!db_expression(&addr)) {
  717             /*
  718              *  We attempt to pick up the user_space indication from db_dot,
  719              *  so that a plain "d" always works.
  720              */
  721             addr = (db_expr_t)db_dot;
  722             if (!user_space && !DB_VALID_ADDRESS((vm_offset_t)addr, FALSE))
  723                 user_space = TRUE;
  724         }
  725         if (!DB_VALID_ADDRESS((vm_offset_t) addr, user_space)) {
  726             db_printf("Address %#X is not in %s space\n", addr, 
  727                         (user_space)? "user": "kernel");
  728             db_error(0);
  729         }
  730         if (thd_bpt || task_bpt) {
  731             for (n = 0; db_get_next_thread(&thread, n); n++) {
  732                 if (thread == THREAD_NULL)
  733                     db_error("No active thread\n");
  734                 if (task_bpt) {
  735                     if (thread->task == TASK_NULL)
  736                         db_error("No task\n");
  737                     task_thd = (vm_offset_t) (thread->task);
  738                 } else
  739                     task_thd = (user_global)? 0: (vm_offset_t) thread;
  740                 db_delete_breakpoint(db_target_space(thread, user_space),
  741                                         (db_addr_t)addr, task_thd);
  742             }
  743         } else {
  744             db_delete_breakpoint(db_target_space(THREAD_NULL, user_space),
  745                                          (db_addr_t)addr, 0);
  746         }
  747 }
  748 
  749 /* Set breakpoint with skip count */
  750 /*ARGSUSED*/
  751 void
  752 db_breakpoint_cmd(addr, have_addr, count, modif)
  753         db_expr_t       addr;
  754         int             have_addr;
  755         db_expr_t       count;
  756         char *          modif;
  757 {
  758         register n;
  759         thread_t thread;
  760         boolean_t user_global = db_option(modif, 'U');
  761         boolean_t task_bpt = db_option(modif, 'T');
  762         boolean_t user_space;
  763 
  764         if (count == -1)
  765             count = 1;
  766 
  767         if (!task_bpt && db_option(modif,'t'))
  768           task_bpt = TRUE;
  769 
  770         if (task_bpt && user_global)
  771             db_error("Cannot specify both 'T' and 'U'\n");
  772         user_space = (user_global)? TRUE: db_option(modif, 'u');
  773         if (user_space && db_access_level < DB_ACCESS_CURRENT)
  774             db_error("User space break point is not supported\n");
  775         if (!task_bpt && !DB_VALID_ADDRESS((vm_offset_t)addr, user_space)) {
  776             /* if the user has explicitly specified user space,
  777                do not insert a breakpoint into the kernel */
  778             if (user_space)
  779               db_error("Invalid user space address\n");
  780             user_space = TRUE;
  781             db_printf("%#X is in user space\n", addr);
  782         }
  783         if (db_option(modif, 't') || task_bpt) {
  784             for (n = 0; db_get_next_thread(&thread, n); n++) {
  785                 if (thread == THREAD_NULL)
  786                     db_error("No active thread\n");
  787                 if (task_bpt && thread->task == TASK_NULL)
  788                     db_error("No task\n");
  789                 if (db_access_level <= DB_ACCESS_CURRENT && user_space
  790                          && thread->task != db_current_task())
  791                     db_error("Cannot set break point in inactive user space\n");
  792                 db_set_breakpoint(db_target_space(thread, user_space), 
  793                                         (db_addr_t)addr, count,
  794                                         (user_global)? THREAD_NULL: thread,
  795                                         task_bpt);
  796             }
  797         } else {
  798             db_set_breakpoint(db_target_space(THREAD_NULL, user_space),
  799                                  (db_addr_t)addr,
  800                                  count, THREAD_NULL, FALSE);
  801         }
  802 }
  803 
  804 /* list breakpoints */
  805 void
  806 db_listbreak_cmd()
  807 {
  808         db_list_breakpoints();
  809 }

Cache object: 3e90284b78d41a74be6fd49bf33bc6fc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.