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

Cache object: 4a6c822a9ceda147ec394f8a35759560


[ 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.