📄 rtl-stub.c
字号:
/* rtl-stub.c for Alpha, originally taken from alpha-gdbstub.c and modified to * work with RTLinux debugger. See comments below. * * RTLinux Debugger modifications are written by Nathan Paul Simons and are * (C) Finite State Machine Labs Inc. 2000 business@fsmlabs.com * * Released under the terms of GPL 2. * Open RTLinux makes use of a patented process described in * US Patent 5,995,745. Use of this process is governed * by the Open RTLinux Patent License which can be obtained from * www.fsmlabs.com/PATENT or by sending email to * licensequestions@fsmlabs.com *//**************************************************************************** THIS SOFTWARE IS NOT COPYRIGHTED HP offers the following for use in the public domain. HP makes no warranty with regard to the software or its performance and the user accepts the software "AS IS" with all faults. HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.****************************************************************************//**************************************************************************** * 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 FreeBSD by Stu Grossman. * * 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. * Also, need to assign exceptionHook and oldExceptionHook. * * 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 its 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 * * c Resume at current address SNN ( signal NN) * cAA..AA Continue at address AA..AA SNN * * s Step one instruction SNN * sAA..AA Step one instruction from AA..AA SNN * * k kill * * ? What was the last sigval ? SNN (signal NN) * * D detach OK * * 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 * ****************************************************************************/#include <linux/string.h>#include <asm/system.h>#include <asm/ptrace.h> /* for linux pt_regs struct */#include <asm/reg.h> /* for EF_* reg num defines */#include <asm/gentrap.h> /* for GEN_* trap num defines */#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/signal.h>/* RTLinux support */#define __NO_VERSION__#include <linux/module.h>#include <rtl_sync.h>#include <rtl_sched.h>#include <psc.h>#include <rtl_ex.c>#define strtoul simple_strtoul#define rtl_running_linux() (pthread_self() == &LOCAL_SCHED->rtl_linux_task)int rtl_debug_initialized = 0;/* end of RTLinux support *//* Indicate to caller of mem2hex or hex2mem that there has been an error. */static volatile int real_mem_err[NR_CPUS];static volatile int real_mem_err_expected[NR_CPUS];#define mem_err (real_mem_err[rtl_getcpuid()])#define mem_err_expected (real_mem_err_expected[rtl_getcpuid()])/* external low-level support routines */typedef void (*Function) (void); /* pointer to a function */extern int putDebugChar(int); /* write a single character */extern int getDebugChar(void); /* read and return a single char */extern int rtl_request_traps(int (*rtl_exception_intercept) (int vector, struct pt_regs * regs));/* ripped from arch/alpha/kernel/process.c * XXX we should probably just export show_regs and use the pre-exisiting * one to cut down on code size -Nathan */void show_regs(struct pt_regs *regs){ printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc); printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs + 1); printk(" r0: %016lx r1: %016lx r2: %016lx r3: %016lx\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" r4: %016lx r5: %016lx r6: %016lx r7: %016lx\n", regs->r4, regs->r5, regs->r6, regs->r7); printk(" r8: %016lx r16: %016lx r17: %016lx r18: %016lx\n", regs->r8, regs->r16, regs->r17, regs->r18); printk("r19: %016lx r20: %016lx r21: %016lx r22: %016lx\n", regs->r19, regs->r20, regs->r21, regs->r22); printk("r23: %016lx r24: %016lx r25: %016lx r26: %016lx\n", regs->r23, regs->r24, regs->r25, regs->r26); printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n", regs->r27, regs->r28, regs->gp, regs->hae);}/* BUFMAX defines the maximum number of characters in inbound/outbound buffers * at least NUMREGBYTES*2 are needed for register packets */#define BUFMAX 1500int remote_debug = 0;static const char hexchars[] = "0123456789abcdef";static int hex(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);}/* scan for the sequence $<data>#<checksum> */static void getpacket(char *buffer){ unsigned char checksum; unsigned char xmitcsum; int i; int count; unsigned char ch; do { /* wait around for the start character, ignore all other * characters */ while ((ch = (getDebugChar() & 0x7f)) != '$'); checksum = 0; xmitcsum = -1; count = 0; /* now, read until a # or end of buffer is found */ while (count < BUFMAX) { ch = getDebugChar() & 0x7f; if (ch == '#') break; checksum = checksum + ch; buffer[count] = ch; count = count + 1; } buffer[count] = 0; if (ch == '#') { xmitcsum = hex(getDebugChar() & 0x7f) << 4; xmitcsum += hex(getDebugChar() & 0x7f); if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */ else { putDebugChar('+'); /* successful xfer */ /* if a sequence char is present, reply the * sequence ID */ if (buffer[2] == ':') { putDebugChar(buffer[0]); putDebugChar(buffer[1]); /* remove sequence chars from buffer */ count = strlen(buffer); for (i = 3; i <= count; i++) buffer[i - 3] = buffer[i]; } } } } while (checksum != xmitcsum); if (strlen(buffer) >= BUFMAX) panic("kgdb: buffer overflow");} /* static void getpacket(char *buffer) *//* send the packet in buffer. */static void putpacket(char *buffer){ unsigned char checksum; int count; unsigned char ch; if (strlen(buffer) >= BUFMAX) panic("kgdb: buffer overflow"); /* $<packet info>#<checksum>. */ do { putDebugChar('$'); checksum = 0; count = 0; while ((ch = buffer[count])) { if (!putDebugChar(ch)) return; checksum += ch; count += 1; } putDebugChar('#'); putDebugChar(hexchars[checksum >> 4]); putDebugChar(hexchars[checksum % 16]); } while ((getDebugChar() & 0x7f) != '+');} /* static void putpacket(char *buffer) */int get_char(char *addr){ return *addr;}void set_char(char *addr, int val){ *addr = val;}/* convert the memory pointed to by mem into hex, placing result in buf *//* return a pointer to the last char put in buf (null) */static char *mem2hex(char *mem, char *buf, int count){ unsigned char ch; int may_fault = 1; if (mem == 0) { strcpy(buf, "E03"); return buf; } if (may_fault) { mem_err_expected = 1; mem_err = 0; } while (count-- > 0) { ch = *mem++; if (may_fault && mem_err) { if (remote_debug) printk ("Mem fault fetching from addr %lx\n", (long) (mem - 1)); *buf = 0; /* truncate buffer */ return 0; } *buf++ = hexchars[ch >> 4]; *buf++ = hexchars[ch & 0xf]; } *buf = 0; if (may_fault) mem_err_expected = 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){ unsigned char ch; while (count-- > 0) { ch = hex(*buf++) << 4; ch = ch + hex(*buf++); set_char(mem++, ch); } return mem;}/* * While we find nice hex chars, build an int. * Return number of chars processed. */static long hexToInt(char **ptr, long *intValue){ long numChars = 0; long hexValue; *intValue = 0; while (**ptr) { hexValue = hex(**ptr); if (hexValue >= 0) { *intValue = (*intValue << 4) | hexValue; numChars++; } else break; (*ptr)++; } return (numChars);}/* more RTLinux support */static spinlock_t bp_lock = SPIN_LOCK_UNLOCKED;#define RTL_MAX_BP 1024static struct bp_cache_entry { char *mem; unsigned char val; struct bp_cache_entry *next;} bp_cache[RTL_MAX_BP];static struct bp_cache_entry *cache_start = 0;int insert_bp(char *mem){ int i; struct bp_cache_entry *e; int old; char buf[3]; if (!mem2hex(mem, buf, 1)) { return EINVAL; /* memory error */ } old = strtoul(buf, 0, 16); for (e = cache_start; e; e = e->next) { if (e->mem == mem) { return EINVAL; /* already there */ } } for (i = 0; i < RTL_MAX_BP; i++) { if (bp_cache[i].mem == 0) { break; } } if (i == RTL_MAX_BP) { return EINVAL; /* no space */ } bp_cache[i].val = old; bp_cache[i].mem = mem; bp_cache[i].next = cache_start; cache_start = &bp_cache[i]; set_char(mem, 0xcc); return 0;}#define CONFIG_RTL_DEBUGGER_THREADS#define CONFIG_RTL_DEBUGGER_Z_PROTOCOLstatic int send_exception_info = 0;static char remcomInBuffer[BUFMAX];static char remcomOutBuffer[BUFMAX];static short error;void debug_error(char *format, char *parm){ if (remote_debug) printk(format, parm);}/* Alpha registers are 64 bit wide, so 8 bytes to a register, times 66 * registers we need to keep track of */#define NUMREGS 66#define BYTESPERREG 8#define NUMREGBYTES (BYTESPERREG * NUMREGS)int remove_bp(char *mem){ struct bp_cache_entry *e = cache_start; struct bp_cache_entry *f = 0; if (!e) { return EINVAL; } if (e->mem == mem) { cache_start = e->next; f = e; } else { for (; e->next; e = e->next) { if (e->next->mem == mem) { f = e->next; e->next = f->next; break; } } } if (!f) { return EINVAL; } mem_err_expected = 1; set_char(f->mem, f->val); if (mem_err) { return EINVAL; } mem_err_expected = 0; return 0;} /* int remove_bp(char *mem) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -