diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-11-17 04:16:43 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-11-17 04:17:47 -0500 |
commit | a7b63425a41cd6a8d50f76fef0660c5110f97e91 (patch) | |
tree | be17ee121f1c8814d8d39c9f3e0205d9397fab54 /tools/perf/util | |
parent | 35039eb6b199749943547c8572be6604edf00229 (diff) | |
parent | 3726cc75e581c157202da93bb2333cce25c15c98 (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.c | 31 | ||||
-rw-r--r-- | tools/perf/util/data_map.h | 1 | ||||
-rw-r--r-- | tools/perf/util/debug.h | 2 | ||||
-rw-r--r-- | tools/perf/util/debugfs.c | 241 | ||||
-rw-r--r-- | tools/perf/util/debugfs.h | 25 | ||||
-rw-r--r-- | tools/perf/util/event.c | 177 | ||||
-rw-r--r-- | tools/perf/util/event.h | 23 | ||||
-rw-r--r-- | tools/perf/util/header.c | 342 | ||||
-rw-r--r-- | tools/perf/util/header.h | 46 | ||||
-rw-r--r-- | tools/perf/util/include/linux/bitmap.h | 1 | ||||
-rw-r--r-- | tools/perf/util/include/linux/ctype.h | 2 | ||||
-rw-r--r-- | tools/perf/util/map.c | 84 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 43 | ||||
-rw-r--r-- | tools/perf/util/string.c | 84 | ||||
-rw-r--r-- | tools/perf/util/string.h | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 286 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 49 | ||||
-rw-r--r-- | tools/perf/util/util.h | 3 |
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 | ||
73 | int 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; | ||
98 | out: | ||
99 | return err; | ||
100 | } | ||
101 | |||
73 | int mmap_dispatch_perf_file(struct perf_header **pheader, | 102 | int 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); |
30 | int 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 | |||
5 | extern int verbose; | 7 | extern int verbose; |
6 | extern int dump_trace; | 8 | extern 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 | |||
5 | static int debugfs_premounted; | ||
6 | static char debugfs_mountpoint[MAX_PATH+1]; | ||
7 | |||
8 | static const char *debugfs_known_mountpoints[] = { | ||
9 | "/sys/kernel/debug/", | ||
10 | "/debug/", | ||
11 | 0, | ||
12 | }; | ||
13 | |||
14 | /* use this to force a umount */ | ||
15 | void 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 */ | ||
23 | int 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 | |||
40 | static int debugfs_found; | ||
41 | |||
42 | /* find the path to the mounted debugfs */ | ||
43 | const 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 | |||
86 | int 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 | |||
99 | int 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 | |||
111 | int 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 | |||
141 | int 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 | |||
160 | int 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 | */ | ||
205 | int 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 | |||
15 | extern const char *debugfs_find_mountpoint(void); | ||
16 | extern int debugfs_valid_mountpoint(const char *debugfs); | ||
17 | extern int debugfs_valid_entry(const char *path); | ||
18 | extern int debugfs_mount(const char *mountpoint); | ||
19 | extern int debugfs_umount(void); | ||
20 | extern int debugfs_write(const char *entry, const char *value); | ||
21 | extern int debugfs_read(const char *entry, char *buffer, size_t size); | ||
22 | extern void debugfs_force_cleanup(void); | ||
23 | extern 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 | |||
6 | static 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) { | ||
22 | out_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 | |||
78 | out_fclose: | ||
79 | fclose(fp); | ||
80 | return tgid; | ||
81 | |||
82 | out_failure: | ||
83 | pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | static 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 | |||
151 | int 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 | |||
159 | void 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 | |||
66 | struct build_id_event { | ||
67 | struct perf_event_header header; | ||
68 | u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; | ||
69 | char filename[]; | ||
70 | }; | ||
71 | |||
72 | struct 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 | ||
65 | typedef union event_union { | 79 | typedef union event_union { |
66 | struct perf_event_header header; | 80 | struct perf_event_header header; |
@@ -105,10 +119,15 @@ struct symbol; | |||
105 | 119 | ||
106 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); | 120 | typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym); |
107 | 121 | ||
108 | struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, | 122 | void 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); |
124 | struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen); | ||
110 | struct map *map__clone(struct map *self); | 125 | struct map *map__clone(struct map *self); |
111 | int map__overlap(struct map *l, struct map *r); | 126 | int map__overlap(struct map *l, struct map *r); |
112 | size_t map__fprintf(struct map *self, FILE *fp); | 127 | size_t map__fprintf(struct map *self, FILE *fp); |
128 | struct symbol *map__find_symbol(struct map *self, u64 ip, symbol_filter_t filter); | ||
129 | |||
130 | int event__synthesize_thread(pid_t pid, int (*process)(event_t *event)); | ||
131 | void 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 | ||
32 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id) | 36 | void perf_header_attr__delete(struct perf_header_attr *self) |
37 | { | ||
38 | free(self->id); | ||
39 | free(self); | ||
40 | } | ||
41 | |||
42 | int 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 | ||
65 | void perf_header__add_attr(struct perf_header *self, | 81 | int 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 | ||
127 | struct perf_file_section { | ||
128 | u64 offset; | ||
129 | u64 size; | ||
130 | }; | ||
131 | |||
132 | struct perf_file_attr { | 149 | struct 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 | ||
137 | struct perf_file_header { | 154 | void 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 | ||
147 | void perf_header__feat_trace_info(struct perf_header *header) | 159 | bool 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 | ||
152 | static void do_write(int fd, void *buf, size_t size) | 164 | static 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 | |||
179 | static 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 | ||
165 | static void perf_header__adds_write(struct perf_header *self, int fd) | 196 | static void |
197 | perf_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 | ||
191 | void 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 | |||
252 | void 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 | ||
275 | static void perf_header__adds_read(struct perf_header *self, int fd) | 341 | int 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 | ||
380 | int 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 | |||
408 | static 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 | |||
289 | struct perf_header *perf_header__read(int fd) | 433 | struct 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 | 18 | enum { |
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 | ||
26 | struct perf_file_section { | ||
27 | u64 offset; | ||
28 | u64 size; | ||
29 | }; | ||
30 | |||
31 | struct 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 | |||
41 | struct perf_header; | ||
42 | |||
43 | int perf_file_header__read(struct perf_file_header *self, | ||
44 | struct perf_header *ph, int fd); | ||
45 | |||
21 | struct perf_header { | 46 | struct 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 | ||
33 | struct perf_header *perf_header__read(int fd); | 58 | struct perf_header *perf_header__read(int fd); |
34 | void perf_header__write(struct perf_header *self, int fd); | 59 | void perf_header__write(struct perf_header *self, int fd, bool at_exit); |
35 | 60 | ||
36 | void perf_header__add_attr(struct perf_header *self, | 61 | int perf_header__add_attr(struct perf_header *self, |
37 | struct perf_header_attr *attr); | 62 | struct perf_header_attr *attr); |
38 | 63 | ||
39 | void perf_header__push_event(u64 id, const char *name); | 64 | void perf_header__push_event(u64 id, const char *name); |
40 | char *perf_header__find_event(u64 id); | 65 | char *perf_header__find_event(u64 id); |
41 | 66 | ||
67 | struct perf_header_attr *perf_header_attr__new(struct perf_event_attr *attr); | ||
68 | void perf_header_attr__delete(struct perf_header_attr *self); | ||
42 | 69 | ||
43 | struct perf_header_attr * | 70 | int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); |
44 | perf_header_attr__new(struct perf_event_attr *attr); | ||
45 | void perf_header_attr__add_id(struct perf_header_attr *self, u64 id); | ||
46 | 71 | ||
47 | u64 perf_header__sample_type(struct perf_header *header); | 72 | u64 perf_header__sample_type(struct perf_header *header); |
48 | struct perf_event_attr * | 73 | struct perf_event_attr * |
49 | perf_header__find_attr(u64 id, struct perf_header *header); | 74 | perf_header__find_attr(u64 id, struct perf_header *header); |
50 | void perf_header__feat_trace_info(struct perf_header *header); | 75 | void perf_header__set_feat(struct perf_header *self, int feat); |
76 | bool perf_header__has_feat(const struct perf_header *self, int feat); | ||
51 | 77 | ||
52 | struct perf_header *perf_header__new(void); | 78 | struct perf_header *perf_header__new(void); |
53 | 79 | ||
80 | int 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 | ||
23 | struct map *map__new(struct mmap_event *event, char *cwd, int cwdlen, | 23 | void 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 | |||
35 | struct 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; |
80 | out_delete: | 73 | out_delete: |
@@ -82,6 +75,47 @@ out_delete: | |||
82 | return NULL; | 75 | return NULL; |
83 | } | 76 | } |
84 | 77 | ||
78 | #define DSO__DELETED "(deleted)" | ||
79 | |||
80 | struct symbol * | ||
81 | map__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 | |||
85 | struct map *map__clone(struct map *self) | 119 | struct 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 | ||
11 | int nr_counters; | 12 | int 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 | ||
152 | int 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 | ||
163 | struct tracepoint_path *tracepoint_id_to_path(u64 config) | 158 | struct 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 | ||
683 | modifier: | 680 | modifier: |
@@ -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 | ||
4 | static int hex(char ch) | 6 | static 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 | */ | ||
55 | s64 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; | ||
76 | kilo: | ||
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; | ||
87 | mega: | ||
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; | ||
98 | giga: | ||
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; | ||
109 | tera: | ||
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 | |||
125 | out_err: | ||
126 | length = -1; | ||
127 | out: | ||
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 | ||
6 | int hex2u64(const char *ptr, u64 *val); | 6 | int hex2u64(const char *ptr, u64 *val); |
7 | char *strxfrchar(char *s, char from, char to); | 7 | char *strxfrchar(char *s, char from, char to); |
8 | s64 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); | |||
26 | static struct dso *dsos__find(const char *name); | 26 | static struct dso *dsos__find(const char *name); |
27 | static struct map *map__new2(u64 start, struct dso *dso); | 27 | static struct map *map__new2(u64 start, struct dso *dso); |
28 | static void kernel_maps__insert(struct map *map); | 28 | static void kernel_maps__insert(struct map *map); |
29 | unsigned int symbol__priv_size; | ||
29 | 30 | ||
30 | static struct rb_root kernel_maps; | 31 | static struct rb_root kernel_maps; |
31 | 32 | ||
@@ -75,18 +76,17 @@ static void kernel_maps__fixup_end(void) | |||
75 | } | 76 | } |
76 | } | 77 | } |
77 | 78 | ||
78 | static struct symbol *symbol__new(u64 start, u64 len, const char *name, | 79 | static 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 | ||
101 | static void symbol__delete(struct symbol *self, unsigned int priv_size) | 101 | static 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 | ||
106 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 106 | static 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 | ||
112 | struct dso *dso__new(const char *name, unsigned int sym_priv_size) | 112 | struct 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 | ||
152 | void 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 | |||
151 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) | 158 | static 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 | ||
193 | size_t dso__fprintf(struct dso *self, FILE *fp) | 200 | int 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 | |||
215 | size_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 | |||
223 | size_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)) { |
337 | delete_symbol: | 373 | delete_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 | */ |
535 | static int dso__synthesize_plt_symbols(struct dso *self) | 570 | static 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; |
805 | new_symbol: | 849 | new_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 | 875 | bool fetch_build_id_table(struct list_head *head) |
876 | { | ||
877 | bool have_buildid = false; | ||
878 | struct dso *pos; | ||
833 | 879 | ||
834 | static 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 | |||
909 | int 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); | ||
880 | out_elf_end: | 946 | out_elf_end: |
881 | elf_end(elf); | 947 | elf_end(elf); |
882 | out_close: | 948 | out_close: |
883 | close(fd); | 949 | close(fd); |
884 | out: | 950 | out: |
951 | return err; | ||
952 | } | ||
953 | |||
954 | static 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); | ||
969 | out: | ||
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 | ||
926 | more: | 1013 | more: |
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); | ||
1052 | compare_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 | ||
1146 | static int dsos__load_modules(unsigned int sym_priv_size) | 1246 | static 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 | ||
1227 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, | 1329 | int 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 | ||
1315 | struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, | 1417 | struct 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 | ||
1340 | int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter) | 1438 | size_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 | |||
1450 | int 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 | ||
1355 | void symbol__init(void) | 1464 | void 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 | ||
52 | extern unsigned int symbol__priv_size; | ||
53 | |||
54 | static inline void *symbol__priv(struct symbol *self) | ||
55 | { | ||
56 | return ((void *)self) - symbol__priv_size; | ||
57 | } | ||
58 | |||
42 | struct dso { | 59 | struct 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 | ||
55 | struct dso *dso__new(const char *name, unsigned int sym_priv_size); | 74 | struct dso *dso__new(const char *name); |
56 | void dso__delete(struct dso *self); | 75 | void dso__delete(struct dso *self); |
57 | 76 | ||
58 | static inline void *dso__sym_priv(struct dso *self, struct symbol *sym) | ||
59 | { | ||
60 | return ((void *)sym) - self->sym_priv_size; | ||
61 | } | ||
62 | |||
63 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); | 77 | struct symbol *dso__find_symbol(struct dso *self, u64 ip); |
64 | 78 | ||
65 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, | 79 | int dsos__load_kernel(const char *vmlinux, symbol_filter_t filter, int modules); |
66 | symbol_filter_t filter, int modules); | 80 | struct dso *dsos__findnew(const char *name); |
67 | struct dso *dsos__findnew(const char *name, unsigned int sym_priv_size, | ||
68 | bool *is_new); | ||
69 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); | 81 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter); |
70 | void dsos__fprintf(FILE *fp); | 82 | void dsos__fprintf(FILE *fp); |
83 | size_t dsos__fprintf_buildid(FILE *fp); | ||
71 | 84 | ||
85 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp); | ||
72 | size_t dso__fprintf(struct dso *self, FILE *fp); | 86 | size_t dso__fprintf(struct dso *self, FILE *fp); |
73 | char dso__symtab_origin(const struct dso *self); | 87 | char dso__symtab_origin(const struct dso *self); |
88 | void dso__set_build_id(struct dso *self, void *build_id); | ||
89 | |||
90 | int filename__read_build_id(const char *filename, void *bf, size_t size); | ||
91 | bool fetch_build_id_table(struct list_head *head); | ||
92 | int build_id__sprintf(u8 *self, int len, char *bf); | ||
74 | 93 | ||
75 | int load_kernel(unsigned int sym_priv_size, symbol_filter_t filter); | 94 | int load_kernel(symbol_filter_t filter); |
76 | 95 | ||
77 | void symbol__init(void); | 96 | void symbol__init(unsigned int priv_size); |
78 | 97 | ||
79 | extern struct list_head dsos; | 98 | extern struct list_head dsos; |
80 | extern struct map *kernel_map; | 99 | extern 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) |