1133 lines · 25.3 KB · C
RawDownload
/* * Kernel Debug Core * * Maintainer: Jason Wessel <jason.wessel@windriver.com> * * Copyright (C) 2000-2001 VERITAS Software Corporation. * Copyright (C) 2002-2004 Timesys Corporation * Copyright (C) 2003-2004 Amit S. Kale <amitkale@linsyssoft.com> * Copyright (C) 2004 Pavel Machek <pavel@ucw.cz> * Copyright (C) 2004-2006 Tom Rini <trini@kernel.crashing.org> * Copyright (C) 2004-2006 LinSysSoft Technologies Pvt. Ltd. * Copyright (C) 2005-2009 Wind River Systems, Inc. * Copyright (C) 2007 MontaVista Software, Inc. * Copyright (C) 2008 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> * * Contributors at various stages not listed above: *  Jason Wessel ( jason.wessel@windriver.com ) *  George Anzinger <george@mvista.com> *  Anurekh Saxena (anurekh.saxena@timesys.com) *  Lake Stevens Instrument Division (Glenn Engel) *  Jim Kingdon, Cygnus Support. * * Original KGDB stub: David Grothe <dave@gcom.com>, * Tigran Aivazian <tigran@sco.com> * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #include <linux/kernel.h>#include <linux/kgdb.h>#include <linux/kdb.h>#include <linux/reboot.h>#include <linux/uaccess.h>#include <asm/cacheflush.h>#include <asm/unaligned.h>#include "debug_core.h" #define KGDB_MAX_THREAD_QUERY 17 /* Our I/O buffers. */static char			remcom_in_buffer[BUFMAX];static char			remcom_out_buffer[BUFMAX];static int			gdbstub_use_prev_in_buf;static int			gdbstub_prev_in_buf_pos; /* Storage for the registers, in GDB format. */static unsigned long		gdb_regs[(NUMREGBYTES +					sizeof(unsigned long) - 1) /					sizeof(unsigned long)]; /* * GDB remote protocol parser: */ #ifdef CONFIG_KGDB_KDBstatic int gdbstub_read_wait(void){	int ret = -1;	int i; 	if (unlikely(gdbstub_use_prev_in_buf)) {		if (gdbstub_prev_in_buf_pos < gdbstub_use_prev_in_buf)			return remcom_in_buffer[gdbstub_prev_in_buf_pos++];		else			gdbstub_use_prev_in_buf = 0;	} 	/* poll any additional I/O interfaces that are defined */	while (ret < 0)		for (i = 0; kdb_poll_funcs[i] != NULL; i++) {			ret = kdb_poll_funcs[i]();			if (ret > 0)				break;		}	return ret;}#elsestatic int gdbstub_read_wait(void){	int ret = dbg_io_ops->read_char();	while (ret == NO_POLL_CHAR)		ret = dbg_io_ops->read_char();	return ret;}#endif/* scan for the sequence $<data>#<checksum> */static void get_packet(char *buffer){	unsigned char checksum;	unsigned char xmitcsum;	int count;	char ch; 	do {		/*		 * Spin and wait around for the start character, ignore all		 * other characters:		 */		while ((ch = (gdbstub_read_wait())) != '$')			/* nothing */; 		kgdb_connected = 1;		checksum = 0;		xmitcsum = -1; 		count = 0; 		/*		 * now, read until a # or end of buffer is found:		 */		while (count < (BUFMAX - 1)) {			ch = gdbstub_read_wait();			if (ch == '#')				break;			checksum = checksum + ch;			buffer[count] = ch;			count = count + 1;		} 		if (ch == '#') {			xmitcsum = hex_to_bin(gdbstub_read_wait()) << 4;			xmitcsum += hex_to_bin(gdbstub_read_wait()); 			if (checksum != xmitcsum)				/* failed checksum */				dbg_io_ops->write_char('-');			else				/* successful transfer */				dbg_io_ops->write_char('+');			if (dbg_io_ops->flush)				dbg_io_ops->flush();		}		buffer[count] = 0;	} while (checksum != xmitcsum);} /* * Send the packet in buffer. * Check for gdb connection if asked for. */static void put_packet(char *buffer){	unsigned char checksum;	int count;	char ch; 	/*	 * $<packet info>#<checksum>.	 */	while (1) {		dbg_io_ops->write_char('$');		checksum = 0;		count = 0; 		while ((ch = buffer[count])) {			dbg_io_ops->write_char(ch);			checksum += ch;			count++;		} 		dbg_io_ops->write_char('#');		dbg_io_ops->write_char(hex_asc_hi(checksum));		dbg_io_ops->write_char(hex_asc_lo(checksum));		if (dbg_io_ops->flush)			dbg_io_ops->flush(); 		/* Now see what we get in reply. */		ch = gdbstub_read_wait(); 		if (ch == 3)			ch = gdbstub_read_wait(); 		/* If we get an ACK, we are done. */		if (ch == '+')			return; 		/*		 * If we get the start of another packet, this means		 * that GDB is attempting to reconnect.  We will NAK		 * the packet being sent, and stop trying to send this		 * packet.		 */		if (ch == '$') {			dbg_io_ops->write_char('-');			if (dbg_io_ops->flush)				dbg_io_ops->flush();			return;		}	}} static char gdbmsgbuf[BUFMAX + 1]; void gdbstub_msg_write(const char *s, int len){	char *bufptr;	int wcount;	int i; 	if (len == 0)		len = strlen(s); 	/* 'O'utput */	gdbmsgbuf[0] = 'O'; 	/* Fill and send buffers... */	while (len > 0) {		bufptr = gdbmsgbuf + 1; 		/* Calculate how many this time */		if ((len << 1) > (BUFMAX - 2))			wcount = (BUFMAX - 2) >> 1;		else			wcount = len; 		/* Pack in hex chars */		for (i = 0; i < wcount; i++)			bufptr = pack_hex_byte(bufptr, s[i]);		*bufptr = '\0'; 		/* Move up */		s += wcount;		len -= wcount; 		/* Write packet */		put_packet(gdbmsgbuf);	}} /* * Convert the memory pointed to by mem into hex, placing result in * buf.  Return a pointer to the last char put in buf (null). May * return an error. */char *kgdb_mem2hex(char *mem, char *buf, int count){	char *tmp;	int err; 	/*	 * We use the upper half of buf as an intermediate buffer for the	 * raw memory copy.  Hex conversion will work against this one.	 */	tmp = buf + count; 	err = probe_kernel_read(tmp, mem, count);	if (err)		return NULL;	while (count > 0) {		buf = pack_hex_byte(buf, *tmp);		tmp++;		count--;	}	*buf = 0; 	return buf;} /* * Convert the hex array pointed to by buf into binary to be placed in * mem.  Return a pointer to the character AFTER the last byte * written.  May return an error. */int kgdb_hex2mem(char *buf, char *mem, int count){	char *tmp_raw;	char *tmp_hex; 	/*	 * We use the upper half of buf as an intermediate buffer for the	 * raw memory that is converted from hex.	 */	tmp_raw = buf + count * 2; 	tmp_hex = tmp_raw - 1;	while (tmp_hex >= buf) {		tmp_raw--;		*tmp_raw = hex_to_bin(*tmp_hex--);		*tmp_raw |= hex_to_bin(*tmp_hex--) << 4;	} 	return probe_kernel_write(mem, tmp_raw, count);} /* * While we find nice hex chars, build a long_val. * Return number of chars processed. */int kgdb_hex2long(char **ptr, unsigned long *long_val){	int hex_val;	int num = 0;	int negate = 0; 	*long_val = 0; 	if (**ptr == '-') {		negate = 1;		(*ptr)++;	}	while (**ptr) {		hex_val = hex_to_bin(**ptr);		if (hex_val < 0)			break; 		*long_val = (*long_val << 4) | hex_val;		num++;		(*ptr)++;	} 	if (negate)		*long_val = -*long_val; 	return num;} /* * Copy the binary array pointed to by buf into mem.  Fix $, #, and * 0x7d escaped with 0x7d. Return -EFAULT on failure or 0 on success. * The input buf is overwitten with the result to write to mem. */static int kgdb_ebin2mem(char *buf, char *mem, int count){	int size = 0;	char *c = buf; 	while (count-- > 0) {		c[size] = *buf++;		if (c[size] == 0x7d)			c[size] = *buf++ ^ 0x20;		size++;	} 	return probe_kernel_write(mem, c, size);} #if DBG_MAX_REG_NUM > 0void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs){	int i;	int idx = 0;	char *ptr = (char *)gdb_regs; 	for (i = 0; i < DBG_MAX_REG_NUM; i++) {		dbg_get_reg(i, ptr + idx, regs);		idx += dbg_reg_def[i].size;	}} void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs){	int i;	int idx = 0;	char *ptr = (char *)gdb_regs; 	for (i = 0; i < DBG_MAX_REG_NUM; i++) {		dbg_set_reg(i, ptr + idx, regs);		idx += dbg_reg_def[i].size;	}}#endif /* DBG_MAX_REG_NUM > 0 */ /* Write memory due to an 'M' or 'X' packet. */static int write_mem_msg(int binary){	char *ptr = &remcom_in_buffer[1];	unsigned long addr;	unsigned long length;	int err; 	if (kgdb_hex2long(&ptr, &addr) > 0 && *(ptr++) == ',' &&	    kgdb_hex2long(&ptr, &length) > 0 && *(ptr++) == ':') {		if (binary)			err = kgdb_ebin2mem(ptr, (char *)addr, length);		else			err = kgdb_hex2mem(ptr, (char *)addr, length);		if (err)			return err;		if (CACHE_FLUSH_IS_SAFE)			flush_icache_range(addr, addr + length);		return 0;	} 	return -EINVAL;} static void error_packet(char *pkt, int error){	error = -error;	pkt[0] = 'E';	pkt[1] = hex_asc[(error / 10)];	pkt[2] = hex_asc[(error % 10)];	pkt[3] = '\0';} /* * Thread ID accessors. We represent a flat TID space to GDB, where * the per CPU idle threads (which under Linux all have PID 0) are * remapped to negative TIDs. */ #define BUF_THREAD_ID_SIZE	8 static char *pack_threadid(char *pkt, unsigned char *id){	unsigned char *limit;	int lzero = 1; 	limit = id + (BUF_THREAD_ID_SIZE / 2);	while (id < limit) {		if (!lzero || *id != 0) {			pkt = pack_hex_byte(pkt, *id);			lzero = 0;		}		id++;	} 	if (lzero)		pkt = pack_hex_byte(pkt, 0); 	return pkt;} static void int_to_threadref(unsigned char *id, int value){	put_unaligned_be32(value, id);} static struct task_struct *getthread(struct pt_regs *regs, int tid){	/*	 * Non-positive TIDs are remapped to the cpu shadow information	 */	if (tid == 0 || tid == -1)		tid = -atomic_read(&kgdb_active) - 2;	if (tid < -1 && tid > -NR_CPUS - 2) {		if (kgdb_info[-tid - 2].task)			return kgdb_info[-tid - 2].task;		else			return idle_task(-tid - 2);	}	if (tid <= 0) {		printk(KERN_ERR "KGDB: Internal thread select error\n");		dump_stack();		return NULL;	} 	/*	 * find_task_by_pid_ns() does not take the tasklist lock anymore	 * but is nicely RCU locked - hence is a pretty resilient	 * thing to use:	 */	return find_task_by_pid_ns(tid, &init_pid_ns);}  /* * Remap normal tasks to their real PID, * CPU shadow threads are mapped to -CPU - 2 */static inline int shadow_pid(int realpid){	if (realpid)		return realpid; 	return -raw_smp_processor_id() - 2;} /* * All the functions that start with gdb_cmd are the various * operations to implement the handlers for the gdbserial protocol * where KGDB is communicating with an external debugger */ /* Handle the '?' status packets */static void gdb_cmd_status(struct kgdb_state *ks){	/*	 * We know that this packet is only sent	 * during initial connect.  So to be safe,	 * we clear out our breakpoints now in case	 * GDB is reconnecting.	 */	dbg_remove_all_break(); 	remcom_out_buffer[0] = 'S';	pack_hex_byte(&remcom_out_buffer[1], ks->signo);} static void gdb_get_regs_helper(struct kgdb_state *ks){	struct task_struct *thread;	void *local_debuggerinfo;	int i; 	thread = kgdb_usethread;	if (!thread) {		thread = kgdb_info[ks->cpu].task;

Lines 1–500 of 1133.