Postmortem Debugging to serial port (#20492)
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
#include "unwinder.h"
|
||||
#include "unwmemaccess.h"
|
||||
|
||||
#include "../../../core/serial.h"
|
||||
#include "../HAL_MinSerial.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
// Dump a backtrace entry
|
||||
@@ -34,10 +34,12 @@ static bool UnwReportOut(void* ctx, const UnwReport* bte) {
|
||||
|
||||
(*p)++;
|
||||
|
||||
SERIAL_CHAR('#'); SERIAL_ECHO(*p); SERIAL_ECHOPGM(" : ");
|
||||
SERIAL_ECHOPGM(bte->name ? bte->name : "unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function, PrintBase::Hex);
|
||||
SERIAL_CHAR('+'); SERIAL_ECHO(bte->address - bte->function);
|
||||
SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address, PrintBase::Hex); SERIAL_CHAR('\n');
|
||||
const uint32_t a = bte->address, f = bte->function;
|
||||
MinSerial::TX('#'); MinSerial::TXDec(*p); MinSerial::TX(" : ");
|
||||
MinSerial::TX(bte->name?:"unknown"); MinSerial::TX('@'); MinSerial::TXHex(f);
|
||||
MinSerial::TX('+'); MinSerial::TXDec(a - f);
|
||||
MinSerial::TX(" PC:"); MinSerial::TXHex(a);
|
||||
MinSerial::TX('\n');
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -48,7 +50,7 @@ static bool UnwReportOut(void* ctx, const UnwReport* bte) {
|
||||
va_start(argptr, format);
|
||||
vsprintf(dest, format, argptr);
|
||||
va_end(argptr);
|
||||
TX(&dest[0]);
|
||||
MinSerial::TX(&dest[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -63,10 +65,10 @@ static const UnwindCallbacks UnwCallbacks = {
|
||||
#endif
|
||||
};
|
||||
|
||||
// Perform a backtrace to the serial port
|
||||
void backtrace() {
|
||||
|
||||
UnwindFrame btf;
|
||||
uint32_t sp = 0, lr = 0, pc = 0;
|
||||
unsigned long sp = 0, lr = 0, pc = 0;
|
||||
|
||||
// Capture the values of the registers to perform the traceback
|
||||
__asm__ __volatile__ (
|
||||
@@ -79,6 +81,12 @@ void backtrace() {
|
||||
::
|
||||
);
|
||||
|
||||
backtrace_ex(sp, lr, pc);
|
||||
}
|
||||
|
||||
void backtrace_ex(unsigned long sp, unsigned long lr, unsigned long pc) {
|
||||
UnwindFrame btf;
|
||||
|
||||
// Fill the traceback structure
|
||||
btf.sp = sp;
|
||||
btf.fp = btf.sp;
|
||||
@@ -86,7 +94,7 @@ void backtrace() {
|
||||
btf.pc = pc | 1; // Force Thumb, as CORTEX only support it
|
||||
|
||||
// Perform a backtrace
|
||||
SERIAL_ERROR_MSG("Backtrace:");
|
||||
MinSerial::TX("Backtrace:");
|
||||
int ctr = 0;
|
||||
UnwindStart(&btf, &UnwCallbacks, &ctr);
|
||||
}
|
||||
@@ -95,4 +103,4 @@ void backtrace() {
|
||||
|
||||
void backtrace() {}
|
||||
|
||||
#endif
|
||||
#endif // __arm__ || __thumb__
|
||||
|
||||
@@ -23,3 +23,6 @@
|
||||
|
||||
// Perform a backtrace to the serial port
|
||||
void backtrace();
|
||||
|
||||
// Perform a backtrace to the serial port
|
||||
void backtrace_ex(unsigned long sp, unsigned long lr, unsigned long pc);
|
||||
|
||||
@@ -41,27 +41,16 @@
|
||||
#define START_FLASH_ADDR 0x00000000
|
||||
#define END_FLASH_ADDR 0x00080000
|
||||
|
||||
#elif 0
|
||||
|
||||
// For STM32F103CBT6
|
||||
// SRAM (0x20000000 - 0x20005000) (20kb)
|
||||
// FLASH (0x00000000 - 0x00020000) (128kb)
|
||||
//
|
||||
#define START_SRAM_ADDR 0x20000000
|
||||
#define END_SRAM_ADDR 0x20005000
|
||||
#define START_FLASH_ADDR 0x00000000
|
||||
#define END_FLASH_ADDR 0x00020000
|
||||
|
||||
#elif defined(__STM32F1__) || defined(STM32F1xx) || defined(STM32F0xx)
|
||||
|
||||
// For STM32F103ZET6/STM32F103VET6/STM32F0xx
|
||||
// SRAM (0x20000000 - 0x20010000) (64kb)
|
||||
// FLASH (0x00000000 - 0x00080000) (512kb)
|
||||
// FLASH (0x08000000 - 0x08080000) (512kb)
|
||||
//
|
||||
#define START_SRAM_ADDR 0x20000000
|
||||
#define END_SRAM_ADDR 0x20010000
|
||||
#define START_FLASH_ADDR 0x00000000
|
||||
#define END_FLASH_ADDR 0x00080000
|
||||
#define START_FLASH_ADDR 0x08000000
|
||||
#define END_FLASH_ADDR 0x08080000
|
||||
|
||||
#elif defined(STM32F4) || defined(STM32F4xx)
|
||||
|
||||
@@ -142,20 +131,57 @@
|
||||
#define START_FLASH_ADDR 0x00000000
|
||||
#define END_FLASH_ADDR 0x00100000
|
||||
|
||||
#else
|
||||
// Generic ARM code, that's testing if an access to the given address would cause a fault or not
|
||||
// It can't guarantee an address is in RAM or Flash only, but we usually don't care
|
||||
|
||||
#define NVIC_FAULT_STAT 0xE000ED28 // Configurable Fault Status Reg.
|
||||
#define NVIC_CFG_CTRL 0xE000ED14 // Configuration Control Register
|
||||
#define NVIC_FAULT_STAT_BFARV 0x00008000 // BFAR is valid
|
||||
#define NVIC_CFG_CTRL_BFHFNMIGN 0x00000100 // Ignore bus fault in NMI/fault
|
||||
#define HW_REG(X) (*((volatile unsigned long *)(X)))
|
||||
|
||||
static bool validate_addr(uint32_t read_address) {
|
||||
bool works = true;
|
||||
uint32_t intDisabled = 0;
|
||||
// Read current interrupt state
|
||||
__asm__ __volatile__ ("MRS %[result], PRIMASK\n\t" : [result]"=r"(intDisabled) :: ); // 0 is int enabled, 1 for disabled
|
||||
|
||||
// Clear bus fault indicator first (write 1 to clear)
|
||||
HW_REG(NVIC_FAULT_STAT) |= NVIC_FAULT_STAT_BFARV;
|
||||
// Ignore bus fault interrupt
|
||||
HW_REG(NVIC_CFG_CTRL) |= NVIC_CFG_CTRL_BFHFNMIGN;
|
||||
// Disable interrupts if not disabled previously
|
||||
if (!intDisabled) __asm__ __volatile__ ("CPSID f");
|
||||
// Probe address
|
||||
*(volatile uint32_t*)read_address;
|
||||
// Check if a fault happened
|
||||
if ((HW_REG(NVIC_FAULT_STAT) & NVIC_FAULT_STAT_BFARV) != 0)
|
||||
works = false;
|
||||
// Enable interrupts again if previously disabled
|
||||
if (!intDisabled) __asm__ __volatile__ ("CPSIE f");
|
||||
// Enable fault interrupt flag
|
||||
HW_REG(NVIC_CFG_CTRL) &= ~NVIC_CFG_CTRL_BFHFNMIGN;
|
||||
|
||||
return works;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool validate_addr(uint32_t addr) {
|
||||
#ifdef START_SRAM_ADDR
|
||||
static bool validate_addr(uint32_t addr) {
|
||||
|
||||
// Address must be in SRAM range
|
||||
if (addr >= START_SRAM_ADDR && addr < END_SRAM_ADDR)
|
||||
return true;
|
||||
// Address must be in SRAM range
|
||||
if (addr >= START_SRAM_ADDR && addr < END_SRAM_ADDR)
|
||||
return true;
|
||||
|
||||
// Or in FLASH range
|
||||
if (addr >= START_FLASH_ADDR && addr < END_FLASH_ADDR)
|
||||
return true;
|
||||
// Or in FLASH range
|
||||
if (addr >= START_FLASH_ADDR && addr < END_FLASH_ADDR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool UnwReadW(const uint32_t a, uint32_t *v) {
|
||||
if (!validate_addr(a))
|
||||
|
||||
Reference in New Issue
Block a user