diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 1 | ||||
-rw-r--r-- | tools/perf/util/header.c | 82 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 17 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 | ||||
-rw-r--r-- | tools/perf/util/util.c | 69 | ||||
-rw-r--r-- | tools/perf/util/util.h | 3 |
6 files changed, 165 insertions, 9 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index fafea0b6f323..7c846424aebf 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -425,6 +425,7 @@ LIB_OBJS += util/svghelper.o | |||
425 | LIB_OBJS += util/sort.o | 425 | LIB_OBJS += util/sort.o |
426 | LIB_OBJS += util/hist.o | 426 | LIB_OBJS += util/hist.o |
427 | LIB_OBJS += util/probe-event.o | 427 | LIB_OBJS += util/probe-event.o |
428 | LIB_OBJS += util/util.o | ||
428 | 429 | ||
429 | BUILTIN_OBJS += builtin-annotate.o | 430 | BUILTIN_OBJS += builtin-annotate.o |
430 | 431 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8a0bca55106f..df237c3a041b 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -169,20 +169,23 @@ static int do_write(int fd, const void *buf, size_t size) | |||
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | 171 | ||
172 | #define dsos__for_each_with_build_id(pos, head) \ | ||
173 | list_for_each_entry(pos, head, node) \ | ||
174 | if (!pos->has_build_id) \ | ||
175 | continue; \ | ||
176 | else | ||
177 | |||
172 | static int __dsos__write_buildid_table(struct list_head *head, int fd) | 178 | static int __dsos__write_buildid_table(struct list_head *head, int fd) |
173 | { | 179 | { |
174 | #define NAME_ALIGN 64 | 180 | #define NAME_ALIGN 64 |
175 | struct dso *pos; | 181 | struct dso *pos; |
176 | static const char zero_buf[NAME_ALIGN]; | 182 | static const char zero_buf[NAME_ALIGN]; |
177 | 183 | ||
178 | list_for_each_entry(pos, head, node) { | 184 | dsos__for_each_with_build_id(pos, head) { |
179 | int err; | 185 | int err; |
180 | struct build_id_event b; | 186 | struct build_id_event b; |
181 | size_t len; | 187 | size_t len = pos->long_name_len + 1; |
182 | 188 | ||
183 | if (!pos->has_build_id) | ||
184 | continue; | ||
185 | len = pos->long_name_len + 1; | ||
186 | len = ALIGN(len, NAME_ALIGN); | 189 | len = ALIGN(len, NAME_ALIGN); |
187 | memset(&b, 0, sizeof(b)); | 190 | memset(&b, 0, sizeof(b)); |
188 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); | 191 | memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); |
@@ -209,6 +212,74 @@ static int dsos__write_buildid_table(int fd) | |||
209 | return err; | 212 | return err; |
210 | } | 213 | } |
211 | 214 | ||
215 | static int dso__cache_build_id(struct dso *self, const char *debugdir) | ||
216 | { | ||
217 | const size_t size = PATH_MAX; | ||
218 | char *filename = malloc(size), | ||
219 | *linkname = malloc(size), *targetname, *sbuild_id; | ||
220 | int len, err = -1; | ||
221 | |||
222 | if (filename == NULL || linkname == NULL) | ||
223 | goto out_free; | ||
224 | |||
225 | len = snprintf(filename, size, "%s%s", debugdir, self->long_name); | ||
226 | if (mkdir_p(filename, 0755)) | ||
227 | goto out_free; | ||
228 | |||
229 | len += snprintf(filename + len, sizeof(filename) - len, "/"); | ||
230 | sbuild_id = filename + len; | ||
231 | build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); | ||
232 | |||
233 | if (access(filename, F_OK) && link(self->long_name, filename) && | ||
234 | copyfile(self->long_name, filename)) | ||
235 | goto out_free; | ||
236 | |||
237 | len = snprintf(linkname, size, "%s/.build-id/%.2s", | ||
238 | debugdir, sbuild_id); | ||
239 | |||
240 | if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) | ||
241 | goto out_free; | ||
242 | |||
243 | snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); | ||
244 | targetname = filename + strlen(debugdir) - 5; | ||
245 | memcpy(targetname, "../..", 5); | ||
246 | |||
247 | if (symlink(targetname, linkname) == 0) | ||
248 | err = 0; | ||
249 | out_free: | ||
250 | free(filename); | ||
251 | free(linkname); | ||
252 | return err; | ||
253 | } | ||
254 | |||
255 | static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) | ||
256 | { | ||
257 | struct dso *pos; | ||
258 | int err = 0; | ||
259 | |||
260 | dsos__for_each_with_build_id(pos, head) | ||
261 | if (dso__cache_build_id(pos, debugdir)) | ||
262 | err = -1; | ||
263 | |||
264 | return err; | ||
265 | } | ||
266 | |||
267 | static int dsos__cache_build_ids(void) | ||
268 | { | ||
269 | int err_kernel, err_user; | ||
270 | char debugdir[PATH_MAX]; | ||
271 | |||
272 | snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"), | ||
273 | DEBUG_CACHE_DIR); | ||
274 | |||
275 | if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) | ||
276 | return -1; | ||
277 | |||
278 | err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir); | ||
279 | err_user = __dsos__cache_build_ids(&dsos__user, debugdir); | ||
280 | return err_kernel || err_user ? -1 : 0; | ||
281 | } | ||
282 | |||
212 | static int perf_header__adds_write(struct perf_header *self, int fd) | 283 | static int perf_header__adds_write(struct perf_header *self, int fd) |
213 | { | 284 | { |
214 | int nr_sections; | 285 | int nr_sections; |
@@ -258,6 +329,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd) | |||
258 | goto out_free; | 329 | goto out_free; |
259 | } | 330 | } |
260 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; | 331 | buildid_sec->size = lseek(fd, 0, SEEK_CUR) - buildid_sec->offset; |
332 | dsos__cache_build_ids(); | ||
261 | } | 333 | } |
262 | 334 | ||
263 | lseek(fd, sec_start, SEEK_SET); | 335 | lseek(fd, sec_start, SEEK_SET); |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index ab92763edb03..79ca6a099f96 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -22,6 +22,7 @@ | |||
22 | enum dso_origin { | 22 | enum dso_origin { |
23 | DSO__ORIG_KERNEL = 0, | 23 | DSO__ORIG_KERNEL = 0, |
24 | DSO__ORIG_JAVA_JIT, | 24 | DSO__ORIG_JAVA_JIT, |
25 | DSO__ORIG_BUILD_ID_CACHE, | ||
25 | DSO__ORIG_FEDORA, | 26 | DSO__ORIG_FEDORA, |
26 | DSO__ORIG_UBUNTU, | 27 | DSO__ORIG_UBUNTU, |
27 | DSO__ORIG_BUILDID, | 28 | DSO__ORIG_BUILDID, |
@@ -1191,6 +1192,7 @@ char dso__symtab_origin(const struct dso *self) | |||
1191 | static const char origin[] = { | 1192 | static const char origin[] = { |
1192 | [DSO__ORIG_KERNEL] = 'k', | 1193 | [DSO__ORIG_KERNEL] = 'k', |
1193 | [DSO__ORIG_JAVA_JIT] = 'j', | 1194 | [DSO__ORIG_JAVA_JIT] = 'j', |
1195 | [DSO__ORIG_BUILD_ID_CACHE] = 'B', | ||
1194 | [DSO__ORIG_FEDORA] = 'f', | 1196 | [DSO__ORIG_FEDORA] = 'f', |
1195 | [DSO__ORIG_UBUNTU] = 'u', | 1197 | [DSO__ORIG_UBUNTU] = 'u', |
1196 | [DSO__ORIG_BUILDID] = 'b', | 1198 | [DSO__ORIG_BUILDID] = 'b', |
@@ -1209,6 +1211,7 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session, | |||
1209 | int size = PATH_MAX; | 1211 | int size = PATH_MAX; |
1210 | char *name; | 1212 | char *name; |
1211 | u8 build_id[BUILD_ID_SIZE]; | 1213 | u8 build_id[BUILD_ID_SIZE]; |
1214 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
1212 | int ret = -1; | 1215 | int ret = -1; |
1213 | int fd; | 1216 | int fd; |
1214 | 1217 | ||
@@ -1230,8 +1233,16 @@ int dso__load(struct dso *self, struct map *map, struct perf_session *session, | |||
1230 | return ret; | 1233 | return ret; |
1231 | } | 1234 | } |
1232 | 1235 | ||
1233 | self->origin = DSO__ORIG_FEDORA - 1; | 1236 | self->origin = DSO__ORIG_BUILD_ID_CACHE; |
1234 | 1237 | ||
1238 | if (self->has_build_id) { | ||
1239 | build_id__sprintf(self->build_id, sizeof(self->build_id), | ||
1240 | build_id_hex); | ||
1241 | snprintf(name, size, "%s/%s/.build-id/%.2s/%s", | ||
1242 | getenv("HOME"), DEBUG_CACHE_DIR, | ||
1243 | build_id_hex, build_id_hex + 2); | ||
1244 | goto open_file; | ||
1245 | } | ||
1235 | more: | 1246 | more: |
1236 | do { | 1247 | do { |
1237 | self->origin++; | 1248 | self->origin++; |
@@ -1247,8 +1258,6 @@ more: | |||
1247 | case DSO__ORIG_BUILDID: | 1258 | case DSO__ORIG_BUILDID: |
1248 | if (filename__read_build_id(self->long_name, build_id, | 1259 | if (filename__read_build_id(self->long_name, build_id, |
1249 | sizeof(build_id))) { | 1260 | sizeof(build_id))) { |
1250 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
1251 | |||
1252 | build_id__sprintf(build_id, sizeof(build_id), | 1261 | build_id__sprintf(build_id, sizeof(build_id), |
1253 | build_id_hex); | 1262 | build_id_hex); |
1254 | snprintf(name, size, | 1263 | snprintf(name, size, |
@@ -1276,7 +1285,7 @@ compare_build_id: | |||
1276 | if (!dso__build_id_equal(self, build_id)) | 1285 | if (!dso__build_id_equal(self, build_id)) |
1277 | goto more; | 1286 | goto more; |
1278 | } | 1287 | } |
1279 | 1288 | open_file: | |
1280 | fd = open(name, O_RDONLY); | 1289 | fd = open(name, O_RDONLY); |
1281 | } while (fd < 0); | 1290 | } while (fd < 0); |
1282 | 1291 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 9eabd60f819d..f27e158943e9 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <linux/rbtree.h> | 8 | #include <linux/rbtree.h> |
9 | #include "event.h" | 9 | #include "event.h" |
10 | 10 | ||
11 | #define DEBUG_CACHE_DIR ".debug" | ||
12 | |||
11 | #ifdef HAVE_CPLUS_DEMANGLE | 13 | #ifdef HAVE_CPLUS_DEMANGLE |
12 | extern char *cplus_demangle(const char *, int); | 14 | extern char *cplus_demangle(const char *, int); |
13 | 15 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c new file mode 100644 index 000000000000..f3c0798a5e78 --- /dev/null +++ b/tools/perf/util/util.c | |||
@@ -0,0 +1,69 @@ | |||
1 | #include <sys/mman.h> | ||
2 | #include <sys/stat.h> | ||
3 | #include <sys/types.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <string.h> | ||
6 | #include <unistd.h> | ||
7 | #include "util.h" | ||
8 | |||
9 | int mkdir_p(char *path, mode_t mode) | ||
10 | { | ||
11 | struct stat st; | ||
12 | int err; | ||
13 | char *d = path; | ||
14 | |||
15 | if (*d != '/') | ||
16 | return -1; | ||
17 | |||
18 | if (stat(path, &st) == 0) | ||
19 | return 0; | ||
20 | |||
21 | while (*++d == '/'); | ||
22 | |||
23 | while ((d = strchr(d, '/'))) { | ||
24 | *d = '\0'; | ||
25 | err = stat(path, &st) && mkdir(path, mode); | ||
26 | *d++ = '/'; | ||
27 | if (err) | ||
28 | return -1; | ||
29 | while (*d == '/') | ||
30 | ++d; | ||
31 | } | ||
32 | return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0; | ||
33 | } | ||
34 | |||
35 | int copyfile(const char *from, const char *to) | ||
36 | { | ||
37 | int fromfd, tofd; | ||
38 | struct stat st; | ||
39 | void *addr; | ||
40 | int err = -1; | ||
41 | |||
42 | if (stat(from, &st)) | ||
43 | goto out; | ||
44 | |||
45 | fromfd = open(from, O_RDONLY); | ||
46 | if (fromfd < 0) | ||
47 | goto out; | ||
48 | |||
49 | tofd = creat(to, 0755); | ||
50 | if (tofd < 0) | ||
51 | goto out_close_from; | ||
52 | |||
53 | addr = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fromfd, 0); | ||
54 | if (addr == MAP_FAILED) | ||
55 | goto out_close_to; | ||
56 | |||
57 | if (write(tofd, addr, st.st_size) == st.st_size) | ||
58 | err = 0; | ||
59 | |||
60 | munmap(addr, st.st_size); | ||
61 | out_close_to: | ||
62 | close(tofd); | ||
63 | if (err) | ||
64 | unlink(to); | ||
65 | out_close_from: | ||
66 | close(fromfd); | ||
67 | out: | ||
68 | return err; | ||
69 | } | ||
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index c673d8825883..0f5b2a6f1080 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -403,4 +403,7 @@ void git_qsort(void *base, size_t nmemb, size_t size, | |||
403 | #endif | 403 | #endif |
404 | #endif | 404 | #endif |
405 | 405 | ||
406 | int mkdir_p(char *path, mode_t mode); | ||
407 | int copyfile(const char *from, const char *to); | ||
408 | |||
406 | #endif | 409 | #endif |