Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142067014
D4244.id10450.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D4244.id10450.diff
View Options
Index: sys/arm/arm/db_trace.c
===================================================================
--- sys/arm/arm/db_trace.c
+++ sys/arm/arm/db_trace.c
@@ -66,7 +66,7 @@
finished = false;
while (!finished) {
- finished = unwind_stack_one(state, 1);
+ finished = unwind_stack_one(state);
/* Print the frame details */
sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset);
Index: sys/arm/arm/unwind.c
===================================================================
--- sys/arm/arm/unwind.c
+++ sys/arm/arm/unwind.c
@@ -32,8 +32,15 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/types.h>
#include <sys/systm.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
#include <sys/linker.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
#include <machine/stack.h>
@@ -61,12 +68,6 @@
#define EXIDX_CANTUNWIND 1
/*
- * These are set in the linker script. Their addresses will be
- * either the start or end of the exception table or index.
- */
-extern int exidx_start, exidx_end;
-
-/*
* Entry types.
* These are the only entry types that have been seen in the kernel.
*/
@@ -107,69 +108,156 @@
return ((int32_t)(prel31 & 0x7fffffffu) << 1) / 2;
}
-struct search_context {
- uint32_t addr;
- caddr_t exidx_start;
- caddr_t exidx_end;
+struct module_idx {
+ SLIST_ENTRY(module_idx) module_next;
+ caddr_t address;
+ size_t size;
+ caddr_t start;
+ caddr_t end;
};
-static int
-module_search(linker_file_t lf, void *context)
+SLIST_HEAD(slisthead, module_idx) modules =
+ SLIST_HEAD_INITIALIZER(head);
+
+struct mtx mtx_modules;
+
+static void
+unwind_kld_load(void *arg __unused, linker_file_t lf)
{
- struct search_context *sc = context;
+ caddr_t exidx_start = 0, exidx_end = 0;
+ struct module_idx *m;
linker_symval_t symval;
c_linker_sym_t sym;
- if (lf->address <= (caddr_t)sc->addr &&
- (lf->address + lf->size) >= (caddr_t)sc->addr) {
- if ((LINKER_LOOKUP_SYMBOL(lf, "__exidx_start", &sym) == 0 ||
- LINKER_LOOKUP_SYMBOL(lf, "exidx_start", &sym) == 0) &&
- LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0)
- sc->exidx_start = symval.value;
-
- if ((LINKER_LOOKUP_SYMBOL(lf, "__exidx_end", &sym) == 0 ||
- LINKER_LOOKUP_SYMBOL(lf, "exidx_end", &sym) == 0) &&
- LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0)
- sc->exidx_end = symval.value;
-
- if (sc->exidx_start != NULL && sc->exidx_end != NULL)
- return (1);
- panic("Invalid module %s, no unwind tables\n", lf->filename);
+ if ((LINKER_LOOKUP_SYMBOL(lf, "__exidx_start", &sym) == 0 ||
+ LINKER_LOOKUP_SYMBOL(lf, "_exidx_start", &sym) == 0) &&
+ LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0)
+ exidx_start = symval.value;
+
+ if ((LINKER_LOOKUP_SYMBOL(lf, "__exidx_end", &sym) == 0 ||
+ LINKER_LOOKUP_SYMBOL(lf, "_exidx_end", &sym) == 0) &&
+ LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0)
+ exidx_end = symval.value;
+
+ if (exidx_start == 0 || exidx_end == 0) {
+ return;
+ }
+
+ struct module_idx *newentry = malloc(sizeof(struct module_idx), M_TEMP, M_WAITOK);
+ mtx_lock(&mtx_modules);
+ SLIST_FOREACH(m, &modules, module_next) {
+ if (m->address == 0 || m->address == lf->address) {
+ m->start = exidx_start;
+ m->end = exidx_end;
+ m->size = lf->size;
+ // set address last
+ atomic_store_rel_ptr((uint32_t*)&m->address, (uint32_t)lf->address);
+
+ mtx_unlock(&mtx_modules);
+ free(newentry, M_TEMP);
+ return;
+ }
+ }
+
+ newentry->start = exidx_start;
+ newentry->end = exidx_end;
+ newentry->size = lf->size;
+ newentry->address = lf->address;
+ SLIST_INSERT_HEAD(&modules, newentry, module_next);
+ mtx_unlock(&mtx_modules);
+}
+
+static void
+unwind_kld_unload_try(void *arg __unused, linker_file_t lf, int *error)
+{
+ if (*error != 0)
+ /* We already have an error, so don't do anything. */
+ return;
+
+ struct module_idx *m;
+ mtx_lock(&mtx_modules);
+ SLIST_FOREACH(m, &modules, module_next) {
+ if (m->address == lf->address) {
+ m->address = 0;
+ mtx_unlock(&mtx_modules);
+
+ return;
+ }
}
+
+ mtx_unlock(&mtx_modules);
+}
+
+static int module_search(linker_file_t lf, void* arg)
+{
+ unwind_kld_load(arg, lf);
+ return (1);
+}
+
+eventhandler_tag unwind_kld_load_tag;
+eventhandler_tag unwind_kld_unload_try_tag;
+
+static int unwind_initialize()
+{
+ mtx_init(&mtx_modules, "unwind module lock", NULL, MTX_DEF);
+
+ linker_file_foreach(module_search, NULL);
+
+ /* Register callbacks for linker file load and unload events. */
+ unwind_kld_load_tag = EVENTHANDLER_REGISTER(kld_load,
+ unwind_kld_load, NULL, EVENTHANDLER_PRI_ANY);
+ unwind_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
+ unwind_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
+
return (0);
}
+SYSINIT(unwind_init, SI_SUB_KLD, SI_ORDER_ANY, unwind_initialize, NULL);
/*
* 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 *
-find_index(uint32_t addr, int search_modules)
+find_index(uint32_t addr)
{
- struct search_context sc;
caddr_t idx_start, idx_end;
unsigned int min, mid, max;
- struct unwind_idx *start;
+ struct unwind_idx *start = NULL;
struct unwind_idx *item;
int32_t prel31_addr;
uint32_t func_addr;
-
- start = (struct unwind_idx *)&exidx_start;
- idx_start = (caddr_t)&exidx_start;
- idx_end = (caddr_t)&exidx_end;
-
- /* This may acquire a lock */
- if (search_modules) {
- bzero(&sc, sizeof(sc));
- sc.addr = addr;
- if (linker_file_foreach(module_search, &sc) != 0 &&
- sc.exidx_start != NULL && sc.exidx_end != NULL) {
- start = (struct unwind_idx *)sc.exidx_start;
- idx_start = sc.exidx_start;
- idx_end = sc.exidx_end;
+ struct module_idx *m;
+
+ SLIST_FOREACH(m, &modules, module_next) {
+ caddr_t daddr, dstart, dend;
+ size_t size;
+
+ do {
+ daddr = (caddr_t)atomic_load_acq_ptr((uint32_t *)&m->address);
+ if (daddr == 0)
+ break;
+
+ size = m->size;
+ dstart = m->start;
+ dend = m->end;
+
+ /* Ensure start, end, size have been loaded before address */
+ atomic_thread_fence_acq();
+ } while (daddr != m->address);
+
+ if (daddr != 0 && daddr <= (caddr_t)addr &&
+ (daddr + size) >= (caddr_t)addr) {
+ start = (struct unwind_idx *)dstart;
+ idx_start = dstart;
+ idx_end = dend;
+ break;
}
}
+ if (start == NULL) {
+ return (NULL);
+ }
+
min = 0;
max = (idx_end - idx_start) / sizeof(struct unwind_idx);
@@ -383,7 +471,7 @@
}
int
-unwind_stack_one(struct unwind_state *state, int can_lock)
+unwind_stack_one(struct unwind_state *state)
{
struct unwind_idx *index;
int finished;
@@ -395,7 +483,10 @@
state->start_pc = state->registers[PC];
/* Find the item to run */
- index = find_index(state->start_pc, can_lock);
+ index = find_index(state->start_pc);
+
+ if (index == NULL)
+ return 1;
finished = 0;
if (index->insn != EXIDX_CANTUNWIND) {
Index: sys/arm/include/atomic.h
===================================================================
--- sys/arm/include/atomic.h
+++ sys/arm/include/atomic.h
@@ -89,6 +89,8 @@
#define atomic_cmpset_acq_ptr atomic_cmpset_acq_32
#define atomic_store_ptr atomic_store_32
#define atomic_store_rel_ptr atomic_store_rel_32
+#define atomic_load_acq_ptr atomic_load_acq_32
+#define atomic_store_rel_ptr atomic_store_rel_32
#define atomic_add_int atomic_add_32
#define atomic_add_acq_int atomic_add_acq_32
Index: sys/arm/include/stack.h
===================================================================
--- sys/arm/include/stack.h
+++ sys/arm/include/stack.h
@@ -55,6 +55,6 @@
#define LR 14
#define PC 15
-int unwind_stack_one(struct unwind_state *, int);
+int unwind_stack_one(struct unwind_state *);
#endif /* !_MACHINE_STACK_H_ */
Index: sys/cddl/dev/dtrace/arm/dtrace_isa.c
===================================================================
--- sys/cddl/dev/dtrace/arm/dtrace_isa.c
+++ sys/cddl/dev/dtrace/arm/dtrace_isa.c
@@ -89,7 +89,7 @@
while (depth < pcstack_limit) {
int done;
- done = unwind_stack_one(&state, 1);
+ done = unwind_stack_one(&state);
/*
* NB: Unlike some other architectures, we don't need to
@@ -156,7 +156,7 @@
state.registers[PC] = (uint32_t)dtrace_getstackdepth;
do {
- done = unwind_stack_one(&state, 1);
+ done = unwind_stack_one(&state);
depth++;
} while (!done);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 16, 5:16 PM (13 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27663642
Default Alt Text
D4244.id10450.diff (8 KB)
Attached To
Mode
D4244: Implement a lock-free way to lookup modules when unwind stack.
Attached
Detach File
Event Timeline
Log In to Comment