@@ -112,6 +112,7 @@ enum {
TRACECMD_OPTION_TRACEID,
TRACECMD_OPTION_TIME_SHIFT,
TRACECMD_OPTION_GUEST,
+ TRACECMD_OPTION_PID_SYMBOLS,
};
enum {
@@ -262,6 +263,10 @@ unsigned int tracecmd_record_ts_delta(struct tracecmd_input *handle,
struct tracecmd_proc_addr_map *
tracecmd_search_task_map(struct tracecmd_input *handle,
int pid, unsigned long long addr);
+
+struct tracecmd_debug_symbols *
+tracecmd_search_task_symbol(struct tracecmd_input *handle,
+ int pid, unsigned long long addr);
#ifndef SWIG
/* hack for function graph work around */
extern __thread struct tracecmd_input *tracecmd_curr_thread_handle;
@@ -19,6 +19,8 @@
#include "trace-local.h"
#include "kbuffer.h"
#include "list.h"
+#include "trace-hash.h"
+#include "trace-hash-local.h"
#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)
@@ -98,6 +100,18 @@ struct host_trace_info {
struct ts_offset_sample *ts_samples;
};
+struct pid_function_map {
+ struct trace_hash_item hash;
+ struct tracecmd_debug_symbols symb;
+};
+
+struct pid_symbol_maps {
+ struct pid_symbol_maps *next;
+ int pid;
+ int symb_count;
+ struct trace_hash symbols;
+};
+
struct tracecmd_input {
struct tep_handle *pevent;
struct tep_plugin_list *plugin_list;
@@ -130,6 +144,7 @@ struct tracecmd_input {
struct hook_list *hooks;
struct pid_addr_maps *pid_maps;
+ struct pid_symbol_maps *pid_symbols;
/* file information */
size_t header_files_start;
size_t ftrace_files_start;
@@ -2430,6 +2445,92 @@ static int trace_pid_map_search(const void *a, const void *b)
return 0;
}
+static void trace_pid_symbols_free(struct pid_symbol_maps *maps)
+{
+ struct pid_symbol_maps *del;
+ struct pid_function_map *fmap;
+ struct trace_hash_item **bucket;
+ struct trace_hash_item *item;
+
+ while (maps) {
+ del = maps;
+ maps = maps->next;
+ trace_hash_for_each_bucket(bucket, &del->symbols) {
+ trace_hash_while_item(item, bucket) {
+ trace_hash_del(item);
+ fmap = (struct pid_function_map *)item;
+ free(fmap->symb.name);
+ free(fmap->symb.fname);
+ free(fmap);
+ }
+ }
+ trace_hash_free(&del->symbols);
+ }
+}
+
+#define MAX_FUNC_NAME 256
+static int trace_pid_symbols_load(struct tracecmd_input *handle, char *buf)
+{
+ struct pid_symbol_maps *maps = NULL;
+ struct pid_function_map *s;
+ char file[PATH_MAX];
+ char fname[MAX_FUNC_NAME];
+ char *line;
+ int res;
+ int ret;
+ int i;
+
+ maps = calloc(1, sizeof(*maps));
+ if (!maps)
+ return -ENOMEM;
+
+ ret = -EINVAL;
+ line = strchr(buf, '\n');
+ if (!line)
+ goto out_fail;
+
+ *line = '\0';
+ res = sscanf(buf, "%x %d", &maps->pid, &maps->symb_count);
+ if (res != 2)
+ goto out_fail;
+
+ ret = -ENOMEM;
+ if (trace_hash_init(&maps->symbols, 64) < 0)
+ goto out_fail;
+
+ buf = line + 1;
+ line = strchr(buf, '\n');
+ for (i = 0; i < maps->symb_count; i++) {
+ if (!line)
+ break;
+ *line = '\0';
+ s = calloc(1, sizeof(*s));
+ if (!s)
+ goto out_fail;
+ res = sscanf(buf, "%"STRINGIFY(PATH_MAX)"s %"STRINGIFY(MAX_FUNC_NAME)"s %llx %llx",
+ file, fname, &s->symb.vma_start, &s->symb.vma_near);
+ if (res != 4)
+ break;
+ s->symb.fname = strdup(file);
+ s->symb.name = strdup(fname);
+ if (!s->symb.fname || !s->symb.name)
+ goto out_fail;
+ s->hash.key = trace_hash(s->symb.vma_near);
+ trace_hash_add(&maps->symbols, (struct trace_hash_item *)s);
+ buf = line + 1;
+ line = strchr(buf, '\n');
+ }
+
+ maps->next = handle->pid_symbols;
+ handle->pid_symbols = maps;
+
+ return 0;
+
+out_fail:
+ trace_pid_symbols_free(maps);
+ return ret;
+}
+
/**
* tracecmd_search_task_map - Search task memory address map
* @handle: input handle to the trace.dat file
@@ -2469,6 +2570,43 @@ tracecmd_search_task_map(struct tracecmd_input *handle,
return lib;
}
+/**
+ * tracecmd_search_task_symbol - Resolve address to function name
+ * @handle: input handle to the trace.dat file
+ * @pid: pid of the task, which function information is stored in the trace.dat
+ * @addr: address of the function
+ *
+ * Mapping of some functions to addresses of traced PIDs can be saved in the
+ * trace.dat file, using the "perf" sub command. If there is such information,
+ * this API can be used to look up into this function maps to find the name of
+ * the function and the name of the file where that function is loaded.
+ *
+ * A pointer to struct tracecmd_debug_symbols is returned, containing information
+ * about the reuquested @addr: the name of the function, its start address, the
+ * name of the binary file that contains the function.
+ */
+struct tracecmd_debug_symbols *
+tracecmd_search_task_symbol(struct tracecmd_input *handle,
+ int pid, unsigned long long addr)
+{
+ struct pid_function_map *symb = NULL;
+ struct pid_symbol_maps *map;
+
+ for (map = handle->pid_symbols; map; map = map->next) {
+ if (pid == map->pid)
+ break;
+ }
+
+ if (map)
+ symb = (struct pid_function_map *)trace_hash_find(&map->symbols,
+ trace_hash(addr), NULL, NULL);
+
+ if (symb)
+ return &symb->symb;
+
+ return NULL;
+}
+
static int handle_options(struct tracecmd_input *handle)
{
long long offset;
@@ -2610,6 +2748,10 @@ static int handle_options(struct tracecmd_input *handle)
case TRACECMD_OPTION_GUEST:
trace_guest_load(handle, buf, size);
break;
+ case TRACECMD_OPTION_PID_SYMBOLS:
+ if (buf[size-1] == '\0')
+ trace_pid_symbols_load(handle, buf);
+ break;
default:
warning("unknown option %d", option);
break;
@@ -3352,6 +3494,8 @@ void tracecmd_close(struct tracecmd_input *handle)
trace_pid_map_free(handle->pid_maps);
handle->pid_maps = NULL;
+ trace_pid_symbols_free(handle->pid_symbols);
+ handle->pid_symbols = NULL;
trace_tsync_offset_free(&handle->host);
trace_guests_free(handle);
@@ -530,6 +530,9 @@ static void dump_options(int fd)
case TRACECMD_OPTION_GUEST:
dump_option_guest(fd, size);
break;
+ case TRACECMD_OPTION_PID_SYMBOLS:
+ dump_option_string(fd, size, "PIDSYMBOLS");
+ break;
default:
do_print(OPTIONS, " %d %d\t[Unknown option, size - skipping]\n",
option, size);
There are cases where resolving a user space address recorded in the trace file to function name is required, when this file is visualised. This mapping is available during the trace. A new trace.dat file option TRACECMD_OPTION_PID_SYMBOLS is added, for storing the mapping in the file. A new API is introduced, to resolve address to name, using information stored in the TRACECMD_OPTION_PID_SYMBOLS option: struct tracecmd_debug_symbols * tracecmd_search_task_symbol(struct tracecmd_input *handle, int pid, unsigned long long addr); Signed-off-by: Tzvetomir Stoyanov (VMware) <tz.stoyanov@gmail.com> --- include/trace-cmd/trace-cmd.h | 5 ++ lib/trace-cmd/trace-input.c | 144 ++++++++++++++++++++++++++++++++++ tracecmd/trace-dump.c | 3 + 3 files changed, 152 insertions(+)