[2.0.x] Move backtrace to a shared location (#10237)
- And implement the `backtrace()` function call
This commit is contained in:
parent
7dc256432f
commit
749f19e502
15 changed files with 466 additions and 237 deletions
|
@ -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"
|
||||||
|
|
102
Marlin/src/backtrace/backtrace.cpp
Normal file
102
Marlin/src/backtrace/backtrace.cpp
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
|
29
Marlin/src/backtrace/backtrace.h
Normal file
29
Marlin/src/backtrace/backtrace.h
Normal 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
|
|
@ -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>
|
|
@ -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 */
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
@ -243,40 +243,40 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
|
|
||||||
UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
|
UnwPrintd3(" r%d = 0x%08x\n", r, state->regData[r].v);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* TBB / TBH
|
* TBB / TBH
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xfff0) == 0xe8d0 && (instr2 & 0xffe0) == 0xf000) {
|
else if ((instr & 0xfff0) == 0xe8d0 && (instr2 & 0xffe0) == 0xf000) {
|
||||||
/* We are only interested in
|
/* We are only interested in
|
||||||
* the forms
|
* the forms
|
||||||
* TBB [PC, ...]
|
* TBB [PC, ...]
|
||||||
* TBH [PC, ..., LSL #1]
|
* TBH [PC, ..., LSL #1]
|
||||||
* as those are used by the C compiler to implement
|
* as those are used by the C compiler to implement
|
||||||
* the switch clauses
|
* the switch clauses
|
||||||
*/
|
*/
|
||||||
uint8_t rn = instr & 0xf;
|
uint8_t rn = instr & 0xf;
|
||||||
uint8_t rm = instr2 & 0xf;
|
uint8_t rm = instr2 & 0xf;
|
||||||
bool H = (instr2 & 0x10) ? true : false;
|
bool H = (instr2 & 0x10) ? true : false;
|
||||||
|
|
||||||
UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, rm, H ? ",LSL #1" : "");
|
UnwPrintd5("TB%c [r%d,r%d%s]\n", H ? 'H' : 'B', rn, rm, H ? ",LSL #1" : "");
|
||||||
|
|
||||||
// We are only interested if the RN is the PC. Let´s choose the 1st destination
|
// We are only interested if the RN is the PC. Let´s choose the 1st destination
|
||||||
if (rn == 15) {
|
if (rn == 15) {
|
||||||
if (H) {
|
if (H) {
|
||||||
uint16_t rv;
|
uint16_t rv;
|
||||||
if(!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv)) {
|
if(!state->cb->readH((state->regData[15].v & (~1)) + 2, &rv)) {
|
||||||
return UNWIND_DREAD_H_FAIL;
|
return UNWIND_DREAD_H_FAIL;
|
||||||
}
|
}
|
||||||
state->regData[15].v += rv * 2;
|
state->regData[15].v += rv * 2;
|
||||||
} else {
|
} else {
|
||||||
uint8_t rv;
|
uint8_t rv;
|
||||||
if(!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv)) {
|
if(!state->cb->readB((state->regData[15].v & (~1)) + 2, &rv)) {
|
||||||
return UNWIND_DREAD_B_FAIL;
|
return UNWIND_DREAD_B_FAIL;
|
||||||
}
|
}
|
||||||
state->regData[15].v += rv * 2;
|
state->regData[15].v += rv * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Unconditional branch
|
* Unconditional branch
|
||||||
*/
|
*/
|
||||||
|
@ -408,118 +408,118 @@ UnwResult UnwStartThumb(UnwState * const state) {
|
||||||
UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
|
UnwPrintd2(" New PC=%x", state->regData[15].v + 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* PC-relative load
|
* PC-relative load
|
||||||
* LDR Rd,[PC, #+/-imm]
|
* LDR Rd,[PC, #+/-imm]
|
||||||
*/
|
*/
|
||||||
else if((instr & 0xff7f) == 0xf85f) {
|
else if((instr & 0xff7f) == 0xf85f) {
|
||||||
uint8_t rt = (instr2 & 0xf000) >> 12;
|
uint8_t rt = (instr2 & 0xf000) >> 12;
|
||||||
uint8_t imm12 = (instr2 & 0x0fff);
|
uint8_t imm12 = (instr2 & 0x0fff);
|
||||||
bool A = (instr & 0x80) ? true : false;
|
bool A = (instr & 0x80) ? true : false;
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
|
|
||||||
/* Compute load address, adding a word to account for prefetch */
|
/* Compute load address, adding a word to account for prefetch */
|
||||||
address = (state->regData[15].v & (~0x3)) + 4;
|
address = (state->regData[15].v & (~0x3)) + 4;
|
||||||
if (A) address += imm12;
|
if (A) address += imm12;
|
||||||
else address -= imm12;
|
else address -= imm12;
|
||||||
|
|
||||||
UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
|
UnwPrintd4("LDR r%d,[PC #%c0x%08x]", rt, A?'+':'-', address);
|
||||||
|
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* LDR immediate.
|
* LDR immediate.
|
||||||
* We are only interested when destination is PC.
|
* We are only interested when destination is PC.
|
||||||
* LDR Rt,[Rn , #n]
|
* LDR Rt,[Rn , #n]
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xfff0) == 0xf8d0) {
|
else if ((instr & 0xfff0) == 0xf8d0) {
|
||||||
uint8_t rn = (instr & 0xf);
|
uint8_t rn = (instr & 0xf);
|
||||||
uint8_t rt = (instr2 & 0xf000) >> 12;
|
uint8_t rt = (instr2 & 0xf000) >> 12;
|
||||||
uint16_t imm12 = (instr2 & 0xfff);
|
uint16_t imm12 = (instr2 & 0xfff);
|
||||||
|
|
||||||
/* If destination is PC and we don't know the source value, then fail */
|
/* If destination is PC and we don't know the source value, then fail */
|
||||||
if (!M_IsOriginValid(state->regData[rn].o)) {
|
if (!M_IsOriginValid(state->regData[rn].o)) {
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
} else {
|
} else {
|
||||||
uint32_t address = state->regData[rn].v + imm12;
|
uint32_t address = state->regData[rn].v + imm12;
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* LDR immediate
|
* LDR immediate
|
||||||
* We are only interested when destination is PC.
|
* We are only interested when destination is PC.
|
||||||
* LDR Rt,[Rn , #-n]
|
* LDR Rt,[Rn , #-n]
|
||||||
* LDR Rt,[Rn], #+/-n]
|
* LDR Rt,[Rn], #+/-n]
|
||||||
* LDR Rt,[Rn, #+/-n]!
|
* LDR Rt,[Rn, #+/-n]!
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0800) == 0x0800) {
|
else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0800) == 0x0800) {
|
||||||
uint8_t rn = (instr & 0xf);
|
uint8_t rn = (instr & 0xf);
|
||||||
uint8_t rt = (instr2 & 0xf000) >> 12;
|
uint8_t rt = (instr2 & 0xf000) >> 12;
|
||||||
uint16_t imm8 = (instr2 & 0xff);
|
uint16_t imm8 = (instr2 & 0xff);
|
||||||
bool P = (instr2 & 0x400) ? true : false;
|
bool P = (instr2 & 0x400) ? true : false;
|
||||||
bool U = (instr2 & 0x200) ? true : false;
|
bool U = (instr2 & 0x200) ? true : false;
|
||||||
bool W = (instr2 & 0x100) ? true : false;
|
bool W = (instr2 & 0x100) ? true : false;
|
||||||
|
|
||||||
if (!M_IsOriginValid(state->regData[rn].o)) {
|
if (!M_IsOriginValid(state->regData[rn].o)) {
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
} else {
|
} else {
|
||||||
uint32_t offaddress = state->regData[rn].v + imm8;
|
uint32_t offaddress = state->regData[rn].v + imm8;
|
||||||
if (U) offaddress += imm8;
|
if (U) offaddress += imm8;
|
||||||
else offaddress -= imm8;
|
else offaddress -= imm8;
|
||||||
|
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
if (P) {
|
if (P) {
|
||||||
address = offaddress;
|
address = offaddress;
|
||||||
} else {
|
} else {
|
||||||
address = state->regData[rn].v;
|
address = state->regData[rn].v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (W) {
|
if (W) {
|
||||||
state->regData[rn].v = offaddress;
|
state->regData[rn].v = offaddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* LDR (register).
|
* LDR (register).
|
||||||
* We are interested in the form
|
* We are interested in the form
|
||||||
* ldr Rt, [Rn, Rm, lsl #x]
|
* ldr Rt, [Rn, Rm, lsl #x]
|
||||||
* Where Rt is PC, Rn value is known, Rm is not known or unknown
|
* Where Rt is PC, Rn value is known, Rm is not known or unknown
|
||||||
*/
|
*/
|
||||||
else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0fc0) == 0x0000) {
|
else if ((instr & 0xfff0) == 0xf850 && (instr2 & 0x0fc0) == 0x0000) {
|
||||||
uint8_t rn = (instr & 0xf);
|
uint8_t rn = (instr & 0xf);
|
||||||
uint8_t rt = (instr2 & 0xf000) >> 12;
|
uint8_t rt = (instr2 & 0xf000) >> 12;
|
||||||
uint8_t rm = (instr2 & 0xf);
|
uint8_t rm = (instr2 & 0xf);
|
||||||
uint8_t imm2 = (instr2 & 0x30) >> 4;
|
uint8_t imm2 = (instr2 & 0x30) >> 4;
|
||||||
|
|
||||||
if (!M_IsOriginValid(state->regData[rn].o) ||
|
if (!M_IsOriginValid(state->regData[rn].o) ||
|
||||||
!M_IsOriginValid(state->regData[rm].o)) {
|
!M_IsOriginValid(state->regData[rm].o)) {
|
||||||
|
|
||||||
/* If Rt is PC, and Rn is known, then do an exception and assume
|
/* If Rt is PC, and Rn is known, then do an exception and assume
|
||||||
Rm equals 0 => This takes the first case in a switch() */
|
Rm equals 0 => This takes the first case in a switch() */
|
||||||
if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
|
if (rt == 15 && M_IsOriginValid(state->regData[rn].o)) {
|
||||||
uint32_t address = state->regData[rn].v;
|
uint32_t address = state->regData[rn].v;
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Propagate unknown value */
|
/* Propagate unknown value */
|
||||||
state->regData[rt].o = state->regData[rn].o;
|
state->regData[rt].o = state->regData[rn].o;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
|
uint32_t address = state->regData[rn].v + (state->regData[rm].v << imm2);
|
||||||
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
if(!UnwMemReadRegister(state, address, &state->regData[rt])) {
|
||||||
return UNWIND_DREAD_W_FAIL;
|
return UNWIND_DREAD_W_FAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
UnwPrintd1("???? (32)");
|
UnwPrintd1("???? (32)");
|
||||||
|
|
|
@ -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) {};
|
|
@ -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 */
|
|
@ -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>
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
|
@ -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 */
|
136
Marlin/src/backtrace/unwmemaccess.cpp
Normal file
136
Marlin/src/backtrace/unwmemaccess.cpp
Normal 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
|
||||||
|
|
26
Marlin/src/backtrace/unwmemaccess.h
Normal file
26
Marlin/src/backtrace/unwmemaccess.h
Normal 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
|
||||||
|
|
Reference in a new issue