Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf callchain: Separate eh/debug frame offset cache.

Commit f1f13af99a90 ("perf callchain: Cache eh/debug frame offset for
dwarf unwind") introduces a cache for .debug_frame and .eh_frame_hdr.
Unfortunately, it makes them share a same cache (dso->frame_offset).
Which causes unwind failure on ARM:

$ perf test unwind
Test dwarf unwind: FAILED!

The reason is that, if a dso has '.debug_frame' but doesn't have
'.eh_frame_hdr' (like ARM), dso->frame_offset will be filled by offset
of '.debug_frame' during the first time calling of find_proc_info() ->
read_unwind_spec_debug_frame(), and be regarded to '.eh_frame_hdr' when
the second time calling of find_proc_info() ->
read_unwind_spec_eh_frame(), since '.eh_frame_hdr' is checked prior to
'.debug_frame'.

This patch solves the problem by creating two cache fields for
'.eh_frame_hdr' and '.debug_frame'.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Link: http://lkml.kernel.org/r/55028BA0.1030701@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
303cb89a 1312c8a8

+6 -5
+2 -1
tools/perf/util/dso.h
··· 139 139 u32 status_seen; 140 140 size_t file_size; 141 141 struct list_head open_entry; 142 - u64 frame_offset; 142 + u64 debug_frame_offset; 143 + u64 eh_frame_hdr_offset; 143 144 } data; 144 145 145 146 union { /* Tool specific area */
+4 -4
tools/perf/util/unwind-libunwind.c
··· 266 266 u64 *fde_count) 267 267 { 268 268 int ret = -EINVAL, fd; 269 - u64 offset = dso->data.frame_offset; 269 + u64 offset = dso->data.eh_frame_hdr_offset; 270 270 271 271 if (offset == 0) { 272 272 fd = dso__data_fd(dso, machine); ··· 275 275 276 276 /* Check the .eh_frame section for unwinding info */ 277 277 offset = elf_section_offset(fd, ".eh_frame_hdr"); 278 - dso->data.frame_offset = offset; 278 + dso->data.eh_frame_hdr_offset = offset; 279 279 } 280 280 281 281 if (offset) ··· 291 291 struct machine *machine, u64 *offset) 292 292 { 293 293 int fd; 294 - u64 ofs = dso->data.frame_offset; 294 + u64 ofs = dso->data.debug_frame_offset; 295 295 296 296 if (ofs == 0) { 297 297 fd = dso__data_fd(dso, machine); ··· 300 300 301 301 /* Check the .debug_frame section for unwinding info */ 302 302 ofs = elf_section_offset(fd, ".debug_frame"); 303 - dso->data.frame_offset = ofs; 303 + dso->data.debug_frame_offset = ofs; 304 304 } 305 305 306 306 *offset = ofs;