Files
skiboot/include/stack.h
Nicholas Piggin dca0d53456 core: interrupt markers for stack traces
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
2020-06-11 12:52:55 +10:00

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 */