xref: /openbmc/linux/kernel/debug/kdb/kdb_bp.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
15d5314d6SJason Wessel /*
25d5314d6SJason Wessel  * Kernel Debugger Architecture Independent Breakpoint Handler
35d5314d6SJason Wessel  *
45d5314d6SJason Wessel  * This file is subject to the terms and conditions of the GNU General Public
55d5314d6SJason Wessel  * License.  See the file "COPYING" in the main directory of this archive
65d5314d6SJason Wessel  * for more details.
75d5314d6SJason Wessel  *
85d5314d6SJason Wessel  * Copyright (c) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved.
95d5314d6SJason Wessel  * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
105d5314d6SJason Wessel  */
115d5314d6SJason Wessel 
125d5314d6SJason Wessel #include <linux/string.h>
135d5314d6SJason Wessel #include <linux/kernel.h>
145d5314d6SJason Wessel #include <linux/init.h>
155d5314d6SJason Wessel #include <linux/kdb.h>
165d5314d6SJason Wessel #include <linux/kgdb.h>
175d5314d6SJason Wessel #include <linux/smp.h>
185d5314d6SJason Wessel #include <linux/sched.h>
195d5314d6SJason Wessel #include <linux/interrupt.h>
205d5314d6SJason Wessel #include "kdb_private.h"
215d5314d6SJason Wessel 
225d5314d6SJason Wessel /*
235d5314d6SJason Wessel  * Table of kdb_breakpoints
245d5314d6SJason Wessel  */
255d5314d6SJason Wessel kdb_bp_t kdb_breakpoints[KDB_MAXBPT];
265d5314d6SJason Wessel 
kdb_setsinglestep(struct pt_regs * regs)275d5314d6SJason Wessel static void kdb_setsinglestep(struct pt_regs *regs)
285d5314d6SJason Wessel {
295d5314d6SJason Wessel 	KDB_STATE_SET(DOING_SS);
305d5314d6SJason Wessel }
315d5314d6SJason Wessel 
325d5314d6SJason Wessel static char *kdb_rwtypes[] = {
335d5314d6SJason Wessel 	"Instruction(i)",
345d5314d6SJason Wessel 	"Instruction(Register)",
355d5314d6SJason Wessel 	"Data Write",
365d5314d6SJason Wessel 	"I/O",
375d5314d6SJason Wessel 	"Data Access"
385d5314d6SJason Wessel };
395d5314d6SJason Wessel 
kdb_bptype(kdb_bp_t * bp)405d5314d6SJason Wessel static char *kdb_bptype(kdb_bp_t *bp)
415d5314d6SJason Wessel {
425d5314d6SJason Wessel 	if (bp->bp_type < 0 || bp->bp_type > 4)
435d5314d6SJason Wessel 		return "";
445d5314d6SJason Wessel 
455d5314d6SJason Wessel 	return kdb_rwtypes[bp->bp_type];
465d5314d6SJason Wessel }
475d5314d6SJason Wessel 
kdb_parsebp(int argc,const char ** argv,int * nextargp,kdb_bp_t * bp)485d5314d6SJason Wessel static int kdb_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp)
495d5314d6SJason Wessel {
505d5314d6SJason Wessel 	int nextarg = *nextargp;
515d5314d6SJason Wessel 	int diag;
525d5314d6SJason Wessel 
535d5314d6SJason Wessel 	bp->bph_length = 1;
545d5314d6SJason Wessel 	if ((argc + 1) != nextarg) {
55f9f2bac2SRasmus Villemoes 		if (strncasecmp(argv[nextarg], "datar", sizeof("datar")) == 0)
565d5314d6SJason Wessel 			bp->bp_type = BP_ACCESS_WATCHPOINT;
57f9f2bac2SRasmus Villemoes 		else if (strncasecmp(argv[nextarg], "dataw", sizeof("dataw")) == 0)
585d5314d6SJason Wessel 			bp->bp_type = BP_WRITE_WATCHPOINT;
59f9f2bac2SRasmus Villemoes 		else if (strncasecmp(argv[nextarg], "inst", sizeof("inst")) == 0)
605d5314d6SJason Wessel 			bp->bp_type = BP_HARDWARE_BREAKPOINT;
615d5314d6SJason Wessel 		else
625d5314d6SJason Wessel 			return KDB_ARGCOUNT;
635d5314d6SJason Wessel 
645d5314d6SJason Wessel 		bp->bph_length = 1;
655d5314d6SJason Wessel 
665d5314d6SJason Wessel 		nextarg++;
675d5314d6SJason Wessel 
685d5314d6SJason Wessel 		if ((argc + 1) != nextarg) {
695d5314d6SJason Wessel 			unsigned long len;
705d5314d6SJason Wessel 
715d5314d6SJason Wessel 			diag = kdbgetularg((char *)argv[nextarg],
725d5314d6SJason Wessel 					   &len);
735d5314d6SJason Wessel 			if (diag)
745d5314d6SJason Wessel 				return diag;
755d5314d6SJason Wessel 
765d5314d6SJason Wessel 
775d5314d6SJason Wessel 			if (len > 8)
785d5314d6SJason Wessel 				return KDB_BADLENGTH;
795d5314d6SJason Wessel 
805d5314d6SJason Wessel 			bp->bph_length = len;
815d5314d6SJason Wessel 			nextarg++;
825d5314d6SJason Wessel 		}
835d5314d6SJason Wessel 
845d5314d6SJason Wessel 		if ((argc + 1) != nextarg)
855d5314d6SJason Wessel 			return KDB_ARGCOUNT;
865d5314d6SJason Wessel 	}
875d5314d6SJason Wessel 
885d5314d6SJason Wessel 	*nextargp = nextarg;
895d5314d6SJason Wessel 	return 0;
905d5314d6SJason Wessel }
915d5314d6SJason Wessel 
_kdb_bp_remove(kdb_bp_t * bp)925d5314d6SJason Wessel static int _kdb_bp_remove(kdb_bp_t *bp)
935d5314d6SJason Wessel {
945d5314d6SJason Wessel 	int ret = 1;
955d5314d6SJason Wessel 	if (!bp->bp_installed)
965d5314d6SJason Wessel 		return ret;
975d5314d6SJason Wessel 	if (!bp->bp_type)
985d5314d6SJason Wessel 		ret = dbg_remove_sw_break(bp->bp_addr);
995d5314d6SJason Wessel 	else
1005d5314d6SJason Wessel 		ret = arch_kgdb_ops.remove_hw_breakpoint(bp->bp_addr,
1015d5314d6SJason Wessel 			 bp->bph_length,
1025d5314d6SJason Wessel 			 bp->bp_type);
1035d5314d6SJason Wessel 	if (ret == 0)
1045d5314d6SJason Wessel 		bp->bp_installed = 0;
1055d5314d6SJason Wessel 	return ret;
1065d5314d6SJason Wessel }
1075d5314d6SJason Wessel 
kdb_handle_bp(struct pt_regs * regs,kdb_bp_t * bp)1085d5314d6SJason Wessel static void kdb_handle_bp(struct pt_regs *regs, kdb_bp_t *bp)
1095d5314d6SJason Wessel {
1105d5314d6SJason Wessel 	if (KDB_DEBUG(BP))
1115d5314d6SJason Wessel 		kdb_printf("regs->ip = 0x%lx\n", instruction_pointer(regs));
1125d5314d6SJason Wessel 
1135d5314d6SJason Wessel 	/*
1145d5314d6SJason Wessel 	 * Setup single step
1155d5314d6SJason Wessel 	 */
1165d5314d6SJason Wessel 	kdb_setsinglestep(regs);
1175d5314d6SJason Wessel 
1185d5314d6SJason Wessel 	/*
1195d5314d6SJason Wessel 	 * Reset delay attribute
1205d5314d6SJason Wessel 	 */
1215d5314d6SJason Wessel 	bp->bp_delay = 0;
1225d5314d6SJason Wessel 	bp->bp_delayed = 1;
1235d5314d6SJason Wessel }
1245d5314d6SJason Wessel 
_kdb_bp_install(struct pt_regs * regs,kdb_bp_t * bp)1255d5314d6SJason Wessel static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp)
1265d5314d6SJason Wessel {
1275d5314d6SJason Wessel 	int ret;
1285d5314d6SJason Wessel 	/*
1295d5314d6SJason Wessel 	 * Install the breakpoint, if it is not already installed.
1305d5314d6SJason Wessel 	 */
1315d5314d6SJason Wessel 
1325d5314d6SJason Wessel 	if (KDB_DEBUG(BP))
1335d5314d6SJason Wessel 		kdb_printf("%s: bp_installed %d\n",
1345d5314d6SJason Wessel 			   __func__, bp->bp_installed);
1355d5314d6SJason Wessel 	if (!KDB_STATE(SSBPT))
1365d5314d6SJason Wessel 		bp->bp_delay = 0;
1375d5314d6SJason Wessel 	if (bp->bp_installed)
1385d5314d6SJason Wessel 		return 1;
1395d5314d6SJason Wessel 	if (bp->bp_delay || (bp->bp_delayed && KDB_STATE(DOING_SS))) {
1405d5314d6SJason Wessel 		if (KDB_DEBUG(BP))
1415d5314d6SJason Wessel 			kdb_printf("%s: delayed bp\n", __func__);
1425d5314d6SJason Wessel 		kdb_handle_bp(regs, bp);
1435d5314d6SJason Wessel 		return 0;
1445d5314d6SJason Wessel 	}
1455d5314d6SJason Wessel 	if (!bp->bp_type)
1465d5314d6SJason Wessel 		ret = dbg_set_sw_break(bp->bp_addr);
1475d5314d6SJason Wessel 	else
1485d5314d6SJason Wessel 		ret = arch_kgdb_ops.set_hw_breakpoint(bp->bp_addr,
1495d5314d6SJason Wessel 			 bp->bph_length,
1505d5314d6SJason Wessel 			 bp->bp_type);
1515d5314d6SJason Wessel 	if (ret == 0) {
1525d5314d6SJason Wessel 		bp->bp_installed = 1;
1535d5314d6SJason Wessel 	} else {
1545d5314d6SJason Wessel 		kdb_printf("%s: failed to set breakpoint at 0x%lx\n",
1555d5314d6SJason Wessel 			   __func__, bp->bp_addr);
1561ba0c172SJason Wessel 		if (!bp->bp_type) {
1571ba0c172SJason Wessel 			kdb_printf("Software breakpoints are unavailable.\n"
158d2aa1acaSKees Cook 				   "  Boot the kernel with rodata=off\n"
1591ba0c172SJason Wessel 				   "  OR use hw breaks: help bph\n");
1601ba0c172SJason Wessel 		}
1615d5314d6SJason Wessel 		return 1;
1625d5314d6SJason Wessel 	}
1635d5314d6SJason Wessel 	return 0;
1645d5314d6SJason Wessel }
1655d5314d6SJason Wessel 
1665d5314d6SJason Wessel /*
1675d5314d6SJason Wessel  * kdb_bp_install
1685d5314d6SJason Wessel  *
1695d5314d6SJason Wessel  *	Install kdb_breakpoints prior to returning from the
1705d5314d6SJason Wessel  *	kernel debugger.  This allows the kdb_breakpoints to be set
1715d5314d6SJason Wessel  *	upon functions that are used internally by kdb, such as
1725d5314d6SJason Wessel  *	printk().  This function is only called once per kdb session.
1735d5314d6SJason Wessel  */
kdb_bp_install(struct pt_regs * regs)1745d5314d6SJason Wessel void kdb_bp_install(struct pt_regs *regs)
1755d5314d6SJason Wessel {
1765d5314d6SJason Wessel 	int i;
1775d5314d6SJason Wessel 
1785d5314d6SJason Wessel 	for (i = 0; i < KDB_MAXBPT; i++) {
1795d5314d6SJason Wessel 		kdb_bp_t *bp = &kdb_breakpoints[i];
1805d5314d6SJason Wessel 
1815d5314d6SJason Wessel 		if (KDB_DEBUG(BP)) {
1825d5314d6SJason Wessel 			kdb_printf("%s: bp %d bp_enabled %d\n",
1835d5314d6SJason Wessel 				   __func__, i, bp->bp_enabled);
1845d5314d6SJason Wessel 		}
1855d5314d6SJason Wessel 		if (bp->bp_enabled)
1865d5314d6SJason Wessel 			_kdb_bp_install(regs, bp);
1875d5314d6SJason Wessel 	}
1885d5314d6SJason Wessel }
1895d5314d6SJason Wessel 
1905d5314d6SJason Wessel /*
1915d5314d6SJason Wessel  * kdb_bp_remove
1925d5314d6SJason Wessel  *
1935d5314d6SJason Wessel  *	Remove kdb_breakpoints upon entry to the kernel debugger.
1945d5314d6SJason Wessel  *
1955d5314d6SJason Wessel  * Parameters:
1965d5314d6SJason Wessel  *	None.
1975d5314d6SJason Wessel  * Outputs:
1985d5314d6SJason Wessel  *	None.
1995d5314d6SJason Wessel  * Returns:
2005d5314d6SJason Wessel  *	None.
2015d5314d6SJason Wessel  * Locking:
2025d5314d6SJason Wessel  *	None.
2035d5314d6SJason Wessel  * Remarks:
2045d5314d6SJason Wessel  */
kdb_bp_remove(void)2055d5314d6SJason Wessel void kdb_bp_remove(void)
2065d5314d6SJason Wessel {
2075d5314d6SJason Wessel 	int i;
2085d5314d6SJason Wessel 
2095d5314d6SJason Wessel 	for (i = KDB_MAXBPT - 1; i >= 0; i--) {
2105d5314d6SJason Wessel 		kdb_bp_t *bp = &kdb_breakpoints[i];
2115d5314d6SJason Wessel 
2125d5314d6SJason Wessel 		if (KDB_DEBUG(BP)) {
2135d5314d6SJason Wessel 			kdb_printf("%s: bp %d bp_enabled %d\n",
2145d5314d6SJason Wessel 				   __func__, i, bp->bp_enabled);
2155d5314d6SJason Wessel 		}
2165d5314d6SJason Wessel 		if (bp->bp_enabled)
2175d5314d6SJason Wessel 			_kdb_bp_remove(bp);
2185d5314d6SJason Wessel 	}
2195d5314d6SJason Wessel }
2205d5314d6SJason Wessel 
2215d5314d6SJason Wessel 
2225d5314d6SJason Wessel /*
2235d5314d6SJason Wessel  * kdb_printbp
2245d5314d6SJason Wessel  *
2255d5314d6SJason Wessel  *	Internal function to format and print a breakpoint entry.
2265d5314d6SJason Wessel  *
2275d5314d6SJason Wessel  * Parameters:
2285d5314d6SJason Wessel  *	None.
2295d5314d6SJason Wessel  * Outputs:
2305d5314d6SJason Wessel  *	None.
2315d5314d6SJason Wessel  * Returns:
2325d5314d6SJason Wessel  *	None.
2335d5314d6SJason Wessel  * Locking:
2345d5314d6SJason Wessel  *	None.
2355d5314d6SJason Wessel  * Remarks:
2365d5314d6SJason Wessel  */
2375d5314d6SJason Wessel 
kdb_printbp(kdb_bp_t * bp,int i)2385d5314d6SJason Wessel static void kdb_printbp(kdb_bp_t *bp, int i)
2395d5314d6SJason Wessel {
2405d5314d6SJason Wessel 	kdb_printf("%s ", kdb_bptype(bp));
2415d5314d6SJason Wessel 	kdb_printf("BP #%d at ", i);
2425d5314d6SJason Wessel 	kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT);
2435d5314d6SJason Wessel 
2445d5314d6SJason Wessel 	if (bp->bp_enabled)
2455d5314d6SJason Wessel 		kdb_printf("\n    is enabled ");
2465d5314d6SJason Wessel 	else
2475d5314d6SJason Wessel 		kdb_printf("\n    is disabled");
2485d5314d6SJason Wessel 
24933f765f6SRandy Dunlap 	kdb_printf("  addr at %016lx, hardtype=%d installed=%d\n",
2505d5314d6SJason Wessel 		   bp->bp_addr, bp->bp_type, bp->bp_installed);
2515d5314d6SJason Wessel 
2525d5314d6SJason Wessel 	kdb_printf("\n");
2535d5314d6SJason Wessel }
2545d5314d6SJason Wessel 
2555d5314d6SJason Wessel /*
2565d5314d6SJason Wessel  * kdb_bp
2575d5314d6SJason Wessel  *
2585d5314d6SJason Wessel  *	Handle the bp commands.
2595d5314d6SJason Wessel  *
2605d5314d6SJason Wessel  *	[bp|bph] <addr-expression> [DATAR|DATAW]
2615d5314d6SJason Wessel  *
2625d5314d6SJason Wessel  * Parameters:
2635d5314d6SJason Wessel  *	argc	Count of arguments in argv
2645d5314d6SJason Wessel  *	argv	Space delimited command line arguments
2655d5314d6SJason Wessel  * Outputs:
2665d5314d6SJason Wessel  *	None.
2675d5314d6SJason Wessel  * Returns:
2685d5314d6SJason Wessel  *	Zero for success, a kdb diagnostic if failure.
2695d5314d6SJason Wessel  * Locking:
2705d5314d6SJason Wessel  *	None.
2715d5314d6SJason Wessel  * Remarks:
2725d5314d6SJason Wessel  *
2735d5314d6SJason Wessel  *	bp	Set breakpoint on all cpus.  Only use hardware assist if need.
2745d5314d6SJason Wessel  *	bph	Set breakpoint on all cpus.  Force hardware register
2755d5314d6SJason Wessel  */
2765d5314d6SJason Wessel 
kdb_bp(int argc,const char ** argv)2775d5314d6SJason Wessel static int kdb_bp(int argc, const char **argv)
2785d5314d6SJason Wessel {
2795d5314d6SJason Wessel 	int i, bpno;
2805d5314d6SJason Wessel 	kdb_bp_t *bp, *bp_check;
2815d5314d6SJason Wessel 	int diag;
2825d5314d6SJason Wessel 	char *symname = NULL;
2835d5314d6SJason Wessel 	long offset = 0ul;
2845d5314d6SJason Wessel 	int nextarg;
2855d5314d6SJason Wessel 	kdb_bp_t template = {0};
2865d5314d6SJason Wessel 
2875d5314d6SJason Wessel 	if (argc == 0) {
2885d5314d6SJason Wessel 		/*
2895d5314d6SJason Wessel 		 * Display breakpoint table
2905d5314d6SJason Wessel 		 */
2915d5314d6SJason Wessel 		for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT;
2925d5314d6SJason Wessel 		     bpno++, bp++) {
2935d5314d6SJason Wessel 			if (bp->bp_free)
2945d5314d6SJason Wessel 				continue;
2955d5314d6SJason Wessel 			kdb_printbp(bp, bpno);
2965d5314d6SJason Wessel 		}
2975d5314d6SJason Wessel 
2985d5314d6SJason Wessel 		return 0;
2995d5314d6SJason Wessel 	}
3005d5314d6SJason Wessel 
3015d5314d6SJason Wessel 	nextarg = 1;
3025d5314d6SJason Wessel 	diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr,
3035d5314d6SJason Wessel 			     &offset, &symname);
3045d5314d6SJason Wessel 	if (diag)
3055d5314d6SJason Wessel 		return diag;
3065d5314d6SJason Wessel 	if (!template.bp_addr)
3075d5314d6SJason Wessel 		return KDB_BADINT;
3085d5314d6SJason Wessel 
3095d5314d6SJason Wessel 	/*
310f2d10ff4SDaniel Thompson 	 * This check is redundant (since the breakpoint machinery should
311f2d10ff4SDaniel Thompson 	 * be doing the same check during kdb_bp_install) but gives the
312f2d10ff4SDaniel Thompson 	 * user immediate feedback.
313f2d10ff4SDaniel Thompson 	 */
314f2d10ff4SDaniel Thompson 	diag = kgdb_validate_break_address(template.bp_addr);
315f2d10ff4SDaniel Thompson 	if (diag)
316f2d10ff4SDaniel Thompson 		return diag;
317f2d10ff4SDaniel Thompson 
318f2d10ff4SDaniel Thompson 	/*
3195d5314d6SJason Wessel 	 * Find an empty bp structure to allocate
3205d5314d6SJason Wessel 	 */
3215d5314d6SJason Wessel 	for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT; bpno++, bp++) {
3225d5314d6SJason Wessel 		if (bp->bp_free)
3235d5314d6SJason Wessel 			break;
3245d5314d6SJason Wessel 	}
3255d5314d6SJason Wessel 
3265d5314d6SJason Wessel 	if (bpno == KDB_MAXBPT)
3275d5314d6SJason Wessel 		return KDB_TOOMANYBPT;
3285d5314d6SJason Wessel 
3295d5314d6SJason Wessel 	if (strcmp(argv[0], "bph") == 0) {
3305d5314d6SJason Wessel 		template.bp_type = BP_HARDWARE_BREAKPOINT;
3315d5314d6SJason Wessel 		diag = kdb_parsebp(argc, argv, &nextarg, &template);
3325d5314d6SJason Wessel 		if (diag)
3335d5314d6SJason Wessel 			return diag;
3345d5314d6SJason Wessel 	} else {
3355d5314d6SJason Wessel 		template.bp_type = BP_BREAKPOINT;
3365d5314d6SJason Wessel 	}
3375d5314d6SJason Wessel 
3385d5314d6SJason Wessel 	/*
3395d5314d6SJason Wessel 	 * Check for clashing breakpoints.
3405d5314d6SJason Wessel 	 *
3415d5314d6SJason Wessel 	 * Note, in this design we can't have hardware breakpoints
3425d5314d6SJason Wessel 	 * enabled for both read and write on the same address.
3435d5314d6SJason Wessel 	 */
3445d5314d6SJason Wessel 	for (i = 0, bp_check = kdb_breakpoints; i < KDB_MAXBPT;
3455d5314d6SJason Wessel 	     i++, bp_check++) {
3465d5314d6SJason Wessel 		if (!bp_check->bp_free &&
3475d5314d6SJason Wessel 		    bp_check->bp_addr == template.bp_addr) {
3485d5314d6SJason Wessel 			kdb_printf("You already have a breakpoint at "
3495d5314d6SJason Wessel 				   kdb_bfd_vma_fmt0 "\n", template.bp_addr);
3505d5314d6SJason Wessel 			return KDB_DUPBPT;
3515d5314d6SJason Wessel 		}
3525d5314d6SJason Wessel 	}
3535d5314d6SJason Wessel 
3545d5314d6SJason Wessel 	template.bp_enabled = 1;
3555d5314d6SJason Wessel 
3565d5314d6SJason Wessel 	/*
3575d5314d6SJason Wessel 	 * Actually allocate the breakpoint found earlier
3585d5314d6SJason Wessel 	 */
3595d5314d6SJason Wessel 	*bp = template;
3605d5314d6SJason Wessel 	bp->bp_free = 0;
3615d5314d6SJason Wessel 
3625d5314d6SJason Wessel 	kdb_printbp(bp, bpno);
3635d5314d6SJason Wessel 
3645d5314d6SJason Wessel 	return 0;
3655d5314d6SJason Wessel }
3665d5314d6SJason Wessel 
3675d5314d6SJason Wessel /*
3685d5314d6SJason Wessel  * kdb_bc
3695d5314d6SJason Wessel  *
3705d5314d6SJason Wessel  *	Handles the 'bc', 'be', and 'bd' commands
3715d5314d6SJason Wessel  *
3725d5314d6SJason Wessel  *	[bd|bc|be] <breakpoint-number>
3735d5314d6SJason Wessel  *	[bd|bc|be] *
3745d5314d6SJason Wessel  *
3755d5314d6SJason Wessel  * Parameters:
3765d5314d6SJason Wessel  *	argc	Count of arguments in argv
3775d5314d6SJason Wessel  *	argv	Space delimited command line arguments
3785d5314d6SJason Wessel  * Outputs:
3795d5314d6SJason Wessel  *	None.
3805d5314d6SJason Wessel  * Returns:
3815d5314d6SJason Wessel  *	Zero for success, a kdb diagnostic for failure
3825d5314d6SJason Wessel  * Locking:
3835d5314d6SJason Wessel  *	None.
3845d5314d6SJason Wessel  * Remarks:
3855d5314d6SJason Wessel  */
kdb_bc(int argc,const char ** argv)3865d5314d6SJason Wessel static int kdb_bc(int argc, const char **argv)
3875d5314d6SJason Wessel {
3885d5314d6SJason Wessel 	unsigned long addr;
3895d5314d6SJason Wessel 	kdb_bp_t *bp = NULL;
3905d5314d6SJason Wessel 	int lowbp = KDB_MAXBPT;
3915d5314d6SJason Wessel 	int highbp = 0;
3925d5314d6SJason Wessel 	int done = 0;
3935d5314d6SJason Wessel 	int i;
3945d5314d6SJason Wessel 	int diag = 0;
3955d5314d6SJason Wessel 
3965d5314d6SJason Wessel 	int cmd;			/* KDBCMD_B? */
3975d5314d6SJason Wessel #define KDBCMD_BC	0
3985d5314d6SJason Wessel #define KDBCMD_BE	1
3995d5314d6SJason Wessel #define KDBCMD_BD	2
4005d5314d6SJason Wessel 
4015d5314d6SJason Wessel 	if (strcmp(argv[0], "be") == 0)
4025d5314d6SJason Wessel 		cmd = KDBCMD_BE;
4035d5314d6SJason Wessel 	else if (strcmp(argv[0], "bd") == 0)
4045d5314d6SJason Wessel 		cmd = KDBCMD_BD;
4055d5314d6SJason Wessel 	else
4065d5314d6SJason Wessel 		cmd = KDBCMD_BC;
4075d5314d6SJason Wessel 
4085d5314d6SJason Wessel 	if (argc != 1)
4095d5314d6SJason Wessel 		return KDB_ARGCOUNT;
4105d5314d6SJason Wessel 
4115d5314d6SJason Wessel 	if (strcmp(argv[1], "*") == 0) {
4125d5314d6SJason Wessel 		lowbp = 0;
4135d5314d6SJason Wessel 		highbp = KDB_MAXBPT;
4145d5314d6SJason Wessel 	} else {
4155d5314d6SJason Wessel 		diag = kdbgetularg(argv[1], &addr);
4165d5314d6SJason Wessel 		if (diag)
4175d5314d6SJason Wessel 			return diag;
4185d5314d6SJason Wessel 
4195d5314d6SJason Wessel 		/*
4205d5314d6SJason Wessel 		 * For addresses less than the maximum breakpoint number,
4215d5314d6SJason Wessel 		 * assume that the breakpoint number is desired.
4225d5314d6SJason Wessel 		 */
4235d5314d6SJason Wessel 		if (addr < KDB_MAXBPT) {
4245d5314d6SJason Wessel 			lowbp = highbp = addr;
4255d5314d6SJason Wessel 			highbp++;
4265d5314d6SJason Wessel 		} else {
4275d5314d6SJason Wessel 			for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT;
4285d5314d6SJason Wessel 			    i++, bp++) {
4295d5314d6SJason Wessel 				if (bp->bp_addr == addr) {
4305d5314d6SJason Wessel 					lowbp = highbp = i;
4315d5314d6SJason Wessel 					highbp++;
4325d5314d6SJason Wessel 					break;
4335d5314d6SJason Wessel 				}
4345d5314d6SJason Wessel 			}
4355d5314d6SJason Wessel 		}
4365d5314d6SJason Wessel 	}
4375d5314d6SJason Wessel 
4385d5314d6SJason Wessel 	/*
4395d5314d6SJason Wessel 	 * Now operate on the set of breakpoints matching the input
4405d5314d6SJason Wessel 	 * criteria (either '*' for all, or an individual breakpoint).
4415d5314d6SJason Wessel 	 */
4425d5314d6SJason Wessel 	for (bp = &kdb_breakpoints[lowbp], i = lowbp;
4435d5314d6SJason Wessel 	    i < highbp;
4445d5314d6SJason Wessel 	    i++, bp++) {
4455d5314d6SJason Wessel 		if (bp->bp_free)
4465d5314d6SJason Wessel 			continue;
4475d5314d6SJason Wessel 
4485d5314d6SJason Wessel 		done++;
4495d5314d6SJason Wessel 
4505d5314d6SJason Wessel 		switch (cmd) {
4515d5314d6SJason Wessel 		case KDBCMD_BC:
4525d5314d6SJason Wessel 			bp->bp_enabled = 0;
4535d5314d6SJason Wessel 
4545d5314d6SJason Wessel 			kdb_printf("Breakpoint %d at "
4555d5314d6SJason Wessel 				   kdb_bfd_vma_fmt " cleared\n",
4565d5314d6SJason Wessel 				   i, bp->bp_addr);
4575d5314d6SJason Wessel 
4585d5314d6SJason Wessel 			bp->bp_addr = 0;
4595d5314d6SJason Wessel 			bp->bp_free = 1;
4605d5314d6SJason Wessel 
4615d5314d6SJason Wessel 			break;
4625d5314d6SJason Wessel 		case KDBCMD_BE:
4635d5314d6SJason Wessel 			bp->bp_enabled = 1;
4645d5314d6SJason Wessel 
4655d5314d6SJason Wessel 			kdb_printf("Breakpoint %d at "
4665d5314d6SJason Wessel 				   kdb_bfd_vma_fmt " enabled",
4675d5314d6SJason Wessel 				   i, bp->bp_addr);
4685d5314d6SJason Wessel 
4695d5314d6SJason Wessel 			kdb_printf("\n");
4705d5314d6SJason Wessel 			break;
4715d5314d6SJason Wessel 		case KDBCMD_BD:
4725d5314d6SJason Wessel 			if (!bp->bp_enabled)
4735d5314d6SJason Wessel 				break;
4745d5314d6SJason Wessel 
4755d5314d6SJason Wessel 			bp->bp_enabled = 0;
4765d5314d6SJason Wessel 
4775d5314d6SJason Wessel 			kdb_printf("Breakpoint %d at "
4785d5314d6SJason Wessel 				   kdb_bfd_vma_fmt " disabled\n",
4795d5314d6SJason Wessel 				   i, bp->bp_addr);
4805d5314d6SJason Wessel 
4815d5314d6SJason Wessel 			break;
4825d5314d6SJason Wessel 		}
4835d5314d6SJason Wessel 		if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) {
4845d5314d6SJason Wessel 			bp->bp_delay = 0;
4855d5314d6SJason Wessel 			KDB_STATE_CLEAR(SSBPT);
4865d5314d6SJason Wessel 		}
4875d5314d6SJason Wessel 	}
4885d5314d6SJason Wessel 
4895d5314d6SJason Wessel 	return (!done) ? KDB_BPTNOTFOUND : 0;
4905d5314d6SJason Wessel }
4915d5314d6SJason Wessel 
4925d5314d6SJason Wessel /*
4935d5314d6SJason Wessel  * kdb_ss
4945d5314d6SJason Wessel  *
49536dfea42SVincent  *	Process the 'ss' (Single Step) command.
4965d5314d6SJason Wessel  *
4975d5314d6SJason Wessel  *	ss
4985d5314d6SJason Wessel  *
4995d5314d6SJason Wessel  * Parameters:
5005d5314d6SJason Wessel  *	argc	Argument count
5015d5314d6SJason Wessel  *	argv	Argument vector
5025d5314d6SJason Wessel  * Outputs:
5035d5314d6SJason Wessel  *	None.
5045d5314d6SJason Wessel  * Returns:
50536dfea42SVincent  *	KDB_CMD_SS for success, a kdb error if failure.
5065d5314d6SJason Wessel  * Locking:
5075d5314d6SJason Wessel  *	None.
5085d5314d6SJason Wessel  * Remarks:
5095d5314d6SJason Wessel  *
5105d5314d6SJason Wessel  *	Set the arch specific option to trigger a debug trap after the next
5115d5314d6SJason Wessel  *	instruction.
5125d5314d6SJason Wessel  */
5135d5314d6SJason Wessel 
kdb_ss(int argc,const char ** argv)5145d5314d6SJason Wessel static int kdb_ss(int argc, const char **argv)
5155d5314d6SJason Wessel {
5165d5314d6SJason Wessel 	if (argc != 0)
5175d5314d6SJason Wessel 		return KDB_ARGCOUNT;
5185d5314d6SJason Wessel 	/*
5195d5314d6SJason Wessel 	 * Set trace flag and go.
5205d5314d6SJason Wessel 	 */
5215d5314d6SJason Wessel 	KDB_STATE_SET(DOING_SS);
5225d5314d6SJason Wessel 	return KDB_CMD_SS;
5235d5314d6SJason Wessel }
5245d5314d6SJason Wessel 
525e4f291b3SSumit Garg static kdbtab_t bptab[] = {
526*e868f0a3SSumit Garg 	{	.name = "bp",
527*e868f0a3SSumit Garg 		.func = kdb_bp,
528*e868f0a3SSumit Garg 		.usage = "[<vaddr>]",
529*e868f0a3SSumit Garg 		.help = "Set/Display breakpoints",
530*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
531e4f291b3SSumit Garg 	},
532*e868f0a3SSumit Garg 	{	.name = "bl",
533*e868f0a3SSumit Garg 		.func = kdb_bp,
534*e868f0a3SSumit Garg 		.usage = "[<vaddr>]",
535*e868f0a3SSumit Garg 		.help = "Display breakpoints",
536*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
537e4f291b3SSumit Garg 	},
538*e868f0a3SSumit Garg 	{	.name = "bc",
539*e868f0a3SSumit Garg 		.func = kdb_bc,
540*e868f0a3SSumit Garg 		.usage = "<bpnum>",
541*e868f0a3SSumit Garg 		.help = "Clear Breakpoint",
542*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL,
543e4f291b3SSumit Garg 	},
544*e868f0a3SSumit Garg 	{	.name = "be",
545*e868f0a3SSumit Garg 		.func = kdb_bc,
546*e868f0a3SSumit Garg 		.usage = "<bpnum>",
547*e868f0a3SSumit Garg 		.help = "Enable Breakpoint",
548*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL,
549e4f291b3SSumit Garg 	},
550*e868f0a3SSumit Garg 	{	.name = "bd",
551*e868f0a3SSumit Garg 		.func = kdb_bc,
552*e868f0a3SSumit Garg 		.usage = "<bpnum>",
553*e868f0a3SSumit Garg 		.help = "Disable Breakpoint",
554*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL,
555e4f291b3SSumit Garg 	},
556*e868f0a3SSumit Garg 	{	.name = "ss",
557*e868f0a3SSumit Garg 		.func = kdb_ss,
558*e868f0a3SSumit Garg 		.usage = "",
559*e868f0a3SSumit Garg 		.help = "Single Step",
560*e868f0a3SSumit Garg 		.minlen = 1,
561*e868f0a3SSumit Garg 		.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
562e4f291b3SSumit Garg 	},
563e4f291b3SSumit Garg };
564e4f291b3SSumit Garg 
565e4f291b3SSumit Garg static kdbtab_t bphcmd = {
566*e868f0a3SSumit Garg 	.name = "bph",
567*e868f0a3SSumit Garg 	.func = kdb_bp,
568*e868f0a3SSumit Garg 	.usage = "[<vaddr>]",
569*e868f0a3SSumit Garg 	.help = "[datar [length]|dataw [length]]   Set hw brk",
570*e868f0a3SSumit Garg 	.flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
571e4f291b3SSumit Garg };
572e4f291b3SSumit Garg 
5735d5314d6SJason Wessel /* Initialize the breakpoint table and register	breakpoint commands. */
5745d5314d6SJason Wessel 
kdb_initbptab(void)5755d5314d6SJason Wessel void __init kdb_initbptab(void)
5765d5314d6SJason Wessel {
5775d5314d6SJason Wessel 	int i;
5785d5314d6SJason Wessel 	kdb_bp_t *bp;
5795d5314d6SJason Wessel 
5805d5314d6SJason Wessel 	/*
5815d5314d6SJason Wessel 	 * First time initialization.
5825d5314d6SJason Wessel 	 */
5835d5314d6SJason Wessel 	memset(&kdb_breakpoints, '\0', sizeof(kdb_breakpoints));
5845d5314d6SJason Wessel 
5855d5314d6SJason Wessel 	for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
5865d5314d6SJason Wessel 		bp->bp_free = 1;
5875d5314d6SJason Wessel 
588e4f291b3SSumit Garg 	kdb_register_table(bptab, ARRAY_SIZE(bptab));
5895d5314d6SJason Wessel 	if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
590e4f291b3SSumit Garg 		kdb_register_table(&bphcmd, 1);
5915d5314d6SJason Wessel }
592