#include "thread.h"
#include "ui/ui.h"
#include "unwind.h"
+#include "unwind-libdw.h"
#include <internal/rc_check.h>
/*
#ifdef HAVE_LIBUNWIND_SUPPORT
void *addr_space;
const struct unwind_libunwind_ops *unwind_libunwind_ops;
+#endif
+#ifdef HAVE_LIBDW_SUPPORT
+ void *libdw_addr_space_dwfl;
#endif
refcount_t refcnt;
/**
RC_CHK_ACCESS(maps)->unwind_libunwind_ops = ops;
}
#endif
+#ifdef HAVE_LIBDW_SUPPORT
+void *maps__libdw_addr_space_dwfl(const struct maps *maps)
+{
+ return RC_CHK_ACCESS(maps)->libdw_addr_space_dwfl;
+}
+
+void maps__set_libdw_addr_space_dwfl(struct maps *maps, void *dwfl)
+{
+ RC_CHK_ACCESS(maps)->libdw_addr_space_dwfl = dwfl;
+}
+#endif
static struct rw_semaphore *maps__lock(struct maps *maps)
{
#ifdef HAVE_LIBUNWIND_SUPPORT
RC_CHK_ACCESS(maps)->addr_space = NULL;
RC_CHK_ACCESS(maps)->unwind_libunwind_ops = NULL;
+#endif
+#ifdef HAVE_LIBDW_SUPPORT
+ RC_CHK_ACCESS(maps)->libdw_addr_space_dwfl = NULL;
#endif
refcount_set(maps__refcnt(maps), 1);
RC_CHK_ACCESS(maps)->nr_maps = 0;
zfree(&maps_by_address);
zfree(&maps_by_name);
unwind__finish_access(maps);
+#ifdef HAVE_LIBDW_SUPPORT
+ libdw__invalidate_dwfl(maps, maps__libdw_addr_space_dwfl(maps));
+#endif
}
struct maps *maps__new(struct machine *machine)
__maps__remove(maps, map);
check_invariants(maps);
up_write(maps__lock(maps));
+#ifdef HAVE_LIBDW_SUPPORT
+ libdw__invalidate_dwfl(maps, maps__libdw_addr_space_dwfl(maps));
+#endif
}
bool maps__empty(struct maps *maps)
void maps__remove_maps(struct maps *maps, bool (*cb)(struct map *map, void *data), void *data)
{
struct map **maps_by_address;
+ bool removed = false;
down_write(maps__lock(maps));
maps_by_address = maps__maps_by_address(maps);
for (unsigned int i = 0; i < maps__nr_maps(maps);) {
- if (cb(maps_by_address[i], data))
+ if (cb(maps_by_address[i], data)) {
__maps__remove(maps, maps_by_address[i]);
- else
+ removed = true;
+ } else {
i++;
+ }
}
check_invariants(maps);
up_write(maps__lock(maps));
+ if (removed) {
+#ifdef HAVE_LIBDW_SUPPORT
+ libdw__invalidate_dwfl(maps, maps__libdw_addr_space_dwfl(maps));
+#endif
+ }
}
struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp)
#include "callchain.h"
#include "util/env.h"
+/*
+ * The dwfl thread argument passed to functions like memory_read. Memory has to
+ * be allocated to persist of multiple uses of the dwfl.
+ */
+struct dwfl_ui_thread_info {
+ /* Back link to the dwfl. */
+ Dwfl *dwfl;
+ /* The current unwind info, only 1 is supported. */
+ struct unwind_info *ui;
+};
+
static char *debuginfo_path;
static int __find_debuginfo(Dwfl_Module *mod __maybe_unused, void **userdata,
return -1;
}
+void libdw__invalidate_dwfl(struct maps *maps, void *arg)
+{
+ struct dwfl_ui_thread_info *dwfl_ui_ti = arg;
+
+ if (!dwfl_ui_ti)
+ return;
+
+ assert(dwfl_ui_ti->ui == NULL);
+ maps__set_libdw_addr_space_dwfl(maps, NULL);
+ dwfl_end(dwfl_ui_ti->dwfl);
+ free(dwfl_ui_ti);
+}
+
static const Dwfl_Callbacks offline_callbacks = {
.find_debuginfo = __find_debuginfo,
.debuginfo_path = &debuginfo_path,
static bool memory_read(Dwfl *dwfl __maybe_unused, Dwarf_Addr addr, Dwarf_Word *result,
void *arg)
{
- struct unwind_info *ui = arg;
+ struct dwfl_ui_thread_info *dwfl_ui_ti = arg;
+ struct unwind_info *ui = dwfl_ui_ti->ui;
uint16_t e_machine = thread__e_machine(ui->thread, ui->machine);
struct stack_dump *stack = &ui->sample->user_stack;
u64 start, end;
static bool libdw_set_initial_registers(Dwfl_Thread *thread, void *arg)
{
- struct unwind_info *ui = arg;
+ struct dwfl_ui_thread_info *dwfl_ui_ti = arg;
+ struct unwind_info *ui = dwfl_ui_ti->ui;
struct regs_dump *user_regs = perf_sample__user_regs(ui->sample);
Dwarf_Word *dwarf_regs;
int max_dwarf_reg = 0;
int max_stack,
bool best_effort)
{
- struct machine *machine = maps__machine(thread__maps(thread));
+ struct maps *maps = thread__maps(thread);
+ struct machine *machine = maps__machine(maps);
uint16_t e_machine = thread__e_machine(thread, machine);
- struct unwind_info *ui, ui_buf = {
- .sample = data,
- .thread = thread,
- .machine = machine,
- .cb = cb,
- .arg = arg,
- .max_stack = max_stack,
- .e_machine = e_machine,
- .best_effort = best_effort
- };
+ struct dwfl_ui_thread_info *dwfl_ui_ti;
+ static struct unwind_info *ui;
+ Dwfl *dwfl;
Dwarf_Word ip;
int err = -EINVAL, i;
if (!data->user_regs || !data->user_regs->regs)
return -EINVAL;
- ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
+ ui = zalloc(sizeof(*ui) + sizeof(ui->entries[0]) * max_stack);
if (!ui)
return -ENOMEM;
- *ui = ui_buf;
+ *ui = (struct unwind_info){
+ .sample = data,
+ .thread = thread,
+ .machine = machine,
+ .cb = cb,
+ .arg = arg,
+ .max_stack = max_stack,
+ .e_machine = e_machine,
+ .best_effort = best_effort
+ };
- ui->dwfl = dwfl_begin(&offline_callbacks);
- if (!ui->dwfl)
- goto out;
+ dwfl_ui_ti = maps__libdw_addr_space_dwfl(maps);
+ if (dwfl_ui_ti) {
+ dwfl = dwfl_ui_ti->dwfl;
+ } else {
+ dwfl_ui_ti = zalloc(sizeof(*dwfl_ui_ti));
+ dwfl = dwfl_begin(&offline_callbacks);
+ if (!dwfl)
+ goto out;
+
+ dwfl_ui_ti->dwfl = dwfl;
+ maps__set_libdw_addr_space_dwfl(maps, dwfl_ui_ti);
+ }
+ assert(dwfl_ui_ti->ui == NULL);
+ assert(dwfl_ui_ti->dwfl == dwfl);
+ assert(dwfl_ui_ti == maps__libdw_addr_space_dwfl(maps));
+ dwfl_ui_ti->ui = ui;
+ ui->dwfl = dwfl;
err = perf_reg_value(&ip, data->user_regs, perf_arch_reg_ip(e_machine));
if (err)
if (err)
goto out;
- err = !dwfl_attach_state(ui->dwfl, /*elf=*/NULL, thread__tid(thread), &callbacks, ui);
- if (err)
- goto out;
+ dwfl_attach_state(dwfl, /*elf=*/NULL, thread__tid(thread), &callbacks,
+ /* Dwfl thread function argument*/dwfl_ui_ti);
+ // Ignore thread already attached error.
- err = dwfl_getthread_frames(ui->dwfl, thread__tid(thread), frame_callback, ui);
+ err = dwfl_getthread_frames(dwfl, thread__tid(thread), frame_callback,
+ /* Dwfl frame function argument*/ui);
if (err && ui->max_stack != max_stack)
err = 0;
for (i = 0; i < ui->idx; i++)
map_symbol__exit(&ui->entries[i].ms);
- dwfl_end(ui->dwfl);
+ dwfl_ui_ti->ui = NULL;
free(ui);
return 0;
}