db_run.c revision 308418
11541Srgrimes/*-
21541Srgrimes * Mach Operating System
31541Srgrimes * Copyright (c) 1991,1990 Carnegie Mellon University
41541Srgrimes * All Rights Reserved.
51541Srgrimes *
61541Srgrimes * Permission to use, copy, modify and distribute this software and its
71541Srgrimes * documentation is hereby granted, provided that both the copyright
81541Srgrimes * notice and this permission notice appear in all copies of the
91541Srgrimes * software, derivative works or modified versions, and any portions
101541Srgrimes * thereof, and that both notices appear in supporting documentation.
111541Srgrimes *
121541Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
131541Srgrimes * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
141541Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
151541Srgrimes *
161541Srgrimes * Carnegie Mellon requests users of this software to return to
171541Srgrimes *
181541Srgrimes *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
191541Srgrimes *  School of Computer Science
201541Srgrimes *  Carnegie Mellon University
211541Srgrimes *  Pittsburgh PA 15213-3890
221541Srgrimes *
231541Srgrimes * any improvements or extensions that they make and grant Carnegie the
241541Srgrimes * rights to redistribute these changes.
251541Srgrimes */
261541Srgrimes/*
271541Srgrimes * 	Author: David B. Golub, Carnegie Mellon University
281541Srgrimes *	Date:	7/90
291541Srgrimes */
301541Srgrimes
311541Srgrimes/*
321541Srgrimes * Commands to run process.
331541Srgrimes */
341541Srgrimes
351541Srgrimes#include <sys/cdefs.h>
361541Srgrimes__FBSDID("$FreeBSD: stable/11/sys/ddb/db_run.c 308418 2016-11-07 12:10:17Z kib $");
371541Srgrimes
381541Srgrimes#include <sys/param.h>
3912577Sbde#include <sys/kdb.h>
401541Srgrimes#include <sys/proc.h>
411541Srgrimes
421541Srgrimes#include <machine/kdb.h>
431541Srgrimes#include <machine/pcb.h>
442112Swollman
452946Swollman#include <vm/vm.h>
461541Srgrimes
471541Srgrimes#include <ddb/ddb.h>
481541Srgrimes#include <ddb/db_break.h>
491541Srgrimes#include <ddb/db_access.h>
501541Srgrimes
511541Srgrimes#define	STEP_ONCE	1
521541Srgrimes#define	STEP_RETURN	2
531541Srgrimes#define	STEP_CALLT	3
541541Srgrimes#define	STEP_CONTINUE	4
552946Swollman#define	STEP_INVISIBLE	5
562946Swollman#define	STEP_COUNT	6
572946Swollmanstatic int	db_run_mode = STEP_CONTINUE;
581541Srgrimes
5912577Sbdestatic bool		db_sstep_multiple;
6012577Sbdestatic bool		db_sstep_print;
6110653Sdgstatic int		db_loop_count;
6210358Sjulianstatic int		db_call_depth;
6310358Sjulian
6412569Sbdeint		db_inst_count;
6512569Sbdeint		db_load_count;
6610358Sjulianint		db_store_count;
671541Srgrimes
681541Srgrimes#ifdef SOFTWARE_SSTEP
691541Srgrimesdb_breakpoint_t	db_not_taken_bkpt = 0;
701541Srgrimesdb_breakpoint_t	db_taken_bkpt = 0;
711541Srgrimes#endif
721541Srgrimes
731541Srgrimes#ifndef db_set_single_step
741541Srgrimesvoid db_set_single_step(void);
752946Swollman#endif
762946Swollman#ifndef db_clear_single_step
772946Swollmanvoid db_clear_single_step(void);
782946Swollman#endif
792946Swollman#ifndef db_pc_is_singlestep
802946Swollmanstatic bool
812946Swollmandb_pc_is_singlestep(db_addr_t pc)
822946Swollman{
832946Swollman#ifdef SOFTWARE_SSTEP
841541Srgrimes	if ((db_not_taken_bkpt != 0 && pc == db_not_taken_bkpt->address)
851541Srgrimes	    || (db_taken_bkpt != 0 && pc == db_taken_bkpt->address))
861541Srgrimes		return (true);
871541Srgrimes#endif
881541Srgrimes	return (false);
891541Srgrimes}
901541Srgrimes#endif
911541Srgrimes
921541Srgrimesbool
931541Srgrimesdb_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
941541Srgrimes{
951541Srgrimes	db_addr_t	pc;
961541Srgrimes	db_breakpoint_t bkpt;
971541Srgrimes
981541Srgrimes	*is_breakpoint = IS_BREAKPOINT_TRAP(type, code);
991541Srgrimes	*is_watchpoint = IS_WATCHPOINT_TRAP(type, code);
1001541Srgrimes	pc = PC_REGS();
1011541Srgrimes	if (db_pc_is_singlestep(pc))
1021541Srgrimes		*is_breakpoint = false;
1031541Srgrimes
1041541Srgrimes	db_clear_single_step();
1051541Srgrimes	db_clear_breakpoints();
1061541Srgrimes	db_clear_watchpoints();
1071541Srgrimes
1081541Srgrimes#ifdef	FIXUP_PC_AFTER_BREAK
1091541Srgrimes	if (*is_breakpoint) {
1101541Srgrimes	    /*
1111541Srgrimes	     * Breakpoint trap.  Fix up the PC if the
1121541Srgrimes	     * machine requires it.
1131541Srgrimes	     */
1141541Srgrimes	    FIXUP_PC_AFTER_BREAK
1151541Srgrimes	    pc = PC_REGS();
1161541Srgrimes	}
1171541Srgrimes#endif
1181541Srgrimes
1191541Srgrimes	/*
1201541Srgrimes	 * Now check for a breakpoint at this address.
1211541Srgrimes	 */
1222946Swollman	bkpt = db_find_breakpoint_here(pc);
1231541Srgrimes	if (bkpt) {
1241541Srgrimes	    if (--bkpt->count == 0) {
12512158Sbde		bkpt->count = bkpt->init_count;
12612158Sbde		*is_breakpoint = true;
1271541Srgrimes		return (true);	/* stop here */
1281541Srgrimes	    }
1291541Srgrimes	    return (false);	/* continue the countdown */
1301541Srgrimes	} else if (*is_breakpoint) {
1311541Srgrimes#ifdef BKPT_SKIP
1322946Swollman		BKPT_SKIP;
1332946Swollman#endif
1341541Srgrimes	}
1351541Srgrimes
1361541Srgrimes	*is_breakpoint = false;	/* might be a breakpoint, but not ours */
1371541Srgrimes
1381541Srgrimes	/*
1391541Srgrimes	 * If not stepping, then silently ignore single-step traps
14012158Sbde	 * (except for clearing the single-step-flag above).
14112158Sbde	 *
14212158Sbde	 * If stepping, then abort if the trap type is unexpected.
14312158Sbde	 * Breakpoints owned by us are expected and were handled above.
14412158Sbde	 * Single-steps are expected and are handled below.  All others
1451541Srgrimes	 * are unexpected.
1461541Srgrimes	 *
1471541Srgrimes	 * Only do either of these if the MD layer claims to classify
1481541Srgrimes	 * single-step traps unambiguously (by defining IS_SSTEP_TRAP).
1492946Swollman	 * Otherwise, fall through to the bad historical behaviour
1502946Swollman	 * given by turning unexpected traps into expected traps: if not
1511541Srgrimes	 * stepping, then expect only breakpoints and stop, and if
1521541Srgrimes	 * stepping, then expect only single-steps and step.
1531541Srgrimes	 */
1541541Srgrimes#ifdef IS_SSTEP_TRAP
1551541Srgrimes	if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code))
1561541Srgrimes	    return (false);
1571541Srgrimes	if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) {
1581541Srgrimes	    printf("Stepping aborted\n");
1591541Srgrimes	    return (true);
1601541Srgrimes	}
1611541Srgrimes#endif
1621541Srgrimes
1631541Srgrimes	if (db_run_mode == STEP_INVISIBLE) {
1641541Srgrimes	    db_run_mode = STEP_CONTINUE;
1651541Srgrimes	    return (false);	/* continue */
1661541Srgrimes	}
1671541Srgrimes	if (db_run_mode == STEP_COUNT) {
1681541Srgrimes	    return (false); /* continue */
1691541Srgrimes	}
1701541Srgrimes	if (db_run_mode == STEP_ONCE) {
1711541Srgrimes	    if (--db_loop_count > 0) {
1721541Srgrimes		if (db_sstep_print) {
1731541Srgrimes		    db_printf("\t\t");
1741541Srgrimes		    db_print_loc_and_inst(pc);
1751541Srgrimes		    db_printf("\n");
1761541Srgrimes		}
1771541Srgrimes		return (false);	/* continue */
1781541Srgrimes	    }
1791541Srgrimes	}
1801541Srgrimes	if (db_run_mode == STEP_RETURN) {
1811541Srgrimes	    /* continue until matching return */
1821541Srgrimes	    db_expr_t ins;
1831541Srgrimes
1841541Srgrimes	    ins = db_get_value(pc, sizeof(int), false);
1851541Srgrimes	    if (!inst_trap_return(ins) &&
1861541Srgrimes		(!inst_return(ins) || --db_call_depth != 0)) {
1871541Srgrimes		if (db_sstep_print) {
1881541Srgrimes		    if (inst_call(ins) || inst_return(ins)) {
1892946Swollman			int i;
1902946Swollman
1911541Srgrimes			db_printf("[after %6d]     ", db_inst_count);
1921541Srgrimes			for (i = db_call_depth; --i > 0; )
1931541Srgrimes			    db_printf("  ");
1941541Srgrimes			db_print_loc_and_inst(pc);
1951541Srgrimes			db_printf("\n");
1961541Srgrimes		    }
1971541Srgrimes		}
1981541Srgrimes		if (inst_call(ins))
1998876Srgrimes		    db_call_depth++;
2001541Srgrimes		return (false);	/* continue */
2011541Srgrimes	    }
2021541Srgrimes	}
2031541Srgrimes	if (db_run_mode == STEP_CALLT) {
2041541Srgrimes	    /* continue until call or return */
2051541Srgrimes	    db_expr_t ins;
2061541Srgrimes
2071541Srgrimes	    ins = db_get_value(pc, sizeof(int), false);
2081541Srgrimes	    if (!inst_call(ins) &&
2091541Srgrimes		!inst_return(ins) &&
2101541Srgrimes		!inst_trap_return(ins)) {
2111541Srgrimes		return (false);	/* continue */
2121541Srgrimes	    }
2131541Srgrimes	}
2141541Srgrimes	return (true);
2151541Srgrimes}
2161541Srgrimes
2171541Srgrimesvoid
2181541Srgrimesdb_restart_at_pc(bool watchpt)
2191541Srgrimes{
2201541Srgrimes	db_addr_t	pc = PC_REGS();
2211541Srgrimes
2221541Srgrimes	if ((db_run_mode == STEP_COUNT) ||
2231541Srgrimes	    ((db_run_mode == STEP_ONCE) && db_sstep_multiple) ||
2241541Srgrimes	    (db_run_mode == STEP_RETURN) ||
2251541Srgrimes	    (db_run_mode == STEP_CALLT)) {
2261541Srgrimes	    /*
2271541Srgrimes	     * We are about to execute this instruction,
2281541Srgrimes	     * so count it now.
2291541Srgrimes	     */
2301541Srgrimes#ifdef	SOFTWARE_SSTEP
2311541Srgrimes	    db_expr_t		ins =
2321541Srgrimes#endif
2331541Srgrimes	    db_get_value(pc, sizeof(int), false);
2341541Srgrimes	    db_inst_count++;
2351541Srgrimes	    db_load_count += inst_load(ins);
2361541Srgrimes	    db_store_count += inst_store(ins);
2371541Srgrimes#ifdef	SOFTWARE_SSTEP
2381541Srgrimes	    /* XXX works on mips, but... */
23910358Sjulian	    if (inst_branch(ins) || inst_call(ins)) {
24010358Sjulian		ins = db_get_value(next_instr_address(pc,1),
24112569Sbde				   sizeof(int), false);
24212569Sbde		db_inst_count++;
2431541Srgrimes		db_load_count += inst_load(ins);
2441541Srgrimes		db_store_count += inst_store(ins);
2452946Swollman	    }
2462946Swollman#endif	/* SOFTWARE_SSTEP */
2471541Srgrimes	}
2481541Srgrimes
2492946Swollman	if (db_run_mode == STEP_CONTINUE) {
2502946Swollman	    if (watchpt || db_find_breakpoint_here(pc)) {
2512946Swollman		/*
2522946Swollman		 * Step over breakpoint/watchpoint.
2532946Swollman		 */
2542946Swollman		db_run_mode = STEP_INVISIBLE;
2552946Swollman		db_set_single_step();
2562946Swollman	    } else {
2572946Swollman		db_set_breakpoints();
2582946Swollman		db_set_watchpoints();
2592946Swollman	    }
2602946Swollman	} else {
2618876Srgrimes	    db_set_single_step();
2622946Swollman	}
2631541Srgrimes}
2641541Srgrimes
2651541Srgrimes#ifdef	SOFTWARE_SSTEP
2661541Srgrimes/*
2671541Srgrimes *	Software implementation of single-stepping.
2681541Srgrimes *	If your machine does not have a trace mode
2691541Srgrimes *	similar to the vax or sun ones you can use
2701541Srgrimes *	this implementation, done for the mips.
2711541Srgrimes *	Just define the above conditional and provide
2721541Srgrimes *	the functions/macros defined below.
2731541Srgrimes *
2742946Swollman * extern bool
2751541Srgrimes *	inst_branch(),		returns true if the instruction might branch
2761541Srgrimes * extern unsigned
2771541Srgrimes *	branch_taken(),		return the address the instruction might
2781541Srgrimes *				branch to
2791541Srgrimes *	db_getreg_val();	return the value of a user register,
2801541Srgrimes *				as indicated in the hardware instruction
2811541Srgrimes *				encoding, e.g. 8 for r8
2821541Srgrimes *
2831541Srgrimes * next_instr_address(pc,bd)	returns the address of the first
2841541Srgrimes *				instruction following the one at "pc",
2852946Swollman *				which is either in the taken path of
2862946Swollman *				the branch (bd==1) or not.  This is
2872946Swollman *				for machines (mips) with branch delays.
2882946Swollman *
28912429Sphk *	A single-step may involve at most 2 breakpoints -
29012429Sphk *	one for branch-not-taken and one for branch taken.
29112429Sphk *	If one of these addresses does not already have a breakpoint,
2922946Swollman *	we allocate a breakpoint and save it here.
29312429Sphk *	These breakpoints are deleted on return.
2942946Swollman */
29512429Sphk
29612429Sphkvoid
29712429Sphkdb_set_single_step(void)
29812429Sphk{
29912429Sphk	db_addr_t pc = PC_REGS(), brpc;
30012429Sphk	unsigned inst;
30112429Sphk
30212429Sphk	/*
3032946Swollman	 *	User was stopped at pc, e.g. the instruction
30412429Sphk	 *	at pc was not executed.
3052946Swollman	 */
30612429Sphk	inst = db_get_value(pc, sizeof(int), false);
30712429Sphk	if (inst_branch(inst) || inst_call(inst) || inst_return(inst)) {
3082946Swollman		brpc = branch_taken(inst, pc);
3092997Swollman		if (brpc != pc) {	/* self-branches are hopeless */
3102997Swollman			db_taken_bkpt = db_set_temp_breakpoint(brpc);
3112997Swollman		}
3122997Swollman		pc = next_instr_address(pc, 1);
3132997Swollman	}
3142997Swollman	pc = next_instr_address(pc, 0);
3152997Swollman	db_not_taken_bkpt = db_set_temp_breakpoint(pc);
3162997Swollman}
317
318void
319db_clear_single_step(void)
320{
321
322	if (db_not_taken_bkpt != 0) {
323		db_delete_temp_breakpoint(db_not_taken_bkpt);
324		db_not_taken_bkpt = 0;
325	}
326	if (db_taken_bkpt != 0) {
327		db_delete_temp_breakpoint(db_taken_bkpt);
328		db_taken_bkpt = 0;
329	}
330}
331
332#endif	/* SOFTWARE_SSTEP */
333
334extern int	db_cmd_loop_done;
335
336/* single-step */
337/*ARGSUSED*/
338void
339db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
340{
341	bool		print = false;
342
343	if (count == -1)
344	    count = 1;
345
346	if (modif[0] == 'p')
347	    print = true;
348
349	db_run_mode = STEP_ONCE;
350	db_loop_count = count;
351	db_sstep_multiple = (count != 1);
352	db_sstep_print = print;
353	db_inst_count = 0;
354	db_load_count = 0;
355	db_store_count = 0;
356
357	db_cmd_loop_done = 1;
358}
359
360/* trace and print until call/return */
361/*ARGSUSED*/
362void
363db_trace_until_call_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
364    char *modif)
365{
366	bool	print = false;
367
368	if (modif[0] == 'p')
369	    print = true;
370
371	db_run_mode = STEP_CALLT;
372	db_sstep_print = print;
373	db_inst_count = 0;
374	db_load_count = 0;
375	db_store_count = 0;
376
377	db_cmd_loop_done = 1;
378}
379
380/*ARGSUSED*/
381void
382db_trace_until_matching_cmd(db_expr_t addr, bool have_addr, db_expr_t count,
383    char *modif)
384{
385	bool	print = false;
386
387	if (modif[0] == 'p')
388	    print = true;
389
390	db_run_mode = STEP_RETURN;
391	db_call_depth = 1;
392	db_sstep_print = print;
393	db_inst_count = 0;
394	db_load_count = 0;
395	db_store_count = 0;
396
397	db_cmd_loop_done = 1;
398}
399
400/* continue */
401/*ARGSUSED*/
402void
403db_continue_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif)
404{
405	if (modif[0] == 'c')
406	    db_run_mode = STEP_COUNT;
407	else
408	    db_run_mode = STEP_CONTINUE;
409	db_inst_count = 0;
410	db_load_count = 0;
411	db_store_count = 0;
412
413	db_cmd_loop_done = 1;
414}
415