Merge branch 'perf' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
This commit is contained in:
commit
bc4b473f1a
23 changed files with 726 additions and 352 deletions
22
tools/perf/Documentation/perf-test.txt
Normal file
22
tools/perf/Documentation/perf-test.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
perf-test(1)
|
||||
============
|
||||
|
||||
NAME
|
||||
----
|
||||
perf-test - Runs sanity tests.
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf test <options>'
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
This command does assorted sanity tests, initially thru linked routines but
|
||||
also will look for a directory with more tests in the form of scripts.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
-v::
|
||||
--verbose::
|
||||
Be more verbose.
|
|
@ -187,6 +187,8 @@ ifeq ($(ARCH),x86_64)
|
|||
ARCH := x86
|
||||
endif
|
||||
|
||||
$(shell sh -c 'mkdir -p $(OUTPUT)arch/$(ARCH)/util/' 2> /dev/null)
|
||||
|
||||
# CFLAGS and LDFLAGS are for the users to override from the command line.
|
||||
|
||||
#
|
||||
|
@ -488,6 +490,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
|
|||
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-test.o
|
||||
|
||||
PERFLIBS = $(LIB_FILE)
|
||||
|
||||
|
|
|
@ -571,7 +571,7 @@ static int __cmd_annotate(void)
|
|||
perf_session__fprintf(session, stdout);
|
||||
|
||||
if (verbose > 2)
|
||||
dsos__fprintf(&session->kerninfo_root, stdout);
|
||||
perf_session__fprintf_dsos(session, stdout);
|
||||
|
||||
perf_session__collapse_resort(&session->hists);
|
||||
perf_session__output_resort(&session->hists, session->event_total[0]);
|
||||
|
|
|
@ -46,7 +46,7 @@ static int __cmd_buildid_list(void)
|
|||
if (with_hits)
|
||||
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
|
||||
|
||||
dsos__fprintf_buildid(&session->kerninfo_root, stdout, with_hits);
|
||||
perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
|
||||
|
||||
perf_session__delete(session);
|
||||
return err;
|
||||
|
|
|
@ -352,7 +352,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
|
|||
int n_lines, int is_caller)
|
||||
{
|
||||
struct rb_node *next;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
|
||||
printf("%.102s\n", graph_dotted_line);
|
||||
printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
|
||||
|
@ -361,8 +361,8 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
|
|||
|
||||
next = rb_first(root);
|
||||
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
if (!kerninfo) {
|
||||
machine = perf_session__find_host_machine(session);
|
||||
if (!machine) {
|
||||
pr_err("__print_result: couldn't find kernel information\n");
|
||||
return;
|
||||
}
|
||||
|
@ -370,7 +370,6 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
|
|||
struct alloc_stat *data = rb_entry(next, struct alloc_stat,
|
||||
node);
|
||||
struct symbol *sym = NULL;
|
||||
struct map_groups *kmaps = &kerninfo->kmaps;
|
||||
struct map *map;
|
||||
char buf[BUFSIZ];
|
||||
u64 addr;
|
||||
|
@ -378,8 +377,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
|
|||
if (is_caller) {
|
||||
addr = data->call_site;
|
||||
if (!raw_ip)
|
||||
sym = map_groups__find_function(kmaps, addr,
|
||||
&map, NULL);
|
||||
sym = machine__find_kernel_function(machine, addr, &map, NULL);
|
||||
} else
|
||||
addr = data->ptr;
|
||||
|
||||
|
|
|
@ -456,14 +456,14 @@ static void atexit_header(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void event__synthesize_guest_os(struct kernel_info *kerninfo,
|
||||
void *data __attribute__((unused)))
|
||||
static void event__synthesize_guest_os(struct machine *machine, void *data)
|
||||
{
|
||||
int err;
|
||||
char *guest_kallsyms;
|
||||
char path[PATH_MAX];
|
||||
struct perf_session *psession = data;
|
||||
|
||||
if (is_host_kernel(kerninfo))
|
||||
if (machine__is_host(machine))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -475,16 +475,15 @@ static void event__synthesize_guest_os(struct kernel_info *kerninfo,
|
|||
*in module instead of in guest kernel.
|
||||
*/
|
||||
err = event__synthesize_modules(process_synthesized_event,
|
||||
session,
|
||||
kerninfo);
|
||||
psession, machine);
|
||||
if (err < 0)
|
||||
pr_err("Couldn't record guest kernel [%d]'s reference"
|
||||
" relocation symbol.\n", kerninfo->pid);
|
||||
" relocation symbol.\n", machine->pid);
|
||||
|
||||
if (is_default_guest(kerninfo))
|
||||
if (machine__is_default_guest(machine))
|
||||
guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms;
|
||||
else {
|
||||
sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
|
||||
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
|
||||
guest_kallsyms = path;
|
||||
}
|
||||
|
||||
|
@ -493,13 +492,13 @@ static void event__synthesize_guest_os(struct kernel_info *kerninfo,
|
|||
* have no _text sometimes.
|
||||
*/
|
||||
err = event__synthesize_kernel_mmap(process_synthesized_event,
|
||||
session, kerninfo, "_text");
|
||||
psession, machine, "_text");
|
||||
if (err < 0)
|
||||
err = event__synthesize_kernel_mmap(process_synthesized_event,
|
||||
session, kerninfo, "_stext");
|
||||
psession, machine, "_stext");
|
||||
if (err < 0)
|
||||
pr_err("Couldn't record guest kernel [%d]'s reference"
|
||||
" relocation symbol.\n", kerninfo->pid);
|
||||
" relocation symbol.\n", machine->pid);
|
||||
}
|
||||
|
||||
static int __cmd_record(int argc, const char **argv)
|
||||
|
@ -513,7 +512,7 @@ static int __cmd_record(int argc, const char **argv)
|
|||
int child_ready_pipe[2], go_pipe[2];
|
||||
const bool forks = argc > 0;
|
||||
char buf;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
|
@ -682,31 +681,30 @@ static int __cmd_record(int argc, const char **argv)
|
|||
advance_output(err);
|
||||
}
|
||||
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
if (!kerninfo) {
|
||||
machine = perf_session__find_host_machine(session);
|
||||
if (!machine) {
|
||||
pr_err("Couldn't find native kernel information.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = event__synthesize_kernel_mmap(process_synthesized_event,
|
||||
session, kerninfo, "_text");
|
||||
session, machine, "_text");
|
||||
if (err < 0)
|
||||
err = event__synthesize_kernel_mmap(process_synthesized_event,
|
||||
session, kerninfo, "_stext");
|
||||
session, machine, "_stext");
|
||||
if (err < 0) {
|
||||
pr_err("Couldn't record kernel reference relocation symbol.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = event__synthesize_modules(process_synthesized_event,
|
||||
session, kerninfo);
|
||||
session, machine);
|
||||
if (err < 0) {
|
||||
pr_err("Couldn't record kernel reference relocation symbol.\n");
|
||||
return err;
|
||||
}
|
||||
if (perf_guest)
|
||||
kerninfo__process_allkernels(&session->kerninfo_root,
|
||||
event__synthesize_guest_os, session);
|
||||
perf_session__process_machines(session, event__synthesize_guest_os);
|
||||
|
||||
if (!system_wide && profile_cpu == -1)
|
||||
event__synthesize_thread(target_tid, process_synthesized_event,
|
||||
|
|
|
@ -313,7 +313,7 @@ static int __cmd_report(void)
|
|||
perf_session__fprintf(session, stdout);
|
||||
|
||||
if (verbose > 2)
|
||||
dsos__fprintf(&session->kerninfo_root, stdout);
|
||||
perf_session__fprintf_dsos(session, stdout);
|
||||
|
||||
next = rb_first(&session->stats_by_id);
|
||||
while (next) {
|
||||
|
|
281
tools/perf/builtin-test.c
Normal file
281
tools/perf/builtin-test.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* builtin-test.c
|
||||
*
|
||||
* Builtin regression testing command: ever growing number of sanity tests
|
||||
*/
|
||||
#include "builtin.h"
|
||||
|
||||
#include "util/cache.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/session.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/thread.h"
|
||||
|
||||
static long page_size;
|
||||
|
||||
static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
|
||||
{
|
||||
bool *visited = symbol__priv(sym);
|
||||
*visited = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test__vmlinux_matches_kallsyms(void)
|
||||
{
|
||||
int err = -1;
|
||||
struct rb_node *nd;
|
||||
struct symbol *sym;
|
||||
struct map *kallsyms_map, *vmlinux_map;
|
||||
struct machine kallsyms, vmlinux;
|
||||
enum map_type type = MAP__FUNCTION;
|
||||
struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
|
||||
|
||||
/*
|
||||
* Step 1:
|
||||
*
|
||||
* Init the machines that will hold kernel, modules obtained from
|
||||
* both vmlinux + .ko files and from /proc/kallsyms split by modules.
|
||||
*/
|
||||
machine__init(&kallsyms, "", HOST_KERNEL_ID);
|
||||
machine__init(&vmlinux, "", HOST_KERNEL_ID);
|
||||
|
||||
/*
|
||||
* Step 2:
|
||||
*
|
||||
* Create the kernel maps for kallsyms and the DSO where we will then
|
||||
* load /proc/kallsyms. Also create the modules maps from /proc/modules
|
||||
* and find the .ko files that match them in /lib/modules/`uname -r`/.
|
||||
*/
|
||||
if (machine__create_kernel_maps(&kallsyms) < 0) {
|
||||
pr_debug("machine__create_kernel_maps ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 3:
|
||||
*
|
||||
* Load and split /proc/kallsyms into multiple maps, one per module.
|
||||
*/
|
||||
if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
|
||||
pr_debug("dso__load_kallsyms ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Step 4:
|
||||
*
|
||||
* kallsyms will be internally on demand sorted by name so that we can
|
||||
* find the reference relocation * symbol, i.e. the symbol we will use
|
||||
* to see if the running kernel was relocated by checking if it has the
|
||||
* same value in the vmlinux file we load.
|
||||
*/
|
||||
kallsyms_map = machine__kernel_map(&kallsyms, type);
|
||||
|
||||
sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
|
||||
if (sym == NULL) {
|
||||
pr_debug("dso__find_symbol_by_name ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ref_reloc_sym.addr = sym->start;
|
||||
|
||||
/*
|
||||
* Step 5:
|
||||
*
|
||||
* Now repeat step 2, this time for the vmlinux file we'll auto-locate.
|
||||
*/
|
||||
if (machine__create_kernel_maps(&vmlinux) < 0) {
|
||||
pr_debug("machine__create_kernel_maps ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
vmlinux_map = machine__kernel_map(&vmlinux, type);
|
||||
map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
|
||||
|
||||
/*
|
||||
* Step 6:
|
||||
*
|
||||
* Locate a vmlinux file in the vmlinux path that has a buildid that
|
||||
* matches the one of the running kernel.
|
||||
*
|
||||
* While doing that look if we find the ref reloc symbol, if we find it
|
||||
* we'll have its ref_reloc_symbol.unrelocated_addr and then
|
||||
* maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
|
||||
* to fixup the symbols.
|
||||
*/
|
||||
if (machine__load_vmlinux_path(&vmlinux, type,
|
||||
vmlinux_matches_kallsyms_filter) <= 0) {
|
||||
pr_debug("machine__load_vmlinux_path ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = 0;
|
||||
/*
|
||||
* Step 7:
|
||||
*
|
||||
* Now look at the symbols in the vmlinux DSO and check if we find all of them
|
||||
* in the kallsyms dso. For the ones that are in both, check its names and
|
||||
* end addresses too.
|
||||
*/
|
||||
for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
|
||||
struct symbol *pair;
|
||||
|
||||
sym = rb_entry(nd, struct symbol, rb_node);
|
||||
pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
|
||||
|
||||
if (pair && pair->start == sym->start) {
|
||||
next_pair:
|
||||
if (strcmp(sym->name, pair->name) == 0) {
|
||||
/*
|
||||
* kallsyms don't have the symbol end, so we
|
||||
* set that by using the next symbol start - 1,
|
||||
* in some cases we get this up to a page
|
||||
* wrong, trace_kmalloc when I was developing
|
||||
* this code was one such example, 2106 bytes
|
||||
* off the real size. More than that and we
|
||||
* _really_ have a problem.
|
||||
*/
|
||||
s64 skew = sym->end - pair->end;
|
||||
if (llabs(skew) < page_size)
|
||||
continue;
|
||||
|
||||
pr_debug("%#Lx: diff end addr for %s v: %#Lx k: %#Lx\n",
|
||||
sym->start, sym->name, sym->end, pair->end);
|
||||
} else {
|
||||
struct rb_node *nnd = rb_prev(&pair->rb_node);
|
||||
|
||||
if (nnd) {
|
||||
struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
|
||||
|
||||
if (next->start == sym->start) {
|
||||
pair = next;
|
||||
goto next_pair;
|
||||
}
|
||||
}
|
||||
pr_debug("%#Lx: diff name v: %s k: %s\n",
|
||||
sym->start, sym->name, pair->name);
|
||||
}
|
||||
} else
|
||||
pr_debug("%#Lx: %s not on kallsyms\n", sym->start, sym->name);
|
||||
|
||||
err = -1;
|
||||
}
|
||||
|
||||
if (!verbose)
|
||||
goto out;
|
||||
|
||||
pr_info("Maps only in vmlinux:\n");
|
||||
|
||||
for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
|
||||
struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
|
||||
/*
|
||||
* If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
|
||||
* the kernel will have the path for the vmlinux file being used,
|
||||
* so use the short name, less descriptive but the same ("[kernel]" in
|
||||
* both cases.
|
||||
*/
|
||||
pair = map_groups__find_by_name(&kallsyms.kmaps, type,
|
||||
(pos->dso->kernel ?
|
||||
pos->dso->short_name :
|
||||
pos->dso->name));
|
||||
if (pair)
|
||||
pair->priv = 1;
|
||||
else
|
||||
map__fprintf(pos, stderr);
|
||||
}
|
||||
|
||||
pr_info("Maps in vmlinux with a different name in kallsyms:\n");
|
||||
|
||||
for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
|
||||
struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
|
||||
|
||||
pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
|
||||
if (pair == NULL || pair->priv)
|
||||
continue;
|
||||
|
||||
if (pair->start == pos->start) {
|
||||
pair->priv = 1;
|
||||
pr_info(" %Lx-%Lx %Lx %s in kallsyms as",
|
||||
pos->start, pos->end, pos->pgoff, pos->dso->name);
|
||||
if (pos->pgoff != pair->pgoff || pos->end != pair->end)
|
||||
pr_info(": \n*%Lx-%Lx %Lx",
|
||||
pair->start, pair->end, pair->pgoff);
|
||||
pr_info(" %s\n", pair->dso->name);
|
||||
pair->priv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("Maps only in kallsyms:\n");
|
||||
|
||||
for (nd = rb_first(&kallsyms.kmaps.maps[type]);
|
||||
nd; nd = rb_next(nd)) {
|
||||
struct map *pos = rb_entry(nd, struct map, rb_node);
|
||||
|
||||
if (!pos->priv)
|
||||
map__fprintf(pos, stderr);
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct test {
|
||||
const char *desc;
|
||||
int (*func)(void);
|
||||
} tests[] = {
|
||||
{
|
||||
.desc = "vmlinux symtab matches kallsyms",
|
||||
.func = test__vmlinux_matches_kallsyms,
|
||||
},
|
||||
{
|
||||
.func = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
static int __cmd_test(void)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
while (tests[i].func) {
|
||||
int err;
|
||||
pr_info("%2d: %s:", i + 1, tests[i].desc);
|
||||
pr_debug("\n--- start ---\n");
|
||||
err = tests[i].func();
|
||||
pr_debug("---- end ----\n%s:", tests[i].desc);
|
||||
pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
|
||||
++i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const test_usage[] = {
|
||||
"perf test [<options>]",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct option test_options[] = {
|
||||
OPT_BOOLEAN('v', "verbose", &verbose,
|
||||
"be more verbose (show symbol address, etc)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
int cmd_test(int argc, const char **argv, const char *prefix __used)
|
||||
{
|
||||
argc = parse_options(argc, argv, test_options, test_usage, 0);
|
||||
if (argc)
|
||||
usage_with_options(test_usage, test_options);
|
||||
|
||||
symbol_conf.priv_size = sizeof(int);
|
||||
symbol_conf.sort_by_name = true;
|
||||
symbol_conf.try_vmlinux_path = true;
|
||||
|
||||
if (symbol__init() < 0)
|
||||
return -1;
|
||||
|
||||
setup_pager();
|
||||
|
||||
return __cmd_test();
|
||||
}
|
|
@ -854,7 +854,7 @@ static void handle_keypress(struct perf_session *session, int c)
|
|||
case 'Q':
|
||||
printf("exiting.\n");
|
||||
if (dump_symtab)
|
||||
dsos__fprintf(&session->kerninfo_root, stderr);
|
||||
perf_session__fprintf_dsos(session, stderr);
|
||||
exit(0);
|
||||
case 's':
|
||||
prompt_symbol(&sym_filter_entry, "Enter details symbol");
|
||||
|
@ -982,7 +982,7 @@ static void event__process_sample(const event_t *self,
|
|||
u64 ip = self->ip.ip;
|
||||
struct sym_entry *syme;
|
||||
struct addr_location al;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
||||
++samples;
|
||||
|
@ -992,18 +992,17 @@ static void event__process_sample(const event_t *self,
|
|||
++us_samples;
|
||||
if (hide_user_symbols)
|
||||
return;
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
machine = perf_session__find_host_machine(session);
|
||||
break;
|
||||
case PERF_RECORD_MISC_KERNEL:
|
||||
++kernel_samples;
|
||||
if (hide_kernel_symbols)
|
||||
return;
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
machine = perf_session__find_host_machine(session);
|
||||
break;
|
||||
case PERF_RECORD_MISC_GUEST_KERNEL:
|
||||
++guest_kernel_samples;
|
||||
kerninfo = kerninfo__find(&session->kerninfo_root,
|
||||
self->ip.pid);
|
||||
machine = perf_session__find_machine(session, self->ip.pid);
|
||||
break;
|
||||
case PERF_RECORD_MISC_GUEST_USER:
|
||||
++guest_us_samples;
|
||||
|
@ -1016,7 +1015,7 @@ static void event__process_sample(const event_t *self,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!kerninfo && perf_guest) {
|
||||
if (!machine && perf_guest) {
|
||||
pr_err("Can't find guest [%d]'s kernel information\n",
|
||||
self->ip.pid);
|
||||
return;
|
||||
|
@ -1041,7 +1040,7 @@ static void event__process_sample(const event_t *self,
|
|||
* --hide-kernel-symbols, even if the user specifies an
|
||||
* invalid --vmlinux ;-)
|
||||
*/
|
||||
if (al.map == kerninfo->vmlinux_maps[MAP__FUNCTION] &&
|
||||
if (al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
|
||||
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
|
||||
pr_err("The %s file can't be used\n",
|
||||
symbol_conf.vmlinux_name);
|
||||
|
|
|
@ -33,5 +33,6 @@ extern int cmd_probe(int argc, const char **argv, const char *prefix);
|
|||
extern int cmd_kmem(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_lock(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_kvm(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_test(int argc, const char **argv, const char *prefix);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,3 +20,4 @@ perf-probe mainporcelain common
|
|||
perf-kmem mainporcelain common
|
||||
perf-lock mainporcelain common
|
||||
perf-kvm mainporcelain common
|
||||
perf-test mainporcelain common
|
||||
|
|
|
@ -308,6 +308,7 @@ static void handle_internal_command(int argc, const char **argv)
|
|||
{ "kmem", cmd_kmem, 0 },
|
||||
{ "lock", cmd_lock, 0 },
|
||||
{ "kvm", cmd_kvm, 0 },
|
||||
{ "test", cmd_test, 0 },
|
||||
};
|
||||
unsigned int i;
|
||||
static const char ext[] = STRIP_EXTENSION;
|
||||
|
|
|
@ -172,17 +172,17 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
|
|||
|
||||
int event__synthesize_modules(event__handler_t process,
|
||||
struct perf_session *session,
|
||||
struct kernel_info *kerninfo)
|
||||
struct machine *machine)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
struct map_groups *kmaps = &kerninfo->kmaps;
|
||||
struct map_groups *kmaps = &machine->kmaps;
|
||||
u16 misc;
|
||||
|
||||
/*
|
||||
* kernel uses 0 for user space maps, see kernel/perf_event.c
|
||||
* __perf_event_mmap
|
||||
*/
|
||||
if (is_host_kernel(kerninfo))
|
||||
if (machine__is_host(machine))
|
||||
misc = PERF_RECORD_MISC_KERNEL;
|
||||
else
|
||||
misc = PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
|
@ -204,7 +204,7 @@ int event__synthesize_modules(event__handler_t process,
|
|||
(sizeof(ev.mmap.filename) - size));
|
||||
ev.mmap.start = pos->start;
|
||||
ev.mmap.len = pos->end - pos->start;
|
||||
ev.mmap.pid = kerninfo->pid;
|
||||
ev.mmap.pid = machine->pid;
|
||||
|
||||
memcpy(ev.mmap.filename, pos->dso->long_name,
|
||||
pos->dso->long_name_len + 1);
|
||||
|
@ -267,7 +267,7 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
|
|||
|
||||
int event__synthesize_kernel_mmap(event__handler_t process,
|
||||
struct perf_session *session,
|
||||
struct kernel_info *kerninfo,
|
||||
struct machine *machine,
|
||||
const char *symbol_name)
|
||||
{
|
||||
size_t size;
|
||||
|
@ -288,8 +288,8 @@ int event__synthesize_kernel_mmap(event__handler_t process,
|
|||
*/
|
||||
struct process_symbol_args args = { .name = symbol_name, };
|
||||
|
||||
mmap_name = kern_mmap_name(kerninfo, name_buff);
|
||||
if (is_host_kernel(kerninfo)) {
|
||||
mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
|
||||
if (machine__is_host(machine)) {
|
||||
/*
|
||||
* kernel uses PERF_RECORD_MISC_USER for user space maps,
|
||||
* see kernel/perf_event.c __perf_event_mmap
|
||||
|
@ -298,10 +298,10 @@ int event__synthesize_kernel_mmap(event__handler_t process,
|
|||
filename = "/proc/kallsyms";
|
||||
} else {
|
||||
ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
|
||||
if (is_default_guest(kerninfo))
|
||||
if (machine__is_default_guest(machine))
|
||||
filename = (char *) symbol_conf.default_guest_kallsyms;
|
||||
else {
|
||||
sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
|
||||
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
|
||||
filename = path;
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ int event__synthesize_kernel_mmap(event__handler_t process,
|
|||
if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
|
||||
return -ENOENT;
|
||||
|
||||
map = kerninfo->vmlinux_maps[MAP__FUNCTION];
|
||||
map = machine->vmlinux_maps[MAP__FUNCTION];
|
||||
size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
|
||||
"%s%s", mmap_name, symbol_name) + 1;
|
||||
size = ALIGN(size, sizeof(u64));
|
||||
|
@ -318,7 +318,7 @@ int event__synthesize_kernel_mmap(event__handler_t process,
|
|||
ev.mmap.pgoff = args.start;
|
||||
ev.mmap.start = map->start;
|
||||
ev.mmap.len = map->end - ev.mmap.start;
|
||||
ev.mmap.pid = kerninfo->pid;
|
||||
ev.mmap.pid = machine->pid;
|
||||
|
||||
return process(&ev, session);
|
||||
}
|
||||
|
@ -389,18 +389,18 @@ static int event__process_kernel_mmap(event_t *self,
|
|||
{
|
||||
struct map *map;
|
||||
char kmmap_prefix[PATH_MAX];
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
enum dso_kernel_type kernel_type;
|
||||
bool is_kernel_mmap;
|
||||
|
||||
kerninfo = kerninfo__findnew(&session->kerninfo_root, self->mmap.pid);
|
||||
if (!kerninfo) {
|
||||
pr_err("Can't find id %d's kerninfo\n", self->mmap.pid);
|
||||
machine = perf_session__findnew_machine(session, self->mmap.pid);
|
||||
if (!machine) {
|
||||
pr_err("Can't find id %d's machine\n", self->mmap.pid);
|
||||
goto out_problem;
|
||||
}
|
||||
|
||||
kern_mmap_name(kerninfo, kmmap_prefix);
|
||||
if (is_host_kernel(kerninfo))
|
||||
machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
|
||||
if (machine__is_host(machine))
|
||||
kernel_type = DSO_TYPE_KERNEL;
|
||||
else
|
||||
kernel_type = DSO_TYPE_GUEST_KERNEL;
|
||||
|
@ -429,10 +429,8 @@ static int event__process_kernel_mmap(event_t *self,
|
|||
} else
|
||||
strcpy(short_module_name, self->mmap.filename);
|
||||
|
||||
map = map_groups__new_module(&kerninfo->kmaps,
|
||||
self->mmap.start,
|
||||
self->mmap.filename,
|
||||
kerninfo);
|
||||
map = machine__new_module(machine, self->mmap.start,
|
||||
self->mmap.filename);
|
||||
if (map == NULL)
|
||||
goto out_problem;
|
||||
|
||||
|
@ -449,27 +447,25 @@ static int event__process_kernel_mmap(event_t *self,
|
|||
* Should be there already, from the build-id table in
|
||||
* the header.
|
||||
*/
|
||||
struct dso *kernel = __dsos__findnew(&kerninfo->dsos__kernel,
|
||||
kmmap_prefix);
|
||||
struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
|
||||
kmmap_prefix);
|
||||
if (kernel == NULL)
|
||||
goto out_problem;
|
||||
|
||||
kernel->kernel = kernel_type;
|
||||
if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
|
||||
kerninfo->vmlinux_maps, kernel) < 0)
|
||||
if (__machine__create_kernel_maps(machine, kernel) < 0)
|
||||
goto out_problem;
|
||||
|
||||
event_set_kernel_mmap_len(kerninfo->vmlinux_maps, self);
|
||||
perf_session__set_kallsyms_ref_reloc_sym(kerninfo->vmlinux_maps,
|
||||
symbol_name,
|
||||
self->mmap.pgoff);
|
||||
if (is_default_guest(kerninfo)) {
|
||||
event_set_kernel_mmap_len(machine->vmlinux_maps, self);
|
||||
perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
|
||||
symbol_name,
|
||||
self->mmap.pgoff);
|
||||
if (machine__is_default_guest(machine)) {
|
||||
/*
|
||||
* preload dso of guest kernel and modules
|
||||
*/
|
||||
dso__load(kernel,
|
||||
kerninfo->vmlinux_maps[MAP__FUNCTION],
|
||||
NULL);
|
||||
dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -479,7 +475,7 @@ out_problem:
|
|||
|
||||
int event__process_mmap(event_t *self, struct perf_session *session)
|
||||
{
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
struct thread *thread;
|
||||
struct map *map;
|
||||
u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
@ -498,8 +494,8 @@ int event__process_mmap(event_t *self, struct perf_session *session)
|
|||
}
|
||||
|
||||
thread = perf_session__findnew(session, self->mmap.pid);
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
map = map__new(&kerninfo->dsos__user, self->mmap.start,
|
||||
machine = perf_session__find_host_machine(session);
|
||||
map = map__new(&machine->user_dsos, self->mmap.start,
|
||||
self->mmap.len, self->mmap.pgoff,
|
||||
self->mmap.pid, self->mmap.filename,
|
||||
MAP__FUNCTION, session->cwd, session->cwdlen);
|
||||
|
@ -546,7 +542,7 @@ void thread__find_addr_map(struct thread *self,
|
|||
struct addr_location *al)
|
||||
{
|
||||
struct map_groups *mg = &self->mg;
|
||||
struct kernel_info *kerninfo = NULL;
|
||||
struct machine *machine = NULL;
|
||||
|
||||
al->thread = self;
|
||||
al->addr = addr;
|
||||
|
@ -555,19 +551,19 @@ void thread__find_addr_map(struct thread *self,
|
|||
|
||||
if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
|
||||
al->level = 'k';
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
mg = &kerninfo->kmaps;
|
||||
machine = perf_session__find_host_machine(session);
|
||||
mg = &machine->kmaps;
|
||||
} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
|
||||
al->level = '.';
|
||||
kerninfo = kerninfo__findhost(&session->kerninfo_root);
|
||||
machine = perf_session__find_host_machine(session);
|
||||
} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
|
||||
al->level = 'g';
|
||||
kerninfo = kerninfo__find(&session->kerninfo_root, pid);
|
||||
if (!kerninfo) {
|
||||
machine = perf_session__find_machine(session, pid);
|
||||
if (!machine) {
|
||||
al->map = NULL;
|
||||
return;
|
||||
}
|
||||
mg = &kerninfo->kmaps;
|
||||
mg = &machine->kmaps;
|
||||
} else {
|
||||
/*
|
||||
* 'u' means guest os user space.
|
||||
|
@ -603,10 +599,9 @@ try_again:
|
|||
* in the whole kernel symbol list.
|
||||
*/
|
||||
if ((long long)al->addr < 0 &&
|
||||
cpumode == PERF_RECORD_MISC_KERNEL &&
|
||||
kerninfo &&
|
||||
mg != &kerninfo->kmaps) {
|
||||
mg = &kerninfo->kmaps;
|
||||
cpumode == PERF_RECORD_MISC_KERNEL &&
|
||||
machine && mg != &machine->kmaps) {
|
||||
mg = &machine->kmaps;
|
||||
goto try_again;
|
||||
}
|
||||
} else
|
||||
|
|
|
@ -156,12 +156,12 @@ void event__synthesize_threads(event__handler_t process,
|
|||
struct perf_session *session);
|
||||
int event__synthesize_kernel_mmap(event__handler_t process,
|
||||
struct perf_session *session,
|
||||
struct kernel_info *kerninfo,
|
||||
struct machine *machine,
|
||||
const char *symbol_name);
|
||||
|
||||
int event__synthesize_modules(event__handler_t process,
|
||||
struct perf_session *session,
|
||||
struct kernel_info *kerninfo);
|
||||
struct machine *machine);
|
||||
|
||||
int event__process_comm(event_t *self, struct perf_session *session);
|
||||
int event__process_lost(event_t *self, struct perf_session *session);
|
||||
|
|
|
@ -229,10 +229,9 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
|
|||
int err = 0;
|
||||
u16 kmisc, umisc;
|
||||
|
||||
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
if (is_host_kernel(pos)) {
|
||||
for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
if (machine__is_host(pos)) {
|
||||
kmisc = PERF_RECORD_MISC_KERNEL;
|
||||
umisc = PERF_RECORD_MISC_USER;
|
||||
} else {
|
||||
|
@ -240,11 +239,11 @@ static int dsos__write_buildid_table(struct perf_header *header, int fd)
|
|||
umisc = PERF_RECORD_MISC_GUEST_USER;
|
||||
}
|
||||
|
||||
err = __dsos__write_buildid_table(&pos->dsos__kernel, pos->pid,
|
||||
kmisc, fd);
|
||||
err = __dsos__write_buildid_table(&pos->kernel_dsos, pos->pid,
|
||||
kmisc, fd);
|
||||
if (err == 0)
|
||||
err = __dsos__write_buildid_table(&pos->dsos__user,
|
||||
pos->pid, umisc, fd);
|
||||
err = __dsos__write_buildid_table(&pos->user_dsos,
|
||||
pos->pid, umisc, fd);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
@ -378,11 +377,10 @@ static int dsos__cache_build_ids(struct perf_header *self)
|
|||
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
|
||||
return -1;
|
||||
|
||||
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
ret |= __dsos__cache_build_ids(&pos->dsos__kernel, debugdir);
|
||||
ret |= __dsos__cache_build_ids(&pos->dsos__user, debugdir);
|
||||
for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
ret |= __dsos__cache_build_ids(&pos->kernel_dsos, debugdir);
|
||||
ret |= __dsos__cache_build_ids(&pos->user_dsos, debugdir);
|
||||
}
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
@ -394,11 +392,10 @@ static bool dsos__read_build_ids(struct perf_header *self, bool with_hits)
|
|||
struct perf_session, header);
|
||||
struct rb_node *nd;
|
||||
|
||||
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
ret |= __dsos__read_build_ids(&pos->dsos__kernel, with_hits);
|
||||
ret |= __dsos__read_build_ids(&pos->dsos__user, with_hits);
|
||||
for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
ret |= __dsos__read_build_ids(&pos->kernel_dsos, with_hits);
|
||||
ret |= __dsos__read_build_ids(&pos->user_dsos, with_hits);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -685,13 +682,13 @@ static int __event_process_build_id(struct build_id_event *bev,
|
|||
{
|
||||
int err = -1;
|
||||
struct list_head *head;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
u16 misc;
|
||||
struct dso *dso;
|
||||
enum dso_kernel_type dso_type;
|
||||
|
||||
kerninfo = kerninfo__findnew(&session->kerninfo_root, bev->pid);
|
||||
if (!kerninfo)
|
||||
machine = perf_session__findnew_machine(session, bev->pid);
|
||||
if (!machine)
|
||||
goto out;
|
||||
|
||||
misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
|
||||
|
@ -699,16 +696,16 @@ static int __event_process_build_id(struct build_id_event *bev,
|
|||
switch (misc) {
|
||||
case PERF_RECORD_MISC_KERNEL:
|
||||
dso_type = DSO_TYPE_KERNEL;
|
||||
head = &kerninfo->dsos__kernel;
|
||||
head = &machine->kernel_dsos;
|
||||
break;
|
||||
case PERF_RECORD_MISC_GUEST_KERNEL:
|
||||
dso_type = DSO_TYPE_GUEST_KERNEL;
|
||||
head = &kerninfo->dsos__kernel;
|
||||
head = &machine->kernel_dsos;
|
||||
break;
|
||||
case PERF_RECORD_MISC_USER:
|
||||
case PERF_RECORD_MISC_GUEST_USER:
|
||||
dso_type = DSO_TYPE_USER;
|
||||
head = &kerninfo->dsos__user;
|
||||
head = &machine->user_dsos;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
|
@ -1113,8 +1110,7 @@ int event__process_tracing_data(event_t *self,
|
|||
}
|
||||
|
||||
int event__synthesize_build_id(struct dso *pos, u16 misc,
|
||||
event__handler_t process,
|
||||
struct kernel_info *kerninfo,
|
||||
event__handler_t process, struct machine *machine,
|
||||
struct perf_session *session)
|
||||
{
|
||||
event_t ev;
|
||||
|
@ -1131,7 +1127,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
|
|||
memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
|
||||
ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
|
||||
ev.build_id.header.misc = misc;
|
||||
ev.build_id.pid = kerninfo->pid;
|
||||
ev.build_id.pid = machine->pid;
|
||||
ev.build_id.header.size = sizeof(ev.build_id) + len;
|
||||
memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
|
||||
|
||||
|
@ -1142,7 +1138,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
|
|||
|
||||
static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
|
||||
event__handler_t process,
|
||||
struct kernel_info *kerninfo,
|
||||
struct machine *machine,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct dso *pos;
|
||||
|
@ -1153,7 +1149,7 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
|
|||
continue;
|
||||
|
||||
err = event__synthesize_build_id(pos, misc, process,
|
||||
kerninfo, session);
|
||||
machine, session);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
@ -1166,15 +1162,15 @@ int event__synthesize_build_ids(event__handler_t process,
|
|||
{
|
||||
int err = 0;
|
||||
u16 kmisc, umisc;
|
||||
struct kernel_info *pos;
|
||||
struct machine *pos;
|
||||
struct rb_node *nd;
|
||||
|
||||
if (!dsos__read_build_ids(&session->header, true))
|
||||
return 0;
|
||||
|
||||
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
pos = rb_entry(nd, struct kernel_info, rb_node);
|
||||
if (is_host_kernel(pos)) {
|
||||
for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) {
|
||||
pos = rb_entry(nd, struct machine, rb_node);
|
||||
if (machine__is_host(pos)) {
|
||||
kmisc = PERF_RECORD_MISC_KERNEL;
|
||||
umisc = PERF_RECORD_MISC_USER;
|
||||
} else {
|
||||
|
@ -1182,11 +1178,11 @@ int event__synthesize_build_ids(event__handler_t process,
|
|||
umisc = PERF_RECORD_MISC_GUEST_USER;
|
||||
}
|
||||
|
||||
err = __event_synthesize_build_ids(&pos->dsos__kernel,
|
||||
kmisc, process, pos, session);
|
||||
err = __event_synthesize_build_ids(&pos->kernel_dsos, kmisc,
|
||||
process, pos, session);
|
||||
if (err == 0)
|
||||
err = __event_synthesize_build_ids(&pos->dsos__user,
|
||||
umisc, process, pos, session);
|
||||
err = __event_synthesize_build_ids(&pos->user_dsos, umisc,
|
||||
process, pos, session);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ int event__process_tracing_data(event_t *self,
|
|||
|
||||
int event__synthesize_build_id(struct dso *pos, u16 misc,
|
||||
event__handler_t process,
|
||||
struct kernel_info *kerninfo,
|
||||
struct machine *machine,
|
||||
struct perf_session *session);
|
||||
int event__synthesize_build_ids(event__handler_t process,
|
||||
struct perf_session *session);
|
||||
|
|
|
@ -245,7 +245,7 @@ void map_groups__init(struct map_groups *self)
|
|||
self->maps[i] = RB_ROOT;
|
||||
INIT_LIST_HEAD(&self->removed_maps[i]);
|
||||
}
|
||||
self->this_kerninfo = NULL;
|
||||
self->machine = NULL;
|
||||
}
|
||||
|
||||
void map_groups__flush(struct map_groups *self)
|
||||
|
@ -513,133 +513,140 @@ struct map *maps__find(struct rb_root *maps, u64 ip)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
struct kernel_info *add_new_kernel_info(struct rb_root *kerninfo_root,
|
||||
pid_t pid, const char *root_dir)
|
||||
int machine__init(struct machine *self, const char *root_dir, pid_t pid)
|
||||
{
|
||||
struct rb_node **p = &kerninfo_root->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct kernel_info *kerninfo, *pos;
|
||||
map_groups__init(&self->kmaps);
|
||||
RB_CLEAR_NODE(&self->rb_node);
|
||||
INIT_LIST_HEAD(&self->user_dsos);
|
||||
INIT_LIST_HEAD(&self->kernel_dsos);
|
||||
|
||||
kerninfo = malloc(sizeof(struct kernel_info));
|
||||
if (!kerninfo)
|
||||
self->kmaps.machine = self;
|
||||
self->pid = pid;
|
||||
self->root_dir = strdup(root_dir);
|
||||
return self->root_dir == NULL ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
struct machine *machines__add(struct rb_root *self, pid_t pid,
|
||||
const char *root_dir)
|
||||
{
|
||||
struct rb_node **p = &self->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct machine *pos, *machine = malloc(sizeof(*machine));
|
||||
|
||||
if (!machine)
|
||||
return NULL;
|
||||
|
||||
kerninfo->pid = pid;
|
||||
map_groups__init(&kerninfo->kmaps);
|
||||
kerninfo->root_dir = strdup(root_dir);
|
||||
RB_CLEAR_NODE(&kerninfo->rb_node);
|
||||
INIT_LIST_HEAD(&kerninfo->dsos__user);
|
||||
INIT_LIST_HEAD(&kerninfo->dsos__kernel);
|
||||
kerninfo->kmaps.this_kerninfo = kerninfo;
|
||||
if (machine__init(machine, root_dir, pid) != 0) {
|
||||
free(machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
pos = rb_entry(parent, struct kernel_info, rb_node);
|
||||
pos = rb_entry(parent, struct machine, rb_node);
|
||||
if (pid < pos->pid)
|
||||
p = &(*p)->rb_left;
|
||||
else
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
|
||||
rb_link_node(&kerninfo->rb_node, parent, p);
|
||||
rb_insert_color(&kerninfo->rb_node, kerninfo_root);
|
||||
rb_link_node(&machine->rb_node, parent, p);
|
||||
rb_insert_color(&machine->rb_node, self);
|
||||
|
||||
return kerninfo;
|
||||
return machine;
|
||||
}
|
||||
|
||||
struct kernel_info *kerninfo__find(struct rb_root *kerninfo_root, pid_t pid)
|
||||
struct machine *machines__find(struct rb_root *self, pid_t pid)
|
||||
{
|
||||
struct rb_node **p = &kerninfo_root->rb_node;
|
||||
struct rb_node **p = &self->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct kernel_info *kerninfo;
|
||||
struct kernel_info *default_kerninfo = NULL;
|
||||
struct machine *machine;
|
||||
struct machine *default_machine = NULL;
|
||||
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
kerninfo = rb_entry(parent, struct kernel_info, rb_node);
|
||||
if (pid < kerninfo->pid)
|
||||
machine = rb_entry(parent, struct machine, rb_node);
|
||||
if (pid < machine->pid)
|
||||
p = &(*p)->rb_left;
|
||||
else if (pid > kerninfo->pid)
|
||||
else if (pid > machine->pid)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return kerninfo;
|
||||
if (!kerninfo->pid)
|
||||
default_kerninfo = kerninfo;
|
||||
return machine;
|
||||
if (!machine->pid)
|
||||
default_machine = machine;
|
||||
}
|
||||
|
||||
return default_kerninfo;
|
||||
return default_machine;
|
||||
}
|
||||
|
||||
struct kernel_info *kerninfo__findhost(struct rb_root *kerninfo_root)
|
||||
/*
|
||||
* FIXME: Why repeatedly search for this?
|
||||
*/
|
||||
struct machine *machines__find_host(struct rb_root *self)
|
||||
{
|
||||
struct rb_node **p = &kerninfo_root->rb_node;
|
||||
struct rb_node **p = &self->rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
pid_t pid = HOST_KERNEL_ID;
|
||||
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
kerninfo = rb_entry(parent, struct kernel_info, rb_node);
|
||||
if (pid < kerninfo->pid)
|
||||
machine = rb_entry(parent, struct machine, rb_node);
|
||||
if (pid < machine->pid)
|
||||
p = &(*p)->rb_left;
|
||||
else if (pid > kerninfo->pid)
|
||||
else if (pid > machine->pid)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
return kerninfo;
|
||||
return machine;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct kernel_info *kerninfo__findnew(struct rb_root *kerninfo_root, pid_t pid)
|
||||
struct machine *machines__findnew(struct rb_root *self, pid_t pid)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
const char *root_dir;
|
||||
int ret;
|
||||
struct kernel_info *kerninfo = kerninfo__find(kerninfo_root, pid);
|
||||
struct machine *machine = machines__find(self, pid);
|
||||
|
||||
if (!kerninfo || kerninfo->pid != pid) {
|
||||
if (!machine || machine->pid != pid) {
|
||||
if (pid == HOST_KERNEL_ID || pid == DEFAULT_GUEST_KERNEL_ID)
|
||||
root_dir = "";
|
||||
else {
|
||||
if (!symbol_conf.guestmount)
|
||||
goto out;
|
||||
sprintf(path, "%s/%d", symbol_conf.guestmount, pid);
|
||||
ret = access(path, R_OK);
|
||||
if (ret) {
|
||||
if (access(path, R_OK)) {
|
||||
pr_err("Can't access file %s\n", path);
|
||||
goto out;
|
||||
}
|
||||
root_dir = path;
|
||||
}
|
||||
kerninfo = add_new_kernel_info(kerninfo_root, pid, root_dir);
|
||||
machine = machines__add(self, pid, root_dir);
|
||||
}
|
||||
|
||||
out:
|
||||
return kerninfo;
|
||||
return machine;
|
||||
}
|
||||
|
||||
void kerninfo__process_allkernels(struct rb_root *kerninfo_root,
|
||||
process_kernel_info process,
|
||||
void *data)
|
||||
void machines__process(struct rb_root *self, machine__process_t process, void *data)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
for (nd = rb_first(self); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
process(pos, data);
|
||||
}
|
||||
}
|
||||
|
||||
char *kern_mmap_name(struct kernel_info *kerninfo, char *buff)
|
||||
char *machine__mmap_name(struct machine *self, char *bf, size_t size)
|
||||
{
|
||||
if (is_host_kernel(kerninfo))
|
||||
sprintf(buff, "[%s]", "kernel.kallsyms");
|
||||
else if (is_default_guest(kerninfo))
|
||||
sprintf(buff, "[%s]", "guest.kernel.kallsyms");
|
||||
if (machine__is_host(self))
|
||||
snprintf(bf, size, "[%s]", "kernel.kallsyms");
|
||||
else if (machine__is_default_guest(self))
|
||||
snprintf(bf, size, "[%s]", "guest.kernel.kallsyms");
|
||||
else
|
||||
sprintf(buff, "[%s.%d]", "guest.kernel.kallsyms", kerninfo->pid);
|
||||
snprintf(bf, size, "[%s.%d]", "guest.kernel.kallsyms", self->pid);
|
||||
|
||||
return buff;
|
||||
return bf;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "types.h"
|
||||
|
||||
enum map_type {
|
||||
|
@ -19,7 +20,7 @@ extern const char *map_type__name[MAP__NR_TYPES];
|
|||
struct dso;
|
||||
struct ref_reloc_sym;
|
||||
struct map_groups;
|
||||
struct kernel_info;
|
||||
struct machine;
|
||||
|
||||
struct map {
|
||||
union {
|
||||
|
@ -29,6 +30,7 @@ struct map {
|
|||
u64 start;
|
||||
u64 end;
|
||||
enum map_type type;
|
||||
u32 priv;
|
||||
u64 pgoff;
|
||||
|
||||
/* ip -> dso rip */
|
||||
|
@ -46,25 +48,31 @@ struct kmap {
|
|||
};
|
||||
|
||||
struct map_groups {
|
||||
struct rb_root maps[MAP__NR_TYPES];
|
||||
struct list_head removed_maps[MAP__NR_TYPES];
|
||||
struct kernel_info *this_kerninfo;
|
||||
struct rb_root maps[MAP__NR_TYPES];
|
||||
struct list_head removed_maps[MAP__NR_TYPES];
|
||||
struct machine *machine;
|
||||
};
|
||||
|
||||
/* Native host kernel uses -1 as pid index in kernel_info */
|
||||
/* Native host kernel uses -1 as pid index in machine */
|
||||
#define HOST_KERNEL_ID (-1)
|
||||
#define DEFAULT_GUEST_KERNEL_ID (0)
|
||||
|
||||
struct kernel_info {
|
||||
struct rb_node rb_node;
|
||||
pid_t pid;
|
||||
char *root_dir;
|
||||
struct list_head dsos__user;
|
||||
struct list_head dsos__kernel;
|
||||
struct machine {
|
||||
struct rb_node rb_node;
|
||||
pid_t pid;
|
||||
char *root_dir;
|
||||
struct list_head user_dsos;
|
||||
struct list_head kernel_dsos;
|
||||
struct map_groups kmaps;
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES];
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES];
|
||||
};
|
||||
|
||||
static inline
|
||||
struct map *machine__kernel_map(struct machine *self, enum map_type type)
|
||||
{
|
||||
return self->vmlinux_maps[type];
|
||||
}
|
||||
|
||||
static inline struct kmap *map__kmap(struct map *self)
|
||||
{
|
||||
return (struct kmap *)(self + 1);
|
||||
|
@ -124,36 +132,31 @@ int map_groups__clone(struct map_groups *self,
|
|||
size_t map_groups__fprintf(struct map_groups *self, int verbose, FILE *fp);
|
||||
size_t map_groups__fprintf_maps(struct map_groups *self, int verbose, FILE *fp);
|
||||
|
||||
struct kernel_info *add_new_kernel_info(struct rb_root *kerninfo_root,
|
||||
pid_t pid, const char *root_dir);
|
||||
struct kernel_info *kerninfo__find(struct rb_root *kerninfo_root, pid_t pid);
|
||||
struct kernel_info *kerninfo__findnew(struct rb_root *kerninfo_root, pid_t pid);
|
||||
struct kernel_info *kerninfo__findhost(struct rb_root *kerninfo_root);
|
||||
char *kern_mmap_name(struct kernel_info *kerninfo, char *buff);
|
||||
typedef void (*machine__process_t)(struct machine *self, void *data);
|
||||
|
||||
void machines__process(struct rb_root *self, machine__process_t process, void *data);
|
||||
struct machine *machines__add(struct rb_root *self, pid_t pid,
|
||||
const char *root_dir);
|
||||
struct machine *machines__find_host(struct rb_root *self);
|
||||
struct machine *machines__find(struct rb_root *self, pid_t pid);
|
||||
struct machine *machines__findnew(struct rb_root *self, pid_t pid);
|
||||
char *machine__mmap_name(struct machine *self, char *bf, size_t size);
|
||||
int machine__init(struct machine *self, const char *root_dir, pid_t pid);
|
||||
|
||||
/*
|
||||
* Default guest kernel is defined by parameter --guestkallsyms
|
||||
* and --guestmodules
|
||||
*/
|
||||
static inline int is_default_guest(struct kernel_info *kerninfo)
|
||||
static inline bool machine__is_default_guest(struct machine *self)
|
||||
{
|
||||
if (!kerninfo)
|
||||
return 0;
|
||||
return kerninfo->pid == DEFAULT_GUEST_KERNEL_ID;
|
||||
return self ? self->pid == DEFAULT_GUEST_KERNEL_ID : false;
|
||||
}
|
||||
|
||||
static inline int is_host_kernel(struct kernel_info *kerninfo)
|
||||
static inline bool machine__is_host(struct machine *self)
|
||||
{
|
||||
if (!kerninfo)
|
||||
return 0;
|
||||
return kerninfo->pid == HOST_KERNEL_ID;
|
||||
return self ? self->pid == HOST_KERNEL_ID : false;
|
||||
}
|
||||
|
||||
typedef void (*process_kernel_info)(struct kernel_info *kerninfo, void *data);
|
||||
void kerninfo__process_allkernels(struct rb_root *kerninfo_root,
|
||||
process_kernel_info process,
|
||||
void *data);
|
||||
|
||||
static inline void map_groups__insert(struct map_groups *self, struct map *map)
|
||||
{
|
||||
maps__insert(&self->maps[map->type], map);
|
||||
|
@ -178,10 +181,20 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *self,
|
|||
symbol_filter_t filter);
|
||||
|
||||
static inline
|
||||
struct symbol *map_groups__find_function(struct map_groups *self, u64 addr,
|
||||
struct map **mapp, symbol_filter_t filter)
|
||||
struct symbol *machine__find_kernel_symbol(struct machine *self,
|
||||
enum map_type type, u64 addr,
|
||||
struct map **mapp,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
return map_groups__find_symbol(self, MAP__FUNCTION, addr, mapp, filter);
|
||||
return map_groups__find_symbol(&self->kmaps, type, addr, mapp, filter);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct symbol *machine__find_kernel_function(struct machine *self, u64 addr,
|
||||
struct map **mapp,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
return machine__find_kernel_symbol(self, MAP__FUNCTION, addr, mapp, filter);
|
||||
}
|
||||
|
||||
static inline
|
||||
|
@ -197,10 +210,7 @@ int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
|
|||
|
||||
struct map *map_groups__find_by_name(struct map_groups *self,
|
||||
enum map_type type, const char *name);
|
||||
struct map *map_groups__new_module(struct map_groups *self,
|
||||
u64 start,
|
||||
const char *filename,
|
||||
struct kernel_info *kerninfo);
|
||||
struct map *machine__new_module(struct machine *self, u64 start, const char *filename);
|
||||
|
||||
void map_groups__flush(struct map_groups *self);
|
||||
|
||||
|
|
|
@ -72,8 +72,7 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
|
|||
}
|
||||
|
||||
static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
|
||||
static struct map_groups kmap_groups;
|
||||
static struct map *kmaps[MAP__NR_TYPES];
|
||||
static struct machine machine;
|
||||
|
||||
/* Initialize symbol maps and path of vmlinux */
|
||||
static int init_vmlinux(void)
|
||||
|
@ -92,12 +91,15 @@ static int init_vmlinux(void)
|
|||
goto out;
|
||||
}
|
||||
|
||||
ret = machine__init(&machine, "/", 0);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
kernel = dso__new_kernel(symbol_conf.vmlinux_name);
|
||||
if (kernel == NULL)
|
||||
die("Failed to create kernel dso.");
|
||||
|
||||
map_groups__init(&kmap_groups);
|
||||
ret = __map_groups__create_kernel_maps(&kmap_groups, kmaps, kernel);
|
||||
ret = __machine__create_kernel_maps(&machine, kernel);
|
||||
if (ret < 0)
|
||||
pr_debug("Failed to create kernel maps.\n");
|
||||
|
||||
|
@ -110,12 +112,12 @@ out:
|
|||
#ifdef DWARF_SUPPORT
|
||||
static int open_vmlinux(void)
|
||||
{
|
||||
if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
|
||||
if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
|
||||
pr_debug("Failed to load kernel map.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
|
||||
return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
|
||||
pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
|
||||
return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
|
||||
}
|
||||
|
||||
/* Convert trace point to probe point with debuginfo */
|
||||
|
@ -125,7 +127,7 @@ static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
|
|||
struct symbol *sym;
|
||||
int fd, ret = -ENOENT;
|
||||
|
||||
sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
|
||||
sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
|
||||
tp->symbol, NULL);
|
||||
if (sym) {
|
||||
fd = open_vmlinux();
|
||||
|
@ -1466,7 +1468,7 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
|
|||
}
|
||||
|
||||
/* Currently just checking function name from symbol map */
|
||||
sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
|
||||
sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
|
||||
tev->point.symbol, NULL);
|
||||
if (!sym) {
|
||||
pr_warning("Kernel symbol \'%s\' not found.\n",
|
||||
|
|
|
@ -69,12 +69,11 @@ void perf_session__update_sample_type(struct perf_session *self)
|
|||
|
||||
int perf_session__create_kernel_maps(struct perf_session *self)
|
||||
{
|
||||
int ret;
|
||||
struct rb_root *root = &self->kerninfo_root;
|
||||
struct rb_root *machines = &self->machines;
|
||||
int ret = machines__create_kernel_maps(machines, HOST_KERNEL_ID);
|
||||
|
||||
ret = map_groups__create_kernel_maps(root, HOST_KERNEL_ID);
|
||||
if (ret >= 0)
|
||||
ret = map_groups__create_guest_kernel_maps(root);
|
||||
ret = machines__create_guest_kernel_maps(machines);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -97,7 +96,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
|
|||
self->cwd = NULL;
|
||||
self->cwdlen = 0;
|
||||
self->unknown_events = 0;
|
||||
self->kerninfo_root = RB_ROOT;
|
||||
self->machines = RB_ROOT;
|
||||
self->ordered_samples.flush_limit = ULLONG_MAX;
|
||||
INIT_LIST_HEAD(&self->ordered_samples.samples_head);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ struct perf_session {
|
|||
unsigned long mmap_window;
|
||||
struct rb_root threads;
|
||||
struct thread *last_match;
|
||||
struct rb_root kerninfo_root;
|
||||
struct rb_root machines;
|
||||
struct events_stats events_stats;
|
||||
struct rb_root stats_by_id;
|
||||
unsigned long event_total[PERF_RECORD_MAX];
|
||||
|
@ -102,4 +102,42 @@ int perf_session__browse_hists(struct rb_root *hists, u64 nr_hists,
|
|||
u64 session_total, const char *helpline,
|
||||
const char *input_name);
|
||||
#endif
|
||||
|
||||
static inline
|
||||
struct machine *perf_session__find_host_machine(struct perf_session *self)
|
||||
{
|
||||
return machines__find_host(&self->machines);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct machine *perf_session__find_machine(struct perf_session *self, pid_t pid)
|
||||
{
|
||||
return machines__find(&self->machines, pid);
|
||||
}
|
||||
|
||||
static inline
|
||||
struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t pid)
|
||||
{
|
||||
return machines__findnew(&self->machines, pid);
|
||||
}
|
||||
|
||||
static inline
|
||||
void perf_session__process_machines(struct perf_session *self,
|
||||
machine__process_t process)
|
||||
{
|
||||
return machines__process(&self->machines, process, self);
|
||||
}
|
||||
|
||||
static inline
|
||||
size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp)
|
||||
{
|
||||
return machines__fprintf_dsos(&self->machines, fp);
|
||||
}
|
||||
|
||||
static inline
|
||||
size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, FILE *fp,
|
||||
bool with_hits)
|
||||
{
|
||||
return machines__fprintf_dsos_buildid(&self->machines, fp, with_hits);
|
||||
}
|
||||
#endif /* __PERF_SESSION_H */
|
||||
|
|
|
@ -485,7 +485,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
|
|||
symbol_filter_t filter)
|
||||
{
|
||||
struct map_groups *kmaps = map__kmap(map)->kmaps;
|
||||
struct kernel_info *kerninfo = kmaps->this_kerninfo;
|
||||
struct machine *machine = kmaps->machine;
|
||||
struct map *curr_map = map;
|
||||
struct symbol *pos;
|
||||
int count = 0;
|
||||
|
@ -508,8 +508,8 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
|
|||
|
||||
if (strcmp(curr_map->dso->short_name, module)) {
|
||||
if (curr_map != map &&
|
||||
self->kernel == DSO_TYPE_GUEST_KERNEL &&
|
||||
is_default_guest(kerninfo)) {
|
||||
self->kernel == DSO_TYPE_GUEST_KERNEL &&
|
||||
machine__is_default_guest(machine)) {
|
||||
/*
|
||||
* We assume all symbols of a module are
|
||||
* continuous in * kallsyms, so curr_map
|
||||
|
@ -527,13 +527,13 @@ static int dso__split_kallsyms(struct dso *self, struct map *map,
|
|||
pr_err("%s/proc/{kallsyms,modules} "
|
||||
"inconsistency while looking "
|
||||
"for \"%s\" module!\n",
|
||||
kerninfo->root_dir, module);
|
||||
machine->root_dir, module);
|
||||
curr_map = map;
|
||||
goto discard_symbol;
|
||||
}
|
||||
|
||||
if (curr_map->dso->loaded &&
|
||||
!is_default_guest(kmaps->this_kerninfo))
|
||||
!machine__is_default_guest(machine))
|
||||
goto discard_symbol;
|
||||
}
|
||||
/*
|
||||
|
@ -586,7 +586,7 @@ discard_symbol: rb_erase(&pos->rb_node, root);
|
|||
|
||||
if (curr_map != map &&
|
||||
self->kernel == DSO_TYPE_GUEST_KERNEL &&
|
||||
is_default_guest(kmaps->this_kerninfo)) {
|
||||
machine__is_default_guest(kmaps->machine)) {
|
||||
dso__set_loaded(curr_map->dso, curr_map->type);
|
||||
}
|
||||
|
||||
|
@ -1291,7 +1291,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
|||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
int ret = -1;
|
||||
int fd;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
const char *root_dir;
|
||||
|
||||
dso__set_loaded(self, map->type);
|
||||
|
@ -1301,10 +1301,10 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
|||
else if (self->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||
return dso__load_guest_kernel_sym(self, map, filter);
|
||||
|
||||
if (map->groups && map->groups->this_kerninfo)
|
||||
kerninfo = map->groups->this_kerninfo;
|
||||
if (map->groups && map->groups->machine)
|
||||
machine = map->groups->machine;
|
||||
else
|
||||
kerninfo = NULL;
|
||||
machine = NULL;
|
||||
|
||||
name = malloc(size);
|
||||
if (!name)
|
||||
|
@ -1359,8 +1359,8 @@ more:
|
|||
snprintf(name, size, "%s", self->long_name);
|
||||
break;
|
||||
case DSO__ORIG_GUEST_KMODULE:
|
||||
if (map->groups && map->groups->this_kerninfo)
|
||||
root_dir = map->groups->this_kerninfo->root_dir;
|
||||
if (map->groups && map->groups->machine)
|
||||
root_dir = map->groups->machine->root_dir;
|
||||
else
|
||||
root_dir = "";
|
||||
snprintf(name, size, "%s%s", root_dir, self->long_name);
|
||||
|
@ -1528,21 +1528,20 @@ static char *get_kernel_version(const char *root_dir)
|
|||
return strdup(name);
|
||||
}
|
||||
|
||||
static int map_groups__set_modules_path(struct map_groups *self,
|
||||
const char *root_dir)
|
||||
static int machine__set_modules_path(struct machine *self)
|
||||
{
|
||||
char *version;
|
||||
char modules_path[PATH_MAX];
|
||||
|
||||
version = get_kernel_version(root_dir);
|
||||
version = get_kernel_version(self->root_dir);
|
||||
if (!version)
|
||||
return -1;
|
||||
|
||||
snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel",
|
||||
root_dir, version);
|
||||
self->root_dir, version);
|
||||
free(version);
|
||||
|
||||
return map_groups__set_modules_path_dir(self, modules_path);
|
||||
return map_groups__set_modules_path_dir(&self->kmaps, modules_path);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1564,14 +1563,12 @@ static struct map *map__new2(u64 start, struct dso *dso, enum map_type type)
|
|||
return self;
|
||||
}
|
||||
|
||||
struct map *map_groups__new_module(struct map_groups *self, u64 start,
|
||||
const char *filename,
|
||||
struct kernel_info *kerninfo)
|
||||
struct map *machine__new_module(struct machine *self, u64 start,
|
||||
const char *filename)
|
||||
{
|
||||
struct map *map;
|
||||
struct dso *dso;
|
||||
struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename);
|
||||
|
||||
dso = __dsos__findnew(&kerninfo->dsos__kernel, filename);
|
||||
if (dso == NULL)
|
||||
return NULL;
|
||||
|
||||
|
@ -1579,28 +1576,27 @@ struct map *map_groups__new_module(struct map_groups *self, u64 start,
|
|||
if (map == NULL)
|
||||
return NULL;
|
||||
|
||||
if (is_host_kernel(kerninfo))
|
||||
if (machine__is_host(self))
|
||||
dso->origin = DSO__ORIG_KMODULE;
|
||||
else
|
||||
dso->origin = DSO__ORIG_GUEST_KMODULE;
|
||||
map_groups__insert(self, map);
|
||||
map_groups__insert(&self->kmaps, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
static int map_groups__create_modules(struct kernel_info *kerninfo)
|
||||
static int machine__create_modules(struct machine *self)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t n;
|
||||
FILE *file;
|
||||
struct map *map;
|
||||
const char *root_dir;
|
||||
const char *modules;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (is_default_guest(kerninfo))
|
||||
if (machine__is_default_guest(self))
|
||||
modules = symbol_conf.default_guest_modules;
|
||||
else {
|
||||
sprintf(path, "%s/proc/modules", kerninfo->root_dir);
|
||||
sprintf(path, "%s/proc/modules", self->root_dir);
|
||||
modules = path;
|
||||
}
|
||||
|
||||
|
@ -1608,8 +1604,6 @@ static int map_groups__create_modules(struct kernel_info *kerninfo)
|
|||
if (file == NULL)
|
||||
return -1;
|
||||
|
||||
root_dir = kerninfo->root_dir;
|
||||
|
||||
while (!feof(file)) {
|
||||
char name[PATH_MAX];
|
||||
u64 start;
|
||||
|
@ -1638,17 +1632,16 @@ static int map_groups__create_modules(struct kernel_info *kerninfo)
|
|||
*sep = '\0';
|
||||
|
||||
snprintf(name, sizeof(name), "[%s]", line);
|
||||
map = map_groups__new_module(&kerninfo->kmaps,
|
||||
start, name, kerninfo);
|
||||
map = machine__new_module(self, start, name);
|
||||
if (map == NULL)
|
||||
goto out_delete_line;
|
||||
dso__kernel_module_get_build_id(map->dso, root_dir);
|
||||
dso__kernel_module_get_build_id(map->dso, self->root_dir);
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(file);
|
||||
|
||||
return map_groups__set_modules_path(&kerninfo->kmaps, root_dir);
|
||||
return machine__set_modules_path(self);
|
||||
|
||||
out_delete_line:
|
||||
free(line);
|
||||
|
@ -1820,16 +1813,16 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
|
|||
{
|
||||
int err;
|
||||
const char *kallsyms_filename = NULL;
|
||||
struct kernel_info *kerninfo;
|
||||
struct machine *machine;
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (!map->groups) {
|
||||
pr_debug("Guest kernel map hasn't the point to groups\n");
|
||||
return -1;
|
||||
}
|
||||
kerninfo = map->groups->this_kerninfo;
|
||||
machine = map->groups->machine;
|
||||
|
||||
if (is_default_guest(kerninfo)) {
|
||||
if (machine__is_default_guest(machine)) {
|
||||
/*
|
||||
* if the user specified a vmlinux filename, use it and only
|
||||
* it, reporting errors to the user if it cannot be used.
|
||||
|
@ -1845,7 +1838,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
|
|||
if (!kallsyms_filename)
|
||||
return -1;
|
||||
} else {
|
||||
sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
|
||||
sprintf(path, "%s/proc/kallsyms", machine->root_dir);
|
||||
kallsyms_filename = path;
|
||||
}
|
||||
|
||||
|
@ -1856,9 +1849,8 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map,
|
|||
out_try_fixup:
|
||||
if (err > 0) {
|
||||
if (kallsyms_filename != NULL) {
|
||||
kern_mmap_name(kerninfo, path);
|
||||
dso__set_long_name(self,
|
||||
strdup(path));
|
||||
machine__mmap_name(machine, path, sizeof(path));
|
||||
dso__set_long_name(self, strdup(path));
|
||||
}
|
||||
map__fixup_start(map);
|
||||
map__fixup_end(map);
|
||||
|
@ -1897,27 +1889,32 @@ struct dso *__dsos__findnew(struct list_head *head, const char *name)
|
|||
return dso;
|
||||
}
|
||||
|
||||
static void __dsos__fprintf(struct list_head *head, FILE *fp)
|
||||
static size_t __dsos__fprintf(struct list_head *head, FILE *fp)
|
||||
{
|
||||
struct dso *pos;
|
||||
size_t ret = 0;
|
||||
|
||||
list_for_each_entry(pos, head, node) {
|
||||
int i;
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
dso__fprintf(pos, i, fp);
|
||||
ret += dso__fprintf(pos, i, fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp)
|
||||
size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
size_t ret = 0;
|
||||
|
||||
for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
__dsos__fprintf(&pos->dsos__kernel, fp);
|
||||
__dsos__fprintf(&pos->dsos__user, fp);
|
||||
for (nd = rb_first(self); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
ret += __dsos__fprintf(&pos->kernel_dsos, fp);
|
||||
ret += __dsos__fprintf(&pos->user_dsos, fp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
|
||||
|
@ -1935,19 +1932,15 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp,
|
|||
return ret;
|
||||
}
|
||||
|
||||
size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root,
|
||||
FILE *fp, bool with_hits)
|
||||
size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits)
|
||||
{
|
||||
struct rb_node *nd;
|
||||
size_t ret = 0;
|
||||
|
||||
for (nd = rb_first(kerninfo_root); nd; nd = rb_next(nd)) {
|
||||
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
|
||||
rb_node);
|
||||
ret += __dsos__fprintf_buildid(&pos->dsos__kernel,
|
||||
fp, with_hits);
|
||||
ret += __dsos__fprintf_buildid(&pos->dsos__user,
|
||||
fp, with_hits);
|
||||
for (nd = rb_first(self); nd; nd = rb_next(nd)) {
|
||||
struct machine *pos = rb_entry(nd, struct machine, rb_node);
|
||||
ret += __dsos__fprintf_buildid(&pos->kernel_dsos, fp, with_hits);
|
||||
ret += __dsos__fprintf_buildid(&pos->user_dsos, fp, with_hits);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -1964,14 +1957,12 @@ struct dso *dso__new_kernel(const char *name)
|
|||
return self;
|
||||
}
|
||||
|
||||
static struct dso *dso__new_guest_kernel(struct kernel_info *kerninfo,
|
||||
static struct dso *dso__new_guest_kernel(struct machine *machine,
|
||||
const char *name)
|
||||
{
|
||||
char buff[PATH_MAX];
|
||||
struct dso *self;
|
||||
char bf[PATH_MAX];
|
||||
struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf)));
|
||||
|
||||
kern_mmap_name(kerninfo, buff);
|
||||
self = dso__new(name ?: buff);
|
||||
if (self != NULL) {
|
||||
dso__set_short_name(self, "[guest.kernel]");
|
||||
self->kernel = DSO_TYPE_GUEST_KERNEL;
|
||||
|
@ -1980,64 +1971,78 @@ static struct dso *dso__new_guest_kernel(struct kernel_info *kerninfo,
|
|||
return self;
|
||||
}
|
||||
|
||||
void dso__read_running_kernel_build_id(struct dso *self,
|
||||
struct kernel_info *kerninfo)
|
||||
void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
|
||||
if (is_default_guest(kerninfo))
|
||||
if (machine__is_default_guest(machine))
|
||||
return;
|
||||
sprintf(path, "%s/sys/kernel/notes", kerninfo->root_dir);
|
||||
sprintf(path, "%s/sys/kernel/notes", machine->root_dir);
|
||||
if (sysfs__read_build_id(path, self->build_id,
|
||||
sizeof(self->build_id)) == 0)
|
||||
self->has_build_id = true;
|
||||
}
|
||||
|
||||
static struct dso *dsos__create_kernel(struct kernel_info *kerninfo)
|
||||
static struct dso *machine__create_kernel(struct machine *self)
|
||||
{
|
||||
const char *vmlinux_name = NULL;
|
||||
struct dso *kernel;
|
||||
|
||||
if (is_host_kernel(kerninfo)) {
|
||||
if (machine__is_host(self)) {
|
||||
vmlinux_name = symbol_conf.vmlinux_name;
|
||||
kernel = dso__new_kernel(vmlinux_name);
|
||||
} else {
|
||||
if (is_default_guest(kerninfo))
|
||||
if (machine__is_default_guest(self))
|
||||
vmlinux_name = symbol_conf.default_guest_vmlinux_name;
|
||||
kernel = dso__new_guest_kernel(kerninfo, vmlinux_name);
|
||||
kernel = dso__new_guest_kernel(self, vmlinux_name);
|
||||
}
|
||||
|
||||
if (kernel != NULL) {
|
||||
dso__read_running_kernel_build_id(kernel, kerninfo);
|
||||
dsos__add(&kerninfo->dsos__kernel, kernel);
|
||||
dso__read_running_kernel_build_id(kernel, self);
|
||||
dsos__add(&self->kernel_dsos, kernel);
|
||||
}
|
||||
return kernel;
|
||||
}
|
||||
|
||||
int __map_groups__create_kernel_maps(struct map_groups *self,
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES],
|
||||
struct dso *kernel)
|
||||
int __machine__create_kernel_maps(struct machine *self, struct dso *kernel)
|
||||
{
|
||||
enum map_type type;
|
||||
|
||||
for (type = 0; type < MAP__NR_TYPES; ++type) {
|
||||
struct kmap *kmap;
|
||||
|
||||
vmlinux_maps[type] = map__new2(0, kernel, type);
|
||||
if (vmlinux_maps[type] == NULL)
|
||||
self->vmlinux_maps[type] = map__new2(0, kernel, type);
|
||||
if (self->vmlinux_maps[type] == NULL)
|
||||
return -1;
|
||||
|
||||
vmlinux_maps[type]->map_ip =
|
||||
vmlinux_maps[type]->unmap_ip = identity__map_ip;
|
||||
self->vmlinux_maps[type]->map_ip =
|
||||
self->vmlinux_maps[type]->unmap_ip = identity__map_ip;
|
||||
|
||||
kmap = map__kmap(vmlinux_maps[type]);
|
||||
kmap->kmaps = self;
|
||||
map_groups__insert(self, vmlinux_maps[type]);
|
||||
kmap = map__kmap(self->vmlinux_maps[type]);
|
||||
kmap->kmaps = &self->kmaps;
|
||||
map_groups__insert(&self->kmaps, self->vmlinux_maps[type]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int machine__create_kernel_maps(struct machine *self)
|
||||
{
|
||||
struct dso *kernel = machine__create_kernel(self);
|
||||
|
||||
if (kernel == NULL ||
|
||||
__machine__create_kernel_maps(self, kernel) < 0)
|
||||
return -1;
|
||||
|
||||
if (symbol_conf.use_modules && machine__create_modules(self) < 0)
|
||||
pr_debug("Problems creating module maps, continuing anyway...\n");
|
||||
/*
|
||||
* Now that we have all the maps created, just set the ->end of them:
|
||||
*/
|
||||
map_groups__fixup_end(&self->kmaps);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vmlinux_path__exit(void)
|
||||
{
|
||||
while (--vmlinux_path__nr_entries >= 0) {
|
||||
|
@ -2154,30 +2159,14 @@ out_free_comm_list:
|
|||
return -1;
|
||||
}
|
||||
|
||||
int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid)
|
||||
int machines__create_kernel_maps(struct rb_root *self, pid_t pid)
|
||||
{
|
||||
struct kernel_info *kerninfo;
|
||||
struct dso *kernel;
|
||||
struct machine *machine = machines__findnew(self, pid);
|
||||
|
||||
kerninfo = kerninfo__findnew(kerninfo_root, pid);
|
||||
if (kerninfo == NULL)
|
||||
return -1;
|
||||
kernel = dsos__create_kernel(kerninfo);
|
||||
if (kernel == NULL)
|
||||
if (machine == NULL)
|
||||
return -1;
|
||||
|
||||
if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
|
||||
kerninfo->vmlinux_maps, kernel) < 0)
|
||||
return -1;
|
||||
|
||||
if (symbol_conf.use_modules &&
|
||||
map_groups__create_modules(kerninfo) < 0)
|
||||
pr_debug("Problems creating module maps, continuing anyway...\n");
|
||||
/*
|
||||
* Now that we have all the maps created, just set the ->end of them:
|
||||
*/
|
||||
map_groups__fixup_end(&kerninfo->kmaps);
|
||||
return 0;
|
||||
return machine__create_kernel_maps(machine);
|
||||
}
|
||||
|
||||
static int hex(char ch)
|
||||
|
@ -2223,7 +2212,7 @@ char *strxfrchar(char *s, char from, char to)
|
|||
return s;
|
||||
}
|
||||
|
||||
int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root)
|
||||
int machines__create_guest_kernel_maps(struct rb_root *self)
|
||||
{
|
||||
int ret = 0;
|
||||
struct dirent **namelist = NULL;
|
||||
|
@ -2234,8 +2223,7 @@ int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root)
|
|||
if (symbol_conf.default_guest_vmlinux_name ||
|
||||
symbol_conf.default_guest_modules ||
|
||||
symbol_conf.default_guest_kallsyms) {
|
||||
map_groups__create_kernel_maps(kerninfo_root,
|
||||
DEFAULT_GUEST_KERNEL_ID);
|
||||
machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID);
|
||||
}
|
||||
|
||||
if (symbol_conf.guestmount) {
|
||||
|
@ -2256,8 +2244,7 @@ int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root)
|
|||
pr_debug("Can't access file %s\n", path);
|
||||
goto failure;
|
||||
}
|
||||
map_groups__create_kernel_maps(kerninfo_root,
|
||||
pid);
|
||||
machines__create_kernel_maps(self, pid);
|
||||
}
|
||||
failure:
|
||||
free(namelist);
|
||||
|
@ -2265,3 +2252,36 @@ failure:
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int machine__load_kallsyms(struct machine *self, const char *filename,
|
||||
enum map_type type, symbol_filter_t filter)
|
||||
{
|
||||
struct map *map = self->vmlinux_maps[type];
|
||||
int ret = dso__load_kallsyms(map->dso, filename, map, filter);
|
||||
|
||||
if (ret > 0) {
|
||||
dso__set_loaded(map->dso, type);
|
||||
/*
|
||||
* Since /proc/kallsyms will have multiple sessions for the
|
||||
* kernel, with modules between them, fixup the end of all
|
||||
* sections.
|
||||
*/
|
||||
__map_groups__fixup_end(&self->kmaps, type);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int machine__load_vmlinux_path(struct machine *self, enum map_type type,
|
||||
symbol_filter_t filter)
|
||||
{
|
||||
struct map *map = self->vmlinux_maps[type];
|
||||
int ret = dso__load_vmlinux_path(map->dso, map, filter);
|
||||
|
||||
if (ret > 0) {
|
||||
dso__set_loaded(map->dso, type);
|
||||
map__reloc_vmlinux(map);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -162,9 +162,13 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map,
|
|||
symbol_filter_t filter);
|
||||
int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
|
||||
symbol_filter_t filter);
|
||||
void dsos__fprintf(struct rb_root *kerninfo_root, FILE *fp);
|
||||
size_t dsos__fprintf_buildid(struct rb_root *kerninfo_root,
|
||||
FILE *fp, bool with_hits);
|
||||
int machine__load_kallsyms(struct machine *self, const char *filename,
|
||||
enum map_type type, symbol_filter_t filter);
|
||||
int machine__load_vmlinux_path(struct machine *self, enum map_type type,
|
||||
symbol_filter_t filter);
|
||||
|
||||
size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
|
||||
size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
|
||||
|
||||
size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
|
||||
size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
|
||||
|
@ -186,8 +190,7 @@ enum dso_origin {
|
|||
char dso__symtab_origin(const struct dso *self);
|
||||
void dso__set_long_name(struct dso *self, char *name);
|
||||
void dso__set_build_id(struct dso *self, void *build_id);
|
||||
void dso__read_running_kernel_build_id(struct dso *self,
|
||||
struct kernel_info *kerninfo);
|
||||
void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine);
|
||||
struct symbol *dso__find_symbol(struct dso *self, enum map_type type, u64 addr);
|
||||
struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type,
|
||||
const char *name);
|
||||
|
@ -200,11 +203,11 @@ int kallsyms__parse(const char *filename, void *arg,
|
|||
int (*process_symbol)(void *arg, const char *name,
|
||||
char type, u64 start));
|
||||
|
||||
int __map_groups__create_kernel_maps(struct map_groups *self,
|
||||
struct map *vmlinux_maps[MAP__NR_TYPES],
|
||||
struct dso *kernel);
|
||||
int map_groups__create_kernel_maps(struct rb_root *kerninfo_root, pid_t pid);
|
||||
int map_groups__create_guest_kernel_maps(struct rb_root *kerninfo_root);
|
||||
int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
|
||||
int machine__create_kernel_maps(struct machine *self);
|
||||
|
||||
int machines__create_kernel_maps(struct rb_root *self, pid_t pid);
|
||||
int machines__create_guest_kernel_maps(struct rb_root *self);
|
||||
|
||||
int symbol__init(void);
|
||||
bool symbol_type__is_a(char symbol_type, enum map_type map_type);
|
||||
|
|
Loading…
Add table
Reference in a new issue