int dram_main(int argc, char *argv) { /* Here we have a in memory value we can change in the debugger * to begin booting in NOR Flash */ static volatile uint32_t wait = DRAM_BOOT_MODE; int ret; /* Disable the PMC. This is necessary on the SAMA5D4-MB Rev C. board. On * that board, the PMIC can lock up the I2C bus. The work around is * awkward: * * 1. Open JP23 (disabling the WM8904 data line) * 2. Execute DRAMBOOT. The WM8904 will be disabled while JP23 is open. * 3. At the prompt to "Send the Intel HEX file now", close JP23, * enabling the WM8904. * 4. Send the NuttX file. When NuttX starts, the WM8904 is initialized, * JP23 will be closed and the PMIC will be initialized. */ sam_pmic_initialize(); /* DRAM was already initialized at boot time, so we are ready to load the * Intel HEX stream into DRAM. * * Hmm.. With no hardware handshake, there is a possibility of data loss * to overrunning incoming data buffer. So far I have not seen this at * 115200 8N1, but still it is a possibility. */ printf("Send Intel HEX file now\n"); fflush(stdout); ret = hex2mem(0, /* Accept Intel HEX on stdin */ (uint32_t)SAM_DDRCS_VSECTION, (uint32_t)(SAM_DDRCS_VSECTION + CONFIG_SAMA5_DDRCS_SIZE), 0); if (ret < 0) { /* We failed the load */ printf("ERROR: Intel HEX file load failed: %d\n", ret); fflush(stdout); for(;;); } /* No success indication.. The following cache/MMU operations will clobber * any I/O that we attempt (Hmm.. unless, perhaps, if we delayed. But who * wants a delay?). */ /* Flush the entire data cache assure that everything is in memory before * we disable caching. */ arch_clean_dcache((uintptr_t)SAM_DDRCS_VSECTION, (uintptr_t)(SAM_DDRCS_VSECTION + CONFIG_SAMA5_DDRCS_SIZE)); /* Interrupts must be disabled through the following. In this configuration, * there should only be timer interrupts. Your NuttX configuration must use * CONFIG_SERIAL_LOWCONSOLE=y or printf() will hang when the interrupts * are disabled! */ (void)up_irq_save(); /* Disable the caches and the MMU. Disabling the MMU should be safe here * because there is a 1-to-1 identity mapping between the physical and * virtual addressing. */ cp15_disable_mmu(); cp15_disable_caches(); /* Invalidate caches and TLBs */ cp15_invalidate_icache(); cp15_invalidate_dcache_all(); cp15_invalidate_tlbs(); /* Then jump into NOR flash */ while (wait) { } DRAM_ENTRY(); return 0; /* We should not get here in either case */ }
/* * This function does all command procesing for interfacing to gdb. */ void gdb_stub_handler(int exception_vector) { int sigval; int addr, length; char * ptr; #ifdef GDB_REMOTE_UDP gdb_udp_poll_start(); #endif /* GDB_REMOTE_UDP */ if(remote_debug) GDB_PRINTF("vector=%d, ps=0x%x, pc=0x%x\n", exception_vector, gdb_registers[PS], gdb_registers[PC]); /* reply to host that an exception has occurred */ sigval = compute_signal(exception_vector); remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; if(remote_debug) GDB_PRINTF("GDB send packet: %s\n", remcomOutBuffer); gdb_put_packet(remcomOutBuffer); while (1) { remcomOutBuffer[0] = 0; gdb_get_packet(remcomInBuffer); if(remote_debug) GDB_PRINTF("GDB reveive packet: %s\n", remcomInBuffer); switch (remcomInBuffer[0]) { case '?' : remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; break; case 'd' : remote_debug = !(remote_debug); /* toggle debug flag */ break; case 'g' : /* return the value of the CPU registers */ mem2hex((char*) gdb_registers, remcomOutBuffer, NUMREGBYTES, 0); break; case 'G' : /* set the value of the CPU registers - return OK */ hex2mem(&remcomInBuffer[1], (char*) gdb_registers, NUMREGBYTES, 0); gdb_strcpy(remcomOutBuffer,"OK"); break; /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ case 'm' : /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) if (*(ptr++) == ',') if (hex2int(&ptr,&length)) { ptr = 0; mem_err = 0; mem2hex((char*) addr, remcomOutBuffer, length, 1); if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed read memory command: %s",remcomInBuffer); } break; /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ case 'M' : /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) if (*(ptr++) == ',') if (hex2int(&ptr,&length)) if (*(ptr++) == ':') { mem_err = 0; hex2mem(ptr, (char*) addr, length, 1); if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); } else { gdb_strcpy(remcomOutBuffer,"OK"); } ptr = 0; } if (ptr) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("malformed write memory command: %s",remcomInBuffer); } break; /* cAA..AA Continue at address AA..AA(optional) */ /* sAA..AA Step one instruction from AA..AA(optional) */ case 'c' : case 's' : /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hex2int(&ptr,&addr)) gdb_registers[PC] = addr; /* set the trace bit if we're stepping */ if (remcomInBuffer[0] == 's') gdb_registers[PS] |= 0x100; else gdb_registers[PS] &= 0xfffffeff; #ifdef GDB_REMOTE_UDP gdb_udp_poll_stop(); #endif /* GDB_REMOTE_UDP */ return; // break; /* kill the program */ case 'k' : /* do nothing */ break; /* Z<type-1x>,<address-x>,<length-x> Add breakpoint */ case 'Z' : if(hex(remcomInBuffer[1]) != 0) { /* We support only software break points so far */ break; } ptr = &remcomInBuffer[2]; if (*(ptr++) == ',') if (hex2int(&ptr,&addr)) { if (*(ptr++) == ',') { if (hex2int(&ptr,&length)) { if(length != 1) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("Breakpoint address length isn't equal to 1."); break; } ptr = 0; } } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed add breakpoint command: %s",remcomInBuffer); } else { struct zbreak *z; /* check whether this break point already set */ z = zbreak_list_find(addr); if(z) { /* Repeated packet */ gdb_strcpy(remcomOutBuffer,"OK"); break; } /* get an free zbreak */ mem_err = 0; z = zbreak_new(addr); if(z == NULL) { gdb_strcpy(remcomOutBuffer,"E03"); if(remote_debug) GDB_PRINTF("new zbreak failed.\n"); break; } if (mem_err) { gdb_strcpy (remcomOutBuffer, "E03"); if(remote_debug) GDB_PRINTF("memory fault"); break; } gdb_strcpy(remcomOutBuffer, "OK"); } break; /* z<type-1x>,<address-x>,<length-x> Remove breakpoint */ /* zz Remove all breakpoints */ case 'z' : if(hex(remcomInBuffer[1]) == 'z') { /* remove all breakpoints */ while(valid_zbreak_list.next != &valid_zbreak_list) { zbreak_free(valid_zbreak_list.next); } gdb_strcpy(remcomOutBuffer, "OK"); break; } if(hex(remcomInBuffer[1]) != 0) { /* We support only software break points so far */ break; } ptr = &remcomInBuffer[2]; if (*(ptr++) == ',') if (hex2int(&ptr,&addr)) { if (*(ptr++) == ',') { if (hex2int(&ptr,&length)) { if(length != 1) { gdb_strcpy(remcomOutBuffer,"E02"); if(remote_debug) GDB_PRINTF("Breakpoint address length isn't equal to 1."); break; } ptr = 0; } } } if (ptr) { gdb_strcpy(remcomOutBuffer,"E01"); if(remote_debug) GDB_PRINTF("malformed remove breakpoint command: %s",remcomInBuffer); } else { struct zbreak *z; z = zbreak_list_find(addr); if(z == NULL) { gdb_strcpy(remcomOutBuffer,"E03"); if(remote_debug) GDB_PRINTF("Breakpoint no found.\n"); break; } /* free zbreak */ zbreak_free(z); gdb_strcpy(remcomOutBuffer,"OK"); } break; } /* switch */ /* reply to the request */ if(remote_debug) GDB_PRINTF("GDB send packet: %s\n", remcomOutBuffer); gdb_put_packet(remcomOutBuffer); } }
/* * This function does all command processing for interfacing to * a remote gdb. Note that the error codes are ignored by gdb * at present, but might eventually become meaningful. (XXX) * It might makes sense to use POSIX errno values, because * that is what the gdb/remote.c functions want to return. */ int kgdb_trap(int type, db_regs_t *regs) { label_t jmpbuf; vaddr_t addr; size_t len; u_char *p; if (kgdb_dev < 0 || kgdb_getc == NULL) { /* not debugging */ return (0); } /* Detect and recover from unexpected traps. */ if (kgdb_recover != 0) { printf("kgdb: caught trap 0x%x at %p\n", type, (void *)PC_REGS(regs)); kgdb_send("E0E"); /* 14==EFAULT */ longjmp(kgdb_recover); } /* * The first entry to this function is normally through * a breakpoint trap in kgdb_connect(), in which case we * must advance past the breakpoint because gdb will not. * * Machines vary as to where they leave the PC after a * breakpoint trap. Those that leave the PC set to the * address of the trap instruction (i.e. pc532) will not * define FIXUP_PC_AFTER_BREAK(), and therefore will just * advance the PC. On machines that leave the PC set to * the instruction after the trap, FIXUP_PC_AFTER_BREAK * will be defined to back-up the PC, so that after the * "first-time" part of the if statement below has run, * the PC will be the same as it was on entry. * * On the first entry here, we expect that gdb is not yet * listening to us, so just enter the interaction loop. * After the debugger is "active" (connected) it will be * waiting for a "signaled" message from us. */ if (kgdb_active == 0) { if (!IS_BREAKPOINT_TRAP(type, 0)) { /* No debugger active -- let trap handle this. */ return (0); } /* Make the PC point at the breakpoint... */ #ifdef FIXUP_PC_AFTER_BREAK FIXUP_PC_AFTER_BREAK(regs); #endif /* ... and then advance past it. */ #ifdef PC_ADVANCE PC_ADVANCE(regs); #else SET_PC_REGS(regs, PC_REGS(regs) + BKPT_SIZE); #endif kgdb_active = 1; } else { /* Tell remote host that an exception has occurred. */ snprintf(buffer, sizeof buffer, "S%02x", kgdb_signal(type)); kgdb_send(buffer); } /* Stick frame regs into our reg cache. */ kgdb_getregs(regs, gdb_regs); /* * Interact with gdb until it lets us go. * If we cause a trap, resume here. */ (void)setjmp((kgdb_recover = &jmpbuf)); for (;;) { kgdb_recv(buffer, sizeof(buffer)); switch (buffer[0]) { default: /* Unknown command. */ kgdb_send(""); continue; case KGDB_SIGNAL: /* * if this command came from a running gdb, * answer it -- the other guy has no way of * knowing if we're in or out of this loop * when he issues a "remote-signal". */ snprintf(buffer, sizeof buffer, "S%02x", kgdb_signal(type)); kgdb_send(buffer); continue; case KGDB_REG_R: mem2hex(buffer, gdb_regs, sizeof(gdb_regs)); kgdb_send(buffer); continue; case KGDB_REG_W: p = hex2mem(gdb_regs, buffer + 1, sizeof(gdb_regs)); if (p == NULL || *p != '\0') kgdb_send("E01"); else { kgdb_setregs(regs, gdb_regs); kgdb_send("OK"); } continue; case KGDB_MEM_R: p = buffer + 1; addr = hex2i(&p); if (*p++ != ',') { kgdb_send("E02"); continue; } len = hex2i(&p); if (*p != '\0') { kgdb_send("E03"); continue; } if (len > sizeof(buffer) / 2) { kgdb_send("E04"); continue; } if (kgdb_acc(addr, len) == 0) { kgdb_send("E05"); continue; } db_read_bytes(addr, (size_t)len, (char *)buffer + sizeof(buffer) / 2); mem2hex(buffer, buffer + sizeof(buffer) / 2, len); kgdb_send(buffer); continue; case KGDB_MEM_W: p = buffer + 1; addr = hex2i(&p); if (*p++ != ',') { kgdb_send("E06"); continue; } len = hex2i(&p); if (*p++ != ':') { kgdb_send("E07"); continue; } if (len > (sizeof(buffer) - (p - buffer))) { kgdb_send("E08"); continue; } p = hex2mem(buffer, p, sizeof(buffer)); if (p == NULL) { kgdb_send("E09"); continue; } if (kgdb_acc(addr, len) == 0) { kgdb_send("E0A"); continue; } db_write_bytes(addr, (size_t)len, (char *)buffer); kgdb_send("OK"); continue; case KGDB_DETACH: kgdb_active = 0; printf("kgdb detached\n"); db_clear_single_step(regs); kgdb_send("OK"); goto out; case KGDB_KILL: kgdb_active = 0; printf("kgdb detached\n"); db_clear_single_step(regs); goto out; case KGDB_CONT: if (buffer[1]) { p = buffer + 1; addr = hex2i(&p); if (*p) { kgdb_send("E0B"); continue; } SET_PC_REGS(regs, addr); } db_clear_single_step(regs); goto out; case KGDB_STEP: if (buffer[1]) { p = buffer + 1; addr = hex2i(&p); if (*p) { kgdb_send("E0B"); continue; } SET_PC_REGS(regs, addr); } db_set_single_step(regs); goto out; } } out: kgdb_recover = 0; return (1); }
/* * This function does all command processing for interfacing to gdb. */ static int handle_exception (struct pt_regs *regs) { int addr; int length; char *ptr; kgdb_data kd; int i; if (!initialized) { printf("kgdb: exception before kgdb is initialized! huh?\n"); return (0); } /* probably should check which exception occured as well */ if (longjmp_on_fault) { longjmp_on_fault = 0; kgdb_longjmp((long*)error_jmp_buf, KGDBERR_MEMFAULT); panic("kgdb longjump failed!\n"); } if (kgdb_active) { printf("kgdb: unexpected exception from within kgdb\n"); return (0); } kgdb_active = 1; kgdb_interruptible(0); printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs)); if (kgdb_setjmp((long*)error_jmp_buf) != 0) panic("kgdb: error or fault in entry init!\n"); kgdb_enter(regs, &kd); if (first_entry) { /* * the first time we enter kgdb, we save the processor * state so that we can return to the monitor if the * remote end quits gdb (or at least, tells us to quit * with the 'k' packet) */ entry_regs = *regs; first_entry = 0; } ptr = remcomOutBuffer; *ptr++ = 'T'; *ptr++ = hexchars[kd.sigval >> 4]; *ptr++ = hexchars[kd.sigval & 0xf]; for (i = 0; i < kd.nregs; i++) { kgdb_reg *rp = &kd.regs[i]; *ptr++ = hexchars[rp->num >> 4]; *ptr++ = hexchars[rp->num & 0xf]; *ptr++ = ':'; ptr = mem2hex((char *)&rp->val, ptr, 4); *ptr++ = ';'; } *ptr = 0; #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); #endif putpacket(remcomOutBuffer); while (1) { volatile int errnum; remcomOutBuffer[0] = 0; getpacket(remcomInBuffer); ptr = &remcomInBuffer[1]; #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer); #endif errnum = kgdb_setjmp((long*)error_jmp_buf); if (errnum == 0) switch (remcomInBuffer[0]) { case '?': /* report most recent signal */ remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[kd.sigval >> 4]; remcomOutBuffer[2] = hexchars[kd.sigval & 0xf]; remcomOutBuffer[3] = 0; break; #ifdef KGDB_DEBUG case 'd': /* toggle debug flag */ kdebug ^= 1; break; #endif case 'g': /* return the value of the CPU registers. */ length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX); mem2hex(remcomRegBuffer, remcomOutBuffer, length); break; case 'G': /* set the value of the CPU registers */ length = strlen(ptr); if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS); hex2mem(ptr, remcomRegBuffer, length/2); kgdb_putregs(regs, remcomRegBuffer, length/2); strcpy(remcomOutBuffer,"OK"); break; case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ /* Try to read %x,%x. */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length)) { mem2hex((char *)addr, remcomOutBuffer, length); } else { kgdb_error(KGDBERR_BADPARAMS); } break; case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ /* Try to read '%x,%x:'. */ if (hexToInt(&ptr, &addr) && *ptr++ == ',' && hexToInt(&ptr, &length) && *ptr++ == ':') { hex2mem(ptr, (char *)addr, length); strcpy(remcomOutBuffer, "OK"); } else { kgdb_error(KGDBERR_BADPARAMS); } break; case 'k': /* kill the program, actually return to monitor */ kd.extype = KGDBEXIT_KILL; *regs = entry_regs; first_entry = 1; goto doexit; case 'C': /* CSS continue with signal SS */ *ptr = '\0'; /* ignore the signal number for now */ /* fall through */ case 'c': /* cAA..AA Continue; address AA..AA optional */ /* try to read optional parameter, pc unchanged if no parm */ kd.extype = KGDBEXIT_CONTINUE; if (hexToInt(&ptr, &addr)) { kd.exaddr = addr; kd.extype |= KGDBEXIT_WITHADDR; } goto doexit; case 'S': /* SSS single step with signal SS */ *ptr = '\0'; /* ignore the signal number for now */ /* fall through */ case 's': kd.extype = KGDBEXIT_SINGLE; if (hexToInt(&ptr, &addr)) { kd.exaddr = addr; kd.extype |= KGDBEXIT_WITHADDR; } doexit: /* 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(); kgdb_exit(regs, &kd); kgdb_active = 0; kgdb_interruptible(1); return (1); case 'r': /* Reset (if user process..exit ???)*/ panic("kgdb reset."); break; case 'P': /* Pr=v set reg r to value v (r and v are hex) */ if (hexToInt(&ptr, &addr) && *ptr++ == '=' && ((length = strlen(ptr)) & 1) == 0) { hex2mem(ptr, remcomRegBuffer, length/2); kgdb_putreg(regs, addr, remcomRegBuffer, length/2); strcpy(remcomOutBuffer,"OK"); } else { kgdb_error(KGDBERR_BADPARAMS); } break; } /* switch */ if (errnum != 0) sprintf(remcomOutBuffer, "E%02d", errnum); #ifdef KGDB_DEBUG if (kdebug) printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer); #endif /* reply to the request */ putpacket(remcomOutBuffer); } /* while(1) */ }
/* All expected commands are sent from remote.c. Send a response according to the description in remote.c. */ static void handle_exception (int sigval) { /* Avoid warning of not used. */ USEDFUN(handle_exception); USEDVAR(internal_stack[0]); /* Send response. */ stub_is_stopped (sigval); for (;;) { remcomOutBuffer[0] = '\0'; getpacket (remcomInBuffer); switch (remcomInBuffer[0]) { case 'g': /* Read registers: g Success: Each byte of register data is described by two hex digits. Registers are in the internal order for GDB, and the bytes in a register are in the same order the machine uses. Failure: void. */ { #ifdef PROCESS_SUPPORT /* Use the special register content in the executing thread. */ copy_registers (®_g, ®, sizeof(registers)); /* Replace the content available on the stack. */ if (current_thread_g != executing_task) { copy_registers_from_stack (current_thread_g, ®_g); } mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)®_g, sizeof(registers)); #else mem2hex(remcomOutBuffer, (char *)®, sizeof(registers)); #endif } break; case 'G': /* Write registers. GXX..XX Each byte of register data is described by two hex digits. Success: OK Failure: void. */ #ifdef PROCESS_SUPPORT hex2mem ((unsigned char *)®_g, &remcomInBuffer[1], sizeof(registers)); if (current_thread_g == executing_task) { copy_registers (®, ®_g, sizeof(registers)); } else { copy_registers_to_stack(current_thread_g, ®_g); } #else hex2mem((char *)®, &remcomInBuffer[1], sizeof(registers)); #endif gdb_cris_strcpy (remcomOutBuffer, "OK"); break; case 'P': /* Write register. Pn...=r... Write register n..., hex value without 0x, with value r..., which contains a hex value without 0x and two hex digits for each byte in the register (target byte order). P1f=11223344 means set register 31 to 44332211. Success: OK Failure: E02, E05 */ { char *suffix; int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); int status; #ifdef PROCESS_SUPPORT if (current_thread_g != executing_task) status = write_stack_register (current_thread_g, regno, suffix+1); else #endif status = write_register (regno, suffix+1); switch (status) { case E02: /* Do not support read-only registers. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E02]); break; case E05: /* Do not support non-existing registers. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E05]); break; case E07: /* Do not support non-existing registers on the stack. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E07]); break; default: /* Valid register number. */ gdb_cris_strcpy (remcomOutBuffer, "OK"); break; } } break; case 'm': /* Read from memory. mAA..AA,LLLL AA..AA is the address and LLLL is the length. Success: XX..XX is the memory content. Can be fewer bytes than requested if only part of the data may be read. m6000120a,6c means retrieve 108 byte from base address 6000120a. Failure: void. */ { char *suffix; unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], &suffix, 16); int length = gdb_cris_strtol(suffix+1, 0, 16); mem2hex(remcomOutBuffer, addr, length); } break; case 'X': /* Write to memory. XAA..AA,LLLL:XX..XX AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the binary data. Success: OK Failure: void. */ case 'M': /* Write to memory. MAA..AA,LLLL:XX..XX AA..AA is the start address, LLLL is the number of bytes, and XX..XX is the hexadecimal data. Success: OK Failure: void. */ { char *lenptr; char *dataptr; unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], &lenptr, 16); int length = gdb_cris_strtol(lenptr+1, &dataptr, 16); if (*lenptr == ',' && *dataptr == ':') { if (remcomInBuffer[0] == 'M') { hex2mem(addr, dataptr + 1, length); } else /* X */ { bin2mem(addr, dataptr + 1, length); } gdb_cris_strcpy (remcomOutBuffer, "OK"); } else { gdb_cris_strcpy (remcomOutBuffer, error_message[E06]); } } break; case 'c': /* Continue execution. cAA..AA AA..AA is the address where execution is resumed. If AA..AA is omitted, resume at the present address. Success: return to the executing thread. Failure: will never know. */ if (remcomInBuffer[1] != '\0') { reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16); } enableDebugIRQ(); return; case 's': /* Step. sAA..AA AA..AA is the address where execution is resumed. If AA..AA is omitted, resume at the present address. Success: return to the executing thread. Failure: will never know. Should never be invoked. The single-step is implemented on the host side. If ever invoked, it is an internal error E04. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); putpacket (remcomOutBuffer); return; case '?': /* The last signal which caused a stop. ? Success: SAA, where AA is the signal number. Failure: void. */ remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hex_asc_hi(sigval); remcomOutBuffer[2] = hex_asc_lo(sigval); remcomOutBuffer[3] = 0; break; case 'D': /* Detach from host. D Success: OK, and return to the executing thread. Failure: will never know */ putpacket ("OK"); return; case 'k': case 'r': /* kill request or reset request. Success: restart of target. Failure: will never know. */ kill_restart (); break; case 'C': case 'S': case '!': case 'R': case 'd': /* Continue with signal sig. Csig;AA..AA Step with signal sig. Ssig;AA..AA Use the extended remote protocol. ! Restart the target system. R0 Toggle debug flag. d Search backwards. tAA:PP,MM Not supported: E04 */ gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); break; #ifdef PROCESS_SUPPORT case 'T': /* Thread alive. TXX Is thread XX alive? Success: OK, thread XX is alive. Failure: E03, thread XX is dead. */ { int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16); /* Cannot tell whether it is alive or not. */ if (thread_id >= 0 && thread_id < number_of_tasks) gdb_cris_strcpy (remcomOutBuffer, "OK"); } break; case 'H': /* Set thread for subsequent operations: Hct c = 'c' for thread used in step and continue; t can be -1 for all threads. c = 'g' for thread used in other operations. t = 0 means pick any thread. Success: OK Failure: E01 */ { int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16); if (remcomInBuffer[1] == 'c') { /* c = 'c' for thread used in step and continue */ /* Do not change current_thread_c here. It would create a mess in the scheduler. */ gdb_cris_strcpy (remcomOutBuffer, "OK"); } else if (remcomInBuffer[1] == 'g') { /* c = 'g' for thread used in other operations. t = 0 means pick any thread. Impossible since the scheduler does not allow that. */ if (thread_id >= 0 && thread_id < number_of_tasks) { current_thread_g = thread_id; gdb_cris_strcpy (remcomOutBuffer, "OK"); } else { /* Not expected - send an error message. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); } } else { /* Not expected - send an error message. */ gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); } } break; case 'q': case 'Q': /* Query of general interest. qXXXX Set general value XXXX. QXXXX=yyyy */ { int pos; int nextpos; int thread_id; switch (remcomInBuffer[1]) { case 'C': /* Identify the remote current thread. */ gdb_cris_strcpy (&remcomOutBuffer[0], "QC"); remcomOutBuffer[2] = hex_asc_hi(current_thread_c); remcomOutBuffer[3] = hex_asc_lo(current_thread_c); remcomOutBuffer[4] = '\0'; break; case 'L': gdb_cris_strcpy (&remcomOutBuffer[0], "QM"); /* Reply with number of threads. */ if (os_is_started()) { remcomOutBuffer[2] = hex_asc_hi(number_of_tasks); remcomOutBuffer[3] = hex_asc_lo(number_of_tasks); } else { remcomOutBuffer[2] = hex_asc_hi(0); remcomOutBuffer[3] = hex_asc_lo(1); } /* Done with the reply. */ remcomOutBuffer[4] = hex_asc_lo(1); pos = 5; /* Expects the argument thread id. */ for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++) remcomOutBuffer[pos] = remcomInBuffer[pos]; /* Reply with the thread identifiers. */ if (os_is_started()) { /* Store the thread identifiers of all tasks. */ for (thread_id = 0; thread_id < number_of_tasks; thread_id++) { nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; for (; pos < nextpos; pos ++) remcomOutBuffer[pos] = hex_asc_lo(0); remcomOutBuffer[pos++] = hex_asc_lo(thread_id); } } else { /* Store the thread identifier of the boot task. */ nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; for (; pos < nextpos; pos ++) remcomOutBuffer[pos] = hex_asc_lo(0); remcomOutBuffer[pos++] = hex_asc_lo(current_thread_c); } remcomOutBuffer[pos] = '\0'; break; default: /* Not supported: "" */ /* Request information about section offsets: qOffsets. */ remcomOutBuffer[0] = 0; break; } } break; #endif /* PROCESS_SUPPORT */ default: /* The stub should ignore other request and send an empty response ($#<checksum>). This way we can extend the protocol and GDB can tell whether the stub it is talking to uses the old or the new. */ remcomOutBuffer[0] = 0; break; } putpacket(remcomOutBuffer); } }
/* * This function does all command procesing for interfacing to gdb. */ void gdb_handle_exception (db_regs_t *raw_regs, int type, int code) { int sigval; int addr, length; char * ptr; struct i386regs { unsigned int eax; unsigned int ecx; unsigned int edx; unsigned int ebx; unsigned int esp; unsigned int ebp; unsigned int esi; unsigned int edi; unsigned int eip; unsigned int eflags; unsigned int cs; unsigned int ss; unsigned int ds; unsigned int es; }; struct i386regs registers; registers.eax = raw_regs->tf_eax; registers.ebx = raw_regs->tf_ebx; registers.ecx = raw_regs->tf_ecx; registers.edx = raw_regs->tf_edx; registers.esp = raw_regs->tf_esp; registers.ebp = raw_regs->tf_ebp; registers.esi = raw_regs->tf_esi; registers.edi = raw_regs->tf_edi; registers.eip = raw_regs->tf_eip; registers.eflags = raw_regs->tf_eflags; registers.cs = raw_regs->tf_cs; registers.ss = raw_regs->tf_ss; registers.ds = raw_regs->tf_ds; registers.es = raw_regs->tf_es; /* reply to host that an exception has occurred */ sigval = computeSignal (type); ptr = remcomOutBuffer; *ptr++ = 'T'; *ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval & 0xf]; *ptr++ = hexchars[PC >> 4]; *ptr++ = hexchars[PC & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.eip, ptr, 4); *ptr++ = ';'; *ptr++ = hexchars[FP >> 4]; *ptr++ = hexchars[FP & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.ebp, ptr, 4); *ptr++ = ';'; *ptr++ = hexchars[SP >> 4]; *ptr++ = hexchars[SP & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.esp, ptr, 4); *ptr++ = ';'; *ptr++ = 0; putpacket (remcomOutBuffer); while (1) { remcomOutBuffer[0] = 0; getpacket (remcomInBuffer); switch (remcomInBuffer[0]) { case '?': remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; break; case 'D': /* detach; say OK and turn off gdb */ putpacket(remcomOutBuffer); boothowto &= ~RB_GDB; return; case 'g': /* return the value of the CPU registers */ mem2hex ((vm_offset_t)®isters, remcomOutBuffer, NUMREGBYTES); break; case 'G': /* set the value of the CPU registers - return OK */ hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, NUMREGBYTES); strcpy (remcomOutBuffer, "OK"); break; case 'P': /* Set the value of one register */ { int regno; ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, ®no) && *ptr++ == '=' && regno < NUM_REGS) { hex2mem (ptr, (vm_offset_t)®isters + regno * 4, 4); strcpy(remcomOutBuffer,"OK"); } else strcpy (remcomOutBuffer, "P01"); 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((vm_offset_t) addr, remcomOutBuffer, length) == NULL) strcpy (remcomOutBuffer, "E03"); break; } 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, (vm_offset_t) addr, length) == NULL) strcpy (remcomOutBuffer, "E03"); else strcpy (remcomOutBuffer, "OK"); } else strcpy (remcomOutBuffer, "E02"); break; /* cAA..AA Continue at address AA..AA(optional) */ /* sAA..AA Step one instruction from AA..AA(optional) */ case 'c' : case 's' : /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hexToInt(&ptr,&addr)) registers.eip = addr; /* set the trace bit if we're stepping */ if (remcomInBuffer[0] == 's') registers.eflags |= PSL_T; else registers.eflags &= ~PSL_T; raw_regs->tf_eax = registers.eax; raw_regs->tf_ebx = registers.ebx; raw_regs->tf_ecx = registers.ecx; raw_regs->tf_edx = registers.edx; raw_regs->tf_esp = registers.esp; raw_regs->tf_ebp = registers.ebp; raw_regs->tf_esi = registers.esi; raw_regs->tf_edi = registers.edi; raw_regs->tf_eip = registers.eip; raw_regs->tf_eflags = registers.eflags; raw_regs->tf_cs = registers.cs; raw_regs->tf_ss = registers.ss; raw_regs->tf_ds = registers.ds; raw_regs->tf_es = registers.es; return; } /* switch */ /* reply to the request */ putpacket (remcomOutBuffer); } }
static void handle_exception (int exceptionVector) { int sigval; int addr, length, reg; char *ptr; gdb_i386vector = exceptionVector; if (remote_debug) printf ("vector=%d, sr=0x%x, pc=0x%x\n", exceptionVector, registers[PS], registers[PC]); /* Reply to host that an exception has occurred. Always return the PC, SP, and FP, since gdb always wants them. */ ptr = remcomOutBuffer; *ptr++ = 'T'; sigval = computeSignal (exceptionVector); *ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval % 16]; *ptr++ = hexchars[ESP]; *ptr++ = ':'; mem2hex ((char *) ®isters[ESP], ptr, REGBYTES, 0); ptr += REGBYTES * 2; *ptr++ = ';'; *ptr++ = hexchars[EBP]; *ptr++ = ':'; mem2hex ((char *) ®isters[EBP], ptr, REGBYTES, 0); ptr += REGBYTES * 2; *ptr++ = ';'; *ptr++ = hexchars[PC]; *ptr++ = ':'; mem2hex ((char *) ®isters[PC], ptr, REGBYTES, 0); ptr += REGBYTES * 2; *ptr++ = ';'; *ptr = '\0'; putpacket (remcomOutBuffer); while (1 == 1) { error = 0; remcomOutBuffer[0] = 0; getpacket (remcomInBuffer); switch (remcomInBuffer[0]) { case '?': remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; break; case 'd': remote_debug = !(remote_debug); /* toggle debug flag */ break; case 'g': /* return the value of the CPU registers */ mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES, 0); break; case 'G': /* set the value of the CPU registers - return OK */ hex2mem (&remcomInBuffer[1], (char *) registers, NUMREGBYTES, 0); strcpy (remcomOutBuffer, "OK"); break; case 'P': /* Set specific register */ ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, ®) && *ptr++ == '=') { hex2mem (ptr, (char *) ®isters[reg], REGBYTES, 0); strcpy (remcomOutBuffer, "OK"); } else { strcpy (remcomOutBuffer, "E01"); debug_error ("malformed register set command; %s", remcomInBuffer); } break; /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ case 'm': /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, &addr)) if (*(ptr++) == ',') if (hexToInt (&ptr, &length)) { ptr = 0; mem_err = 0; mem2hex ((char *) addr, remcomOutBuffer, length, 1); if (mem_err) { strcpy (remcomOutBuffer, "E03"); debug_error ("memory fault", 0); } } if (ptr) { strcpy (remcomOutBuffer, "E01"); debug_error ("malformed read memory command: %s", remcomInBuffer); } break; /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ case 'M': /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, &addr)) if (*(ptr++) == ',') if (hexToInt (&ptr, &length)) if (*(ptr++) == ':') { mem_err = 0; hex2mem (ptr, (char *) addr, length, 1); if (mem_err) { strcpy (remcomOutBuffer, "E03"); debug_error ("memory fault", 0); } else { strcpy (remcomOutBuffer, "OK"); } ptr = 0; } if (ptr) { strcpy (remcomOutBuffer, "E02"); debug_error ("malformed write memory command: %s", remcomInBuffer); } break; /* cAA..AA Continue at address AA..AA(optional) */ /* sAA..AA Step one instruction from AA..AA(optional) */ case 'c': case 's': /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, &addr)) registers[PC] = addr; /* clear the trace bit */ registers[PS] &= 0xfffffeff; /* set the trace bit if we're stepping */ if (remcomInBuffer[0] == 's') registers[PS] |= 0x100; _returnFromException (); /* this is a jump */ break; /* Detach. */ case 'D': putpacket (remcomOutBuffer); registers[PS] &= 0xfffffeff; _returnFromException (); /* this is a jump */ break; /* kill the program */ case 'k': /* do nothing */ break; } /* switch */ /* reply to the request */ putpacket (remcomOutBuffer); } }
/* * This function does all command procesing for interfacing to gdb. */ void gdb_handle_exception (db_regs_t *raw_regs, int type, int code) { int sigval; long addr, length; char * ptr; struct alpharegs { u_int64_t r[32]; u_int64_t f[32]; u_int64_t pc, vfp; }; static struct alpharegs registers; int i; clear_single_step(raw_regs); bzero(®isters, sizeof registers); /* * Map trapframe to registers. * Ignore float regs for now. */ for (i = 0; i < FRAME_SIZE; i++) if (tf2gdb[i] >= 0) registers.r[tf2gdb[i]] = raw_regs->tf_regs[i]; registers.pc = raw_regs->tf_regs[FRAME_PC]; /* reply to host that an exception has occurred */ sigval = computeSignal (type, code); ptr = remcomOutBuffer; *ptr++ = 'T'; *ptr++ = hexchars[sigval >> 4]; *ptr++ = hexchars[sigval & 0xf]; *ptr++ = hexchars[PC >> 4]; *ptr++ = hexchars[PC & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.pc, ptr, 8); *ptr++ = ';'; *ptr++ = hexchars[FP >> 4]; *ptr++ = hexchars[FP & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.r[FP], ptr, 8); *ptr++ = ';'; *ptr++ = hexchars[SP >> 4]; *ptr++ = hexchars[SP & 0xf]; *ptr++ = ':'; ptr = mem2hex ((vm_offset_t)®isters.r[SP], ptr, 8); *ptr++ = ';'; *ptr++ = 0; putpacket (remcomOutBuffer); while (1) { remcomOutBuffer[0] = 0; getpacket (remcomInBuffer); switch (remcomInBuffer[0]) { case '?': remcomOutBuffer[0] = 'S'; remcomOutBuffer[1] = hexchars[sigval >> 4]; remcomOutBuffer[2] = hexchars[sigval % 16]; remcomOutBuffer[3] = 0; break; case 'D': /* detach; say OK and turn off gdb */ putpacket(remcomOutBuffer); boothowto &= ~RB_GDB; return; case 'k': prom_halt(); /*NOTREACHED*/ break; case 'g': /* return the value of the CPU registers */ mem2hex ((vm_offset_t)®isters, remcomOutBuffer, NUMREGBYTES); break; case 'G': /* set the value of the CPU registers - return OK */ hex2mem (&remcomInBuffer[1], (vm_offset_t)®isters, NUMREGBYTES); strcpy (remcomOutBuffer, "OK"); break; case 'P': /* Set the value of one register */ { long regno; ptr = &remcomInBuffer[1]; if (hexToInt (&ptr, ®no) && *ptr++ == '=' && regno < NUM_REGS) { hex2mem (ptr, (vm_offset_t)®isters + regno * 8, 8); strcpy(remcomOutBuffer,"OK"); } else strcpy (remcomOutBuffer, "P01"); 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((vm_offset_t) addr, remcomOutBuffer, length) == NULL) strcpy (remcomOutBuffer, "E03"); break; } 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, (vm_offset_t) addr, length) == NULL) strcpy (remcomOutBuffer, "E03"); else strcpy (remcomOutBuffer, "OK"); } else strcpy (remcomOutBuffer, "E02"); break; /* cAA..AA Continue at address AA..AA(optional) */ /* sAA..AA Step one instruction from AA..AA(optional) */ case 'c' : case 's' : /* try to read optional parameter, pc unchanged if no parm */ ptr = &remcomInBuffer[1]; if (hexToInt(&ptr,&addr)) registers.pc = addr; /* * Map gdb registers back to trapframe (ignoring fp regs). */ for (i = 0; i < NUM_REGS; i++) if (gdb2tf[i] >= 0) raw_regs->tf_regs[gdb2tf[i]] = registers.r[i]; raw_regs->tf_regs[FRAME_PC] = registers.pc; if (remcomInBuffer[0] == 's') if (!set_single_step(raw_regs)) printf("Can't set single step breakpoint\n"); return; } /* switch */ /* reply to the request */ putpacket (remcomOutBuffer); } }