^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) typedef unsigned int instr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #define MAJOR_OP 0xfc000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #define LDA_OP 0x20000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define STQ_OP 0xb4000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define BR_OP 0xc0000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define STK_ALLOC_1 0x23de8000 /* lda $30,-X($30) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define STK_ALLOC_1M 0xffff8000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define STK_ALLOC_2 0x43c0153e /* subq $30,X,$30 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define STK_ALLOC_2M 0xffe01fff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define MEM_REG 0x03e00000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define MEM_BASE 0x001f0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define MEM_OFF 0x0000ffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define MEM_OFF_SIGN 0x00008000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define BASE_SP 0x001e0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define STK_ALLOC_MATCH(INSTR) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) (((INSTR) & STK_ALLOC_1M) == STK_ALLOC_1 \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) || ((INSTR) & STK_ALLOC_2M) == STK_ALLOC_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define STK_PUSH_MATCH(INSTR) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) (((INSTR) & (MAJOR_OP | MEM_BASE | MEM_OFF_SIGN)) == (STQ_OP | BASE_SP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MEM_OP_OFFSET(INSTR) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) (((long)((INSTR) & MEM_OFF) << 48) >> 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MEM_OP_REG(INSTR) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) (((INSTR) & MEM_REG) >> 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* Branches, jumps, PAL calls, and illegal opcodes end a basic block. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define BB_END(INSTR) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) (((instr)(INSTR) >= BR_OP) | ((instr)(INSTR) < LDA_OP) | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) ((((instr)(INSTR) ^ 0x60000000) < 0x20000000) & \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) (((instr)(INSTR) & 0x0c000000) != 0)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define IS_KERNEL_TEXT(PC) ((unsigned long)(PC) > START_ADDR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static char reg_name[][4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", "t7 ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "a0 ", "a1 ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", "t10", "t11", "ra ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) "pv ", "at ", "gp ", "sp ", "0"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static instr *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) display_stored_regs(instr * pro_pc, unsigned char * sp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) instr * ret_pc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) printk("Prologue [<%p>], Frame %p:\n", pro_pc, sp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) while (!BB_END(*pro_pc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (STK_PUSH_MATCH(*pro_pc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) reg = (*pro_pc & MEM_REG) >> 21;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) value = *(unsigned long *)(sp + (*pro_pc & MEM_OFF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (reg == 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) ret_pc = (instr *)value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) printk("\t\t%s / 0x%016lx\n", reg_name[reg], value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return ret_pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static instr *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) seek_prologue(instr * pc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) while (!STK_ALLOC_MATCH(*pc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) --pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) while (!BB_END(*(pc - 1)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) --pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static long
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) stack_increment(instr * prologue_pc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) while (!STK_ALLOC_MATCH(*prologue_pc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ++prologue_pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Count the bytes allocated. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if ((*prologue_pc & STK_ALLOC_1M) == STK_ALLOC_1M)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return -(((long)(*prologue_pc) << 48) >> 48);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return (*prologue_pc >> 13) & 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) stacktrace(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) instr * ret_pc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) instr * prologue = (instr *)stacktrace;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) register unsigned char * sp __asm__ ("$30");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) printk("\tstack trace:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) ret_pc = display_stored_regs(prologue, sp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) sp += stack_increment(prologue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) prologue = seek_prologue(ret_pc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) } while (IS_KERNEL_TEXT(ret_pc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }