558 lines · 10.9 KB · C
RawDownload
/* * Kernel Debugger Architecture Independent Breakpoint Handler * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (c) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved. * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved. */ #include <linux/string.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/kdb.h>#include <linux/kgdb.h>#include <linux/smp.h>#include <linux/sched.h>#include <linux/interrupt.h>#include "kdb_private.h" /* * Table of kdb_breakpoints */kdb_bp_t kdb_breakpoints[KDB_MAXBPT]; static void kdb_setsinglestep(struct pt_regs *regs){	KDB_STATE_SET(DOING_SS);} static char *kdb_rwtypes[] = {	"Instruction(i)",	"Instruction(Register)",	"Data Write",	"I/O",	"Data Access"}; static char *kdb_bptype(kdb_bp_t *bp){	if (bp->bp_type < 0 || bp->bp_type > 4)		return ""; 	return kdb_rwtypes[bp->bp_type];} static int kdb_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp){	int nextarg = *nextargp;	int diag; 	bp->bph_length = 1;	if ((argc + 1) != nextarg) {		if (strncasecmp(argv[nextarg], "datar", sizeof("datar")) == 0)			bp->bp_type = BP_ACCESS_WATCHPOINT;		else if (strncasecmp(argv[nextarg], "dataw", sizeof("dataw")) == 0)			bp->bp_type = BP_WRITE_WATCHPOINT;		else if (strncasecmp(argv[nextarg], "inst", sizeof("inst")) == 0)			bp->bp_type = BP_HARDWARE_BREAKPOINT;		else			return KDB_ARGCOUNT; 		bp->bph_length = 1; 		nextarg++; 		if ((argc + 1) != nextarg) {			unsigned long len; 			diag = kdbgetularg((char *)argv[nextarg],					   &len);			if (diag)				return diag;  			if (len > 8)				return KDB_BADLENGTH; 			bp->bph_length = len;			nextarg++;		} 		if ((argc + 1) != nextarg)			return KDB_ARGCOUNT;	} 	*nextargp = nextarg;	return 0;} static int _kdb_bp_remove(kdb_bp_t *bp){	int ret = 1;	if (!bp->bp_installed)		return ret;	if (!bp->bp_type)		ret = dbg_remove_sw_break(bp->bp_addr);	else		ret = arch_kgdb_ops.remove_hw_breakpoint(bp->bp_addr,			 bp->bph_length,			 bp->bp_type);	if (ret == 0)		bp->bp_installed = 0;	return ret;} static void kdb_handle_bp(struct pt_regs *regs, kdb_bp_t *bp){	if (KDB_DEBUG(BP))		kdb_printf("regs->ip = 0x%lx\n", instruction_pointer(regs)); 	/*	 * Setup single step	 */	kdb_setsinglestep(regs); 	/*	 * Reset delay attribute	 */	bp->bp_delay = 0;	bp->bp_delayed = 1;} static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp){	int ret;	/*	 * Install the breakpoint, if it is not already installed.	 */ 	if (KDB_DEBUG(BP))		kdb_printf("%s: bp_installed %d\n",			   __func__, bp->bp_installed);	if (!KDB_STATE(SSBPT))		bp->bp_delay = 0;	if (bp->bp_installed)		return 1;	if (bp->bp_delay || (bp->bp_delayed && KDB_STATE(DOING_SS))) {		if (KDB_DEBUG(BP))			kdb_printf("%s: delayed bp\n", __func__);		kdb_handle_bp(regs, bp);		return 0;	}	if (!bp->bp_type)		ret = dbg_set_sw_break(bp->bp_addr);	else		ret = arch_kgdb_ops.set_hw_breakpoint(bp->bp_addr,			 bp->bph_length,			 bp->bp_type);	if (ret == 0) {		bp->bp_installed = 1;	} else {		kdb_printf("%s: failed to set breakpoint at 0x%lx\n",			   __func__, bp->bp_addr);		if (!bp->bp_type) {			kdb_printf("Software breakpoints are unavailable.\n"				   "  Boot the kernel with rodata=off\n"				   "  OR use hw breaks: help bph\n");		}		return 1;	}	return 0;} /* * kdb_bp_install * *	Install kdb_breakpoints prior to returning from the *	kernel debugger.  This allows the kdb_breakpoints to be set *	upon functions that are used internally by kdb, such as *	printk().  This function is only called once per kdb session. */void kdb_bp_install(struct pt_regs *regs){	int i; 	for (i = 0; i < KDB_MAXBPT; i++) {		kdb_bp_t *bp = &kdb_breakpoints[i]; 		if (KDB_DEBUG(BP)) {			kdb_printf("%s: bp %d bp_enabled %d\n",				   __func__, i, bp->bp_enabled);		}		if (bp->bp_enabled)			_kdb_bp_install(regs, bp);	}} /* * kdb_bp_remove * *	Remove kdb_breakpoints upon entry to the kernel debugger. * * Parameters: *	None. * Outputs: *	None. * Returns: *	None. * Locking: *	None. * Remarks: */void kdb_bp_remove(void){	int i; 	for (i = KDB_MAXBPT - 1; i >= 0; i--) {		kdb_bp_t *bp = &kdb_breakpoints[i]; 		if (KDB_DEBUG(BP)) {			kdb_printf("%s: bp %d bp_enabled %d\n",				   __func__, i, bp->bp_enabled);		}		if (bp->bp_enabled)			_kdb_bp_remove(bp);	}}  /* * kdb_printbp * *	Internal function to format and print a breakpoint entry. * * Parameters: *	None. * Outputs: *	None. * Returns: *	None. * Locking: *	None. * Remarks: */ static void kdb_printbp(kdb_bp_t *bp, int i){	kdb_printf("%s ", kdb_bptype(bp));	kdb_printf("BP #%d at ", i);	kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT); 	if (bp->bp_enabled)		kdb_printf("\n    is enabled");	else		kdb_printf("\n    is disabled"); 	kdb_printf("\taddr at %016lx, hardtype=%d installed=%d\n",		   bp->bp_addr, bp->bp_type, bp->bp_installed); 	kdb_printf("\n");} /* * kdb_bp * *	Handle the bp commands. * *	[bp|bph] <addr-expression> [DATAR|DATAW] * * Parameters: *	argc	Count of arguments in argv *	argv	Space delimited command line arguments * Outputs: *	None. * Returns: *	Zero for success, a kdb diagnostic if failure. * Locking: *	None. * Remarks: * *	bp	Set breakpoint on all cpus.  Only use hardware assist if need. *	bph	Set breakpoint on all cpus.  Force hardware register */ static int kdb_bp(int argc, const char **argv){	int i, bpno;	kdb_bp_t *bp, *bp_check;	int diag;	char *symname = NULL;	long offset = 0ul;	int nextarg;	kdb_bp_t template = {0}; 	if (argc == 0) {		/*		 * Display breakpoint table		 */		for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT;		     bpno++, bp++) {			if (bp->bp_free)				continue;			kdb_printbp(bp, bpno);		} 		return 0;	} 	nextarg = 1;	diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr,			     &offset, &symname);	if (diag)		return diag;	if (!template.bp_addr)		return KDB_BADINT; 	/*	 * Find an empty bp structure to allocate	 */	for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT; bpno++, bp++) {		if (bp->bp_free)			break;	} 	if (bpno == KDB_MAXBPT)		return KDB_TOOMANYBPT; 	if (strcmp(argv[0], "bph") == 0) {		template.bp_type = BP_HARDWARE_BREAKPOINT;		diag = kdb_parsebp(argc, argv, &nextarg, &template);		if (diag)			return diag;	} else {		template.bp_type = BP_BREAKPOINT;	} 	/*	 * Check for clashing breakpoints.	 *	 * Note, in this design we can't have hardware breakpoints	 * enabled for both read and write on the same address.	 */	for (i = 0, bp_check = kdb_breakpoints; i < KDB_MAXBPT;	     i++, bp_check++) {		if (!bp_check->bp_free &&		    bp_check->bp_addr == template.bp_addr) {			kdb_printf("You already have a breakpoint at "				   kdb_bfd_vma_fmt0 "\n", template.bp_addr);			return KDB_DUPBPT;		}	} 	template.bp_enabled = 1; 	/*	 * Actually allocate the breakpoint found earlier	 */	*bp = template;	bp->bp_free = 0; 	kdb_printbp(bp, bpno); 	return 0;} /* * kdb_bc * *	Handles the 'bc', 'be', and 'bd' commands * *	[bd|bc|be] <breakpoint-number> *	[bd|bc|be] * * * Parameters: *	argc	Count of arguments in argv *	argv	Space delimited command line arguments * Outputs: *	None. * Returns: *	Zero for success, a kdb diagnostic for failure * Locking: *	None. * Remarks: */static int kdb_bc(int argc, const char **argv){	unsigned long addr;	kdb_bp_t *bp = NULL;	int lowbp = KDB_MAXBPT;	int highbp = 0;	int done = 0;	int i;	int diag = 0; 	int cmd;			/* KDBCMD_B? */#define KDBCMD_BC	0#define KDBCMD_BE	1#define KDBCMD_BD	2 	if (strcmp(argv[0], "be") == 0)		cmd = KDBCMD_BE;	else if (strcmp(argv[0], "bd") == 0)		cmd = KDBCMD_BD;	else		cmd = KDBCMD_BC; 	if (argc != 1)		return KDB_ARGCOUNT; 	if (strcmp(argv[1], "*") == 0) {		lowbp = 0;		highbp = KDB_MAXBPT;	} else {		diag = kdbgetularg(argv[1], &addr);		if (diag)			return diag; 		/*		 * For addresses less than the maximum breakpoint number,		 * assume that the breakpoint number is desired.		 */		if (addr < KDB_MAXBPT) {			bp = &kdb_breakpoints[addr];			lowbp = highbp = addr;			highbp++;		} else {			for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT;			    i++, bp++) {				if (bp->bp_addr == addr) {					lowbp = highbp = i;					highbp++;					break;				}			}		}	} 	/*	 * Now operate on the set of breakpoints matching the input	 * criteria (either '*' for all, or an individual breakpoint).	 */	for (bp = &kdb_breakpoints[lowbp], i = lowbp;	    i < highbp;	    i++, bp++) {		if (bp->bp_free)			continue; 		done++; 		switch (cmd) {		case KDBCMD_BC:			bp->bp_enabled = 0; 			kdb_printf("Breakpoint %d at "				   kdb_bfd_vma_fmt " cleared\n",				   i, bp->bp_addr); 			bp->bp_addr = 0;			bp->bp_free = 1; 			break;		case KDBCMD_BE:			bp->bp_enabled = 1; 			kdb_printf("Breakpoint %d at "				   kdb_bfd_vma_fmt " enabled",				   i, bp->bp_addr); 			kdb_printf("\n");			break;		case KDBCMD_BD:			if (!bp->bp_enabled)				break; 			bp->bp_enabled = 0; 			kdb_printf("Breakpoint %d at "				   kdb_bfd_vma_fmt " disabled\n",				   i, bp->bp_addr); 			break;		}		if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) {			bp->bp_delay = 0;			KDB_STATE_CLEAR(SSBPT);		}	} 	return (!done) ? KDB_BPTNOTFOUND : 0;} /* * kdb_ss * *	Process the 'ss' (Single Step) command. * *	ss * * Parameters: *	argc	Argument count *	argv	Argument vector * Outputs: *	None. * Returns: *	KDB_CMD_SS for success, a kdb error if failure. * Locking: *	None. * Remarks:

Lines 1–500 of 558.