diff options
-rw-r--r-- | tools/perf/util/event.c | 7 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 87 | ||||
-rw-r--r-- | tools/perf/util/machine.h | 2 | ||||
-rw-r--r-- | tools/perf/util/session.c | 7 | ||||
-rw-r--r-- | tools/perf/util/symbol_conf.h | 3 |
5 files changed, 103 insertions, 3 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6439c888ae38..0476bb3a4188 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -683,9 +683,12 @@ static bool check_address_range(struct intlist *addr_list, int addr_range, int machine__resolve(struct machine *machine, struct addr_location *al, struct perf_sample *sample) { - struct thread *thread = machine__findnew_thread(machine, sample->pid, - sample->tid); + struct thread *thread; + if (symbol_conf.guest_code && !machine__is_host(machine)) + thread = machine__findnew_guest_code(machine, sample->pid); + else + thread = machine__findnew_thread(machine, sample->pid, sample->tid); if (thread == NULL) return -1; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index e67b5a7670f3..009061852808 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -392,6 +392,93 @@ struct machine *machines__find_guest(struct machines *machines, pid_t pid) return machine; } +/* + * A common case for KVM test programs is that the test program acts as the + * hypervisor, creating, running and destroying the virtual machine, and + * providing the guest object code from its own object code. In this case, + * the VM is not running an OS, but only the functions loaded into it by the + * hypervisor test program, and conveniently, loaded at the same virtual + * addresses. + * + * Normally to resolve addresses, MMAP events are needed to map addresses + * back to the object code and debug symbols for that object code. + * + * Currently, there is no way to get such mapping information from guests + * but, in the scenario described above, the guest has the same mappings + * as the hypervisor, so support for that scenario can be achieved. + * + * To support that, copy the host thread's maps to the guest thread's maps. + * Note, we do not discover the guest until we encounter a guest event, + * which works well because it is not until then that we know that the host + * thread's maps have been set up. + * + * This function returns the guest thread. Apart from keeping the data + * structures sane, using a thread belonging to the guest machine, instead + * of the host thread, allows it to have its own comm (refer + * thread__set_guest_comm()). + */ +static struct thread *findnew_guest_code(struct machine *machine, + struct machine *host_machine, + pid_t pid) +{ + struct thread *host_thread; + struct thread *thread; + int err; + + if (!machine) + return NULL; + + thread = machine__findnew_thread(machine, -1, pid); + if (!thread) + return NULL; + + /* Assume maps are set up if there are any */ + if (thread->maps->nr_maps) + return thread; + + host_thread = machine__find_thread(host_machine, -1, pid); + if (!host_thread) + goto out_err; + + thread__set_guest_comm(thread, pid); + + /* + * Guest code can be found in hypervisor process at the same address + * so copy host maps. + */ + err = maps__clone(thread, host_thread->maps); + thread__put(host_thread); + if (err) + goto out_err; + + return thread; + +out_err: + thread__zput(thread); + return NULL; +} + +struct thread *machines__findnew_guest_code(struct machines *machines, pid_t pid) +{ + struct machine *host_machine = machines__find(machines, HOST_KERNEL_ID); + struct machine *machine = machines__findnew(machines, pid); + + return findnew_guest_code(machine, host_machine, pid); +} + +struct thread *machine__findnew_guest_code(struct machine *machine, pid_t pid) +{ + struct machines *machines = machine->machines; + struct machine *host_machine; + + if (!machines) + return NULL; + + host_machine = machines__find(machines, HOST_KERNEL_ID); + + return findnew_guest_code(machine, host_machine, pid); +} + void machines__process_guests(struct machines *machines, machine__process_t process, void *data) { diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index a5e479b8df5b..5d7daf7cb7bc 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -167,6 +167,8 @@ struct machine *machines__add(struct machines *machines, pid_t pid, struct machine *machines__find(struct machines *machines, pid_t pid); struct machine *machines__findnew(struct machines *machines, pid_t pid); struct machine *machines__find_guest(struct machines *machines, pid_t pid); +struct thread *machines__findnew_guest_code(struct machines *machines, pid_t pid); +struct thread *machine__findnew_guest_code(struct machine *machine, pid_t pid); void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size); void machines__set_comm_exec(struct machines *machines, bool comm_exec); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index a7f93f5a1ac8..0aa818977d2b 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1426,6 +1426,13 @@ static struct machine *machines__find_for_cpumode(struct machines *machines, else pid = sample->pid; + /* + * Guest code machine is created as needed and does not use + * DEFAULT_GUEST_KERNEL_ID. + */ + if (symbol_conf.guest_code) + return machines__findnew(machines, pid); + return machines__find_guest(machines, pid); } diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h index a70b3ec09dac..bc3d046fbb63 100644 --- a/tools/perf/util/symbol_conf.h +++ b/tools/perf/util/symbol_conf.h @@ -43,7 +43,8 @@ struct symbol_conf { report_individual_block, inline_name, disable_add2line_warn, - buildid_mmap2; + buildid_mmap2, + guest_code; const char *vmlinux_name, *kallsyms_name, *source_prefix, |