mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
127 lines
4.4 KiB
C
127 lines
4.4 KiB
C
/******************************************************************************
|
|
* Copyright 2015 Espressif Systems
|
|
*
|
|
* Description: A stub to make the ESP8266 debuggable by GDB over the serial
|
|
* port.
|
|
*
|
|
* License: ESPRESSIF MIT License
|
|
*******************************************************************************/
|
|
|
|
#include <stddef.h>
|
|
#include "ets_sys.h"
|
|
#include "eagle_soc.h"
|
|
#include "c_types.h"
|
|
#include "gpio.h"
|
|
#include "xtensa/corebits.h"
|
|
|
|
#include "osapi_release.h"
|
|
#include "user_interface.h"
|
|
#include "espmissingincludes.h"
|
|
|
|
//From xtruntime-frames.h
|
|
struct XTensa_exception_frame_s {
|
|
uint32_t pc;
|
|
uint32_t ps;
|
|
uint32_t sar;
|
|
uint32_t vpri;
|
|
uint32_t a0;
|
|
uint32_t a[14]; //a2..a15
|
|
// The following are added manually by the exception code; the HAL doesn't set these on an exception.
|
|
uint32_t litbase;
|
|
uint32_t sr176;
|
|
uint32_t sr208;
|
|
uint32_t a1;
|
|
uint32_t reason;
|
|
uint32_t excvaddr;
|
|
};
|
|
|
|
//The asm stub saves the Xtensa registers here when a debugging exception happens.
|
|
struct XTensa_exception_frame_s gdbstub_savedRegs;
|
|
|
|
//Get the value of one of the A registers
|
|
static unsigned int getaregval(int reg) {
|
|
if (reg==0) return gdbstub_savedRegs.a0;
|
|
if (reg==1) return gdbstub_savedRegs.a1;
|
|
return gdbstub_savedRegs.a[reg-2];
|
|
}
|
|
|
|
static void print_stack(uint32_t start, uint32_t end) {
|
|
os_printf("\nStack dump:\n");
|
|
for (uint32_t pos = start; pos < end; pos += 0x10) {
|
|
uint32_t* values = (uint32_t*)(pos);
|
|
// rough indicator: stack frames usually have SP saved as the second word
|
|
bool looksLikeStackFrame = (values[2] == pos + 0x10);
|
|
|
|
os_printf("%08lx: %08lx %08lx %08lx %08lx %c\n",
|
|
(long unsigned int) pos,
|
|
(long unsigned int) values[0],
|
|
(long unsigned int) values[1],
|
|
(long unsigned int) values[2],
|
|
(long unsigned int) values[3],
|
|
(looksLikeStackFrame)?'<':' ');
|
|
}
|
|
os_printf("\n");
|
|
}
|
|
|
|
void _xtos_set_exception_handler(int cause, void (exhandler)(struct XTensa_exception_frame_s *frame));
|
|
int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2)));
|
|
|
|
// Print exception info to console
|
|
static void printReason() {
|
|
//register uint32_t sp asm("a1");
|
|
struct XTensa_exception_frame_s *reg = &gdbstub_savedRegs;
|
|
os_printf("\n\n***** Fatal exception %ld\n", (long int) reg->reason);
|
|
os_printf("pc=0x%08lx sp=0x%08lx excvaddr=0x%08lx\n",
|
|
(long unsigned int) reg->pc,
|
|
(long unsigned int) reg->a1,
|
|
(long unsigned int) reg->excvaddr);
|
|
os_printf("ps=0x%08lx sar=0x%08lx vpri=0x%08lx\n",
|
|
(long unsigned int) reg->ps,
|
|
(long unsigned int) reg->sar,
|
|
(long unsigned int) reg->vpri);
|
|
for (int i=0; i<16; i++) {
|
|
unsigned int r = getaregval(i);
|
|
os_printf("r%02d: 0x%08x=%10d ", i, r, r);
|
|
if (i%3 == 2) os_printf("\n");
|
|
}
|
|
os_printf("\n");
|
|
//print_stack(reg->pc, sp, 0x3fffffb0);
|
|
print_stack(getaregval(1), 0x3fffffb0);
|
|
}
|
|
|
|
extern void ets_wdt_disable();
|
|
extern void ets_wdt_enable();
|
|
|
|
// Non-OS exception handler. Gets called by the Xtensa HAL.
|
|
static void gdb_exception_handler(struct XTensa_exception_frame_s *frame) {
|
|
//Save the extra registers the Xtensa HAL doesn't save
|
|
extern void gdbstub_save_extra_sfrs_for_exception();
|
|
gdbstub_save_extra_sfrs_for_exception();
|
|
//Copy registers the Xtensa HAL did save to gdbstub_savedRegs
|
|
os_memcpy(&gdbstub_savedRegs, frame, 19*4);
|
|
//Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it
|
|
//has a fixed offset from the address of the passed frame, we can recover it.
|
|
//gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET;
|
|
gdbstub_savedRegs.a1=(uint32_t)frame;
|
|
|
|
ets_wdt_disable();
|
|
printReason();
|
|
ets_wdt_enable();
|
|
while(1) ;
|
|
}
|
|
|
|
//The OS-less SDK uses the Xtensa HAL to handle exceptions. We can use those functions to catch any
|
|
//fatal exceptions and invoke the debugger when this happens.
|
|
void gdbstub_init() {
|
|
unsigned int i;
|
|
int exno[]={EXCCAUSE_ILLEGAL, EXCCAUSE_SYSCALL, EXCCAUSE_INSTR_ERROR, EXCCAUSE_LOAD_STORE_ERROR,
|
|
EXCCAUSE_DIVIDE_BY_ZERO, EXCCAUSE_UNALIGNED, EXCCAUSE_INSTR_DATA_ERROR, EXCCAUSE_LOAD_STORE_DATA_ERROR,
|
|
EXCCAUSE_INSTR_ADDR_ERROR, EXCCAUSE_LOAD_STORE_ADDR_ERROR, EXCCAUSE_INSTR_PROHIBITED,
|
|
EXCCAUSE_LOAD_PROHIBITED, EXCCAUSE_STORE_PROHIBITED};
|
|
for (i=0; i<(sizeof(exno)/sizeof(exno[0])); i++) {
|
|
_xtos_set_exception_handler(exno[i], gdb_exception_handler);
|
|
}
|
|
}
|
|
|
|
//extern void gdb_init() __attribute__((weak, alias("gdbstub_init")));
|