Annotation of XNU/osfmk/ddb/db_watch.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /*
        !            26:  * HISTORY
        !            27:  * 
        !            28:  * Revision 1.1.1.1  1998/09/22 21:05:48  wsanchez
        !            29:  * Import of Mac OS X kernel (~semeria)
        !            30:  *
        !            31:  * Revision 1.1.1.1  1998/03/07 02:26:09  wsanchez
        !            32:  * Import of OSF Mach kernel (~mburg)
        !            33:  *
        !            34:  * Revision 1.1.12.2  1995/01/06  19:11:06  devrcs
        !            35:  *     mk6 CR668 - 1.3b26 merge
        !            36:  *     * Revision 1.1.3.5  1994/05/06  18:40:29  tmt
        !            37:  *     Merged osc1.3dec/shared with osc1.3b19
        !            38:  *     Merge Alpha changes into osc1.312b source code.
        !            39:  *     64bit cleanup.
        !            40:  *     * End1.3merge
        !            41:  *     [1994/11/04  08:50:16  dwm]
        !            42:  *
        !            43:  * Revision 1.1.12.1  1994/09/23  01:22:53  ezf
        !            44:  *     change marker to not FREE
        !            45:  *     [1994/09/22  21:11:33  ezf]
        !            46:  * 
        !            47:  * Revision 1.1.10.1  1994/01/05  19:28:22  bolinger
        !            48:  *     Be sure to count kernel-loaded tasks as part of kernel address space
        !            49:  *     in locating watchpoints.
        !            50:  *     [1994/01/04  17:43:33  bolinger]
        !            51:  * 
        !            52:  * Revision 1.1.3.3  1993/07/27  18:28:31  elliston
        !            53:  *     Add ANSI prototypes.  CR #9523.
        !            54:  *     [1993/07/27  18:13:30  elliston]
        !            55:  * 
        !            56:  * Revision 1.1.3.2  1993/06/02  23:13:14  jeffc
        !            57:  *     Added to OSF/1 R1.3 from NMK15.0.
        !            58:  *     [1993/06/02  20:57:54  jeffc]
        !            59:  * 
        !            60:  * Revision 1.1  1992/09/30  02:01:33  robert
        !            61:  *     Initial revision
        !            62:  * 
        !            63:  * $EndLog$
        !            64:  */
        !            65: /* CMU_HIST */
        !            66: /*
        !            67:  * Revision 2.7  91/10/09  16:04:32  af
        !            68:  *      Revision 2.6.3.1  91/10/05  13:08:50  jeffreyh
        !            69:  *             Added user space watch point support including non current task.
        !            70:  *             Changed "map" field of db_watchpoint structure to "task"
        !            71:  *               for a user to easily understand the target space.
        !            72:  *             [91/08/29            tak]
        !            73:  * 
        !            74:  * Revision 2.6.3.1  91/10/05  13:08:50  jeffreyh
        !            75:  *     Added user space watch point support including non current task.
        !            76:  *     Changed "map" field of db_watchpoint structure to "task"
        !            77:  *       for a user to easily understand the target space.
        !            78:  *     [91/08/29            tak]
        !            79:  * 
        !            80:  * Revision 2.6  91/05/14  15:37:30  mrt
        !            81:  *     Correcting copyright
        !            82:  * 
        !            83:  * Revision 2.5  91/02/05  17:07:27  mrt
        !            84:  *     Changed to new Mach copyright
        !            85:  *     [91/01/31  16:20:02  mrt]
        !            86:  * 
        !            87:  * Revision 2.4  91/01/08  15:09:24  rpd
        !            88:  *     Use db_map_equal, db_map_current, db_map_addr.
        !            89:  *     [90/11/10            rpd]
        !            90:  * 
        !            91:  * Revision 2.3  90/11/05  14:26:39  rpd
        !            92:  *     Initialize db_watchpoints_inserted to TRUE.
        !            93:  *     [90/11/04            rpd]
        !            94:  * 
        !            95:  * Revision 2.2  90/10/25  14:44:16  rwd
        !            96:  *     Made db_watchpoint_cmd parse a size argument.
        !            97:  *     [90/10/17            rpd]
        !            98:  *     Generalized the watchpoint support.
        !            99:  *     [90/10/16            rwd]
        !           100:  *     Created.
        !           101:  *     [90/10/16            rpd]
        !           102:  * 
        !           103:  */
        !           104: /* CMU_ENDHIST */
        !           105: /* 
        !           106:  * Mach Operating System
        !           107:  * Copyright (c) 1991,1990 Carnegie Mellon University
        !           108:  * All Rights Reserved.
        !           109:  * 
        !           110:  * Permission to use, copy, modify and distribute this software and its
        !           111:  * documentation is hereby granted, provided that both the copyright
        !           112:  * notice and this permission notice appear in all copies of the
        !           113:  * software, derivative works or modified versions, and any portions
        !           114:  * thereof, and that both notices appear in supporting documentation.
        !           115:  * 
        !           116:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !           117:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !           118:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !           119:  * 
        !           120:  * Carnegie Mellon requests users of this software to return to
        !           121:  * 
        !           122:  *  Software Distribution Coordinator  or  [email protected]
        !           123:  *  School of Computer Science
        !           124:  *  Carnegie Mellon University
        !           125:  *  Pittsburgh PA 15213-3890
        !           126:  * 
        !           127:  * any improvements or extensions that they make and grant Carnegie Mellon
        !           128:  * the rights to redistribute these changes.
        !           129:  */
        !           130: /*
        !           131:  */
        !           132: /*
        !           133:  *     Author: Richard P. Draves, Carnegie Mellon University
        !           134:  *     Date:   10/90
        !           135:  */
        !           136: 
        !           137: #include <mach/boolean.h>
        !           138: #include <mach/vm_param.h>
        !           139: #include <mach/machine/vm_types.h>
        !           140: #include <mach/machine/vm_param.h>
        !           141: #include <vm/vm_map.h>
        !           142: 
        !           143: #include <machine/db_machdep.h>
        !           144: #include <ddb/db_lex.h>
        !           145: #include <ddb/db_watch.h>
        !           146: #include <ddb/db_access.h>
        !           147: #include <ddb/db_sym.h>
        !           148: #include <ddb/db_task_thread.h>
        !           149: #include <ddb/db_command.h>
        !           150: #include <ddb/db_expr.h>
        !           151: #include <ddb/db_output.h>             /* For db_printf() */
        !           152: #include <ddb/db_run.h>                        /* For db_single_step() */
        !           153: 
        !           154: /*
        !           155:  * Watchpoints.
        !           156:  */
        !           157: 
        !           158: boolean_t      db_watchpoints_inserted = TRUE;
        !           159: 
        !           160: #define        NWATCHPOINTS    100
        !           161: struct db_watchpoint   db_watch_table[NWATCHPOINTS];
        !           162: db_watchpoint_t                db_next_free_watchpoint = &db_watch_table[0];
        !           163: db_watchpoint_t                db_free_watchpoints = 0;
        !           164: db_watchpoint_t                db_watchpoint_list = 0;
        !           165: 
        !           166: extern vm_map_t                kernel_map;
        !           167: 
        !           168: 
        !           169: 
        !           170: /* Prototypes for functions local to this file.  XXX -- should be static.
        !           171:  */
        !           172: 
        !           173: db_watchpoint_t db_watchpoint_alloc(void);
        !           174: 
        !           175: void db_watchpoint_free(register db_watchpoint_t watch);
        !           176: 
        !           177: void db_set_watchpoint(
        !           178:        task_t          task,
        !           179:        db_addr_t       addr,
        !           180:        vm_size_t       size);
        !           181: 
        !           182: void db_delete_watchpoint(
        !           183:        task_t          task,
        !           184:        db_addr_t       addr);
        !           185: 
        !           186: static int db_get_task(
        !           187:        char            *modif,
        !           188:        task_t          *taskp,
        !           189:        db_addr_t       addr);
        !           190: 
        !           191: void db_list_watchpoints(void);
        !           192: 
        !           193: 
        !           194: 
        !           195: db_watchpoint_t
        !           196: db_watchpoint_alloc(void)
        !           197: {
        !           198:        register db_watchpoint_t        watch;
        !           199: 
        !           200:        if ((watch = db_free_watchpoints) != 0) {
        !           201:            db_free_watchpoints = watch->link;
        !           202:            return (watch);
        !           203:        }
        !           204:        if (db_next_free_watchpoint == &db_watch_table[NWATCHPOINTS]) {
        !           205:            db_printf("All watchpoints used.\n");
        !           206:            return (0);
        !           207:        }
        !           208:        watch = db_next_free_watchpoint;
        !           209:        db_next_free_watchpoint++;
        !           210: 
        !           211:        return (watch);
        !           212: }
        !           213: 
        !           214: void
        !           215: db_watchpoint_free(register db_watchpoint_t watch)
        !           216: {
        !           217:        watch->link = db_free_watchpoints;
        !           218:        db_free_watchpoints = watch;
        !           219: }
        !           220: 
        !           221: void
        !           222: db_set_watchpoint(
        !           223:        task_t          task,
        !           224:        db_addr_t       addr,
        !           225:        vm_size_t       size)
        !           226: {
        !           227:        register db_watchpoint_t        watch;
        !           228: 
        !           229:        /*
        !           230:         *      Should we do anything fancy with overlapping regions?
        !           231:         */
        !           232: 
        !           233:        for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
        !           234:            if (watch->task == task &&
        !           235:                (watch->loaddr == addr) &&
        !           236:                (watch->hiaddr == addr+size)) {
        !           237:                db_printf("Already set.\n");
        !           238:                return;
        !           239:            }
        !           240:        }
        !           241: 
        !           242:        watch = db_watchpoint_alloc();
        !           243:        if (watch == 0) {
        !           244:            db_printf("Too many watchpoints.\n");
        !           245:            return;
        !           246:        }
        !           247: 
        !           248:        watch->task = task;
        !           249:        watch->loaddr = addr;
        !           250:        watch->hiaddr = addr+size;
        !           251: 
        !           252:        watch->link = db_watchpoint_list;
        !           253:        db_watchpoint_list = watch;
        !           254: 
        !           255:        db_watchpoints_inserted = FALSE;
        !           256: }
        !           257: 
        !           258: void
        !           259: db_delete_watchpoint(
        !           260:        task_t          task,
        !           261:        db_addr_t       addr)
        !           262: {
        !           263:        register db_watchpoint_t        watch;
        !           264:        register db_watchpoint_t        *prev;
        !           265: 
        !           266:        for (prev = &db_watchpoint_list; (watch = *prev) != 0;
        !           267:             prev = &watch->link) {
        !           268:            if (watch->task == task &&
        !           269:                (watch->loaddr <= addr) &&
        !           270:                (addr < watch->hiaddr)) {
        !           271:                *prev = watch->link;
        !           272:                db_watchpoint_free(watch);
        !           273:                return;
        !           274:            }
        !           275:        }
        !           276: 
        !           277:        db_printf("Not set.\n");
        !           278: }
        !           279: 
        !           280: void
        !           281: db_list_watchpoints(void)
        !           282: {
        !           283:        register db_watchpoint_t watch;
        !           284:        int      task_id;
        !           285: 
        !           286:        if (db_watchpoint_list == 0) {
        !           287:            db_printf("No watchpoints set\n");
        !           288:            return;
        !           289:        }
        !           290: 
        !           291:        db_printf("Space      Address  Size\n");
        !           292:        for (watch = db_watchpoint_list; watch != 0; watch = watch->link)  {
        !           293:            if (watch->task == TASK_NULL)
        !           294:                db_printf("kernel  ");
        !           295:            else {
        !           296:                task_id = db_lookup_task(watch->task);
        !           297:                if (task_id < 0)
        !           298:                    db_printf("%*X", 2*sizeof(vm_offset_t), watch->task);
        !           299:                else
        !           300:                    db_printf("task%-3d ", task_id);
        !           301:            }
        !           302:            db_printf("  %*X  %X\n", 2*sizeof(vm_offset_t), watch->loaddr,
        !           303:                      watch->hiaddr - watch->loaddr);
        !           304:        }
        !           305: }
        !           306: 
        !           307: static int
        !           308: db_get_task(
        !           309:        char            *modif,
        !           310:        task_t          *taskp,
        !           311:        db_addr_t       addr)
        !           312: {
        !           313:        task_t          task = TASK_NULL;
        !           314:        db_expr_t       value;
        !           315:        boolean_t       user_space;
        !           316: 
        !           317:        user_space = db_option(modif, 'T');
        !           318:        if (user_space) {
        !           319:            if (db_expression(&value)) {
        !           320:                task = (task_t)value;
        !           321:                if (db_lookup_task(task) < 0) {
        !           322:                    db_printf("bad task address %X\n", task);
        !           323:                    return(-1);
        !           324:                }
        !           325:            } else {
        !           326:                task = db_default_task;
        !           327:                if (task == TASK_NULL) {
        !           328:                    if ((task = db_current_task()) == TASK_NULL) {
        !           329:                        db_printf("no task\n");
        !           330:                        return(-1);
        !           331:                    }
        !           332:                }
        !           333:            }
        !           334:        }
        !           335:        if (!DB_VALID_ADDRESS(addr, user_space)) {
        !           336:            db_printf("Address %#X is not in %s space\n", addr, 
        !           337:                        (user_space)? "user": "kernel");
        !           338:            return(-1);
        !           339:        }
        !           340:        *taskp = task;
        !           341:        return(0);
        !           342: }
        !           343: 
        !           344: /* Delete watchpoint */
        !           345: void
        !           346: db_deletewatch_cmd(
        !           347:        db_expr_t       addr,
        !           348:        int             have_addr,
        !           349:        db_expr_t       count,
        !           350:        char *          modif)
        !           351: {
        !           352:        task_t          task;
        !           353: 
        !           354:        if (db_get_task(modif, &task, addr) < 0)
        !           355:            return;
        !           356:        db_delete_watchpoint(task, addr);
        !           357: }
        !           358: 
        !           359: /* Set watchpoint */
        !           360: void
        !           361: db_watchpoint_cmd(
        !           362:        db_expr_t       addr,
        !           363:        int             have_addr,
        !           364:        db_expr_t       count,
        !           365:        char *          modif)
        !           366: {
        !           367:        vm_size_t       size;
        !           368:        db_expr_t       value;
        !           369:        task_t          task;
        !           370: 
        !           371:        if (db_get_task(modif, &task, addr) < 0)
        !           372:            return;
        !           373:        if (db_expression(&value))
        !           374:            size = (vm_size_t) value;
        !           375:        else
        !           376:            size = sizeof(int);
        !           377:        db_set_watchpoint(task, addr, size);
        !           378: }
        !           379: 
        !           380: /* list watchpoints */
        !           381: void
        !           382: db_listwatch_cmd(void)
        !           383: {
        !           384:        db_list_watchpoints();
        !           385: }
        !           386: 
        !           387: void
        !           388: db_set_watchpoints(void)
        !           389: {
        !           390:        register db_watchpoint_t        watch;
        !           391:        vm_map_t                        map;
        !           392: 
        !           393:        if (!db_watchpoints_inserted) {
        !           394:            for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
        !           395:                map = (watch->task)? watch->task->map: kernel_map;
        !           396:                pmap_protect(map->pmap,
        !           397:                             trunc_page(watch->loaddr),
        !           398:                             round_page(watch->hiaddr),
        !           399:                             VM_PROT_READ);
        !           400:            }
        !           401:            db_watchpoints_inserted = TRUE;
        !           402:        }
        !           403: }
        !           404: 
        !           405: void
        !           406: db_clear_watchpoints(void)
        !           407: {
        !           408:        db_watchpoints_inserted = FALSE;
        !           409: }
        !           410: 
        !           411: boolean_t
        !           412: db_find_watchpoint(
        !           413:        vm_map_t        map,
        !           414:        db_addr_t       addr,
        !           415:        db_regs_t       *regs)
        !           416: {
        !           417:        register db_watchpoint_t watch;
        !           418:        db_watchpoint_t found = 0;
        !           419:        register task_t task_space;
        !           420: 
        !           421:        task_space = (vm_map_pmap(map) == kernel_pmap)?
        !           422:                TASK_NULL: db_current_space();
        !           423:        for (watch = db_watchpoint_list; watch != 0; watch = watch->link) {
        !           424:            if (watch->task == task_space) {
        !           425:                if ((watch->loaddr <= addr) && (addr < watch->hiaddr))
        !           426:                    return (TRUE);
        !           427:                else if ((trunc_page(watch->loaddr) <= addr) &&
        !           428:                         (addr < round_page(watch->hiaddr)))
        !           429:                    found = watch;
        !           430:            }
        !           431:        }
        !           432: 
        !           433:        /*
        !           434:         *      We didn't hit exactly on a watchpoint, but we are
        !           435:         *      in a protected region.  We want to single-step
        !           436:         *      and then re-protect.
        !           437:         */
        !           438: 
        !           439:        if (found) {
        !           440:            db_watchpoints_inserted = FALSE;
        !           441:            db_single_step(regs, task_space);
        !           442:        }
        !           443: 
        !           444:        return (FALSE);
        !           445: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.