📄 kgdb.c
字号:
/*!***************************************************************************!*! FILE NAME : kgdb.c*!*! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100.*! It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c.*!*!---------------------------------------------------------------------------*! HISTORY*!*! DATE NAME CHANGES*! ---- ---- -------*! Apr 26 1999 Hendrik Ruijter Initial version.*! May 6 1999 Hendrik Ruijter Removed call to strlen in libc and removed*! struct assignment as it generates calls to*! memcpy in libc.*! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'.*! Jul 21 1999 Bjorn Wesen eLinux port*!*! $Log: kgdb.c,v $*! Revision 1.4 2003/04/09 05:20:44 starvik*! Merge of Linux 2.5.67*!*! Revision 1.3 2003/01/21 19:11:08 starvik*! Modified include path for new dir layout*!*! Revision 1.2 2002/11/19 14:35:24 starvik*! Changes from linux 2.4*! Changed struct initializer syntax to the currently prefered notation*!*! Revision 1.1 2001/12/17 13:59:27 bjornw*! Initial revision*!*! Revision 1.6 2001/10/09 13:10:03 matsfg*! Added $ on registers and removed some underscores*!*! Revision 1.5 2001/04/17 13:58:39 orjanf*! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB.*!*! Revision 1.4 2001/02/23 13:45:19 bjornw*! config.h check*!*! Revision 1.3 2001/01/31 18:08:23 orjanf*! Removed kgdb_handle_breakpoint from being the break 8 handler.*!*! Revision 1.2 2001/01/12 14:22:25 orjanf*! Updated kernel debugging support to work with ETRAX 100LX.*!*! Revision 1.1 2000/07/10 16:25:21 bjornw*! Initial revision*!*! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw*! * Initial version of arch/cris, the latest CRIS architecture with an MMU.*! Mostly copied from arch/etrax100 with appropriate renames of files.*! The mm/ subdir is copied from arch/i386.*! This does not compile yet at all.*!*!*! Revision 1.4 1999/07/22 17:25:25 bjornw*! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors.*!*! Revision 1.3 1999/07/21 19:51:18 bjornw*! Check if the interrupting char is a ctrl-C, ignore otherwise.*!*! Revision 1.2 1999/07/21 18:09:39 bjornw*! Ported to eLinux architecture, and added some kgdb documentation.*!*!*!---------------------------------------------------------------------------*!*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $*!*! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN*!*!**************************************************************************//* @(#) cris_stub.c 1.3 06/17/99 *//* * kgdb usage notes: * ----------------- * * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be * built with different gcc flags: "-g" is added to get debug infos, and * "-fomit-frame-pointer" is omitted to make debugging easier. Since the * resulting kernel will be quite big (approx. > 7 MB), it will be stripped * before compresion. Such a kernel will behave just as usually, except if * given a "debug=<device>" command line option. (Only serial devices are * allowed for <device>, i.e. no printers or the like; possible values are * machine depedend and are the same as for the usual debug device, the one * for logging kernel messages.) If that option is given and the device can be * initialized, the kernel will connect to the remote gdb in trap_init(). The * serial parameters are fixed to 8N1 and 115200 bps, for easyness of * implementation. * * To start a debugging session, start that gdb with the debugging kernel * image (the one with the symbols, vmlinux.debug) named on the command line. * This file will be used by gdb to get symbol and debugging infos about the * kernel. Next, select remote debug mode by * target remote <device> * where <device> is the name of the serial device over which the debugged * machine is connected. Maybe you have to adjust the baud rate by * set remotebaud <rate> * or also other parameters with stty: * shell stty ... </dev/... * If the kernel to debug has already booted, it waited for gdb and now * connects, and you'll see a breakpoint being reported. If the kernel isn't * running yet, start it now. The order of gdb and the kernel doesn't matter. * Another thing worth knowing about in the getting-started phase is how to * debug the remote protocol itself. This is activated with * set remotedebug 1 * gdb will then print out each packet sent or received. You'll also get some * messages about the gdb stub on the console of the debugged machine. * * If all that works, you can use lots of the usual debugging techniques on * the kernel, e.g. inspecting and changing variables/memory, setting * breakpoints, single stepping and so on. It's also possible to interrupt the * debugged kernel by pressing C-c in gdb. Have fun! :-) * * The gdb stub is entered (and thus the remote gdb gets control) in the * following situations: * * - If breakpoint() is called. This is just after kgdb initialization, or if * a breakpoint() call has been put somewhere into the kernel source. * (Breakpoints can of course also be set the usual way in gdb.) * In eLinux, we call breakpoint() in init/main.c after IRQ initialization. * * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel() * are entered. All the CPU exceptions are mapped to (more or less..., see * the hard_trap_info array below) appropriate signal, which are reported * to gdb. die_if_kernel() is usually called after some kind of access * error and thus is reported as SIGSEGV. * * - When panic() is called. This is reported as SIGABRT. * * - If C-c is received over the serial line, which is treated as * SIGINT. * * Of course, all these signals are just faked for gdb, since there is no * signal concept as such for the kernel. It also isn't possible --obviously-- * to set signal handlers from inside gdb, or restart the kernel with a * signal. * * Current limitations: * * - While the kernel is stopped, interrupts are disabled for safety reasons * (i.e., variables not changing magically or the like). But this also * means that the clock isn't running anymore, and that interrupts from the * hardware may get lost/not be served in time. This can cause some device * errors... * * - When single-stepping, only one instruction of the current thread is * executed, but interrupts are allowed for that time and will be serviced * if pending. Be prepared for that. * * - All debugging happens in kernel virtual address space. There's no way to * access physical memory not mapped in kernel space, or to access user * space. A way to work around this is using get_user_long & Co. in gdb * expressions, but only for the current process. * * - Interrupting the kernel only works if interrupts are currently allowed, * and the interrupt of the serial line isn't blocked by some other means * (IPL too high, disabled, ...) * * - The gdb stub is currently not reentrant, i.e. errors that happen therein * (e.g. accessing invalid memory) may not be caught correctly. This could * be removed in future by introducing a stack of struct registers. * *//* * To enable debugger support, two things need to happen. One, a * call to kgdb_init() 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(). * * 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) * * bBB..BB Set baud rate to BB..BB OK or BNN, then sets * baud rate * * 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/signal.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/linkage.h>#include <asm/setup.h>#include <asm/ptrace.h>#include <asm/arch/svinto.h>#include <asm/irq.h>static int kgdb_started = 0;/********************************* Register image ****************************//* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's Reference", p. 1-1, with the additional register definitions of the ETRAX 100LX in cris-opc.h. There are 16 general 32-bit registers, R0-R15, where R14 is the stack pointer, SP, and R15 is the program counter, PC. There are 16 special registers, P0-P15, where three of the unimplemented registers, P0, P4 and P8, are reserved as zero-registers. A read from any of these registers returns zero and a write has no effect. */typedefstruct register_image{ /* Offset */ unsigned int r0; /* 0x00 */ unsigned int r1; /* 0x04 */ unsigned int r2; /* 0x08 */ unsigned int r3; /* 0x0C */ unsigned int r4; /* 0x10 */ unsigned int r5; /* 0x14 */ unsigned int r6; /* 0x18 */ unsigned int r7; /* 0x1C */ unsigned int r8; /* 0x20 Frame pointer */ unsigned int r9; /* 0x24 */ unsigned int r10; /* 0x28 */ unsigned int r11; /* 0x2C */ unsigned int r12; /* 0x30 */ unsigned int r13; /* 0x34 */ unsigned int sp; /* 0x38 Stack pointer */ unsigned int pc; /* 0x3C Program counter */ unsigned char p0; /* 0x40 8-bit zero-register */ unsigned char vr; /* 0x41 Version register */ unsigned short p4; /* 0x42 16-bit zero-register */ unsigned short ccr; /* 0x44 Condition code register */ unsigned int mof; /* 0x46 Multiply overflow register */ unsigned int p8; /* 0x4A 32-bit zero-register */ unsigned int ibr; /* 0x4E Interrupt base register */ unsigned int irp; /* 0x52 Interrupt return pointer */ unsigned int srp; /* 0x56 Subroutine return pointer */ unsigned int bar; /* 0x5A Breakpoint address register */ unsigned int dccr; /* 0x5E Double condition code register */ unsigned int brp; /* 0x62 Breakpoint return pointer (pc in caller) */ unsigned int usp; /* 0x66 User mode stack pointer */} registers;/************** Prototypes for local library functions ***********************//* Copy of strcpy from libc. */static char *gdb_cris_strcpy (char *s1, const char *s2);/* Copy of strlen from libc. */static int gdb_cris_strlen (const char *s);/* Copy of memchr from libc. */static void *gdb_cris_memchr (const void *s, int c, int n);/* Copy of strtol from libc. Does only support base 16. */static int gdb_cris_strtol (const char *s, char **endptr, int base);/********************** Prototypes for local functions. **********************//* Copy the content of a register image into another. The size n is the size of the register image. Due to struct assignment generation of memcpy in libc. */static void copy_registers (registers *dptr, registers *sptr, int n);/* Copy the stored registers from the stack. Put the register contents of thread thread_id in the struct reg. */static void copy_registers_from_stack (int thread_id, registers *reg);/* Copy the registers to the stack. Put the register contents of thread thread_id from struct reg to the stack. */static void copy_registers_to_stack (int thread_id, registers *reg);/* Write a value to a specified register regno in the register image of the current thread. */static int write_register (int regno, char *val);/* Write a value to a specified register in the stack of a thread other than the current thread. */static write_stack_register (int thread_id, int regno, char *valptr);/* Read a value from a specified register in the register image. Returns the status of the read operation. The register value is returned in valptr. */static int read_register (char regno, unsigned int *valptr);/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */int getDebugChar (void);/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */void putDebugChar (int val);void enableDebugIRQ (void);/* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, represented by int x. */static char highhex (int x);/* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, represented by int x. */static char lowhex (int x);/* Returns the integer equivalent of a hexadecimal character. */static int hex (char ch);/* Convert the memory, pointed to by mem into hexadecimal representation. Put the result in buf, and return a pointer to the last character in buf (null). */static char *mem2hex (char *buf, unsigned char *mem, int count);/* Convert the array, in hexadecimal representation, pointed to by buf into binary representation. Put the result in mem, and return a pointer to the character after the last byte written. */static unsigned char *hex2mem (unsigned char *mem, char *buf, int count);/* Put the content of the array, in binary representation, pointed to by buf into memory pointed to by mem, and return a pointer to the character after the last byte written. */static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count);/* Await the sequence $<data>#<checksum> and store <data> in the array buffer returned. */static void getpacket (char *buffer);/* Send $<data>#<checksum> from the <data> in the array buffer. */static void putpacket (char *buffer);/* Build and send a response packet in order to inform the host the stub is stopped. */static void stub_is_stopped (int sigval);/* All expected commands are sent from remote.c. Send a response according to the description in remote.c. */static void handle_exception (int sigval);/* Performs a complete re-start from scratch. ETRAX specific. */static void kill_restart (void);/******************** Prototypes for global functions. ***********************//* The string str is prepended with the GDB printout token and sent. */void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c *//* The hook for both static (compiled) and dynamic breakpoints set by GDB. ETRAX 100 specific. */void handle_breakpoint (void); /* used by irq.c *//* The hook for an interrupt generated by GDB. ETRAX 100 specific. */void handle_interrupt (void); /* used by irq.c *//* A static breakpoint to be used at startup. */void breakpoint (void); /* called by init/main.c *//* From osys_int.c, executing_task contains the number of the current executing task in osys. Does not know of object-oriented threads. */extern unsigned char executing_task;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -