aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-11-17 04:16:43 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-17 04:17:47 -0500
commita7b63425a41cd6a8d50f76fef0660c5110f97e91 (patch)
treebe17ee121f1c8814d8d39c9f3e0205d9397fab54 /tools/perf/util
parent35039eb6b199749943547c8572be6604edf00229 (diff)
parent3726cc75e581c157202da93bb2333cce25c15c98 (diff)
Merge branch 'perf/core' into perf/probes
Resolved merge conflict in tools/perf/Makefile Merge reason: we want to queue up a dependent patch. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/data_map.c31
-rw-r--r--tools/perf/util/data_map.h1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/debugfs.c241
-rw-r--r--tools/perf/util/debugfs.h25
-rw-r--r--tools/perf/util/event.c177
-rw-r--r--tools/perf/util/event.h23
-rw-r--r--tools/perf/util/header.c342
-rw-r--r--tools/perf/util/header.h46
-rw-r--r--tools/perf/util/include/linux/bitmap.h1
-rw-r--r--tools/perf/util/include/linux/ctype.h2
-rw-r--r--tools/perf/util/map.c84
-rw-r--r--tools/perf/util/parse-events.c43
-rw-r--r--tools/perf/util/string.c84
-rw-r--r--tools/perf/util/string.h1
-rw-r--r--tools/perf/util/symbol.c286
-rw-r--r--tools/perf/util/symbol.h49
-rw-r--r--tools/perf/util/util.h3
18 files changed, 1173 insertions, 268 deletions
diff --git a/tools/perf/util/data_map.c b/tools/perf/util/data_map.c
index 18accb8fee4d..14cb8465eb08 100644
--- a/tools/perf/util/data_map.c
+++ b/tools/perf/util/data_map.c
@@ -70,6 +70,35 @@ process_event(event_t *event, unsigned long offset, unsigned long head)
70 } 70 }
71} 71}
72 72
73int perf_header__read_build_ids(int input, off_t offset, off_t size)
74{
75 struct build_id_event bev;
76 char filename[PATH_MAX];
77 off_t limit = offset + size;
78 int err = -1;
79
80 while (offset < limit) {
81 struct dso *dso;
82 ssize_t len;
83
84 if (read(input, &bev, sizeof(bev)) != sizeof(bev))
85 goto out;
86
87 len = bev.header.size - sizeof(bev);
88 if (read(input, filename, len) != len)
89 goto out;
90
91 dso = dsos__findnew(filename);
92 if (dso != NULL)
93 dso__set_build_id(dso, &bev.build_id);
94
95 offset += bev.header.size;
96 }
97 err = 0;
98out:
99 return err;
100}
101
73int mmap_dispatch_perf_file(struct perf_header **pheader, 102int mmap_dispatch_perf_file(struct perf_header **pheader,
74 const char *input_name, 103 const char *input_name,
75 int force, 104 int force,
@@ -130,7 +159,7 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
130 if (curr_handler->sample_type_check(sample_type) < 0) 159 if (curr_handler->sample_type_check(sample_type) < 0)
131 exit(-1); 160 exit(-1);
132 161
133 if (load_kernel(0, NULL) < 0) { 162 if (load_kernel(NULL) < 0) {
134 perror("failed to load kernel symbols"); 163 perror("failed to load kernel symbols");
135 return EXIT_FAILURE; 164 return EXIT_FAILURE;
136 } 165 }
diff --git a/tools/perf/util/data_map.h b/tools/perf/util/data_map.h
index 716d1053b074..ae036ecd7625 100644
--- a/tools/perf/util/data_map.h
+++ b/tools/perf/util/data_map.h
@@ -27,5 +27,6 @@ int mmap_dispatch_perf_file(struct perf_header **pheader,
27 int full_paths, 27 int full_paths,
28 int *cwdlen, 28 int *cwdlen,
29 char **cwd); 29 char **cwd);
30int perf_header__read_build_ids(int input, off_t offset, off_t file_size);
30 31
31#endif 32#endif
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index e8b18a1f87a4..c6c24c522dea 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -2,6 +2,8 @@
2#ifndef __PERF_DEBUG_H 2#ifndef __PERF_DEBUG_H
3#define __PERF_DEBUG_H 3#define __PERF_DEBUG_H
4 4
5#include "event.h"
6
5extern int verbose; 7extern int verbose;
6extern int dump_trace; 8extern int dump_trace;
7 9
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c
new file mode 100644
index 000000000000..06b73ee02c49
--- /dev/null
+++ b/tools/perf/util/debugfs.c
@@ -0,0 +1,241 @@
1#include "util.h"
2#include "debugfs.h"
3#include "cache.h"
4
5static int debugfs_premounted;
6static char debugfs_mountpoint[MAX_PATH+1];
7
8static const char *debugfs_known_mountpoints[] = {
9 "/sys/kernel/debug/",
10 "/debug/",
11 0,
12};
13
14/* use this to force a umount */
15void debugfs_force_cleanup(void)
16{
17 debugfs_find_mountpoint();
18 debugfs_premounted = 0;
19 debugfs_umount();
20}
21
22/* construct a full path to a debugfs element */
23int debugfs_make_path(const char *element, char *buffer, int size)
24{
25 int len;
26
27 if (strlen(debugfs_mountpoint) == 0) {
28 buffer[0] = '\0';
29 return -1;
30 }
31
32 len = strlen(debugfs_mountpoint) + strlen(element) + 1;
33 if (len >= size)
34 return len+1;
35
36 snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
37 return 0;
38}
39
40static int debugfs_found;
41
42/* find the path to the mounted debugfs */
43const char *debugfs_find_mountpoint(void)
44{
45 const char **ptr;
46 char type[100];
47 FILE *fp;
48
49 if (debugfs_found)
50 return (const char *) debugfs_mountpoint;
51
52 ptr = debugfs_known_mountpoints;
53 while (*ptr) {
54 if (debugfs_valid_mountpoint(*ptr) == 0) {
55 debugfs_found = 1;
56 strcpy(debugfs_mountpoint, *ptr);
57 return debugfs_mountpoint;
58 }
59 ptr++;
60 }
61
62 /* give up and parse /proc/mounts */
63 fp = fopen("/proc/mounts", "r");
64 if (fp == NULL)
65 die("Can't open /proc/mounts for read");
66
67 while (fscanf(fp, "%*s %"
68 STR(MAX_PATH)
69 "s %99s %*s %*d %*d\n",
70 debugfs_mountpoint, type) == 2) {
71 if (strcmp(type, "debugfs") == 0)
72 break;
73 }
74 fclose(fp);
75
76 if (strcmp(type, "debugfs") != 0)
77 return NULL;
78
79 debugfs_found = 1;
80
81 return debugfs_mountpoint;
82}
83
84/* verify that a mountpoint is actually a debugfs instance */
85
86int debugfs_valid_mountpoint(const char *debugfs)
87{
88 struct statfs st_fs;
89
90 if (statfs(debugfs, &st_fs) < 0)
91 return -ENOENT;
92 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
93 return -ENOENT;
94
95 return 0;
96}
97
98
99int debugfs_valid_entry(const char *path)
100{
101 struct stat st;
102
103 if (stat(path, &st))
104 return -errno;
105
106 return 0;
107}
108
109/* mount the debugfs somewhere */
110
111int debugfs_mount(const char *mountpoint)
112{
113 char mountcmd[128];
114
115 /* see if it's already mounted */
116 if (debugfs_find_mountpoint()) {
117 debugfs_premounted = 1;
118 return 0;
119 }
120
121 /* if not mounted and no argument */
122 if (mountpoint == NULL) {
123 /* see if environment variable set */
124 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
125 /* if no environment variable, use default */
126 if (mountpoint == NULL)
127 mountpoint = "/sys/kernel/debug";
128 }
129
130 /* save the mountpoint */
131 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
132
133 /* mount it */
134 snprintf(mountcmd, sizeof(mountcmd),
135 "/bin/mount -t debugfs debugfs %s", mountpoint);
136 return system(mountcmd);
137}
138
139/* umount the debugfs */
140
141int debugfs_umount(void)
142{
143 char umountcmd[128];
144 int ret;
145
146 /* if it was already mounted, leave it */
147 if (debugfs_premounted)
148 return 0;
149
150 /* make sure it's a valid mount point */
151 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
152 if (ret)
153 return ret;
154
155 snprintf(umountcmd, sizeof(umountcmd),
156 "/bin/umount %s", debugfs_mountpoint);
157 return system(umountcmd);
158}
159
160int debugfs_write(const char *entry, const char *value)
161{
162 char path[MAX_PATH+1];
163 int ret, count;
164 int fd;
165
166 /* construct the path */
167 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
168
169 /* verify that it exists */
170 ret = debugfs_valid_entry(path);
171 if (ret)
172 return ret;
173
174 /* get how many chars we're going to write */
175 count = strlen(value);
176
177 /* open the debugfs entry */
178 fd = open(path, O_RDWR);
179 if (fd < 0)
180 return -errno;
181
182 while (count > 0) {
183 /* write it */
184 ret = write(fd, value, count);
185 if (ret <= 0) {
186 if (ret == EAGAIN)
187 continue;
188 close(fd);
189 return -errno;
190 }
191 count -= ret;
192 }
193
194 /* close it */
195 close(fd);
196
197 /* return success */
198 return 0;
199}
200
201/*
202 * read a debugfs entry
203 * returns the number of chars read or a negative errno
204 */
205int debugfs_read(const char *entry, char *buffer, size_t size)
206{
207 char path[MAX_PATH+1];
208 int ret;
209 int fd;
210
211 /* construct the path */
212 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
213
214 /* verify that it exists */
215 ret = debugfs_valid_entry(path);
216 if (ret)
217 return ret;
218
219 /* open the debugfs entry */
220 fd = open(path, O_RDONLY);
221 if (fd < 0)
222 return -errno;
223
224 do {
225 /* read it */
226 ret = read(fd, buffer, size);
227 if (ret == 0) {
228 close(fd);
229 return EOF;
230 }
231 } while (ret < 0 && errno == EAGAIN);
232
233 /* close it */
234 close(fd);
235
236 /* make *sure* there's a null character at the end */
237 buffer[ret] = '\0';
238
239 /* return the number of chars read */
240 return ret;
241}
diff --git a/tools/perf/util/debugfs.h b/tools/perf/util/debugfs.h
new file mode 100644
index 000000000000..3cd14f9ae784
--- /dev/null
+++ b/tools/perf/util/debugfs.h
@@ -0,0 +1,25 @@
1#ifndef __DEBUGFS_H__
2#define __DEBUGFS_H__
3
4#include <sys/mount.h>
5
6#ifndef MAX_PATH
7# define MAX_PATH 256
8#endif
9
10#ifndef STR
11# define _STR(x) #x
12# define STR(x) _STR(x)
13#endif
14
15extern const char *debugfs_find_mountpoint(void);
16extern int debugfs_valid_mountpoint(const char *debugfs);
17extern int debugfs_valid_entry(const char *path);
18extern int debugfs_mount(const char *mountpoint);
19extern int debugfs_umount(void);
20extern int debugfs_write(const char *entry, const char *value);
21extern int debugfs_read(const char *entry, char *buffer, size_t size);
22extern void debugfs_force_cleanup(void);
23extern int debugfs_make_path(const char *element, char *buffer, int size);
24
25#endif /* __DEBUGFS_H__ */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
new file mode 100644
index 000000000000..1dae7e3b400d
--- /dev/null
+++ b/tools/perf/util/event.c
@@ -0,0 +1,177 @@
1#include <linux/types.h>
2#include "event.h"
3#include "debug.h"
4#include "string.h"
5
6static pid_t event__synthesize_comm(pid_t pid, int full,
7 int (*process)(event_t *event))
8{
9 event_t ev;
10 char filename[PATH_MAX];
11 char bf[BUFSIZ];
12 FILE *fp;
13 size_t size = 0;
14 DIR *tasks;
15 struct dirent dirent, *next;
16 pid_t tgid = 0;
17
18 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
19
20 fp = fopen(filename, "r");
21 if (fp == NULL) {
22out_race:
23 /*
24 * We raced with a task exiting - just return:
25 */
26 pr_debug("couldn't open %s\n", filename);
27 return 0;
28 }
29
30 memset(&ev.comm, 0, sizeof(ev.comm));
31 while (!ev.comm.comm[0] || !ev.comm.pid) {
32 if (fgets(bf, sizeof(bf), fp) == NULL)
33 goto out_failure;
34
35 if (memcmp(bf, "Name:", 5) == 0) {
36 char *name = bf + 5;
37 while (*name && isspace(*name))
38 ++name;
39 size = strlen(name) - 1;
40 memcpy(ev.comm.comm, name, size++);
41 } else if (memcmp(bf, "Tgid:", 5) == 0) {
42 char *tgids = bf + 5;
43 while (*tgids && isspace(*tgids))
44 ++tgids;
45 tgid = ev.comm.pid = atoi(tgids);
46 }
47 }
48
49 ev.comm.header.type = PERF_RECORD_COMM;
50 size = ALIGN(size, sizeof(u64));
51 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size);
52
53 if (!full) {
54 ev.comm.tid = pid;
55
56 process(&ev);
57 goto out_fclose;
58 }
59
60 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
61
62 tasks = opendir(filename);
63 if (tasks == NULL)
64 goto out_race;
65
66 while (!readdir_r(tasks, &dirent, &next) && next) {
67 char *end;
68 pid = strtol(dirent.d_name, &end, 10);
69 if (*end)
70 continue;
71
72 ev.comm.tid = pid;
73
74 process(&ev);
75 }
76 closedir(tasks);
77
78out_fclose:
79 fclose(fp);
80 return tgid;
81
82out_failure:
83 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
84 return -1;
85}
86
87static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
88 int (*process)(event_t *event))
89{
90 char filename[PATH_MAX];
91 FILE *fp;
92
93 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
94
95 fp = fopen(filename, "r");
96 if (fp == NULL) {
97 /*
98 * We raced with a task exiting - just return:
99 */
100 pr_debug("couldn't open %s\n", filename);
101 return -1;
102 }
103
104 while (1) {
105 char bf[BUFSIZ], *pbf = bf;
106 event_t ev = {
107 .header = { .type = PERF_RECORD_MMAP },
108 };
109 int n;
110 size_t size;
111 if (fgets(bf, sizeof(bf), fp) == NULL)
112 break;
113
114 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
115 n = hex2u64(pbf, &ev.mmap.start);
116 if (n < 0)
117 continue;
118 pbf += n + 1;
119 n = hex2u64(pbf, &ev.mmap.len);
120 if (n < 0)
121 continue;
122 pbf += n + 3;
123 if (*pbf == 'x') { /* vm_exec */
124 char *execname = strchr(bf, '/');
125
126 /* Catch VDSO */
127 if (execname == NULL)
128 execname = strstr(bf, "[vdso]");
129
130 if (execname == NULL)
131 continue;
132
133 size = strlen(execname);
134 execname[size - 1] = '\0'; /* Remove \n */
135 memcpy(ev.mmap.filename, execname, size);
136 size = ALIGN(size, sizeof(u64));
137 ev.mmap.len -= ev.mmap.start;
138 ev.mmap.header.size = (sizeof(ev.mmap) -
139 (sizeof(ev.mmap.filename) - size));
140 ev.mmap.pid = tgid;
141 ev.mmap.tid = pid;
142
143 process(&ev);
144 }
145 }
146
147 fclose(fp);
148 return 0;
149}
150
151int event__synthesize_thread(pid_t pid, int (*process)(event_t *event))
152{
153 pid_t tgid = event__synthesize_comm(pid, 1, process);
154 if (tgid == -1)
155 return -1;
156 return event__synthesize_mmap_events(pid, tgid, process);
157}
158
159void event__synthesize_threads(int (*process)(event_t *event))
160{
161 DIR *proc;
162 struct dirent dirent, *next;
163
164 proc = opendir("/proc");
165
166 while (!readdir_r(proc, &dirent, &next) && next) {
167 char *end;
168 pid_t pid = strtol(dirent.d_name, &end, 10);
169
170 if (*end) /* only interested in proper numerical dirents */
171 continue;
172
173 event__synthesize_thread(pid, process);
174 }
175
176 closedir(proc);
177}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d972b4b0d38c..1f771ce3a957 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -61,6 +61,20 @@ struct sample_event{
61 u64 array[]; 61 u64 array[];
62}; 62};
63 63
64#define BUILD_ID_SIZE 20
65
66struct build_id_event {
67 struct perf_event_header header;
68 u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
69 char filename[];
70};
71
72struct build_id_list {
73 struct build_id_event event;
74 struct list_head list;
75 const char *dso_name;
76 int len;
77};
64 78
65typedef union event_union { 79typedef union event_union {
66 struct perf_event_header header; 80 struct perf_event_header header;
@@ -105,10 +119,15 @@ struct symbol;
105 119
106typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); 120typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
107 121
108struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, 122void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
109 unsigned int sym_priv_size, symbol_filter_t filter); 123 struct dso *dso);
124struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen);
110struct map *map__clone(struct map *self); 125struct map *map__clone(struct map *self);
111int map__overlap(struct map *l, struct map *r); 126int map__overlap(struct map *l, struct map *r);
112size_t map__fprintf(struct map *self, FILE *fp); 127size_t map__fprintf(struct map *self, FILE *fp);
128struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter);
129
130int event__synthesize_thread(pid_t pid, int (*process)(event_t *event));
131void event__synthesize_threads(int (*process)(event_t *event));
113 132
114#endif /* __PERF_RECORD_H */ 133#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 7d26659b806c..b01a9537977f 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2,11 +2,15 @@
2#include <unistd.h> 2#include <unistd.h>
3#include <stdio.h> 3#include <stdio.h>
4#include <stdlib.h> 4#include <stdlib.h>
5#include <linux/list.h>
5 6
6#include "util.h" 7#include "util.h"
7#include "header.h" 8#include "header.h"
8#include "../perf.h" 9#include "../perf.h"
9#include "trace-event.h" 10#include "trace-event.h"
11#include "symbol.h"
12#include "data_map.h"
13#include "debug.h"
10 14
11/* 15/*
12 * Create new perf.data header attribute: 16 * Create new perf.data header attribute:
@@ -15,32 +19,43 @@ struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr)
15{ 19{
16 struct perf_header_attr *self = malloc(sizeof(*self)); 20 struct perf_header_attr *self = malloc(sizeof(*self));
17 21
18 if (!self) 22 if (self != NULL) {
19 die("nomem"); 23 self->attr = *attr;
20 24 self->ids = 0;
21 self->attr = *attr; 25 self->size = 1;
22 self->ids = 0; 26 self->id = malloc(sizeof(u64));
23 self->size = 1; 27 if (self->id == NULL) {
24 self->id = malloc(sizeof(u64)); 28 free(self);
25 29 self = NULL;
26 if (!self->id) 30 }
27 die("nomem"); 31 }
28 32
29 return self; 33 return self;
30} 34}
31 35
32void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) 36void perf_header_attr__delete(struct perf_header_attr *self)
37{
38 free(self->id);
39 free(self);
40}
41
42int perf_header_attr__add_id(struct perf_header_attr *self, u64 id)
33{ 43{
34 int pos = self->ids; 44 int pos = self->ids;
35 45
36 self->ids++; 46 self->ids++;
37 if (self->ids > self->size) { 47 if (self->ids > self->size) {
38 self->size *= 2; 48 int nsize = self->size * 2;
39 self->id = realloc(self->id, self->size * sizeof(u64)); 49 u64 *nid = realloc(self->id, nsize * sizeof(u64));
40 if (!self->id) 50
41 die("nomem"); 51 if (nid == NULL)
52 return -1;
53
54 self->size = nsize;
55 self->id = nid;
42 } 56 }
43 self->id[pos] = id; 57 self->id[pos] = id;
58 return 0;
44} 59}
45 60
46/* 61/*
@@ -50,34 +65,41 @@ struct perf_header *perf_header__new(void)
50{ 65{
51 struct perf_header *self = calloc(sizeof(*self), 1); 66 struct perf_header *self = calloc(sizeof(*self), 1);
52 67
53 if (!self) 68 if (self != NULL) {
54 die("nomem"); 69 self->size = 1;
55 70 self->attr = malloc(sizeof(void *));
56 self->size = 1;
57 self->attr = malloc(sizeof(void *));
58 71
59 if (!self->attr) 72 if (self->attr == NULL) {
60 die("nomem"); 73 free(self);
74 self = NULL;
75 }
76 }
61 77
62 return self; 78 return self;
63} 79}
64 80
65void perf_header__add_attr(struct perf_header *self, 81int perf_header__add_attr(struct perf_header *self,
66 struct perf_header_attr *attr) 82 struct perf_header_attr *attr)
67{ 83{
68 int pos = self->attrs; 84 int pos = self->attrs;
69 85
70 if (self->frozen) 86 if (self->frozen)
71 die("frozen"); 87 return -1;
72 88
73 self->attrs++; 89 self->attrs++;
74 if (self->attrs > self->size) { 90 if (self->attrs > self->size) {
75 self->size *= 2; 91 int nsize = self->size * 2;
76 self->attr = realloc(self->attr, self->size * sizeof(void *)); 92 struct perf_header_attr **nattr;
77 if (!self->attr) 93
78 die("nomem"); 94 nattr = realloc(self->attr, nsize * sizeof(void *));
95 if (nattr == NULL)
96 return -1;
97
98 self->size = nsize;
99 self->attr = nattr;
79 } 100 }
80 self->attr[pos] = attr; 101 self->attr[pos] = attr;
102 return 0;
81} 103}
82 104
83#define MAX_EVENT_NAME 64 105#define MAX_EVENT_NAME 64
@@ -124,71 +146,110 @@ static const char *__perf_magic = "PERFFILE";
124 146
125#define PERF_MAGIC (*(u64 *)__perf_magic) 147#define PERF_MAGIC (*(u64 *)__perf_magic)
126 148
127struct perf_file_section {
128 u64 offset;
129 u64 size;
130};
131
132struct perf_file_attr { 149struct perf_file_attr {
133 struct perf_event_attr attr; 150 struct perf_event_attr attr;
134 struct perf_file_section ids; 151 struct perf_file_section ids;
135}; 152};
136 153
137struct perf_file_header { 154void perf_header__set_feat(struct perf_header *self, int feat)
138 u64 magic; 155{
139 u64 size; 156 set_bit(feat, self->adds_features);
140 u64 attr_size; 157}
141 struct perf_file_section attrs;
142 struct perf_file_section data;
143 struct perf_file_section event_types;
144 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
145};
146 158
147void perf_header__feat_trace_info(struct perf_header *header) 159bool perf_header__has_feat(const struct perf_header *self, int feat)
148{ 160{
149 set_bit(HEADER_TRACE_INFO, header->adds_features); 161 return test_bit(feat, self->adds_features);
150} 162}
151 163
152static void do_write(int fd, void *buf, size_t size) 164static int do_write(int fd, const void *buf, size_t size)
153{ 165{
154 while (size) { 166 while (size) {
155 int ret = write(fd, buf, size); 167 int ret = write(fd, buf, size);
156 168
157 if (ret < 0) 169 if (ret < 0)
158 die("failed to write"); 170 return -1;
159 171
160 size -= ret; 172 size -= ret;
161 buf += ret; 173 buf += ret;
162 } 174 }
175
176 return 0;
177}
178
179static int write_buildid_table(int fd, struct list_head *id_head)
180{
181 struct build_id_list *iter, *next;
182
183 list_for_each_entry_safe(iter, next, id_head, list) {
184 struct build_id_event *b = &iter->event;
185
186 if (do_write(fd, b, sizeof(*b)) < 0 ||
187 do_write(fd, iter->dso_name, iter->len) < 0)
188 return -1;
189 list_del(&iter->list);
190 free(iter);
191 }
192
193 return 0;
163} 194}
164 195
165static void perf_header__adds_write(struct perf_header *self, int fd) 196static void
197perf_header__adds_write(struct perf_header *self, int fd)
166{ 198{
167 struct perf_file_section trace_sec; 199 LIST_HEAD(id_list);
168 u64 cur_offset = lseek(fd, 0, SEEK_CUR); 200 int nr_sections;
169 unsigned long *feat_mask = self->adds_features; 201 struct perf_file_section *feat_sec;
202 int sec_size;
203 u64 sec_start;
204 int idx = 0;
205
206 if (fetch_build_id_table(&id_list))
207 perf_header__set_feat(self, HEADER_BUILD_ID);
208
209 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
210 if (!nr_sections)
211 return;
212
213 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
214 if (!feat_sec)
215 die("No memory");
216
217 sec_size = sizeof(*feat_sec) * nr_sections;
218
219 sec_start = self->data_offset + self->data_size;
220 lseek(fd, sec_start + sec_size, SEEK_SET);
221
222 if (perf_header__has_feat(self, HEADER_TRACE_INFO)) {
223 struct perf_file_section *trace_sec;
224
225 trace_sec = &feat_sec[idx++];
170 226
171 if (test_bit(HEADER_TRACE_INFO, feat_mask)) {
172 /* Write trace info */ 227 /* Write trace info */
173 trace_sec.offset = lseek(fd, sizeof(trace_sec), SEEK_CUR); 228 trace_sec->offset = lseek(fd, 0, SEEK_CUR);
174 read_tracing_data(fd, attrs, nr_counters); 229 read_tracing_data(fd, attrs, nr_counters);
175 trace_sec.size = lseek(fd, 0, SEEK_CUR) - trace_sec.offset; 230 trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset;
176
177 /* Write trace info headers */
178 lseek(fd, cur_offset, SEEK_SET);
179 do_write(fd, &trace_sec, sizeof(trace_sec));
180
181 /*
182 * Update cur_offset. So that other (future)
183 * features can set their own infos in this place. But if we are
184 * the only feature, at least that seeks to the place the data
185 * should begin.
186 */
187 cur_offset = lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET);
188 } 231 }
189};
190 232
191void perf_header__write(struct perf_header *self, int fd) 233
234 if (perf_header__has_feat(self, HEADER_BUILD_ID)) {
235 struct perf_file_section *buildid_sec;
236
237 buildid_sec = &feat_sec[idx++];
238
239 /* Write build-ids */
240 buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
241 if (write_buildid_table(fd, &id_list) < 0)
242 die("failed to write buildid table");
243 buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset;
244 }
245
246 lseek(fd, sec_start, SEEK_SET);
247 if (do_write(fd, feat_sec, sec_size) < 0)
248 die("failed to write feature section");
249 free(feat_sec);
250}
251
252void perf_header__write(struct perf_header *self, int fd, bool at_exit)
192{ 253{
193 struct perf_file_header f_header; 254 struct perf_file_header f_header;
194 struct perf_file_attr f_attr; 255 struct perf_file_attr f_attr;
@@ -202,7 +263,8 @@ void perf_header__write(struct perf_header *self, int fd)
202 attr = self->attr[i]; 263 attr = self->attr[i];
203 264
204 attr->id_offset = lseek(fd, 0, SEEK_CUR); 265 attr->id_offset = lseek(fd, 0, SEEK_CUR);
205 do_write(fd, attr->id, attr->ids * sizeof(u64)); 266 if (do_write(fd, attr->id, attr->ids * sizeof(u64)) < 0)
267 die("failed to write perf header");
206 } 268 }
207 269
208 270
@@ -218,18 +280,21 @@ void perf_header__write(struct perf_header *self, int fd)
218 .size = attr->ids * sizeof(u64), 280 .size = attr->ids * sizeof(u64),
219 } 281 }
220 }; 282 };
221 do_write(fd, &f_attr, sizeof(f_attr)); 283 if (do_write(fd, &f_attr, sizeof(f_attr)) < 0)
284 die("failed to write perf header attribute");
222 } 285 }
223 286
224 self->event_offset = lseek(fd, 0, SEEK_CUR); 287 self->event_offset = lseek(fd, 0, SEEK_CUR);
225 self->event_size = event_count * sizeof(struct perf_trace_event_type); 288 self->event_size = event_count * sizeof(struct perf_trace_event_type);
226 if (events) 289 if (events)
227 do_write(fd, events, self->event_size); 290 if (do_write(fd, events, self->event_size) < 0)
228 291 die("failed to write perf header events");
229 perf_header__adds_write(self, fd);
230 292
231 self->data_offset = lseek(fd, 0, SEEK_CUR); 293 self->data_offset = lseek(fd, 0, SEEK_CUR);
232 294
295 if (at_exit)
296 perf_header__adds_write(self, fd);
297
233 f_header = (struct perf_file_header){ 298 f_header = (struct perf_file_header){
234 .magic = PERF_MAGIC, 299 .magic = PERF_MAGIC,
235 .size = sizeof(f_header), 300 .size = sizeof(f_header),
@@ -251,7 +316,8 @@ void perf_header__write(struct perf_header *self, int fd)
251 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features)); 316 memcpy(&f_header.adds_features, &self->adds_features, sizeof(self->adds_features));
252 317
253 lseek(fd, 0, SEEK_SET); 318 lseek(fd, 0, SEEK_SET);
254 do_write(fd, &f_header, sizeof(f_header)); 319 if (do_write(fd, &f_header, sizeof(f_header)) < 0)
320 die("failed to write perf header");
255 lseek(fd, self->data_offset + self->data_size, SEEK_SET); 321 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
256 322
257 self->frozen = 1; 323 self->frozen = 1;
@@ -272,43 +338,112 @@ static void do_read(int fd, void *buf, size_t size)
272 } 338 }
273} 339}
274 340
275static void perf_header__adds_read(struct perf_header *self, int fd) 341int perf_header__process_sections(struct perf_header *self, int fd,
342 int (*process)(struct perf_file_section *self,
343 int feat, int fd))
276{ 344{
277 const unsigned long *feat_mask = self->adds_features; 345 struct perf_file_section *feat_sec;
346 int nr_sections;
347 int sec_size;
348 int idx = 0;
349 int err = 0, feat = 1;
278 350
279 if (test_bit(HEADER_TRACE_INFO, feat_mask)) { 351 nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
280 struct perf_file_section trace_sec; 352 if (!nr_sections)
353 return 0;
281 354
282 do_read(fd, &trace_sec, sizeof(trace_sec)); 355 feat_sec = calloc(sizeof(*feat_sec), nr_sections);
283 lseek(fd, trace_sec.offset, SEEK_SET); 356 if (!feat_sec)
284 trace_report(fd); 357 return -1;
285 lseek(fd, trace_sec.offset + trace_sec.size, SEEK_SET); 358
359 sec_size = sizeof(*feat_sec) * nr_sections;
360
361 lseek(fd, self->data_offset + self->data_size, SEEK_SET);
362
363 do_read(fd, feat_sec, sec_size);
364
365 while (idx < nr_sections && feat < HEADER_LAST_FEATURE) {
366 if (perf_header__has_feat(self, feat)) {
367 struct perf_file_section *sec = &feat_sec[idx++];
368
369 err = process(sec, feat, fd);
370 if (err < 0)
371 break;
372 }
373 ++feat;
286 } 374 }
375
376 free(feat_sec);
377 return err;
287}; 378};
288 379
380int perf_file_header__read(struct perf_file_header *self,
381 struct perf_header *ph, int fd)
382{
383 lseek(fd, 0, SEEK_SET);
384 do_read(fd, self, sizeof(*self));
385
386 if (self->magic != PERF_MAGIC ||
387 self->attr_size != sizeof(struct perf_file_attr))
388 return -1;
389
390 if (self->size != sizeof(*self)) {
391 /* Support the previous format */
392 if (self->size == offsetof(typeof(*self), adds_features))
393 bitmap_zero(self->adds_features, HEADER_FEAT_BITS);
394 else
395 return -1;
396 }
397
398 memcpy(&ph->adds_features, &self->adds_features,
399 sizeof(self->adds_features));
400
401 ph->event_offset = self->event_types.offset;
402 ph->event_size = self->event_types.size;
403 ph->data_offset = self->data.offset;
404 ph->data_size = self->data.size;
405 return 0;
406}
407
408static int perf_file_section__process(struct perf_file_section *self,
409 int feat, int fd)
410{
411 if (lseek(fd, self->offset, SEEK_SET) < 0) {
412 pr_debug("Failed to lseek to %Ld offset for feature %d, "
413 "continuing...\n", self->offset, feat);
414 return 0;
415 }
416
417 switch (feat) {
418 case HEADER_TRACE_INFO:
419 trace_report(fd);
420 break;
421
422 case HEADER_BUILD_ID:
423 if (perf_header__read_build_ids(fd, self->offset, self->size))
424 pr_debug("Failed to read buildids, continuing...\n");
425 break;
426 default:
427 pr_debug("unknown feature %d, continuing...\n", feat);
428 }
429
430 return 0;
431}
432
289struct perf_header *perf_header__read(int fd) 433struct perf_header *perf_header__read(int fd)
290{ 434{
291 struct perf_header *self = perf_header__new(); 435 struct perf_header *self = perf_header__new();
292 struct perf_file_header f_header; 436 struct perf_file_header f_header;
293 struct perf_file_attr f_attr; 437 struct perf_file_attr f_attr;
294 u64 f_id; 438 u64 f_id;
295
296 int nr_attrs, nr_ids, i, j; 439 int nr_attrs, nr_ids, i, j;
297 440
298 lseek(fd, 0, SEEK_SET); 441 if (self == NULL)
299 do_read(fd, &f_header, sizeof(f_header)); 442 die("nomem");
300 443
301 if (f_header.magic != PERF_MAGIC || 444 if (perf_file_header__read(&f_header, self, fd) < 0)
302 f_header.attr_size != sizeof(f_attr))
303 die("incompatible file format"); 445 die("incompatible file format");
304 446
305 if (f_header.size != sizeof(f_header)) {
306 /* Support the previous format */
307 if (f_header.size == offsetof(typeof(f_header), adds_features))
308 bitmap_zero(f_header.adds_features, HEADER_FEAT_BITS);
309 else
310 die("incompatible file format");
311 }
312 nr_attrs = f_header.attrs.size / sizeof(f_attr); 447 nr_attrs = f_header.attrs.size / sizeof(f_attr);
313 lseek(fd, f_header.attrs.offset, SEEK_SET); 448 lseek(fd, f_header.attrs.offset, SEEK_SET);
314 449
@@ -320,6 +455,8 @@ struct perf_header *perf_header__read(int fd)
320 tmp = lseek(fd, 0, SEEK_CUR); 455 tmp = lseek(fd, 0, SEEK_CUR);
321 456
322 attr = perf_header_attr__new(&f_attr.attr); 457 attr = perf_header_attr__new(&f_attr.attr);
458 if (attr == NULL)
459 die("nomem");
323 460
324 nr_ids = f_attr.ids.size / sizeof(u64); 461 nr_ids = f_attr.ids.size / sizeof(u64);
325 lseek(fd, f_attr.ids.offset, SEEK_SET); 462 lseek(fd, f_attr.ids.offset, SEEK_SET);
@@ -327,9 +464,12 @@ struct perf_header *perf_header__read(int fd)
327 for (j = 0; j < nr_ids; j++) { 464 for (j = 0; j < nr_ids; j++) {
328 do_read(fd, &f_id, sizeof(f_id)); 465 do_read(fd, &f_id, sizeof(f_id));
329 466
330 perf_header_attr__add_id(attr, f_id); 467 if (perf_header_attr__add_id(attr, f_id) < 0)
468 die("nomem");
331 } 469 }
332 perf_header__add_attr(self, attr); 470 if (perf_header__add_attr(self, attr) < 0)
471 die("nomem");
472
333 lseek(fd, tmp, SEEK_SET); 473 lseek(fd, tmp, SEEK_SET);
334 } 474 }
335 475
@@ -342,15 +482,7 @@ struct perf_header *perf_header__read(int fd)
342 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); 482 event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
343 } 483 }
344 484
345 memcpy(&self->adds_features, &f_header.adds_features, sizeof(f_header.adds_features)); 485 perf_header__process_sections(self, fd, perf_file_section__process);
346
347 perf_header__adds_read(self, fd);
348
349 self->event_offset = f_header.event_types.offset;
350 self->event_size = f_header.event_types.size;
351
352 self->data_offset = f_header.data.offset;
353 self->data_size = f_header.data.size;
354 486
355 lseek(fd, self->data_offset, SEEK_SET); 487 lseek(fd, self->data_offset, SEEK_SET);
356 488
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 2ea9dfb1236a..f46a94e09eea 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -3,6 +3,7 @@
3 3
4#include "../../../include/linux/perf_event.h" 4#include "../../../include/linux/perf_event.h"
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h>
6#include "types.h" 7#include "types.h"
7 8
8#include <linux/bitmap.h> 9#include <linux/bitmap.h>
@@ -14,10 +15,34 @@ struct perf_header_attr {
14 off_t id_offset; 15 off_t id_offset;
15}; 16};
16 17
17#define HEADER_TRACE_INFO 1 18enum {
19 HEADER_TRACE_INFO = 1,
20 HEADER_BUILD_ID,
21 HEADER_LAST_FEATURE,
22};
18 23
19#define HEADER_FEAT_BITS 256 24#define HEADER_FEAT_BITS 256
20 25
26struct perf_file_section {
27 u64 offset;
28 u64 size;
29};
30
31struct perf_file_header {
32 u64 magic;
33 u64 size;
34 u64 attr_size;
35 struct perf_file_section attrs;
36 struct perf_file_section data;
37 struct perf_file_section event_types;
38 DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
39};
40
41struct perf_header;
42
43int perf_file_header__read(struct perf_file_header *self,
44 struct perf_header *ph, int fd);
45
21struct perf_header { 46struct perf_header {
22 int frozen; 47 int frozen;
23 int attrs, size; 48 int attrs, size;
@@ -31,24 +56,29 @@ struct perf_header {
31}; 56};
32 57
33struct perf_header *perf_header__read(int fd); 58struct perf_header *perf_header__read(int fd);
34void perf_header__write(struct perf_header *self, int fd); 59void perf_header__write(struct perf_header *self, int fd, bool at_exit);
35 60
36void perf_header__add_attr(struct perf_header *self, 61int perf_header__add_attr(struct perf_header *self,
37 struct perf_header_attr *attr); 62 struct perf_header_attr *attr);
38 63
39void perf_header__push_event(u64 id, const char *name); 64void perf_header__push_event(u64 id, const char *name);
40char *perf_header__find_event(u64 id); 65char *perf_header__find_event(u64 id);
41 66
67struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr);
68void perf_header_attr__delete(struct perf_header_attr *self);
42 69
43struct perf_header_attr * 70int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
44perf_header_attr__new(struct perf_event_attr *attr);
45void perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
46 71
47u64 perf_header__sample_type(struct perf_header *header); 72u64 perf_header__sample_type(struct perf_header *header);
48struct perf_event_attr * 73struct perf_event_attr *
49perf_header__find_attr(u64 id, struct perf_header *header); 74perf_header__find_attr(u64 id, struct perf_header *header);
50void perf_header__feat_trace_info(struct perf_header *header); 75void perf_header__set_feat(struct perf_header *self, int feat);
76bool perf_header__has_feat(const struct perf_header *self, int feat);
51 77
52struct perf_header *perf_header__new(void); 78struct perf_header *perf_header__new(void);
53 79
80int perf_header__process_sections(struct perf_header *self, int fd,
81 int (*process)(struct perf_file_section *self,
82 int feat, int fd));
83
54#endif /* __PERF_HEADER_H */ 84#endif /* __PERF_HEADER_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 821c1033bccf..94507639a8c4 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -1,2 +1,3 @@
1#include "../../../../include/linux/bitmap.h" 1#include "../../../../include/linux/bitmap.h"
2#include "../../../../include/asm-generic/bitops/find.h" 2#include "../../../../include/asm-generic/bitops/find.h"
3#include <linux/errno.h>
diff --git a/tools/perf/util/include/linux/ctype.h b/tools/perf/util/include/linux/ctype.h
index bae5783282ef..a53d4ee1e0b7 100644
--- a/tools/perf/util/include/linux/ctype.h
+++ b/tools/perf/util/include/linux/ctype.h
@@ -1 +1 @@
#include "../../../../include/linux/ctype.h" #include "../util.h"
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index c1c556825343..94ca95073c40 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -20,16 +20,27 @@ static int strcommon(const char *pathname, char *cwd, int cwdlen)
20 return n; 20 return n;
21} 21}
22 22
23struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, 23void map__init(struct map *self, u64 start, u64 end, u64 pgoff,
24 unsigned int sym_priv_size, symbol_filter_t filter) 24 struct dso *dso)
25{
26 self->start = start;
27 self->end = end;
28 self->pgoff = pgoff;
29 self->dso = dso;
30 self->map_ip = map__map_ip;
31 self->unmap_ip = map__unmap_ip;
32 RB_CLEAR_NODE(&self->rb_node);
33}
34
35struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen)
25{ 36{
26 struct map *self = malloc(sizeof(*self)); 37 struct map *self = malloc(sizeof(*self));
27 38
28 if (self != NULL) { 39 if (self != NULL) {
29 const char *filename = event->filename; 40 const char *filename = event->filename;
30 char newfilename[PATH_MAX]; 41 char newfilename[PATH_MAX];
42 struct dso *dso;
31 int anon; 43 int anon;
32 bool new_dso;
33 44
34 if (cwd) { 45 if (cwd) {
35 int n = strcommon(filename, cwd, cwdlen); 46 int n = strcommon(filename, cwd, cwdlen);
@@ -48,33 +59,15 @@ struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen,
48 filename = newfilename; 59 filename = newfilename;
49 } 60 }
50 61
51 self->start = event->start; 62 dso = dsos__findnew(filename);
52 self->end = event->start + event->len; 63 if (dso == NULL)
53 self->pgoff = event->pgoff;
54
55 self->dso = dsos__findnew(filename, sym_priv_size, &new_dso);
56 if (self->dso == NULL)
57 goto out_delete; 64 goto out_delete;
58 65
59 if (new_dso) { 66 map__init(self, event->start, event->start + event->len,
60 int nr = dso__load(self->dso, self, filter); 67 event->pgoff, dso);
61
62 if (nr < 0)
63 pr_warning("Failed to open %s, continuing "
64 "without symbols\n",
65 self->dso->long_name);
66 else if (nr == 0)
67 pr_warning("No symbols found in %s, maybe "
68 "install a debug package?\n",
69 self->dso->long_name);
70 }
71 68
72 if (self->dso == vdso || anon) 69 if (self->dso == vdso || anon)
73 self->map_ip = self->unmap_ip = identity__map_ip; 70 self->map_ip = self->unmap_ip = identity__map_ip;
74 else {
75 self->map_ip = map__map_ip;
76 self->unmap_ip = map__unmap_ip;
77 }
78 } 71 }
79 return self; 72 return self;
80out_delete: 73out_delete:
@@ -82,6 +75,47 @@ out_delete:
82 return NULL; 75 return NULL;
83} 76}
84 77
78#define DSO__DELETED "(deleted)"
79
80struct symbol *
81map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter)
82{
83 if (!self->dso->loaded) {
84 int nr = dso__load(self->dso, self, filter);
85
86 if (nr < 0) {
87 if (self->dso->has_build_id) {
88 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
89
90 build_id__sprintf(self->dso->build_id,
91 sizeof(self->dso->build_id),
92 sbuild_id);
93 pr_warning("%s with build id %s not found",
94 self->dso->long_name, sbuild_id);
95 } else
96 pr_warning("Failed to open %s",
97 self->dso->long_name);
98 pr_warning(", continuing without symbols\n");
99 return NULL;
100 } else if (nr == 0) {
101 const char *name = self->dso->long_name;
102 const size_t len = strlen(name);
103 const size_t real_len = len - sizeof(DSO__DELETED);
104
105 if (len > sizeof(DSO__DELETED) &&
106 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
107 pr_warning("%.*s was updated, restart the long running apps that use it!\n",
108 (int)real_len, name);
109 } else {
110 pr_warning("no symbols found in %s, maybe install a debug package?\n", name);
111 }
112 return NULL;
113 }
114 }
115
116 return self->dso->find_symbol(self->dso, ip);
117}
118
85struct map *map__clone(struct map *self) 119struct map *map__clone(struct map *self)
86{ 120{
87 struct map *map = malloc(sizeof(*self)); 121 struct map *map = malloc(sizeof(*self));
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b097570e9623..0faf4f2bb5ca 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -7,6 +7,7 @@
7#include "string.h" 7#include "string.h"
8#include "cache.h" 8#include "cache.h"
9#include "header.h" 9#include "header.h"
10#include "debugfs.h"
10 11
11int nr_counters; 12int nr_counters;
12 13
@@ -47,6 +48,8 @@ static struct event_symbol event_symbols[] = {
47 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, 48 { CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
48 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, 49 { CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
49 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, 50 { CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
51 { CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
52 { CSW(EMULATION_FAULTS), "emulation-faults", "" },
50}; 53};
51 54
52#define __PERF_EVENT_FIELD(config, name) \ 55#define __PERF_EVENT_FIELD(config, name) \
@@ -75,6 +78,8 @@ static const char *sw_event_names[] = {
75 "CPU-migrations", 78 "CPU-migrations",
76 "minor-faults", 79 "minor-faults",
77 "major-faults", 80 "major-faults",
81 "alignment-faults",
82 "emulation-faults",
78}; 83};
79 84
80#define MAX_ALIASES 8 85#define MAX_ALIASES 8
@@ -149,16 +154,6 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir)
149 154
150#define MAX_EVENT_LENGTH 512 155#define MAX_EVENT_LENGTH 512
151 156
152int valid_debugfs_mount(const char *debugfs)
153{
154 struct statfs st_fs;
155
156 if (statfs(debugfs, &st_fs) < 0)
157 return -ENOENT;
158 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
159 return -ENOENT;
160 return 0;
161}
162 157
163struct tracepoint_path *tracepoint_id_to_path(u64 config) 158struct tracepoint_path *tracepoint_id_to_path(u64 config)
164{ 159{
@@ -171,7 +166,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config)
171 char evt_path[MAXPATHLEN]; 166 char evt_path[MAXPATHLEN];
172 char dir_path[MAXPATHLEN]; 167 char dir_path[MAXPATHLEN];
173 168
174 if (valid_debugfs_mount(debugfs_path)) 169 if (debugfs_valid_mountpoint(debugfs_path))
175 return NULL; 170 return NULL;
176 171
177 sys_dir = opendir(debugfs_path); 172 sys_dir = opendir(debugfs_path);
@@ -510,7 +505,7 @@ static enum event_result parse_tracepoint_event(const char **strp,
510 char sys_name[MAX_EVENT_LENGTH]; 505 char sys_name[MAX_EVENT_LENGTH];
511 unsigned int sys_length, evt_length; 506 unsigned int sys_length, evt_length;
512 507
513 if (valid_debugfs_mount(debugfs_path)) 508 if (debugfs_valid_mountpoint(debugfs_path))
514 return 0; 509 return 0;
515 510
516 evt_name = strchr(*strp, ':'); 511 evt_name = strchr(*strp, ':');
@@ -678,6 +673,8 @@ parse_event_symbols(const char **str, struct perf_event_attr *attr)
678 if (ret != EVT_FAILED) 673 if (ret != EVT_FAILED)
679 goto modifier; 674 goto modifier;
680 675
676 fprintf(stderr, "invalid or unsupported event: '%s'\n", *str);
677 fprintf(stderr, "Run 'perf list' for a list of valid events\n");
681 return EVT_FAILED; 678 return EVT_FAILED;
682 679
683modifier: 680modifier:
@@ -786,7 +783,7 @@ static void print_tracepoint_events(void)
786 char evt_path[MAXPATHLEN]; 783 char evt_path[MAXPATHLEN];
787 char dir_path[MAXPATHLEN]; 784 char dir_path[MAXPATHLEN];
788 785
789 if (valid_debugfs_mount(debugfs_path)) 786 if (debugfs_valid_mountpoint(debugfs_path))
790 return; 787 return;
791 788
792 sys_dir = opendir(debugfs_path); 789 sys_dir = opendir(debugfs_path);
@@ -804,7 +801,7 @@ static void print_tracepoint_events(void)
804 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { 801 for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
805 snprintf(evt_path, MAXPATHLEN, "%s:%s", 802 snprintf(evt_path, MAXPATHLEN, "%s:%s",
806 sys_dirent.d_name, evt_dirent.d_name); 803 sys_dirent.d_name, evt_dirent.d_name);
807 fprintf(stderr, " %-42s [%s]\n", evt_path, 804 printf(" %-42s [%s]\n", evt_path,
808 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]); 805 event_type_descriptors[PERF_TYPE_TRACEPOINT+1]);
809 } 806 }
810 closedir(evt_dir); 807 closedir(evt_dir);
@@ -821,8 +818,8 @@ void print_events(void)
821 unsigned int i, type, op, prev_type = -1; 818 unsigned int i, type, op, prev_type = -1;
822 char name[40]; 819 char name[40];
823 820
824 fprintf(stderr, "\n"); 821 printf("\n");
825 fprintf(stderr, "List of pre-defined events (to be used in -e):\n"); 822 printf("List of pre-defined events (to be used in -e):\n");
826 823
827 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { 824 for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
828 type = syms->type + 1; 825 type = syms->type + 1;
@@ -830,19 +827,19 @@ void print_events(void)
830 type = 0; 827 type = 0;
831 828
832 if (type != prev_type) 829 if (type != prev_type)
833 fprintf(stderr, "\n"); 830 printf("\n");
834 831
835 if (strlen(syms->alias)) 832 if (strlen(syms->alias))
836 sprintf(name, "%s OR %s", syms->symbol, syms->alias); 833 sprintf(name, "%s OR %s", syms->symbol, syms->alias);
837 else 834 else
838 strcpy(name, syms->symbol); 835 strcpy(name, syms->symbol);
839 fprintf(stderr, " %-42s [%s]\n", name, 836 printf(" %-42s [%s]\n", name,
840 event_type_descriptors[type]); 837 event_type_descriptors[type]);
841 838
842 prev_type = type; 839 prev_type = type;
843 } 840 }
844 841
845 fprintf(stderr, "\n"); 842 printf("\n");
846 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 843 for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
847 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 844 for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
848 /* skip invalid cache type */ 845 /* skip invalid cache type */
@@ -850,17 +847,17 @@ void print_events(void)
850 continue; 847 continue;
851 848
852 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 849 for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
853 fprintf(stderr, " %-42s [%s]\n", 850 printf(" %-42s [%s]\n",
854 event_cache_name(type, op, i), 851 event_cache_name(type, op, i),
855 event_type_descriptors[4]); 852 event_type_descriptors[4]);
856 } 853 }
857 } 854 }
858 } 855 }
859 856
860 fprintf(stderr, "\n"); 857 printf("\n");
861 fprintf(stderr, " %-42s [raw hardware event descriptor]\n", 858 printf(" %-42s [raw hardware event descriptor]\n",
862 "rNNN"); 859 "rNNN");
863 fprintf(stderr, "\n"); 860 printf("\n");
864 861
865 print_tracepoint_events(); 862 print_tracepoint_events();
866 863
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index 04743d3e9039..227043577e06 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -1,5 +1,7 @@
1#include <string.h> 1#include <string.h>
2#include <stdlib.h>
2#include "string.h" 3#include "string.h"
4#include "util.h"
3 5
4static int hex(char ch) 6static int hex(char ch)
5{ 7{
@@ -43,3 +45,85 @@ char *strxfrchar(char *s, char from, char to)
43 45
44 return s; 46 return s;
45} 47}
48
49#define K 1024LL
50/*
51 * perf_atoll()
52 * Parse (\d+)(b|B|kb|KB|mb|MB|gb|GB|tb|TB) (e.g. "256MB")
53 * and return its numeric value
54 */
55s64 perf_atoll(const char *str)
56{
57 unsigned int i;
58 s64 length = -1, unit = 1;
59
60 if (!isdigit(str[0]))
61 goto out_err;
62
63 for (i = 1; i < strlen(str); i++) {
64 switch (str[i]) {
65 case 'B':
66 case 'b':
67 break;
68 case 'K':
69 if (str[i + 1] != 'B')
70 goto out_err;
71 else
72 goto kilo;
73 case 'k':
74 if (str[i + 1] != 'b')
75 goto out_err;
76kilo:
77 unit = K;
78 break;
79 case 'M':
80 if (str[i + 1] != 'B')
81 goto out_err;
82 else
83 goto mega;
84 case 'm':
85 if (str[i + 1] != 'b')
86 goto out_err;
87mega:
88 unit = K * K;
89 break;
90 case 'G':
91 if (str[i + 1] != 'B')
92 goto out_err;
93 else
94 goto giga;
95 case 'g':
96 if (str[i + 1] != 'b')
97 goto out_err;
98giga:
99 unit = K * K * K;
100 break;
101 case 'T':
102 if (str[i + 1] != 'B')
103 goto out_err;
104 else
105 goto tera;
106 case 't':
107 if (str[i + 1] != 'b')
108 goto out_err;
109tera:
110 unit = K * K * K * K;
111 break;
112 case '\0': /* only specified figures */
113 unit = 1;
114 break;
115 default:
116 if (!isdigit(str[i]))
117 goto out_err;
118 break;
119 }
120 }
121
122 length = atoll(str) * unit;
123 goto out;
124
125out_err:
126 length = -1;
127out:
128 return length;
129}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 2c84bf65ba0f..e50b07f80827 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -5,6 +5,7 @@
5 5
6int hex2u64(const char *ptr, u64 *val); 6int hex2u64(const char *ptr, u64 *val);
7char *strxfrchar(char *s, char from, char to); 7char *strxfrchar(char *s, char from, char to);
8s64 perf_atoll(const char *str);
8 9
9#define _STR(x) #x 10#define _STR(x) #x
10#define STR(x) _STR(x) 11#define STR(x) _STR(x)
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 8f0208ce237a..1b77e81b38de 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -26,6 +26,7 @@ static void dsos__add(struct dso *dso);
26static struct dso *dsos__find(const char *name); 26static struct dso *dsos__find(const char *name);
27static struct map *map__new2(u64 start, struct dso *dso); 27static struct map *map__new2(u64 start, struct dso *dso);
28static void kernel_maps__insert(struct map *map); 28static void kernel_maps__insert(struct map *map);
29unsigned int symbol__priv_size;
29 30
30static struct rb_root kernel_maps; 31static struct rb_root kernel_maps;
31 32
@@ -75,18 +76,17 @@ static void kernel_maps__fixup_end(void)
75 } 76 }
76} 77}
77 78
78static struct symbol *symbol__new(u64 start, u64 len, const char *name, 79static struct symbol *symbol__new(u64 start, u64 len, const char *name)
79 unsigned int priv_size)
80{ 80{
81 size_t namelen = strlen(name) + 1; 81 size_t namelen = strlen(name) + 1;
82 struct symbol *self = calloc(1, priv_size + sizeof(*self) + namelen); 82 struct symbol *self = calloc(1, (symbol__priv_size +
83 83 sizeof(*self) + namelen));
84 if (!self) 84 if (!self)
85 return NULL; 85 return NULL;
86 86
87 if (priv_size) { 87 if (symbol__priv_size) {
88 memset(self, 0, priv_size); 88 memset(self, 0, symbol__priv_size);
89 self = ((void *)self) + priv_size; 89 self = ((void *)self) + symbol__priv_size;
90 } 90 }
91 self->start = start; 91 self->start = start;
92 self->end = len ? start + len - 1 : start; 92 self->end = len ? start + len - 1 : start;
@@ -98,9 +98,9 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name,
98 return self; 98 return self;
99} 99}
100 100
101static void symbol__delete(struct symbol *self, unsigned int priv_size) 101static void symbol__delete(struct symbol *self)
102{ 102{
103 free(((void *)self) - priv_size); 103 free(((void *)self) - symbol__priv_size);
104} 104}
105 105
106static size_t symbol__fprintf(struct symbol *self, FILE *fp) 106static size_t symbol__fprintf(struct symbol *self, FILE *fp)
@@ -109,7 +109,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
109 self->start, self->end, self->name); 109 self->start, self->end, self->name);
110} 110}
111 111
112struct dso *dso__new(const char *name, unsigned int sym_priv_size) 112struct dso *dso__new(const char *name)
113{ 113{
114 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1); 114 struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);
115 115
@@ -118,10 +118,11 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
118 self->long_name = self->name; 118 self->long_name = self->name;
119 self->short_name = self->name; 119 self->short_name = self->name;
120 self->syms = RB_ROOT; 120 self->syms = RB_ROOT;
121 self->sym_priv_size = sym_priv_size;
122 self->find_symbol = dso__find_symbol; 121 self->find_symbol = dso__find_symbol;
123 self->slen_calculated = 0; 122 self->slen_calculated = 0;
124 self->origin = DSO__ORIG_NOT_FOUND; 123 self->origin = DSO__ORIG_NOT_FOUND;
124 self->loaded = 0;
125 self->has_build_id = 0;
125 } 126 }
126 127
127 return self; 128 return self;
@@ -136,7 +137,7 @@ static void dso__delete_symbols(struct dso *self)
136 pos = rb_entry(next, struct symbol, rb_node); 137 pos = rb_entry(next, struct symbol, rb_node);
137 next = rb_next(&pos->rb_node); 138 next = rb_next(&pos->rb_node);
138 rb_erase(&pos->rb_node, &self->syms); 139 rb_erase(&pos->rb_node, &self->syms);
139 symbol__delete(pos, self->sym_priv_size); 140 symbol__delete(pos);
140 } 141 }
141} 142}
142 143
@@ -148,6 +149,12 @@ void dso__delete(struct dso *self)
148 free(self); 149 free(self);
149} 150}
150 151
152void dso__set_build_id(struct dso *self, void *build_id)
153{
154 memcpy(self->build_id, build_id, sizeof(self->build_id));
155 self->has_build_id = 1;
156}
157
151static void dso__insert_symbol(struct dso *self, struct symbol *sym) 158static void dso__insert_symbol(struct dso *self, struct symbol *sym)
152{ 159{
153 struct rb_node **p = &self->syms.rb_node; 160 struct rb_node **p = &self->syms.rb_node;
@@ -190,11 +197,37 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip)
190 return NULL; 197 return NULL;
191} 198}
192 199
193size_t dso__fprintf(struct dso *self, FILE *fp) 200int build_id__sprintf(u8 *self, int len, char *bf)
194{ 201{
195 size_t ret = fprintf(fp, "dso: %s\n", self->short_name); 202 char *bid = bf;
203 u8 *raw = self;
204 int i;
196 205
206 for (i = 0; i < len; ++i) {
207 sprintf(bid, "%02x", *raw);
208 ++raw;
209 bid += 2;
210 }
211
212 return raw - self;
213}
214
215size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
216{
217 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
218
219 build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
220 return fprintf(fp, "%s", sbuild_id);
221}
222
223size_t dso__fprintf(struct dso *self, FILE *fp)
224{
197 struct rb_node *nd; 225 struct rb_node *nd;
226 size_t ret = fprintf(fp, "dso: %s (", self->short_name);
227
228 ret += dso__fprintf_buildid(self, fp);
229 ret += fprintf(fp, ")\n");
230
198 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { 231 for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) {
199 struct symbol *pos = rb_entry(nd, struct symbol, rb_node); 232 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
200 ret += symbol__fprintf(pos, fp); 233 ret += symbol__fprintf(pos, fp);
@@ -250,12 +283,16 @@ static int kernel_maps__load_all_kallsyms(void)
250 /* 283 /*
251 * Will fix up the end later, when we have all symbols sorted. 284 * Will fix up the end later, when we have all symbols sorted.
252 */ 285 */
253 sym = symbol__new(start, 0, symbol_name, 286 sym = symbol__new(start, 0, symbol_name);
254 kernel_map->dso->sym_priv_size);
255 287
256 if (sym == NULL) 288 if (sym == NULL)
257 goto out_delete_line; 289 goto out_delete_line;
258 290
291 /*
292 * We will pass the symbols to the filter later, in
293 * kernel_maps__split_kallsyms, when we have split the
294 * maps per module
295 */
259 dso__insert_symbol(kernel_map->dso, sym); 296 dso__insert_symbol(kernel_map->dso, sym);
260 } 297 }
261 298
@@ -317,8 +354,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
317 snprintf(dso_name, sizeof(dso_name), "[kernel].%d", 354 snprintf(dso_name, sizeof(dso_name), "[kernel].%d",
318 kernel_range++); 355 kernel_range++);
319 356
320 dso = dso__new(dso_name, 357 dso = dso__new(dso_name);
321 kernel_map->dso->sym_priv_size);
322 if (dso == NULL) 358 if (dso == NULL)
323 return -1; 359 return -1;
324 360
@@ -336,7 +372,7 @@ static int kernel_maps__split_kallsyms(symbol_filter_t filter, int use_modules)
336 if (filter && filter(map, pos)) { 372 if (filter && filter(map, pos)) {
337delete_symbol: 373delete_symbol:
338 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 374 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
339 symbol__delete(pos, kernel_map->dso->sym_priv_size); 375 symbol__delete(pos);
340 } else { 376 } else {
341 if (map != kernel_map) { 377 if (map != kernel_map) {
342 rb_erase(&pos->rb_node, &kernel_map->dso->syms); 378 rb_erase(&pos->rb_node, &kernel_map->dso->syms);
@@ -417,14 +453,13 @@ static int dso__load_perf_map(struct dso *self, struct map *map,
417 if (len + 2 >= line_len) 453 if (len + 2 >= line_len)
418 continue; 454 continue;
419 455
420 sym = symbol__new(start, size, line + len, 456 sym = symbol__new(start, size, line + len);
421 self->sym_priv_size);
422 457
423 if (sym == NULL) 458 if (sym == NULL)
424 goto out_delete_line; 459 goto out_delete_line;
425 460
426 if (filter && filter(map, sym)) 461 if (filter && filter(map, sym))
427 symbol__delete(sym, self->sym_priv_size); 462 symbol__delete(sym);
428 else { 463 else {
429 dso__insert_symbol(self, sym); 464 dso__insert_symbol(self, sym);
430 nr_syms++; 465 nr_syms++;
@@ -532,7 +567,8 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
532 * And always look at the original dso, not at debuginfo packages, that 567 * And always look at the original dso, not at debuginfo packages, that
533 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 568 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
534 */ 569 */
535static int dso__synthesize_plt_symbols(struct dso *self) 570static int dso__synthesize_plt_symbols(struct dso *self, struct map *map,
571 symbol_filter_t filter)
536{ 572{
537 uint32_t nr_rel_entries, idx; 573 uint32_t nr_rel_entries, idx;
538 GElf_Sym sym; 574 GElf_Sym sym;
@@ -552,7 +588,7 @@ static int dso__synthesize_plt_symbols(struct dso *self)
552 if (fd < 0) 588 if (fd < 0)
553 goto out; 589 goto out;
554 590
555 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 591 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
556 if (elf == NULL) 592 if (elf == NULL)
557 goto out_close; 593 goto out_close;
558 594
@@ -616,12 +652,16 @@ static int dso__synthesize_plt_symbols(struct dso *self)
616 "%s@plt", elf_sym__name(&sym, symstrs)); 652 "%s@plt", elf_sym__name(&sym, symstrs));
617 653
618 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 654 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
619 sympltname, self->sym_priv_size); 655 sympltname);
620 if (!f) 656 if (!f)
621 goto out_elf_end; 657 goto out_elf_end;
622 658
623 dso__insert_symbol(self, f); 659 if (filter && filter(map, f))
624 ++nr; 660 symbol__delete(f);
661 else {
662 dso__insert_symbol(self, f);
663 ++nr;
664 }
625 } 665 }
626 } else if (shdr_rel_plt.sh_type == SHT_REL) { 666 } else if (shdr_rel_plt.sh_type == SHT_REL) {
627 GElf_Rel pos_mem, *pos; 667 GElf_Rel pos_mem, *pos;
@@ -634,12 +674,16 @@ static int dso__synthesize_plt_symbols(struct dso *self)
634 "%s@plt", elf_sym__name(&sym, symstrs)); 674 "%s@plt", elf_sym__name(&sym, symstrs));
635 675
636 f = symbol__new(plt_offset, shdr_plt.sh_entsize, 676 f = symbol__new(plt_offset, shdr_plt.sh_entsize,
637 sympltname, self->sym_priv_size); 677 sympltname);
638 if (!f) 678 if (!f)
639 goto out_elf_end; 679 goto out_elf_end;
640 680
641 dso__insert_symbol(self, f); 681 if (filter && filter(map, f))
642 ++nr; 682 symbol__delete(f);
683 else {
684 dso__insert_symbol(self, f);
685 ++nr;
686 }
643 } 687 }
644 } 688 }
645 689
@@ -676,7 +720,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
676 Elf *elf; 720 Elf *elf;
677 int nr = 0; 721 int nr = 0;
678 722
679 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 723 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
680 if (elf == NULL) { 724 if (elf == NULL) {
681 pr_err("%s: cannot read %s ELF file.\n", __func__, name); 725 pr_err("%s: cannot read %s ELF file.\n", __func__, name);
682 goto out_close; 726 goto out_close;
@@ -769,7 +813,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
769 if (kmodule) 813 if (kmodule)
770 start += map->start + shdr.sh_offset; 814 start += map->start + shdr.sh_offset;
771 815
772 curr_dso = dso__new(dso_name, self->sym_priv_size); 816 curr_dso = dso__new(dso_name);
773 if (curr_dso == NULL) 817 if (curr_dso == NULL)
774 goto out_elf_end; 818 goto out_elf_end;
775 curr_map = map__new2(start, curr_dso); 819 curr_map = map__new2(start, curr_dso);
@@ -803,14 +847,13 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
803 if (demangled != NULL) 847 if (demangled != NULL)
804 elf_name = demangled; 848 elf_name = demangled;
805new_symbol: 849new_symbol:
806 f = symbol__new(sym.st_value, sym.st_size, elf_name, 850 f = symbol__new(sym.st_value, sym.st_size, elf_name);
807 curr_dso->sym_priv_size);
808 free(demangled); 851 free(demangled);
809 if (!f) 852 if (!f)
810 goto out_elf_end; 853 goto out_elf_end;
811 854
812 if (filter && filter(curr_map, f)) 855 if (filter && filter(curr_map, f))
813 symbol__delete(f, curr_dso->sym_priv_size); 856 symbol__delete(f);
814 else { 857 else {
815 dso__insert_symbol(curr_dso, f); 858 dso__insert_symbol(curr_dso, f);
816 nr++; 859 nr++;
@@ -829,27 +872,59 @@ out_close:
829 return err; 872 return err;
830} 873}
831 874
832#define BUILD_ID_SIZE 128 875bool fetch_build_id_table(struct list_head *head)
876{
877 bool have_buildid = false;
878 struct dso *pos;
833 879
834static char *dso__read_build_id(struct dso *self) 880 list_for_each_entry(pos, &dsos, node) {
881 struct build_id_list *new;
882 struct build_id_event b;
883 size_t len;
884
885 if (filename__read_build_id(pos->long_name,
886 &b.build_id,
887 sizeof(b.build_id)) < 0)
888 continue;
889 have_buildid = true;
890 memset(&b.header, 0, sizeof(b.header));
891 len = strlen(pos->long_name) + 1;
892 len = ALIGN(len, 64);
893 b.header.size = sizeof(b) + len;
894
895 new = malloc(sizeof(*new));
896 if (!new)
897 die("No memory\n");
898
899 memcpy(&new->event, &b, sizeof(b));
900 new->dso_name = pos->long_name;
901 new->len = len;
902
903 list_add_tail(&new->list, head);
904 }
905
906 return have_buildid;
907}
908
909int filename__read_build_id(const char *filename, void *bf, size_t size)
835{ 910{
836 int i; 911 int fd, err = -1;
837 GElf_Ehdr ehdr; 912 GElf_Ehdr ehdr;
838 GElf_Shdr shdr; 913 GElf_Shdr shdr;
839 Elf_Data *build_id_data; 914 Elf_Data *build_id_data;
840 Elf_Scn *sec; 915 Elf_Scn *sec;
841 char *build_id = NULL, *bid;
842 unsigned char *raw;
843 Elf *elf; 916 Elf *elf;
844 int fd = open(self->long_name, O_RDONLY);
845 917
918 if (size < BUILD_ID_SIZE)
919 goto out;
920
921 fd = open(filename, O_RDONLY);
846 if (fd < 0) 922 if (fd < 0)
847 goto out; 923 goto out;
848 924
849 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 925 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
850 if (elf == NULL) { 926 if (elf == NULL) {
851 pr_err("%s: cannot read %s ELF file.\n", __func__, 927 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
852 self->long_name);
853 goto out_close; 928 goto out_close;
854 } 929 }
855 930
@@ -858,30 +933,40 @@ static char *dso__read_build_id(struct dso *self)
858 goto out_elf_end; 933 goto out_elf_end;
859 } 934 }
860 935
861 sec = elf_section_by_name(elf, &ehdr, &shdr, ".note.gnu.build-id", NULL); 936 sec = elf_section_by_name(elf, &ehdr, &shdr,
937 ".note.gnu.build-id", NULL);
862 if (sec == NULL) 938 if (sec == NULL)
863 goto out_elf_end; 939 goto out_elf_end;
864 940
865 build_id_data = elf_getdata(sec, NULL); 941 build_id_data = elf_getdata(sec, NULL);
866 if (build_id_data == NULL) 942 if (build_id_data == NULL)
867 goto out_elf_end; 943 goto out_elf_end;
868 build_id = malloc(BUILD_ID_SIZE); 944 memcpy(bf, build_id_data->d_buf + 16, BUILD_ID_SIZE);
869 if (build_id == NULL) 945 err = BUILD_ID_SIZE;
870 goto out_elf_end;
871 raw = build_id_data->d_buf + 16;
872 bid = build_id;
873
874 for (i = 0; i < 20; ++i) {
875 sprintf(bid, "%02x", *raw);
876 ++raw;
877 bid += 2;
878 }
879 pr_debug2("%s(%s): %s\n", __func__, self->long_name, build_id);
880out_elf_end: 946out_elf_end:
881 elf_end(elf); 947 elf_end(elf);
882out_close: 948out_close:
883 close(fd); 949 close(fd);
884out: 950out:
951 return err;
952}
953
954static char *dso__read_build_id(struct dso *self)
955{
956 int len;
957 char *build_id = NULL;
958 unsigned char rawbf[BUILD_ID_SIZE];
959
960 len = filename__read_build_id(self->long_name, rawbf, sizeof(rawbf));
961 if (len < 0)
962 goto out;
963
964 build_id = malloc(len * 2 + 1);
965 if (build_id == NULL)
966 goto out;
967
968 build_id__sprintf(rawbf, len, build_id);
969out:
885 return build_id; 970 return build_id;
886} 971}
887 972
@@ -909,6 +994,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
909 int ret = -1; 994 int ret = -1;
910 int fd; 995 int fd;
911 996
997 self->loaded = 1;
998
912 if (!name) 999 if (!name)
913 return -1; 1000 return -1;
914 1001
@@ -925,6 +1012,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
925 1012
926more: 1013more:
927 do { 1014 do {
1015 int berr = 0;
1016
928 self->origin++; 1017 self->origin++;
929 switch (self->origin) { 1018 switch (self->origin) {
930 case DSO__ORIG_FEDORA: 1019 case DSO__ORIG_FEDORA:
@@ -941,8 +1030,7 @@ more:
941 snprintf(name, size, 1030 snprintf(name, size,
942 "/usr/lib/debug/.build-id/%.2s/%s.debug", 1031 "/usr/lib/debug/.build-id/%.2s/%s.debug",
943 build_id, build_id + 2); 1032 build_id, build_id + 2);
944 free(build_id); 1033 goto compare_build_id;
945 break;
946 } 1034 }
947 self->origin++; 1035 self->origin++;
948 /* Fall thru */ 1036 /* Fall thru */
@@ -954,6 +1042,22 @@ more:
954 goto out; 1042 goto out;
955 } 1043 }
956 1044
1045 if (self->has_build_id) {
1046 bool match;
1047 build_id = malloc(BUILD_ID_SIZE);
1048 if (build_id == NULL)
1049 goto more;
1050 berr = filename__read_build_id(name, build_id,
1051 BUILD_ID_SIZE);
1052compare_build_id:
1053 match = berr > 0 && memcmp(build_id, self->build_id,
1054 sizeof(self->build_id)) == 0;
1055 free(build_id);
1056 build_id = NULL;
1057 if (!match)
1058 goto more;
1059 }
1060
957 fd = open(name, O_RDONLY); 1061 fd = open(name, O_RDONLY);
958 } while (fd < 0); 1062 } while (fd < 0);
959 1063
@@ -967,7 +1071,7 @@ more:
967 goto more; 1071 goto more;
968 1072
969 if (ret > 0) { 1073 if (ret > 0) {
970 int nr_plt = dso__synthesize_plt_symbols(self); 1074 int nr_plt = dso__synthesize_plt_symbols(self, map, filter);
971 if (nr_plt > 0) 1075 if (nr_plt > 0)
972 ret += nr_plt; 1076 ret += nr_plt;
973 } 1077 }
@@ -1019,6 +1123,8 @@ static int dso__load_module_sym(struct dso *self, struct map *map,
1019{ 1123{
1020 int err = 0, fd = open(self->long_name, O_RDONLY); 1124 int err = 0, fd = open(self->long_name, O_RDONLY);
1021 1125
1126 self->loaded = 1;
1127
1022 if (fd < 0) { 1128 if (fd < 0) {
1023 pr_err("%s: cannot open %s\n", __func__, self->long_name); 1129 pr_err("%s: cannot open %s\n", __func__, self->long_name);
1024 return err; 1130 return err;
@@ -1128,22 +1234,16 @@ static struct map *map__new2(u64 start, struct dso *dso)
1128 struct map *self = malloc(sizeof(*self)); 1234 struct map *self = malloc(sizeof(*self));
1129 1235
1130 if (self != NULL) { 1236 if (self != NULL) {
1131 self->start = start;
1132 /* 1237 /*
1133 * Will be filled after we load all the symbols 1238 * ->end will be filled after we load all the symbols
1134 */ 1239 */
1135 self->end = 0; 1240 map__init(self, start, 0, 0, dso);
1136
1137 self->pgoff = 0;
1138 self->dso = dso;
1139 self->map_ip = map__map_ip;
1140 self->unmap_ip = map__unmap_ip;
1141 RB_CLEAR_NODE(&self->rb_node);
1142 } 1241 }
1242
1143 return self; 1243 return self;
1144} 1244}
1145 1245
1146static int dsos__load_modules(unsigned int sym_priv_size) 1246static int dsos__load_modules(void)
1147{ 1247{
1148 char *line = NULL; 1248 char *line = NULL;
1149 size_t n; 1249 size_t n;
@@ -1182,7 +1282,7 @@ static int dsos__load_modules(unsigned int sym_priv_size)
1182 *sep = '\0'; 1282 *sep = '\0';
1183 1283
1184 snprintf(name, sizeof(name), "[%s]", line); 1284 snprintf(name, sizeof(name), "[%s]", line);
1185 dso = dso__new(name, sym_priv_size); 1285 dso = dso__new(name);
1186 1286
1187 if (dso == NULL) 1287 if (dso == NULL)
1188 goto out_delete_line; 1288 goto out_delete_line;
@@ -1214,6 +1314,8 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1214{ 1314{
1215 int err, fd = open(vmlinux, O_RDONLY); 1315 int err, fd = open(vmlinux, O_RDONLY);
1216 1316
1317 self->loaded = 1;
1318
1217 if (fd < 0) 1319 if (fd < 0)
1218 return -1; 1320 return -1;
1219 1321
@@ -1224,11 +1326,11 @@ static int dso__load_vmlinux(struct dso *self, struct map *map,
1224 return err; 1326 return err;
1225} 1327}
1226 1328
1227int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, 1329int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter,
1228 symbol_filter_t filter, int use_modules) 1330 int use_modules)
1229{ 1331{
1230 int err = -1; 1332 int err = -1;
1231 struct dso *dso = dso__new(vmlinux, sym_priv_size); 1333 struct dso *dso = dso__new(vmlinux);
1232 1334
1233 if (dso == NULL) 1335 if (dso == NULL)
1234 return -1; 1336 return -1;
@@ -1240,7 +1342,7 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
1240 1342
1241 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip; 1343 kernel_map->map_ip = kernel_map->unmap_ip = identity__map_ip;
1242 1344
1243 if (use_modules && dsos__load_modules(sym_priv_size) < 0) { 1345 if (use_modules && dsos__load_modules() < 0) {
1244 pr_warning("Failed to load list of modules in use! " 1346 pr_warning("Failed to load list of modules in use! "
1245 "Continuing...\n"); 1347 "Continuing...\n");
1246 use_modules = 0; 1348 use_modules = 0;
@@ -1312,19 +1414,15 @@ static struct dso *dsos__find(const char *name)
1312 return NULL; 1414 return NULL;
1313} 1415}
1314 1416
1315struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, 1417struct dso *dsos__findnew(const char *name)
1316 bool *is_new)
1317{ 1418{
1318 struct dso *dso = dsos__find(name); 1419 struct dso *dso = dsos__find(name);
1319 1420
1320 if (!dso) { 1421 if (!dso) {
1321 dso = dso__new(name, sym_priv_size); 1422 dso = dso__new(name);
1322 if (dso) { 1423 if (dso != NULL)
1323 dsos__add(dso); 1424 dsos__add(dso);
1324 *is_new = true; 1425 }
1325 }
1326 } else
1327 *is_new = false;
1328 1426
1329 return dso; 1427 return dso;
1330} 1428}
@@ -1337,13 +1435,24 @@ void dsos__fprintf(FILE *fp)
1337 dso__fprintf(pos, fp); 1435 dso__fprintf(pos, fp);
1338} 1436}
1339 1437
1340int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) 1438size_t dsos__fprintf_buildid(FILE *fp)
1439{
1440 struct dso *pos;
1441 size_t ret = 0;
1442
1443 list_for_each_entry(pos, &dsos, node) {
1444 ret += dso__fprintf_buildid(pos, fp);
1445 ret += fprintf(fp, " %s\n", pos->long_name);
1446 }
1447 return ret;
1448}
1449
1450int load_kernel(symbol_filter_t filter)
1341{ 1451{
1342 if (dsos__load_kernel(vmlinux_name, sym_priv_size, filter, 1452 if (dsos__load_kernel(vmlinux_name, filter, modules) <= 0)
1343 modules) <= 0)
1344 return -1; 1453 return -1;
1345 1454
1346 vdso = dso__new("[vdso]", 0); 1455 vdso = dso__new("[vdso]");
1347 if (!vdso) 1456 if (!vdso)
1348 return -1; 1457 return -1;
1349 1458
@@ -1352,7 +1461,8 @@ int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter)
1352 return 0; 1461 return 0;
1353} 1462}
1354 1463
1355void symbol__init(void) 1464void symbol__init(unsigned int priv_size)
1356{ 1465{
1357 elf_version(EV_CURRENT); 1466 elf_version(EV_CURRENT);
1467 symbol__priv_size = priv_size;
1358} 1468}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 77b7b3e42417..51c5a4a08133 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -27,6 +27,16 @@ static inline char *bfd_demangle(void __used *v, const char __used *c,
27#endif 27#endif
28#endif 28#endif
29 29
30/*
31 * libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
32 * for newer versions we can use mmap to reduce memory usage:
33 */
34#ifdef LIBELF_NO_MMAP
35# define PERF_ELF_C_READ_MMAP ELF_C_READ
36#else
37# define PERF_ELF_C_READ_MMAP ELF_C_READ_MMAP
38#endif
39
30#ifndef DMGL_PARAMS 40#ifndef DMGL_PARAMS
31#define DMGL_PARAMS (1 << 0) /* Include function args */ 41#define DMGL_PARAMS (1 << 0) /* Include function args */
32#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ 42#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
@@ -39,42 +49,51 @@ struct symbol {
39 char name[0]; 49 char name[0];
40}; 50};
41 51
52extern unsigned int symbol__priv_size;
53
54static inline void *symbol__priv(struct symbol *self)
55{
56 return ((void *)self) - symbol__priv_size;
57}
58
42struct dso { 59struct dso {
43 struct list_head node; 60 struct list_head node;
44 struct rb_root syms; 61 struct rb_root syms;
45 struct symbol *(*find_symbol)(struct dso *, u64 ip); 62 struct symbol *(*find_symbol)(struct dso *, u64 ip);
46 unsigned int sym_priv_size; 63 u8 adjust_symbols:1;
47 unsigned char adjust_symbols; 64 u8 slen_calculated:1;
48 unsigned char slen_calculated; 65 u8 loaded:1;
66 u8 has_build_id:1;
49 unsigned char origin; 67 unsigned char origin;
68 u8 build_id[BUILD_ID_SIZE];
50 const char *short_name; 69 const char *short_name;
51 char *long_name; 70 char *long_name;
52 char name[0]; 71 char name[0];
53}; 72};
54 73
55struct dso *dso__new(const char *name, unsigned int sym_priv_size); 74struct dso *dso__new(const char *name);
56void dso__delete(struct dso *self); 75void dso__delete(struct dso *self);
57 76
58static inline void *dso__sym_priv(struct dso *self, struct symbol *sym)
59{
60 return ((void *)sym) - self->sym_priv_size;
61}
62
63struct symbol *dso__find_symbol(struct dso *self, u64 ip); 77struct symbol *dso__find_symbol(struct dso *self, u64 ip);
64 78
65int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, 79int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, int modules);
66 symbol_filter_t filter, int modules); 80struct dso *dsos__findnew(const char *name);
67struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size,
68 bool *is_new);
69int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); 81int dso__load(struct dso *self, struct map *map, symbol_filter_t filter);
70void dsos__fprintf(FILE *fp); 82void dsos__fprintf(FILE *fp);
83size_t dsos__fprintf_buildid(FILE *fp);
71 84
85size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
72size_t dso__fprintf(struct dso *self, FILE *fp); 86size_t dso__fprintf(struct dso *self, FILE *fp);
73char dso__symtab_origin(const struct dso *self); 87char dso__symtab_origin(const struct dso *self);
88void dso__set_build_id(struct dso *self, void *build_id);
89
90int filename__read_build_id(const char *filename, void *bf, size_t size);
91bool fetch_build_id_table(struct list_head *head);
92int build_id__sprintf(u8 *self, int len, char *bf);
74 93
75int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter); 94int load_kernel(symbol_filter_t filter);
76 95
77void symbol__init(void); 96void symbol__init(unsigned int priv_size);
78 97
79extern struct list_head dsos; 98extern struct list_head dsos;
80extern struct map *kernel_map; 99extern struct map *kernel_map;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0daa341734f9..f2203a0946bc 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -315,6 +315,7 @@ static inline int has_extension(const char *filename, const char *ext)
315#undef isascii 315#undef isascii
316#undef isspace 316#undef isspace
317#undef isdigit 317#undef isdigit
318#undef isxdigit
318#undef isalpha 319#undef isalpha
319#undef isprint 320#undef isprint
320#undef isalnum 321#undef isalnum
@@ -332,6 +333,8 @@ extern unsigned char sane_ctype[256];
332#define isascii(x) (((x) & ~0x7f) == 0) 333#define isascii(x) (((x) & ~0x7f) == 0)
333#define isspace(x) sane_istest(x,GIT_SPACE) 334#define isspace(x) sane_istest(x,GIT_SPACE)
334#define isdigit(x) sane_istest(x,GIT_DIGIT) 335#define isdigit(x) sane_istest(x,GIT_DIGIT)
336#define isxdigit(x) \
337 (sane_istest(toupper(x), GIT_ALPHA | GIT_DIGIT) && toupper(x) < 'G')
335#define isalpha(x) sane_istest(x,GIT_ALPHA) 338#define isalpha(x) sane_istest(x,GIT_ALPHA)
336#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) 339#define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT)
337#define isprint(x) sane_istest(x,GIT_PRINT) 340#define isprint(x) sane_istest(x,GIT_PRINT)