From owner-svn-src-all@FreeBSD.ORG Tue Feb 17 13:09:22 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 232ABAC4; Tue, 17 Feb 2015 13:09:22 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 0D023A4; Tue, 17 Feb 2015 13:09:22 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1HD9MAW004902; Tue, 17 Feb 2015 13:09:22 GMT (envelope-from andrew@FreeBSD.org) Received: (from andrew@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1HD9L4b004892; Tue, 17 Feb 2015 13:09:21 GMT (envelope-from andrew@FreeBSD.org) Message-Id: <201502171309.t1HD9L4b004892@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: andrew set sender to andrew@FreeBSD.org using -f From: Andrew Turner Date: Tue, 17 Feb 2015 13:09:21 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r278895 - in head/sys: arm/arm arm/include conf X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 17 Feb 2015 13:09:22 -0000 Author: andrew Date: Tue Feb 17 13:09:20 2015 New Revision: 278895 URL: https://svnweb.freebsd.org/changeset/base/278895 Log: Pull the ARM ddb unwind code out to a new file. This will allow it to be used by other places that expect to unwind the stack, e.g. dtrace and stack(9). As I have written most of this code I'm changing the license to the standard FreeBSD license. I have received approval from the other developers who have changed any of the affected code. Approved by: ian, imp, rpaulo, eadler (all license change) Added: head/sys/arm/arm/unwind.c - copied, changed from r278894, head/sys/arm/arm/db_trace.c Modified: head/sys/arm/arm/db_trace.c head/sys/arm/include/stack.h head/sys/conf/files.arm Modified: head/sys/arm/arm/db_trace.c ============================================================================== --- head/sys/arm/arm/db_trace.c Tue Feb 17 10:00:15 2015 (r278894) +++ head/sys/arm/arm/db_trace.c Tue Feb 17 13:09:20 2015 (r278895) @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include + #include #include #include @@ -45,322 +46,15 @@ __FBSDID("$FreeBSD$"); #include #include #include + #include #include #include #include -/* - * Definitions for the instruction interpreter. - * - * The ARM EABI specifies how to perform the frame unwinding in the - * Exception Handling ABI for the ARM Architecture document. To perform - * the unwind we need to know the initial frame pointer, stack pointer, - * link register and program counter. We then find the entry within the - * index table that points to the function the program counter is within. - * This gives us either a list of three instructions to process, a 31-bit - * relative offset to a table of instructions, or a value telling us - * we can't unwind any further. - * - * When we have the instructions to process we need to decode them - * following table 4 in section 9.3. This describes a collection of bit - * patterns to encode that steps to take to update the stack pointer and - * link register to the correct values at the start of the function. - */ - -/* A special case when we are unable to unwind past this function */ -#define EXIDX_CANTUNWIND 1 - -/* The register names */ -#define FP 11 -#define SP 13 -#define LR 14 -#define PC 15 - -/* - * These are set in the linker script. Their addresses will be - * either the start or end of the exception table or index. - */ -extern int extab_start, extab_end, exidx_start, exidx_end; - -/* - * Entry types. - * These are the only entry types that have been seen in the kernel. - */ -#define ENTRY_MASK 0xff000000 -#define ENTRY_ARM_SU16 0x80000000 -#define ENTRY_ARM_LU16 0x81000000 - -/* Instruction masks. */ -#define INSN_VSP_MASK 0xc0 -#define INSN_VSP_SIZE_MASK 0x3f -#define INSN_STD_MASK 0xf0 -#define INSN_STD_DATA_MASK 0x0f -#define INSN_POP_TYPE_MASK 0x08 -#define INSN_POP_COUNT_MASK 0x07 -#define INSN_VSP_LARGE_INC_MASK 0xff - -/* Instruction definitions */ -#define INSN_VSP_INC 0x00 -#define INSN_VSP_DEC 0x40 -#define INSN_POP_MASKED 0x80 -#define INSN_VSP_REG 0x90 -#define INSN_POP_COUNT 0xa0 -#define INSN_FINISH 0xb0 -#define INSN_POP_REGS 0xb1 -#define INSN_VSP_LARGE_INC 0xb2 - -/* An item in the exception index table */ -struct unwind_idx { - uint32_t offset; - uint32_t insn; -}; - -/* The state of the unwind process */ -struct unwind_state { - uint32_t registers[16]; - uint32_t start_pc; - uint32_t *insn; - u_int entries; - u_int byte; - uint16_t update_mask; -}; - -/* Expand a 31-bit signed value to a 32-bit signed value */ -static __inline int32_t -db_expand_prel31(uint32_t prel31) -{ - - return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; -} - -/* - * Perform a binary search of the index table to find the function - * with the largest address that doesn't exceed addr. - */ -static struct unwind_idx * -db_find_index(uint32_t addr) -{ - unsigned int min, mid, max; - struct unwind_idx *start; - struct unwind_idx *item; - int32_t prel31_addr; - uint32_t func_addr; - - start = (struct unwind_idx *)&exidx_start; - - min = 0; - max = (&exidx_end - &exidx_start) / 2; - - while (min != max) { - mid = min + (max - min + 1) / 2; - - item = &start[mid]; - - prel31_addr = db_expand_prel31(item->offset); - func_addr = (uint32_t)&item->offset + prel31_addr; - - if (func_addr <= addr) { - min = mid; - } else { - max = mid - 1; - } - } - - return &start[min]; -} - -/* Reads the next byte from the instruction list */ -static uint8_t -db_unwind_exec_read_byte(struct unwind_state *state) -{ - uint8_t insn; - - /* Read the unwind instruction */ - insn = (*state->insn) >> (state->byte * 8); - - /* Update the location of the next instruction */ - if (state->byte == 0) { - state->byte = 3; - state->insn++; - state->entries--; - } else - state->byte--; - - return insn; -} - -/* Executes the next instruction on the list */ -static int -db_unwind_exec_insn(struct unwind_state *state) -{ - unsigned int insn; - uint32_t *vsp = (uint32_t *)state->registers[SP]; - int update_vsp = 0; - - /* This should never happen */ - if (state->entries == 0) - return 1; - - /* Read the next instruction */ - insn = db_unwind_exec_read_byte(state); - - if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { - state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; - - } else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) { - state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; - - } else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) { - unsigned int mask, reg; - - /* Load the mask */ - mask = db_unwind_exec_read_byte(state); - mask |= (insn & INSN_STD_DATA_MASK) << 8; - - /* We have a refuse to unwind instruction */ - if (mask == 0) - return 1; - - /* Update SP */ - update_vsp = 1; - - /* Load the registers */ - for (reg = 4; mask && reg < 16; mask >>= 1, reg++) { - if (mask & 1) { - state->registers[reg] = *vsp++; - state->update_mask |= 1 << reg; - - /* If we have updated SP kep its value */ - if (reg == SP) - update_vsp = 0; - } - } - - } else if ((insn & INSN_STD_MASK) == INSN_VSP_REG && - ((insn & INSN_STD_DATA_MASK) != 13) && - ((insn & INSN_STD_DATA_MASK) != 15)) { - /* sp = register */ - state->registers[SP] = - state->registers[insn & INSN_STD_DATA_MASK]; - - } else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) { - unsigned int count, reg; - - /* Read how many registers to load */ - count = insn & INSN_POP_COUNT_MASK; - - /* Update sp */ - update_vsp = 1; - - /* Pop the registers */ - for (reg = 4; reg <= 4 + count; reg++) { - state->registers[reg] = *vsp++; - state->update_mask |= 1 << reg; - } - - /* Check if we are in the pop r14 version */ - if ((insn & INSN_POP_TYPE_MASK) != 0) { - state->registers[14] = *vsp++; - } - - } else if (insn == INSN_FINISH) { - /* Stop processing */ - state->entries = 0; - - } else if (insn == INSN_POP_REGS) { - unsigned int mask, reg; - - mask = db_unwind_exec_read_byte(state); - if (mask == 0 || (mask & 0xf0) != 0) - return 1; - - /* Update SP */ - update_vsp = 1; - - /* Load the registers */ - for (reg = 0; mask && reg < 4; mask >>= 1, reg++) { - if (mask & 1) { - state->registers[reg] = *vsp++; - state->update_mask |= 1 << reg; - } - } - - } else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) { - unsigned int uleb128; - - /* Read the increment value */ - uleb128 = db_unwind_exec_read_byte(state); - - state->registers[SP] += 0x204 + (uleb128 << 2); - - } else { - /* We hit a new instruction that needs to be implemented */ - db_printf("Unhandled instruction %.2x\n", insn); - return 1; - } - - if (update_vsp) { - state->registers[SP] = (uint32_t)vsp; - } - -#if 0 - db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n", - state->registers[FP], state->registers[SP], state->registers[LR], - state->registers[PC]); -#endif - - return 0; -} - -/* Performs the unwind of a function */ -static int -db_unwind_tab(struct unwind_state *state) -{ - uint32_t entry; - - /* Set PC to a known value */ - state->registers[PC] = 0; - - /* Read the personality */ - entry = *state->insn & ENTRY_MASK; - - if (entry == ENTRY_ARM_SU16) { - state->byte = 2; - state->entries = 1; - } else if (entry == ENTRY_ARM_LU16) { - state->byte = 1; - state->entries = ((*state->insn >> 16) & 0xFF) + 1; - } else { - db_printf("Unknown entry: %x\n", entry); - return 1; - } - - while (state->entries > 0) { - if (db_unwind_exec_insn(state) != 0) - return 1; - } - - /* - * The program counter was not updated, load it from the link register. - */ - if (state->registers[PC] == 0) { - state->registers[PC] = state->registers[LR]; - - /* - * If the program counter changed, flag it in the update mask. - */ - if (state->start_pc != state->registers[PC]) - state->update_mask |= 1 << PC; - } - - return 0; -} - static void db_stack_trace_cmd(struct unwind_state *state) { - struct unwind_idx *index; const char *name; db_expr_t value; db_expr_t offset; @@ -372,28 +66,7 @@ db_stack_trace_cmd(struct unwind_state * finished = false; while (!finished) { - /* Reset the mask of updated registers */ - state->update_mask = 0; - - /* The pc value is correct and will be overwritten, save it */ - state->start_pc = state->registers[PC]; - - /* Find the item to run */ - index = db_find_index(state->start_pc); - - if (index->insn != EXIDX_CANTUNWIND) { - if (index->insn & (1U << 31)) { - /* The data is within the instruction */ - state->insn = &index->insn; - } else { - /* A prel31 offset to the unwind table */ - state->insn = (uint32_t *) - ((uintptr_t)&index->insn + - db_expand_prel31(index->insn)); - } - /* Run the unwind function */ - finished = db_unwind_tab(state); - } + finished = unwind_stack_one(state); /* Print the frame details */ sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); @@ -432,6 +105,9 @@ db_stack_trace_cmd(struct unwind_state * } db_printf("\n"); + if (finished) + break; + /* * Stop if directed to do so, or if we've unwound back to the * kernel entry point, or if the unwind function didn't change @@ -441,9 +117,7 @@ db_stack_trace_cmd(struct unwind_state * * the last frame printed before you see the unwind failure * message (maybe it needs a STOP_UNWINDING). */ - if (index->insn == EXIDX_CANTUNWIND) { - finished = true; - } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { + if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { db_printf("Unable to unwind into user mode\n"); finished = true; } else if (state->update_mask == 0) { Copied and modified: head/sys/arm/arm/unwind.c (from r278894, head/sys/arm/arm/db_trace.c) ============================================================================== --- head/sys/arm/arm/db_trace.c Tue Feb 17 10:00:15 2015 (r278894, copy source) +++ head/sys/arm/arm/unwind.c Tue Feb 17 13:09:20 2015 (r278895) @@ -1,54 +1,40 @@ -/* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ - -/*- - * Copyright (c) 2000, 2001 Ben Harris - * Copyright (c) 1996 Scott K. Stevens - * - * Mach Operating System - * Copyright (c) 1991,1990 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. +/* + * Copyright 2013-2014 Andrew Turner. + * Copyright 2013-2014 Ian Lepore. + * Copyright 2013-2014 Rui Paulo. + * Copyright 2013 Eitan Adler. + * All rights reserved. * - * Carnegie Mellon requests users of this software to return to + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); + #include #include - -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include /* * Definitions for the instruction interpreter. @@ -71,12 +57,6 @@ __FBSDID("$FreeBSD$"); /* A special case when we are unable to unwind past this function */ #define EXIDX_CANTUNWIND 1 -/* The register names */ -#define FP 11 -#define SP 13 -#define LR 14 -#define PC 15 - /* * These are set in the linker script. Their addresses will be * either the start or end of the exception table or index. @@ -116,19 +96,9 @@ struct unwind_idx { uint32_t insn; }; -/* The state of the unwind process */ -struct unwind_state { - uint32_t registers[16]; - uint32_t start_pc; - uint32_t *insn; - u_int entries; - u_int byte; - uint16_t update_mask; -}; - /* Expand a 31-bit signed value to a 32-bit signed value */ static __inline int32_t -db_expand_prel31(uint32_t prel31) +expand_prel31(uint32_t prel31) { return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; @@ -139,7 +109,7 @@ db_expand_prel31(uint32_t prel31) * with the largest address that doesn't exceed addr. */ static struct unwind_idx * -db_find_index(uint32_t addr) +find_index(uint32_t addr) { unsigned int min, mid, max; struct unwind_idx *start; @@ -157,7 +127,7 @@ db_find_index(uint32_t addr) item = &start[mid]; - prel31_addr = db_expand_prel31(item->offset); + prel31_addr = expand_prel31(item->offset); func_addr = (uint32_t)&item->offset + prel31_addr; if (func_addr <= addr) { @@ -172,7 +142,7 @@ db_find_index(uint32_t addr) /* Reads the next byte from the instruction list */ static uint8_t -db_unwind_exec_read_byte(struct unwind_state *state) +unwind_exec_read_byte(struct unwind_state *state) { uint8_t insn; @@ -192,7 +162,7 @@ db_unwind_exec_read_byte(struct unwind_s /* Executes the next instruction on the list */ static int -db_unwind_exec_insn(struct unwind_state *state) +unwind_exec_insn(struct unwind_state *state) { unsigned int insn; uint32_t *vsp = (uint32_t *)state->registers[SP]; @@ -203,7 +173,7 @@ db_unwind_exec_insn(struct unwind_state return 1; /* Read the next instruction */ - insn = db_unwind_exec_read_byte(state); + insn = unwind_exec_read_byte(state); if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) { state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4; @@ -215,7 +185,7 @@ db_unwind_exec_insn(struct unwind_state unsigned int mask, reg; /* Load the mask */ - mask = db_unwind_exec_read_byte(state); + mask = unwind_exec_read_byte(state); mask |= (insn & INSN_STD_DATA_MASK) << 8; /* We have a refuse to unwind instruction */ @@ -271,7 +241,7 @@ db_unwind_exec_insn(struct unwind_state } else if (insn == INSN_POP_REGS) { unsigned int mask, reg; - mask = db_unwind_exec_read_byte(state); + mask = unwind_exec_read_byte(state); if (mask == 0 || (mask & 0xf0) != 0) return 1; @@ -290,13 +260,15 @@ db_unwind_exec_insn(struct unwind_state unsigned int uleb128; /* Read the increment value */ - uleb128 = db_unwind_exec_read_byte(state); + uleb128 = unwind_exec_read_byte(state); state->registers[SP] += 0x204 + (uleb128 << 2); } else { /* We hit a new instruction that needs to be implemented */ +#if 0 db_printf("Unhandled instruction %.2x\n", insn); +#endif return 1; } @@ -315,7 +287,7 @@ db_unwind_exec_insn(struct unwind_state /* Performs the unwind of a function */ static int -db_unwind_tab(struct unwind_state *state) +unwind_tab(struct unwind_state *state) { uint32_t entry; @@ -332,12 +304,14 @@ db_unwind_tab(struct unwind_state *state state->byte = 1; state->entries = ((*state->insn >> 16) & 0xFF) + 1; } else { +#if 0 db_printf("Unknown entry: %x\n", entry); +#endif return 1; } while (state->entries > 0) { - if (db_unwind_exec_insn(state) != 0) + if (unwind_exec_insn(state) != 0) return 1; } @@ -357,153 +331,39 @@ db_unwind_tab(struct unwind_state *state return 0; } -static void -db_stack_trace_cmd(struct unwind_state *state) +int +unwind_stack_one(struct unwind_state *state) { struct unwind_idx *index; - const char *name; - db_expr_t value; - db_expr_t offset; - c_db_sym_t sym; - u_int reg, i; - char *sep; - uint16_t upd_mask; - bool finished; - - finished = false; - while (!finished) { - /* Reset the mask of updated registers */ - state->update_mask = 0; - - /* The pc value is correct and will be overwritten, save it */ - state->start_pc = state->registers[PC]; - - /* Find the item to run */ - index = db_find_index(state->start_pc); - - if (index->insn != EXIDX_CANTUNWIND) { - if (index->insn & (1U << 31)) { - /* The data is within the instruction */ - state->insn = &index->insn; - } else { - /* A prel31 offset to the unwind table */ - state->insn = (uint32_t *) - ((uintptr_t)&index->insn + - db_expand_prel31(index->insn)); - } - /* Run the unwind function */ - finished = db_unwind_tab(state); - } + int finished; - /* Print the frame details */ - sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); - if (sym == C_DB_SYM_NULL) { - value = 0; - name = "(null)"; - } else - db_symbol_values(sym, &name, &value); - db_printf("%s() at ", name); - db_printsym(state->start_pc, DB_STGY_PROC); - db_printf("\n"); - db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, - state->registers[LR]); - db_printsym(state->registers[LR], DB_STGY_PROC); - db_printf(")\n"); - db_printf("\t sp = 0x%08x fp = 0x%08x", - state->registers[SP], state->registers[FP]); - - /* Don't print the registers we have already printed */ - upd_mask = state->update_mask & - ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC)); - sep = "\n\t"; - for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) { - if ((upd_mask & 1) != 0) { - db_printf("%s%sr%d = 0x%08x", sep, - (reg < 10) ? " " : "", reg, - state->registers[reg]); - i++; - if (i == 2) { - sep = "\n\t"; - i = 0; - } else - sep = " "; + /* Reset the mask of updated registers */ + state->update_mask = 0; - } - } - db_printf("\n"); + /* The pc value is correct and will be overwritten, save it */ + state->start_pc = state->registers[PC]; - /* - * Stop if directed to do so, or if we've unwound back to the - * kernel entry point, or if the unwind function didn't change - * anything (to avoid getting stuck in this loop forever). - * If the latter happens, it's an indication that the unwind - * information is incorrect somehow for the function named in - * the last frame printed before you see the unwind failure - * message (maybe it needs a STOP_UNWINDING). - */ - if (index->insn == EXIDX_CANTUNWIND) { - finished = true; - } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { - db_printf("Unable to unwind into user mode\n"); - finished = true; - } else if (state->update_mask == 0) { - db_printf("Unwind failure (no registers changed)\n"); - finished = true; + /* Find the item to run */ + index = find_index(state->start_pc); + + finished = 0; + if (index->insn != EXIDX_CANTUNWIND) { + if (index->insn & (1U << 31)) { + /* The data is within the instruction */ + state->insn = &index->insn; + } else { + /* A prel31 offset to the unwind table */ + state->insn = (uint32_t *) + ((uintptr_t)&index->insn + + expand_prel31(index->insn)); } + /* Run the unwind function */ + finished = unwind_tab(state); } -} - -/* XXX stubs */ -void -db_md_list_watchpoints() -{ -} - -int -db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) -{ - return (0); -} - -int -db_md_set_watchpoint(db_expr_t addr, db_expr_t size) -{ - return (0); -} - -int -db_trace_thread(struct thread *thr, int count) -{ - struct unwind_state state; - struct pcb *ctx; - - if (thr != curthread) { - ctx = kdb_thr_ctx(thr); - - state.registers[FP] = ctx->pcb_regs.sf_r11; - state.registers[SP] = ctx->pcb_regs.sf_sp; - state.registers[LR] = ctx->pcb_regs.sf_lr; - state.registers[PC] = ctx->pcb_regs.sf_pc; - - db_stack_trace_cmd(&state); - } else - db_trace_self(); - return (0); -} - -void -db_trace_self(void) -{ - struct unwind_state state; - uint32_t sp; - - /* Read the stack pointer */ - __asm __volatile("mov %0, sp" : "=&r" (sp)); - state.registers[FP] = (uint32_t)__builtin_frame_address(0); - state.registers[SP] = sp; - state.registers[LR] = (uint32_t)__builtin_return_address(0); - state.registers[PC] = (uint32_t)db_trace_self; + /* This is the top of the stack, finish */ + if (index->insn == EXIDX_CANTUNWIND) + finished = 1; - db_stack_trace_cmd(&state); + return (finished); } Modified: head/sys/arm/include/stack.h ============================================================================== --- head/sys/arm/include/stack.h Tue Feb 17 10:00:15 2015 (r278894) +++ head/sys/arm/include/stack.h Tue Feb 17 13:09:20 2015 (r278895) @@ -39,4 +39,22 @@ #define FR_RSP (-2) #define FR_RFP (-3) +/* The state of the unwind process */ +struct unwind_state { + uint32_t registers[16]; + uint32_t start_pc; + uint32_t *insn; + u_int entries; + u_int byte; + uint16_t update_mask; +}; + +/* The register names */ +#define FP 11 +#define SP 13 +#define LR 14 +#define PC 15 + +int unwind_stack_one(struct unwind_state *); + #endif /* !_MACHINE_STACK_H_ */ Modified: head/sys/conf/files.arm ============================================================================== --- head/sys/conf/files.arm Tue Feb 17 10:00:15 2015 (r278894) +++ head/sys/conf/files.arm Tue Feb 17 13:09:20 2015 (r278895) @@ -57,6 +57,7 @@ arm/arm/trap.c optional !armv6 arm/arm/trap-v6.c optional armv6 arm/arm/uio_machdep.c standard arm/arm/undefined.c standard +arm/arm/unwind.c optional ddb arm/arm/vm_machdep.c standard arm/arm/vfp.c standard board_id.h standard \