Ignore:
Timestamp:
2010-07-16T09:08:39Z (14 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
65914ac
Parents:
257ceb1
Message:

Add experimental support for kernel stack tracing on mips32.

File:
1 edited

Legend:

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

    r257ceb1 r63bdde6  
    3636#include <syscall/copy.h>
    3737#include <typedefs.h>
    38 
    39 bool kernel_frame_pointer_validate(uintptr_t fp)
     38#include <arch/debugger.h>
     39#include <print.h>
     40
     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
     95extern char ktext_start;
     96extern char ktext_end;
     97
     98static bool
     99scan(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
     206bool 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
     213bool kernel_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
     214{
     215        return scan(ctx, prev, NULL);
     216}
     217
     218bool kernel_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
     219{
     220        return scan(ctx, NULL, ra);
     221}
     222
     223bool uspace_stack_trace_context_validate(stack_trace_context_t *ctx)
    40224{
    41225        return false;
    42226}
    43227
    44 bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
     228bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)
    45229{
    46230        return false;
    47231}
    48232
    49 bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra)
     233bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra)
    50234{
    51235        return false;
    52236}
    53237
    54 bool uspace_frame_pointer_validate(uintptr_t fp)
    55 {
    56         return false;
    57 }
    58 
    59 bool uspace_frame_pointer_prev(uintptr_t fp, uintptr_t *prev)
    60 {
    61         return false;
    62 }
    63 
    64 bool uspace_return_address_get(uintptr_t fp, uintptr_t *ra)
    65 {
    66         return false;
    67 }
    68 
    69238/** @}
    70239 */
Note: See TracChangeset for help on using the changeset viewer.