Annotation of XNU/osfmk/ddb/db_run.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:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: /*
                     53:  *     Author: David B. Golub, Carnegie Mellon University
                     54:  *     Date:   7/90
                     55:  */
                     56: 
                     57: /*
                     58:  * Commands to run process.
                     59:  */
                     60: #include <mach/boolean.h>
                     61: #include <machine/db_machdep.h>
                     62: 
                     63: #include <ddb/db_lex.h>
                     64: #include <ddb/db_break.h>
                     65: #include <ddb/db_access.h>
                     66: #include <ddb/db_run.h>
                     67: #include <ddb/db_cond.h>
                     68: #include <ddb/db_examine.h>
                     69: #include <ddb/db_output.h>             /* For db_printf() */
                     70: #include <ddb/db_watch.h>
                     71: #include <kern/misc_protos.h>
                     72: #include <kern/debug.h>
                     73: 
                     74: boolean_t      db_sstep_print;
                     75: int            db_loop_count;
                     76: int            db_call_depth;
                     77: 
                     78: int            db_inst_count;
                     79: int            db_last_inst_count;
                     80: int            db_load_count;
                     81: int            db_store_count;
                     82: int            db_max_inst_count = 1000;
                     83: 
                     84: #ifndef db_set_single_step
                     85: void db_set_task_single_step(
                     86:        register db_regs_t      *regs,
                     87:        task_t                  task);
                     88: #else
                     89: #define        db_set_task_single_step(regs,task)      db_set_single_step(regs)
                     90: #endif
                     91: #ifndef db_clear_single_step
                     92: void db_clear_task_single_step(
                     93:        db_regs_t       *regs,
                     94:        task_t          task);
                     95: #else
                     96: #define db_clear_task_single_step(regs,task)   db_clear_single_step(regs)
                     97: #endif
                     98: 
                     99: extern jmp_buf_t *db_recover;
                    100: boolean_t db_step_again(void);
                    101: 
                    102: boolean_t
                    103: db_stop_at_pc(
                    104:        boolean_t       *is_breakpoint,
                    105:        task_t          task,
                    106:        task_t          space)
                    107: {
                    108:        register  db_addr_t     pc;
                    109:        register  db_thread_breakpoint_t bkpt;
                    110: 
                    111:        db_clear_task_single_step(DDB_REGS, space);
                    112:        db_clear_breakpoints();
                    113:        db_clear_watchpoints();
                    114:        pc = PC_REGS(DDB_REGS);
                    115: 
                    116: #ifdef FIXUP_PC_AFTER_BREAK
                    117:        if (*is_breakpoint) {
                    118:            /*
                    119:             * Breakpoint trap.  Fix up the PC if the
                    120:             * machine requires it.
                    121:             */
                    122:            FIXUP_PC_AFTER_BREAK
                    123:            pc = PC_REGS(DDB_REGS);
                    124:        }
                    125: #endif
                    126: 
                    127:        /*
                    128:         * Now check for a breakpoint at this address.
                    129:         */
                    130:        bkpt = db_find_thread_breakpoint_here(space, pc);
                    131:        if (bkpt) {
                    132:            if (db_cond_check(bkpt)) {
                    133:                *is_breakpoint = TRUE;
                    134:                return (TRUE);  /* stop here */
                    135:            }
                    136:        }
                    137:        *is_breakpoint = FALSE;
                    138: 
                    139:        if (db_run_mode == STEP_INVISIBLE) {
                    140:            db_run_mode = STEP_CONTINUE;
                    141:            return (FALSE);     /* continue */
                    142:        }
                    143:        if (db_run_mode == STEP_COUNT) {
                    144:            return (FALSE); /* continue */
                    145:        }
                    146:        if (db_run_mode == STEP_ONCE) {
                    147:            if (--db_loop_count > 0) {
                    148:                if (db_sstep_print) {
                    149:                    db_print_loc_and_inst(pc, task);
                    150:                }
                    151:                return (FALSE); /* continue */
                    152:            }
                    153:        }
                    154:        if (db_run_mode == STEP_RETURN) {
                    155:            jmp_buf_t *prev;
                    156:            jmp_buf_t db_jmpbuf;
                    157:            /* WARNING: the following assumes an instruction fits an int */
                    158:            db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, space);
                    159: 
                    160:            /* continue until matching return */
                    161: 
                    162:            prev = db_recover;
                    163:            if (_setjmp(db_recover = &db_jmpbuf) == 0) {
                    164:                if (!inst_trap_return(ins) &&
                    165:                    (!inst_return(ins) || --db_call_depth != 0)) {
                    166:                        if (db_sstep_print) {
                    167:                            if (inst_call(ins) || inst_return(ins)) {
                    168:                                register int i;
                    169: 
                    170:                                db_printf("[after %6d /%4d] ",
                    171:                                          db_inst_count,
                    172:                                          db_inst_count - db_last_inst_count);
                    173:                                db_last_inst_count = db_inst_count;
                    174:                                for (i = db_call_depth; --i > 0; )
                    175:                                    db_printf("  ");
                    176:                                db_print_loc_and_inst(pc, task);
                    177:                                db_printf("\n");
                    178:                            }
                    179:                        }
                    180:                        if (inst_call(ins))
                    181:                            db_call_depth++;
                    182:                        db_recover = prev;
                    183:                        if (db_step_again())
                    184:                                return (FALSE); /* continue */
                    185:                }
                    186:            }
                    187:            db_recover = prev;
                    188:        }
                    189:        if (db_run_mode == STEP_CALLT) {
                    190:            /* WARNING: the following assumes an instruction fits an int */
                    191:            db_expr_t ins = db_get_task_value(pc, sizeof(int), FALSE, space);
                    192: 
                    193:            /* continue until call or return */
                    194: 
                    195:            if (!inst_call(ins) &&
                    196:                !inst_return(ins) &&
                    197:                !inst_trap_return(ins)) {
                    198:                        if (db_step_again())
                    199:                                return (FALSE); /* continue */
                    200:            }
                    201:        }
                    202:        if (db_find_breakpoint_here(space, pc))
                    203:                return(FALSE);
                    204:        db_run_mode = STEP_NONE;
                    205:        return (TRUE);
                    206: }
                    207: 
                    208: void
                    209: db_restart_at_pc(
                    210:        boolean_t       watchpt,
                    211:        task_t          task)
                    212: {
                    213:        register db_addr_t pc = PC_REGS(DDB_REGS), brpc;
                    214: 
                    215:        if ((db_run_mode == STEP_COUNT) ||
                    216:            (db_run_mode == STEP_RETURN) ||
                    217:            (db_run_mode == STEP_CALLT)) {
                    218:            db_expr_t           ins;
                    219: 
                    220:            /*
                    221:             * We are about to execute this instruction,
                    222:             * so count it now.
                    223:             */
                    224: 
                    225:            ins = db_get_task_value(pc, sizeof(int), FALSE, task);
                    226:            db_inst_count++;
                    227:            db_load_count += db_inst_load(ins);
                    228:            db_store_count += db_inst_store(ins);
                    229: #ifdef SOFTWARE_SSTEP
                    230:            /* Account for instructions in delay slots */
                    231:            brpc = next_instr_address(pc,1,task);
                    232:            if ((brpc != pc) && (inst_branch(ins) || inst_call(ins))) {
                    233:                /* Note: this ~assumes an instruction <= sizeof(int) */
                    234:                ins = db_get_task_value(brpc, sizeof(int), FALSE, task);
                    235:                db_inst_count++;
                    236:                db_load_count += db_inst_load(ins);
                    237:                db_store_count += db_inst_store(ins);
                    238:            }
                    239: #endif /* SOFTWARE_SSTEP */
                    240:        }
                    241: 
                    242:        if (db_run_mode == STEP_CONTINUE) {
                    243:            if (watchpt || db_find_breakpoint_here(task, pc)) {
                    244:                /*
                    245:                 * Step over breakpoint/watchpoint.
                    246:                 */
                    247:                db_run_mode = STEP_INVISIBLE;
                    248:                db_set_task_single_step(DDB_REGS, task);
                    249:            } else {
                    250:                db_set_breakpoints();
                    251:                db_set_watchpoints();
                    252:            }
                    253:        } else {
                    254:            db_set_task_single_step(DDB_REGS, task);
                    255:        }
                    256: }
                    257: 
                    258: /*
                    259:  * 'n' and 'u' commands might never return.
                    260:  * Limit the maximum number of steps.
                    261:  */
                    262: 
                    263: boolean_t
                    264: db_step_again(void)
                    265: {
                    266:        if (db_inst_count && !(db_inst_count%db_max_inst_count)) {
                    267:                char c;
                    268:                db_printf("%d instructions, continue ? (y/n) ",
                    269:                          db_inst_count);
                    270:                c = cngetc();
                    271:                db_printf("\n");
                    272:                if(c == 'n')
                    273:                        return(FALSE);
                    274:        }
                    275:        return(TRUE);
                    276: }
                    277: 
                    278: void
                    279: db_single_step(
                    280:        db_regs_t       *regs,
                    281:        task_t          task)
                    282: {
                    283:        if (db_run_mode == STEP_CONTINUE) {
                    284:            db_run_mode = STEP_INVISIBLE;
                    285:            db_set_task_single_step(regs, task);
                    286:        }
                    287: }
                    288: 
                    289: #ifdef SOFTWARE_SSTEP
                    290: /*
                    291:  *     Software implementation of single-stepping.
                    292:  *     If your machine does not have a trace mode
                    293:  *     similar to the vax or sun ones you can use
                    294:  *     this implementation, done for the mips.
                    295:  *     Just define the above conditional and provide
                    296:  *     the functions/macros defined below.
                    297:  *
                    298:  * extern boolean_t
                    299:  *     inst_branch(),          returns true if the instruction might branch
                    300:  * extern unsigned
                    301:  *     branch_taken(),         return the address the instruction might
                    302:  *                             branch to
                    303:  *     db_getreg_val();        return the value of a user register,
                    304:  *                             as indicated in the hardware instruction
                    305:  *                             encoding, e.g. 8 for r8
                    306:  *                     
                    307:  * next_instr_address(pc,bd,task) returns the address of the first
                    308:  *                             instruction following the one at "pc",
                    309:  *                             which is either in the taken path of
                    310:  *                             the branch (bd==1) or not.  This is
                    311:  *                             for machines (mips) with branch delays.
                    312:  *
                    313:  *     A single-step may involve at most 2 breakpoints -
                    314:  *     one for branch-not-taken and one for branch taken.
                    315:  *     If one of these addresses does not already have a breakpoint,
                    316:  *     we allocate a breakpoint and save it here.
                    317:  *     These breakpoints are deleted on return.
                    318:  */                    
                    319: db_breakpoint_t        db_not_taken_bkpt = 0;
                    320: db_breakpoint_t        db_taken_bkpt = 0;
                    321: 
                    322: db_breakpoint_t
                    323: db_find_temp_breakpoint(
                    324:        task_t             task,
                    325:        db_addr_t          addr)
                    326: {
                    327:        if (db_taken_bkpt && (db_taken_bkpt->address == addr) &&
                    328:            db_taken_bkpt->task == task)
                    329:                return db_taken_bkpt;
                    330:        if (db_not_taken_bkpt && (db_not_taken_bkpt->address == addr) &&
                    331:            db_not_taken_bkpt->task == task)
                    332:                return db_not_taken_bkpt;
                    333:        return 0;
                    334: }
                    335: 
                    336: void
                    337: db_set_task_single_step(
                    338:        register db_regs_t      *regs,
                    339:        task_t                  task)
                    340: {
                    341:        db_addr_t pc = PC_REGS(regs), brpc;
                    342:        register unsigned int    inst;
                    343:        register boolean_t       unconditional;
                    344: 
                    345:        /*
                    346:         *      User was stopped at pc, e.g. the instruction
                    347:         *      at pc was not executed.
                    348:         */
                    349:        inst = db_get_task_value(pc, sizeof(int), FALSE, task);
                    350:        if (inst_branch(inst) || inst_call(inst)) {
                    351:            extern db_expr_t getreg_val();      /* XXX -- need prototype! */
                    352: 
                    353:            brpc = branch_taken(inst, pc, getreg_val, (unsigned char*)regs);
                    354:            if (brpc != pc) {   /* self-branches are hopeless */
                    355:                db_taken_bkpt = db_set_temp_breakpoint(task, brpc);
                    356:            } else
                    357:                db_taken_bkpt = 0;
                    358:            pc = next_instr_address(pc,1,task);
                    359:        } else 
                    360:            pc = next_instr_address(pc,0,task);
                    361:        
                    362:        /* 
                    363:         * check if this control flow instruction is an
                    364:         * unconditional transfer
                    365:         */
                    366: 
                    367:        unconditional = inst_unconditional_flow_transfer(inst);
                    368: 
                    369:        /* 
                    370:          We only set the sequential breakpoint if previous instruction was not
                    371:          an unconditional change of flow of control. If the previous instruction
                    372:          is an unconditional change of flow of control, setting a breakpoint in the
                    373:          next sequential location may set a breakpoint in data or in another routine,
                    374:          which could screw up either the program or the debugger. 
                    375:          (Consider, for instance, that the next sequential instruction is the 
                    376:          start of a routine needed by the debugger.)
                    377:        */
                    378:        if (!unconditional && db_find_breakpoint_here(task, pc) == 0 &&
                    379:            (db_taken_bkpt == 0 || db_taken_bkpt->address != pc)) {
                    380:                db_not_taken_bkpt = db_set_temp_breakpoint(task, pc);
                    381:        } else
                    382:                db_not_taken_bkpt = 0;
                    383: }
                    384: 
                    385: void
                    386: db_clear_task_single_step(
                    387:        db_regs_t       *regs,
                    388:        task_t          task)
                    389: {
                    390:        if (db_taken_bkpt != 0) {
                    391:            db_delete_temp_breakpoint(task, db_taken_bkpt);
                    392:            db_taken_bkpt = 0;
                    393:        }
                    394:        if (db_not_taken_bkpt != 0) {
                    395:            db_delete_temp_breakpoint(task, db_not_taken_bkpt);
                    396:            db_not_taken_bkpt = 0;
                    397:        }
                    398: }
                    399: 
                    400: #endif /* SOFTWARE_SSTEP */
                    401: 
                    402: extern int     db_cmd_loop_done;
                    403: 
                    404: /* single-step */
                    405: void
                    406: db_single_step_cmd(
                    407:        db_expr_t       addr,
                    408:        int             have_addr,
                    409:        db_expr_t       count,
                    410:        char *          modif)
                    411: {
                    412:        boolean_t       print = FALSE;
                    413: 
                    414:        if (count == -1)
                    415:            count = 1;
                    416: 
                    417:        if (modif[0] == 'p')
                    418:            print = TRUE;
                    419: 
                    420:        db_run_mode = STEP_ONCE;
                    421:        db_loop_count = count;
                    422:        db_sstep_print = print;
                    423:        db_inst_count = 0;
                    424:        db_last_inst_count = 0;
                    425:        db_load_count = 0;
                    426:        db_store_count = 0;
                    427: 
                    428:        db_cmd_loop_done = 1;
                    429: }
                    430: 
                    431: /* trace and print until call/return */
                    432: void
                    433: db_trace_until_call_cmd(
                    434:        db_expr_t       addr,
                    435:        int             have_addr,
                    436:        db_expr_t       count,
                    437:        char *          modif)
                    438: {
                    439:        boolean_t       print = FALSE;
                    440: 
                    441:        if (modif[0] == 'p')
                    442:            print = TRUE;
                    443: 
                    444:        db_run_mode = STEP_CALLT;
                    445:        db_sstep_print = print;
                    446:        db_inst_count = 0;
                    447:        db_last_inst_count = 0;
                    448:        db_load_count = 0;
                    449:        db_store_count = 0;
                    450: 
                    451:        db_cmd_loop_done = 1;
                    452: }
                    453: 
                    454: void
                    455: db_trace_until_matching_cmd(
                    456:        db_expr_t       addr,
                    457:        int             have_addr,
                    458:        db_expr_t       count,
                    459:        char *          modif)
                    460: {
                    461:        boolean_t       print = FALSE;
                    462: 
                    463:        if (modif[0] == 'p')
                    464:            print = TRUE;
                    465: 
                    466:        db_run_mode = STEP_RETURN;
                    467:        db_call_depth = 1;
                    468:        db_sstep_print = print;
                    469:        db_inst_count = 0;
                    470:        db_last_inst_count = 0;
                    471:        db_load_count = 0;
                    472:        db_store_count = 0;
                    473: 
                    474:        db_cmd_loop_done = 1;
                    475: }
                    476: 
                    477: /* continue */
                    478: void
                    479: db_continue_cmd(
                    480:        db_expr_t       addr,
                    481:        int             have_addr,
                    482:        db_expr_t       count,
                    483:        char *          modif)
                    484: {
                    485:        /*
                    486:         * Though "cont/c" works fairly well, it's not really robust
                    487:         * enough to use in arbitrary situations, so disable it.
                    488:         * (Doesn't seem cost-effective to debug and fix what ails
                    489:         * it.)
                    490:         */
                    491: #if 0
                    492:        if (modif[0] == 'c')
                    493:            db_run_mode = STEP_COUNT;
                    494:        else
                    495:            db_run_mode = STEP_CONTINUE;
                    496: #else
                    497:        db_run_mode = STEP_CONTINUE;
                    498: #endif
                    499:        db_inst_count = 0;
                    500:        db_last_inst_count = 0;
                    501:        db_load_count = 0;
                    502:        db_store_count = 0;
                    503: 
                    504:        db_cmd_loop_done = 1;
                    505: }
                    506: 
                    507: /* gdb */
                    508: void    
                    509: db_continue_gdb(
                    510:        db_expr_t       addr, 
                    511:        int             have_addr,
                    512:        db_expr_t       count,   
                    513:        char *          modif)
                    514: {
                    515: #if defined(__ppc__)
                    516:        db_to_gdb();
                    517: #endif
                    518:        db_run_mode = STEP_CONTINUE;
                    519:        db_inst_count = 0;
                    520:        db_last_inst_count = 0;   
                    521:        db_load_count = 0;
                    522:        db_store_count = 0;  
                    523: 
                    524:        db_cmd_loop_done = 1;
                    525: }
                    526:         
                    527: 
                    528: 
                    529: boolean_t
                    530: db_in_single_step(void)
                    531: {
                    532:        return(db_run_mode != STEP_NONE && db_run_mode != STEP_CONTINUE);
                    533: }

unix.superglobalmegacorp.com

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