trace-cmd report: Add callback for kvm plugin to show guest functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: "Steven Rostedt (Google)" <rostedt@xxxxxxxxxxx>

Starting with libtraceevent 1.6.2, the kvm plugin will call a weak
function that can be overridden by the application (in this case
trace-cmd) called tep_plugin_kvm_get_func() that passes in the event, the
record, and an address to a value containing the address of the function
being requested. If the application has the guest mapping of addresses to
function names (usually taken from kallsyms), then it can define this
function to return the name of the function at the given address of the
guest.

Optionally, it can update the value holding the address, to the start of
the function such that the tep kvm plugin can print not only the function
name, but also the address offset of the original location and the
function itself.

Signed-off-by: Steven Rostedt (Google) <rostedt@xxxxxxxxxxx>
---
 tracecmd/trace-read.c | 94 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/tracecmd/trace-read.c b/tracecmd/trace-read.c
index db9bb2e5219f..b8931cf95543 100644
--- a/tracecmd/trace-read.c
+++ b/tracecmd/trace-read.c
@@ -1040,6 +1040,98 @@ static bool skip_record(struct handle_list *handles, struct tep_record *record,
 	return !found;
 }
 
+struct kvm_cpu_map {
+	struct tracecmd_input		*guest_handle;
+	int				guest_vcpu;
+	int				host_pid;
+};
+
+static struct kvm_cpu_map *vcpu_maps;
+static int nr_vcpu_maps;
+
+static int cmp_map(const void *A, const void *B)
+{
+	const struct kvm_cpu_map *a = A;
+	const struct kvm_cpu_map *b = B;
+
+	if (a->host_pid < b->host_pid)
+		return -1;
+	return a->host_pid > b->host_pid;
+}
+
+static void map_vcpus(struct tracecmd_input **handles, int nr_handles)
+{
+	struct tracecmd_input *host_handle = handles[0];
+	unsigned long long traceid;
+	struct kvm_cpu_map *map;
+	const int *cpu_pids;
+	const char *name;
+	int vcpu_count;
+	int ret;
+	int i, k;
+
+	for (i = 1; i < nr_handles; i++) {
+		traceid = tracecmd_get_traceid(handles[i]);
+		ret = tracecmd_get_guest_cpumap(host_handle, traceid,
+						&name, &vcpu_count, &cpu_pids);
+		if (ret)
+			continue;
+		map = realloc(vcpu_maps, sizeof(*map) * (nr_vcpu_maps + vcpu_count));
+		if (!map)
+			die("Could not allocate vcpu maps");
+
+		vcpu_maps = map;
+		map += nr_vcpu_maps;
+		nr_vcpu_maps += vcpu_count;
+
+		for (k = 0; k < vcpu_count; k++) {
+			map[k].guest_handle = handles[i];
+			map[k].guest_vcpu = k;
+			map[k].host_pid = cpu_pids[k];
+		}
+	}
+	if (!vcpu_maps)
+		return;
+
+	qsort(vcpu_maps, nr_vcpu_maps, sizeof(*map), cmp_map);
+}
+
+
+const char *tep_plugin_kvm_get_func(struct tep_event *event,
+				    struct tep_record *record,
+				    unsigned long long *val)
+{
+	struct tep_handle *tep;
+	struct kvm_cpu_map *map;
+	struct kvm_cpu_map key;
+	unsigned long long rip = *val;
+	const char *func;
+	int pid;
+
+	if (!vcpu_maps || !nr_vcpu_maps)
+		return NULL;
+
+	/*
+	 * A kvm event is referencing an address of the guest.
+	 * get the PID of this event, and then find which guest
+	 * it belongs to. Then return the function name from that guest's
+	 * handle.
+	 */
+	pid = tep_data_pid(event->tep, record);
+
+	key.host_pid = pid;
+	map = bsearch(&key, vcpu_maps, nr_vcpu_maps, sizeof(*vcpu_maps), cmp_map);
+
+	if (!map)
+		return NULL;
+
+	tep = tracecmd_get_tep(map->guest_handle);
+	func = tep_find_function(tep, rip);
+	if (func)
+		*val = tep_find_function_address(tep, rip);
+	return func;
+}
+
 static int process_record(struct tracecmd_input *handle, struct tep_record *record,
 			  int cpu, void *data)
 {
@@ -1192,6 +1284,8 @@ static void read_data_info(struct list_head *handle_list, enum output_type otype
 		handle_array[nr_handles++] = handles->handle;
 	}
 
+	map_vcpus(handle_array, nr_handles);
+
 	tracecmd_iterate_events_multi(handle_array, nr_handles,
 				      process_record, &last_timestamp);
 
-- 
2.35.1




[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux