⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kgdb-stub.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/**************************************************************************** *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ * *  Module name: remcom.c $ *  Revision: 1.34 $ *  Date: 91/03/09 12:29:49 $ *  Contributor:     Lake Stevens Instrument Division$ * *  Description:     low level support for gdb debugger. $ * *  Considerations:  only works on target hardware $ * *  Written by:      Glenn Engel $ *  ModuleState:     Experimental $ * *  NOTES:           See Below $ * *  Modified for 386 by Jim Kingdon, Cygnus Support. * *  To enable debugger support, two things need to happen.  One, a *  call to set_debug_traps() is necessary in order to allow any breakpoints *  or error conditions to be properly intercepted and reported to gdb. *  Two, a breakpoint needs to be generated to begin communication.  This *  is most easily accomplished by a call to breakpoint().  Breakpoint() *  simulates a breakpoint by executing a trap #1. * *  The external function exceptionHandler() is *  used to attach a specific handler to a specific 386 vector number. *  It should use the same privilege level it runs at.  It should *  install it as an interrupt gate so that interrupts are masked *  while the handler runs. * *  Because gdb will sometimes write to the stack area to execute function *  calls, this program cannot rely on using the supervisor stack so it *  uses it's own stack area reserved in the int array remcomStack. * ************* * *    The following gdb commands are supported: * * command          function                               Return value * *    g             return the value of the CPU registers  hex data or ENN *    G             set the value of the CPU registers     OK or ENN * *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN *    XAA..AA,LLLL: Same, but data is binary (not hex)     OK or ENN * *    c             Resume at current address              SNN   ( signal NN) *    cAA..AA       Continue at address AA..AA             SNN *    CNN;          Resume at current address with signal  SNN *    CNN;AA..AA    Resume at address AA..AA with signal   SNN * *    s             Step one instruction                   SNN *    sAA..AA       Step one instruction from AA..AA       SNN *    SNN;          Step one instruction with signal       SNN *    SNNAA..AA     Step one instruction from AA..AA w/NN  SNN * *    k             kill (Detach GDB) * *    d             Toggle debug flag *    D             Detach GDB * *    Hct           Set thread t for operations,           OK or ENN *                  c = 'c' (step, cont), c = 'g' (other *                  operations) * *    qC            Query current thread ID                QCpid *    qfThreadInfo  Get list of current threads (first)    m<id> *    qsThreadInfo   "    "  "     "      "   (subsequent) *    qOffsets      Get section offsets                  Text=x;Data=y;Bss=z * *    TXX           Find if thread XX is alive             OK or ENN *    ?             What was the last sigval ?             SNN   (signal NN) *    O             Output to GDB console * * All commands and responses are sent with a packet which includes a * checksum.  A packet consists of * * $<packet info>#<checksum>. * * where * <packet info> :: <characters representing the command or response> * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>> * * When a packet is received, it is first acknowledged with either '+' or '-'. * '+' indicates a successful transfer.  '-' indicates a failed transfer. * * Example: * * Host:                  Reply: * $m0,10#2a               +$00010203040506070809101112131415#42 * ****************************************************************************//* * * Remote communication protocol. * *    A debug packet whose contents are <data> is encapsulated for *    transmission in the form: * *       $ <data> # CSUM1 CSUM2 * *       <data> must be ASCII alphanumeric and cannot include characters *       '$' or '#'.  If <data> starts with two characters followed by *       ':', then the existing stubs interpret this as a sequence number. * *       CSUM1 and CSUM2 are ascii hex representation of an 8-bit *       checksum of <data>, the most significant nibble is sent first. *       the hex digits 0-9,a-f are used. * *    Receiver responds with: * *       +       - if CSUM is correct and ready for next packet *       -       - if CSUM is incorrect * * Responses can be run-length encoded to save space.  A '*' means that * the next character is an ASCII encoding giving a repeat count which * stands for that many repititions of the character preceding the '*'. * The encoding is n+29, yielding a printable character where n >=3 * (which is where RLE starts to win).  Don't use an n > 126. * * So "0* " means the same as "0000". *//* * ARM port Copyright (c) 2002 MontaVista Software, Inc * * Authors:  George Davis <davis_g@mvista.com> *          Deepak Saxena <dsaxena@mvista.com> * * * See Documentation/ARM/kgdb for information on porting to a new board * * tabstop=3 to make this readable */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/spinlock.h>#include <linux/personality.h>#include <linux/ptrace.h>#include <linux/elf.h>#include <linux/interrupt.h>#include <linux/init.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/unistd.h>#include <asm/kgdb.h>#ifdef CONFIG_MAGIC_SYSRQ#include <linux/sysrq.h>#endif#ifdef	CONFIG_DEBUG_LL// #define printascii(x, args...)  printk(x, ## args)// #undef printascii// #define printascii(x, args...)extern void printascii(const char *);extern void printhex8(unsigned int);#else#define	printascii(s)#define	printhex8(i)#endif#define GDB_MAXREGS	(16 + 8 * 3 + 1 + 1)#define GDB_REGBYTES	(GDB_MAXREGS << 2)#define BUFMAX 2048#define PC_REGNUM	0x0f#define	LR_REGNUM	0x0e#define	SP_REGNUM	0x0d/* External functions */extern struct pt_regs *get_task_registers(const struct task_struct *);/* Forward declarations */static unsigned long get_next_pc(struct pt_regs *);/* Globals */int kgdb_fault_expected = 0;	/* Boolean to ignore bus errs (i.e. in GDB) */int kgdb_enabled = 0;/* Locals */static char remote_debug = 0;static const char hexchars[]="0123456789abcdef";static int fault_jmp_buf[32]; /* Jump buffer for kgdb_setjmp/longjmp */static char remcomInBuffer[BUFMAX];static char remcomOutBuffer[BUFMAX];static int kgdb_initialized = 0;static volatile unsigned int *step_addr = NULL;static unsigned int step_instr = 0;static struct pt_regs kgdb_regs;static unsigned int gdb_regs[GDB_MAXREGS];#ifdef CONFIG_KGDB_THREADstatic struct task_struct *trapped_thread;static struct task_struct *current_thread;typedef unsigned char threadref[8];#define BUF_THREAD_ID_SIZE 16#endif/* * Various conversion functions */static int hex(unsigned char ch){  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);  if ((ch >= '0') && (ch <= '9')) return (ch-'0');  if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);  return (-1);}static unsigned char * mem2hex(const char *mem, char *buf, int count){	/* Accessing 16-bit and 32-bit objects in a single	 * load instruction is required to avoid bad side	 * effects for some IO registers.	 */	if ((count == 2) && (((long)mem & 1) == 0)) {		unsigned short tmp_s =			cpu_to_be16(*(unsigned short *)mem);		mem += 2;		*buf++ = hexchars[(tmp_s >> 12) & 0xf];		*buf++ = hexchars[(tmp_s >> 8) & 0xf];		*buf++ = hexchars[(tmp_s >> 4) & 0xf];		*buf++ = hexchars[tmp_s & 0xf];	} else if ((count == 4) && (((long)mem & 3) == 0)) {		unsigned int tmp_l =			cpu_to_be32(*(unsigned int *)mem);		mem += 4;		*buf++ = hexchars[(tmp_l >> 28) & 0xf];		*buf++ = hexchars[(tmp_l >> 24) & 0xf];		*buf++ = hexchars[(tmp_l >> 20) & 0xf];		*buf++ = hexchars[(tmp_l >> 16) & 0xf];		*buf++ = hexchars[(tmp_l >> 12) & 0xf];		*buf++ = hexchars[(tmp_l >> 8) & 0xf];		*buf++ = hexchars[(tmp_l >> 4) & 0xf];		*buf++ = hexchars[tmp_l & 0xf];	} else {		unsigned char ch;		while (count-- > 0) {			ch = *mem++;			*buf++ = hexchars[ch >> 4];			*buf++ = hexchars[ch & 0xf];		}	}	*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. */static char * hex2mem(char *buf, char *mem, int count){	/* Accessing 16-bit and 32-bit objects in a single	 * store instruction is required to avoid bad side	 * effects for some IO registers.	 */	if ((count == 2) && (((long)mem & 1) == 0)) {		unsigned short tmp_s =			hex(*buf++) << 12;		tmp_s |= hex(*buf++) << 8;		tmp_s |= hex(*buf++) << 4;		tmp_s |= hex(*buf++);		*(unsigned short *)mem = be16_to_cpu(tmp_s);		mem += 2;	} else if ((count == 4) && (((long)mem & 3) == 0)) {		unsigned int tmp_l =			hex(*buf++) << 28;		tmp_l |= hex(*buf++) << 24;		tmp_l |= hex(*buf++) << 20;		tmp_l |= hex(*buf++) << 16;		tmp_l |= hex(*buf++) << 12;		tmp_l |= hex(*buf++) << 8;		tmp_l |= hex(*buf++) << 4;		tmp_l |= hex(*buf++);		*(unsigned int *)mem = be32_to_cpu(tmp_l);		mem += 4;	} else {		int i;		unsigned char ch;		for (i=0; i<count; i++) {			ch = hex(*buf++) << 4;			ch |= hex(*buf++);			*mem++ = ch;		}	}	return mem;}/*  Copy the binary array pointed to by buf into mem.  Fix $, #,    and 0x7d escaped with 0x7d.  Return a pointer to the character    after the last byte written. */static char *ebin2mem(const char *buf, char *mem, int count){	for (; count > 0; count--, buf++) {		if (*buf == 0x7d)			*mem++ = *(++buf) ^ 0x20;		else			*mem++ = *buf;	}	return mem;}/* * While we find nice hex chars, build an int. * Return number of chars processed. */static int hex2int(char **ptr, int *intValue){	int numChars = 0;	int hexValue;	*intValue = 0;	while (**ptr) {		hexValue = hex(**ptr);		if (hexValue < 0)			break;		*intValue = (*intValue << 4) | hexValue;		numChars ++;		(*ptr)++;	}	return (numChars);}/* Make a local copy of the registers passed into the handler (bletch) */static void kregs2gregs(const struct pt_regs *kregs, int *gregs){	int regno;	/* Initialize to zero */	for (regno = 0; regno < GDB_MAXREGS; regno++)		gregs[regno] = 0;	gregs[0] = kregs->ARM_r0;	gregs[1] = kregs->ARM_r1;	gregs[2] = kregs->ARM_r2;	gregs[3] = kregs->ARM_r3;	gregs[4] = kregs->ARM_r4;	gregs[5] = kregs->ARM_r5;	gregs[6] = kregs->ARM_r6;	gregs[7] = kregs->ARM_r7;	gregs[8] = kregs->ARM_r8;	gregs[9] = kregs->ARM_r9;	gregs[10] = kregs->ARM_r10;	gregs[11] = kregs->ARM_fp;	gregs[12] = kregs->ARM_ip;	gregs[13] = kregs->ARM_sp;	gregs[14] = kregs->ARM_lr;	gregs[15] = kregs->ARM_pc;	gregs[GDB_MAXREGS - 1] = kregs->ARM_cpsr;}/* Copy local gdb registers back to kgdb regs, for later copy to kernel */static void gregs2kregs(const int *gregs, struct pt_regs *kregs){	kregs->ARM_r0 = gregs[0];	kregs->ARM_r1 = gregs[1];	kregs->ARM_r2 = gregs[2];	kregs->ARM_r3 = gregs[3];	kregs->ARM_r4 = gregs[4];	kregs->ARM_r5 = gregs[5];	kregs->ARM_r6 = gregs[6];	kregs->ARM_r7 = gregs[7];	kregs->ARM_r8 = gregs[8];	kregs->ARM_r9 = gregs[9];	kregs->ARM_r10 = gregs[10];	kregs->ARM_fp = gregs[11];	kregs->ARM_ip = gregs[12];	kregs->ARM_sp = gregs[13];	kregs->ARM_lr = gregs[14];	kregs->ARM_pc = gregs[15];	kregs->ARM_cpsr = gregs[GDB_MAXREGS - 1];}#ifdef CONFIG_KGDB_THREAD/* Make a local copy of registers from the specified thread */static void tregs2gregs(const struct task_struct *task, int *gregs){	int regno;	struct pt_regs *tregs;	/* Initialize to zero */	for (regno = 0; regno < GDB_MAXREGS; regno++)		gregs[regno] = 0;	/* Just making sure... */	if (task == NULL)		return;#if	0 /* REVISIT */	/* A new fork has pt_regs on the stack from a fork() call */	if (task->thread->save.pc == (unsigned long)ret_from_fork) {		struct pt_regs *tregs;		kregs = (struct pt_regs*)task->thread->save;		gregs[0] = tregs->ARM_r0;		gregs[1] = tregs->ARM_r1;		gregs[2] = tregs->ARM_r2;		gregs[3] = tregs->ARM_r3;		gregs[4] = tregs->ARM_r4;		gregs[5] = tregs->ARM_r5;		gregs[6] = tregs->ARM_r6;		gregs[7] = tregs->ARM_r7;		gregs[8] = tregs->ARM_r8;		gregs[9] = tregs->ARM_r9;		gregs[10] = tregs->ARM_r10;		gregs[11] = tregs->ARM_fp;		gregs[12] = tregs->ARM_ip;		gregs[13] = tregs->ARM_sp;		gregs[14] = tregs->ARM_lr;		gregs[15] = tregs->ARM_pc;		gregs[GDB_MAXREGS - 1] = tregs->ARM_cpsr;	}#endif	/* Otherwise, we have only some registers from switch_to() */	tregs = get_task_registers(task);	gregs[0] = tregs->ARM_r0; /* Not really valid? */	gregs[1] = tregs->ARM_r1; /* "               " */	gregs[2] = tregs->ARM_r2; /* "               " */	gregs[3] = tregs->ARM_r3; /* "               " */	gregs[4] = tregs->ARM_r4;	gregs[5] = tregs->ARM_r5;	gregs[6] = tregs->ARM_r6;	gregs[7] = tregs->ARM_r7;	gregs[8] = tregs->ARM_r8;	gregs[9] = tregs->ARM_r9;	gregs[10] = tregs->ARM_r10;	gregs[11] = tregs->ARM_fp;	gregs[12] = tregs->ARM_ip;	gregs[13] = tregs->ARM_sp;	gregs[14] = tregs->ARM_lr;	gregs[15] = tregs->ARM_pc;	gregs[GDB_MAXREGS - 1] = tregs->ARM_cpsr;}static char * pack_hex_byte(char *pkt, int byte){	*pkt++ = hexchars[(byte >> 4) & 0xf];	*pkt++ = hexchars[(byte & 0xf)];	return pkt;}static char * pack_threadid(char *pkt, threadref * id){	char *limit;	unsigned char *altid;	altid = (unsigned char *) id;	limit = pkt + BUF_THREAD_ID_SIZE;	while (pkt < limit)		pkt = pack_hex_byte(pkt, *altid++);	return pkt;}static void int_to_threadref(threadref * id, const int value){	unsigned char *scan = (unsigned char *) id;	int i = 4;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -