16fc729afSOlivier Houchard /* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ 26fc729afSOlivier Houchard 3d8315c79SWarner Losh /*- 46fc729afSOlivier Houchard * Copyright (c) 2000, 2001 Ben Harris 56fc729afSOlivier Houchard * Copyright (c) 1996 Scott K. Stevens 66fc729afSOlivier Houchard * 76fc729afSOlivier Houchard * Mach Operating System 86fc729afSOlivier Houchard * Copyright (c) 1991,1990 Carnegie Mellon University 96fc729afSOlivier Houchard * All Rights Reserved. 106fc729afSOlivier Houchard * 116fc729afSOlivier Houchard * Permission to use, copy, modify and distribute this software and its 126fc729afSOlivier Houchard * documentation is hereby granted, provided that both the copyright 136fc729afSOlivier Houchard * notice and this permission notice appear in all copies of the 146fc729afSOlivier Houchard * software, derivative works or modified versions, and any portions 156fc729afSOlivier Houchard * thereof, and that both notices appear in supporting documentation. 166fc729afSOlivier Houchard * 176fc729afSOlivier Houchard * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 186fc729afSOlivier Houchard * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 196fc729afSOlivier Houchard * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 206fc729afSOlivier Houchard * 216fc729afSOlivier Houchard * Carnegie Mellon requests users of this software to return to 226fc729afSOlivier Houchard * 236fc729afSOlivier Houchard * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 246fc729afSOlivier Houchard * School of Computer Science 256fc729afSOlivier Houchard * Carnegie Mellon University 266fc729afSOlivier Houchard * Pittsburgh PA 15213-3890 276fc729afSOlivier Houchard * 286fc729afSOlivier Houchard * any improvements or extensions that they make and grant Carnegie the 296fc729afSOlivier Houchard * rights to redistribute these changes. 306fc729afSOlivier Houchard */ 316fc729afSOlivier Houchard 326fc729afSOlivier Houchard #include <sys/cdefs.h> 336fc729afSOlivier Houchard __FBSDID("$FreeBSD$"); 346fc729afSOlivier Houchard #include <sys/param.h> 359cdb2bfcSOlivier Houchard #include <sys/systm.h> 366fc729afSOlivier Houchard 376fc729afSOlivier Houchard 386fc729afSOlivier Houchard #include <sys/proc.h> 392f6d0d8fSOlivier Houchard #include <sys/kdb.h> 408d511e2aSJeff Roberson #include <sys/stack.h> 416fc729afSOlivier Houchard #include <machine/armreg.h> 426fc729afSOlivier Houchard #include <machine/asm.h> 436fc729afSOlivier Houchard #include <machine/cpufunc.h> 446fc729afSOlivier Houchard #include <machine/db_machdep.h> 456004362eSDavid Schultz #include <machine/pcb.h> 463c90d1eaSRobert Watson #include <machine/stack.h> 476fc729afSOlivier Houchard #include <machine/vmparam.h> 486fc729afSOlivier Houchard #include <ddb/ddb.h> 496fc729afSOlivier Houchard #include <ddb/db_access.h> 506fc729afSOlivier Houchard #include <ddb/db_sym.h> 516fc729afSOlivier Houchard #include <ddb/db_output.h> 526fc729afSOlivier Houchard 53*29ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 54*29ce0a2aSAndrew Turner /* 55*29ce0a2aSAndrew Turner * Definitions for the instruction interpreter. 56*29ce0a2aSAndrew Turner * 57*29ce0a2aSAndrew Turner * The ARM EABI specifies how to perform the frame unwinding in the 58*29ce0a2aSAndrew Turner * Exception Handling ABI for the ARM Architecture document. To perform 59*29ce0a2aSAndrew Turner * the unwind we need to know the initial frame pointer, stack pointer, 60*29ce0a2aSAndrew Turner * link register and program counter. We then find the entry within the 61*29ce0a2aSAndrew Turner * index table that points to the function the program counter is within. 62*29ce0a2aSAndrew Turner * This gives us either a list of three instructions to process, a 31-bit 63*29ce0a2aSAndrew Turner * relative offset to a table of instructions, or a value telling us 64*29ce0a2aSAndrew Turner * we can't unwind any further. 65*29ce0a2aSAndrew Turner * 66*29ce0a2aSAndrew Turner * When we have the instructions to process we need to decode them 67*29ce0a2aSAndrew Turner * following table 4 in section 9.3. This describes a collection of bit 68*29ce0a2aSAndrew Turner * patterns to encode that steps to take to update the stack pointer and 69*29ce0a2aSAndrew Turner * link register to the correct values at the start of the function. 70*29ce0a2aSAndrew Turner */ 71*29ce0a2aSAndrew Turner 72*29ce0a2aSAndrew Turner /* A special case when we are unable to unwind past this function */ 73*29ce0a2aSAndrew Turner #define EXIDX_CANTUNWIND 1 74*29ce0a2aSAndrew Turner 75*29ce0a2aSAndrew Turner /* The register names */ 76*29ce0a2aSAndrew Turner #define FP 11 77*29ce0a2aSAndrew Turner #define SP 13 78*29ce0a2aSAndrew Turner #define LR 14 79*29ce0a2aSAndrew Turner #define PC 15 80*29ce0a2aSAndrew Turner 81*29ce0a2aSAndrew Turner /* 82*29ce0a2aSAndrew Turner * These are set in the linker script. Their addresses will be 83*29ce0a2aSAndrew Turner * either the start or end of the exception table or index. 84*29ce0a2aSAndrew Turner */ 85*29ce0a2aSAndrew Turner extern int extab_start, extab_end, exidx_start, exidx_end; 86*29ce0a2aSAndrew Turner 87*29ce0a2aSAndrew Turner /* 88*29ce0a2aSAndrew Turner * Entry types. 89*29ce0a2aSAndrew Turner * These are the only entry types that have been seen in the kernel. 90*29ce0a2aSAndrew Turner */ 91*29ce0a2aSAndrew Turner #define ENTRY_MASK 0xff000000 92*29ce0a2aSAndrew Turner #define ENTRY_ARM_SU16 0x80000000 93*29ce0a2aSAndrew Turner #define ENTRY_ARM_LU16 0x81000000 94*29ce0a2aSAndrew Turner 95*29ce0a2aSAndrew Turner /* Instruction masks. */ 96*29ce0a2aSAndrew Turner #define INSN_VSP_MASK 0xc0 97*29ce0a2aSAndrew Turner #define INSN_VSP_SIZE_MASK 0x3f 98*29ce0a2aSAndrew Turner #define INSN_STD_MASK 0xf0 99*29ce0a2aSAndrew Turner #define INSN_STD_DATA_MASK 0x0f 100*29ce0a2aSAndrew Turner #define INSN_POP_TYPE_MASK 0x08 101*29ce0a2aSAndrew Turner #define INSN_POP_COUNT_MASK 0x07 102*29ce0a2aSAndrew Turner #define INSN_VSP_LARGE_INC_MASK 0xff 103*29ce0a2aSAndrew Turner 104*29ce0a2aSAndrew Turner /* Instruction definitions */ 105*29ce0a2aSAndrew Turner #define INSN_VSP_INC 0x00 106*29ce0a2aSAndrew Turner #define INSN_VSP_DEC 0x40 107*29ce0a2aSAndrew Turner #define INSN_POP_MASKED 0x80 108*29ce0a2aSAndrew Turner #define INSN_VSP_REG 0x90 109*29ce0a2aSAndrew Turner #define INSN_POP_COUNT 0xa0 110*29ce0a2aSAndrew Turner #define INSN_FINISH 0xb0 111*29ce0a2aSAndrew Turner #define INSN_VSP_LARGE_INC 0xb2 112*29ce0a2aSAndrew Turner 113*29ce0a2aSAndrew Turner /* An item in the exception index table */ 114*29ce0a2aSAndrew Turner struct unwind_idx { 115*29ce0a2aSAndrew Turner uint32_t offset; 116*29ce0a2aSAndrew Turner uint32_t insn; 117*29ce0a2aSAndrew Turner }; 118*29ce0a2aSAndrew Turner 119*29ce0a2aSAndrew Turner /* The state of the unwind process */ 120*29ce0a2aSAndrew Turner struct unwind_state { 121*29ce0a2aSAndrew Turner uint32_t registers[16]; 122*29ce0a2aSAndrew Turner uint32_t start_pc; 123*29ce0a2aSAndrew Turner uint32_t *insn; 124*29ce0a2aSAndrew Turner u_int entries; 125*29ce0a2aSAndrew Turner u_int byte; 126*29ce0a2aSAndrew Turner uint16_t update_mask; 127*29ce0a2aSAndrew Turner }; 128*29ce0a2aSAndrew Turner 129*29ce0a2aSAndrew Turner /* We need to provide these but never use them */ 130*29ce0a2aSAndrew Turner void __aeabi_unwind_cpp_pr0(void); 131*29ce0a2aSAndrew Turner void __aeabi_unwind_cpp_pr1(void); 132*29ce0a2aSAndrew Turner void __aeabi_unwind_cpp_pr2(void); 133*29ce0a2aSAndrew Turner 134*29ce0a2aSAndrew Turner void 135*29ce0a2aSAndrew Turner __aeabi_unwind_cpp_pr0(void) 136*29ce0a2aSAndrew Turner { 137*29ce0a2aSAndrew Turner panic("__aeabi_unwind_cpp_pr0"); 138*29ce0a2aSAndrew Turner } 139*29ce0a2aSAndrew Turner 140*29ce0a2aSAndrew Turner void 141*29ce0a2aSAndrew Turner __aeabi_unwind_cpp_pr1(void) 142*29ce0a2aSAndrew Turner { 143*29ce0a2aSAndrew Turner panic("__aeabi_unwind_cpp_pr1"); 144*29ce0a2aSAndrew Turner } 145*29ce0a2aSAndrew Turner 146*29ce0a2aSAndrew Turner void 147*29ce0a2aSAndrew Turner __aeabi_unwind_cpp_pr2(void) 148*29ce0a2aSAndrew Turner { 149*29ce0a2aSAndrew Turner panic("__aeabi_unwind_cpp_pr2"); 150*29ce0a2aSAndrew Turner } 151*29ce0a2aSAndrew Turner 152*29ce0a2aSAndrew Turner /* Expand a 31-bit signed value to a 32-bit signed value */ 153*29ce0a2aSAndrew Turner static __inline int32_t 154*29ce0a2aSAndrew Turner db_expand_prel31(uint32_t prel31) 155*29ce0a2aSAndrew Turner { 156*29ce0a2aSAndrew Turner 157*29ce0a2aSAndrew Turner return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; 158*29ce0a2aSAndrew Turner } 159*29ce0a2aSAndrew Turner 160*29ce0a2aSAndrew Turner /* 161*29ce0a2aSAndrew Turner * Perform a binary search of the index table to find the function 162*29ce0a2aSAndrew Turner * with the largest address that doesn't exceed addr. 163*29ce0a2aSAndrew Turner */ 164*29ce0a2aSAndrew Turner static struct unwind_idx * 165*29ce0a2aSAndrew Turner db_find_index(uint32_t addr) 166*29ce0a2aSAndrew Turner { 167*29ce0a2aSAndrew Turner unsigned int min, mid, max; 168*29ce0a2aSAndrew Turner struct unwind_idx *start; 169*29ce0a2aSAndrew Turner struct unwind_idx *item; 170*29ce0a2aSAndrew Turner int32_t prel31_addr; 171*29ce0a2aSAndrew Turner uint32_t func_addr; 172*29ce0a2aSAndrew Turner 173*29ce0a2aSAndrew Turner start = (struct unwind_idx *)&exidx_start; 174*29ce0a2aSAndrew Turner 175*29ce0a2aSAndrew Turner min = 0; 176*29ce0a2aSAndrew Turner max = (&exidx_end - &exidx_start) / 2; 177*29ce0a2aSAndrew Turner 178*29ce0a2aSAndrew Turner while (min != max) { 179*29ce0a2aSAndrew Turner mid = min + (max - min + 1) / 2; 180*29ce0a2aSAndrew Turner 181*29ce0a2aSAndrew Turner item = &start[mid]; 182*29ce0a2aSAndrew Turner 183*29ce0a2aSAndrew Turner prel31_addr = db_expand_prel31(item->offset); 184*29ce0a2aSAndrew Turner func_addr = (uint32_t)&item->offset + prel31_addr; 185*29ce0a2aSAndrew Turner 186*29ce0a2aSAndrew Turner if (func_addr <= addr) { 187*29ce0a2aSAndrew Turner min = mid; 188*29ce0a2aSAndrew Turner } else { 189*29ce0a2aSAndrew Turner max = mid - 1; 190*29ce0a2aSAndrew Turner } 191*29ce0a2aSAndrew Turner } 192*29ce0a2aSAndrew Turner 193*29ce0a2aSAndrew Turner return &start[min]; 194*29ce0a2aSAndrew Turner } 195*29ce0a2aSAndrew Turner 196*29ce0a2aSAndrew Turner /* Reads the next byte from the instruction list */ 197*29ce0a2aSAndrew Turner static uint8_t 198*29ce0a2aSAndrew Turner db_unwind_exec_read_byte(struct unwind_state *state) 199*29ce0a2aSAndrew Turner { 200*29ce0a2aSAndrew Turner uint8_t insn; 201*29ce0a2aSAndrew Turner 202*29ce0a2aSAndrew Turner /* Read the unwind instruction */ 203*29ce0a2aSAndrew Turner insn = (*state->insn) >> (state->byte * 8); 204*29ce0a2aSAndrew Turner 205*29ce0a2aSAndrew Turner /* Update the location of the next instruction */ 206*29ce0a2aSAndrew Turner if (state->byte == 0) { 207*29ce0a2aSAndrew Turner state->byte = 3; 208*29ce0a2aSAndrew Turner state->insn++; 209*29ce0a2aSAndrew Turner state->entries--; 210*29ce0a2aSAndrew Turner } else 211*29ce0a2aSAndrew Turner state->byte--; 212*29ce0a2aSAndrew Turner 213*29ce0a2aSAndrew Turner return insn; 214*29ce0a2aSAndrew Turner } 215*29ce0a2aSAndrew Turner 216*29ce0a2aSAndrew Turner /* Executes the next instruction on the list */ 217*29ce0a2aSAndrew Turner static int 218*29ce0a2aSAndrew Turner db_unwind_exec_insn(struct unwind_state *state) 219*29ce0a2aSAndrew Turner { 220*29ce0a2aSAndrew Turner unsigned int insn; 221*29ce0a2aSAndrew Turner uint32_t *vsp = (uint32_t *)state->registers[SP]; 222*29ce0a2aSAndrew Turner int update_vsp = 0; 223*29ce0a2aSAndrew Turner 224*29ce0a2aSAndrew Turner /* This should never happen */ 225*29ce0a2aSAndrew Turner if (state->entries == 0) 226*29ce0a2aSAndrew Turner return 1; 227*29ce0a2aSAndrew Turner 228*29ce0a2aSAndrew Turner /* Read the next instruction */ 229*29ce0a2aSAndrew Turner insn = db_unwind_exec_read_byte(state); 230*29ce0a2aSAndrew Turner 231*29ce0a2aSAndrew Turner if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { 232*29ce0a2aSAndrew Turner state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 233*29ce0a2aSAndrew Turner 234*29ce0a2aSAndrew Turner } else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) { 235*29ce0a2aSAndrew Turner state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 236*29ce0a2aSAndrew Turner 237*29ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) { 238*29ce0a2aSAndrew Turner unsigned int mask, reg; 239*29ce0a2aSAndrew Turner 240*29ce0a2aSAndrew Turner /* Load the mask */ 241*29ce0a2aSAndrew Turner mask = db_unwind_exec_read_byte(state); 242*29ce0a2aSAndrew Turner mask |= (insn & INSN_STD_DATA_MASK) << 8; 243*29ce0a2aSAndrew Turner 244*29ce0a2aSAndrew Turner /* We have a refuse to unwind instruction */ 245*29ce0a2aSAndrew Turner if (mask == 0) 246*29ce0a2aSAndrew Turner return 1; 247*29ce0a2aSAndrew Turner 248*29ce0a2aSAndrew Turner /* Update SP */ 249*29ce0a2aSAndrew Turner update_vsp = 1; 250*29ce0a2aSAndrew Turner 251*29ce0a2aSAndrew Turner /* Load the registers */ 252*29ce0a2aSAndrew Turner for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { 253*29ce0a2aSAndrew Turner if (mask & 1) { 254*29ce0a2aSAndrew Turner state->registers[reg] = *vsp++; 255*29ce0a2aSAndrew Turner state->update_mask |= 1 << reg; 256*29ce0a2aSAndrew Turner 257*29ce0a2aSAndrew Turner /* If we have updated SP kep its value */ 258*29ce0a2aSAndrew Turner if (reg == SP) 259*29ce0a2aSAndrew Turner update_vsp = 0; 260*29ce0a2aSAndrew Turner } 261*29ce0a2aSAndrew Turner } 262*29ce0a2aSAndrew Turner 263*29ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_VSP_REG && 264*29ce0a2aSAndrew Turner ((insn & INSN_STD_DATA_MASK) != 13) && 265*29ce0a2aSAndrew Turner ((insn & INSN_STD_DATA_MASK) != 15)) { 266*29ce0a2aSAndrew Turner /* sp = register */ 267*29ce0a2aSAndrew Turner state->registers[SP] = 268*29ce0a2aSAndrew Turner state->registers[insn & INSN_STD_DATA_MASK]; 269*29ce0a2aSAndrew Turner 270*29ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) { 271*29ce0a2aSAndrew Turner unsigned int count, reg; 272*29ce0a2aSAndrew Turner 273*29ce0a2aSAndrew Turner /* Read how many registers to load */ 274*29ce0a2aSAndrew Turner count = insn & INSN_POP_COUNT_MASK; 275*29ce0a2aSAndrew Turner 276*29ce0a2aSAndrew Turner /* Update sp */ 277*29ce0a2aSAndrew Turner update_vsp = 1; 278*29ce0a2aSAndrew Turner 279*29ce0a2aSAndrew Turner /* Pop the registers */ 280*29ce0a2aSAndrew Turner for (reg = 4; reg <= 4 + count; reg++) { 281*29ce0a2aSAndrew Turner state->registers[reg] = *vsp++; 282*29ce0a2aSAndrew Turner state->update_mask |= 1 << reg; 283*29ce0a2aSAndrew Turner } 284*29ce0a2aSAndrew Turner 285*29ce0a2aSAndrew Turner /* Check if we are in the pop r14 version */ 286*29ce0a2aSAndrew Turner if ((insn & INSN_POP_TYPE_MASK) != 0) { 287*29ce0a2aSAndrew Turner state->registers[14] = *vsp++; 288*29ce0a2aSAndrew Turner } 289*29ce0a2aSAndrew Turner 290*29ce0a2aSAndrew Turner } else if (insn == INSN_FINISH) { 291*29ce0a2aSAndrew Turner /* Stop processing */ 292*29ce0a2aSAndrew Turner state->entries = 0; 293*29ce0a2aSAndrew Turner 294*29ce0a2aSAndrew Turner } else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) { 295*29ce0a2aSAndrew Turner unsigned int uleb128; 296*29ce0a2aSAndrew Turner 297*29ce0a2aSAndrew Turner /* Read the increment value */ 298*29ce0a2aSAndrew Turner uleb128 = db_unwind_exec_read_byte(state); 299*29ce0a2aSAndrew Turner 300*29ce0a2aSAndrew Turner state->registers[SP] += 0x204 + (uleb128 << 2); 301*29ce0a2aSAndrew Turner 302*29ce0a2aSAndrew Turner } else { 303*29ce0a2aSAndrew Turner /* We hit a new instruction that needs to be implemented */ 304*29ce0a2aSAndrew Turner db_printf("Unhandled instruction %.2x\n", insn); 305*29ce0a2aSAndrew Turner return 1; 306*29ce0a2aSAndrew Turner } 307*29ce0a2aSAndrew Turner 308*29ce0a2aSAndrew Turner if (update_vsp) { 309*29ce0a2aSAndrew Turner state->registers[SP] = (uint32_t)vsp; 310*29ce0a2aSAndrew Turner } 311*29ce0a2aSAndrew Turner 312*29ce0a2aSAndrew Turner #if 0 313*29ce0a2aSAndrew Turner db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n", 314*29ce0a2aSAndrew Turner state->registers[FP], state->registers[SP], state->registers[LR], 315*29ce0a2aSAndrew Turner state->registers[PC]); 316*29ce0a2aSAndrew Turner #endif 317*29ce0a2aSAndrew Turner 318*29ce0a2aSAndrew Turner return 0; 319*29ce0a2aSAndrew Turner } 320*29ce0a2aSAndrew Turner 321*29ce0a2aSAndrew Turner /* Performs the unwind of a function */ 322*29ce0a2aSAndrew Turner static int 323*29ce0a2aSAndrew Turner db_unwind_tab(struct unwind_state *state) 324*29ce0a2aSAndrew Turner { 325*29ce0a2aSAndrew Turner uint32_t entry; 326*29ce0a2aSAndrew Turner 327*29ce0a2aSAndrew Turner /* Set PC to a known value */ 328*29ce0a2aSAndrew Turner state->registers[PC] = 0; 329*29ce0a2aSAndrew Turner 330*29ce0a2aSAndrew Turner /* Read the personality */ 331*29ce0a2aSAndrew Turner entry = *state->insn & ENTRY_MASK; 332*29ce0a2aSAndrew Turner 333*29ce0a2aSAndrew Turner if (entry == ENTRY_ARM_SU16) { 334*29ce0a2aSAndrew Turner state->byte = 2; 335*29ce0a2aSAndrew Turner state->entries = 1; 336*29ce0a2aSAndrew Turner } else if (entry == ENTRY_ARM_LU16) { 337*29ce0a2aSAndrew Turner state->byte = 1; 338*29ce0a2aSAndrew Turner state->entries = ((*state->insn >> 16) & 0xFF) + 1; 339*29ce0a2aSAndrew Turner } else { 340*29ce0a2aSAndrew Turner db_printf("Unknown entry: %x\n", entry); 341*29ce0a2aSAndrew Turner return 1; 342*29ce0a2aSAndrew Turner } 343*29ce0a2aSAndrew Turner 344*29ce0a2aSAndrew Turner while (state->entries > 0) { 345*29ce0a2aSAndrew Turner if (db_unwind_exec_insn(state) != 0) 346*29ce0a2aSAndrew Turner return 1; 347*29ce0a2aSAndrew Turner } 348*29ce0a2aSAndrew Turner 349*29ce0a2aSAndrew Turner /* 350*29ce0a2aSAndrew Turner * The program counter was not updated, load it from the link register. 351*29ce0a2aSAndrew Turner */ 352*29ce0a2aSAndrew Turner if (state->registers[PC] == 0) 353*29ce0a2aSAndrew Turner state->registers[PC] = state->registers[LR]; 354*29ce0a2aSAndrew Turner 355*29ce0a2aSAndrew Turner return 0; 356*29ce0a2aSAndrew Turner } 357*29ce0a2aSAndrew Turner 358*29ce0a2aSAndrew Turner static void 359*29ce0a2aSAndrew Turner db_stack_trace_cmd(struct unwind_state *state) 360*29ce0a2aSAndrew Turner { 361*29ce0a2aSAndrew Turner struct unwind_idx *index; 362*29ce0a2aSAndrew Turner const char *name; 363*29ce0a2aSAndrew Turner db_expr_t value; 364*29ce0a2aSAndrew Turner db_expr_t offset; 365*29ce0a2aSAndrew Turner c_db_sym_t sym; 366*29ce0a2aSAndrew Turner u_int reg, i; 367*29ce0a2aSAndrew Turner char *sep; 368*29ce0a2aSAndrew Turner 369*29ce0a2aSAndrew Turner while (1) { 370*29ce0a2aSAndrew Turner /* Reset the mask of updated registers */ 371*29ce0a2aSAndrew Turner state->update_mask = 0; 372*29ce0a2aSAndrew Turner 373*29ce0a2aSAndrew Turner /* The pc value is correct and will be overwritten, save it */ 374*29ce0a2aSAndrew Turner state->start_pc = state->registers[PC]; 375*29ce0a2aSAndrew Turner 376*29ce0a2aSAndrew Turner /* Find the item to run */ 377*29ce0a2aSAndrew Turner index = db_find_index(state->start_pc); 378*29ce0a2aSAndrew Turner 379*29ce0a2aSAndrew Turner if (index->insn == EXIDX_CANTUNWIND) { 380*29ce0a2aSAndrew Turner printf("Unable to unwind\n"); 381*29ce0a2aSAndrew Turner break; 382*29ce0a2aSAndrew Turner } else if (index->insn & (1 << 31)) { 383*29ce0a2aSAndrew Turner /* The data is within the instruction */ 384*29ce0a2aSAndrew Turner state->insn = &index->insn; 385*29ce0a2aSAndrew Turner } else { 386*29ce0a2aSAndrew Turner /* We have a prel31 offset to the unwind table */ 387*29ce0a2aSAndrew Turner uint32_t prel31_tbl = db_expand_prel31(index->insn); 388*29ce0a2aSAndrew Turner 389*29ce0a2aSAndrew Turner state->insn = (uint32_t *)((uintptr_t)&index->insn + 390*29ce0a2aSAndrew Turner prel31_tbl); 391*29ce0a2aSAndrew Turner } 392*29ce0a2aSAndrew Turner 393*29ce0a2aSAndrew Turner /* Run the unwind function */ 394*29ce0a2aSAndrew Turner if (db_unwind_tab(state) != 0) 395*29ce0a2aSAndrew Turner break; 396*29ce0a2aSAndrew Turner 397*29ce0a2aSAndrew Turner /* This is not a kernel address, stop processing */ 398*29ce0a2aSAndrew Turner if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) 399*29ce0a2aSAndrew Turner break; 400*29ce0a2aSAndrew Turner 401*29ce0a2aSAndrew Turner /* Print the frame details */ 402*29ce0a2aSAndrew Turner sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); 403*29ce0a2aSAndrew Turner if (sym == C_DB_SYM_NULL) { 404*29ce0a2aSAndrew Turner value = 0; 405*29ce0a2aSAndrew Turner name = "(null)"; 406*29ce0a2aSAndrew Turner } else 407*29ce0a2aSAndrew Turner db_symbol_values(sym, &name, &value); 408*29ce0a2aSAndrew Turner db_printf("%s() at ", name); 409*29ce0a2aSAndrew Turner db_printsym(state->start_pc, DB_STGY_PROC); 410*29ce0a2aSAndrew Turner db_printf("\n"); 411*29ce0a2aSAndrew Turner db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, 412*29ce0a2aSAndrew Turner state->registers[LR]); 413*29ce0a2aSAndrew Turner db_printsym(state->registers[LR], DB_STGY_PROC); 414*29ce0a2aSAndrew Turner db_printf(")\n"); 415*29ce0a2aSAndrew Turner db_printf("\t sp = 0x%08x fp = 0x%08x", 416*29ce0a2aSAndrew Turner state->registers[SP], state->registers[FP]); 417*29ce0a2aSAndrew Turner 418*29ce0a2aSAndrew Turner /* Don't print the registers we have already printed */ 419*29ce0a2aSAndrew Turner state->update_mask &= ~((1 << SP) | (1 << FP) | (1 << LR) | 420*29ce0a2aSAndrew Turner (1 << PC)); 421*29ce0a2aSAndrew Turner sep = "\n\t"; 422*29ce0a2aSAndrew Turner for (i = 0, reg = 0; state->update_mask != 0; 423*29ce0a2aSAndrew Turner state->update_mask >>= 1, reg++) { 424*29ce0a2aSAndrew Turner if ((state->update_mask & 1) != 0) { 425*29ce0a2aSAndrew Turner db_printf("%s%sr%d = 0x%08x", sep, 426*29ce0a2aSAndrew Turner (reg < 10) ? " " : "", reg, 427*29ce0a2aSAndrew Turner state->registers[reg]); 428*29ce0a2aSAndrew Turner i++; 429*29ce0a2aSAndrew Turner if (i == 2) { 430*29ce0a2aSAndrew Turner sep = "\n\t"; 431*29ce0a2aSAndrew Turner i = 0; 432*29ce0a2aSAndrew Turner } else 433*29ce0a2aSAndrew Turner sep = " "; 434*29ce0a2aSAndrew Turner 435*29ce0a2aSAndrew Turner } 436*29ce0a2aSAndrew Turner } 437*29ce0a2aSAndrew Turner db_printf("\n"); 438*29ce0a2aSAndrew Turner } 439*29ce0a2aSAndrew Turner } 440*29ce0a2aSAndrew Turner #endif 441*29ce0a2aSAndrew Turner 4426fc729afSOlivier Houchard /* 4436fc729afSOlivier Houchard * APCS stack frames are awkward beasts, so I don't think even trying to use 4446fc729afSOlivier Houchard * a structure to represent them is a good idea. 4456fc729afSOlivier Houchard * 4466fc729afSOlivier Houchard * Here's the diagram from the APCS. Increasing address is _up_ the page. 4476fc729afSOlivier Houchard * 4486fc729afSOlivier Houchard * save code pointer [fp] <- fp points to here 4496fc729afSOlivier Houchard * return link value [fp, #-4] 4506fc729afSOlivier Houchard * return sp value [fp, #-8] 4516fc729afSOlivier Houchard * return fp value [fp, #-12] 4526fc729afSOlivier Houchard * [saved v7 value] 4536fc729afSOlivier Houchard * [saved v6 value] 4546fc729afSOlivier Houchard * [saved v5 value] 4556fc729afSOlivier Houchard * [saved v4 value] 4566fc729afSOlivier Houchard * [saved v3 value] 4576fc729afSOlivier Houchard * [saved v2 value] 4586fc729afSOlivier Houchard * [saved v1 value] 4596fc729afSOlivier Houchard * [saved a4 value] 4606fc729afSOlivier Houchard * [saved a3 value] 4616fc729afSOlivier Houchard * [saved a2 value] 4626fc729afSOlivier Houchard * [saved a1 value] 4636fc729afSOlivier Houchard * 4646fc729afSOlivier Houchard * The save code pointer points twelve bytes beyond the start of the 4656fc729afSOlivier Houchard * code sequence (usually a single STM) that created the stack frame. 4666fc729afSOlivier Houchard * We have to disassemble it if we want to know which of the optional 4676fc729afSOlivier Houchard * fields are actually present. 4686fc729afSOlivier Houchard */ 4696fc729afSOlivier Houchard 470*29ce0a2aSAndrew Turner #ifndef __ARM_EABI__ /* The frame format is differend in AAPCS */ 471fd32d93bSMarcel Moolenaar static void 4720cdf4611SGrzegorz Bernacki db_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only) 4736fc729afSOlivier Houchard { 4746fc729afSOlivier Houchard u_int32_t *frame, *lastframe; 4756fc729afSOlivier Houchard c_db_sym_t sym; 4766fc729afSOlivier Houchard const char *name; 4776fc729afSOlivier Houchard db_expr_t value; 4786fc729afSOlivier Houchard db_expr_t offset; 47919e9205aSJohn Baldwin int scp_offset; 4806fc729afSOlivier Houchard 481b1ff74ebSOlivier Houchard frame = (u_int32_t *)addr; 4826fc729afSOlivier Houchard lastframe = NULL; 4836fc729afSOlivier Houchard scp_offset = -(get_pc_str_offset() >> 2); 4846fc729afSOlivier Houchard 48519e9205aSJohn Baldwin while (count-- && frame != NULL && !db_pager_quit) { 4866fc729afSOlivier Houchard db_addr_t scp; 4876fc729afSOlivier Houchard u_int32_t savecode; 4886fc729afSOlivier Houchard int r; 4896fc729afSOlivier Houchard u_int32_t *rp; 4906fc729afSOlivier Houchard const char *sep; 4916fc729afSOlivier Houchard 4926fc729afSOlivier Houchard /* 4936fc729afSOlivier Houchard * In theory, the SCP isn't guaranteed to be in the function 4946fc729afSOlivier Houchard * that generated the stack frame. We hope for the best. 4956fc729afSOlivier Houchard */ 4966fc729afSOlivier Houchard scp = frame[FR_SCP]; 4976fc729afSOlivier Houchard 498282c3a65SOlivier Houchard sym = db_search_symbol(scp, DB_STGY_ANY, &offset); 4996fc729afSOlivier Houchard if (sym == C_DB_SYM_NULL) { 5006fc729afSOlivier Houchard value = 0; 5016fc729afSOlivier Houchard name = "(null)"; 5026fc729afSOlivier Houchard } else 5036fc729afSOlivier Houchard db_symbol_values(sym, &name, &value); 5046fc729afSOlivier Houchard db_printf("%s() at ", name); 505282c3a65SOlivier Houchard db_printsym(scp, DB_STGY_PROC); 5066fc729afSOlivier Houchard db_printf("\n"); 5076fc729afSOlivier Houchard #ifdef __PROG26 5086fc729afSOlivier Houchard db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC); 5096fc729afSOlivier Houchard db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC); 5106fc729afSOlivier Houchard db_printf(")\n"); 5116fc729afSOlivier Houchard #else 5126fc729afSOlivier Houchard db_printf("scp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]); 5136fc729afSOlivier Houchard db_printsym(frame[FR_RLV], DB_STGY_PROC); 5146fc729afSOlivier Houchard db_printf(")\n"); 5156fc729afSOlivier Houchard #endif 5166fc729afSOlivier Houchard db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]); 5176fc729afSOlivier Houchard 5186fc729afSOlivier Houchard savecode = ((u_int32_t *)scp)[scp_offset]; 5196fc729afSOlivier Houchard if ((savecode & 0x0e100000) == 0x08000000) { 5206fc729afSOlivier Houchard /* Looks like an STM */ 5216fc729afSOlivier Houchard rp = frame - 4; 5226fc729afSOlivier Houchard sep = "\n\t"; 5236fc729afSOlivier Houchard for (r = 10; r >= 0; r--) { 5246fc729afSOlivier Houchard if (savecode & (1 << r)) { 5256fc729afSOlivier Houchard db_printf("%sr%d=0x%08x", 5266fc729afSOlivier Houchard sep, r, *rp--); 5276fc729afSOlivier Houchard sep = (frame - rp) % 4 == 2 ? 5286fc729afSOlivier Houchard "\n\t" : " "; 5296fc729afSOlivier Houchard } 5306fc729afSOlivier Houchard } 5316fc729afSOlivier Houchard } 5326fc729afSOlivier Houchard 5336fc729afSOlivier Houchard db_printf("\n"); 5346fc729afSOlivier Houchard 5356fc729afSOlivier Houchard /* 5366fc729afSOlivier Houchard * Switch to next frame up 5376fc729afSOlivier Houchard */ 5386fc729afSOlivier Houchard if (frame[FR_RFP] == 0) 5396fc729afSOlivier Houchard break; /* Top of stack */ 5406fc729afSOlivier Houchard 5416fc729afSOlivier Houchard lastframe = frame; 5426fc729afSOlivier Houchard frame = (u_int32_t *)(frame[FR_RFP]); 5436fc729afSOlivier Houchard 5446fc729afSOlivier Houchard if (INKERNEL((int)frame)) { 5456fc729afSOlivier Houchard /* staying in kernel */ 5466fc729afSOlivier Houchard if (frame <= lastframe) { 5476fc729afSOlivier Houchard db_printf("Bad frame pointer: %p\n", frame); 5486fc729afSOlivier Houchard break; 5496fc729afSOlivier Houchard } 5506fc729afSOlivier Houchard } else if (INKERNEL((int)lastframe)) { 5516fc729afSOlivier Houchard /* switch from user to kernel */ 5526fc729afSOlivier Houchard if (kernel_only) 5536fc729afSOlivier Houchard break; /* kernel stack only */ 5546fc729afSOlivier Houchard } else { 5556fc729afSOlivier Houchard /* in user */ 5566fc729afSOlivier Houchard if (frame <= lastframe) { 5576fc729afSOlivier Houchard db_printf("Bad user frame pointer: %p\n", 5586fc729afSOlivier Houchard frame); 5596fc729afSOlivier Houchard break; 5606fc729afSOlivier Houchard } 5616fc729afSOlivier Houchard } 5626fc729afSOlivier Houchard } 5636fc729afSOlivier Houchard } 564*29ce0a2aSAndrew Turner #endif 5656fc729afSOlivier Houchard 5666fc729afSOlivier Houchard /* XXX stubs */ 5676fc729afSOlivier Houchard void 5686fc729afSOlivier Houchard db_md_list_watchpoints() 5696fc729afSOlivier Houchard { 5706fc729afSOlivier Houchard } 5716fc729afSOlivier Houchard 5726fc729afSOlivier Houchard int 5736fc729afSOlivier Houchard db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 5746fc729afSOlivier Houchard { 5756fc729afSOlivier Houchard return (0); 5766fc729afSOlivier Houchard } 5776fc729afSOlivier Houchard 5786fc729afSOlivier Houchard int 5796fc729afSOlivier Houchard db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 5806fc729afSOlivier Houchard { 5816fc729afSOlivier Houchard return (0); 5826fc729afSOlivier Houchard } 583fd32d93bSMarcel Moolenaar 5842f6d0d8fSOlivier Houchard int 5852f6d0d8fSOlivier Houchard db_trace_thread(struct thread *thr, int count) 5866fc729afSOlivier Houchard { 587*29ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 588*29ce0a2aSAndrew Turner struct unwind_state state; 589*29ce0a2aSAndrew Turner #endif 5902ffa4420SMarcel Moolenaar struct pcb *ctx; 5916fc729afSOlivier Houchard 5920cdf4611SGrzegorz Bernacki if (thr != curthread) { 5932ffa4420SMarcel Moolenaar ctx = kdb_thr_ctx(thr); 594*29ce0a2aSAndrew Turner 595*29ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 596*29ce0a2aSAndrew Turner state.registers[FP] = ctx->un_32.pcb32_r11; 597*29ce0a2aSAndrew Turner state.registers[SP] = ctx->un_32.pcb32_sp; 598*29ce0a2aSAndrew Turner state.registers[LR] = ctx->un_32.pcb32_lr; 599*29ce0a2aSAndrew Turner state.registers[PC] = ctx->un_32.pcb32_pc; 600*29ce0a2aSAndrew Turner 601*29ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 602*29ce0a2aSAndrew Turner #else 6030cdf4611SGrzegorz Bernacki db_stack_trace_cmd(ctx->un_32.pcb32_r11, -1, TRUE); 604*29ce0a2aSAndrew Turner #endif 6050cdf4611SGrzegorz Bernacki } else 6060cdf4611SGrzegorz Bernacki db_trace_self(); 6072f6d0d8fSOlivier Houchard return (0); 6082f6d0d8fSOlivier Houchard } 6092f6d0d8fSOlivier Houchard 6102f6d0d8fSOlivier Houchard void 6112f6d0d8fSOlivier Houchard db_trace_self(void) 6122f6d0d8fSOlivier Houchard { 613*29ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 614*29ce0a2aSAndrew Turner struct unwind_state state; 615*29ce0a2aSAndrew Turner register uint32_t sp __asm__ ("sp"); 616*29ce0a2aSAndrew Turner 617*29ce0a2aSAndrew Turner state.registers[FP] = (uint32_t)__builtin_frame_address(0); 618*29ce0a2aSAndrew Turner state.registers[SP] = (uint32_t)sp; 619*29ce0a2aSAndrew Turner state.registers[LR] = (uint32_t)__builtin_return_address(0); 620*29ce0a2aSAndrew Turner state.registers[PC] = (uint32_t)db_trace_self; 621*29ce0a2aSAndrew Turner 622*29ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 623*29ce0a2aSAndrew Turner #else 624faa7ba7aSMarcel Moolenaar db_addr_t addr; 625faa7ba7aSMarcel Moolenaar 62688256118SMarcel Moolenaar addr = (db_addr_t)__builtin_frame_address(0); 6270cdf4611SGrzegorz Bernacki db_stack_trace_cmd(addr, -1, FALSE); 628*29ce0a2aSAndrew Turner #endif 6296fc729afSOlivier Houchard } 630