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_watch.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_watch.c,v $
   29  * Revision 2.11  93/11/17  16:26:50  dbg
   30  *      Added ANSI function prototypes.
   31  *      [93/10/11            dbg]
   32  * 
   33  * Revision 2.10  93/01/14  17:26:16  danner
   34  *      64bit cleanup.
   35  *      [92/11/30            af]
   36  * 
   37  * Revision 2.9  92/08/03  17:32:31  jfriedl
   38  *      removed silly prototypes
   39  *      [92/08/02            jfriedl]
   40  * 
   41  * Revision 2.8  92/05/21  17:08:16  jfriedl
   42  *      tried prototypes.
   43  *      [92/05/20            jfriedl]
   44  * 
   45  * Revision 2.7  91/10/09  16:04:32  af
   46  *      Added user space watch point support including non current task.
   47  *      Changed "map" field of db_watchpoint structure to "task"
   48  *        for a user to easily understand the target space.
   49  *      [91/08/29            tak]
   50  * 
   51  * Revision 2.6  91/05/14  15:37:30  mrt
   52  *      Correcting copyright
   53  * 
   54  * Revision 2.5  91/02/05  17:07:27  mrt
   55  *      Changed to new Mach copyright
   56  *      [91/01/31  16:20:02  mrt]
   57  * 
   58  * Revision 2.4  91/01/08  15:09:24  rpd
   59  *      Use db_map_equal, db_map_current, db_map_addr.
   60  *      [90/11/10            rpd]
   61  * 
   62  * Revision 2.3  90/11/05  14:26:39  rpd
   63  *      Initialize db_watchpoints_inserted to TRUE.
   64  *      [90/11/04            rpd]
   65  * 
   66  * Revision 2.2  90/10/25  14:44:16  rwd
   67  *      Made db_watchpoint_cmd parse a size argument.
   68  *      [90/10/17            rpd]
   69  *      Generalized the watchpoint support.
   70  *      [90/10/16            rwd]
   71  *      Created.
   72  *      [90/10/16            rpd]
   73  * 
   74  */
   75 /*
   76  *      Author: Richard P. Draves, Carnegie Mellon University
   77  *      Date:   10/90
   78  */
   79 
   80 #include <mach/boolean.h>
   81 #include <mach/vm_param.h>
   82 #include <mach/machine/vm_types.h>
   83 #include <mach/machine/vm_param.h>
   84 #include <vm/vm_map.h>
   85 #include <vm/vm_kern.h>
   86 
   87 #include <machine/db_machdep.h>
   88 #include <ddb/db_lex.h>
   89 #include <ddb/db_watch.h>
   90 #include <ddb/db_access.h>
   91 #include <ddb/db_command.h>
   92 #include <ddb/db_output.h>
   93 #include <ddb/db_sym.h>
   94 #include <ddb/db_task_thread.h>
   95 #include <ddb/db_run.h>
   96 
   97 
   98 
   99 /*
  100  * Watchpoints.
  101  */
  102 
  103 boolean_t       db_watchpoints_inserted = TRUE;
  104 
  105 #define NWATCHPOINTS    100
  106 struct db_watchpoint    db_watch_table[NWATCHPOINTS];
  107 db_watchpoint_t         db_next_free_watchpoint = &db_watch_table[0];
  108 db_watchpoint_t         db_free_watchpoints = 0;
  109 db_watchpoint_t         db_watchpoint_list = 0;
  110 
  111 db_watchpoint_t
  112 db_watchpoint_alloc(void)
  113 {
  114         register db_watchpoint_t        watch;
  115 
  116         if ((watch = db_free_watchpoints) != 0) {
  117             db_free_watchpoints = watch->link;
  118             return watch;
  119         }
  120         if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
  121             db_printf("All watchpoints used.\n");
  122             return 0;
  123         }
  124         watch = db_next_free_watchpoint;
  125         db_next_free_watchpoint++;
  126 
  127         return watch;
  128 }
  129 
  130 void
  131 db_watchpoint_free(
  132         register db_watchpoint_t        watch)
  133 {
  134         watch->link = db_free_watchpoints;
  135         db_free_watchpoints = watch;
  136 }
  137 
  138 void
  139 db_set_watchpoint(
  140         task_t          task,
  141         db_addr_t       addr,
  142         vm_size_t       size)
  143 {
  144         register db_watchpoint_t        watch;
  145 
  146         /*
  147          *      Should we do anything fancy with overlapping regions?
  148          */
  149 
  150         for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
  151             if (watch->task == task &&
  152                 (watch->loaddr == addr) &&
  153                 (watch->hiaddr == addr+size)) {
  154                 db_printf("Already set.\n");
  155                 return;
  156             }
  157         }
  158 
  159         watch = db_watchpoint_alloc();
  160         if (watch == 0) {
  161             db_printf("Too many watchpoints.\n");
  162             return;
  163         }
  164 
  165         watch->task = task;
  166         watch->loaddr = addr;
  167         watch->hiaddr = addr+size;
  168 
  169         watch->link = db_watchpoint_list;
  170         db_watchpoint_list = watch;
  171 
  172         db_watchpoints_inserted = FALSE;
  173 }
  174 
  175 void
  176 db_delete_watchpoint(
  177         task_t          task,
  178         db_addr_t       addr)
  179 {
  180         register db_watchpoint_t        watch;
  181         register db_watchpoint_t        *prev;
  182 
  183         for (prev = &db_watchpoint_list; (watch = *prev) != 0;
  184              prev = &watch->link) {
  185             if (watch->task == task &&
  186                 (watch->loaddr <= addr) &&
  187                 (addr < watch->hiaddr)) {
  188                 *prev = watch->link;
  189                 db_watchpoint_free(watch);
  190                 return;
  191             }
  192         }
  193 
  194         db_printf("Not set.\n");
  195 }
  196 
  197 void
  198 db_list_watchpoints(void)
  199 {
  200         register db_watchpoint_t watch;
  201         int      task_id;
  202 
  203         if (db_watchpoint_list == 0) {
  204             db_printf("No watchpoints set\n");
  205             return;
  206         }
  207 
  208         db_printf("Space      Address  Size\n");
  209         for (watch = db_watchpoint_list; watch != 0; watch = watch->link)  {
  210             if (watch->task == TASK_NULL)
  211                 db_printf("kernel  ");
  212             else {
  213                 task_id = db_lookup_task(watch->task);
  214                 if (task_id < 0)
  215                     db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
  216                 else
  217                     db_printf("task%-3d ", task_id);
  218             }
  219             db_printf("  %*X  %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
  220                       watch->hiaddr - watch->loaddr);
  221         }
  222 }
  223 
  224 static boolean_t
  225 db_get_task(
  226         char            *modif,
  227         task_t          *taskp,
  228         db_addr_t       addr)
  229 {
  230         task_t          task = TASK_NULL;
  231         db_expr_t       value;
  232         boolean_t       user_space;
  233 
  234         user_space = db_option(modif, 'T');
  235         if (user_space) {
  236             if (db_expression(&value)) {
  237                 task = (task_t)value;
  238                 if (db_lookup_task(task) < 0) {
  239                     db_printf("bad task address %X\n", task);
  240                     return FALSE;
  241                 }
  242             } else {
  243                 task = db_default_task;
  244                 if (task == TASK_NULL) {
  245                     if ((task = db_current_task()) == TASK_NULL) {
  246                         db_printf("no task\n");
  247                         return FALSE;
  248                     }
  249                 }
  250             }
  251         }
  252         if (!DB_VALID_ADDRESS(addr, user_space)) {
  253             db_printf("Address %#X is not in %s space\n", addr, 
  254                         (user_space)? "user": "kernel");
  255             return -1;
  256         }
  257         *taskp = task;
  258         return TRUE;
  259 }
  260 
  261 /* Delete watchpoint */
  262 /*ARGSUSED*/
  263 void
  264 db_deletewatch_cmd(
  265         db_expr_t       addr,
  266         int             have_addr,
  267         db_expr_t       count,
  268         char *          modif)
  269 {
  270         task_t          task;
  271 
  272         if (!db_get_task(modif, &task, addr))
  273             return;
  274         db_delete_watchpoint(task, addr);
  275 }
  276 
  277 /* Set watchpoint */
  278 /*ARGSUSED*/
  279 void
  280 db_watchpoint_cmd(
  281         db_expr_t       addr,
  282         int             have_addr,
  283         db_expr_t       count,
  284         char *          modif)
  285 {
  286         vm_size_t       size;
  287         db_expr_t       value;
  288         task_t          task;
  289         boolean_t       db_option();
  290 
  291         if (!db_get_task(modif, &task, addr))
  292             return;
  293         if (db_expression(&value))
  294             size = (vm_size_t) value;
  295         else
  296             size = sizeof(int);
  297         db_set_watchpoint(task, addr, size);
  298 }
  299 
  300 /* list watchpoints */
  301 void
  302 db_listwatch_cmd()
  303 {
  304         db_list_watchpoints();
  305 }
  306 
  307 void
  308 db_set_watchpoints(void)
  309 {
  310         register db_watchpoint_t        watch;
  311         vm_map_t                        map;
  312 
  313         if (!db_watchpoints_inserted) {
  314             for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
  315                 map = (watch->task)? watch->task->map: kernel_map;
  316                 pmap_protect(map->pmap,
  317                              trunc_page(watch->loaddr),
  318                              round_page(watch->hiaddr),
  319                              VM_PROT_READ);
  320             }
  321             db_watchpoints_inserted = TRUE;
  322         }
  323 }
  324 
  325 void
  326 db_clear_watchpoints(void)
  327 {
  328         db_watchpoints_inserted = FALSE;
  329 }
  330 
  331 boolean_t
  332 db_find_watchpoint(
  333         vm_map_t        map,
  334         db_addr_t       addr,
  335         db_regs_t       *regs)
  336 {
  337         register db_watchpoint_t watch;
  338         db_watchpoint_t found = 0;
  339         register task_t task_space;
  340 
  341         task_space = (map == kernel_map)? TASK_NULL: db_current_task();
  342         for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
  343             if (watch->task == task_space) {
  344                 if ((watch->loaddr <= addr) && (addr < watch->hiaddr))
  345                     return TRUE;
  346                 else if ((trunc_page(watch->loaddr) <= addr) &&
  347                          (addr < round_page(watch->hiaddr)))
  348                     found = watch;
  349             }
  350         }
  351 
  352         /*
  353          *      We didn't hit exactly on a watchpoint, but we are
  354          *      in a protected region.  We want to single-step
  355          *      and then re-protect.
  356          */
  357 
  358         if (found) {
  359             db_watchpoints_inserted = FALSE;
  360             db_single_step(regs, task_space);
  361         }
  362 
  363         return FALSE;
  364 }

Cache object: f6a3f2eb4cf15a7a14ad29d51c9d8934


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