From owner-freebsd-arm@FreeBSD.ORG Sat Dec 7 12:16:37 2013 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 140942AE for ; Sat, 7 Dec 2013 12:16:37 +0000 (UTC) Received: from mail-qc0-x236.google.com (mail-qc0-x236.google.com [IPv6:2607:f8b0:400d:c01::236]) (using TLSv1 with cipher ECDHE-RSA-RC4-SHA (128/128 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id BF2D21834 for ; Sat, 7 Dec 2013 12:16:36 +0000 (UTC) Received: by mail-qc0-f182.google.com with SMTP id e16so1347969qcx.27 for ; Sat, 07 Dec 2013 04:16:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=i+o8gVKTLyNK1iOvZu/uyMb7lGVLEsfQpSAu91DAdpQ=; b=GVd/Uvr1KDN/ToPNq3/6F4f3MGxFRWRjWK9QFm3cwAAlVgqRtEoV9kbkoCPzjq3cSx s0XSwbJWL5/AxHTn030+FdNRR5Y0geHGsb++iADToxZ/7xRRBsEK7MC38HOhC5Mkmygv sF63VwqXRZDkg2doyGnp+0Z5tl+sQXNuphci/gXtNeuP+iVKETS2WbP27UAC/xa51Oym v9EQ6a3m+wRQFEZwj+rlTcgE8/qCx7bjKX/Pe5qtoKkktT5nDWaD7gpcoJsZoSTFmtLs II3OZ/LWx59BXxWpnvT1K2BB+lidLl02jNMF7icyI0+vYaEB0Ox7dknJqoF0SdlAXKDM CPQg== MIME-Version: 1.0 X-Received: by 10.224.4.70 with SMTP id 6mr15804719qaq.86.1386418595681; Sat, 07 Dec 2013 04:16:35 -0800 (PST) Received: by 10.224.130.194 with HTTP; Sat, 7 Dec 2013 04:16:35 -0800 (PST) Date: Sat, 7 Dec 2013 20:16:35 +0800 Message-ID: Subject: [PATCH] Add stack unwind support for the functions in .ko From: Howard Su To: freebsd-arm Content-Type: text/plain; charset=ISO-8859-1 X-Content-Filtered-By: Mailman/MimeDel 2.1.17 X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "Porting FreeBSD to ARM processors." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 07 Dec 2013 12:16:37 -0000 I need this function when working on dtrace/arm support. the basic idea is locate the ARM.EXIDX section by the symbol __exidx_start and __exidx_stop. To keep it simple, I always look through the link_file_list when unwind the stack. From the testing, the performance seems ok. Also, I implement the count parameter when unwind the stack which can make 'show threads' output more readable. I also disabled some print output by #if 0 which makes output more align with the other platform. Please review. Thanks, Howard Su diff --git a/sys/arm/arm/db_trace.c b/sys/arm/arm/db_trace.c index 57119da..9a4728d 100644 --- a/sys/arm/arm/db_trace.c +++ b/sys/arm/arm/db_trace.c @@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -79,12 +80,6 @@ __FBSDID("$FreeBSD$"); #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. */ @@ -135,6 +130,28 @@ db_expand_prel31(uint32_t prel31) return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2; } +struct db_find_index_context_t +{ + int valid; + caddr_t addr; + caddr_t exidx_start, exidx_end; +}; + +static int +db_find_index_file_cb(linker_file_t lf, void* arg) +{ + struct db_find_index_context_t *context = (struct db_find_index_context_t*)arg; + if (context->addr >= lf->address && context->addr < lf->address + lf->size) + { + context->exidx_start = linker_file_lookup_symbol(lf, "__exidx_start", 0); + context->exidx_end = linker_file_lookup_symbol(lf, "__exidx_end", 0); + context->valid = 1; + return 1; + } + + return 0; +} + /* * Perform a binary search of the index table to find the function * with the largest address that doesn't exceed addr. @@ -148,10 +165,18 @@ db_find_index(uint32_t addr) int32_t prel31_addr; uint32_t func_addr; - start = (struct unwind_idx *)&exidx_start; + struct db_find_index_context_t context; + context.valid = 0; + context.addr = (caddr_t)addr; + + linker_file_foreach(db_find_index_file_cb, &context); + if (!context.valid) + return 0; + + start = (struct unwind_idx *)context.exidx_start; min = 0; - max = (&exidx_end - &exidx_start) / 2; + max = (context.exidx_end - context.exidx_start) / 2; while (min != max) { mid = min + (max - min + 1) / 2; @@ -269,7 +294,7 @@ db_unwind_exec_insn(struct unwind_state *state) /* Stop processing */ state->entries = 0; - } else if ((insn == INSN_POP_REGS)) { + } else if (insn == INSN_POP_REGS) { unsigned int mask, reg; mask = db_unwind_exec_read_byte(state); @@ -352,20 +377,22 @@ db_unwind_tab(struct unwind_state *state) } static void -db_stack_trace_cmd(struct unwind_state *state) +db_stack_trace_cmd(struct unwind_state *state, int count) { struct unwind_idx *index; const char *name; db_expr_t value; db_expr_t offset; c_db_sym_t sym; +#if 0 u_int reg, i; char *sep; uint16_t upd_mask; +#endif bool finished; finished = false; - while (!finished) { + while (!finished && count--) { /* Reset the mask of updated registers */ state->update_mask = 0; @@ -375,7 +402,7 @@ db_stack_trace_cmd(struct unwind_state *state) /* Find the item to run */ index = db_find_index(state->start_pc); - if (index->insn != EXIDX_CANTUNWIND) { + if (index && index->insn != EXIDX_CANTUNWIND) { if (index->insn & (1U << 31)) { /* The data is within the instruction */ state->insn = &index->insn; @@ -399,6 +426,7 @@ db_stack_trace_cmd(struct unwind_state *state) db_printf("%s() at ", name); db_printsym(state->start_pc, DB_STGY_PROC); db_printf("\n"); +#if 0 db_printf("\t pc = 0x%08x lr = 0x%08x (", state->start_pc, state->registers[LR]); db_printsym(state->registers[LR], DB_STGY_PROC); @@ -425,7 +453,7 @@ db_stack_trace_cmd(struct unwind_state *state) } } db_printf("\n"); - +#endif /* * 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 @@ -435,14 +463,17 @@ db_stack_trace_cmd(struct unwind_state *state) * the last frame printed before you see the unwind failure * message (maybe it needs a STOP_UNWINDING). */ - if (index->insn == EXIDX_CANTUNWIND) { - db_printf("Unable to unwind further\n"); + if (index && index->insn == EXIDX_CANTUNWIND) { + if (count) + db_printf("Unable to unwind further\n"); finished = true; } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) { - db_printf("Unable to unwind into user mode\n"); + if (count) + 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"); + if (count) + db_printf("Unwind failure (no registers changed)\n"); finished = true; } } @@ -479,7 +510,7 @@ db_stack_trace_cmd(struct unwind_state *state) #ifndef __ARM_EABI__ /* The frame format is differend in AAPCS */ static void -db_stack_trace_cmd(db_expr_t addr, db_expr_t count, boolean_t kernel_only) +db_stack_trace_cmd(db_expr_t addr, int count, boolean_t kernel_only) { u_int32_t *frame, *lastframe; c_db_sym_t sym; @@ -608,9 +639,9 @@ db_trace_thread(struct thread *thr, int count) state.registers[LR] = ctx->un_32.pcb32_lr; state.registers[PC] = ctx->un_32.pcb32_pc; - db_stack_trace_cmd(&state); + db_stack_trace_cmd(&state, count); #else - db_stack_trace_cmd(ctx->un_32.pcb32_r11, -1, TRUE); + db_stack_trace_cmd(ctx->un_32.pcb32_r11, count, TRUE); #endif } else db_trace_self(); @@ -632,7 +663,7 @@ db_trace_self(void) state.registers[LR] = (uint32_t)__builtin_return_address(0); state.registers[PC] = (uint32_t)db_trace_self; - db_stack_trace_cmd(&state); + db_stack_trace_cmd(&state, -1); #else db_addr_t addr; diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk index bd05878..d0a1f0f 100644 --- a/sys/conf/kmod.mk +++ b/sys/conf/kmod.mk @@ -133,6 +133,16 @@ CFLAGS+= -mlongcall -fno-omit-frame-pointer CFLAGS+= -G0 -fno-pic -mno-abicalls -mlong-calls .endif +.if ${MACHINE_CPUARCH} == arm +.if !defined(WITHOUT_ARM_EABI) +CFLAGS+= -funwind-tables +.if ${COMPILER_TYPE} == "clang" +# clang requires us to tell it to emit assembly with unwind information +CFLAGS+= -mllvm -arm-enable-ehabi +.endif +.endif +.endif + .if defined(DEBUG) || defined(DEBUG_FLAGS) CTFFLAGS+= -g .endif diff --git a/sys/conf/ldscript.arm b/sys/conf/ldscript.arm index 0d1c7ee..2482ce7 100644 --- a/sys/conf/ldscript.arm +++ b/sys/conf/ldscript.arm @@ -57,17 +57,11 @@ SECTIONS .plt : { *(.plt) } . = ALIGN(4); - _extab_start = .; - PROVIDE(extab_start = .); .ARM.extab : { *(.ARM.extab) } - _extab.end = .; - PROVIDE(extab_end = .); - _exidx_start = .; - PROVIDE(exidx_start = .); + __exidx_start = .; .ARM.exidx : { *(.ARM.exidx) } - _exidx_end = .; - PROVIDE(exidx_end = .); + __exidx_end = .; /* Adjust the address for the data segment. We want to adjust up to the same address within the page on the next page up. */ -- -Howard