db_trace.c revision 276190
1129198Scognet/* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 2000, 2001 Ben Harris 5129198Scognet * Copyright (c) 1996 Scott K. Stevens 6129198Scognet * 7129198Scognet * Mach Operating System 8129198Scognet * Copyright (c) 1991,1990 Carnegie Mellon University 9129198Scognet * All Rights Reserved. 10236991Simp * 11129198Scognet * Permission to use, copy, modify and distribute this software and its 12129198Scognet * documentation is hereby granted, provided that both the copyright 13129198Scognet * notice and this permission notice appear in all copies of the 14129198Scognet * software, derivative works or modified versions, and any portions 15129198Scognet * thereof, and that both notices appear in supporting documentation. 16236991Simp * 17129198Scognet * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 18129198Scognet * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 19129198Scognet * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 20236991Simp * 21129198Scognet * Carnegie Mellon requests users of this software to return to 22236991Simp * 23129198Scognet * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 24129198Scognet * School of Computer Science 25129198Scognet * Carnegie Mellon University 26129198Scognet * Pittsburgh PA 15213-3890 27236991Simp * 28129198Scognet * any improvements or extensions that they make and grant Carnegie the 29129198Scognet * rights to redistribute these changes. 30129198Scognet */ 31129198Scognet 32129198Scognet#include <sys/cdefs.h> 33129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/db_trace.c 276190 2014-12-24 18:54:31Z ian $"); 34129198Scognet#include <sys/param.h> 35132402Scognet#include <sys/systm.h> 36129198Scognet 37129198Scognet 38129198Scognet#include <sys/proc.h> 39132059Scognet#include <sys/kdb.h> 40148666Sjeff#include <sys/stack.h> 41129198Scognet#include <machine/armreg.h> 42129198Scognet#include <machine/asm.h> 43129198Scognet#include <machine/cpufunc.h> 44129198Scognet#include <machine/db_machdep.h> 45138129Sdas#include <machine/pcb.h> 46174195Srwatson#include <machine/stack.h> 47129198Scognet#include <machine/vmparam.h> 48129198Scognet#include <ddb/ddb.h> 49129198Scognet#include <ddb/db_access.h> 50129198Scognet#include <ddb/db_sym.h> 51129198Scognet#include <ddb/db_output.h> 52129198Scognet 53245549Sandrew#ifdef __ARM_EABI__ 54129198Scognet/* 55245549Sandrew * Definitions for the instruction interpreter. 56245549Sandrew * 57245549Sandrew * The ARM EABI specifies how to perform the frame unwinding in the 58245549Sandrew * Exception Handling ABI for the ARM Architecture document. To perform 59245549Sandrew * the unwind we need to know the initial frame pointer, stack pointer, 60245549Sandrew * link register and program counter. We then find the entry within the 61245549Sandrew * index table that points to the function the program counter is within. 62245549Sandrew * This gives us either a list of three instructions to process, a 31-bit 63245549Sandrew * relative offset to a table of instructions, or a value telling us 64245549Sandrew * we can't unwind any further. 65245549Sandrew * 66245549Sandrew * When we have the instructions to process we need to decode them 67245549Sandrew * following table 4 in section 9.3. This describes a collection of bit 68245549Sandrew * patterns to encode that steps to take to update the stack pointer and 69245549Sandrew * link register to the correct values at the start of the function. 70245549Sandrew */ 71245549Sandrew 72245549Sandrew/* A special case when we are unable to unwind past this function */ 73245549Sandrew#define EXIDX_CANTUNWIND 1 74245549Sandrew 75245549Sandrew/* The register names */ 76245549Sandrew#define FP 11 77245549Sandrew#define SP 13 78245549Sandrew#define LR 14 79245549Sandrew#define PC 15 80245549Sandrew 81245549Sandrew/* 82245549Sandrew * These are set in the linker script. Their addresses will be 83245549Sandrew * either the start or end of the exception table or index. 84245549Sandrew */ 85245549Sandrewextern int extab_start, extab_end, exidx_start, exidx_end; 86245549Sandrew 87245549Sandrew/* 88245549Sandrew * Entry types. 89245549Sandrew * These are the only entry types that have been seen in the kernel. 90245549Sandrew */ 91245549Sandrew#define ENTRY_MASK 0xff000000 92245549Sandrew#define ENTRY_ARM_SU16 0x80000000 93245549Sandrew#define ENTRY_ARM_LU16 0x81000000 94245549Sandrew 95245549Sandrew/* Instruction masks. */ 96245549Sandrew#define INSN_VSP_MASK 0xc0 97245549Sandrew#define INSN_VSP_SIZE_MASK 0x3f 98245549Sandrew#define INSN_STD_MASK 0xf0 99245549Sandrew#define INSN_STD_DATA_MASK 0x0f 100245549Sandrew#define INSN_POP_TYPE_MASK 0x08 101245549Sandrew#define INSN_POP_COUNT_MASK 0x07 102245549Sandrew#define INSN_VSP_LARGE_INC_MASK 0xff 103245549Sandrew 104245549Sandrew/* Instruction definitions */ 105245549Sandrew#define INSN_VSP_INC 0x00 106245549Sandrew#define INSN_VSP_DEC 0x40 107245549Sandrew#define INSN_POP_MASKED 0x80 108245549Sandrew#define INSN_VSP_REG 0x90 109245549Sandrew#define INSN_POP_COUNT 0xa0 110245549Sandrew#define INSN_FINISH 0xb0 111252320Sandrew#define INSN_POP_REGS 0xb1 112245549Sandrew#define INSN_VSP_LARGE_INC 0xb2 113245549Sandrew 114245549Sandrew/* An item in the exception index table */ 115245549Sandrewstruct unwind_idx { 116245549Sandrew uint32_t offset; 117245549Sandrew uint32_t insn; 118245549Sandrew}; 119245549Sandrew 120245549Sandrew/* The state of the unwind process */ 121245549Sandrewstruct unwind_state { 122245549Sandrew uint32_t registers[16]; 123245549Sandrew uint32_t start_pc; 124245549Sandrew uint32_t *insn; 125245549Sandrew u_int entries; 126245549Sandrew u_int byte; 127245549Sandrew uint16_t update_mask; 128245549Sandrew}; 129245549Sandrew 130245549Sandrew/* Expand a 31-bit signed value to a 32-bit signed value */ 131245549Sandrewstatic __inline int32_t 132245549Sandrewdb_expand_prel31(uint32_t prel31) 133245549Sandrew{ 134245549Sandrew 135245549Sandrew return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; 136245549Sandrew} 137245549Sandrew 138245549Sandrew/* 139245549Sandrew * Perform a binary search of the index table to find the function 140245549Sandrew * with the largest address that doesn't exceed addr. 141245549Sandrew */ 142245549Sandrewstatic struct unwind_idx * 143245549Sandrewdb_find_index(uint32_t addr) 144245549Sandrew{ 145245549Sandrew unsigned int min, mid, max; 146245549Sandrew struct unwind_idx *start; 147245549Sandrew struct unwind_idx *item; 148245549Sandrew int32_t prel31_addr; 149245549Sandrew uint32_t func_addr; 150245549Sandrew 151245549Sandrew start = (struct unwind_idx *)&exidx_start; 152245549Sandrew 153245549Sandrew min = 0; 154245549Sandrew max = (&exidx_end - &exidx_start) / 2; 155245549Sandrew 156245549Sandrew while (min != max) { 157245549Sandrew mid = min + (max - min + 1) / 2; 158245549Sandrew 159245549Sandrew item = &start[mid]; 160245549Sandrew 161245549Sandrew prel31_addr = db_expand_prel31(item->offset); 162245549Sandrew func_addr = (uint32_t)&item->offset + prel31_addr; 163245549Sandrew 164245549Sandrew if (func_addr <= addr) { 165245549Sandrew min = mid; 166245549Sandrew } else { 167245549Sandrew max = mid - 1; 168245549Sandrew } 169245549Sandrew } 170245549Sandrew 171245549Sandrew return &start[min]; 172245549Sandrew} 173245549Sandrew 174245549Sandrew/* Reads the next byte from the instruction list */ 175245549Sandrewstatic uint8_t 176245549Sandrewdb_unwind_exec_read_byte(struct unwind_state *state) 177245549Sandrew{ 178245549Sandrew uint8_t insn; 179245549Sandrew 180245549Sandrew /* Read the unwind instruction */ 181245549Sandrew insn = (*state->insn) >> (state->byte * 8); 182245549Sandrew 183245549Sandrew /* Update the location of the next instruction */ 184245549Sandrew if (state->byte == 0) { 185245549Sandrew state->byte = 3; 186245549Sandrew state->insn++; 187245549Sandrew state->entries--; 188245549Sandrew } else 189245549Sandrew state->byte--; 190245549Sandrew 191245549Sandrew return insn; 192245549Sandrew} 193245549Sandrew 194245549Sandrew/* Executes the next instruction on the list */ 195245549Sandrewstatic int 196245549Sandrewdb_unwind_exec_insn(struct unwind_state *state) 197245549Sandrew{ 198245549Sandrew unsigned int insn; 199245549Sandrew uint32_t *vsp = (uint32_t *)state->registers[SP]; 200245549Sandrew int update_vsp = 0; 201245549Sandrew 202245549Sandrew /* This should never happen */ 203245549Sandrew if (state->entries == 0) 204245549Sandrew return 1; 205245549Sandrew 206245549Sandrew /* Read the next instruction */ 207245549Sandrew insn = db_unwind_exec_read_byte(state); 208245549Sandrew 209245549Sandrew if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { 210245549Sandrew state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 211245549Sandrew 212245549Sandrew } else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) { 213245549Sandrew state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; 214245549Sandrew 215245549Sandrew } else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) { 216245549Sandrew unsigned int mask, reg; 217245549Sandrew 218245549Sandrew /* Load the mask */ 219245549Sandrew mask = db_unwind_exec_read_byte(state); 220245549Sandrew mask |= (insn & INSN_STD_DATA_MASK) << 8; 221245549Sandrew 222245549Sandrew /* We have a refuse to unwind instruction */ 223245549Sandrew if (mask == 0) 224245549Sandrew return 1; 225245549Sandrew 226245549Sandrew /* Update SP */ 227245549Sandrew update_vsp = 1; 228245549Sandrew 229245549Sandrew /* Load the registers */ 230245549Sandrew for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { 231245549Sandrew if (mask & 1) { 232245549Sandrew state->registers[reg] = *vsp++; 233245549Sandrew state->update_mask |= 1 << reg; 234245549Sandrew 235245549Sandrew /* If we have updated SP kep its value */ 236245549Sandrew if (reg == SP) 237245549Sandrew update_vsp = 0; 238245549Sandrew } 239245549Sandrew } 240245549Sandrew 241245549Sandrew } else if ((insn & INSN_STD_MASK) == INSN_VSP_REG && 242245549Sandrew ((insn & INSN_STD_DATA_MASK) != 13) && 243245549Sandrew ((insn & INSN_STD_DATA_MASK) != 15)) { 244245549Sandrew /* sp = register */ 245245549Sandrew state->registers[SP] = 246245549Sandrew state->registers[insn & INSN_STD_DATA_MASK]; 247245549Sandrew 248245549Sandrew } else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) { 249245549Sandrew unsigned int count, reg; 250245549Sandrew 251245549Sandrew /* Read how many registers to load */ 252245549Sandrew count = insn & INSN_POP_COUNT_MASK; 253245549Sandrew 254245549Sandrew /* Update sp */ 255245549Sandrew update_vsp = 1; 256245549Sandrew 257245549Sandrew /* Pop the registers */ 258245549Sandrew for (reg = 4; reg <= 4 + count; reg++) { 259245549Sandrew state->registers[reg] = *vsp++; 260245549Sandrew state->update_mask |= 1 << reg; 261245549Sandrew } 262245549Sandrew 263245549Sandrew /* Check if we are in the pop r14 version */ 264245549Sandrew if ((insn & INSN_POP_TYPE_MASK) != 0) { 265245549Sandrew state->registers[14] = *vsp++; 266245549Sandrew } 267245549Sandrew 268245549Sandrew } else if (insn == INSN_FINISH) { 269245549Sandrew /* Stop processing */ 270245549Sandrew state->entries = 0; 271245549Sandrew 272261214Simp } else if (insn == INSN_POP_REGS) { 273252320Sandrew unsigned int mask, reg; 274252320Sandrew 275252320Sandrew mask = db_unwind_exec_read_byte(state); 276252320Sandrew if (mask == 0 || (mask & 0xf0) != 0) 277252320Sandrew return 1; 278252320Sandrew 279252320Sandrew /* Update SP */ 280252320Sandrew update_vsp = 1; 281252320Sandrew 282252320Sandrew /* Load the registers */ 283252320Sandrew for (reg = 0; mask && reg < 4; mask >>= 1, reg++) { 284252320Sandrew if (mask & 1) { 285252320Sandrew state->registers[reg] = *vsp++; 286252320Sandrew state->update_mask |= 1 << reg; 287252320Sandrew } 288252320Sandrew } 289252320Sandrew 290245549Sandrew } else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) { 291245549Sandrew unsigned int uleb128; 292245549Sandrew 293245549Sandrew /* Read the increment value */ 294245549Sandrew uleb128 = db_unwind_exec_read_byte(state); 295245549Sandrew 296245549Sandrew state->registers[SP] += 0x204 + (uleb128 << 2); 297245549Sandrew 298245549Sandrew } else { 299245549Sandrew /* We hit a new instruction that needs to be implemented */ 300245549Sandrew db_printf("Unhandled instruction %.2x\n", insn); 301245549Sandrew return 1; 302245549Sandrew } 303245549Sandrew 304245549Sandrew if (update_vsp) { 305245549Sandrew state->registers[SP] = (uint32_t)vsp; 306245549Sandrew } 307245549Sandrew 308245549Sandrew#if 0 309245549Sandrew db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n", 310245549Sandrew state->registers[FP], state->registers[SP], state->registers[LR], 311245549Sandrew state->registers[PC]); 312245549Sandrew#endif 313245549Sandrew 314245549Sandrew return 0; 315245549Sandrew} 316245549Sandrew 317245549Sandrew/* Performs the unwind of a function */ 318245549Sandrewstatic int 319245549Sandrewdb_unwind_tab(struct unwind_state *state) 320245549Sandrew{ 321245549Sandrew uint32_t entry; 322245549Sandrew 323245549Sandrew /* Set PC to a known value */ 324245549Sandrew state->registers[PC] = 0; 325245549Sandrew 326245549Sandrew /* Read the personality */ 327245549Sandrew entry = *state->insn & ENTRY_MASK; 328245549Sandrew 329245549Sandrew if (entry == ENTRY_ARM_SU16) { 330245549Sandrew state->byte = 2; 331245549Sandrew state->entries = 1; 332245549Sandrew } else if (entry == ENTRY_ARM_LU16) { 333245549Sandrew state->byte = 1; 334245549Sandrew state->entries = ((*state->insn >> 16) & 0xFF) + 1; 335245549Sandrew } else { 336245549Sandrew db_printf("Unknown entry: %x\n", entry); 337245549Sandrew return 1; 338245549Sandrew } 339245549Sandrew 340245549Sandrew while (state->entries > 0) { 341245549Sandrew if (db_unwind_exec_insn(state) != 0) 342245549Sandrew return 1; 343245549Sandrew } 344245549Sandrew 345245549Sandrew /* 346245549Sandrew * The program counter was not updated, load it from the link register. 347245549Sandrew */ 348276033Sandrew if (state->registers[PC] == 0) { 349245549Sandrew state->registers[PC] = state->registers[LR]; 350245549Sandrew 351276033Sandrew /* 352276033Sandrew * If the program counter changed, flag it in the update mask. 353276033Sandrew */ 354276033Sandrew if (state->start_pc != state->registers[PC]) 355276033Sandrew state->update_mask |= 1 << PC; 356276033Sandrew } 357276033Sandrew 358245549Sandrew return 0; 359245549Sandrew} 360245549Sandrew 361245549Sandrewstatic void 362245549Sandrewdb_stack_trace_cmd(struct unwind_state *state) 363245549Sandrew{ 364245549Sandrew struct unwind_idx *index; 365245549Sandrew const char *name; 366245549Sandrew db_expr_t value; 367245549Sandrew db_expr_t offset; 368245549Sandrew c_db_sym_t sym; 369245549Sandrew u_int reg, i; 370245549Sandrew char *sep; 371250252Sian uint16_t upd_mask; 372250252Sian bool finished; 373245549Sandrew 374250252Sian finished = false; 375250252Sian while (!finished) { 376245549Sandrew /* Reset the mask of updated registers */ 377245549Sandrew state->update_mask = 0; 378245549Sandrew 379245549Sandrew /* The pc value is correct and will be overwritten, save it */ 380245549Sandrew state->start_pc = state->registers[PC]; 381245549Sandrew 382245549Sandrew /* Find the item to run */ 383245549Sandrew index = db_find_index(state->start_pc); 384245549Sandrew 385250252Sian if (index->insn != EXIDX_CANTUNWIND) { 386258780Seadler if (index->insn & (1U << 31)) { 387250252Sian /* The data is within the instruction */ 388250252Sian state->insn = &index->insn; 389250252Sian } else { 390250252Sian /* A prel31 offset to the unwind table */ 391250252Sian state->insn = (uint32_t *) 392273157Srpaulo ((uintptr_t)&index->insn + 393250252Sian db_expand_prel31(index->insn)); 394250252Sian } 395250252Sian /* Run the unwind function */ 396250252Sian finished = db_unwind_tab(state); 397245549Sandrew } 398245549Sandrew 399245549Sandrew /* Print the frame details */ 400245549Sandrew sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); 401245549Sandrew if (sym == C_DB_SYM_NULL) { 402245549Sandrew value = 0; 403245549Sandrew name = "(null)"; 404245549Sandrew } else 405245549Sandrew db_symbol_values(sym, &name, &value); 406245549Sandrew db_printf("%s() at ", name); 407245549Sandrew db_printsym(state->start_pc, DB_STGY_PROC); 408245549Sandrew db_printf("\n"); 409245549Sandrew db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, 410245549Sandrew state->registers[LR]); 411245549Sandrew db_printsym(state->registers[LR], DB_STGY_PROC); 412245549Sandrew db_printf(")\n"); 413245549Sandrew db_printf("\t sp = 0x%08x fp = 0x%08x", 414245549Sandrew state->registers[SP], state->registers[FP]); 415245549Sandrew 416245549Sandrew /* Don't print the registers we have already printed */ 417273157Srpaulo upd_mask = state->update_mask & 418250252Sian ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC)); 419245549Sandrew sep = "\n\t"; 420250252Sian for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) { 421250252Sian if ((upd_mask & 1) != 0) { 422245549Sandrew db_printf("%s%sr%d = 0x%08x", sep, 423245549Sandrew (reg < 10) ? " " : "", reg, 424245549Sandrew state->registers[reg]); 425245549Sandrew i++; 426245549Sandrew if (i == 2) { 427245549Sandrew sep = "\n\t"; 428245549Sandrew i = 0; 429245549Sandrew } else 430245549Sandrew sep = " "; 431273157Srpaulo 432245549Sandrew } 433245549Sandrew } 434245549Sandrew db_printf("\n"); 435250252Sian 436250254Sian /* 437250254Sian * Stop if directed to do so, or if we've unwound back to the 438250252Sian * kernel entry point, or if the unwind function didn't change 439250252Sian * anything (to avoid getting stuck in this loop forever). 440250252Sian * If the latter happens, it's an indication that the unwind 441250252Sian * information is incorrect somehow for the function named in 442250252Sian * the last frame printed before you see the unwind failure 443250252Sian * message (maybe it needs a STOP_UNWINDING). 444250252Sian */ 445250252Sian if (index->insn == EXIDX_CANTUNWIND) { 446250252Sian finished = true; 447250252Sian } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { 448250252Sian db_printf("Unable to unwind into user mode\n"); 449250252Sian finished = true; 450250252Sian } else if (state->update_mask == 0) { 451250252Sian db_printf("Unwind failure (no registers changed)\n"); 452250252Sian finished = true; 453250252Sian } 454245549Sandrew } 455245549Sandrew} 456245549Sandrew#endif 457245549Sandrew 458245549Sandrew/* 459129198Scognet * APCS stack frames are awkward beasts, so I don't think even trying to use 460129198Scognet * a structure to represent them is a good idea. 461129198Scognet * 462129198Scognet * Here's the diagram from the APCS. Increasing address is _up_ the page. 463236991Simp * 464129198Scognet * save code pointer [fp] <- fp points to here 465129198Scognet * return link value [fp, #-4] 466129198Scognet * return sp value [fp, #-8] 467129198Scognet * return fp value [fp, #-12] 468129198Scognet * [saved v7 value] 469129198Scognet * [saved v6 value] 470129198Scognet * [saved v5 value] 471129198Scognet * [saved v4 value] 472129198Scognet * [saved v3 value] 473129198Scognet * [saved v2 value] 474129198Scognet * [saved v1 value] 475129198Scognet * [saved a4 value] 476129198Scognet * [saved a3 value] 477129198Scognet * [saved a2 value] 478129198Scognet * [saved a1 value] 479129198Scognet * 480236991Simp * The save code pointer points twelve bytes beyond the start of the 481236991Simp * code sequence (usually a single STM) that created the stack frame. 482236991Simp * We have to disassemble it if we want to know which of the optional 483129198Scognet * fields are actually present. 484129198Scognet */ 485129198Scognet 486245549Sandrew#ifndef __ARM_EABI__ /* The frame format is differend in AAPCS */ 487132482Smarcelstatic void 488236308Sgberdb_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only) 489129198Scognet{ 490129198Scognet u_int32_t *frame, *lastframe; 491129198Scognet c_db_sym_t sym; 492129198Scognet const char *name; 493129198Scognet db_expr_t value; 494129198Scognet db_expr_t offset; 495160312Sjhb int scp_offset; 496129198Scognet 497137977Scognet frame = (u_int32_t *)addr; 498129198Scognet lastframe = NULL; 499129198Scognet scp_offset = -(get_pc_str_offset() >> 2); 500129198Scognet 501160312Sjhb while (count-- && frame != NULL && !db_pager_quit) { 502129198Scognet db_addr_t scp; 503129198Scognet u_int32_t savecode; 504129198Scognet int r; 505129198Scognet u_int32_t *rp; 506129198Scognet const char *sep; 507129198Scognet 508129198Scognet /* 509129198Scognet * In theory, the SCP isn't guaranteed to be in the function 510129198Scognet * that generated the stack frame. We hope for the best. 511129198Scognet */ 512129198Scognet scp = frame[FR_SCP]; 513129198Scognet 514135647Scognet sym = db_search_symbol(scp, DB_STGY_ANY, &offset); 515129198Scognet if (sym == C_DB_SYM_NULL) { 516129198Scognet value = 0; 517129198Scognet name = "(null)"; 518129198Scognet } else 519129198Scognet db_symbol_values(sym, &name, &value); 520129198Scognet db_printf("%s() at ", name); 521135647Scognet db_printsym(scp, DB_STGY_PROC); 522129198Scognet db_printf("\n"); 523129198Scognet#ifdef __PROG26 524253309Srpaulo db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV] & R15_PC); 525129198Scognet db_printsym(frame[FR_RLV] & R15_PC, DB_STGY_PROC); 526129198Scognet db_printf(")\n"); 527129198Scognet#else 528253309Srpaulo db_printf("\tscp=0x%08x rlv=0x%08x (", scp, frame[FR_RLV]); 529129198Scognet db_printsym(frame[FR_RLV], DB_STGY_PROC); 530129198Scognet db_printf(")\n"); 531129198Scognet#endif 532129198Scognet db_printf("\trsp=0x%08x rfp=0x%08x", frame[FR_RSP], frame[FR_RFP]); 533129198Scognet 534129198Scognet savecode = ((u_int32_t *)scp)[scp_offset]; 535129198Scognet if ((savecode & 0x0e100000) == 0x08000000) { 536129198Scognet /* Looks like an STM */ 537129198Scognet rp = frame - 4; 538129198Scognet sep = "\n\t"; 539129198Scognet for (r = 10; r >= 0; r--) { 540129198Scognet if (savecode & (1 << r)) { 541129198Scognet db_printf("%sr%d=0x%08x", 542129198Scognet sep, r, *rp--); 543129198Scognet sep = (frame - rp) % 4 == 2 ? 544129198Scognet "\n\t" : " "; 545129198Scognet } 546129198Scognet } 547129198Scognet } 548129198Scognet 549129198Scognet db_printf("\n"); 550129198Scognet 551129198Scognet /* 552129198Scognet * Switch to next frame up 553129198Scognet */ 554129198Scognet if (frame[FR_RFP] == 0) 555129198Scognet break; /* Top of stack */ 556129198Scognet 557129198Scognet lastframe = frame; 558129198Scognet frame = (u_int32_t *)(frame[FR_RFP]); 559129198Scognet 560129198Scognet if (INKERNEL((int)frame)) { 561129198Scognet /* staying in kernel */ 562129198Scognet if (frame <= lastframe) { 563129198Scognet db_printf("Bad frame pointer: %p\n", frame); 564129198Scognet break; 565129198Scognet } 566129198Scognet } else if (INKERNEL((int)lastframe)) { 567129198Scognet /* switch from user to kernel */ 568129198Scognet if (kernel_only) 569129198Scognet break; /* kernel stack only */ 570129198Scognet } else { 571129198Scognet /* in user */ 572129198Scognet if (frame <= lastframe) { 573129198Scognet db_printf("Bad user frame pointer: %p\n", 574129198Scognet frame); 575129198Scognet break; 576129198Scognet } 577129198Scognet } 578129198Scognet } 579129198Scognet} 580245549Sandrew#endif 581129198Scognet 582129198Scognet/* XXX stubs */ 583129198Scognetvoid 584129198Scognetdb_md_list_watchpoints() 585129198Scognet{ 586129198Scognet} 587129198Scognet 588129198Scognetint 589129198Scognetdb_md_clr_watchpoint(db_expr_t addr, db_expr_t size) 590129198Scognet{ 591129198Scognet return (0); 592129198Scognet} 593129198Scognet 594129198Scognetint 595129198Scognetdb_md_set_watchpoint(db_expr_t addr, db_expr_t size) 596129198Scognet{ 597129198Scognet return (0); 598129198Scognet} 599132482Smarcel 600132059Scognetint 601132059Scognetdb_trace_thread(struct thread *thr, int count) 602129198Scognet{ 603245549Sandrew#ifdef __ARM_EABI__ 604245549Sandrew struct unwind_state state; 605245549Sandrew#endif 606198943Smarcel struct pcb *ctx; 607129198Scognet 608236308Sgber if (thr != curthread) { 609236308Sgber ctx = kdb_thr_ctx(thr); 610245549Sandrew 611245549Sandrew#ifdef __ARM_EABI__ 612276190Sian state.registers[FP] = ctx->pcb_regs.sf_r11; 613276190Sian state.registers[SP] = ctx->pcb_regs.sf_sp; 614276190Sian state.registers[LR] = ctx->pcb_regs.sf_lr; 615276190Sian state.registers[PC] = ctx->pcb_regs.sf_pc; 616245549Sandrew 617245549Sandrew db_stack_trace_cmd(&state); 618245549Sandrew#else 619276190Sian db_stack_trace_cmd(ctx->pcb_regs.sf_r11, -1, TRUE); 620245549Sandrew#endif 621236308Sgber } else 622236308Sgber db_trace_self(); 623132059Scognet return (0); 624129198Scognet} 625132059Scognet 626132059Scognetvoid 627132059Scognetdb_trace_self(void) 628132059Scognet{ 629245549Sandrew#ifdef __ARM_EABI__ 630245549Sandrew struct unwind_state state; 631248124Sandrew uint32_t sp; 632245549Sandrew 633248124Sandrew /* Read the stack pointer */ 634248124Sandrew __asm __volatile("mov %0, sp" : "=&r" (sp)); 635248124Sandrew 636245549Sandrew state.registers[FP] = (uint32_t)__builtin_frame_address(0); 637248124Sandrew state.registers[SP] = sp; 638245549Sandrew state.registers[LR] = (uint32_t)__builtin_return_address(0); 639245549Sandrew state.registers[PC] = (uint32_t)db_trace_self; 640245549Sandrew 641245549Sandrew db_stack_trace_cmd(&state); 642245549Sandrew#else 643198942Smarcel db_addr_t addr; 644198942Smarcel 645203171Smarcel addr = (db_addr_t)__builtin_frame_address(0); 646236308Sgber db_stack_trace_cmd(addr, -1, FALSE); 647245549Sandrew#endif 648132059Scognet} 649