0001
0002 #include <linux/kernel.h>
0003
0004 typedef unsigned int instr;
0005
0006 #define MAJOR_OP 0xfc000000
0007 #define LDA_OP 0x20000000
0008 #define STQ_OP 0xb4000000
0009 #define BR_OP 0xc0000000
0010
0011 #define STK_ALLOC_1 0x23de8000
0012 #define STK_ALLOC_1M 0xffff8000
0013 #define STK_ALLOC_2 0x43c0153e
0014 #define STK_ALLOC_2M 0xffe01fff
0015
0016 #define MEM_REG 0x03e00000
0017 #define MEM_BASE 0x001f0000
0018 #define MEM_OFF 0x0000ffff
0019 #define MEM_OFF_SIGN 0x00008000
0020 #define BASE_SP 0x001e0000
0021
0022 #define STK_ALLOC_MATCH(INSTR) \
0023 (((INSTR) & STK_ALLOC_1M) == STK_ALLOC_1 \
0024 || ((INSTR) & STK_ALLOC_2M) == STK_ALLOC_2)
0025 #define STK_PUSH_MATCH(INSTR) \
0026 (((INSTR) & (MAJOR_OP | MEM_BASE | MEM_OFF_SIGN)) == (STQ_OP | BASE_SP))
0027 #define MEM_OP_OFFSET(INSTR) \
0028 (((long)((INSTR) & MEM_OFF) << 48) >> 48)
0029 #define MEM_OP_REG(INSTR) \
0030 (((INSTR) & MEM_REG) >> 22)
0031
0032
0033 #define BB_END(INSTR) \
0034 (((instr)(INSTR) >= BR_OP) | ((instr)(INSTR) < LDA_OP) | \
0035 ((((instr)(INSTR) ^ 0x60000000) < 0x20000000) & \
0036 (((instr)(INSTR) & 0x0c000000) != 0)))
0037
0038 #define IS_KERNEL_TEXT(PC) ((unsigned long)(PC) > START_ADDR)
0039
0040 static char reg_name[][4] = {
0041 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ", "t7 ",
0042 "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "s6 ", "a0 ", "a1 ",
0043 "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ", "t10", "t11", "ra ",
0044 "pv ", "at ", "gp ", "sp ", "0"
0045 };
0046
0047
0048 static instr *
0049 display_stored_regs(instr * pro_pc, unsigned char * sp)
0050 {
0051 instr * ret_pc = 0;
0052 int reg;
0053 unsigned long value;
0054
0055 printk("Prologue [<%p>], Frame %p:\n", pro_pc, sp);
0056 while (!BB_END(*pro_pc))
0057 if (STK_PUSH_MATCH(*pro_pc)) {
0058 reg = (*pro_pc & MEM_REG) >> 21;
0059 value = *(unsigned long *)(sp + (*pro_pc & MEM_OFF));
0060 if (reg == 26)
0061 ret_pc = (instr *)value;
0062 printk("\t\t%s / 0x%016lx\n", reg_name[reg], value);
0063 }
0064 return ret_pc;
0065 }
0066
0067 static instr *
0068 seek_prologue(instr * pc)
0069 {
0070 while (!STK_ALLOC_MATCH(*pc))
0071 --pc;
0072 while (!BB_END(*(pc - 1)))
0073 --pc;
0074 return pc;
0075 }
0076
0077 static long
0078 stack_increment(instr * prologue_pc)
0079 {
0080 while (!STK_ALLOC_MATCH(*prologue_pc))
0081 ++prologue_pc;
0082
0083
0084 if ((*prologue_pc & STK_ALLOC_1M) == STK_ALLOC_1M)
0085 return -(((long)(*prologue_pc) << 48) >> 48);
0086 else
0087 return (*prologue_pc >> 13) & 0xff;
0088 }
0089
0090 void
0091 stacktrace(void)
0092 {
0093 instr * ret_pc;
0094 instr * prologue = (instr *)stacktrace;
0095 register unsigned char * sp __asm__ ("$30");
0096
0097 printk("\tstack trace:\n");
0098 do {
0099 ret_pc = display_stored_regs(prologue, sp);
0100 sp += stack_increment(prologue);
0101 prologue = seek_prologue(ret_pc);
0102 } while (IS_KERNEL_TEXT(ret_pc));
0103 }