📄 rtl-stub.c
字号:
/* * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * RTLinux Debugger modifications are written by Michael Barabanov * (baraban@fsmlabs.com) and * are Copyright (C) 2000, Finite State Machine Labs Inc. * */ /**************************************************************************** * 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 $ * Updated by: David Grothe <dave@gcom.com> * ModuleState: Experimental $ * * NOTES: See Below $ * * Modified for 386 by Jim Kingdon, Cygnus Support. * Compatibility with 2.1.xx kernel by David Grothe <dave@gcom.com> * Integrated into 2.2.5 kernel by Tigran Aivazian <tigran@sco.com> * Modified for RTLinux by Michael Barabanov (baraban@fsmlabs.com) * * 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 an int 3. * ************* * * 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) * * 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 <linux/kernel.h>#include <asm/vm86.h>#include <asm/system.h>#include <asm/ptrace.h> /* for linux pt_regs struct */#include <linux/signal.h>/* RTLinux support */#define __NO_VERSION__#include <linux/module.h>#include <rtl_sync.h>#include <rtl_sched.h>#define strtoul simple_strtoul#include <psc.h>#define rtl_running_linux() (pthread_self() == &LOCAL_SCHED->rtl_linux_task)int rtl_debug_initialized = 0;/* end of RTLinux support *//************************************************************************ * * 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 *//************************************************************************//* BUFMAX defines the maximum number of characters in inbound/outbound buffers*//* at least NUMREGBYTES*2 are needed for register packets */#define BUFMAX 800static int remote_debug = 0;/* debug > 0 prints ill-formed commands in valid packets & checksum errors */static const char hexchars[]="0123456789abcdef";/* Number of bytes of registers. */#define NUMREGBYTES 64/* * Note that this register image is in a different order than * the register image that Linux produces at interrupt time. * * Linux's register image is defined by struct pt_regs in ptrace.h. * Just why GDB uses a different order is a historical mystery. */enum regnames {_EAX, /* 0 */ _ECX, /* 1 */ _EDX, /* 2 */ _EBX, /* 3 */ _ESP, /* 4 */ _EBP, /* 5 */ _ESI, /* 6 */ _EDI, /* 7 */ _PC /* 8 also known as eip */, _PS /* 9 also known as eflags */, _CS, /* 10 */ _SS, /* 11 */ _DS, /* 12 */ _ES, /* 13 */ _FS, /* 14 */ _GS}; /* 15 *//*************************** ASSEMBLY CODE MACROS *************************//* *//* Put the error code here just in case the user cares. */int gdb_i386errcode;/* Likewise, the vector number here (since GDB only gets the signal number through the usual means, and that's not very specific). */int gdb_i386vector = -1;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> */void getpacket(char * buffer){ unsigned char checksum; unsigned char xmitcsum; int i; int count; 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 ((remote_debug ) && (checksum != xmitcsum)) { printk ("bad checksum. My count = 0x%x, sent=0x%x. buf=%s\n", checksum,xmitcsum,buffer); } if (checksum != xmitcsum) putDebugChar('-'); /* failed checksum */ else { putDebugChar('+'); /* successful transfer */ /* 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 (remote_debug) printk("R:%s\n", buffer) ;}/* send the packet in buffer. */void putpacket(char * buffer){ unsigned char checksum; int count; char ch; /* $<packet info>#<checksum>. */ do { if (remote_debug) printk("T:%s\n", buffer) ; 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 char remcomInBuffer[BUFMAX];static char remcomOutBuffer[BUFMAX];static short error;void debug_error( char * format, char * parm){ if (remote_debug) printk (format,parm);}static void print_regs(struct pt_regs *regs){ printk("EAX=%08lx ", regs->eax); printk("EBX=%08lx ", regs->ebx); printk("ECX=%08lx ", regs->ecx); printk("EDX=%08lx ", regs->edx); printk("\n"); printk("ESI=%08lx ", regs->esi); printk("EDI=%08lx ", regs->edi); printk("EBP=%08lx ", regs->ebp); printk("ESP=%08lx ", (long) (regs+1)); printk("\n"); printk(" DS=%08x ", regs->xds); printk(" ES=%08x ", regs->xes); printk(" SS=%08x ", __KERNEL_DS); printk(" FL=%08lx ", regs->eflags); printk("\n"); printk(" CS=%08x ", regs->xcs); printk(" IP=%08lx ", regs->eip);#if 0 printk(" FS=%08x ", regs->fs); printk(" GS=%08x ", regs->gs);#endif printk("\n");} /* print_regs */static void regs_to_gdb_regs(int *gdb_regs, struct pt_regs *regs){ gdb_regs[_EAX] = regs->eax; gdb_regs[_EBX] = regs->ebx; gdb_regs[_ECX] = regs->ecx; gdb_regs[_EDX] = regs->edx; gdb_regs[_ESI] = regs->esi; gdb_regs[_EDI] = regs->edi; gdb_regs[_EBP] = regs->ebp; gdb_regs[ _DS] = regs->xds; gdb_regs[ _ES] = regs->xes; gdb_regs[ _PS] = regs->eflags; gdb_regs[ _CS] = regs->xcs; gdb_regs[ _PC] = regs->eip; gdb_regs[_ESP] = (int) (®s->esp) ; gdb_regs[ _SS] = __KERNEL_DS; gdb_regs[ _FS] = 0xFFFF; gdb_regs[ _GS] = 0xFFFF;} /* regs_to_gdb_regs */static void gdb_regs_to_regs(int *gdb_regs, struct pt_regs *regs){ regs->eax = gdb_regs[_EAX] ; regs->ebx = gdb_regs[_EBX] ; regs->ecx = gdb_regs[_ECX] ; regs->edx = gdb_regs[_EDX] ; regs->esi = gdb_regs[_ESI] ; regs->edi = gdb_regs[_EDI] ; regs->ebp = gdb_regs[_EBP] ; regs->xds = gdb_regs[ _DS] ; regs->xes = gdb_regs[ _ES] ; regs->eflags= gdb_regs[ _PS] ; regs->xcs = gdb_regs[ _CS] ; regs->eip = gdb_regs[ _PC] ;#if 0 /* can't change these */ regs->esp = gdb_regs[_ESP] ; regs->xss = gdb_regs[ _SS] ; regs->fs = gdb_regs[ _FS] ; regs->gs = gdb_regs[ _GS] ;#endif} /* gdb_regs_to_regs *//* 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()])static int garbage_loc = -1 ;intget_char (char *addr){ return *addr;}voidset_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), in case of mem fault, * return 0. */char* mem2hex( char* mem, char* buf, int count) { int i; unsigned char ch; int may_fault = 1; if (may_fault) { mem_err_expected = 1 ; mem_err = 0 ; } for (i=0;i<count;i++) { /* printk("%lx = ", mem) ; */ ch = get_char (mem++); /* printk("%02x\n", ch & 0xFF) ; */ 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 % 16]; } *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 */char* hex2mem( char* buf, char* mem, int count){ int i; unsigned char ch; int may_fault = 1; if (may_fault) { mem_err_expected = 1 ; mem_err = 0 ; } for (i=0;i<count;i++) { ch = hex(*buf++) << 4; ch = ch + hex(*buf++); set_char (mem++, ch); if (may_fault && mem_err) { if (remote_debug) printk("Mem fault storing to addr %lx\n", (long)(mem-1)); return 0; } } if (may_fault) mem_err_expected = 0 ; return(mem);}/**********************************************//* WHILE WE FIND NICE HEX CHARS, BUILD AN INT *//* RETURN NUMBER OF CHARS PROCESSED *//**********************************************/int hexToInt(char **ptr, int *intValue){ int numChars = 0; int hexValue; *intValue = 0; while (**ptr) { hexValue = hex(**ptr); if (hexValue >=0) { *intValue = (*intValue <<4) | hexValue; numChars ++; } else break; (*ptr)++; } return (numChars);}/* * This function does all command procesing for interfacing to gdb. * * NOTE: The INT nn instruction leaves the state of the interrupt * enable flag UNCHANGED. That means that when this routine * is entered via a breakpoint (INT 3) instruction from code * that has interrupts enabled, then interrupts will STILL BE * enabled when this routine is entered. The first thing that * we do here is disable interrupts so as to prevent recursive * entries and bothersome serial interrupts while we are * trying to run the serial port in polled mode. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -