Annotation of XNU/osfmk/ddb/db_run.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:  * 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.