diff options
author | Namhyung Kim <namhyung@kernel.org> | 2015-05-20 12:03:41 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-05-27 11:21:44 -0400 |
commit | 4bb11d012ab248d0e383008d725be0d26a74fac2 (patch) | |
tree | 56d8b7f278f2dad61c936b981b2844249e48c129 /tools | |
parent | e840238d7c6afcde0f6402aac3a74723ee9c448f (diff) |
perf tools: Add dso__data_get/put_fd()
Using dso__data_fd() in multi-thread environment is not safe since
returned fd can be closed and/or reused anytime.
So convert it to the dso__data_get/put_fd() pair to protect the access
with lock.
The original dso__data_fd() is deprecated and kept only for testing.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1432137821-10853-3-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/tests/dso-data.c | 11 | ||||
-rw-r--r-- | tools/perf/util/dso.c | 31 | ||||
-rw-r--r-- | tools/perf/util/dso.h | 13 | ||||
-rw-r--r-- | tools/perf/util/unwind-libunwind.c | 11 |
4 files changed, 50 insertions, 16 deletions
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 513e5febbe5a..3e41c61bd861 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -99,6 +99,17 @@ struct test_data_offset offsets[] = { | |||
99 | }, | 99 | }, |
100 | }; | 100 | }; |
101 | 101 | ||
102 | /* move it from util/dso.c for compatibility */ | ||
103 | static int dso__data_fd(struct dso *dso, struct machine *machine) | ||
104 | { | ||
105 | int fd = dso__data_get_fd(dso, machine); | ||
106 | |||
107 | if (fd >= 0) | ||
108 | dso__data_put_fd(dso); | ||
109 | |||
110 | return fd; | ||
111 | } | ||
112 | |||
102 | int test__dso_data(void) | 113 | int test__dso_data(void) |
103 | { | 114 | { |
104 | struct machine machine; | 115 | struct machine machine; |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index e95e850dd832..7e11a700303f 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -473,25 +473,35 @@ out: | |||
473 | } | 473 | } |
474 | 474 | ||
475 | /** | 475 | /** |
476 | * dso__data_fd - Get dso's data file descriptor | 476 | * dso__data_get_fd - Get dso's data file descriptor |
477 | * @dso: dso object | 477 | * @dso: dso object |
478 | * @machine: machine object | 478 | * @machine: machine object |
479 | * | 479 | * |
480 | * External interface to find dso's file, open it and | 480 | * External interface to find dso's file, open it and |
481 | * returns file descriptor. | 481 | * returns file descriptor. It should be paired with |
482 | * dso__data_put_fd() if it returns non-negative value. | ||
482 | */ | 483 | */ |
483 | int dso__data_fd(struct dso *dso, struct machine *machine) | 484 | int dso__data_get_fd(struct dso *dso, struct machine *machine) |
484 | { | 485 | { |
485 | if (dso->data.status == DSO_DATA_STATUS_ERROR) | 486 | if (dso->data.status == DSO_DATA_STATUS_ERROR) |
486 | return -1; | 487 | return -1; |
487 | 488 | ||
488 | pthread_mutex_lock(&dso__data_open_lock); | 489 | if (pthread_mutex_lock(&dso__data_open_lock) < 0) |
490 | return -1; | ||
491 | |||
489 | try_to_open_dso(dso, machine); | 492 | try_to_open_dso(dso, machine); |
490 | pthread_mutex_unlock(&dso__data_open_lock); | 493 | |
494 | if (dso->data.fd < 0) | ||
495 | pthread_mutex_unlock(&dso__data_open_lock); | ||
491 | 496 | ||
492 | return dso->data.fd; | 497 | return dso->data.fd; |
493 | } | 498 | } |
494 | 499 | ||
500 | void dso__data_put_fd(struct dso *dso __maybe_unused) | ||
501 | { | ||
502 | pthread_mutex_unlock(&dso__data_open_lock); | ||
503 | } | ||
504 | |||
495 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) | 505 | bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) |
496 | { | 506 | { |
497 | u32 flag = 1 << by; | 507 | u32 flag = 1 << by; |
@@ -1199,12 +1209,15 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | |||
1199 | enum dso_type dso__type(struct dso *dso, struct machine *machine) | 1209 | enum dso_type dso__type(struct dso *dso, struct machine *machine) |
1200 | { | 1210 | { |
1201 | int fd; | 1211 | int fd; |
1212 | enum dso_type type = DSO__TYPE_UNKNOWN; | ||
1202 | 1213 | ||
1203 | fd = dso__data_fd(dso, machine); | 1214 | fd = dso__data_get_fd(dso, machine); |
1204 | if (fd < 0) | 1215 | if (fd >= 0) { |
1205 | return DSO__TYPE_UNKNOWN; | 1216 | type = dso__type_fd(fd); |
1217 | dso__data_put_fd(dso); | ||
1218 | } | ||
1206 | 1219 | ||
1207 | return dso__type_fd(fd); | 1220 | return type; |
1208 | } | 1221 | } |
1209 | 1222 | ||
1210 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) | 1223 | int dso__strerror_load(struct dso *dso, char *buf, size_t buflen) |
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index b26ec3ab1336..bcec06ad73a2 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h | |||
@@ -240,7 +240,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
240 | 240 | ||
241 | /* | 241 | /* |
242 | * The dso__data_* external interface provides following functions: | 242 | * The dso__data_* external interface provides following functions: |
243 | * dso__data_fd | 243 | * dso__data_get_fd |
244 | * dso__data_put_fd | ||
244 | * dso__data_close | 245 | * dso__data_close |
245 | * dso__data_size | 246 | * dso__data_size |
246 | * dso__data_read_offset | 247 | * dso__data_read_offset |
@@ -257,8 +258,11 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
257 | * The current usage of the dso__data_* interface is as follows: | 258 | * The current usage of the dso__data_* interface is as follows: |
258 | * | 259 | * |
259 | * Get DSO's fd: | 260 | * Get DSO's fd: |
260 | * int fd = dso__data_fd(dso, machine); | 261 | * int fd = dso__data_get_fd(dso, machine); |
261 | * USE 'fd' SOMEHOW | 262 | * if (fd >= 0) { |
263 | * USE 'fd' SOMEHOW | ||
264 | * dso__data_put_fd(dso); | ||
265 | * } | ||
262 | * | 266 | * |
263 | * Read DSO's data: | 267 | * Read DSO's data: |
264 | * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); | 268 | * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE); |
@@ -277,7 +281,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, | |||
277 | * | 281 | * |
278 | * TODO | 282 | * TODO |
279 | */ | 283 | */ |
280 | int dso__data_fd(struct dso *dso, struct machine *machine); | 284 | int dso__data_get_fd(struct dso *dso, struct machine *machine); |
285 | void dso__data_put_fd(struct dso *dso __maybe_unused); | ||
281 | void dso__data_close(struct dso *dso); | 286 | void dso__data_close(struct dso *dso); |
282 | 287 | ||
283 | off_t dso__data_size(struct dso *dso, struct machine *machine); | 288 | off_t dso__data_size(struct dso *dso, struct machine *machine); |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 7b09a443a280..f079b63f0b7f 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -269,13 +269,14 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, | |||
269 | u64 offset = dso->data.eh_frame_hdr_offset; | 269 | u64 offset = dso->data.eh_frame_hdr_offset; |
270 | 270 | ||
271 | if (offset == 0) { | 271 | if (offset == 0) { |
272 | fd = dso__data_fd(dso, machine); | 272 | fd = dso__data_get_fd(dso, machine); |
273 | if (fd < 0) | 273 | if (fd < 0) |
274 | return -EINVAL; | 274 | return -EINVAL; |
275 | 275 | ||
276 | /* Check the .eh_frame section for unwinding info */ | 276 | /* Check the .eh_frame section for unwinding info */ |
277 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 277 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
278 | dso->data.eh_frame_hdr_offset = offset; | 278 | dso->data.eh_frame_hdr_offset = offset; |
279 | dso__data_put_fd(dso); | ||
279 | } | 280 | } |
280 | 281 | ||
281 | if (offset) | 282 | if (offset) |
@@ -294,13 +295,14 @@ static int read_unwind_spec_debug_frame(struct dso *dso, | |||
294 | u64 ofs = dso->data.debug_frame_offset; | 295 | u64 ofs = dso->data.debug_frame_offset; |
295 | 296 | ||
296 | if (ofs == 0) { | 297 | if (ofs == 0) { |
297 | fd = dso__data_fd(dso, machine); | 298 | fd = dso__data_get_fd(dso, machine); |
298 | if (fd < 0) | 299 | if (fd < 0) |
299 | return -EINVAL; | 300 | return -EINVAL; |
300 | 301 | ||
301 | /* Check the .debug_frame section for unwinding info */ | 302 | /* Check the .debug_frame section for unwinding info */ |
302 | ofs = elf_section_offset(fd, ".debug_frame"); | 303 | ofs = elf_section_offset(fd, ".debug_frame"); |
303 | dso->data.debug_frame_offset = ofs; | 304 | dso->data.debug_frame_offset = ofs; |
305 | dso__data_put_fd(dso); | ||
304 | } | 306 | } |
305 | 307 | ||
306 | *offset = ofs; | 308 | *offset = ofs; |
@@ -353,10 +355,13 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
353 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | 355 | #ifndef NO_LIBUNWIND_DEBUG_FRAME |
354 | /* Check the .debug_frame section for unwinding info */ | 356 | /* Check the .debug_frame section for unwinding info */ |
355 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | 357 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { |
356 | int fd = dso__data_fd(map->dso, ui->machine); | 358 | int fd = dso__data_get_fd(map->dso, ui->machine); |
357 | int is_exec = elf_is_exec(fd, map->dso->name); | 359 | int is_exec = elf_is_exec(fd, map->dso->name); |
358 | unw_word_t base = is_exec ? 0 : map->start; | 360 | unw_word_t base = is_exec ? 0 : map->start; |
359 | 361 | ||
362 | if (fd >= 0) | ||
363 | dso__data_put_fd(dso); | ||
364 | |||
360 | memset(&di, 0, sizeof(di)); | 365 | memset(&di, 0, sizeof(di)); |
361 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, | 366 | if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, |
362 | map->start, map->end)) | 367 | map->start, map->end)) |