Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/arch/mips32/src/debug/stacktrace.c

    r63bdde6 rd99c1d2  
    3636#include <syscall/copy.h>
    3737#include <typedefs.h>
    38 #include <arch/debugger.h>
    39 #include <print.h>
    4038
    41 #define R0      0U
    42 #define SP      29U
    43 #define RA      31U
    44 
    45 #define OP_SHIFT        26
    46 #define RS_SHIFT        21
    47 #define RT_SHIFT        16
    48 #define RD_SHIFT        11
    49 
    50 #define HINT_SHIFT      6
    51 #define BASE_SHIFT      RS_SHIFT
    52 #define IMM_SHIFT       0
    53 #define OFFSET_SHIFT    IMM_SHIFT
    54 
    55 #define RS_MASK         (0x1f << RS_SHIFT)
    56 #define RT_MASK         (0x1f << RT_SHIFT)
    57 #define RD_MASK         (0x1f << RD_SHIFT)
    58 #define HINT_MASK       (0x1f << HINT_SHIFT)
    59 #define BASE_MASK       RS_MASK
    60 #define IMM_MASK        (0xffff << IMM_SHIFT)
    61 #define OFFSET_MASK     IMM_MASK       
    62 
    63 #define RS_GET(inst)            (((inst) & RS_MASK) >> RS_SHIFT)
    64 #define RD_GET(inst)            (((inst) & RD_MASK) >> RD_SHIFT)
    65 #define IMM_GET(inst)           (int16_t)(((inst) & IMM_MASK) >> IMM_SHIFT)
    66 #define BASE_GET(inst)          RS_GET(inst)
    67 #define OFFSET_GET(inst)        IMM_GET(inst)   
    68 
    69 #define ADDU_R_SP_R0_TEMPL \
    70         ((0x0 << OP_SHIFT) | (SP << RS_SHIFT) | (R0 << RT_SHIFT) | 0x21)
    71 #define ADDU_SP_R_R0_TEMPL \
    72         ((0x0 << OP_SHIFT) | (SP << RD_SHIFT) | (R0 << RT_SHIFT) | 0x21)
    73 #define ADDI_SP_SP_IMM_TEMPL \
    74         ((0x8 << OP_SHIFT) | (SP << RS_SHIFT) | (SP << RT_SHIFT))
    75 #define ADDIU_SP_SP_IMM_TEMPL \
    76         ((0x9 << OP_SHIFT) | (SP << RS_SHIFT) | (SP << RT_SHIFT))
    77 #define JR_RA_TEMPL \
    78         ((0x0 << OP_SHIFT) | (RA << RS_SHIFT) | (0x0 << HINT_SHIFT) | 0x8)
    79 #define SW_RA_TEMPL \
    80         ((0x2b << OP_SHIFT) | (RA << RT_SHIFT))
    81 
    82 #define IS_ADDU_R_SP_R0(inst) \
    83         (((inst) & ~RD_MASK) == ADDU_R_SP_R0_TEMPL)
    84 #define IS_ADDU_SP_R_R0(inst) \
    85         (((inst) & ~RS_MASK) == ADDU_SP_R_R0_TEMPL)
    86 #define IS_ADDI_SP_SP_IMM(inst) \
    87         (((inst) & ~IMM_MASK) == ADDI_SP_SP_IMM_TEMPL)
    88 #define IS_ADDIU_SP_SP_IMM(inst) \
    89         (((inst) & ~IMM_MASK) == ADDIU_SP_SP_IMM_TEMPL)
    90 #define IS_JR_RA(inst) \
    91         (((inst) & ~HINT_MASK) == JR_RA_TEMPL)
    92 #define IS_SW_RA(inst) \
    93         (((inst) & ~(BASE_MASK | OFFSET_MASK)) == SW_RA_TEMPL)
    94 
    95 extern char ktext_start;
    96 extern char ktext_end;
    97 
    98 static bool
    99 scan(stack_trace_context_t *ctx, uintptr_t *prev_fp, uintptr_t *prev_ra)
    100 {
    101         uint32_t *inst = (void *) ctx->pc;
    102         bool has_fp = false;
    103         size_t frame_size;
    104         unsigned int fp = SP;
    105 
    106         do {
    107                 inst--;
    108 #if 0
    109                 /*
    110                  * This is one of the situations in which the theory (ABI) does
    111                  * not meet the practice (GCC). GCC simply does not place the
    112                  * JR $ra instruction as dictated by the ABI, rendering the
    113                  * official stack tracing algorithm somewhat unapplicable.
    114                  */
    115 
    116                 if (IS_ADDU_R_SP_R0(*inst)) {
    117                         uint32_t *cur;
    118                         fp = RD_GET(*inst);
    119                         /*
    120                          * We have a candidate for frame pointer.
    121                          */
    122                        
    123                         /* Seek to the end of this function. */
    124                         for (cur = inst + 1; !IS_JR_RA(*cur); cur++)
    125                                 ;
    126                         /* Scan the last basic block */
    127                         for (cur--; !is_jump(*(cur - 1)); cur--) {
    128                                 if (IS_ADDU_SP_R_R0(*cur) &&
    129                                     (fp == RS_GET(*cur))) {
    130                                         has_fp = true;
    131                                 }
    132                         }
    133                         continue;
    134                 }
    135                
    136                 if (IS_JR_RA(*inst)) {
    137                         if (!ctx->istate)
    138                                 return false;
    139                         /*
    140                          * No stack frame has been allocated yet.
    141                          * Use the values stored in istate.
    142                          */
    143                         if (prev_fp)
    144                                 *prev_fp = ctx->istate->sp;
    145                         if (prev_ra)
    146                                 *prev_ra = ctx->istate->ra - 8;
    147                         ctx->istate = NULL;
    148                         return true;
    149                 }
    150 #endif
    151 
    152         } while ((!IS_ADDIU_SP_SP_IMM(*inst) && !IS_ADDI_SP_SP_IMM(*inst)) ||
    153             (IMM_GET(*inst) >= 0));
    154        
    155         /*
    156          * We are at the instruction which allocates the space for the current
    157          * stack frame.
    158          */
    159         frame_size = -IMM_GET(*inst);
    160         if (prev_fp)
    161                 *prev_fp = ctx->fp + frame_size;
    162 
    163         /*
    164          * Scan the first basic block for the occurrence of
    165          * SW $ra, OFFSET($base).
    166          */
    167         for (inst++; !is_jump(*(inst - 1)) && (uintptr_t) inst < ctx->pc;
    168             inst++) {
    169                 if (IS_SW_RA(*inst)) {
    170                         unsigned int base = BASE_GET(*inst);
    171                         int16_t offset = OFFSET_GET(*inst);
    172 
    173                         if (base == SP || (has_fp && base == fp)) {
    174                                 uint32_t *addr = (void *) (ctx->fp + offset);
    175                                
    176                                 if (offset % 4 != 0)
    177                                         return false;
    178                                 /* cannot store below current stack pointer */
    179                                 if (offset < 0)
    180                                         return false;
    181                                 /* too big offsets are suspicious */
    182                                 if (offset > 32 * 4)
    183                                         return false;
    184 
    185                                 if (prev_ra)
    186                                         *prev_ra = *addr;
    187                                 return true;
    188                         }
    189                 }
    190         }
    191 
    192         /*
    193          * The first basic block does not save the return address or saves it
    194          * after ctx->pc, which means that the correct value is in istate.
    195          */
    196         if (prev_ra) {
    197                 if (!ctx->istate)
    198                         return false;
    199                 *prev_ra = ctx->istate->ra - 8;
    200                 ctx->istate = NULL;
    201         }
    202         return true;
    203 }
    204 
    205 
    206 bool kernel_stack_trace_context_validate(stack_trace_context_t *ctx)
    207 {
    208         return !((ctx->fp == 0) || ((ctx->fp % 8) != 0) ||
    209             (ctx->pc % 4 != 0) || (ctx->pc < (uintptr_t) &ktext_start) ||
    210             (ctx->pc >= (uintptr_t) &ktext_end));
    211 }
    212 
    213 bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
    214 {
    215         return scan(ctx, prev, NULL);
    216 }
    217 
    218 bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
    219 {
    220         return scan(ctx, NULL, ra);
    221 }
    222 
    223 bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
     39bool kernel_frame_pointer_validate(uintptr_t fp)
    22440{
    22541        return false;
    22642}
    22743
    228 bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
     44bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
    22945{
    23046        return false;
    23147}
    23248
    233 bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
     49bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
     50{
     51        return false;
     52}
     53
     54bool uspace_frame_pointer_validate(uintptr_t fp)
     55{
     56        return false;
     57}
     58
     59bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
     60{
     61        return false;
     62}
     63
     64bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
    23465{
    23566        return false;
Note: See TracChangeset for help on using the changeset viewer.