105 lines
2.5 KiB
C
105 lines
2.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include "debug.h"
|
|
#include "symbol_conf.h"
|
|
#include "unwind.h"
|
|
#include <linux/string.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
|
|
struct thread *thread __maybe_unused,
|
|
struct perf_sample *data __maybe_unused,
|
|
int max_stack __maybe_unused,
|
|
bool best_effort __maybe_unused)
|
|
{
|
|
int ret = 0;
|
|
|
|
#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
|
|
if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
|
|
int i = 0;
|
|
#ifdef HAVE_LIBDW_SUPPORT
|
|
symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
|
|
#endif
|
|
#ifdef HAVE_LIBUNWIND_SUPPORT
|
|
symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
|
|
#endif
|
|
}
|
|
#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
|
|
switch (symbol_conf.unwind_style[i]) {
|
|
case UNWIND_STYLE_LIBDW:
|
|
ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
|
|
break;
|
|
case UNWIND_STYLE_LIBUNWIND:
|
|
ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
|
|
break;
|
|
case UNWIND_STYLE_UNKNOWN:
|
|
default:
|
|
#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
|
|
pr_warning_once(
|
|
"Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
|
|
#endif
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret > 0) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret < 0)
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
|
|
{
|
|
static const char * const unwind_style_names[] = {
|
|
[UNWIND_STYLE_LIBDW] = "libdw",
|
|
[UNWIND_STYLE_LIBUNWIND] = "libunwind",
|
|
NULL
|
|
};
|
|
char *s, *p, *saveptr;
|
|
size_t i = 0;
|
|
|
|
if (strcmp(var, "unwind.style"))
|
|
return 0;
|
|
|
|
if (!value)
|
|
return -1;
|
|
|
|
s = strdup(value);
|
|
if (!s)
|
|
return -1;
|
|
|
|
memset(symbol_conf.unwind_style, 0, sizeof(symbol_conf.unwind_style));
|
|
|
|
p = strtok_r(s, ",", &saveptr);
|
|
while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
|
|
bool found = false;
|
|
char *q = strim(p);
|
|
|
|
for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
|
|
if (!strcasecmp(q, unwind_style_names[j])) {
|
|
symbol_conf.unwind_style[i++] = j;
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found)
|
|
pr_warning("Unknown unwind style: %s\n", q);
|
|
p = strtok_r(NULL, ",", &saveptr);
|
|
}
|
|
|
|
free(s);
|
|
return 0;
|
|
}
|
|
|
|
int unwind__option(const struct option *opt __maybe_unused,
|
|
const char *arg,
|
|
int unset __maybe_unused)
|
|
{
|
|
return unwind__configure("unwind.style", arg, NULL);
|
|
}
|