mirror of
https://github.com/Dasharo/skiboot.git
synced 2026-03-06 14:50:44 -08:00
Use magic marker in the exception stack frame that is used by the unwinder to decode the interrupt type and NIA. The below example trace comes from a modified skiboot that uses virtual memory, but any interrupt type will appear similarly. CPU 0000 Backtrace: S: 0000000031c13580 R: 0000000030028210 .vm_dsi+0x360 S: 0000000031c13630 R: 000000003003b0dc .exception_entry+0x4fc S: 0000000031c13830 R: 0000000030001f4c exception_entry_foo+0x4 --- Interrupt 0x300 at 000000003002431c --- S: 0000000031c13b40 R: 000000003002430c .make_free.isra.0+0x110 S: 0000000031c13bd0 R: 0000000030025198 .mem_alloc+0x4a0 S: 0000000031c13c80 R: 0000000030028bac .__memalign+0x48 S: 0000000031c13d10 R: 0000000030028da4 .__zalloc+0x18 S: 0000000031c13d90 R: 000000003002fb34 .opal_init_msg+0x34 S: 0000000031c13e20 R: 00000000300234b4 .main_cpu_entry+0x61c S: 0000000031c13f00 R: 00000000300031b8 boot_entry+0x1b0 --- OPAL boot --- Signed-off-by: Nicholas Piggin <npiggin@gmail.com> [oliver: the new stackentry fields made our test heaps too small] Signed-off-by: Oliver O'Halloran <oohall@gmail.com> fixup! core: interrupt markers for stack traces
150 lines
3.5 KiB
C
150 lines
3.5 KiB
C
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
/* Copyright 2013-2019 IBM Corp. */
|
|
|
|
#ifndef __STACKFRAME_H
|
|
#define __STACKFRAME_H
|
|
|
|
#include <mem-map.h>
|
|
|
|
#define STACK_ENTRY_OPAL_API 0 /* OPAL call */
|
|
#define STACK_ENTRY_HMI 0x0e60 /* Hypervisor maintenance */
|
|
#define STACK_ENTRY_RESET 0x0100 /* System reset */
|
|
#define STACK_ENTRY_SOFTPATCH 0x1500 /* Soft patch (denorm emulation) */
|
|
|
|
#if HAVE_BIG_ENDIAN
|
|
#define STACK_TOC_OFFSET 40
|
|
#else
|
|
#define STACK_TOC_OFFSET 24
|
|
#endif
|
|
|
|
/* Safety/ABI gap at top of stack */
|
|
#define STACK_TOP_GAP 0x100
|
|
|
|
/* Remaining stack space (gap included) */
|
|
#define NORMAL_STACK_SIZE (STACK_SIZE/2)
|
|
|
|
/* Emergency (re-entry) stack size */
|
|
#define EMERGENCY_STACK_SIZE (STACK_SIZE/2)
|
|
|
|
/* Offset to get to normal CPU stacks */
|
|
#define CPU_STACKS_OFFSET (CPU_STACKS_BASE + \
|
|
NORMAL_STACK_SIZE - STACK_TOP_GAP)
|
|
|
|
/* Offset to get to emergency CPU stacks */
|
|
#define EMERGENCY_CPU_STACKS_OFFSET (CPU_STACKS_BASE + NORMAL_STACK_SIZE + \
|
|
EMERGENCY_STACK_SIZE - STACK_TOP_GAP)
|
|
|
|
/* Gap below the stack. If our stack checker sees the stack below that
|
|
* gap, it will flag a stack overflow
|
|
*/
|
|
#define STACK_SAFETY_GAP 512
|
|
|
|
/* Warning threshold, if stack goes below that on mcount, print a
|
|
* warning.
|
|
*/
|
|
#define STACK_WARNING_GAP 2048
|
|
|
|
#define STACK_CHECK_GUARD_BASE 0xdeadf00dbaad300
|
|
#define STACK_INT_MAGIC 0xb1ab1af00ba1234ULL
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
#include <stdint.h>
|
|
#include <opal-api.h>
|
|
|
|
/* This is the struct used to save GPRs etc.. on OPAL entry
|
|
* and from some exceptions. It is not always entirely populated
|
|
* depending on the entry type
|
|
*/
|
|
struct stack_frame {
|
|
/* Standard 112-byte stack frame header (the minimum size required,
|
|
* using an 8-doubleword param save area). The callee (in C) may use
|
|
* lrsave; we declare these here so we don't get our own save area
|
|
* overwritten */
|
|
uint64_t backchain;
|
|
uint64_t crsave;
|
|
uint64_t lrsave;
|
|
uint64_t compiler_dw;
|
|
uint64_t linker_dw;
|
|
uint64_t tocsave;
|
|
uint64_t paramsave[8];
|
|
|
|
/* Space for stack-local vars used by asm. At present we only use
|
|
* one doubleword. */
|
|
uint64_t locals[1];
|
|
|
|
/* Interrupt entry magic value */
|
|
uint64_t magic;
|
|
|
|
/* Entry type */
|
|
uint64_t type;
|
|
|
|
/* GPR save area
|
|
*
|
|
* We don't necessarily save everything in here
|
|
*/
|
|
uint64_t gpr[32];
|
|
|
|
/* Other SPR saved
|
|
*
|
|
* Only for some exceptions.
|
|
*/
|
|
uint32_t cr;
|
|
uint32_t xer;
|
|
uint32_t dsisr;
|
|
uint64_t ctr;
|
|
uint64_t lr;
|
|
uint64_t pc;
|
|
uint64_t msr;
|
|
uint64_t cfar;
|
|
uint64_t srr0;
|
|
uint64_t srr1;
|
|
uint64_t hsrr0;
|
|
uint64_t hsrr1;
|
|
uint64_t dar;
|
|
} __attribute__((aligned(16)));
|
|
|
|
/* Backtrace entry */
|
|
struct bt_entry {
|
|
unsigned long sp;
|
|
unsigned long pc;
|
|
unsigned long exception_type;
|
|
unsigned long exception_pc;
|
|
};
|
|
|
|
/* Backtrace metadata */
|
|
struct bt_metadata {
|
|
unsigned int ents;
|
|
unsigned long token;
|
|
unsigned long r1_caller;
|
|
unsigned long pir;
|
|
};
|
|
|
|
/* Boot stack top */
|
|
extern void *boot_stack_top;
|
|
|
|
/* Create a backtrace */
|
|
void backtrace_create(struct bt_entry *entries, unsigned int max_ents,
|
|
struct bt_metadata *metadata);
|
|
|
|
/* Convert a backtrace to ASCII */
|
|
extern void backtrace_print(struct bt_entry *entries,
|
|
struct bt_metadata *metadata, char *out_buf,
|
|
unsigned int *len, bool symbols);
|
|
|
|
/* For use by debug code, create and print backtrace, uses a static buffer */
|
|
extern void backtrace(void);
|
|
|
|
/* For use by exception debug code, supply an r1 */
|
|
extern void backtrace_r1(uint64_t r1);
|
|
|
|
#ifdef STACK_CHECK_ENABLED
|
|
extern void check_stacks(void);
|
|
#else
|
|
static inline void check_stacks(void) { }
|
|
#endif
|
|
|
|
#endif /* __ASSEMBLY__ */
|
|
#endif /* __STACKFRAME_H */
|
|
|