Annotation of XNU/osfmk/ddb/db_break.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:47  wsanchez
        !            29:  * Import of Mac OS X kernel (~semeria)
        !            30:  *
        !            31:  * Revision 1.2  1998/04/29 17:35:26  mburg
        !            32:  * MK7.3 merger
        !            33:  *
        !            34:  * Revision 1.2.47.1  1998/02/03  09:23:57  gdt
        !            35:  *     Merge up to MK7.3
        !            36:  *     [1998/02/03  09:10:14  gdt]
        !            37:  *
        !            38:  * Revision 1.2.45.1  1997/03/27  18:46:16  barbou
        !            39:  *     ri-osc CR1557: re-enable thread-specific breakpoints.
        !            40:  *     [1995/09/20  15:23:46  bolinger]
        !            41:  *     [97/02/25            barbou]
        !            42:  * 
        !            43:  * Revision 1.2.21.6  1996/01/09  19:15:21  devrcs
        !            44:  *     Changed declarations of 'register foo' to 'register int foo'
        !            45:  *     Fixed printfs which print addresses.
        !            46:  *     [1995/12/01  21:41:51  jfraser]
        !            47:  * 
        !            48:  *     Merged '64-bit safe' changes from DEC alpha port.
        !            49:  *     [1995/11/21  18:02:40  jfraser]
        !            50:  * 
        !            51:  * Revision 1.2.21.5  1995/04/07  18:52:54  barbou
        !            52:  *     Allow breakpoints on non-resident pages. The breakpoint will
        !            53:  *     actually be set when the page is paged in.
        !            54:  *     [93/09/23            barbou]
        !            55:  *     [95/03/08            barbou]
        !            56:  * 
        !            57:  * Revision 1.2.21.4  1995/02/23  21:43:19  alanl
        !            58:  *     Merged with DIPC2_SHARED.
        !            59:  *     [1995/01/04  20:15:04  alanl]
        !            60:  * 
        !            61:  * Revision 1.2.28.1  1994/11/04  09:52:15  dwm
        !            62:  *     mk6 CR668 - 1.3b26 merge
        !            63:  *     * Revision 1.2.4.5  1994/05/06  18:38:52  tmt
        !            64:  *     Merged osc1.3dec/shared with osc1.3b19
        !            65:  *     Moved struct db_breakpoint from here to db_break.h.
        !            66:  *     Merge Alpha changes into osc1.312b source code.
        !            67:  *     64bit cleanup.
        !            68:  *     * End1.3merge
        !            69:  *     [1994/11/04  08:49:10  dwm]
        !            70:  * 
        !            71:  * Revision 1.2.21.2  1994/09/23  01:17:57  ezf
        !            72:  *     change marker to not FREE
        !            73:  *     [1994/09/22  21:09:19  ezf]
        !            74:  * 
        !            75:  * Revision 1.2.21.1  1994/06/11  21:11:24  bolinger
        !            76:  *     Merge up to NMK17.2.
        !            77:  *     [1994/06/11  20:01:06  bolinger]
        !            78:  * 
        !            79:  * Revision 1.2.25.2  1994/10/28  18:56:21  rwd
        !            80:  *     Delint.
        !            81:  *     [94/10/28            rwd]
        !            82:  * 
        !            83:  * Revision 1.2.25.1  1994/08/04  01:42:15  mmp
        !            84:  *     23-Jun-94  Stan Smith ([email protected])
        !            85:  *     Let d * delete all breakpoints.
        !            86:  *     [1994/06/28  13:54:00  sjs]
        !            87:  * 
        !            88:  * Revision 1.2.19.2  1994/04/11  09:34:22  bernadat
        !            89:  *     Moved db_breakpoint struct declaration to db_break.h
        !            90:  *     [94/03/16            bernadat]
        !            91:  * 
        !            92:  * Revision 1.2.19.1  1994/02/08  10:57:22  bernadat
        !            93:  *     When setting a breakpoint, force user_space if breakpoint is
        !            94:  *     outside kernel_space (like in the case of an emulator).
        !            95:  *     [93/09/27            paire]
        !            96:  * 
        !            97:  *     Changed silly decimal display to hex (to match input conventions).
        !            98:  *     Change from NORMA_MK14.6 [93/01/09            sjs]
        !            99:  *     [93/07/16            bernadat]
        !           100:  *     [94/02/07            bernadat]
        !           101:  * 
        !           102:  * Revision 1.2.4.3  1993/07/27  18:26:48  elliston
        !           103:  *     Add ANSI prototypes.  CR #9523.
        !           104:  *     [1993/07/27  18:10:54  elliston]
        !           105:  * 
        !           106:  * Revision 1.2.4.2  1993/06/09  02:19:39  gm
        !           107:  *     Added to OSF/1 R1.3 from NMK15.0.
        !           108:  *     [1993/06/02  20:55:42  jeffc]
        !           109:  * 
        !           110:  * Revision 1.2  1993/04/19  16:01:31  devrcs
        !           111:  *     Changes from MK78:
        !           112:  *     Removed unused variable from db_delete_cmd().
        !           113:  *     Added declaration for arg 'count' of db_add_thread_breakpoint().
        !           114:  *     [92/05/18            jfriedl]
        !           115:  *     Fixed b/tu to b/Tu work if the specified address is valid in the
        !           116:  *      target address space but not the current user space. Explicit
        !           117:  *      user space breakpoints (b/u, b/Tu, etc) will no longer get
        !           118:  *      inserted into the kernel if the specified address is invalid.
        !           119:  *     [92/04/18            danner]
        !           120:  *     [92/12/18            bruel]
        !           121:  * 
        !           122:  * Revision 1.1  1992/09/30  02:00:52  robert
        !           123:  *     Initial revision
        !           124:  * 
        !           125:  * $EndLog$
        !           126:  */
        !           127: /* CMU_HIST */
        !           128: /*
        !           129:  * Revision 2.11.3.1  92/03/03  16:13:20  jeffreyh
        !           130:  *     Pick up changes from TRUNK
        !           131:  *     [92/02/26  10:58:37  jeffreyh]
        !           132:  *
        !           133:  * Revision 2.12  92/02/19  16:46:24  elf
        !           134:  *     Removed one of the many user-unfriendlinesses.
        !           135:  *     [92/02/10  17:48:25  af]
        !           136:  * 
        !           137:  * Revision 2.11  91/11/12  11:50:24  rvb
        !           138:  *     Fixed db_delete_cmd so that just "d" works in user space.
        !           139:  *     [91/10/31            rpd]
        !           140:  *     Fixed db_delete_thread_breakpoint for zero task_thd.
        !           141:  *     [91/10/30            rpd]
        !           142:  * 
        !           143:  * Revision 2.10  91/10/09  15:57:41  af
        !           144:  *     Supported thread-oriented break points.
        !           145:  *     [91/08/29            tak]
        !           146:  * 
        !           147:  * Revision 2.9  91/07/09  23:15:39  danner
        !           148:  *     Conditionalized db_map_addr to work right on the luna. Used a
        !           149:  *     ifdef luna88k. This is evil, and needs to be fixed.
        !           150:  *     [91/07/08            danner]
        !           151:  *
        !           152:  * Revision 2.2  91/04/10  22:54:50  mbj
        !           153:  *     Grabbed 3.0 copyright/disclaimer since ddb comes from 3.0.
        !           154:  *     [91/04/09            rvb]
        !           155:  * 
        !           156:  * Revision 2.7  91/02/05  17:06:00  mrt
        !           157:  *     Changed to new Mach copyright
        !           158:  *     [91/01/31  16:17:01  mrt]
        !           159:  * 
        !           160:  * Revision 2.6  91/01/08  15:09:03  rpd
        !           161:  *     Added db_map_equal, db_map_current, db_map_addr.
        !           162:  *     [90/11/10            rpd]
        !           163:  * 
        !           164:  * Revision 2.5  90/11/05  14:26:32  rpd
        !           165:  *     Initialize db_breakpoints_inserted to TRUE.
        !           166:  *     [90/11/04            rpd]
        !           167:  * 
        !           168:  * Revision 2.4  90/10/25  14:43:33  rwd
        !           169:  *     Added map field to breakpoints.
        !           170:  *     Added map argument to db_set_breakpoint, db_delete_breakpoint,
        !           171:  *     db_find_breakpoint.  Added db_find_breakpoint_here.
        !           172:  *     [90/10/18            rpd]
        !           173:  * 
        !           174:  * Revision 2.3  90/09/28  16:57:07  jsb
        !           175:  *     Fixed db_breakpoint_free.
        !           176:  *     [90/09/18            rpd]
        !           177:  * 
        !           178:  * Revision 2.2  90/08/27  21:49:53  dbg
        !           179:  *     Reflected changes in db_printsym()'s calling seq.
        !           180:  *     [90/08/20            af]
        !           181:  *     Clear breakpoints only if inserted.
        !           182:  *     Reduce lint.
        !           183:  *     [90/08/07            dbg]
        !           184:  *     Created.
        !           185:  *     [90/07/25            dbg]
        !           186:  * 
        !           187:  */
        !           188: /* CMU_ENDHIST */
        !           189: /* 
        !           190:  * Mach Operating System
        !           191:  * Copyright (c) 1991,1990 Carnegie Mellon University
        !           192:  * All Rights Reserved.
        !           193:  * 
        !           194:  * Permission to use, copy, modify and distribute this software and its
        !           195:  * documentation is hereby granted, provided that both the copyright
        !           196:  * notice and this permission notice appear in all copies of the
        !           197:  * software, derivative works or modified versions, and any portions
        !           198:  * thereof, and that both notices appear in supporting documentation.
        !           199:  * 
        !           200:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !           201:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !           202:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !           203:  * 
        !           204:  * Carnegie Mellon requests users of this software to return to
        !           205:  * 
        !           206:  *  Software Distribution Coordinator  or  [email protected]
        !           207:  *  School of Computer Science
        !           208:  *  Carnegie Mellon University
        !           209:  *  Pittsburgh PA 15213-3890
        !           210:  * 
        !           211:  * any improvements or extensions that they make and grant Carnegie Mellon
        !           212:  * the rights to redistribute these changes.
        !           213:  */
        !           214: /*
        !           215:  */
        !           216: /*
        !           217:  *     Author: David B. Golub, Carnegie Mellon University
        !           218:  *     Date:   7/90
        !           219:  */
        !           220: 
        !           221: /*
        !           222:  * Breakpoints.
        !           223:  */
        !           224: #include <mach/boolean.h>
        !           225: #include <machine/db_machdep.h>
        !           226: #include <ddb/db_lex.h>
        !           227: #include <ddb/db_break.h>
        !           228: #include <ddb/db_access.h>
        !           229: #include <ddb/db_sym.h>
        !           230: #include <ddb/db_variables.h>
        !           231: #include <ddb/db_command.h>
        !           232: #include <ddb/db_cond.h>
        !           233: #include <ddb/db_expr.h>
        !           234: #include <ddb/db_output.h>             /* For db_printf() */
        !           235: #include <ddb/db_task_thread.h>
        !           236: 
        !           237: 
        !           238: #define        NBREAKPOINTS    100
        !           239: #define NTHREAD_LIST   (NBREAKPOINTS*3)
        !           240: 
        !           241: struct db_breakpoint   db_break_table[NBREAKPOINTS];
        !           242: db_breakpoint_t                db_next_free_breakpoint = &db_break_table[0];
        !           243: db_breakpoint_t                db_free_breakpoints = 0;
        !           244: db_breakpoint_t                db_breakpoint_list = 0;
        !           245: 
        !           246: static struct db_thread_breakpoint     db_thread_break_list[NTHREAD_LIST];
        !           247: static db_thread_breakpoint_t          db_free_thread_break_list = 0;
        !           248: static boolean_t                       db_thread_break_init = FALSE;
        !           249: static int                             db_breakpoint_number = 0;
        !           250: 
        !           251: /* Prototypes for functions local to this file.  XXX -- should be static!
        !           252:  */
        !           253: static int db_add_thread_breakpoint(
        !           254:        register db_breakpoint_t        bkpt,
        !           255:        vm_offset_t                     task_thd,
        !           256:        int                             count,
        !           257:        boolean_t                       task_bpt);
        !           258: 
        !           259: static int db_delete_thread_breakpoint(
        !           260:        register db_breakpoint_t        bkpt,
        !           261:        vm_offset_t                     task_thd);
        !           262: 
        !           263: static db_thread_breakpoint_t db_find_thread_breakpoint(
        !           264:        db_breakpoint_t bkpt,
        !           265:        thread_act_t    thr_act);
        !           266: 
        !           267: static void db_force_delete_breakpoint(
        !           268:        db_breakpoint_t bkpt,
        !           269:        vm_offset_t     task_thd,
        !           270:        boolean_t       is_task);
        !           271: 
        !           272: db_breakpoint_t db_breakpoint_alloc(void);
        !           273: 
        !           274: void db_breakpoint_free(register db_breakpoint_t bkpt);
        !           275: 
        !           276: void db_delete_breakpoint(
        !           277:        task_t          task,
        !           278:        db_addr_t       addr,
        !           279:        vm_offset_t     task_thd);
        !           280: 
        !           281: void
        !           282: db_delete_all_breakpoints(
        !           283:        task_t          task);
        !           284: 
        !           285: void db_list_breakpoints(void);
        !           286: 
        !           287: 
        !           288: 
        !           289: db_breakpoint_t
        !           290: db_breakpoint_alloc(void)
        !           291: {
        !           292:        register db_breakpoint_t        bkpt;
        !           293: 
        !           294:        if ((bkpt = db_free_breakpoints) != 0) {
        !           295:            db_free_breakpoints = bkpt->link;
        !           296:            return (bkpt);
        !           297:        }
        !           298:        if (db_next_free_breakpoint == &db_break_table[NBREAKPOINTS]) {
        !           299:            db_printf("All breakpoints used.\n");
        !           300:            return (0);
        !           301:        }
        !           302:        bkpt = db_next_free_breakpoint;
        !           303:        db_next_free_breakpoint++;
        !           304: 
        !           305:        return (bkpt);
        !           306: }
        !           307: 
        !           308: void
        !           309: db_breakpoint_free(register db_breakpoint_t bkpt)
        !           310: {
        !           311:        bkpt->link = db_free_breakpoints;
        !           312:        db_free_breakpoints = bkpt;
        !           313: }
        !           314: 
        !           315: static int
        !           316: db_add_thread_breakpoint(
        !           317:        register db_breakpoint_t        bkpt,
        !           318:        vm_offset_t                     task_thd,
        !           319:        int                             count,
        !           320:        boolean_t                       task_bpt)
        !           321: {
        !           322:        register db_thread_breakpoint_t tp;
        !           323: 
        !           324:        if (db_thread_break_init == FALSE) {
        !           325:            for (tp = db_thread_break_list; 
        !           326:                tp < &db_thread_break_list[NTHREAD_LIST-1]; tp++)
        !           327:                tp->tb_next = tp+1;
        !           328:            tp->tb_next = 0;
        !           329:            db_free_thread_break_list = db_thread_break_list;
        !           330:            db_thread_break_init = TRUE;
        !           331:        }
        !           332:        if (db_free_thread_break_list == 0)
        !           333:            return (-1);
        !           334:        tp = db_free_thread_break_list;
        !           335:        db_free_thread_break_list = tp->tb_next;
        !           336:        tp->tb_is_task = task_bpt;
        !           337:        tp->tb_task_thd = task_thd;
        !           338:        tp->tb_count = count;
        !           339:        tp->tb_init_count = count;
        !           340:        tp->tb_cond = 0;
        !           341:        tp->tb_number = ++db_breakpoint_number;
        !           342:        tp->tb_next = bkpt->threads;
        !           343:        bkpt->threads = tp;
        !           344:        return(0);
        !           345: }
        !           346: 
        !           347: static int
        !           348: db_delete_thread_breakpoint(
        !           349:        register db_breakpoint_t        bkpt,
        !           350:        vm_offset_t                     task_thd)
        !           351: {
        !           352:        register db_thread_breakpoint_t tp;
        !           353:        register db_thread_breakpoint_t *tpp;
        !           354: 
        !           355:        if (task_thd == 0) {
        !           356:            /* delete all the thread-breakpoints */
        !           357: 
        !           358:            for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
        !           359:                db_cond_free(tp);
        !           360: 
        !           361:            *tpp = db_free_thread_break_list;
        !           362:            db_free_thread_break_list = bkpt->threads;
        !           363:            bkpt->threads = 0;
        !           364:            return 0;
        !           365:        } else {
        !           366:            /* delete the specified thread-breakpoint */
        !           367: 
        !           368:            for (tpp = &bkpt->threads; (tp = *tpp) != 0; tpp = &tp->tb_next)
        !           369:                if (tp->tb_task_thd == task_thd) {
        !           370:                    db_cond_free(tp);
        !           371:                    *tpp = tp->tb_next;
        !           372:                    tp->tb_next = db_free_thread_break_list;
        !           373:                    db_free_thread_break_list = tp;
        !           374:                    return 0;
        !           375:                }
        !           376: 
        !           377:            return -1;  /* not found */
        !           378:        }
        !           379: }
        !           380: 
        !           381: static db_thread_breakpoint_t
        !           382: db_find_thread_breakpoint(
        !           383:        db_breakpoint_t bkpt,
        !           384:        thread_act_t    thr_act)
        !           385: {
        !           386:        register db_thread_breakpoint_t tp;
        !           387:        register task_t task =
        !           388:                        (thr_act == THR_ACT_NULL || thr_act->kernel_loaded)
        !           389:                                        ? TASK_NULL : thr_act->task;
        !           390: 
        !           391:        for (tp = bkpt->threads; tp; tp = tp->tb_next) {
        !           392:            if (tp->tb_is_task) {
        !           393:                if (tp->tb_task_thd == (vm_offset_t)task)
        !           394:                    break;
        !           395:                continue;
        !           396:            }
        !           397:            if (tp->tb_task_thd == (vm_offset_t)thr_act || tp->tb_task_thd == 0)
        !           398:                break;
        !           399:        }
        !           400:        return(tp);
        !           401: }
        !           402: 
        !           403: db_thread_breakpoint_t
        !           404: db_find_thread_breakpoint_here(
        !           405:        task_t          task,
        !           406:        db_addr_t       addr)
        !           407: {
        !           408:        db_breakpoint_t bkpt;
        !           409: 
        !           410:        bkpt = db_find_breakpoint(task, (db_addr_t)addr);
        !           411:        if (bkpt == 0)
        !           412:            return(0);
        !           413:        return(db_find_thread_breakpoint(bkpt, current_act()));
        !           414: }
        !           415: 
        !           416: db_thread_breakpoint_t
        !           417: db_find_breakpoint_number(
        !           418:        int             num,
        !           419:        db_breakpoint_t *bkptp)
        !           420: {
        !           421:        register db_thread_breakpoint_t tp;
        !           422:        register db_breakpoint_t bkpt;
        !           423: 
        !           424:        for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
        !           425:            for (tp = bkpt->threads; tp; tp = tp->tb_next) {
        !           426:                if (tp->tb_number == num) {
        !           427:                    if (bkptp)
        !           428:                        *bkptp = bkpt;
        !           429:                    return(tp);
        !           430:                }
        !           431:            }
        !           432:        }
        !           433:        return(0);
        !           434: }
        !           435: 
        !           436: static void
        !           437: db_force_delete_breakpoint(
        !           438:        db_breakpoint_t bkpt,
        !           439:        vm_offset_t     task_thd,
        !           440:        boolean_t       is_task)
        !           441: {
        !           442:        db_printf("deleted a stale breakpoint at ");
        !           443:        if (bkpt->task == TASK_NULL || db_lookup_task(bkpt->task) >= 0)
        !           444:           db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
        !           445:        else
        !           446:           db_printf("%#X", bkpt->address);
        !           447:        if (bkpt->task)
        !           448:           db_printf(" in task %X", bkpt->task);
        !           449:        if (task_thd)
        !           450:           db_printf(" for %s %X", (is_task)? "task": "thr_act", task_thd);
        !           451:        db_printf("\n");
        !           452:        db_delete_thread_breakpoint(bkpt, task_thd);
        !           453: }
        !           454: 
        !           455: void
        !           456: db_check_breakpoint_valid(void)
        !           457: {
        !           458:        register db_thread_breakpoint_t tbp, tbp_next;
        !           459:        register db_breakpoint_t bkpt, *bkptp;
        !           460: 
        !           461:        bkptp = &db_breakpoint_list;
        !           462:        for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
        !           463:            if (bkpt->task != TASK_NULL) {
        !           464:                if (db_lookup_task(bkpt->task) < 0) {
        !           465:                    db_force_delete_breakpoint(bkpt, 0, FALSE);
        !           466:                    *bkptp = bkpt->link;
        !           467:                    db_breakpoint_free(bkpt);
        !           468:                    continue;
        !           469:                }
        !           470:            } else {
        !           471:                for (tbp = bkpt->threads; tbp; tbp = tbp_next) {
        !           472:                    tbp_next = tbp->tb_next;
        !           473:                    if (tbp->tb_task_thd == 0)
        !           474:                        continue;
        !           475:                    if ((tbp->tb_is_task && 
        !           476:                         db_lookup_task((task_t)(tbp->tb_task_thd)) < 0) ||
        !           477:                        (!tbp->tb_is_task && 
        !           478:                         db_lookup_act((thread_act_t)(tbp->tb_task_thd)) < 0)) {
        !           479:                        db_force_delete_breakpoint(bkpt, 
        !           480:                                        tbp->tb_task_thd, tbp->tb_is_task);
        !           481:                    }
        !           482:                }
        !           483:                if (bkpt->threads == 0) {
        !           484:                    db_put_task_value(bkpt->address, BKPT_SIZE,
        !           485:                                 bkpt->bkpt_inst, bkpt->task);
        !           486:                    *bkptp = bkpt->link;
        !           487:                    db_breakpoint_free(bkpt);
        !           488:                    continue;
        !           489:                }
        !           490:            }
        !           491:            bkptp = &bkpt->link;
        !           492:        }
        !           493: }
        !           494: 
        !           495: void
        !           496: db_set_breakpoint(
        !           497:        task_t          task,
        !           498:        db_addr_t       addr,
        !           499:        int             count,
        !           500:        thread_act_t    thr_act,
        !           501:        boolean_t       task_bpt)
        !           502: {
        !           503:        register db_breakpoint_t bkpt;
        !           504:        db_breakpoint_t alloc_bkpt = 0;
        !           505:        vm_offset_t task_thd;
        !           506: 
        !           507:        bkpt = db_find_breakpoint(task, addr);
        !           508:        if (bkpt) {
        !           509:            if (thr_act == THR_ACT_NULL
        !           510:                || db_find_thread_breakpoint(bkpt, thr_act)) {
        !           511:                db_printf("Already set.\n");
        !           512:                return;
        !           513:            }
        !           514:        } else {
        !           515:            if (!DB_CHECK_ACCESS(addr, BKPT_SIZE, task)) {
        !           516:                if (task) {
        !           517:                    db_printf("Warning: non-resident page for breakpoint at %lX",
        !           518:                              addr);
        !           519:                    db_printf(" in task %lX.\n", task);
        !           520:                } else {
        !           521:                    db_printf("Cannot set breakpoint at %lX in kernel space.\n",
        !           522:                              addr);
        !           523:                    return;
        !           524:                }
        !           525:            }
        !           526:            alloc_bkpt = bkpt = db_breakpoint_alloc();
        !           527:            if (bkpt == 0) {
        !           528:                db_printf("Too many breakpoints.\n");
        !           529:                return;
        !           530:            }
        !           531:            bkpt->task = task;
        !           532:            bkpt->flags = (task && thr_act == THR_ACT_NULL)?
        !           533:                                (BKPT_USR_GLOBAL|BKPT_1ST_SET): 0;
        !           534:            bkpt->address = addr;
        !           535:            bkpt->threads = 0;
        !           536:        }
        !           537:        if (db_breakpoint_list == 0)
        !           538:            db_breakpoint_number = 0;
        !           539:        task_thd = (task_bpt)   ? (vm_offset_t)(thr_act->task)
        !           540:                                : (vm_offset_t)thr_act;
        !           541:        if (db_add_thread_breakpoint(bkpt, task_thd, count, task_bpt) < 0) {
        !           542:            if (alloc_bkpt)
        !           543:                db_breakpoint_free(alloc_bkpt);
        !           544:            db_printf("Too many thread_breakpoints.\n");
        !           545:        } else {
        !           546:            db_printf("set breakpoint #%x\n", db_breakpoint_number);
        !           547:            if (alloc_bkpt) {
        !           548:                bkpt->link = db_breakpoint_list;
        !           549:                db_breakpoint_list = bkpt;
        !           550:            }
        !           551:        }
        !           552: }
        !           553: 
        !           554: void
        !           555: db_delete_breakpoint(
        !           556:        task_t          task,
        !           557:        db_addr_t       addr,
        !           558:        vm_offset_t     task_thd)
        !           559: {
        !           560:        register db_breakpoint_t        bkpt;
        !           561:        register db_breakpoint_t        *prev;
        !           562: 
        !           563:        for (prev = &db_breakpoint_list; (bkpt = *prev) != 0;
        !           564:                                             prev = &bkpt->link) {
        !           565:            if ((bkpt->task == task
        !           566:                   || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
        !           567:                && bkpt->address == addr)
        !           568:                break;
        !           569:        }
        !           570:        if (bkpt && (bkpt->flags & BKPT_SET_IN_MEM)) {
        !           571:            db_printf("cannot delete it now.\n");
        !           572:            return;
        !           573:        }
        !           574:        if (bkpt == 0
        !           575:            || db_delete_thread_breakpoint(bkpt, task_thd) < 0) {
        !           576:            db_printf("Not set.\n");
        !           577:            return;
        !           578:        }
        !           579:        if (bkpt->threads == 0) {
        !           580:            *prev = bkpt->link;
        !           581:            db_breakpoint_free(bkpt);
        !           582:        }
        !           583: }
        !           584: 
        !           585: db_breakpoint_t
        !           586: db_find_breakpoint(
        !           587:        task_t          task,
        !           588:        db_addr_t       addr)
        !           589: {
        !           590:        register db_breakpoint_t        bkpt;
        !           591: 
        !           592:        for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
        !           593:            if ((bkpt->task == task
        !           594:                  || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
        !           595:                && bkpt->address == addr)
        !           596:                return (bkpt);
        !           597:        }
        !           598:        return (0);
        !           599: }
        !           600: 
        !           601: boolean_t
        !           602: db_find_breakpoint_here(
        !           603:        task_t          task,
        !           604:        db_addr_t       addr)
        !           605: {
        !           606:        register db_breakpoint_t        bkpt;
        !           607: 
        !           608:        for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
        !           609:            if ((bkpt->task == task
        !           610:                   || (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL)))
        !           611:                 && bkpt->address == addr)
        !           612:                return(TRUE);
        !           613:            if ((bkpt->flags & BKPT_USR_GLOBAL) == 0 &&
        !           614:                  DB_PHYS_EQ(task, addr, bkpt->task, bkpt->address))
        !           615:                return (TRUE);
        !           616:        }
        !           617:        return(FALSE);
        !           618: }
        !           619: 
        !           620: boolean_t      db_breakpoints_inserted = TRUE;
        !           621: 
        !           622: void
        !           623: db_set_breakpoints(void)
        !           624: {
        !           625:        register db_breakpoint_t bkpt;
        !           626:        register task_t task;
        !           627:        db_expr_t       inst;
        !           628:        thread_act_t    cur_act = current_act();
        !           629:        task_t          cur_task =
        !           630:                                (cur_act && !cur_act->kernel_loaded) ?
        !           631:                                        cur_act->task : TASK_NULL;
        !           632:        boolean_t       inserted = TRUE;
        !           633: 
        !           634:        if (!db_breakpoints_inserted) {
        !           635:            for (bkpt = db_breakpoint_list; bkpt != 0; bkpt = bkpt->link) {
        !           636:                if (bkpt->flags & BKPT_SET_IN_MEM)
        !           637:                    continue;
        !           638:                task = bkpt->task;
        !           639:                if (bkpt->flags & BKPT_USR_GLOBAL) {
        !           640:                    if ((bkpt->flags & BKPT_1ST_SET) == 0) {
        !           641:                        if (cur_task == TASK_NULL)
        !           642:                            continue;
        !           643:                        task = cur_task;
        !           644:                    } else
        !           645:                        bkpt->flags &= ~BKPT_1ST_SET;
        !           646:                }
        !           647:                if (DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
        !           648:                    inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE,
        !           649:                                                                task);
        !           650:                    if (inst == BKPT_SET(inst))
        !           651:                        continue;
        !           652:                    bkpt->bkpt_inst = inst;
        !           653:                    db_put_task_value(bkpt->address,
        !           654:                                BKPT_SIZE,
        !           655:                                BKPT_SET(bkpt->bkpt_inst), task);
        !           656:                    bkpt->flags |= BKPT_SET_IN_MEM;
        !           657:                } else {
        !           658:                    inserted = FALSE;
        !           659:                }
        !           660:            }
        !           661:            db_breakpoints_inserted = inserted;
        !           662:        }
        !           663: }
        !           664: 
        !           665: void
        !           666: db_clear_breakpoints(void)
        !           667: {
        !           668:        register db_breakpoint_t bkpt, *bkptp;
        !           669:        register task_t  task;
        !           670:        db_expr_t inst;
        !           671:        thread_act_t     cur_act = current_act();
        !           672:        task_t   cur_task = (cur_act && !cur_act->kernel_loaded) ?
        !           673:                        cur_act->task: TASK_NULL;
        !           674: 
        !           675:        if (db_breakpoints_inserted) {
        !           676:            bkptp = &db_breakpoint_list;
        !           677:            for (bkpt = *bkptp; bkpt; bkpt = *bkptp) {
        !           678:                task = bkpt->task;
        !           679:                if (bkpt->flags & BKPT_USR_GLOBAL) {
        !           680:                    if (cur_task == TASK_NULL) {
        !           681:                        bkptp = &bkpt->link;
        !           682:                        continue;
        !           683:                    }
        !           684:                    task = cur_task;
        !           685:                }
        !           686:                if ((bkpt->flags & BKPT_SET_IN_MEM)
        !           687:                    && DB_CHECK_ACCESS(bkpt->address, BKPT_SIZE, task)) {
        !           688:                    inst = db_get_task_value(bkpt->address, BKPT_SIZE, FALSE, 
        !           689:                                                                task);
        !           690:                    if (inst != BKPT_SET(inst)) {
        !           691:                        if (bkpt->flags & BKPT_USR_GLOBAL) {
        !           692:                            bkptp = &bkpt->link;
        !           693:                            continue;
        !           694:                        }
        !           695:                        db_force_delete_breakpoint(bkpt, 0, FALSE);
        !           696:                        *bkptp = bkpt->link;
        !           697:                        db_breakpoint_free(bkpt);
        !           698:                        continue;
        !           699:                    }
        !           700:                    db_put_task_value(bkpt->address, BKPT_SIZE,
        !           701:                                 bkpt->bkpt_inst, task);
        !           702:                    bkpt->flags &= ~BKPT_SET_IN_MEM;
        !           703:                }
        !           704:                bkptp = &bkpt->link;
        !           705:            }
        !           706:            db_breakpoints_inserted = FALSE;
        !           707:        }
        !           708: }
        !           709: 
        !           710: /*
        !           711:  * Set a temporary breakpoint.
        !           712:  * The instruction is changed immediately,
        !           713:  * so the breakpoint does not have to be on the breakpoint list.
        !           714:  */
        !           715: db_breakpoint_t
        !           716: db_set_temp_breakpoint(
        !           717:        task_t          task,
        !           718:        db_addr_t       addr)
        !           719: {
        !           720:        register db_breakpoint_t        bkpt;
        !           721: 
        !           722:        bkpt = db_breakpoint_alloc();
        !           723:        if (bkpt == 0) {
        !           724:            db_printf("Too many breakpoints.\n");
        !           725:            return 0;
        !           726:        }
        !           727:        bkpt->task = task;
        !           728:        bkpt->address = addr;
        !           729:        bkpt->flags = BKPT_TEMP;
        !           730:        bkpt->threads = 0;
        !           731:        if (db_add_thread_breakpoint(bkpt, 0, 1, FALSE) < 0) {
        !           732:            if (bkpt)
        !           733:                db_breakpoint_free(bkpt);
        !           734:            db_printf("Too many thread_breakpoints.\n");
        !           735:            return 0;
        !           736:        }
        !           737:        bkpt->bkpt_inst = db_get_task_value(bkpt->address, BKPT_SIZE, 
        !           738:                                                FALSE, task);
        !           739:        db_put_task_value(bkpt->address, BKPT_SIZE, 
        !           740:                                BKPT_SET(bkpt->bkpt_inst), task);
        !           741:        return bkpt;
        !           742: }
        !           743: 
        !           744: void
        !           745: db_delete_temp_breakpoint(
        !           746:        task_t          task,
        !           747:        db_breakpoint_t bkpt)
        !           748: {
        !           749:        db_put_task_value(bkpt->address, BKPT_SIZE, bkpt->bkpt_inst, task);
        !           750:        db_delete_thread_breakpoint(bkpt, 0);
        !           751:        db_breakpoint_free(bkpt);
        !           752: }
        !           753: 
        !           754: /*
        !           755:  * List breakpoints.
        !           756:  */
        !           757: void
        !           758: db_list_breakpoints(void)
        !           759: {
        !           760:        register db_breakpoint_t        bkpt;
        !           761: 
        !           762:        if (db_breakpoint_list == 0) {
        !           763:            db_printf("No breakpoints set\n");
        !           764:            return;
        !           765:        }
        !           766: 
        !           767:        db_printf(" No  Space    Task.Act    Cnt  Address(Cond)\n");
        !           768:        for (bkpt = db_breakpoint_list;
        !           769:             bkpt != 0;
        !           770:             bkpt = bkpt->link)
        !           771:        {
        !           772:            register    db_thread_breakpoint_t tp;
        !           773:            int         task_id;
        !           774:            int         act_id;
        !           775: 
        !           776:            if (bkpt->threads) {
        !           777:                for (tp = bkpt->threads; tp; tp = tp->tb_next) {
        !           778:                    db_printf("%3d  ", tp->tb_number);
        !           779:                    if (bkpt->flags & BKPT_USR_GLOBAL)
        !           780:                        db_printf("user     ");
        !           781:                    else if (bkpt->task == TASK_NULL)
        !           782:                        db_printf("kernel   ");
        !           783:                    else if ((task_id = db_lookup_task(bkpt->task)) < 0)
        !           784:                        db_printf("%0*X ", 2*sizeof(vm_offset_t), bkpt->task);
        !           785:                    else
        !           786:                        db_printf("task%-3d  ", task_id);
        !           787:                    if (tp->tb_task_thd == 0) {
        !           788:                        db_printf("all         ");
        !           789:                    } else {
        !           790:                        if (tp->tb_is_task) {
        !           791:                            task_id = db_lookup_task((task_t)(tp->tb_task_thd));
        !           792:                            if (task_id < 0)
        !           793:                                db_printf("%0*X    ", 2*sizeof(vm_offset_t),
        !           794:                                           tp->tb_task_thd);
        !           795:                            else
        !           796:                                db_printf("task%03d     ", task_id);
        !           797:                        } else {
        !           798:                            thread_act_t thd = (thread_act_t)(tp->tb_task_thd);
        !           799:                            task_id = db_lookup_task(thd->task);
        !           800:                            act_id = db_lookup_task_act(thd->task, thd);
        !           801:                            if (task_id < 0 || act_id < 0)
        !           802:                                db_printf("%0*X    ", 2*sizeof(vm_offset_t),
        !           803:                                                tp->tb_task_thd);
        !           804:                            else        
        !           805:                                db_printf("task%03d.%-3d ", task_id, act_id);
        !           806:                        }
        !           807:                    }
        !           808:                    db_printf("%3d  ", tp->tb_init_count);
        !           809:                    db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
        !           810:                    if (tp->tb_cond > 0) {
        !           811:                        db_printf("(");
        !           812:                        db_cond_print(tp);
        !           813:                        db_printf(")");
        !           814:                    }
        !           815:                    db_printf("\n");
        !           816:                }
        !           817:            } else {
        !           818:                if (bkpt->task == TASK_NULL)
        !           819:                    db_printf("  ?  kernel   ");
        !           820:                else
        !           821:                    db_printf("%*X ", 2*sizeof(vm_offset_t), bkpt->task);
        !           822:                db_printf("(?)              ");
        !           823:                db_task_printsym(bkpt->address, DB_STGY_PROC, bkpt->task);
        !           824:                db_printf("\n");
        !           825:            }
        !           826:        }
        !           827: }
        !           828: 
        !           829: void
        !           830: db_delete_all_breakpoints(
        !           831:        task_t          task)
        !           832: {
        !           833:        register db_breakpoint_t        bkpt;
        !           834: 
        !           835:        bkpt = db_breakpoint_list;
        !           836:        while ( bkpt != 0 ) {
        !           837:                if (bkpt->task == task ||
        !           838:                    (task != TASK_NULL && (bkpt->flags & BKPT_USR_GLOBAL))) {
        !           839:                        db_delete_breakpoint(task, bkpt->address, 0);
        !           840:                        bkpt = db_breakpoint_list;
        !           841:                }
        !           842:                else
        !           843:                        bkpt = bkpt->link;
        !           844:        
        !           845:        }
        !           846: }
        !           847: 
        !           848: /* Delete breakpoint */
        !           849: void
        !           850: db_delete_cmd(void)
        !           851: {
        !           852:        register int n;
        !           853:        thread_act_t     thr_act;
        !           854:        vm_offset_t task_thd;
        !           855:        boolean_t user_global = FALSE;
        !           856:        boolean_t task_bpt = FALSE;
        !           857:        boolean_t user_space = FALSE;
        !           858:        boolean_t thd_bpt = FALSE;
        !           859:        db_expr_t addr;
        !           860:        int t;
        !           861:        
        !           862:        t = db_read_token();
        !           863:        if (t == tSLASH) {
        !           864:            t = db_read_token();
        !           865:            if (t != tIDENT) {
        !           866:                db_printf("Bad modifier \"%s\"\n", db_tok_string);
        !           867:                db_error(0);
        !           868:            }
        !           869:            user_global = db_option(db_tok_string, 'U');
        !           870:            user_space = (user_global)? TRUE: db_option(db_tok_string, 'u');
        !           871:            task_bpt = db_option(db_tok_string, 'T');
        !           872:            thd_bpt = db_option(db_tok_string, 't');
        !           873:            if (task_bpt && user_global)
        !           874:                db_error("Cannot specify both 'T' and 'U' option\n");
        !           875:            t = db_read_token();
        !           876:        }
        !           877: 
        !           878:        if ( t == tSTAR ) {
        !           879:                db_printf("Delete ALL breakpoints\n");
        !           880:                db_delete_all_breakpoints( (task_t)task_bpt );
        !           881:                return;
        !           882:        }
        !           883: 
        !           884:        if (t == tHASH) {
        !           885:            db_thread_breakpoint_t tbp;
        !           886:            db_breakpoint_t bkpt;
        !           887: 
        !           888:            if (db_read_token() != tNUMBER) {
        !           889:                db_printf("Bad break point number #%s\n", db_tok_string);
        !           890:                db_error(0);
        !           891:            }
        !           892:            if ((tbp = db_find_breakpoint_number(db_tok_number, &bkpt)) == 0) {
        !           893:                db_printf("No such break point #%d\n", db_tok_number);
        !           894:                db_error(0);
        !           895:            }
        !           896:            db_delete_breakpoint(bkpt->task, bkpt->address, tbp->tb_task_thd);
        !           897:            return;
        !           898:        }
        !           899:        db_unread_token(t);
        !           900:        if (!db_expression(&addr)) {
        !           901:            /*
        !           902:             *  We attempt to pick up the user_space indication from db_dot,
        !           903:             *  so that a plain "d" always works.
        !           904:             */
        !           905:            addr = (db_expr_t)db_dot;
        !           906:            if (!user_space && !DB_VALID_ADDRESS(addr, FALSE))
        !           907:                user_space = TRUE;
        !           908:        }
        !           909:        if (!DB_VALID_ADDRESS(addr, user_space)) {
        !           910:            db_printf("Address %#X is not in %s space\n", addr, 
        !           911:                        (user_space)? "user": "kernel");
        !           912:            db_error(0);
        !           913:        }
        !           914:        if (thd_bpt || task_bpt) {
        !           915:            for (n = 0; db_get_next_act(&thr_act, n); n++) {
        !           916:                if (thr_act == THR_ACT_NULL)
        !           917:                    db_error("No active thr_act\n");
        !           918:                if (task_bpt) {
        !           919:                    if (thr_act->task == TASK_NULL)
        !           920:                        db_error("No task\n");
        !           921:                    task_thd = (vm_offset_t) (thr_act->task);
        !           922:                } else
        !           923:                    task_thd = (user_global)? 0: (vm_offset_t) thr_act;
        !           924:                db_delete_breakpoint(db_target_space(thr_act, user_space),
        !           925:                                        (db_addr_t)addr, task_thd);
        !           926:            }
        !           927:        } else {
        !           928:            db_delete_breakpoint(db_target_space(THR_ACT_NULL, user_space),
        !           929:                                         (db_addr_t)addr, 0);
        !           930:        }
        !           931: }
        !           932: 
        !           933: /* Set breakpoint with skip count */
        !           934: #include <mach/machine/vm_param.h>
        !           935: 
        !           936: void
        !           937: db_breakpoint_cmd(
        !           938:        db_expr_t       addr,
        !           939:        int             have_addr,
        !           940:        db_expr_t       count,
        !           941:        char *          modif)
        !           942: {
        !           943:        register int n;
        !           944:        thread_act_t thr_act;
        !           945:        boolean_t user_global = db_option(modif, 'U');
        !           946:        boolean_t task_bpt = db_option(modif, 'T');
        !           947:        boolean_t user_space;
        !           948: 
        !           949:        if (count == -1)
        !           950:            count = 1;
        !           951: #if 0 /* CHECKME */
        !           952:        if (!task_bpt && db_option(modif,'t'))
        !           953:          task_bpt = TRUE;
        !           954: #endif
        !           955: 
        !           956:        if (task_bpt && user_global)
        !           957:            db_error("Cannot specify both 'T' and 'U'\n");
        !           958:        user_space = (user_global)? TRUE: db_option(modif, 'u');
        !           959:        if (user_space && db_access_level < DB_ACCESS_CURRENT)
        !           960:            db_error("User space break point is not supported\n");
        !           961:        if ((!task_bpt || !user_space) &&
        !           962:            !DB_VALID_ADDRESS(addr, user_space)) {
        !           963:            /* if the user has explicitly specified user space,
        !           964:               do not insert a breakpoint into the kernel */
        !           965:            if (user_space)
        !           966:              db_error("Invalid user space address\n");
        !           967:            user_space = TRUE;
        !           968:            db_printf("%#X is in user space\n", addr);
        !           969:            db_printf("kernel is from %#X to %#x\n", VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS);
        !           970:        }
        !           971:        if (db_option(modif, 't') || task_bpt) {
        !           972:            for (n = 0; db_get_next_act(&thr_act, n); n++) {
        !           973:                if (thr_act == THR_ACT_NULL)
        !           974:                    db_error("No active thr_act\n");
        !           975:                if (task_bpt && thr_act->task == TASK_NULL)
        !           976:                    db_error("No task\n");
        !           977:                if (db_access_level <= DB_ACCESS_CURRENT && user_space
        !           978:                         && thr_act->task != db_current_space())
        !           979:                    db_error("Cannot set break point in inactive user space\n");
        !           980:                db_set_breakpoint(db_target_space(thr_act, user_space), 
        !           981:                                        (db_addr_t)addr, count,
        !           982:                                        (user_global)? THR_ACT_NULL: thr_act,
        !           983:                                        task_bpt);
        !           984:            }
        !           985:        } else {
        !           986:            db_set_breakpoint(db_target_space(THR_ACT_NULL, user_space),
        !           987:                                 (db_addr_t)addr,
        !           988:                                 count, THR_ACT_NULL, FALSE);
        !           989:        }
        !           990: }
        !           991: 
        !           992: /* list breakpoints */
        !           993: void
        !           994: db_listbreak_cmd(void)
        !           995: {
        !           996:        db_list_breakpoints();
        !           997: }

unix.superglobalmegacorp.com

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