📄 ppc-stub.c
字号:
/* In case GDB is started before us, ack any packets (presumably * "$?#xx") sitting there. * * I've found this code causes more problems than it solves, * so that's why it's commented out. GDB seems to work fine * now starting either before or after the kernel -bwb */ while((c = getDebugChar()) != '$'); while((c = getDebugChar()) != '#'); c = getDebugChar(); /* eat first csum byte */ c = getDebugChar(); /* eat second csum byte */ putDebugChar('+'); /* ack it */#endif debugger = kgdb; debugger_bpt = kgdb_bpt; debugger_sstep = kgdb_sstep; debugger_iabr_match = kgdb_iabr_match; debugger_dabr_match = kgdb_dabr_match; initialized = 1;}static void kgdb_fault_handler(struct pt_regs *regs){ kgdb_longjmp((long*)fault_jmp_buf, 1);}int kgdb_bpt(struct pt_regs *regs){ return handle_exception(regs);}int kgdb_sstep(struct pt_regs *regs){ return handle_exception(regs);}void kgdb(struct pt_regs *regs){ handle_exception(regs);}int kgdb_iabr_match(struct pt_regs *regs){ printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); return handle_exception(regs);}int kgdb_dabr_match(struct pt_regs *regs){ printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); return handle_exception(regs);}/* Convert the hardware trap type code to a unix signal number. *//* * This table contains the mapping between PowerPC hardware trap types, and * signals, which are primarily what GDB understands. */static struct hard_trap_info{ unsigned int tt; /* Trap type code for powerpc */ unsigned char signo; /* Signal that we map this trap into */} hard_trap_info[] = {#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) { 0x100, SIGINT }, /* critical input interrupt */ { 0x200, SIGSEGV }, /* machine check */ { 0x300, SIGSEGV }, /* data storage */ { 0x400, SIGBUS }, /* instruction storage */ { 0x500, SIGINT }, /* interrupt */ { 0x600, SIGBUS }, /* alignment */ { 0x700, SIGILL }, /* program */ { 0x800, SIGILL }, /* reserved */ { 0x900, SIGILL }, /* reserved */ { 0xa00, SIGILL }, /* reserved */ { 0xb00, SIGILL }, /* reserved */ { 0xc00, SIGCHLD }, /* syscall */ { 0xd00, SIGILL }, /* reserved */ { 0xe00, SIGILL }, /* reserved */ { 0xf00, SIGILL }, /* reserved */ /* ** 0x1000 PIT ** 0x1010 FIT ** 0x1020 watchdog ** 0x1100 data TLB miss ** 0x1200 instruction TLB miss */ { 0x2002, SIGTRAP}, /* debug */#else { 0x200, SIGSEGV }, /* machine check */ { 0x300, SIGSEGV }, /* address error (store) */ { 0x400, SIGBUS }, /* instruction bus error */ { 0x500, SIGINT }, /* interrupt */ { 0x600, SIGBUS }, /* alingment */ { 0x700, SIGTRAP }, /* breakpoint trap */ { 0x800, SIGFPE }, /* fpu unavail */ { 0x900, SIGALRM }, /* decrementer */ { 0xa00, SIGILL }, /* reserved */ { 0xb00, SIGILL }, /* reserved */ { 0xc00, SIGCHLD }, /* syscall */ { 0xd00, SIGTRAP }, /* single-step/watch */ { 0xe00, SIGFPE }, /* fp assist */#endif { 0, 0} /* Must be last */};static int computeSignal(unsigned int tt){ struct hard_trap_info *ht; for (ht = hard_trap_info; ht->tt && ht->signo; ht++) if (ht->tt == tt) return ht->signo; return SIGHUP; /* default for things we don't know about */}#define PC_REGNUM 64#define SP_REGNUM 1/* * This function does all command processing for interfacing to gdb. */static inthandle_exception (struct pt_regs *regs){ int sigval; int addr; int length; char *ptr; unsigned int msr; /* We don't handle user-mode breakpoints. */ if (user_mode(regs)) return 0; if (debugger_fault_handler) { debugger_fault_handler(regs); panic("kgdb longjump failed!\n"); } if (kgdb_active) { printk(KERN_ERR "interrupt while in kgdb, returning\n"); return 0; } kgdb_active = 1; kgdb_started = 1;#ifdef KGDB_DEBUG printk("kgdb: entering handle_exception; trap [0x%x]\n", (unsigned int)regs->trap);#endif kgdb_interruptible(0); lock_kernel(); msr = mfmsr(); mtmsr(msr & ~MSR_EE); /* disable interrupts */ if (regs->nip == (unsigned long)breakinst) { /* Skip over breakpoint trap insn */ regs->nip += 4; } /* reply to host that an exception has occurred */ sigval = computeSignal(regs->trap); ptr = remcomOutBuffer; *ptr++ = 'T'; *ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval & 0xf]; *ptr++ = hexchars[PC_REGNUM >> 4]; *ptr++ = hexchars[PC_REGNUM & 0xf]; *ptr++ = ':'; ptr = mem2hex((char *)®s->nip, ptr, 4); *ptr++ = ';'; *ptr++ = hexchars[SP_REGNUM >> 4]; *ptr++ = hexchars[SP_REGNUM & 0xf]; *ptr++ = ':'; ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); *ptr++ = ';'; *ptr++ = 0; putpacket(remcomOutBuffer); if (kdebug) printk("remcomOutBuffer: %s\n", remcomOutBuffer); /* XXX We may want to add some features dealing with poking the * XXX page tables, ... (look at sparc-stub.c for more info) * XXX also required hacking to the gdb sources directly... */ while (1) { remcomOutBuffer[0] = 0; getpacket(remcomInBuffer); switch (remcomInBuffer[0]) { case '?': /* report most recent signal */ remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval & 0xf]; remcomOutBuffer[3] = 0; break;#if 0 case 'q': /* this screws up gdb for some reason...*/ { extern long _start, sdata, __bss_start; ptr = &remcomInBuffer[1]; if (strncmp(ptr, "Offsets", 7) != 0) break; ptr = remcomOutBuffer; sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", &_start, &sdata, &__bss_start); break; }#endif case 'd': /* toggle debug flag */ kdebug ^= 1; break; case 'g': /* return the value of the CPU registers. * some of them are non-PowerPC names :( * they are stored in gdb like: * struct { * u32 gpr[32]; * f64 fpr[32]; * u32 pc, ps, cnd, lr; (ps=msr) * u32 cnt, xer, mq; * } */ { int i; ptr = remcomOutBuffer; /* General Purpose Regs */ ptr = mem2hex((char *)regs, ptr, 32 * 4); /* Floating Point Regs - FIXME */ /*ptr = mem2hex((char *), ptr, 32 * 8);*/ for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ ptr[i] = '0'; } ptr += 32*8*2; /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ ptr = mem2hex((char *)®s->nip, ptr, 4); ptr = mem2hex((char *)®s->msr, ptr, 4); ptr = mem2hex((char *)®s->ccr, ptr, 4); ptr = mem2hex((char *)®s->link, ptr, 4); ptr = mem2hex((char *)®s->ctr, ptr, 4); ptr = mem2hex((char *)®s->xer, ptr, 4); } break; case 'G': /* set the value of the CPU registers */ { ptr = &remcomInBuffer[1]; /* * If the stack pointer has moved, you should pray. * (cause only god can help you). */ /* General Purpose Regs */ hex2mem(ptr, (char *)regs, 32 * 4); /* Floating Point Regs - FIXME?? */ /*ptr = hex2mem(ptr, ??, 32 * 8);*/ ptr += 32*8*2; /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ ptr = hex2mem(ptr, (char *)®s->nip, 4); ptr = hex2mem(ptr, (char *)®s->msr, 4); ptr = hex2mem(ptr, (char *)®s->ccr, 4); ptr = hex2mem(ptr, (char *)®s->link, 4); ptr = hex2mem(ptr, (char *)®s->ctr, 4); ptr = hex2mem(ptr, (char *)®s->xer, 4); strcpy(remcomOutBuffer,"OK"); } break; case 'H': /* don't do anything, yet, just acknowledge */ hexToInt(&ptr, &addr); strcpy(remcomOutBuffer,"OK"); break; case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ /* Try to read %x,%x. */ ptr = &remcomInBuffer[1]; if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) { if (mem2hex((char *)addr, remcomOutBuffer, length)) break; strcpy(remcomOutBuffer, "E03"); } else strcpy(remcomOutBuffer, "E01"); break; case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ /* Try to read '%x,%x:'. */ ptr = &remcomInBuffer[1]; if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':') { if (hex2mem(ptr, (char *)addr, length)) strcpy(remcomOutBuffer, "OK"); else strcpy(remcomOutBuffer, "E03"); flush_icache_range(addr, addr+length); } else strcpy(remcomOutBuffer, "E02"); break; case 'k': /* kill the program, actually just continue */ case 'c': /* cAA..AA Continue; address AA..AA optional */ /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hexToInt(&ptr, &addr)) regs->nip = addr;/* Need to flush the instruction cache here, as we may have deposited a * breakpoint, and the icache probably has no way of knowing that a data ref to * some location may have changed something that is in the instruction cache. */ kgdb_flush_cache_all(); mtmsr(msr); kgdb_interruptible(1); unlock_kernel(); kgdb_active = 0; if (kdebug) { printk("remcomInBuffer: %s\n", remcomInBuffer); printk("remcomOutBuffer: %s\n", remcomOutBuffer); } return 1; case 's': kgdb_flush_cache_all();#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); regs->msr |= MSR_DE;#else regs->msr |= MSR_SE;#endif unlock_kernel(); kgdb_active = 0; if (kdebug) { printk("remcomInBuffer: %s\n", remcomInBuffer); printk("remcomOutBuffer: %s\n", remcomOutBuffer); } return 1; case 'r': /* Reset (if user process..exit ???)*/ panic("kgdb reset."); break; } /* switch */ if (remcomOutBuffer[0] && kdebug) { printk("remcomInBuffer: %s\n", remcomInBuffer); printk("remcomOutBuffer: %s\n", remcomOutBuffer); } /* reply to the request */ putpacket(remcomOutBuffer); } /* while(1) */}/* This function will generate a breakpoint exception. It is used at the beginning of a program to sync up with a debugger and can be used otherwise as a quick means to stop program execution and "break" into the debugger. */voidbreakpoint(void){ if (!initialized) { printk("breakpoint() called b4 kgdb init\n"); return; } asm(" .globl breakinst \n\ breakinst: .long 0x7d821008");}#ifdef CONFIG_KGDB_CONSOLE/* Output string in GDB O-packet format if GDB has connected. If nothing output, returns 0 (caller must then handle output). */intkgdb_output_string (const char* s, unsigned int count){ char buffer[512]; if (!kgdb_started) return 0; count = (count <= (sizeof(buffer) / 2 - 2)) ? count : (sizeof(buffer) / 2 - 2); buffer[0] = 'O'; mem2hex (s, &buffer[1], count); putpacket(buffer); return 1;}#endifstatic void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, struct tty_struct *tty){ printk("Entering GDB stub\n"); breakpoint();}static struct sysrq_key_op sysrq_gdb_op = { .handler = sysrq_handle_gdb, .help_msg = "Gdb", .action_msg = "GDB",};static int gdb_register_sysrq(void){ printk("Registering GDB sysrq handler\n"); register_sysrq_key('g', &sysrq_gdb_op); return 0;}module_init(gdb_register_sysrq);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -