From: Paul Floyd Date: Sat, 7 Sep 2024 07:06:03 +0000 (+0200) Subject: Bug 492663 - Valgrind ignores debug info for some binaries X-Git-Tag: VALGRIND_3_24_0~73 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1076dc0912e68b085de2bbf52e9e31cb32866f85;p=thirdparty%2Fvalgrind.git Bug 492663 - Valgrind ignores debug info for some binaries ML_(check_elf_and_get_rw_loads) now always checks for merged PT_LOADs when called from valgrind_main when iterating over nsegments. Updated comments and changed variable names and the debug message when the number of expected RW PT_LOADs hasn't been reached. --- diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index cc79429bd..a6a0f79b3 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -1072,7 +1072,8 @@ static ULong di_notify_ACHIEVE_ACCEPT_STATE ( struct _DebugInfo* di ) exe_handlers->load_fn ( == VG_(load_ELF) ) [or load_MACHO]. - This does the mmap'ing and creates the associated NSegments. + This does the mmap'ing with VG_(am_do_mmap_NO_NOTIFY) + and creates the associated NSegments. The NSegments may get merged, (see maybe_merge_nsegments) so there could be more PT_LOADs than there are NSegments. @@ -1125,7 +1126,7 @@ static ULong di_notify_ACHIEVE_ACCEPT_STATE ( struct _DebugInfo* di ) ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) { NSegment const * seg; - Int rw_load_count; + Int expected_rw_load_count; const HChar* filename; Bool is_rx_map, is_rw_map, is_ro_map; @@ -1372,9 +1373,9 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) /* We're only interested in mappings of object files. */ # if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) - rw_load_count = 0; + expected_rw_load_count = 0; - elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &rw_load_count ); + elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &expected_rw_load_count, use_fd == -1 ); if (use_fd == -1) { VG_(close)( actual_fd ); @@ -1444,7 +1445,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) /* So, finally, are we in an accept state? */ vg_assert(!di->have_dinfo); if (di->fsm.have_rx_map && - di->fsm.rw_map_count == rw_load_count) { + di->fsm.rw_map_count == expected_rw_load_count) { /* Ok, so, finally, we found what we need, and we haven't already read debuginfo for this object. So let's do so now. Yee-ha! */ @@ -1457,7 +1458,8 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) /* If we don't have an rx and rw mapping, go no further. */ if (debug) VG_(dmsg)("di_notify_mmap-6: " - "no dinfo loaded %s (no rx or no rw mapping)\n", filename); + "no dinfo loaded %s (no rx or rw mappings (%d) not reached expected count (%d))\n", + filename, di->fsm.rw_map_count, expected_rw_load_count); return 0; } } diff --git a/coregrind/m_debuginfo/priv_readelf.h b/coregrind/m_debuginfo/priv_readelf.h index 7e0fa17c9..75e02c980 100644 --- a/coregrind/m_debuginfo/priv_readelf.h +++ b/coregrind/m_debuginfo/priv_readelf.h @@ -62,7 +62,8 @@ extern Bool ML_(read_elf_object) ( DebugInfo* di ); function. */ extern Bool ML_(read_elf_debug) ( DebugInfo* di ); -extern Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count ); +extern Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, + Int * rw_load_count, Bool from_nsegments ); #endif /* ndef __PRIV_READELF_H */ diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index 735f83044..b037b9201 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -3852,7 +3852,8 @@ Bool ML_(read_elf_debug) ( struct _DebugInfo* di ) /* NOTREACHED */ } -Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count ) +Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, + Int * rw_load_count, Bool from_nsegments ) { Bool res, ok; UWord i; @@ -3924,9 +3925,10 @@ Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_l * Hold your horses * Just because The ELF file contains 2 RW PT_LOAD segments * doesn't mean that Valgrind will also make 2 calls to - * VG_(di_notify_mmap): in some cases, the 2 NSegments will get - * merged and VG_(di_notify_mmap) only gets called once. - * How to detect that the segments will be merged ? + * VG_(di_notify_mmap): in some cases, the 2 NSegments will + * have been merged and VG_(di_notify_mmap) only gets called + * once. + * How to detect that the segments were be merged ? * Logically, they will be merged if the first segment ends * at the beginning of the second segment: * Seg1 virtual address + Seg1 segment_size @@ -3949,12 +3951,12 @@ Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_l * the 2 different segments loaded separately are both counted * here, we use the non rounded up p_filesz. * This is all a nightmare/hack. Something cleaner should be - * done than trying to guess here if segments will or will not - * be merged later depending on how the loader will load - * with or without rounding up. - * */ + * done than other than reverse engineering whether this call + * results from merged nsegments or not. Particularly as + * the mmap'ing and nsegment merging is all under our control. + */ if (previous_rw_a_phdr.p_memsz > 0 && - ehdr_m.e_type == ET_EXEC && + from_nsegments && previous_rw_a_phdr.p_vaddr + previous_rw_a_phdr.p_filesz == a_phdr.p_vaddr) {