Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
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 /* lda $30,-X($30) */
0012 #define STK_ALLOC_1M    0xffff8000
0013 #define STK_ALLOC_2 0x43c0153e /* subq $30,X,$30 */
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 /* Branches, jumps, PAL calls, and illegal opcodes end a basic block. */
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     /* Count the bytes allocated. */
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 }