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 5329ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 5429ce0a2aSAndrew Turner /* 5529ce0a2aSAndrew Turner * Definitions for the instruction interpreter. 5629ce0a2aSAndrew Turner * 5729ce0a2aSAndrew Turner * The ARM EABI specifies how to perform the frame unwinding in the 5829ce0a2aSAndrew Turner * Exception Handling ABI for the ARM Architecture document. To perform 5929ce0a2aSAndrew Turner * the unwind we need to know the initial frame pointer, stack pointer, 6029ce0a2aSAndrew Turner * link register and program counter. We then find the entry within the 6129ce0a2aSAndrew Turner * index table that points to the function the program counter is within. 6229ce0a2aSAndrew Turner * This gives us either a list of three instructions to process, a 31-bit 6329ce0a2aSAndrew Turner * relative offset to a table of instructions, or a value telling us 6429ce0a2aSAndrew Turner * we can't unwind any further. 6529ce0a2aSAndrew Turner * 6629ce0a2aSAndrew Turner * When we have the instructions to process we need to decode them 6729ce0a2aSAndrew Turner * following table 4 in section 9.3. This describes a collection of bit 6829ce0a2aSAndrew Turner * patterns to encode that steps to take to update the stack pointer and 6929ce0a2aSAndrew Turner * link register to the correct values at the start of the function. 7029ce0a2aSAndrew Turner */ 7129ce0a2aSAndrew Turner 7229ce0a2aSAndrew Turner /* A special case when we are unable to unwind past this function */ 7329ce0a2aSAndrew Turner #define EXIDX_CANTUNWIND 1 7429ce0a2aSAndrew Turner 7529ce0a2aSAndrew Turner /* The register names */ 7629ce0a2aSAndrew Turner #define FP 11 7729ce0a2aSAndrew Turner #define SP 13 7829ce0a2aSAndrew Turner #define LR 14 7929ce0a2aSAndrew Turner #define PC 15 8029ce0a2aSAndrew Turner 8129ce0a2aSAndrew Turner /* 8229ce0a2aSAndrew Turner * These are set in the linker script. Their addresses will be 8329ce0a2aSAndrew Turner * either the start or end of the exception table or index. 8429ce0a2aSAndrew Turner */ 8529ce0a2aSAndrew Turner extern int extab_start, extab_end, exidx_start, exidx_end; 8629ce0a2aSAndrew Turner 8729ce0a2aSAndrew Turner /* 8829ce0a2aSAndrew Turner * Entry types. 8929ce0a2aSAndrew Turner * These are the only entry types that have been seen in the kernel. 9029ce0a2aSAndrew Turner */ 9129ce0a2aSAndrew Turner #define ENTRY_MASK 0xff000000 9229ce0a2aSAndrew Turner #define ENTRY_ARM_SU16 0x80000000 9329ce0a2aSAndrew Turner #define ENTRY_ARM_LU16 0x81000000 9429ce0a2aSAndrew Turner 9529ce0a2aSAndrew Turner /* Instruction masks. */ 9629ce0a2aSAndrew Turner #define INSN_VSP_MASK 0xc0 9729ce0a2aSAndrew Turner #define INSN_VSP_SIZE_MASK 0x3f 9829ce0a2aSAndrew Turner #define INSN_STD_MASK 0xf0 9929ce0a2aSAndrew Turner #define INSN_STD_DATA_MASK 0x0f 10029ce0a2aSAndrew Turner #define INSN_POP_TYPE_MASK 0x08 10129ce0a2aSAndrew Turner #define INSN_POP_COUNT_MASK 0x07 10229ce0a2aSAndrew Turner #define INSN_VSP_LARGE_INC_MASK 0xff 10329ce0a2aSAndrew Turner 10429ce0a2aSAndrew Turner /* Instruction definitions */ 10529ce0a2aSAndrew Turner #define INSN_VSP_INC 0x00 10629ce0a2aSAndrew Turner #define INSN_VSP_DEC 0x40 10729ce0a2aSAndrew Turner #define INSN_POP_MASKED 0x80 10829ce0a2aSAndrew Turner #define INSN_VSP_REG 0x90 10929ce0a2aSAndrew Turner #define INSN_POP_COUNT 0xa0 11029ce0a2aSAndrew Turner #define INSN_FINISH 0xb0 11119d8e1c7SAndrew Turner #define INSN_POP_REGS 0xb1 11229ce0a2aSAndrew Turner #define INSN_VSP_LARGE_INC 0xb2 11329ce0a2aSAndrew Turner 11429ce0a2aSAndrew Turner /* An item in the exception index table */ 11529ce0a2aSAndrew Turner struct unwind_idx { 11629ce0a2aSAndrew Turner uint32_t offset; 11729ce0a2aSAndrew Turner uint32_t insn; 11829ce0a2aSAndrew Turner }; 11929ce0a2aSAndrew Turner 12029ce0a2aSAndrew Turner /* The state of the unwind process */ 12129ce0a2aSAndrew Turner struct unwind_state { 12229ce0a2aSAndrew Turner uint32_t registers[16]; 12329ce0a2aSAndrew Turner uint32_t start_pc; 12429ce0a2aSAndrew Turner uint32_t *insn; 12529ce0a2aSAndrew Turner u_int entries; 12629ce0a2aSAndrew Turner u_int byte; 12729ce0a2aSAndrew Turner uint16_t update_mask; 12829ce0a2aSAndrew Turner }; 12929ce0a2aSAndrew Turner 13029ce0a2aSAndrew Turner /* Expand a 31-bit signed value to a 32-bit signed value */ 13129ce0a2aSAndrew Turner static __inline int32_t 13229ce0a2aSAndrew Turner db_expand_prel31(uint32_t prel31) 13329ce0a2aSAndrew Turner { 13429ce0a2aSAndrew Turner 13529ce0a2aSAndrew Turner return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; 13629ce0a2aSAndrew Turner } 13729ce0a2aSAndrew Turner 13829ce0a2aSAndrew Turner /* 13929ce0a2aSAndrew Turner * Perform a binary search of the index table to find the function 14029ce0a2aSAndrew Turner * with the largest address that doesn't exceed addr. 14129ce0a2aSAndrew Turner */ 14229ce0a2aSAndrew Turner static struct unwind_idx * 14329ce0a2aSAndrew Turner db_find_index(uint32_t addr) 14429ce0a2aSAndrew Turner { 14529ce0a2aSAndrew Turner unsigned int min, mid, max; 14629ce0a2aSAndrew Turner struct unwind_idx *start; 14729ce0a2aSAndrew Turner struct unwind_idx *item; 14829ce0a2aSAndrew Turner int32_t prel31_addr; 14929ce0a2aSAndrew Turner uint32_t func_addr; 15029ce0a2aSAndrew Turner 15129ce0a2aSAndrew Turner start = (struct unwind_idx *)&exidx_start; 15229ce0a2aSAndrew Turner 15329ce0a2aSAndrew Turner min = 0; 15429ce0a2aSAndrew Turner max = (&exidx_end - &exidx_start) / 2; 15529ce0a2aSAndrew Turner 15629ce0a2aSAndrew Turner while (min != max) { 15729ce0a2aSAndrew Turner mid = min + (max - min + 1) / 2; 15829ce0a2aSAndrew Turner 15929ce0a2aSAndrew Turner item = &start[mid]; 16029ce0a2aSAndrew Turner 16129ce0a2aSAndrew Turner prel31_addr = db_expand_prel31(item->offset); 16229ce0a2aSAndrew Turner func_addr = (uint32_t)&item->offset + prel31_addr; 16329ce0a2aSAndrew Turner 16429ce0a2aSAndrew Turner if (func_addr <= addr) { 16529ce0a2aSAndrew Turner min = mid; 16629ce0a2aSAndrew Turner } else { 16729ce0a2aSAndrew Turner max = mid - 1; 16829ce0a2aSAndrew Turner } 16929ce0a2aSAndrew Turner } 17029ce0a2aSAndrew Turner 17129ce0a2aSAndrew Turner return &start[min]; 17229ce0a2aSAndrew Turner } 17329ce0a2aSAndrew Turner 17429ce0a2aSAndrew Turner /* Reads the next byte from the instruction list */ 17529ce0a2aSAndrew Turner static uint8_t 17629ce0a2aSAndrew Turner db_unwind_exec_read_byte(struct unwind_state *state) 17729ce0a2aSAndrew Turner { 17829ce0a2aSAndrew Turner uint8_t insn; 17929ce0a2aSAndrew Turner 18029ce0a2aSAndrew Turner /* Read the unwind instruction */ 18129ce0a2aSAndrew Turner insn = (*state->insn) >> (state->byte * 8); 18229ce0a2aSAndrew Turner 18329ce0a2aSAndrew Turner /* Update the location of the next instruction */ 18429ce0a2aSAndrew Turner if (state->byte == 0) { 18529ce0a2aSAndrew Turner state->byte = 3; 18629ce0a2aSAndrew Turner state->insn++; 18729ce0a2aSAndrew Turner state->entries--; 18829ce0a2aSAndrew Turner } else 18929ce0a2aSAndrew Turner state->byte--; 19029ce0a2aSAndrew Turner 19129ce0a2aSAndrew Turner return insn; 19229ce0a2aSAndrew Turner } 19329ce0a2aSAndrew Turner 19429ce0a2aSAndrew Turner /* Executes the next instruction on the list */ 19529ce0a2aSAndrew Turner static int 19629ce0a2aSAndrew Turner db_unwind_exec_insn(struct unwind_state *state) 19729ce0a2aSAndrew Turner { 19829ce0a2aSAndrew Turner unsigned int insn; 19929ce0a2aSAndrew Turner uint32_t *vsp = (uint32_t *)state->registers[SP]; 20029ce0a2aSAndrew Turner int update_vsp = 0; 20129ce0a2aSAndrew Turner 20229ce0a2aSAndrew Turner /* This should never happen */ 20329ce0a2aSAndrew Turner if (state->entries == 0) 20429ce0a2aSAndrew Turner return 1; 20529ce0a2aSAndrew Turner 20629ce0a2aSAndrew Turner /* Read the next instruction */ 20729ce0a2aSAndrew Turner insn = db_unwind_exec_read_byte(state); 20829ce0a2aSAndrew Turner 20929ce0a2aSAndrew Turner if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { 21029ce0a2aSAndrew Turner state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 21129ce0a2aSAndrew Turner 21229ce0a2aSAndrew Turner } else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) { 21329ce0a2aSAndrew Turner state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 21429ce0a2aSAndrew Turner 21529ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) { 21629ce0a2aSAndrew Turner unsigned int mask, reg; 21729ce0a2aSAndrew Turner 21829ce0a2aSAndrew Turner /* Load the mask */ 21929ce0a2aSAndrew Turner mask = db_unwind_exec_read_byte(state); 22029ce0a2aSAndrew Turner mask |= (insn & INSN_STD_DATA_MASK) << 8; 22129ce0a2aSAndrew Turner 22229ce0a2aSAndrew Turner /* We have a refuse to unwind instruction */ 22329ce0a2aSAndrew Turner if (mask == 0) 22429ce0a2aSAndrew Turner return 1; 22529ce0a2aSAndrew Turner 22629ce0a2aSAndrew Turner /* Update SP */ 22729ce0a2aSAndrew Turner update_vsp = 1; 22829ce0a2aSAndrew Turner 22929ce0a2aSAndrew Turner /* Load the registers */ 23029ce0a2aSAndrew Turner for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { 23129ce0a2aSAndrew Turner if (mask & 1) { 23229ce0a2aSAndrew Turner state->registers[reg] = *vsp++; 23329ce0a2aSAndrew Turner state->update_mask |= 1 << reg; 23429ce0a2aSAndrew Turner 23529ce0a2aSAndrew Turner /* If we have updated SP kep its value */ 23629ce0a2aSAndrew Turner if (reg == SP) 23729ce0a2aSAndrew Turner update_vsp = 0; 23829ce0a2aSAndrew Turner } 23929ce0a2aSAndrew Turner } 24029ce0a2aSAndrew Turner 24129ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_VSP_REG && 24229ce0a2aSAndrew Turner ((insn & INSN_STD_DATA_MASK) != 13) && 24329ce0a2aSAndrew Turner ((insn & INSN_STD_DATA_MASK) != 15)) { 24429ce0a2aSAndrew Turner /* sp = register */ 24529ce0a2aSAndrew Turner state->registers[SP] = 24629ce0a2aSAndrew Turner state->registers[insn & INSN_STD_DATA_MASK]; 24729ce0a2aSAndrew Turner 24829ce0a2aSAndrew Turner } else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) { 24929ce0a2aSAndrew Turner unsigned int count, reg; 25029ce0a2aSAndrew Turner 25129ce0a2aSAndrew Turner /* Read how many registers to load */ 25229ce0a2aSAndrew Turner count = insn & INSN_POP_COUNT_MASK; 25329ce0a2aSAndrew Turner 25429ce0a2aSAndrew Turner /* Update sp */ 25529ce0a2aSAndrew Turner update_vsp = 1; 25629ce0a2aSAndrew Turner 25729ce0a2aSAndrew Turner /* Pop the registers */ 25829ce0a2aSAndrew Turner for (reg = 4; reg <= 4 + count; reg++) { 25929ce0a2aSAndrew Turner state->registers[reg] = *vsp++; 26029ce0a2aSAndrew Turner state->update_mask |= 1 << reg; 26129ce0a2aSAndrew Turner } 26229ce0a2aSAndrew Turner 26329ce0a2aSAndrew Turner /* Check if we are in the pop r14 version */ 26429ce0a2aSAndrew Turner if ((insn & INSN_POP_TYPE_MASK) != 0) { 26529ce0a2aSAndrew Turner state->registers[14] = *vsp++; 26629ce0a2aSAndrew Turner } 26729ce0a2aSAndrew Turner 26829ce0a2aSAndrew Turner } else if (insn == INSN_FINISH) { 26929ce0a2aSAndrew Turner /* Stop processing */ 27029ce0a2aSAndrew Turner state->entries = 0; 27129ce0a2aSAndrew Turner 272255943f9SWarner Losh } else if (insn == INSN_POP_REGS) { 27319d8e1c7SAndrew Turner unsigned int mask, reg; 27419d8e1c7SAndrew Turner 27519d8e1c7SAndrew Turner mask = db_unwind_exec_read_byte(state); 27619d8e1c7SAndrew Turner if (mask == 0 || (mask & 0xf0) != 0) 27719d8e1c7SAndrew Turner return 1; 27819d8e1c7SAndrew Turner 27919d8e1c7SAndrew Turner /* Update SP */ 28019d8e1c7SAndrew Turner update_vsp = 1; 28119d8e1c7SAndrew Turner 28219d8e1c7SAndrew Turner /* Load the registers */ 28319d8e1c7SAndrew Turner for (reg = 0; mask && reg < 4; mask >>= 1, reg++) { 28419d8e1c7SAndrew Turner if (mask & 1) { 28519d8e1c7SAndrew Turner state->registers[reg] = *vsp++; 28619d8e1c7SAndrew Turner state->update_mask |= 1 << reg; 28719d8e1c7SAndrew Turner } 28819d8e1c7SAndrew Turner } 28919d8e1c7SAndrew Turner 29029ce0a2aSAndrew Turner } else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) { 29129ce0a2aSAndrew Turner unsigned int uleb128; 29229ce0a2aSAndrew Turner 29329ce0a2aSAndrew Turner /* Read the increment value */ 29429ce0a2aSAndrew Turner uleb128 = db_unwind_exec_read_byte(state); 29529ce0a2aSAndrew Turner 29629ce0a2aSAndrew Turner state->registers[SP] += 0x204 + (uleb128 << 2); 29729ce0a2aSAndrew Turner 29829ce0a2aSAndrew Turner } else { 29929ce0a2aSAndrew Turner /* We hit a new instruction that needs to be implemented */ 30029ce0a2aSAndrew Turner db_printf("Unhandled instruction %.2x\n", insn); 30129ce0a2aSAndrew Turner return 1; 30229ce0a2aSAndrew Turner } 30329ce0a2aSAndrew Turner 30429ce0a2aSAndrew Turner if (update_vsp) { 30529ce0a2aSAndrew Turner state->registers[SP] = (uint32_t)vsp; 30629ce0a2aSAndrew Turner } 30729ce0a2aSAndrew Turner 30829ce0a2aSAndrew Turner #if 0 30929ce0a2aSAndrew Turner db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n", 31029ce0a2aSAndrew Turner state->registers[FP], state->registers[SP], state->registers[LR], 31129ce0a2aSAndrew Turner state->registers[PC]); 31229ce0a2aSAndrew Turner #endif 31329ce0a2aSAndrew Turner 31429ce0a2aSAndrew Turner return 0; 31529ce0a2aSAndrew Turner } 31629ce0a2aSAndrew Turner 31729ce0a2aSAndrew Turner /* Performs the unwind of a function */ 31829ce0a2aSAndrew Turner static int 31929ce0a2aSAndrew Turner db_unwind_tab(struct unwind_state *state) 32029ce0a2aSAndrew Turner { 32129ce0a2aSAndrew Turner uint32_t entry; 32229ce0a2aSAndrew Turner 32329ce0a2aSAndrew Turner /* Set PC to a known value */ 32429ce0a2aSAndrew Turner state->registers[PC] = 0; 32529ce0a2aSAndrew Turner 32629ce0a2aSAndrew Turner /* Read the personality */ 32729ce0a2aSAndrew Turner entry = *state->insn & ENTRY_MASK; 32829ce0a2aSAndrew Turner 32929ce0a2aSAndrew Turner if (entry == ENTRY_ARM_SU16) { 33029ce0a2aSAndrew Turner state->byte = 2; 33129ce0a2aSAndrew Turner state->entries = 1; 33229ce0a2aSAndrew Turner } else if (entry == ENTRY_ARM_LU16) { 33329ce0a2aSAndrew Turner state->byte = 1; 33429ce0a2aSAndrew Turner state->entries = ((*state->insn >> 16) & 0xFF) + 1; 33529ce0a2aSAndrew Turner } else { 33629ce0a2aSAndrew Turner db_printf("Unknown entry: %x\n", entry); 33729ce0a2aSAndrew Turner return 1; 33829ce0a2aSAndrew Turner } 33929ce0a2aSAndrew Turner 34029ce0a2aSAndrew Turner while (state->entries > 0) { 34129ce0a2aSAndrew Turner if (db_unwind_exec_insn(state) != 0) 34229ce0a2aSAndrew Turner return 1; 34329ce0a2aSAndrew Turner } 34429ce0a2aSAndrew Turner 34529ce0a2aSAndrew Turner /* 34629ce0a2aSAndrew Turner * The program counter was not updated, load it from the link register. 34729ce0a2aSAndrew Turner */ 348c18b81e5SAndrew Turner if (state->registers[PC] == 0) { 34929ce0a2aSAndrew Turner state->registers[PC] = state->registers[LR]; 35029ce0a2aSAndrew Turner 351c18b81e5SAndrew Turner /* 352c18b81e5SAndrew Turner * If the program counter changed, flag it in the update mask. 353c18b81e5SAndrew Turner */ 354c18b81e5SAndrew Turner if (state->start_pc != state->registers[PC]) 355c18b81e5SAndrew Turner state->update_mask |= 1 << PC; 356c18b81e5SAndrew Turner } 357c18b81e5SAndrew Turner 35829ce0a2aSAndrew Turner return 0; 35929ce0a2aSAndrew Turner } 36029ce0a2aSAndrew Turner 36129ce0a2aSAndrew Turner static void 36229ce0a2aSAndrew Turner db_stack_trace_cmd(struct unwind_state *state) 36329ce0a2aSAndrew Turner { 36429ce0a2aSAndrew Turner struct unwind_idx *index; 36529ce0a2aSAndrew Turner const char *name; 36629ce0a2aSAndrew Turner db_expr_t value; 36729ce0a2aSAndrew Turner db_expr_t offset; 36829ce0a2aSAndrew Turner c_db_sym_t sym; 36929ce0a2aSAndrew Turner u_int reg, i; 37029ce0a2aSAndrew Turner char *sep; 371abf29ad1SIan Lepore uint16_t upd_mask; 372abf29ad1SIan Lepore bool finished; 37329ce0a2aSAndrew Turner 374abf29ad1SIan Lepore finished = false; 375abf29ad1SIan Lepore while (!finished) { 37629ce0a2aSAndrew Turner /* Reset the mask of updated registers */ 37729ce0a2aSAndrew Turner state->update_mask = 0; 37829ce0a2aSAndrew Turner 37929ce0a2aSAndrew Turner /* The pc value is correct and will be overwritten, save it */ 38029ce0a2aSAndrew Turner state->start_pc = state->registers[PC]; 38129ce0a2aSAndrew Turner 38229ce0a2aSAndrew Turner /* Find the item to run */ 38329ce0a2aSAndrew Turner index = db_find_index(state->start_pc); 38429ce0a2aSAndrew Turner 385abf29ad1SIan Lepore if (index->insn != EXIDX_CANTUNWIND) { 3867a22215cSEitan Adler if (index->insn & (1U << 31)) { 38729ce0a2aSAndrew Turner /* The data is within the instruction */ 38829ce0a2aSAndrew Turner state->insn = &index->insn; 38929ce0a2aSAndrew Turner } else { 390abf29ad1SIan Lepore /* A prel31 offset to the unwind table */ 391abf29ad1SIan Lepore state->insn = (uint32_t *) 392abf29ad1SIan Lepore ((uintptr_t)&index->insn + 393abf29ad1SIan Lepore db_expand_prel31(index->insn)); 39429ce0a2aSAndrew Turner } 39529ce0a2aSAndrew Turner /* Run the unwind function */ 396abf29ad1SIan Lepore finished = db_unwind_tab(state); 397abf29ad1SIan Lepore } 39829ce0a2aSAndrew Turner 39929ce0a2aSAndrew Turner /* Print the frame details */ 40029ce0a2aSAndrew Turner sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); 40129ce0a2aSAndrew Turner if (sym == C_DB_SYM_NULL) { 40229ce0a2aSAndrew Turner value = 0; 40329ce0a2aSAndrew Turner name = "(null)"; 40429ce0a2aSAndrew Turner } else 40529ce0a2aSAndrew Turner db_symbol_values(sym, &name, &value); 40629ce0a2aSAndrew Turner db_printf("%s() at ", name); 40729ce0a2aSAndrew Turner db_printsym(state->start_pc, DB_STGY_PROC); 40829ce0a2aSAndrew Turner db_printf("\n"); 40929ce0a2aSAndrew Turner db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, 41029ce0a2aSAndrew Turner state->registers[LR]); 41129ce0a2aSAndrew Turner db_printsym(state->registers[LR], DB_STGY_PROC); 41229ce0a2aSAndrew Turner db_printf(")\n"); 41329ce0a2aSAndrew Turner db_printf("\t sp = 0x%08x fp = 0x%08x", 41429ce0a2aSAndrew Turner state->registers[SP], state->registers[FP]); 41529ce0a2aSAndrew Turner 41629ce0a2aSAndrew Turner /* Don't print the registers we have already printed */ 417abf29ad1SIan Lepore upd_mask = state->update_mask & 418abf29ad1SIan Lepore ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC)); 41929ce0a2aSAndrew Turner sep = "\n\t"; 420abf29ad1SIan Lepore for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) { 421abf29ad1SIan Lepore if ((upd_mask & 1) != 0) { 42229ce0a2aSAndrew Turner db_printf("%s%sr%d = 0x%08x", sep, 42329ce0a2aSAndrew Turner (reg < 10) ? " " : "", reg, 42429ce0a2aSAndrew Turner state->registers[reg]); 42529ce0a2aSAndrew Turner i++; 42629ce0a2aSAndrew Turner if (i == 2) { 42729ce0a2aSAndrew Turner sep = "\n\t"; 42829ce0a2aSAndrew Turner i = 0; 42929ce0a2aSAndrew Turner } else 43029ce0a2aSAndrew Turner sep = " "; 43129ce0a2aSAndrew Turner 43229ce0a2aSAndrew Turner } 43329ce0a2aSAndrew Turner } 43429ce0a2aSAndrew Turner db_printf("\n"); 435abf29ad1SIan Lepore 436d0e8071aSIan Lepore /* 437d0e8071aSIan Lepore * Stop if directed to do so, or if we've unwound back to the 438abf29ad1SIan Lepore * kernel entry point, or if the unwind function didn't change 439abf29ad1SIan Lepore * anything (to avoid getting stuck in this loop forever). 440abf29ad1SIan Lepore * If the latter happens, it's an indication that the unwind 441abf29ad1SIan Lepore * information is incorrect somehow for the function named in 442abf29ad1SIan Lepore * the last frame printed before you see the unwind failure 443abf29ad1SIan Lepore * message (maybe it needs a STOP_UNWINDING). 444abf29ad1SIan Lepore */ 445abf29ad1SIan Lepore if (index->insn == EXIDX_CANTUNWIND) { 446abf29ad1SIan Lepore finished = true; 447abf29ad1SIan Lepore } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { 448abf29ad1SIan Lepore db_printf("Unable to unwind into user mode\n"); 449abf29ad1SIan Lepore finished = true; 450abf29ad1SIan Lepore } else if (state->update_mask == 0) { 451abf29ad1SIan Lepore db_printf("Unwind failure (no registers changed)\n"); 452abf29ad1SIan Lepore finished = true; 453abf29ad1SIan Lepore } 45429ce0a2aSAndrew Turner } 45529ce0a2aSAndrew Turner } 45629ce0a2aSAndrew Turner #endif 45729ce0a2aSAndrew Turner 4586fc729afSOlivier Houchard /* 4596fc729afSOlivier Houchard * APCS stack frames are awkward beasts, so I don't think even trying to use 4606fc729afSOlivier Houchard * a structure to represent them is a good idea. 4616fc729afSOlivier Houchard * 4626fc729afSOlivier Houchard * Here's the diagram from the APCS. Increasing address is _up_ the page. 4636fc729afSOlivier Houchard * 4646fc729afSOlivier Houchard * save code pointer [fp] <- fp points to here 4656fc729afSOlivier Houchard * return link value [fp, #-4] 4666fc729afSOlivier Houchard * return sp value [fp, #-8] 4676fc729afSOlivier Houchard * return fp value [fp, #-12] 4686fc729afSOlivier Houchard * [saved v7 value] 4696fc729afSOlivier Houchard * [saved v6 value] 4706fc729afSOlivier Houchard * [saved v5 value] 4716fc729afSOlivier Houchard * [saved v4 value] 4726fc729afSOlivier Houchard * [saved v3 value] 4736fc729afSOlivier Houchard * [saved v2 value] 4746fc729afSOlivier Houchard * [saved v1 value] 4756fc729afSOlivier Houchard * [saved a4 value] 4766fc729afSOlivier Houchard * [saved a3 value] 4776fc729afSOlivier Houchard * [saved a2 value] 4786fc729afSOlivier Houchard * [saved a1 value] 4796fc729afSOlivier Houchard * 4806fc729afSOlivier Houchard * The save code pointer points twelve bytes beyond the start of the 4816fc729afSOlivier Houchard * code sequence (usually a single STM) that created the stack frame. 4826fc729afSOlivier Houchard * We have to disassemble it if we want to know which of the optional 4836fc729afSOlivier Houchard * fields are actually present. 4846fc729afSOlivier Houchard */ 4856fc729afSOlivier Houchard 48629ce0a2aSAndrew Turner #ifndef __ARM_EABI__ /* The frame format is differend in AAPCS */ 487fd32d93bSMarcel Moolenaar static void 4880cdf4611SGrzegorz Bernacki db_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only) 4896fc729afSOlivier Houchard { 4906fc729afSOlivier Houchard u_int32_t *frame, *lastframe; 4916fc729afSOlivier Houchard c_db_sym_t sym; 4926fc729afSOlivier Houchard const char *name; 4936fc729afSOlivier Houchard db_expr_t value; 4946fc729afSOlivier Houchard db_expr_t offset; 49519e9205aSJohn Baldwin int scp_offset; 4966fc729afSOlivier Houchard 497b1ff74ebSOlivier Houchard frame = (u_int32_t *)addr; 4986fc729afSOlivier Houchard lastframe = NULL; 4996fc729afSOlivier Houchard scp_offset = -(get_pc_str_offset() >> 2); 5006fc729afSOlivier Houchard 50119e9205aSJohn Baldwin while (count-- && frame != NULL && !db_pager_quit) { 5026fc729afSOlivier Houchard db_addr_t scp; 5036fc729afSOlivier Houchard u_int32_t savecode; 5046fc729afSOlivier Houchard int r; 5056fc729afSOlivier Houchard u_int32_t *rp; 5066fc729afSOlivier Houchard const char *sep; 5076fc729afSOlivier Houchard 5086fc729afSOlivier Houchard /* 5096fc729afSOlivier Houchard * In theory, the SCP isn't guaranteed to be in the function 5106fc729afSOlivier Houchard * that generated the stack frame. We hope for the best. 5116fc729afSOlivier Houchard */ 5126fc729afSOlivier Houchard scp = frame[FR_SCP]; 5136fc729afSOlivier Houchard 514282c3a65SOlivier Houchard sym = db_search_symbol(scp, DB_STGY_ANY, &offset); 5156fc729afSOlivier Houchard if (sym == C_DB_SYM_NULL) { 5166fc729afSOlivier Houchard value = 0; 5176fc729afSOlivier Houchard name = "(null)"; 5186fc729afSOlivier Houchard } else 5196fc729afSOlivier Houchard db_symbol_values(sym, &name, &value); 5206fc729afSOlivier Houchard db_printf("%s() at ", name); 521282c3a65SOlivier Houchard db_printsym(scp, DB_STGY_PROC); 5226fc729afSOlivier Houchard db_printf("\n"); 5236fc729afSOlivier Houchard #ifdef __PROG26 5248945bee0SRui Paulo db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC); 5256fc729afSOlivier Houchard db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC); 5266fc729afSOlivier Houchard db_printf(")\n"); 5276fc729afSOlivier Houchard #else 5288945bee0SRui Paulo db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]); 5296fc729afSOlivier Houchard db_printsym(frame[FR_RLV], DB_STGY_PROC); 5306fc729afSOlivier Houchard db_printf(")\n"); 5316fc729afSOlivier Houchard #endif 5326fc729afSOlivier Houchard db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]); 5336fc729afSOlivier Houchard 5346fc729afSOlivier Houchard savecode = ((u_int32_t *)scp)[scp_offset]; 5356fc729afSOlivier Houchard if ((savecode & 0x0e100000) == 0x08000000) { 5366fc729afSOlivier Houchard /* Looks like an STM */ 5376fc729afSOlivier Houchard rp = frame - 4; 5386fc729afSOlivier Houchard sep = "\n\t"; 5396fc729afSOlivier Houchard for (r = 10; r >= 0; r--) { 5406fc729afSOlivier Houchard if (savecode & (1 << r)) { 5416fc729afSOlivier Houchard db_printf("%sr%d=0x%08x", 5426fc729afSOlivier Houchard sep, r, *rp--); 5436fc729afSOlivier Houchard sep = (frame - rp) % 4 == 2 ? 5446fc729afSOlivier Houchard "\n\t" : " "; 5456fc729afSOlivier Houchard } 5466fc729afSOlivier Houchard } 5476fc729afSOlivier Houchard } 5486fc729afSOlivier Houchard 5496fc729afSOlivier Houchard db_printf("\n"); 5506fc729afSOlivier Houchard 5516fc729afSOlivier Houchard /* 5526fc729afSOlivier Houchard * Switch to next frame up 5536fc729afSOlivier Houchard */ 5546fc729afSOlivier Houchard if (frame[FR_RFP] == 0) 5556fc729afSOlivier Houchard break; /* Top of stack */ 5566fc729afSOlivier Houchard 5576fc729afSOlivier Houchard lastframe = frame; 5586fc729afSOlivier Houchard frame = (u_int32_t *)(frame[FR_RFP]); 5596fc729afSOlivier Houchard 5606fc729afSOlivier Houchard if (INKERNEL((int)frame)) { 5616fc729afSOlivier Houchard /* staying in kernel */ 5626fc729afSOlivier Houchard if (frame <= lastframe) { 5636fc729afSOlivier Houchard db_printf("Bad frame pointer: %p\n", frame); 5646fc729afSOlivier Houchard break; 5656fc729afSOlivier Houchard } 5666fc729afSOlivier Houchard } else if (INKERNEL((int)lastframe)) { 5676fc729afSOlivier Houchard /* switch from user to kernel */ 5686fc729afSOlivier Houchard if (kernel_only) 5696fc729afSOlivier Houchard break; /* kernel stack only */ 5706fc729afSOlivier Houchard } else { 5716fc729afSOlivier Houchard /* in user */ 5726fc729afSOlivier Houchard if (frame <= lastframe) { 5736fc729afSOlivier Houchard db_printf("Bad user frame pointer: %p\n", 5746fc729afSOlivier Houchard frame); 5756fc729afSOlivier Houchard break; 5766fc729afSOlivier Houchard } 5776fc729afSOlivier Houchard } 5786fc729afSOlivier Houchard } 5796fc729afSOlivier Houchard } 58029ce0a2aSAndrew Turner #endif 5816fc729afSOlivier Houchard 5826fc729afSOlivier Houchard /* XXX stubs */ 5836fc729afSOlivier Houchard void 5846fc729afSOlivier Houchard db_md_list_watchpoints() 5856fc729afSOlivier Houchard { 5866fc729afSOlivier Houchard } 5876fc729afSOlivier Houchard 5886fc729afSOlivier Houchard int 5896fc729afSOlivier Houchard db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 5906fc729afSOlivier Houchard { 5916fc729afSOlivier Houchard return (0); 5926fc729afSOlivier Houchard } 5936fc729afSOlivier Houchard 5946fc729afSOlivier Houchard int 5956fc729afSOlivier Houchard db_md_set_watchpoint(db_expr_t addr, db_expr_t size) 5966fc729afSOlivier Houchard { 5976fc729afSOlivier Houchard return (0); 5986fc729afSOlivier Houchard } 599fd32d93bSMarcel Moolenaar 6002f6d0d8fSOlivier Houchard int 6012f6d0d8fSOlivier Houchard db_trace_thread(struct thread *thr, int count) 6026fc729afSOlivier Houchard { 60329ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 60429ce0a2aSAndrew Turner struct unwind_state state; 60529ce0a2aSAndrew Turner #endif 6062ffa4420SMarcel Moolenaar struct pcb *ctx; 6076fc729afSOlivier Houchard 6080cdf4611SGrzegorz Bernacki if (thr != curthread) { 6092ffa4420SMarcel Moolenaar ctx = kdb_thr_ctx(thr); 61029ce0a2aSAndrew Turner 61129ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 612*c4c27bc9SIan Lepore state.registers[FP] = ctx->pcb_regs.sf_r11; 613*c4c27bc9SIan Lepore state.registers[SP] = ctx->pcb_regs.sf_sp; 614*c4c27bc9SIan Lepore state.registers[LR] = ctx->pcb_regs.sf_lr; 615*c4c27bc9SIan Lepore state.registers[PC] = ctx->pcb_regs.sf_pc; 61629ce0a2aSAndrew Turner 61729ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 61829ce0a2aSAndrew Turner #else 619*c4c27bc9SIan Lepore db_stack_trace_cmd(ctx->pcb_regs.sf_r11, -1, TRUE); 62029ce0a2aSAndrew Turner #endif 6210cdf4611SGrzegorz Bernacki } else 6220cdf4611SGrzegorz Bernacki db_trace_self(); 6232f6d0d8fSOlivier Houchard return (0); 6242f6d0d8fSOlivier Houchard } 6252f6d0d8fSOlivier Houchard 6262f6d0d8fSOlivier Houchard void 6272f6d0d8fSOlivier Houchard db_trace_self(void) 6282f6d0d8fSOlivier Houchard { 62929ce0a2aSAndrew Turner #ifdef __ARM_EABI__ 63029ce0a2aSAndrew Turner struct unwind_state state; 631d80f56e1SAndrew Turner uint32_t sp; 632d80f56e1SAndrew Turner 633d80f56e1SAndrew Turner /* Read the stack pointer */ 634d80f56e1SAndrew Turner __asm __volatile("mov %0, sp" : "=&r" (sp)); 63529ce0a2aSAndrew Turner 63629ce0a2aSAndrew Turner state.registers[FP] = (uint32_t)__builtin_frame_address(0); 637d80f56e1SAndrew Turner state.registers[SP] = sp; 63829ce0a2aSAndrew Turner state.registers[LR] = (uint32_t)__builtin_return_address(0); 63929ce0a2aSAndrew Turner state.registers[PC] = (uint32_t)db_trace_self; 64029ce0a2aSAndrew Turner 64129ce0a2aSAndrew Turner db_stack_trace_cmd(&state); 64229ce0a2aSAndrew Turner #else 643faa7ba7aSMarcel Moolenaar db_addr_t addr; 644faa7ba7aSMarcel Moolenaar 64588256118SMarcel Moolenaar addr = (db_addr_t)__builtin_frame_address(0); 6460cdf4611SGrzegorz Bernacki db_stack_trace_cmd(addr, -1, FALSE); 64729ce0a2aSAndrew Turner #endif 6486fc729afSOlivier Houchard } 649