|
@@ -11,6 +11,7 @@
|
|
#include <linux/types.h>
|
|
#include <linux/types.h>
|
|
#include "event.h"
|
|
#include "event.h"
|
|
#include "perf_regs.h"
|
|
#include "perf_regs.h"
|
|
|
|
+#include "callchain.h"
|
|
|
|
|
|
static char *debuginfo_path;
|
|
static char *debuginfo_path;
|
|
|
|
|
|
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
|
|
return __report_module(&al, ip, ui);
|
|
return __report_module(&al, ip, ui);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Store all entries within entries array,
|
|
|
|
+ * we will process it after we finish unwind.
|
|
|
|
+ */
|
|
static int entry(u64 ip, struct unwind_info *ui)
|
|
static int entry(u64 ip, struct unwind_info *ui)
|
|
|
|
|
|
{
|
|
{
|
|
- struct unwind_entry e;
|
|
|
|
|
|
+ struct unwind_entry *e = &ui->entries[ui->idx++];
|
|
struct addr_location al;
|
|
struct addr_location al;
|
|
|
|
|
|
if (__report_module(&al, ip, ui))
|
|
if (__report_module(&al, ip, ui))
|
|
return -1;
|
|
return -1;
|
|
|
|
|
|
- e.ip = ip;
|
|
|
|
- e.map = al.map;
|
|
|
|
- e.sym = al.sym;
|
|
|
|
|
|
+ e->ip = ip;
|
|
|
|
+ e->map = al.map;
|
|
|
|
+ e->sym = al.sym;
|
|
|
|
|
|
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
|
|
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
|
|
al.sym ? al.sym->name : "''",
|
|
al.sym ? al.sym->name : "''",
|
|
ip,
|
|
ip,
|
|
al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
|
|
al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
|
|
-
|
|
|
|
- return ui->cb(&e, ui->arg);
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
|
|
static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
|
|
@@ -168,7 +172,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
|
struct perf_sample *data,
|
|
struct perf_sample *data,
|
|
int max_stack)
|
|
int max_stack)
|
|
{
|
|
{
|
|
- struct unwind_info ui = {
|
|
|
|
|
|
+ struct unwind_info *ui, ui_buf = {
|
|
.sample = data,
|
|
.sample = data,
|
|
.thread = thread,
|
|
.thread = thread,
|
|
.machine = thread->mg->machine,
|
|
.machine = thread->mg->machine,
|
|
@@ -177,35 +181,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
|
|
.max_stack = max_stack,
|
|
.max_stack = max_stack,
|
|
};
|
|
};
|
|
Dwarf_Word ip;
|
|
Dwarf_Word ip;
|
|
- int err = -EINVAL;
|
|
|
|
|
|
+ int err = -EINVAL, i;
|
|
|
|
|
|
if (!data->user_regs.regs)
|
|
if (!data->user_regs.regs)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
- ui.dwfl = dwfl_begin(&offline_callbacks);
|
|
|
|
- if (!ui.dwfl)
|
|
|
|
|
|
+ ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
|
|
|
|
+ if (!ui)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ *ui = ui_buf;
|
|
|
|
+
|
|
|
|
+ ui->dwfl = dwfl_begin(&offline_callbacks);
|
|
|
|
+ if (!ui->dwfl)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
|
|
err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
|
|
if (err)
|
|
if (err)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- err = report_module(ip, &ui);
|
|
|
|
|
|
+ err = report_module(ip, ui);
|
|
if (err)
|
|
if (err)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
|
|
|
|
|
|
+ if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
|
|
|
|
|
|
+ err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
|
|
|
|
|
|
- if (err && !ui.max_stack)
|
|
|
|
|
|
+ if (err && !ui->max_stack)
|
|
err = 0;
|
|
err = 0;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Display what we got based on the order setup.
|
|
|
|
+ */
|
|
|
|
+ for (i = 0; i < ui->idx && !err; i++) {
|
|
|
|
+ int j = i;
|
|
|
|
+
|
|
|
|
+ if (callchain_param.order == ORDER_CALLER)
|
|
|
|
+ j = ui->idx - i - 1;
|
|
|
|
+
|
|
|
|
+ err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
out:
|
|
out:
|
|
if (err)
|
|
if (err)
|
|
pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
|
|
pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
|
|
|
|
|
|
- dwfl_end(ui.dwfl);
|
|
|
|
|
|
+ dwfl_end(ui->dwfl);
|
|
|
|
+ free(ui);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|