From a681faba1602b036b04ca6a39210277cd7f86a27 Mon Sep 17 00:00:00 2001 From: Jerome Forissier Date: Fri, 2 Sep 2016 11:39:03 +0200 Subject: [PATCH] trace.h: add macros to unwind and print the call stack (kernel only) Adds [EIDF]PRINT_STACK() for debugging purposes. Depends on CFG_CORE_UNWIND=y. As a side-effect, also adds a few things that may be useful on their own: __always_inline, read_pc(), read_fp(), read_lr(). Signed-off-by: Jerome Forissier Reviewed-by: Jens Wiklander --- core/arch/arm/include/arm32.h | 25 +++++++++++++++++++ core/arch/arm/include/arm64.h | 17 +++++++++++++ core/arch/arm/include/kernel/unwind.h | 9 +++++++ core/arch/arm/kernel/unwind_arm32.c | 36 +++++++++++++++++++++++++++ core/arch/arm/kernel/unwind_arm64.c | 35 ++++++++++++++++++++++++++ lib/libutils/ext/include/compiler.h | 2 +- lib/libutils/ext/include/trace.h | 33 ++++++++++++++++++++++++ lib/libutils/isoc/include/sys/cdefs.h | 2 ++ 8 files changed, 158 insertions(+), 1 deletion(-) diff --git a/core/arch/arm/include/arm32.h b/core/arch/arm/include/arm32.h index d20419b0acc..78887bb6482 100644 --- a/core/arch/arm/include/arm32.h +++ b/core/arch/arm/include/arm32.h @@ -29,6 +29,7 @@ #ifndef ARM32_H #define ARM32_H +#include #include #include @@ -533,6 +534,30 @@ static inline uint32_t read_cntfrq(void) asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq)); return frq; } + +static __always_inline uint32_t read_pc(void) +{ + uint32_t val; + + asm volatile ("adr %0, ." : "=r" (val)); + return val; +} + +static __always_inline uint32_t read_sp(void) +{ + uint32_t val; + + asm volatile ("mov %0, sp" : "=r" (val)); + return val; +} + +static __always_inline uint32_t read_lr(void) +{ + uint32_t val; + + asm volatile ("mov %0, lr" : "=r" (val)); + return val; +} #endif /*ASM*/ #endif /*ARM32_H*/ diff --git a/core/arch/arm/include/arm64.h b/core/arch/arm/include/arm64.h index fff196824bb..148b7615f97 100644 --- a/core/arch/arm/include/arm64.h +++ b/core/arch/arm/include/arm64.h @@ -27,6 +27,7 @@ #ifndef ARM64_H #define ARM64_H +#include #include #include @@ -221,6 +222,22 @@ static inline void write_at_s1e1r(uint64_t va) asm volatile ("at S1E1R, %0" : : "r" (va)); } +static __always_inline uint64_t read_pc(void) +{ + uint64_t val; + + asm volatile ("adr %0, ." : "=r" (val)); + return val; +} + +static __always_inline uint64_t read_fp(void) +{ + uint64_t val; + + asm volatile ("mov %0, x29" : "=r" (val)); + return val; +} + /* * Templates for register read/write functions based on mrs/msr */ diff --git a/core/arch/arm/include/kernel/unwind.h b/core/arch/arm/include/kernel/unwind.h index 846f6590c2d..cc5ff5a19e4 100644 --- a/core/arch/arm/include/kernel/unwind.h +++ b/core/arch/arm/include/kernel/unwind.h @@ -57,6 +57,15 @@ struct unwind_state { #endif /*ARM64*/ bool unwind_stack(struct unwind_state *state); + +#if defined(CFG_CORE_UNWIND) && (TRACE_LEVEL > 0) +void print_stack(int level); +#else +static inline void print_stack(int level __unused) +{ +} +#endif + #endif /*ASM*/ #ifdef CFG_CORE_UNWIND diff --git a/core/arch/arm/kernel/unwind_arm32.c b/core/arch/arm/kernel/unwind_arm32.c index 921f469d0ce..fa75e962e38 100644 --- a/core/arch/arm/kernel/unwind_arm32.c +++ b/core/arch/arm/kernel/unwind_arm32.c @@ -29,7 +29,10 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include +#include #include /* The register names */ @@ -358,6 +361,39 @@ bool unwind_stack(struct unwind_state *state) return !finished; } +#if defined(CFG_CORE_UNWIND) && (TRACE_LEVEL > 0) + +void print_stack(int level) +{ + struct unwind_state state; + + memset(&state, 0, sizeof(state)); + state.registers[SP] = read_sp(); + state.registers[LR] = read_lr(); + state.registers[PC] = read_pc(); + + do { + switch (level) { + case TRACE_FLOW: + FMSG_RAW("pc 0x%08" PRIx32, state.registers[PC]); + break; + case TRACE_DEBUG: + DMSG_RAW("pc 0x%08" PRIx32, state.registers[PC]); + break; + case TRACE_INFO: + IMSG_RAW("pc 0x%08" PRIx32, state.registers[PC]); + break; + case TRACE_ERROR: + EMSG_RAW("pc 0x%08" PRIx32, state.registers[PC]); + break; + default: + break; + } + } while (unwind_stack(&state)); +} + +#endif /* defined(CFG_CORE_UNWIND) && (TRACE_LEVEL > 0) */ + /* * These functions are referenced but never used */ diff --git a/core/arch/arm/kernel/unwind_arm64.c b/core/arch/arm/kernel/unwind_arm64.c index 67a45b12f76..10b70ef4929 100644 --- a/core/arch/arm/kernel/unwind_arm64.c +++ b/core/arch/arm/kernel/unwind_arm64.c @@ -28,8 +28,11 @@ * SUCH DAMAGE. */ +#include #include #include +#include +#include bool unwind_stack(struct unwind_state *frame) { @@ -47,3 +50,35 @@ bool unwind_stack(struct unwind_state *frame) return true; } + +#if defined(CFG_CORE_UNWIND) && (TRACE_LEVEL > 0) + +void print_stack(int level) +{ + struct unwind_state state; + + memset(&state, 0, sizeof(state)); + state.pc = read_pc(); + state.fp = read_fp(); + + do { + switch (level) { + case TRACE_FLOW: + FMSG_RAW("pc 0x%016" PRIx64, state.pc); + break; + case TRACE_DEBUG: + DMSG_RAW("pc 0x%016" PRIx64, state.pc); + break; + case TRACE_INFO: + IMSG_RAW("pc 0x%016" PRIx64, state.pc); + break; + case TRACE_ERROR: + EMSG_RAW("pc 0x%016" PRIx64, state.pc); + break; + default: + break; + } + } while (unwind_stack(&state)); +} + +#endif /* defined(CFG_CORE_UNWIND) && (TRACE_LEVEL > 0) */ diff --git a/lib/libutils/ext/include/compiler.h b/lib/libutils/ext/include/compiler.h index 6f3b233444b..b58c8edd4dd 100644 --- a/lib/libutils/ext/include/compiler.h +++ b/lib/libutils/ext/include/compiler.h @@ -29,7 +29,7 @@ #define COMPILER_H /* - * Macros that should be used instead of using __attributue__ directly to + * Macros that should be used instead of using __attribute__ directly to * ease portability and make the code easier to read. */ diff --git a/lib/libutils/ext/include/trace.h b/lib/libutils/ext/include/trace.h index 52dbec7f82a..8e0abb5700c 100644 --- a/lib/libutils/ext/include/trace.h +++ b/lib/libutils/ext/include/trace.h @@ -167,4 +167,37 @@ void dhex_dump(const char *function, int line, int level, #endif /* TRACE_LEVEL */ +#if defined(__KERNEL__) && defined(CFG_CORE_UNWIND) +#include +#define _PRINT_STACK +#endif + +#if defined(_PRINT_STACK) && (TRACE_LEVEL >= TRACE_ERROR) +#define EPRINT_STACK() print_stack(TRACE_ERROR) +#else +#define EPRINT_STACK() (void)0 +#endif + +#if defined(_PRINT_STACK) && (TRACE_LEVEL >= TRACE_INFO) +#define IPRINT_STACK() print_stack(TRACE_INFO) +#else +#define IPRINT_STACK() (void)0 +#endif + +#if defined(_PRINT_STACK) && (TRACE_LEVEL >= TRACE_DEBUG) +#define DPRINT_STACK() print_stack(TRACE_DEBUG) +#else +#define DPRINT_STACK() (void)0 +#endif + +#if defined(_PRINT_STACK) && (TRACE_LEVEL >= TRACE_FLOW) +#define FPRINT_STACK() print_stack(TRACE_FLOW) +#else +#define FPRINT_STACK() (void)0 +#endif + +#if defined(__KERNEL__) && defined(CFG_CORE_UNWIND) +#undef _PRINT_STACK +#endif + #endif /* TRACE_H */ diff --git a/lib/libutils/isoc/include/sys/cdefs.h b/lib/libutils/isoc/include/sys/cdefs.h index 79078690c11..354d661bf4d 100644 --- a/lib/libutils/isoc/include/sys/cdefs.h +++ b/lib/libutils/isoc/include/sys/cdefs.h @@ -41,4 +41,6 @@ #endif #endif +#define __always_inline __attribute__((always_inline)) inline + #endif /*SYS_CDEFS_H*/