perf probe: Provide perf interface for uprobes
- Enhances perf to probe user space executables and libraries. - Enhances -F/--funcs option of "perf probe" to list possible probe points in an executable file or library. - Documents userspace probing support in perf. [ Probing a function in the executable using function name ] perf probe -x /bin/zsh zfree [ Probing a library function using function name ] perf probe -x /lib64/libc.so.6 malloc [ list probe-able functions in an executable ] perf probe -F -x /bin/zsh [ list probe-able functions in an library] perf probe -F -x /lib/libc.so.6 Signed-off-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Anton Arapov <anton@redhat.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Linux-mm <linux-mm@kvack.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/20120416120909.30661.99781.sendpatchset@srdronam.in.ibm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
5dcefda0fd
commit
225466f1c2
@@ -77,7 +77,8 @@ OPTIONS
|
|||||||
|
|
||||||
-F::
|
-F::
|
||||||
--funcs::
|
--funcs::
|
||||||
Show available functions in given module or kernel.
|
Show available functions in given module or kernel. With -x/--exec,
|
||||||
|
can also list functions in a user space executable / shared library.
|
||||||
|
|
||||||
--filter=FILTER::
|
--filter=FILTER::
|
||||||
(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
|
(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
|
||||||
@@ -98,6 +99,11 @@ OPTIONS
|
|||||||
--max-probes::
|
--max-probes::
|
||||||
Set the maximum number of probe points for an event. Default is 128.
|
Set the maximum number of probe points for an event. Default is 128.
|
||||||
|
|
||||||
|
-x::
|
||||||
|
--exec=PATH::
|
||||||
|
Specify path to the executable or shared library file for user
|
||||||
|
space tracing. Can also be used with --funcs option.
|
||||||
|
|
||||||
PROBE SYNTAX
|
PROBE SYNTAX
|
||||||
------------
|
------------
|
||||||
Probe points are defined by following syntax.
|
Probe points are defined by following syntax.
|
||||||
@@ -182,6 +188,13 @@ Delete all probes on schedule().
|
|||||||
|
|
||||||
./perf probe --del='schedule*'
|
./perf probe --del='schedule*'
|
||||||
|
|
||||||
|
Add probes at zfree() function on /bin/zsh
|
||||||
|
|
||||||
|
./perf probe -x /bin/zsh zfree
|
||||||
|
|
||||||
|
Add probes at malloc() function on libc
|
||||||
|
|
||||||
|
./perf probe -x /lib/libc.so.6 malloc
|
||||||
|
|
||||||
SEE ALSO
|
SEE ALSO
|
||||||
--------
|
--------
|
||||||
|
@@ -54,6 +54,7 @@ static struct {
|
|||||||
bool show_ext_vars;
|
bool show_ext_vars;
|
||||||
bool show_funcs;
|
bool show_funcs;
|
||||||
bool mod_events;
|
bool mod_events;
|
||||||
|
bool uprobes;
|
||||||
int nevents;
|
int nevents;
|
||||||
struct perf_probe_event events[MAX_PROBES];
|
struct perf_probe_event events[MAX_PROBES];
|
||||||
struct strlist *dellist;
|
struct strlist *dellist;
|
||||||
@@ -75,6 +76,8 @@ static int parse_probe_event(const char *str)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pev->uprobes = params.uprobes;
|
||||||
|
|
||||||
/* Parse a perf-probe command into event */
|
/* Parse a perf-probe command into event */
|
||||||
ret = parse_perf_probe_command(str, pev);
|
ret = parse_perf_probe_command(str, pev);
|
||||||
pr_debug("%d arguments\n", pev->nargs);
|
pr_debug("%d arguments\n", pev->nargs);
|
||||||
@@ -125,6 +128,28 @@ static int opt_del_probe_event(const struct option *opt __used,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int opt_set_target(const struct option *opt, const char *str,
|
||||||
|
int unset __used)
|
||||||
|
{
|
||||||
|
int ret = -ENOENT;
|
||||||
|
|
||||||
|
if (str && !params.target) {
|
||||||
|
if (!strcmp(opt->long_name, "exec"))
|
||||||
|
params.uprobes = true;
|
||||||
|
#ifdef DWARF_SUPPORT
|
||||||
|
else if (!strcmp(opt->long_name, "module"))
|
||||||
|
params.uprobes = false;
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
params.target = str;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
static int opt_show_lines(const struct option *opt __used,
|
static int opt_show_lines(const struct option *opt __used,
|
||||||
const char *str, int unset __used)
|
const char *str, int unset __used)
|
||||||
@@ -246,9 +271,9 @@ static const struct option options[] = {
|
|||||||
"file", "vmlinux pathname"),
|
"file", "vmlinux pathname"),
|
||||||
OPT_STRING('s', "source", &symbol_conf.source_prefix,
|
OPT_STRING('s', "source", &symbol_conf.source_prefix,
|
||||||
"directory", "path to kernel source"),
|
"directory", "path to kernel source"),
|
||||||
OPT_STRING('m', "module", ¶ms.target,
|
OPT_CALLBACK('m', "module", NULL, "modname|path",
|
||||||
"modname|path",
|
"target module name (for online) or path (for offline)",
|
||||||
"target module name (for online) or path (for offline)"),
|
opt_set_target),
|
||||||
#endif
|
#endif
|
||||||
OPT__DRY_RUN(&probe_event_dry_run),
|
OPT__DRY_RUN(&probe_event_dry_run),
|
||||||
OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points,
|
OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points,
|
||||||
@@ -260,6 +285,8 @@ static const struct option options[] = {
|
|||||||
"\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
|
"\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
|
||||||
"\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
|
"\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
|
||||||
opt_set_filter),
|
opt_set_filter),
|
||||||
|
OPT_CALLBACK('x', "exec", NULL, "executable|path",
|
||||||
|
"target executable name or path", opt_set_target),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -310,6 +337,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
|||||||
pr_err(" Error: Don't use --list with --funcs.\n");
|
pr_err(" Error: Don't use --list with --funcs.\n");
|
||||||
usage_with_options(probe_usage, options);
|
usage_with_options(probe_usage, options);
|
||||||
}
|
}
|
||||||
|
if (params.uprobes) {
|
||||||
|
pr_warning(" Error: Don't use --list with --exec.\n");
|
||||||
|
usage_with_options(probe_usage, options);
|
||||||
|
}
|
||||||
ret = show_perf_probe_events();
|
ret = show_perf_probe_events();
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
pr_err(" Error: Failed to show event list. (%d)\n",
|
pr_err(" Error: Failed to show event list. (%d)\n",
|
||||||
@@ -333,8 +364,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
|||||||
if (!params.filter)
|
if (!params.filter)
|
||||||
params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
|
params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
|
||||||
NULL);
|
NULL);
|
||||||
ret = show_available_funcs(params.target,
|
ret = show_available_funcs(params.target, params.filter,
|
||||||
params.filter);
|
params.uprobes);
|
||||||
strfilter__delete(params.filter);
|
strfilter__delete(params.filter);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
pr_err(" Error: Failed to show functions."
|
pr_err(" Error: Failed to show functions."
|
||||||
@@ -343,7 +374,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
if (params.show_lines) {
|
if (params.show_lines && !params.uprobes) {
|
||||||
if (params.mod_events) {
|
if (params.mod_events) {
|
||||||
pr_err(" Error: Don't use --line with"
|
pr_err(" Error: Don't use --line with"
|
||||||
" --add/--del.\n");
|
" --add/--del.\n");
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include "trace-event.h" /* For __unused */
|
#include "trace-event.h" /* For __unused */
|
||||||
#include "probe-event.h"
|
#include "probe-event.h"
|
||||||
#include "probe-finder.h"
|
#include "probe-finder.h"
|
||||||
|
#include "session.h"
|
||||||
|
|
||||||
#define MAX_CMDLEN 256
|
#define MAX_CMDLEN 256
|
||||||
#define MAX_PROBE_ARGS 128
|
#define MAX_PROBE_ARGS 128
|
||||||
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
|
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
|
||||||
|
static int convert_name_to_addr(struct perf_probe_event *pev,
|
||||||
|
const char *exec);
|
||||||
static struct machine machine;
|
static struct machine machine;
|
||||||
|
|
||||||
/* Initialize symbol maps and path of vmlinux/modules */
|
/* Initialize symbol maps and path of vmlinux/modules */
|
||||||
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
|
|||||||
return (dso) ? dso->long_name : NULL;
|
return (dso) ? dso->long_name : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int init_user_exec(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
symbol_conf.try_vmlinux_path = false;
|
||||||
|
symbol_conf.sort_by_name = true;
|
||||||
|
ret = symbol__init();
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
pr_debug("Failed to init symbol map.\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int convert_to_perf_probe_point(struct probe_trace_point *tp,
|
||||||
|
struct perf_probe_point *pp)
|
||||||
|
{
|
||||||
|
pp->function = strdup(tp->symbol);
|
||||||
|
|
||||||
|
if (pp->function == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pp->offset = tp->offset;
|
||||||
|
pp->retprobe = tp->retprobe;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DWARF_SUPPORT
|
#ifdef DWARF_SUPPORT
|
||||||
/* Open new debuginfo of given module */
|
/* Open new debuginfo of given module */
|
||||||
static struct debuginfo *open_debuginfo(const char *module)
|
static struct debuginfo *open_debuginfo(const char *module)
|
||||||
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
|
|||||||
if (ret <= 0) {
|
if (ret <= 0) {
|
||||||
pr_debug("Failed to find corresponding probes from "
|
pr_debug("Failed to find corresponding probes from "
|
||||||
"debuginfo. Use kprobe event information.\n");
|
"debuginfo. Use kprobe event information.\n");
|
||||||
pp->function = strdup(tp->symbol);
|
return convert_to_perf_probe_point(tp, pp);
|
||||||
if (pp->function == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
pp->offset = tp->offset;
|
|
||||||
}
|
}
|
||||||
pp->retprobe = tp->retprobe;
|
pp->retprobe = tp->retprobe;
|
||||||
|
|
||||||
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
|
|||||||
int max_tevs, const char *target)
|
int max_tevs, const char *target)
|
||||||
{
|
{
|
||||||
bool need_dwarf = perf_probe_event_need_dwarf(pev);
|
bool need_dwarf = perf_probe_event_need_dwarf(pev);
|
||||||
struct debuginfo *dinfo = open_debuginfo(target);
|
struct debuginfo *dinfo;
|
||||||
int ntevs, ret = 0;
|
int ntevs, ret = 0;
|
||||||
|
|
||||||
|
if (pev->uprobes) {
|
||||||
|
if (need_dwarf) {
|
||||||
|
pr_warning("Debuginfo-analysis is not yet supported"
|
||||||
|
" with -x/--exec option.\n");
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
return convert_name_to_addr(pev, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
dinfo = open_debuginfo(target);
|
||||||
|
|
||||||
if (!dinfo) {
|
if (!dinfo) {
|
||||||
if (need_dwarf) {
|
if (need_dwarf) {
|
||||||
pr_warning("Failed to open debuginfo file.\n");
|
pr_warning("Failed to open debuginfo file.\n");
|
||||||
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
|
|||||||
pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
|
pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
pp->function = strdup(tp->symbol);
|
|
||||||
if (pp->function == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
pp->offset = tp->offset;
|
|
||||||
pp->retprobe = tp->retprobe;
|
|
||||||
|
|
||||||
return 0;
|
return convert_to_perf_probe_point(tp, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
|
static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
|
||||||
struct probe_trace_event **tevs __unused,
|
struct probe_trace_event **tevs __unused,
|
||||||
int max_tevs __unused, const char *mod __unused)
|
int max_tevs __unused, const char *target)
|
||||||
{
|
{
|
||||||
if (perf_probe_event_need_dwarf(pev)) {
|
if (perf_probe_event_need_dwarf(pev)) {
|
||||||
pr_warning("Debuginfo-analysis is not supported.\n");
|
pr_warning("Debuginfo-analysis is not supported.\n");
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pev->uprobes)
|
||||||
|
return convert_name_to_addr(pev, target);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
|
|||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
|
if (tev->uprobes)
|
||||||
tp->retprobe ? 'r' : 'p',
|
len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
|
||||||
tev->group, tev->event,
|
tp->retprobe ? 'r' : 'p',
|
||||||
tp->module ?: "", tp->module ? ":" : "",
|
tev->group, tev->event,
|
||||||
tp->symbol, tp->offset);
|
tp->module, tp->symbol);
|
||||||
|
else
|
||||||
|
len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
|
||||||
|
tp->retprobe ? 'r' : 'p',
|
||||||
|
tev->group, tev->event,
|
||||||
|
tp->module ?: "", tp->module ? ":" : "",
|
||||||
|
tp->symbol, tp->offset);
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@@ -1364,7 +1409,7 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int convert_to_perf_probe_event(struct probe_trace_event *tev,
|
static int convert_to_perf_probe_event(struct probe_trace_event *tev,
|
||||||
struct perf_probe_event *pev)
|
struct perf_probe_event *pev, bool is_kprobe)
|
||||||
{
|
{
|
||||||
char buf[64] = "";
|
char buf[64] = "";
|
||||||
int i, ret;
|
int i, ret;
|
||||||
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Convert trace_point to probe_point */
|
/* Convert trace_point to probe_point */
|
||||||
ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
|
if (is_kprobe)
|
||||||
|
ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
|
||||||
|
else
|
||||||
|
ret = convert_to_perf_probe_point(&tev->point, &pev->point);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
|
|||||||
memset(tev, 0, sizeof(*tev));
|
memset(tev, 0, sizeof(*tev));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_kprobe_events(bool readwrite)
|
static void print_warn_msg(const char *file, bool is_kprobe)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
const char *config;
|
||||||
|
|
||||||
|
if (!is_kprobe)
|
||||||
|
config = "CONFIG_UPROBE_EVENTS";
|
||||||
|
else
|
||||||
|
config = "CONFIG_KPROBE_EVENTS";
|
||||||
|
|
||||||
|
pr_warning("%s file does not exist - please rebuild kernel"
|
||||||
|
" with %s.\n", file, config);
|
||||||
|
} else
|
||||||
|
pr_warning("Failed to open %s file: %s\n", file,
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_probe_events(const char *trace_file, bool readwrite,
|
||||||
|
bool is_kprobe)
|
||||||
{
|
{
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
const char *__debugfs;
|
const char *__debugfs;
|
||||||
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
|
ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
pr_debug("Opening %s write=%d\n", buf, readwrite);
|
pr_debug("Opening %s write=%d\n", buf, readwrite);
|
||||||
if (readwrite && !probe_event_dry_run)
|
if (readwrite && !probe_event_dry_run)
|
||||||
ret = open(buf, O_RDWR, O_APPEND);
|
ret = open(buf, O_RDWR, O_APPEND);
|
||||||
else
|
else
|
||||||
ret = open(buf, O_RDONLY, 0);
|
ret = open(buf, O_RDONLY, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
if (errno == ENOENT)
|
print_warn_msg(buf, is_kprobe);
|
||||||
pr_warning("kprobe_events file does not exist - please"
|
|
||||||
" rebuild kernel with CONFIG_KPROBE_EVENT.\n");
|
|
||||||
else
|
|
||||||
pr_warning("Failed to open kprobe_events file: %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get raw string list of current kprobe_events */
|
static int open_kprobe_events(bool readwrite)
|
||||||
|
{
|
||||||
|
return open_probe_events("tracing/kprobe_events", readwrite, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_uprobe_events(bool readwrite)
|
||||||
|
{
|
||||||
|
return open_probe_events("tracing/uprobe_events", readwrite, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get raw string list of current kprobe_events or uprobe_events */
|
||||||
static struct strlist *get_probe_trace_command_rawlist(int fd)
|
static struct strlist *get_probe_trace_command_rawlist(int fd)
|
||||||
{
|
{
|
||||||
int ret, idx;
|
int ret, idx;
|
||||||
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* List up current perf-probe events */
|
static int __show_perf_probe_events(int fd, bool is_kprobe)
|
||||||
int show_perf_probe_events(void)
|
|
||||||
{
|
{
|
||||||
int fd, ret;
|
int ret = 0;
|
||||||
struct probe_trace_event tev;
|
struct probe_trace_event tev;
|
||||||
struct perf_probe_event pev;
|
struct perf_probe_event pev;
|
||||||
struct strlist *rawlist;
|
struct strlist *rawlist;
|
||||||
struct str_node *ent;
|
struct str_node *ent;
|
||||||
|
|
||||||
setup_pager();
|
|
||||||
ret = init_vmlinux();
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
memset(&tev, 0, sizeof(tev));
|
memset(&tev, 0, sizeof(tev));
|
||||||
memset(&pev, 0, sizeof(pev));
|
memset(&pev, 0, sizeof(pev));
|
||||||
|
|
||||||
fd = open_kprobe_events(false);
|
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
rawlist = get_probe_trace_command_rawlist(fd);
|
rawlist = get_probe_trace_command_rawlist(fd);
|
||||||
close(fd);
|
|
||||||
if (!rawlist)
|
if (!rawlist)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
strlist__for_each(ent, rawlist) {
|
strlist__for_each(ent, rawlist) {
|
||||||
ret = parse_probe_trace_command(ent->s, &tev);
|
ret = parse_probe_trace_command(ent->s, &tev);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
ret = convert_to_perf_probe_event(&tev, &pev);
|
ret = convert_to_perf_probe_event(&tev, &pev,
|
||||||
|
is_kprobe);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
ret = show_perf_probe_event(&pev);
|
ret = show_perf_probe_event(&pev);
|
||||||
}
|
}
|
||||||
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* List up current perf-probe events */
|
||||||
|
int show_perf_probe_events(void)
|
||||||
|
{
|
||||||
|
int fd, ret;
|
||||||
|
|
||||||
|
setup_pager();
|
||||||
|
fd = open_kprobe_events(false);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return fd;
|
||||||
|
|
||||||
|
ret = init_vmlinux();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = __show_perf_probe_events(fd, true);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fd = open_uprobe_events(false);
|
||||||
|
if (fd >= 0) {
|
||||||
|
ret = __show_perf_probe_events(fd, false);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get current perf-probe event names */
|
/* Get current perf-probe event names */
|
||||||
static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
|
static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
|
||||||
{
|
{
|
||||||
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
|
|||||||
const char *event, *group;
|
const char *event, *group;
|
||||||
struct strlist *namelist;
|
struct strlist *namelist;
|
||||||
|
|
||||||
fd = open_kprobe_events(true);
|
if (pev->uprobes)
|
||||||
|
fd = open_uprobe_events(true);
|
||||||
|
else
|
||||||
|
fd = open_kprobe_events(true);
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
/* Get current event names */
|
/* Get current event names */
|
||||||
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
|
|||||||
tev->point.offset = pev->point.offset;
|
tev->point.offset = pev->point.offset;
|
||||||
tev->point.retprobe = pev->point.retprobe;
|
tev->point.retprobe = pev->point.retprobe;
|
||||||
tev->nargs = pev->nargs;
|
tev->nargs = pev->nargs;
|
||||||
|
tev->uprobes = pev->uprobes;
|
||||||
|
|
||||||
if (tev->nargs) {
|
if (tev->nargs) {
|
||||||
tev->args = zalloc(sizeof(struct probe_trace_arg)
|
tev->args = zalloc(sizeof(struct probe_trace_arg)
|
||||||
* tev->nargs);
|
* tev->nargs);
|
||||||
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pev->uprobes)
|
||||||
|
return 1;
|
||||||
|
|
||||||
/* Currently just checking function name from symbol map */
|
/* Currently just checking function name from symbol map */
|
||||||
sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
|
sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
|
|||||||
int i, j, ret;
|
int i, j, ret;
|
||||||
struct __event_package *pkgs;
|
struct __event_package *pkgs;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
pkgs = zalloc(sizeof(struct __event_package) * npevs);
|
pkgs = zalloc(sizeof(struct __event_package) * npevs);
|
||||||
|
|
||||||
if (pkgs == NULL)
|
if (pkgs == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/* Init vmlinux path */
|
if (!pevs->uprobes)
|
||||||
ret = init_vmlinux();
|
/* Init vmlinux path */
|
||||||
|
ret = init_vmlinux();
|
||||||
|
else
|
||||||
|
ret = init_user_exec();
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
free(pkgs);
|
free(pkgs);
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1971,23 +2075,15 @@ error:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int del_trace_probe_event(int fd, const char *group,
|
static int del_trace_probe_event(int fd, const char *buf,
|
||||||
const char *event, struct strlist *namelist)
|
struct strlist *namelist)
|
||||||
{
|
{
|
||||||
char buf[128];
|
|
||||||
struct str_node *ent, *n;
|
struct str_node *ent, *n;
|
||||||
int found = 0, ret = 0;
|
int ret = -1;
|
||||||
|
|
||||||
ret = e_snprintf(buf, 128, "%s:%s", group, event);
|
|
||||||
if (ret < 0) {
|
|
||||||
pr_err("Failed to copy event.\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpbrk(buf, "*?")) { /* Glob-exp */
|
if (strpbrk(buf, "*?")) { /* Glob-exp */
|
||||||
strlist__for_each_safe(ent, n, namelist)
|
strlist__for_each_safe(ent, n, namelist)
|
||||||
if (strglobmatch(ent->s, buf)) {
|
if (strglobmatch(ent->s, buf)) {
|
||||||
found++;
|
|
||||||
ret = __del_trace_probe_event(fd, ent);
|
ret = __del_trace_probe_event(fd, ent);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
break;
|
break;
|
||||||
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,
|
|||||||
} else {
|
} else {
|
||||||
ent = strlist__find(namelist, buf);
|
ent = strlist__find(namelist, buf);
|
||||||
if (ent) {
|
if (ent) {
|
||||||
found++;
|
|
||||||
ret = __del_trace_probe_event(fd, ent);
|
ret = __del_trace_probe_event(fd, ent);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
strlist__remove(namelist, ent);
|
strlist__remove(namelist, ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found == 0 && ret >= 0)
|
|
||||||
pr_info("Info: Event \"%s\" does not exist.\n", buf);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int del_perf_probe_events(struct strlist *dellist)
|
int del_perf_probe_events(struct strlist *dellist)
|
||||||
{
|
{
|
||||||
int fd, ret = 0;
|
int ret = -1, ufd = -1, kfd = -1;
|
||||||
|
char buf[128];
|
||||||
const char *group, *event;
|
const char *group, *event;
|
||||||
char *p, *str;
|
char *p, *str;
|
||||||
struct str_node *ent;
|
struct str_node *ent;
|
||||||
struct strlist *namelist;
|
struct strlist *namelist = NULL, *unamelist = NULL;
|
||||||
|
|
||||||
fd = open_kprobe_events(true);
|
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
/* Get current event names */
|
/* Get current event names */
|
||||||
namelist = get_probe_trace_event_names(fd, true);
|
kfd = open_kprobe_events(true);
|
||||||
if (namelist == NULL)
|
if (kfd < 0)
|
||||||
return -EINVAL;
|
return kfd;
|
||||||
|
|
||||||
|
namelist = get_probe_trace_event_names(kfd, true);
|
||||||
|
ufd = open_uprobe_events(true);
|
||||||
|
|
||||||
|
if (ufd >= 0)
|
||||||
|
unamelist = get_probe_trace_event_names(ufd, true);
|
||||||
|
|
||||||
|
if (namelist == NULL && unamelist == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
strlist__for_each(ent, dellist) {
|
strlist__for_each(ent, dellist) {
|
||||||
str = strdup(ent->s);
|
str = strdup(ent->s);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
break;
|
goto error;
|
||||||
}
|
}
|
||||||
pr_debug("Parsing: %s\n", str);
|
pr_debug("Parsing: %s\n", str);
|
||||||
p = strchr(str, ':');
|
p = strchr(str, ':');
|
||||||
@@ -2041,17 +2140,46 @@ int del_perf_probe_events(struct strlist *dellist)
|
|||||||
group = "*";
|
group = "*";
|
||||||
event = str;
|
event = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = e_snprintf(buf, 128, "%s:%s", group, event);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_err("Failed to copy event.");
|
||||||
|
free(str);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
pr_debug("Group: %s, Event: %s\n", group, event);
|
pr_debug("Group: %s, Event: %s\n", group, event);
|
||||||
ret = del_trace_probe_event(fd, group, event, namelist);
|
|
||||||
|
if (namelist)
|
||||||
|
ret = del_trace_probe_event(kfd, buf, namelist);
|
||||||
|
|
||||||
|
if (unamelist && ret != 0)
|
||||||
|
ret = del_trace_probe_event(ufd, buf, unamelist);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
pr_info("Info: Event \"%s\" does not exist.\n", buf);
|
||||||
|
|
||||||
free(str);
|
free(str);
|
||||||
if (ret < 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
strlist__delete(namelist);
|
|
||||||
close(fd);
|
error:
|
||||||
|
if (kfd >= 0) {
|
||||||
|
if (namelist)
|
||||||
|
strlist__delete(namelist);
|
||||||
|
|
||||||
|
close(kfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ufd >= 0) {
|
||||||
|
if (unamelist)
|
||||||
|
strlist__delete(unamelist);
|
||||||
|
|
||||||
|
close(ufd);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: don't use a global variable for filter ... */
|
/* TODO: don't use a global variable for filter ... */
|
||||||
static struct strfilter *available_func_filter;
|
static struct strfilter *available_func_filter;
|
||||||
|
|
||||||
@@ -2068,23 +2196,8 @@ static int filter_available_functions(struct map *map __unused,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int show_available_funcs(const char *target, struct strfilter *_filter)
|
static int __show_available_funcs(struct map *map)
|
||||||
{
|
{
|
||||||
struct map *map;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
setup_pager();
|
|
||||||
|
|
||||||
ret = init_vmlinux();
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
map = kernel_get_module_map(target);
|
|
||||||
if (!map) {
|
|
||||||
pr_err("Failed to find %s map.\n", (target) ? : "kernel");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
available_func_filter = _filter;
|
|
||||||
if (map__load(map, filter_available_functions)) {
|
if (map__load(map, filter_available_functions)) {
|
||||||
pr_err("Failed to load map.\n");
|
pr_err("Failed to load map.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -2095,3 +2208,140 @@ int show_available_funcs(const char *target, struct strfilter *_filter)
|
|||||||
dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
|
dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int available_kernel_funcs(const char *module)
|
||||||
|
{
|
||||||
|
struct map *map;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = init_vmlinux();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
map = kernel_get_module_map(module);
|
||||||
|
if (!map) {
|
||||||
|
pr_err("Failed to find %s map.\n", (module) ? : "kernel");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __show_available_funcs(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int available_user_funcs(const char *target)
|
||||||
|
{
|
||||||
|
struct map *map;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = init_user_exec();
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
map = dso__new_map(target);
|
||||||
|
ret = __show_available_funcs(map);
|
||||||
|
dso__delete(map->dso);
|
||||||
|
map__delete(map);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int show_available_funcs(const char *target, struct strfilter *_filter,
|
||||||
|
bool user)
|
||||||
|
{
|
||||||
|
setup_pager();
|
||||||
|
available_func_filter = _filter;
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
return available_kernel_funcs(target);
|
||||||
|
|
||||||
|
return available_user_funcs(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* uprobe_events only accepts address:
|
||||||
|
* Convert function and any offset to address
|
||||||
|
*/
|
||||||
|
static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
|
||||||
|
{
|
||||||
|
struct perf_probe_point *pp = &pev->point;
|
||||||
|
struct symbol *sym;
|
||||||
|
struct map *map = NULL;
|
||||||
|
char *function = NULL, *name = NULL;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
unsigned long long vaddr = 0;
|
||||||
|
|
||||||
|
if (!pp->function) {
|
||||||
|
pr_warning("No function specified for uprobes");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function = strdup(pp->function);
|
||||||
|
if (!function) {
|
||||||
|
pr_warning("Failed to allocate memory by strdup.\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = realpath(exec, NULL);
|
||||||
|
if (!name) {
|
||||||
|
pr_warning("Cannot find realpath for %s.\n", exec);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
map = dso__new_map(name);
|
||||||
|
if (!map) {
|
||||||
|
pr_warning("Cannot find appropriate DSO for %s.\n", exec);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
available_func_filter = strfilter__new(function, NULL);
|
||||||
|
if (map__load(map, filter_available_functions)) {
|
||||||
|
pr_err("Failed to load map.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
sym = map__find_symbol_by_name(map, function, NULL);
|
||||||
|
if (!sym) {
|
||||||
|
pr_warning("Cannot find %s in DSO %s\n", function, exec);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map->start > sym->start)
|
||||||
|
vaddr = map->start;
|
||||||
|
vaddr += sym->start + pp->offset + map->pgoff;
|
||||||
|
pp->offset = 0;
|
||||||
|
|
||||||
|
if (!pev->event) {
|
||||||
|
pev->event = function;
|
||||||
|
function = NULL;
|
||||||
|
}
|
||||||
|
if (!pev->group) {
|
||||||
|
char *ptr1, *ptr2;
|
||||||
|
|
||||||
|
pev->group = zalloc(sizeof(char *) * 64);
|
||||||
|
ptr1 = strdup(basename(exec));
|
||||||
|
if (ptr1) {
|
||||||
|
ptr2 = strpbrk(ptr1, "-._");
|
||||||
|
if (ptr2)
|
||||||
|
*ptr2 = '\0';
|
||||||
|
e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
|
||||||
|
ptr1);
|
||||||
|
free(ptr1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(pp->function);
|
||||||
|
pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
|
||||||
|
if (!pp->function) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
pr_warning("Failed to allocate memory by zalloc.\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (map) {
|
||||||
|
dso__delete(map->dso);
|
||||||
|
map__delete(map);
|
||||||
|
}
|
||||||
|
if (function)
|
||||||
|
free(function);
|
||||||
|
if (name)
|
||||||
|
free(name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
extern bool probe_event_dry_run;
|
extern bool probe_event_dry_run;
|
||||||
|
|
||||||
/* kprobe-tracer tracing point */
|
/* kprobe-tracer and uprobe-tracer tracing point */
|
||||||
struct probe_trace_point {
|
struct probe_trace_point {
|
||||||
char *symbol; /* Base symbol */
|
char *symbol; /* Base symbol */
|
||||||
char *module; /* Module name */
|
char *module; /* Module name */
|
||||||
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
|
|||||||
long offset; /* Offset value */
|
long offset; /* Offset value */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* kprobe-tracer tracing argument */
|
/* kprobe-tracer and uprobe-tracer tracing argument */
|
||||||
struct probe_trace_arg {
|
struct probe_trace_arg {
|
||||||
char *name; /* Argument name */
|
char *name; /* Argument name */
|
||||||
char *value; /* Base value */
|
char *value; /* Base value */
|
||||||
@@ -29,12 +29,13 @@ struct probe_trace_arg {
|
|||||||
struct probe_trace_arg_ref *ref; /* Referencing offset */
|
struct probe_trace_arg_ref *ref; /* Referencing offset */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* kprobe-tracer tracing event (point + arg) */
|
/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
|
||||||
struct probe_trace_event {
|
struct probe_trace_event {
|
||||||
char *event; /* Event name */
|
char *event; /* Event name */
|
||||||
char *group; /* Group name */
|
char *group; /* Group name */
|
||||||
struct probe_trace_point point; /* Trace point */
|
struct probe_trace_point point; /* Trace point */
|
||||||
int nargs; /* Number of args */
|
int nargs; /* Number of args */
|
||||||
|
bool uprobes; /* uprobes only */
|
||||||
struct probe_trace_arg *args; /* Arguments */
|
struct probe_trace_arg *args; /* Arguments */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,6 +71,7 @@ struct perf_probe_event {
|
|||||||
char *group; /* Group name */
|
char *group; /* Group name */
|
||||||
struct perf_probe_point point; /* Probe point */
|
struct perf_probe_point point; /* Probe point */
|
||||||
int nargs; /* Number of arguments */
|
int nargs; /* Number of arguments */
|
||||||
|
bool uprobes;
|
||||||
struct perf_probe_arg *args; /* Arguments */
|
struct perf_probe_arg *args; /* Arguments */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
|
|||||||
extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
|
extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
|
||||||
int max_probe_points, const char *module,
|
int max_probe_points, const char *module,
|
||||||
struct strfilter *filter, bool externs);
|
struct strfilter *filter, bool externs);
|
||||||
extern int show_available_funcs(const char *module, struct strfilter *filter);
|
extern int show_available_funcs(const char *module, struct strfilter *filter,
|
||||||
|
bool user);
|
||||||
|
|
||||||
/* Maximum index number of event-name postfix */
|
/* Maximum index number of event-name postfix */
|
||||||
#define MAX_EVENT_INDEX 1024
|
#define MAX_EVENT_INDEX 1024
|
||||||
|
@@ -2784,3 +2784,11 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct map *dso__new_map(const char *name)
|
||||||
|
{
|
||||||
|
struct dso *dso = dso__new(name);
|
||||||
|
struct map *map = map__new2(0, dso, MAP__FUNCTION);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
@@ -242,6 +242,7 @@ void dso__set_long_name(struct dso *dso, char *name);
|
|||||||
void dso__set_build_id(struct dso *dso, void *build_id);
|
void dso__set_build_id(struct dso *dso, void *build_id);
|
||||||
void dso__read_running_kernel_build_id(struct dso *dso,
|
void dso__read_running_kernel_build_id(struct dso *dso,
|
||||||
struct machine *machine);
|
struct machine *machine);
|
||||||
|
struct map *dso__new_map(const char *name);
|
||||||
struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
|
struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
|
||||||
u64 addr);
|
u64 addr);
|
||||||
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
|
struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
|
||||||
|
Reference in New Issue
Block a user