Changes in kernel/arch/mips32/src/debug/stacktrace.c [63bdde6:d99c1d2] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/arch/mips32/src/debug/stacktrace.c
r63bdde6 rd99c1d2 36 36 #include <syscall/copy.h> 37 37 #include <typedefs.h> 38 #include <arch/debugger.h>39 #include <print.h>40 38 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) 39 bool kernel_frame_pointer_validate(uintptr_t fp) 224 40 { 225 41 return false; 226 42 } 227 43 228 bool uspace_frame_pointer_prev(stack_trace_context_t *ctx, uintptr_t *prev)44 bool kernel_frame_pointer_prev(uintptr_t fp, uintptr_t *prev) 229 45 { 230 46 return false; 231 47 } 232 48 233 bool uspace_return_address_get(stack_trace_context_t *ctx, uintptr_t *ra) 49 bool kernel_return_address_get(uintptr_t fp, uintptr_t *ra) 50 { 51 return false; 52 } 53 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) 234 65 { 235 66 return false;
Note:
See TracChangeset
for help on using the changeset viewer.