diff options
| author | Jean Pihet <jean.pihet@linaro.org> | 2013-09-26 07:36:38 -0400 |
|---|---|---|
| committer | Will Deacon <will.deacon@arm.com> | 2013-09-30 11:42:12 -0400 |
| commit | ab255e72204fc5127f0adf40ba103d9335fefa30 (patch) | |
| tree | 953f548561e3e4011f514deb5a5e80bbf8f13bf7 /tools | |
| parent | 405ffbd4988118c56ff127792ebddae77d2c7a43 (diff) | |
perf: parse the .debug_frame section in case .eh_frame is not present
On ARM the debug info is not present in the .eh_frame sections but
in .debug_frame instead, in dwarf format.
Use libunwind to load and parse the debug info.
Dependencies:
. if present, libunwind >= 1.1 is needed to prevent a segfault when
parsing the dwarf info,
. libunwind needs to be configured with --enable-debug-frame. Note:
--enable-debug-frame is automatically selected on ARM.
Acked-by: Jiri Olsa <jolsa@redhat.com>
Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/unwind.c | 75 |
1 files changed, 59 insertions, 16 deletions
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c index 2f891f7e70bf..5390d0b8862a 100644 --- a/tools/perf/util/unwind.c +++ b/tools/perf/util/unwind.c | |||
| @@ -39,6 +39,15 @@ UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | |||
| 39 | 39 | ||
| 40 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | 40 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) |
| 41 | 41 | ||
| 42 | extern int | ||
| 43 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | ||
| 44 | unw_word_t ip, | ||
| 45 | unw_word_t segbase, | ||
| 46 | const char *obj_name, unw_word_t start, | ||
| 47 | unw_word_t end); | ||
| 48 | |||
| 49 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | ||
| 50 | |||
| 42 | #define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ | 51 | #define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ |
| 43 | #define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ | 52 | #define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ |
| 44 | 53 | ||
| @@ -245,8 +254,9 @@ static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, | |||
| 245 | return 0; | 254 | return 0; |
| 246 | } | 255 | } |
| 247 | 256 | ||
| 248 | static int read_unwind_spec(struct dso *dso, struct machine *machine, | 257 | static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine, |
| 249 | u64 *table_data, u64 *segbase, u64 *fde_count) | 258 | u64 *table_data, u64 *segbase, |
| 259 | u64 *fde_count) | ||
| 250 | { | 260 | { |
| 251 | int ret = -EINVAL, fd; | 261 | int ret = -EINVAL, fd; |
| 252 | u64 offset; | 262 | u64 offset; |
| @@ -255,6 +265,7 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine, | |||
| 255 | if (fd < 0) | 265 | if (fd < 0) |
| 256 | return -EINVAL; | 266 | return -EINVAL; |
| 257 | 267 | ||
| 268 | /* Check the .eh_frame section for unwinding info */ | ||
| 258 | offset = elf_section_offset(fd, ".eh_frame_hdr"); | 269 | offset = elf_section_offset(fd, ".eh_frame_hdr"); |
| 259 | close(fd); | 270 | close(fd); |
| 260 | 271 | ||
| @@ -263,10 +274,29 @@ static int read_unwind_spec(struct dso *dso, struct machine *machine, | |||
| 263 | table_data, segbase, | 274 | table_data, segbase, |
| 264 | fde_count); | 275 | fde_count); |
| 265 | 276 | ||
| 266 | /* TODO .debug_frame check if eh_frame_hdr fails */ | ||
| 267 | return ret; | 277 | return ret; |
| 268 | } | 278 | } |
| 269 | 279 | ||
| 280 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | ||
| 281 | static int read_unwind_spec_debug_frame(struct dso *dso, | ||
| 282 | struct machine *machine, u64 *offset) | ||
| 283 | { | ||
| 284 | int fd = dso__data_fd(dso, machine); | ||
| 285 | |||
| 286 | if (fd < 0) | ||
| 287 | return -EINVAL; | ||
| 288 | |||
| 289 | /* Check the .debug_frame section for unwinding info */ | ||
| 290 | *offset = elf_section_offset(fd, ".debug_frame"); | ||
| 291 | close(fd); | ||
| 292 | |||
| 293 | if (*offset) | ||
| 294 | return 0; | ||
| 295 | |||
| 296 | return -EINVAL; | ||
| 297 | } | ||
| 298 | #endif | ||
| 299 | |||
| 270 | static struct map *find_map(unw_word_t ip, struct unwind_info *ui) | 300 | static struct map *find_map(unw_word_t ip, struct unwind_info *ui) |
| 271 | { | 301 | { |
| 272 | struct addr_location al; | 302 | struct addr_location al; |
| @@ -291,20 +321,33 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, | |||
| 291 | 321 | ||
| 292 | pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); | 322 | pr_debug("unwind: find_proc_info dso %s\n", map->dso->name); |
| 293 | 323 | ||
| 294 | if (read_unwind_spec(map->dso, ui->machine, | 324 | /* Check the .eh_frame section for unwinding info */ |
| 295 | &table_data, &segbase, &fde_count)) | 325 | if (!read_unwind_spec_eh_frame(map->dso, ui->machine, |
| 296 | return -EINVAL; | 326 | &table_data, &segbase, &fde_count)) { |
| 327 | memset(&di, 0, sizeof(di)); | ||
| 328 | di.format = UNW_INFO_FORMAT_REMOTE_TABLE; | ||
| 329 | di.start_ip = map->start; | ||
| 330 | di.end_ip = map->end; | ||
| 331 | di.u.rti.segbase = map->start + segbase; | ||
| 332 | di.u.rti.table_data = map->start + table_data; | ||
| 333 | di.u.rti.table_len = fde_count * sizeof(struct table_entry) | ||
| 334 | / sizeof(unw_word_t); | ||
| 335 | return dwarf_search_unwind_table(as, ip, &di, pi, | ||
| 336 | need_unwind_info, arg); | ||
| 337 | } | ||
| 338 | |||
| 339 | #ifndef NO_LIBUNWIND_DEBUG_FRAME | ||
| 340 | /* Check the .debug_frame section for unwinding info */ | ||
| 341 | if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { | ||
| 342 | memset(&di, 0, sizeof(di)); | ||
| 343 | dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name, | ||
| 344 | map->start, map->end); | ||
| 345 | return dwarf_search_unwind_table(as, ip, &di, pi, | ||
| 346 | need_unwind_info, arg); | ||
| 347 | } | ||
| 348 | #endif | ||
| 297 | 349 | ||
| 298 | memset(&di, 0, sizeof(di)); | 350 | return -EINVAL; |
| 299 | di.format = UNW_INFO_FORMAT_REMOTE_TABLE; | ||
| 300 | di.start_ip = map->start; | ||
| 301 | di.end_ip = map->end; | ||
| 302 | di.u.rti.segbase = map->start + segbase; | ||
| 303 | di.u.rti.table_data = map->start + table_data; | ||
| 304 | di.u.rti.table_len = fde_count * sizeof(struct table_entry) | ||
| 305 | / sizeof(unw_word_t); | ||
| 306 | return dwarf_search_unwind_table(as, ip, &di, pi, | ||
| 307 | need_unwind_info, arg); | ||
| 308 | } | 351 | } |
| 309 | 352 | ||
| 310 | static int access_fpreg(unw_addr_space_t __maybe_unused as, | 353 | static int access_fpreg(unw_addr_space_t __maybe_unused as, |
