arch/xtensa: Print backtrace on assertions.
Signed-off-by: Abdelatif Guettouche <abdelatif.guettouche@espressif.com>
This commit is contained in:
parent
759b63d4be
commit
9d28687b6f
@ -94,6 +94,20 @@ config XTENSA_CP_INITSET
|
||||
is provided by CONFIG_XTENSA_CP_INITSET. Each bit corresponds to one
|
||||
coprocessor with the same bit layout as for the CPENABLE register.
|
||||
|
||||
config XTENSA_DUMPBT_ON_ASSERT
|
||||
bool "Dump backtrace on assertions"
|
||||
default y
|
||||
depends on DEBUG_ALERT
|
||||
---help---
|
||||
Enable a backtrace dump on assertions.
|
||||
|
||||
config XTENSA_BTDEPTH
|
||||
int "Backtrace depth"
|
||||
default 50
|
||||
depends on XTENSA_DUMPBT_ON_ASSERT
|
||||
---help---
|
||||
This is the depth of the backtrace.
|
||||
|
||||
config XTENSA_USE_SEPARATE_IMEM
|
||||
bool "Use a separate heap for internal memory"
|
||||
default n
|
||||
|
@ -361,5 +361,9 @@ void xtensa_pminitialize(void);
|
||||
void up_stack_color(FAR void *stackbase, size_t nbytes);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_XTENSA_DUMPBT_ON_ASSERT
|
||||
void xtensa_backtrace_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc);
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __ARCH_XTENSA_SRC_COMMON_XTENSA_H */
|
||||
|
103
arch/xtensa/src/common/xtensa_backtrace.S
Normal file
103
arch/xtensa/src/common/xtensa_backtrace.S
Normal file
@ -0,0 +1,103 @@
|
||||
/****************************************************************************
|
||||
* arch/xtensa/src/common/xtensa_dumpstate.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <arch/xtensa/core.h>
|
||||
#include <arch/xtensa/xtensa_specregs.h>
|
||||
|
||||
#include "xtensa_abi.h"
|
||||
|
||||
/*
|
||||
* This is how the stack looks like when calling the function below:
|
||||
*
|
||||
* High Addr
|
||||
* ..................
|
||||
* | i-3 BSA |
|
||||
* | i-1 locals | Function B
|
||||
* .................. i-1 SP
|
||||
* | i-2 BSA |
|
||||
* | i locals | Function A (Start of backtrace)
|
||||
* ------------------ i SP
|
||||
* | i-1 BSA |
|
||||
* | i+1 locals | Backtracing function (e.g. xtensa_btdump())
|
||||
* ------------------ i+1 SP
|
||||
* | i BSA |
|
||||
* | i+2 locals | xtensa_backtrace_start()
|
||||
* ------------------ i+2 SP
|
||||
* | i+1 BSA |
|
||||
* | i+3 locals | xtensa_window_spill()
|
||||
* ------------------ i+3 SP
|
||||
* .................. Low Addr
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_backtrace_start
|
||||
*
|
||||
* Description:
|
||||
* Get the first frame of the current stack's backtrace
|
||||
*
|
||||
* Given the following function call flow (B -> A -> X -> xtensa_backtrace_start),
|
||||
* this function will do the following:
|
||||
* - Flush CPU registers and window frames onto the current stack
|
||||
* - Return PC and SP of function A (i.e. start of the stack's backtrace)
|
||||
* - Return PC of function B (i.e. next_pc)
|
||||
*
|
||||
* Input Parameters:
|
||||
* pc - PC of the first frame in the backtrace
|
||||
* sp - SP of the first frame in the backtrace
|
||||
* next_pc - PC of the first frame's caller
|
||||
*
|
||||
* C callable as:
|
||||
* void xtensa_backtrace_start(uint32_t *pc, uint32_t *sp, uint32_t *next_pc)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
.section .iram1, "ax"
|
||||
.global xtensa_backtrace_start
|
||||
.type xtensa_backtrace_start, @function
|
||||
.align 4
|
||||
|
||||
xtensa_backtrace_start:
|
||||
|
||||
ENTRY(32)
|
||||
|
||||
call8 xtensa_window_spill /* Spill registers onto stack (excluding this
|
||||
* function) */
|
||||
|
||||
/* a2, a3, a4 should be out arguments for i SP, i PC, i-1 PC respectively.
|
||||
* Use a5 and a6 as scratch.
|
||||
*/
|
||||
|
||||
l32e a5, sp, -16 /* Get i PC, which is ret addres of i+1 */
|
||||
s32i a5, a2, 0 /* Store i PC to arg *pc */
|
||||
l32e a6, sp, -12 /* Get i+1 SP. Used to access i BS */
|
||||
l32e a5, a6, -12 /* Get i SP */
|
||||
s32i a5, a3, 0 /* Store i SP to arg *sp */
|
||||
l32e a5, a6, -16 /* Get i-1 PC, which is ret address of i */
|
||||
s32i a5, a4, 0 /* Store i-1 PC to arg *next_pc */
|
||||
RET0
|
||||
|
||||
.size xtensa_backtrace_start, . - xtensa_backtrace_start
|
||||
|
@ -32,12 +32,12 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/arch.h>
|
||||
|
||||
#include <arch/xtensa/xtensa_corebits.h>
|
||||
#include <arch/board/board.h>
|
||||
#include <arch/chip/core-isa.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "xtensa.h"
|
||||
#include "chip_macros.h"
|
||||
#include "chip_memory.h"
|
||||
|
||||
#ifdef CONFIG_DEBUG_ALERT
|
||||
|
||||
@ -150,6 +150,109 @@ static inline void xtensa_registerdump(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_XTENSA_DUMPBT_ON_ASSERT
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_getcause
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t xtensa_getcause(void)
|
||||
{
|
||||
uint32_t cause;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"rsr %0, EXCCAUSE" : "=r"(cause)
|
||||
);
|
||||
|
||||
return cause;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stackpc
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t stackpc(uint32_t pc)
|
||||
{
|
||||
if (pc & 0x80000000)
|
||||
{
|
||||
/* Top two bits of a0 (return address) specify window increment.
|
||||
* Overwrite to map to address space.
|
||||
*/
|
||||
|
||||
pc = (pc & 0x3fffffff) | 0x40000000;
|
||||
}
|
||||
|
||||
/* Minus 3 to get PC of previous instruction (i.e. instruction executed
|
||||
* before return address).
|
||||
*/
|
||||
|
||||
return pc - 3;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: corruptedframe
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool corruptedframe(uint32_t pc, uint32_t sp)
|
||||
{
|
||||
return !(xtensa_ptr_exec((void *)stackpc(pc)) || xtensa_sp_sane(sp));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nextframe
|
||||
****************************************************************************/
|
||||
|
||||
static bool nextframe(uint32_t *pc, uint32_t *sp, uint32_t *npc)
|
||||
{
|
||||
/* Use frame(i - 1)'s base save area located below frame(i)'s sp to get
|
||||
* frame(i - 1)'s sp and frame(i - 2)'s pc. Base save area consists of
|
||||
* 4 words under SP.
|
||||
*/
|
||||
|
||||
void *bsa = (void *)*sp;
|
||||
|
||||
*pc = *npc;
|
||||
*npc = *((uint32_t *)(bsa - 16));
|
||||
*sp = *((uint32_t *)(bsa - 12));
|
||||
|
||||
return !corruptedframe(*pc, *sp);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: xtensa_btdump
|
||||
****************************************************************************/
|
||||
|
||||
static inline void xtensa_btdump(void)
|
||||
{
|
||||
uint32_t pc;
|
||||
uint32_t sp;
|
||||
uint32_t npc;
|
||||
int i;
|
||||
bool corrupted = false;
|
||||
|
||||
xtensa_backtrace_start(&pc, &sp, &npc);
|
||||
|
||||
_alert("Backtrace0: %x:%x\n", stackpc(pc), sp);
|
||||
|
||||
corrupted = corruptedframe(pc, sp) &&
|
||||
!(xtensa_getcause() == EXCCAUSE_INSTR_PROHIBITED);
|
||||
|
||||
for (i = 1; i <= CONFIG_XTENSA_BTDEPTH && npc != 0 && !corrupted; i++)
|
||||
{
|
||||
if (!nextframe(&pc, &sp, &npc))
|
||||
{
|
||||
corrupted = true;
|
||||
}
|
||||
|
||||
_alert("Backtrace%d: %x:%x\n", i, stackpc(pc), sp);
|
||||
}
|
||||
|
||||
_alert("BACKTRACE %s\n",
|
||||
(corrupted ? "CORRUPTED!" : (npc == 0 ? "Done":"CONTINUES...")));
|
||||
}
|
||||
#endif /* CONFIG_XTENSA_DUMPBT_ON_ASSERT */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -179,6 +282,12 @@ void xtensa_dumpstate(void)
|
||||
|
||||
xtensa_registerdump();
|
||||
|
||||
/* Dump the backtrace */
|
||||
|
||||
#ifdef CONFIG_XTENSA_DUMPBT_ON_ASSERT
|
||||
xtensa_btdump();
|
||||
#endif
|
||||
|
||||
/* Get the limits on the user stack memory */
|
||||
|
||||
ustackbase = (uint32_t)rtcb->adj_stack_ptr;
|
||||
@ -267,4 +376,4 @@ void xtensa_dumpstate(void)
|
||||
up_showtasks();
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ARCH_STACKDUMP */
|
||||
#endif /* CONFIG_DEBUG_ALERT */
|
||||
|
@ -65,6 +65,10 @@ ifeq ($(CONFIG_DEBUG_ALERT),y)
|
||||
CMN_CSRCS += xtensa_dumpstate.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_XTENSA_DUMPBT_ON_ASSERT),y)
|
||||
CMN_ASRCS += xtensa_backtrace.S
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SPINLOCK),y)
|
||||
CMN_CSRCS += xtensa_testset.c
|
||||
endif
|
||||
@ -165,7 +169,6 @@ CHIP_CSRCS += esp32_wtd.c
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CONFIG_ARCH_USE_MODULE_TEXT),y)
|
||||
CHIP_CSRCS += esp32_modtext.c
|
||||
CMN_ASRCS += xtensa_loadstore.S
|
||||
|
@ -794,6 +794,19 @@ extern int rom_i2c_writeReg(int block, int block_id, int reg_add,
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_sp_dram
|
||||
*
|
||||
* Description:
|
||||
* Check if the stack pointer is in DRAM.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool IRAM_ATTR esp32_sp_dram(uint32_t sp)
|
||||
{
|
||||
return (sp >= SOC_DRAM_LOW + 0x10 && sp < SOC_DRAM_HIGH - 0x10);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_ptr_extram
|
||||
*
|
||||
@ -808,4 +821,24 @@ static inline bool IRAM_ATTR esp32_ptr_extram(const void *p)
|
||||
(intptr_t)p < SOC_EXTRAM_DATA_HIGH);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: esp32_ptr_exec
|
||||
*
|
||||
* Description:
|
||||
* Check if the pointer is within an executable range.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline bool IRAM_ATTR esp32_ptr_exec(const void *p)
|
||||
{
|
||||
intptr_t ip = (intptr_t)p;
|
||||
return (ip >= SOC_IROM_LOW && ip < SOC_IROM_HIGH)
|
||||
|| (ip >= SOC_IRAM_LOW && ip < SOC_IRAM_HIGH)
|
||||
|| (ip >= SOC_IROM_MASK_LOW && ip < SOC_IROM_MASK_HIGH)
|
||||
#if defined(SOC_CACHE_APP_LOW) && !defined(CONFIG_SMP)
|
||||
|| (ip >= SOC_CACHE_APP_LOW && ip < SOC_CACHE_APP_HIGH)
|
||||
#endif
|
||||
|| (ip >= SOC_RTC_IRAM_LOW && ip < SOC_RTC_IRAM_HIGH);
|
||||
}
|
||||
|
||||
#endif /* __ARCH_XTENSA_SRC_ESP32_HARDWARE_ESP32_SOC_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user