[2.0.x] Move backtrace to a shared location (#10237)

- And implement the `backtrace()` function call
This commit is contained in:
Eduardo José Tagle 2018-03-28 15:13:20 -03:00 committed by Scott Lahteine
parent 7dc256432f
commit 749f19e502
15 changed files with 466 additions and 237 deletions

View file

@ -24,7 +24,8 @@
#include "../../inc/MarlinConfig.h" #include "../../inc/MarlinConfig.h"
#include "../../Marlin.h" #include "../../Marlin.h"
#include "backtrace/unwinder.h" #include "../../backtrace/unwinder.h"
#include "../../backtrace/unwmemaccess.h"
// Debug monitor that dumps to the Programming port all status when // Debug monitor that dumps to the Programming port all status when
// an exception or WDT timeout happens - And then resets the board // an exception or WDT timeout happens - And then resets the board
@ -112,45 +113,6 @@ static void TXDec(uint32_t v) {
} while (p != &nbrs[0]); } while (p != &nbrs[0]);
} }
/* Validate address */
static bool validate_addr(uint32_t addr) {
// Address must be in SRAM (0x20070000 - 0x20088000)
if (addr >= 0x20070000 && addr < 0x20088000)
return true;
// Or in FLASH (0x00080000 - 0x00100000)
if (addr >= 0x00080000 && addr < 0x00100000)
return true;
return false;
}
static bool UnwReadW(const uint32_t a, uint32_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint32_t *)a;
return true;
}
static bool UnwReadH(const uint32_t a, uint16_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint16_t *)a;
return true;
}
static bool UnwReadB(const uint32_t a, uint8_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint8_t *)a;
return true;
}
// Dump a backtrace entry // Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) { static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int* p = (int*)ctx; int* p = (int*)ctx;
@ -270,7 +232,8 @@ void HardFault_HandlerC(unsigned long *sp, unsigned long lr, unsigned long cause
} }
__attribute__((naked)) void NMI_Handler(void) { __attribute__((naked)) void NMI_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -282,7 +245,8 @@ __attribute__((naked)) void NMI_Handler(void) {
} }
__attribute__((naked)) void HardFault_Handler(void) { __attribute__((naked)) void HardFault_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -294,7 +258,8 @@ __attribute__((naked)) void HardFault_Handler(void) {
} }
__attribute__((naked)) void MemManage_Handler(void) { __attribute__((naked)) void MemManage_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -306,7 +271,8 @@ __attribute__((naked)) void MemManage_Handler(void) {
} }
__attribute__((naked)) void BusFault_Handler(void) { __attribute__((naked)) void BusFault_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -318,7 +284,8 @@ __attribute__((naked)) void BusFault_Handler(void) {
} }
__attribute__((naked)) void UsageFault_Handler(void) { __attribute__((naked)) void UsageFault_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -330,7 +297,8 @@ __attribute__((naked)) void UsageFault_Handler(void) {
} }
__attribute__((naked)) void DebugMon_Handler(void) { __attribute__((naked)) void DebugMon_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -343,7 +311,8 @@ __attribute__((naked)) void DebugMon_Handler(void) {
/* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */ /* This is NOT an exception, it is an interrupt handler - Nevertheless, the framing is the same */
__attribute__((naked)) void WDT_Handler(void) { __attribute__((naked)) void WDT_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"
@ -355,7 +324,8 @@ __attribute__((naked)) void WDT_Handler(void) {
} }
__attribute__((naked)) void RSTC_Handler(void) { __attribute__((naked)) void RSTC_Handler(void) {
__asm volatile ( __asm__ __volatile__ (
".syntax unified \n"
" tst lr, #4 \n" " tst lr, #4 \n"
" ite eq \n" " ite eq \n"
" mrseq r0, msp \n" " mrseq r0, msp \n"

View file

@ -0,0 +1,102 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "backtrace.h"
#if defined(__arm__) || defined(__thumb__)
#include "unwinder.h"
#include "unwmemaccess.h"
#include "../Marlin.h"
// Dump a backtrace entry
static bool UnwReportOut(void* ctx, const UnwReport* bte) {
int* p = (int*)ctx;
(*p)++;
SERIAL_CHAR('#'); SERIAL_PRINT(*p,DEC); SERIAL_ECHOPGM(" : ");
SERIAL_ECHOPGM(bte->name?bte->name:"unknown"); SERIAL_ECHOPGM("@0x"); SERIAL_PRINT(bte->function,HEX);
SERIAL_CHAR('+'); SERIAL_PRINT(bte->address - bte->function,DEC);
SERIAL_ECHOPGM(" PC:"); SERIAL_PRINT(bte->address,HEX); SERIAL_CHAR('\n');
return true;
}
#if defined(UNW_DEBUG)
void UnwPrintf(const char* format, ...) {
char dest[256];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
TX(&dest[0]);
}
#endif
/* Table of function pointers for passing to the unwinder */
static const UnwindCallbacks UnwCallbacks = {
UnwReportOut,
UnwReadW,
UnwReadH,
UnwReadB
#if defined(UNW_DEBUG)
,UnwPrintf
#endif
};
void backtrace(void) {
UnwindFrame btf;
uint32_t sp,lr,pc;
// Capture the values of the registers to perform the traceback
__asm__ __volatile__ (
" mov %[lrv],lr\n"
" mov %[spv],sp\n"
" mov %[pcv],pc\n"
: [spv]"+r"( sp ),
[lrv]"+r"( lr ),
[pcv]"+r"( pc )
::
);
// Fill the traceback structure
btf.sp = sp;
btf.fp = btf.sp;
btf.lr = lr;
btf.pc = pc | 1; // Force Thumb, as CORTEX only support it
// Perform a backtrace
SERIAL_ERROR_START();
SERIAL_ERRORLNPGM("Backtrace:");
int ctr = 0;
UnwindStart(&btf, &UnwCallbacks, &ctr);
}
#else
void backtrace(void) {}
#endif

View file

@ -0,0 +1,29 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _BACKTRACE_H_
#define _BACKTRACE_H_
// Perform a backtrace to the serial port
void backtrace(void);
#endif

View file

@ -12,12 +12,11 @@
* File Description: Utility functions and glue for ARM unwinding sub-modules. * File Description: Utility functions and glue for ARM unwinding sub-modules.
**************************************************************************/ **************************************************************************/
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARM" #define MODULE_NAME "UNWARM"
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>

View file

@ -54,7 +54,7 @@ typedef struct {
/** The origin of the register value. /** The origin of the register value.
* This is used to track how the value in the register was loaded. * This is used to track how the value in the register was loaded.
*/ */
RegValOrigin o; int o; /* (RegValOrigin) */
} RegData; } RegData;
@ -131,10 +131,6 @@ typedef struct {
* Function Prototypes * Function Prototypes
**************************************************************************/ **************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
UnwResult UnwStartArm(UnwState * const state); UnwResult UnwStartArm(UnwState * const state);
UnwResult UnwStartThumb(UnwState * const state); UnwResult UnwStartThumb(UnwState * const state);
void UnwInvalidateRegisterFile(RegData *regFile); void UnwInvalidateRegisterFile(RegData *regFile);
@ -144,10 +140,6 @@ bool UnwMemWriteRegister(UnwState * const state, const uint32_t addr, const RegD
bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg); bool UnwMemReadRegister(UnwState * const state, const uint32_t addr, RegData * const reg);
void UnwMemHashGC(UnwState * const state); void UnwMemHashGC(UnwState * const state);
#ifdef __cplusplus
}
#endif
#endif /* UNWARM_H */ #endif /* UNWARM_H */
/* END OF FILE */ /* END OF FILE */

View file

@ -12,7 +12,7 @@
* File Description: Abstract interpreter for ARM mode. * File Description: Abstract interpreter for ARM mode.
**************************************************************************/ **************************************************************************/
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARM_ARM" #define MODULE_NAME "UNWARM_ARM"
@ -180,7 +180,7 @@ UnwResult UnwStartArm(UnwState * const state) {
uint8_t rd = (instr & 0x0000f000) >> 12; uint8_t rd = (instr & 0x0000f000) >> 12;
uint16_t operand2 = (instr & 0x00000fff); uint16_t operand2 = (instr & 0x00000fff);
uint32_t op2val; uint32_t op2val;
RegValOrigin op2origin; int op2origin;
switch(opcode) { switch(opcode) {
case 0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break; case 0: UnwPrintd4("AND%s r%d,r%d,", S ? "S" : "", rd, rn); break;
@ -344,7 +344,7 @@ UnwResult UnwStartArm(UnwState * const state) {
} }
else { else {
state->regData[rd].o = state->regData[rn].o; state->regData[rd].o = state->regData[rn].o;
state->regData[rd].o |= op2origin; state->regData[rd].o = (RegValOrigin)(state->regData[rd].o | op2origin);
} }
break; break;
@ -363,7 +363,7 @@ UnwResult UnwStartArm(UnwState * const state) {
case 13: /* MOV: Rd:= Op2 */ case 13: /* MOV: Rd:= Op2 */
case 15: /* MVN: Rd:= NOT Op2 */ case 15: /* MVN: Rd:= NOT Op2 */
state->regData[rd].o = op2origin; state->regData[rd].o = (RegValOrigin) op2origin;
break; break;
} }

View file

@ -12,7 +12,7 @@
* File Description: Abstract interpretation for Thumb mode. * File Description: Abstract interpretation for Thumb mode.
**************************************************************************/ **************************************************************************/
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARM_THUMB" #define MODULE_NAME "UNWARM_THUMB"

View file

@ -11,7 +11,7 @@
* for exceptions for debugging purposes in 2018 by Eduardo José Tagle. * for exceptions for debugging purposes in 2018 by Eduardo José Tagle.
*/ */
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#include "unwarmbytab.h" #include "unwarmbytab.h"
@ -19,8 +19,8 @@
#include <string.h> #include <string.h>
/* These symbols point to the unwind index and should be provide by the linker script */ /* These symbols point to the unwind index and should be provide by the linker script */
extern const UnwTabEntry __exidx_start[]; extern "C" const UnwTabEntry __exidx_start[];
extern const UnwTabEntry __exidx_end[]; extern "C" const UnwTabEntry __exidx_end[];
/* This prevents the linking of libgcc unwinder code */ /* This prevents the linking of libgcc unwinder code */
void __aeabi_unwind_cpp_pr0(void) {}; void __aeabi_unwind_cpp_pr0(void) {};

View file

@ -29,16 +29,8 @@ typedef struct {
uint32_t insn; uint32_t insn;
} UnwTabEntry; } UnwTabEntry;
#ifdef __cplusplus
extern "C" {
#endif
UnwResult UnwindByTableStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data); UnwResult UnwindByTableStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);
#ifdef __cplusplus
}
#endif
#endif #endif
/* END OF FILE */ /* END OF FILE */

View file

@ -12,7 +12,7 @@
* File Description: Implementation of the memory tracking sub-system. * File Description: Implementation of the memory tracking sub-system.
**************************************************************************/ **************************************************************************/
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWARMMEM" #define MODULE_NAME "UNWARMMEM"
#include <stdio.h> #include <stdio.h>

View file

@ -17,17 +17,9 @@
#include "unwarm.h" #include "unwarm.h"
#ifdef __cplusplus
extern "C" {
#endif
bool UnwMemHashRead(MemData * const memData, uint32_t addr, uint32_t * const data, bool * const tracked); bool UnwMemHashRead(MemData * const memData, uint32_t addr, uint32_t * const data, bool * const tracked);
bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid); bool UnwMemHashWrite(MemData * const memData, uint32_t addr, uint32_t val, bool valValid);
void UnwMemHashGC(UnwState * const state); void UnwMemHashGC(UnwState * const state);
#ifdef __cplusplus
}
#endif
#endif #endif

View file

@ -12,7 +12,7 @@
* File Description: Implementation of the interface into the ARM unwinder. * File Description: Implementation of the interface into the ARM unwinder.
**************************************************************************/ **************************************************************************/
#ifdef ARDUINO_ARCH_SAM #if defined(__arm__) || defined(__thumb__)
#define MODULE_NAME "UNWINDER" #define MODULE_NAME "UNWINDER"
@ -23,8 +23,8 @@
#include "unwarmbytab.h" #include "unwarmbytab.h"
/* These symbols point to the unwind index and should be provide by the linker script */ /* These symbols point to the unwind index and should be provide by the linker script */
extern const UnwTabEntry __exidx_start[]; extern "C" const UnwTabEntry __exidx_start[];
extern const UnwTabEntry __exidx_end[]; extern "C" const UnwTabEntry __exidx_end[];
// Detect if unwind information is present or not // Detect if unwind information is present or not
static int HasUnwindTableInfo(void) { static int HasUnwindTableInfo(void) {

View file

@ -17,7 +17,6 @@
#define UNWINDER_H #define UNWINDER_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
/** \def UNW_DEBUG /** \def UNW_DEBUG
* If this define is set, additional information will be produced while * If this define is set, additional information will be produced while
@ -161,10 +160,6 @@ typedef struct {
uint32_t pc; uint32_t pc;
} UnwindFrame; } UnwindFrame;
#ifdef __cplusplus
extern "C" {
#endif
/** Start unwinding the current stack. /** Start unwinding the current stack.
* This will unwind the stack starting at the PC value supplied to in the * This will unwind the stack starting at the PC value supplied to in the
* link register (i.e. not a normal register) and the stack pointer value * link register (i.e. not a normal register) and the stack pointer value
@ -177,8 +172,4 @@ extern "C" {
*/ */
UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data); UnwResult UnwindStart(UnwindFrame* frame, const UnwindCallbacks *cb, void *data);
#ifdef __cplusplus
}
#endif
#endif /* UNWINDER_H */ #endif /* UNWINDER_H */

View file

@ -0,0 +1,136 @@
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
* Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
*
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commercially or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liability for it's use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions to access memory
**************************************************************************/
#if defined(__arm__) || defined(__thumb__)
#include "unwmemaccess.h"
/* Validate address */
#ifdef ARDUINO_ARCH_SAM
// For DUE, valid address ranges are
// SRAM (0x20070000 - 0x20088000) (96kb)
// FLASH (0x00080000 - 0x00100000) (512kb)
//
#define START_SRAM_ADDR 0x20070000
#define END_SRAM_ADDR 0x20088000
#define START_FLASH_ADDR 0x00080000
#define END_FLASH_ADDR 0x00100000
#endif
#ifdef TARGET_LPC1768
// For LPC1769:
// SRAM (0x10000000 - 0x10008000) (32kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x10000000
#define END_SRAM_ADDR 0x10008000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#endif
#if 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
#endif
#ifdef __STM32F1__
// For STM32F103ZET6/STM32F103VET6
// SRAM (0x20000000 - 0x20010000) (64kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20010000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#endif
#ifdef STM32F7
// For STM32F765 in BORG
// SRAM (0x20000000 - 0x20080000) (512kb)
// FLASH (0x08000000 - 0x08100000) (1024kb)
//
#define START_SRAM_ADDR 0x20000000
#define END_SRAM_ADDR 0x20080000
#define START_FLASH_ADDR 0x08000000
#define END_FLASH_ADDR 0x08100000
#endif
#ifdef __MK64FX512__
// For MK64FX512 in TEENSY 3.5
// SRAM (0x1FFF0000 - 0x20020000) (192kb)
// FLASH (0x00000000 - 0x00080000) (512kb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20020000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00080000
#endif
#ifdef __MK66FX1M0__
// For MK66FX1M0 in TEENSY 3.6
// SRAM (0x1FFF0000 - 0x20030000) (256kb)
// FLASH (0x00000000 - 0x00140000) (1.25Mb)
//
#define START_SRAM_ADDR 0x1FFF0000
#define END_SRAM_ADDR 0x20030000
#define START_FLASH_ADDR 0x00000000
#define END_FLASH_ADDR 0x00140000
#endif
static bool validate_addr(uint32_t addr) {
// 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;
return false;
}
bool UnwReadW(const uint32_t a, uint32_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint32_t *)a;
return true;
}
bool UnwReadH(const uint32_t a, uint16_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint16_t *)a;
return true;
}
bool UnwReadB(const uint32_t a, uint8_t *v) {
if (!validate_addr(a))
return false;
*v = *(uint8_t *)a;
return true;
}
#endif

View file

@ -0,0 +1,26 @@
/***************************************************************************
* ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk
* Updated, adapted and several bug fixes on 2018 by Eduardo José Tagle
*
* This program is PUBLIC DOMAIN.
* This means that there is no copyright and anyone is able to take a copy
* for free and use it as they wish, with or without modifications, and in
* any context, commerically or otherwise. The only limitation is that I
* don't guarantee that the software is fit for any purpose or accept any
* liablity for it's use or misuse - this software is without warranty.
***************************************************************************
* File Description: Utility functions to access memory
**************************************************************************/
#ifndef UNWMEMACCESS_H
#define UNWMEMACCESS_H
#include "unwarm.h"
#include <stdint.h>
bool UnwReadW(const uint32_t a, uint32_t *v);
bool UnwReadH(const uint32_t a, uint16_t *v);
bool UnwReadB(const uint32_t a, uint8_t *v);
#endif