Annotation of XNU/osfmk/ddb/db_break.c, revision 1.1.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.