Many changes mostly related to modifying VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd )
so that instead of triggering debuginfo reading after seeing one RX PT_LOAD and 1 RW PT_LOAD it
can handle either 1 or 2 RW PT_LOADs.
452779 Valgrind fails to build on FreeBSD 13.0 with llvm-devel (15.0.0)
453055 shared_timed_mutex drd test fails with "Lock shared failed" message
453602 Missing command line option to enable/disable debuginfod
+452802 Handle lld 9+ split RW PT_LOAD segments correctly
To see details of a given bug, visit
https://bugs.kde.org/show_bug.cgi?id=XXXXXX
been successfully read. And that shouldn't happen until we have
both a r-x and rw- mapping for the object. Hence: */
vg_assert(di->fsm.have_rx_map);
- vg_assert(di->fsm.have_rw_map);
+ vg_assert(di->fsm.rw_map_count);
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
/* We are interested in r-x mappings only */
/* Notify the debuginfo system about a new mapping. This is the way
- new debug information gets loaded. If allow_SkFileV is True, it
- will try load debug info if the mapping at 'a' belongs to Valgrind;
- whereas normally (False) it will not do that. This allows us to
- carefully control when the thing will read symbols from the
- Valgrind executable itself.
+ new debug information gets loaded.
+
+ redelf -e will output something like
+
+ readelf -e says
+
+ Program Headers:
+ Type Offset VirtAddr PhysAddr
+ FileSiz MemSiz Flg Align
+ PHDR 0x0000000000000040 0x0000000000200040 0x0000000000200040
+ 0x0000000000000268 0x0000000000000268 R 0x8
+ INTERP 0x00000000000002a8 0x00000000002002a8 0x00000000002002a8
+ 0x0000000000000015 0x0000000000000015 R 0x1
+ [Requesting program interpreter: /libexec/ld-elf.so.1]
+ LOAD 0x0000000000000000 0x0000000000200000 0x0000000000200000
+ 0x0000000000002acc 0x0000000000002acc R 0x1000
+ LOAD 0x0000000000002ad0 0x0000000000203ad0 0x0000000000203ad0
+ 0x0000000000004a70 0x0000000000004a70 R E 0x1000
+ LOAD 0x0000000000007540 0x0000000000209540 0x0000000000209540
+ 0x00000000000001d8 0x00000000000001d8 RW 0x1000
+ LOAD 0x0000000000007720 0x000000000020a720 0x000000000020a720
+ 0x00000000000002b8 0x00000000000005a0 RW 0x1000
+ DYNAMIC 0x0000000000007570 0x0000000000209570 0x0000000000209570
+ 0x00000000000001a0 0x00000000000001a0 RW 0x8
+ GNU_RELRO 0x0000000000007540 0x0000000000209540 0x0000000000209540
+ 0x00000000000001d8 0x00000000000001d8 R 0x1
+ GNU_EH_FRAME 0x0000000000002334 0x0000000000202334 0x0000000000202334
+ 0x000000000000012c 0x000000000000012c R 0x4
+ GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
+ 0x0000000000000000 0x0000000000000000 RW 0
+ NOTE 0x00000000000002c0 0x00000000002002c0 0x00000000002002c0
+ 0x0000000000000048 0x0000000000000048 R 0x4
+
+ This function will be called for the "LOAD" segments above.
+
+ This function gets called from 2 contexts
+
+ "HOST TRIGGERED"
+
+ 1a. For the tool exe and tool/core shared libs. These are already
+ mmap'd when the host starts so we look at something like the
+ /proc filesystem to get the mapping after the event and build
+ up the NSegments from that.
+
+ 1b. Then the host loads ld.so and the guest exe. This is done in
+ the sequence
+ load_client -> VG_(do_exec) -> VG_(do_exec_inner) ->
+ exe_handlers->load_fn ( == VG_(load_ELF) ).
+
+ This does the mmap'ing and creats the associated NSegments.
+
+ The NSegments may get merged, (see maybe_merge_nsegments)
+ so there could be more PT_LOADs than there are NSegments.
+ VG_(di_notify_mmap) is called by iterating over the
+ NSegments
+
+ "GUEST TRIGGERED"
+
+ 2. When the guest loads any further shared libs (libc,
+ other dependencies, dlopens) using mmap.
+
+ There are a few variations for syswraps/platforms.
+
+ In this case the NSegment could possibly be merged,
+ but that is irrelevant because di_notify_mmap is being
+ called directy on the mmap result.
+
+ If allow_SkFileV is True, it will try load debug info if the
+ mapping at 'a' belongs to Valgrind; whereas normally (False)
+ it will not do that. This allows us to carefully control when
+ the thing will read symbols from the Valgrind executable itself.
If use_fd is not -1, that is used instead of the filename; this
avoids perturbing fcntl locks, which are released by simply
re-opening and closing the same file (even via different fd!).
+ Read-only mappings will be ignored.
+ There may be 1 or 2 RW mappings.
+ There will also be 1 RX mapping.
+
+ If there is no RX or no RW mapping then we will not attempt to
+ read debuginfo for the file.
+
+ In order to know whether there are 1 or 2 RW mappings we
+ need to check the ELF headers. And in the case that we
+ detect 2 RW mappings we need to double check that they
+ aren't contiguous in memory resulting in merged NSegemnts.
+
+ This does not apply to Darwin which just checks the Mach-O header
+
If a call to VG_(di_notify_mmap) causes debug info to be read, then
the returned ULong is an abstract handle which can later be used to
refer to the debuginfo read as a result of this specific mapping,
ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd )
{
NSegment const * seg;
+ Int rw_load_count;
const HChar* filename;
Bool is_rx_map, is_rw_map, is_ro_map;
+
DebugInfo* di;
Int actual_fd, oflags;
+#if defined(VGO_darwin)
SysRes preadres;
HChar buf1k[1024];
+#else
+ Bool elf_ok;
+#endif
+
const Bool debug = VG_(debugLog_getLevel)() >= 3;
SysRes statres;
struct vg_stat statbuf;
return 0;
#endif
+#if defined(VGO_darwin)
/* Peer at the first few bytes of the file, to see if it is an ELF */
/* object file. Ignore the file if we do not have read permission. */
VG_(memset)(buf1k, 0, sizeof(buf1k));
+#endif
+
oflags = VKI_O_RDONLY;
# if defined(VKI_O_LARGEFILE)
oflags |= VKI_O_LARGEFILE;
actual_fd = use_fd;
}
+#if defined(VGO_darwin)
preadres = VG_(pread)( actual_fd, buf1k, sizeof(buf1k), 0 );
if (use_fd == -1) {
VG_(close)( actual_fd );
DebugInfo fake_di;
VG_(memset)(&fake_di, 0, sizeof(fake_di));
fake_di.fsm.filename = ML_(dinfo_strdup)("di.debuginfo.nmm", filename);
- ML_(symerr)(&fake_di, True, "can't read file to inspect ELF header");
+ ML_(symerr)(&fake_di, True, "can't read file to inspect Mach-O headers");
return 0;
}
if (sr_Res(preadres) == 0)
return 0;
vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf1k) );
+#endif
/* We're only interested in mappings of object files. */
# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
- if (!ML_(is_elf_object_file)( buf1k, (SizeT)sr_Res(preadres), False ))
+
+ rw_load_count = 0;
+
+ elf_ok = ML_(check_elf_and_get_rw_loads) ( actual_fd, filename, &rw_load_count );
+
+ if (use_fd == -1) {
+ VG_(close)( actual_fd );
+ }
+
+ if (!elf_ok) {
return 0;
+ }
+
# elif defined(VGO_darwin)
if (!ML_(is_macho_object_file)( buf1k, (SizeT)sr_Res(preadres) ))
return 0;
+ rw_load_count = 1;
# else
# error "unknown OS"
# endif
/* Update flags about what kind of mappings we've already seen. */
di->fsm.have_rx_map |= is_rx_map;
- di->fsm.have_rw_map |= is_rw_map;
+ /* This is a bit of a hack, using a Bool as a counter */
+ if (is_rw_map)
+ ++di->fsm.rw_map_count;
di->fsm.have_ro_map |= is_ro_map;
/* So, finally, are we in an accept state? */
vg_assert(!di->have_dinfo);
- if (di->fsm.have_rx_map && di->fsm.have_rw_map) {
+ if (di->fsm.have_rx_map &&
+ rw_load_count >= 1 &&
+ di->fsm.rw_map_count == 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! */
+
if (debug)
VG_(dmsg)("di_notify_mmap-5: "
"achieved accept state for %s\n", filename);
continue; /* need to have a r-- mapping for this object */
if (di->fsm.have_rx_map)
continue; /* rx- mapping already exists */
- if (!di->fsm.have_rw_map)
+ if (!di->fsm.rw_map_count)
continue; /* need to have a rw- mapping */
/* Try to find a mapping matching the memory area. */
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
}
/* Check if we're now in an accept state and read debuginfo. Finally. */
- if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
+ if (di->fsm.have_rx_map && di->fsm.rw_map_count && !di->have_dinfo) {
if (debug)
VG_(dmsg)("di_notify_vm_protect-5: "
"achieved accept state for %s\n", di->fsm.filename);
{ DebugInfo* di = find_or_create_DebugInfo_for(exename);
/* this di must be new, since we just nuked any old stuff in the range */
- vg_assert(di && !di->fsm.have_rx_map && !di->fsm.have_rw_map);
+ vg_assert(di && !di->fsm.have_rx_map && !di->fsm.rw_map_count);
vg_assert(!di->have_dinfo);
/* don't set up any of the di-> fields; let
return img;
}
+/* As above, but uses fd rather than filename */
+DiImage* ML_(img_from_fd)(Int fd, const HChar* fullpath)
+{
+ struct vg_stat stat_buf;
+ DiOffT size;
+
+ if (VG_(fstat)(fd, &stat_buf) != 0) {
+ return NULL;
+ }
+
+ size = stat_buf.size;
+ if (size == 0 || size == DiOffT_INVALID
+ || /* size is unrepresentable as a SizeT */
+ size != (DiOffT)(SizeT)(size)) {
+ return NULL;
+ }
+
+ DiImage* img = ML_(dinfo_zalloc)("di.image.ML_iflf.1", sizeof(DiImage));
+ img->source.is_local = True;
+ img->source.fd = fd;
+ img->size = size;
+ img->real_size = size;
+ img->ces_used = 0;
+ img->source.name = ML_(dinfo_strdup)("di.image.ML_iflf.2", fullpath);
+ img->cslc = NULL;
+ img->cslc_size = 0;
+ img->cslc_used = 0;
+ /* img->ces is already zeroed out */
+ vg_assert(img->source.fd >= 0);
+
+ /* Force the zeroth entry to be the first chunk of the file.
+ That's likely to be the first part that's requested anyway, and
+ loading it at this point forcing img->cent[0] to always be
+ non-empty, thereby saving us an is-it-empty check on the fast
+ path in get(). */
+ UInt entNo = alloc_CEnt(img, CACHE_ENTRY_SIZE, False/*!fromC*/);
+ vg_assert(entNo == 0);
+ set_CEnt(img, 0, 0);
+
+ return img;
+}
+
+
/* Create an image from a file on a remote debuginfo server. This is
more complex. There are lots of ways in which it can fail. */
return ret;
}
-void ML_(img_done)(DiImage* img)
+void ML_(img_free)(DiImage* img)
{
vg_assert(img != NULL);
- if (img->source.is_local) {
- /* Close the file; nothing else to do. */
- vg_assert(img->source.session_id == 0);
- VG_(close)(img->source.fd);
- } else {
- /* Close the socket. The server can detect this and will scrub
- the connection when it happens, so there's no need to tell it
- explicitly by sending it a "CLOSE" message, or any such. */
- vg_assert(img->source.session_id != 0);
- VG_(close)(img->source.fd);
- }
/* Free up the cache entries, ultimately |img| itself. */
UInt i;
ML_(dinfo_free)(img);
}
+void ML_(img_done)(DiImage* img)
+{
+ vg_assert(img != NULL);
+ if (img->source.is_local) {
+ /* Close the file; nothing else to do. */
+ vg_assert(img->source.session_id == 0);
+ VG_(close)(img->source.fd);
+ } else {
+ /* Close the socket. The server can detect this and will scrub
+ the connection when it happens, so there's no need to tell it
+ explicitly by sending it a "CLOSE" message, or any such. */
+ vg_assert(img->source.session_id != 0);
+ VG_(close)(img->source.fd);
+ }
+
+ ML_(img_free)(img);
+}
+
+
+
DiOffT ML_(img_size)(const DiImage* img)
{
vg_assert(img != NULL);
if it fails, for whatever reason. */
DiImage* ML_(img_from_local_file)(const HChar* fullpath);
+DiImage* ML_(img_from_fd)(Int fd, const HChar* fullpath);
+
/* Create an image by connecting to a Valgrind debuginfo server
(auxprogs/valgrind-di-server.c). |filename| contains the object
name to ask for; it must be a plain filename, not absolute, not a
DiImage* ML_(img_from_di_server)(const HChar* filename,
const HChar* serverAddr);
+/* Free memory allocated for image. */
+void ML_(img_free)(DiImage*);
+
/* Destroy an existing image. */
void ML_(img_done)(DiImage*);
*/
extern Bool ML_(read_elf_debug_info) ( DebugInfo* di );
+extern Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count );
+
#endif /* ndef __PRIV_READELF_H */
HChar* dbgname; /* in mallocville (VG_AR_DINFO) */
XArray* maps; /* XArray of DebugInfoMapping structs */
Bool have_rx_map; /* did we see a r?x mapping yet for the file? */
- Bool have_rw_map; /* did we see a rw? mapping yet for the file? */
+ Int rw_map_count; /* count of w? mappings seen (may be > 1 ) */
Bool have_ro_map; /* did we see a r-- mapping yet for the file? */
};
SizeT newlen = sizeof(osrel);
Int error = VG_(sysctl)(name, 4, NULL, NULL, &osrel, newlen);
if (error == -1) {
- VG_(message)(Vg_DebugMsg, "Warning: failed to set osrel for current process with value %d\n", osrel);
+ VG_(message)(Vg_DebugMsg, "Warning: failed to set osrel for current process with value %u\n", osrel);
} else {
if (VG_(clo_verbosity) > 1) {
- VG_(message)(Vg_DebugMsg, "Set osrel for current process with value %d\n", osrel);
+ VG_(message)(Vg_DebugMsg, "Set osrel for current process with value %u\n", osrel);
}
}
}
vg_assert(di);
vg_assert(di->fsm.have_rx_map == True);
- vg_assert(di->fsm.have_rw_map == True);
+ vg_assert(di->fsm.rw_map_count >= 1);
vg_assert(di->have_dinfo == False);
vg_assert(di->fsm.filename);
vg_assert(!di->symtab);
item.svma_limit = a_phdr.p_vaddr + a_phdr.p_memsz;
item.bias = map->avma - map->foff
+ a_phdr.p_offset - a_phdr.p_vaddr;
-#if (FREEBSD_VERS >= FREEBSD_12_2)
- if ((long long int)item.bias < 0LL) {
- item.bias = 0;
- }
-#endif
if (map->rw
&& (a_phdr.p_flags & (PF_R | PF_W))
== (PF_R | PF_W)) {
}
for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
- if (map->rw)
+ if (map->rw) {
TRACE_SYMTAB("rw: at %#lx are mapped foffsets %lld .. %lld\n",
map->avma, (Long)map->foff, (Long)(map->foff + map->size - 1) );
+ }
}
TRACE_SYMTAB("rw: contains these svma regions:\n");
for (i = 0; i < VG_(sizeXA)(svma_ranges); i++) {
UInt alyn = a_shdr.sh_addralign;
Bool nobits = a_shdr.sh_type == SHT_NOBITS;
/* Look through our collection of info obtained from the PT_LOAD
- headers, and make 'inrx' and 'inrw' point to the first entry
+ headers, and make 'inrx' and 'inrw1' point to the first entry
in each that intersects 'avma'. If in each case none is found,
leave the relevant pointer at NULL. */
RangeAndBias* inrx = NULL;
- RangeAndBias* inrw = NULL;
+ RangeAndBias* inrw1 = NULL;
+ /* Depending on the link editro there may be two RW PT_LOAD headers
+ * If so this will point to the seond one */
+ RangeAndBias* inrw2 = NULL;
+ /* used to switch between inrw1 and inrw2 */
+ RangeAndBias* inrw;
+
for (j = 0; j < VG_(sizeXA)(svma_ranges); j++) {
RangeAndBias* rng = VG_(indexXA)(svma_ranges, j);
if (svma >= rng->svma_base && svma < rng->svma_limit) {
if (!inrx && rng->exec) {
inrx = rng;
- } else if (!inrw && !rng->exec) {
- inrw = rng;
+ } else if (!inrw1 && !rng->exec) {
+ inrw1 = rng;
+ } else if (!inrw2 && !rng->exec) {
+ inrw2 = rng;
}
- if (inrx && inrw)
- break;
}
}
- TRACE_SYMTAB(" [sec %2ld] %s %s al%4u foff %6lld .. %6lld "
+ TRACE_SYMTAB(" [sec %2ld] %s %s %s al%4u foff %6lld .. %6lld "
" svma %p name \"%s\"\n",
- i, inrx ? "rx" : " ", inrw ? "rw" : " ", alyn,
- (Long) foff, (size == 0) ? (Long)foff : (Long)(foff+size-1),
+ i, inrx ? "rx" : " ", inrw1 ? "rw" : " ", inrw2 ? "rw" : " ",
+ alyn, (Long) foff, (size == 0) ? (Long)foff : (Long)(foff+size-1),
(void *) svma, name);
/* Check for sane-sized segments. SHT_NOBITS sections have zero
/* Find avma-s for: .text .data .sdata .rodata .bss .sbss .plt .got .opd
and .eh_frame */
+ /* In inrw2 is non-NULL then it will be used for .data .got.plt .bss */
+
/* Accept .text where mapped as rx (code), even if zero-sized */
if (0 == VG_(strcmp)(name, ".text")) {
if (inrx && !di->text_present) {
"%#lx .. %#lx\n", svma, svma + size - 1);
} else
# endif /* SOLARIS_PT_SUNDWTRACE_THRP */
+
+ if (inrw2) {
+ inrw = inrw2;
+ } else {
+ inrw = inrw1;
+ }
+
if (inrw && !di->data_present) {
di->data_present = True;
di->data_svma = svma;
/* Accept .sdata where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".sdata")) {
- if (inrw && !di->sdata_present) {
+ if (inrw1 && !di->sdata_present) {
di->sdata_present = True;
di->sdata_svma = svma;
- di->sdata_avma = svma + inrw->bias;
+ di->sdata_avma = svma + inrw1->bias;
di->sdata_size = size;
- di->sdata_bias = inrw->bias;
+ di->sdata_bias = inrw1->bias;
di->sdata_debug_svma = svma;
- di->sdata_debug_bias = inrw->bias;
+ di->sdata_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sdata svma = %#lx .. %#lx\n",
di->sdata_svma,
di->sdata_svma + di->sdata_size - 1);
di->rodata_avma += inrx->bias;
di->rodata_bias = inrx->bias;
di->rodata_debug_bias = inrx->bias;
- } else if (inrw) {
- di->rodata_avma += inrw->bias;
- di->rodata_bias = inrw->bias;
- di->rodata_debug_bias = inrw->bias;
+ } else if (inrw1) {
+ di->rodata_avma += inrw1->bias;
+ di->rodata_bias = inrw1->bias;
+ di->rodata_debug_bias = inrw1->bias;
} else {
BAD(".rodata");
}
}
if (0 == VG_(strcmp)(name, ".dynbss")) {
- if (inrw && !di->bss_present) {
+ if (inrw1 && !di->bss_present) {
dynbss_present = True;
di->bss_present = True;
di->bss_svma = svma;
- di->bss_avma = svma + inrw->bias;
+ di->bss_avma = svma + inrw1->bias;
di->bss_size = size;
- di->bss_bias = inrw->bias;
+ di->bss_bias = inrw1->bias;
di->bss_debug_svma = svma;
- di->bss_debug_bias = inrw->bias;
+ di->bss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .dynbss svma = %#lx .. %#lx\n",
di->bss_svma,
di->bss_svma + di->bss_size - 1);
/* Accept .bss where mapped as rw (data), even if zero-sized */
if (0 == VG_(strcmp)(name, ".bss")) {
+
+ if (inrw2) {
+ inrw = inrw2;
+ } else {
+ inrw = inrw1;
+ }
+
if (inrw && dynbss_present) {
vg_assert(di->bss_present);
dynbss_present = False;
}
if (0 == VG_(strcmp)(name, ".sdynbss")) {
- if (inrw && !di->sbss_present) {
+ if (inrw1 && !di->sbss_present) {
sdynbss_present = True;
di->sbss_present = True;
di->sbss_svma = svma;
- di->sbss_avma = svma + inrw->bias;
+ di->sbss_avma = svma + inrw1->bias;
di->sbss_size = size;
- di->sbss_bias = inrw->bias;
+ di->sbss_bias = inrw1->bias;
di->sbss_debug_svma = svma;
- di->sbss_debug_bias = inrw->bias;
+ di->sbss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sdynbss svma = %#lx .. %#lx\n",
di->sbss_svma,
di->sbss_svma + di->sbss_size - 1);
/* Accept .sbss where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".sbss")) {
- if (inrw && sdynbss_present) {
+ if (inrw1 && sdynbss_present) {
vg_assert(di->sbss_present);
sdynbss_present = False;
vg_assert(di->sbss_svma + di->sbss_size == svma);
TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n",
svma, svma + size - 1);
TRACE_SYMTAB("acquiring .sbss avma = %#lx .. %#lx\n",
- svma + inrw->bias, svma + inrw->bias + size - 1);
+ svma + inrw1->bias, svma + inrw1->bias + size - 1);
TRACE_SYMTAB("acquiring .sbss bias = %#lx\n", (UWord)di->sbss_bias);
} else
- if (inrw && !di->sbss_present) {
+ if (inrw1 && !di->sbss_present) {
di->sbss_present = True;
di->sbss_svma = svma;
- di->sbss_avma = svma + inrw->bias;
+ di->sbss_avma = svma + inrw1->bias;
di->sbss_size = size;
- di->sbss_bias = inrw->bias;
+ di->sbss_bias = inrw1->bias;
di->sbss_debug_svma = svma;
- di->sbss_debug_bias = inrw->bias;
+ di->sbss_debug_bias = inrw1->bias;
TRACE_SYMTAB("acquiring .sbss svma = %#lx .. %#lx\n",
di->sbss_svma,
di->sbss_svma + di->sbss_size - 1);
/* Accept .got where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".got")) {
- if (inrw && !di->got_present) {
+ if (inrw1 && !di->got_present) {
di->got_present = True;
- di->got_avma = svma + inrw->bias;
+ di->got_avma = svma + inrw1->bias;
di->got_size = size;
TRACE_SYMTAB("acquiring .got avma = %#lx\n", di->got_avma);
} else {
/* Accept .got.plt where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".got.plt")) {
+
+ if (inrw2) {
+ inrw = inrw2;
+ } else {
+ inrw = inrw1;
+ }
+
if (inrw && !di->gotplt_present) {
di->gotplt_present = True;
di->gotplt_avma = svma + inrw->bias;
# elif defined(VGP_ppc32_linux)
/* Accept .plt where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".plt")) {
- if (inrw && !di->plt_present) {
+ if (inrw1 && !di->plt_present) {
di->plt_present = True;
- di->plt_avma = svma + inrw->bias;
+ di->plt_avma = svma + inrw1->bias;
di->plt_size = size;
TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma);
} else {
# elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)
/* Accept .plt where mapped as rw (data), or unmapped */
if (0 == VG_(strcmp)(name, ".plt")) {
- if (inrw && !di->plt_present) {
+ if (inrw1 && !di->plt_present) {
di->plt_present = True;
- di->plt_avma = svma + inrw->bias;
+ di->plt_avma = svma + inrw1->bias;
di->plt_size = size;
TRACE_SYMTAB("acquiring .plt avma = %#lx\n", di->plt_avma);
} else
- if ((!inrw) && (!inrx) && size > 0 && !di->plt_present) {
+ if ((!inrw1) && (!inrx) && size > 0 && !di->plt_present) {
/* File contains a .plt, but it didn't get mapped.
Presumably it is not required on this platform. At
least don't reject the situation as invalid. */
/* Accept .opd where mapped as rw (data) */
if (0 == VG_(strcmp)(name, ".opd")) {
- if (inrw && !di->opd_present) {
+ if (inrw1 && !di->opd_present) {
di->opd_present = True;
- di->opd_avma = svma + inrw->bias;
+ di->opd_avma = svma + inrw1->bias;
di->opd_size = size;
TRACE_SYMTAB("acquiring .opd avma = %#lx\n", di->opd_avma);
} else {
di->ehframe_avma[di->n_ehframe]);
di->n_ehframe++;
} else
- if (inrw && di->n_ehframe < N_EHFRAME_SECTS) {
- di->ehframe_avma[di->n_ehframe] = svma + inrw->bias;
+ if (inrw1 && di->n_ehframe < N_EHFRAME_SECTS) {
+ di->ehframe_avma[di->n_ehframe] = svma + inrw1->bias;
di->ehframe_size[di->n_ehframe] = size;
TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n",
di->ehframe_avma[di->n_ehframe]);
/* NOTREACHED */
}
+Bool ML_(check_elf_and_get_rw_loads) ( Int fd, const HChar* filename, Int * rw_load_count )
+{
+ Bool res, ok;
+ UWord i;
+ DiImage* mimg = NULL;
+ DiOffT ehdr_mioff = 0;
+ DiOffT phdr_mioff = 0;
+ UWord phdr_mnent = 0U;
+ UWord phdr_ment_szB = 0U;
+
+ res = False;
+
+ mimg = ML_(img_from_fd)(fd, filename);
+ if (mimg == NULL) {
+ VG_(message)(Vg_UserMsg, "warning: connection to image %s failed\n",
+ filename );
+ VG_(message)(Vg_UserMsg, " cannot read program headers \n" );
+ return False;
+ }
+
+ ok = is_elf_object_file_by_DiImage(mimg, False);
+ if (!ok) {
+ goto out;
+ }
+
+ ElfXX_Ehdr ehdr_m;
+ Elf64_Word flag_x;
+#if defined(VGA_amd64) || defined(VGA_ppc64be) || defined(VGA_ppc64le) || defined(VGA_arm) || defined(VGA_arm64)
+ flag_x = PF_X;
+#else
+ flag_x = 0;
+#endif
+ vg_assert(ehdr_mioff == 0); // ensured by its initialisation
+ ok = ML_(img_valid)(mimg, ehdr_mioff, sizeof(ehdr_m));
+ vg_assert(ok); // ML_(is_elf_object_file) should ensure this
+ ML_(img_get)(&ehdr_m, mimg, ehdr_mioff, sizeof(ehdr_m));
+
+ phdr_mioff = ehdr_mioff + ehdr_m.e_phoff;
+ phdr_mnent = ehdr_m.e_phnum;
+ phdr_ment_szB = ehdr_m.e_phentsize;
+
+ for (i = 0U; i < phdr_mnent; i++) {
+ ElfXX_Phdr a_phdr;
+ ML_(img_get)(&a_phdr, mimg,
+ INDEX_BIS(phdr_mioff, i, phdr_ment_szB),
+ sizeof(a_phdr));
+
+ if (a_phdr.p_type == PT_LOAD) {
+ if (a_phdr.p_memsz > 0) {
+ if (((a_phdr.p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) &&
+ ((a_phdr.p_flags & flag_x) == 0)) {
+ ++*rw_load_count;
+ }
+
+ /*
+ * Hold your horses
+ * Just because The ELF file contains 2 RW PT_LOAD segments it
+ * doesn't mean that Valgrind will also make 2 calls to
+ * VG_(di_notify_mmap). If the stars are all aligned
+ * (which usually means that the ELF file is the client
+ * executable with the segment offset for the
+ * second PT_LOAD falls exactly on 0x1000) then the NSegements
+ * will get merged and VG_(di_notify_mmap) only gets called once. */
+ if (*rw_load_count == 2 &&
+ ehdr_m.e_type == ET_EXEC &&
+ a_phdr.p_offset == VG_PGROUNDDN(a_phdr.p_offset) )
+ {
+ *rw_load_count = 1;
+ }
+ }
+ }
+ } /* for (i = 0; i < phdr_Mnent; i++) ... */
+
+ res = True;
+
+ out:
+ {
+ /* Last, but not least, detach from the image(s). */
+ if (mimg) ML_(img_free)(mimg);
+
+ return res;
+ } /* out: */
+
+ /* NOTREACHED */
+}
+
+
+
#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
/*--------------------------------------------------------------------*/
map.rx = False;
map.rw = True;
VG_(addToXA)(di->fsm.maps, &map);
- di->fsm.have_rw_map = True;
+ di->fsm.rw_map_count = 1;
di->data_present = True;
if (di->data_avma == 0) {
}
}
- if (di->fsm.have_rx_map && di->fsm.have_rw_map && !di->have_dinfo) {
+ if (di->fsm.have_rx_map && di->fsm.rw_map_count && !di->have_dinfo) {
vg_assert(di->fsm.filename);
TRACE_SYMTAB("\n");
TRACE_SYMTAB("------ start PE OBJECT with PDB INFO "
/* Rule out ones which are completely outside the r-x mapped area.
See "Comment_Regarding_Text_Range_Checks" elsewhere in this file
for background and rationale. */
- vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
+ vg_assert(di->fsm.have_rx_map && di->fsm.rw_map_count);
if (ML_(find_rx_mapping)(di, this, this + size - 1) == NULL) {
if (0)
VG_(message)(Vg_DebugMsg,
"warning: DiCfSI %#lx .. %#lx is huge; length = %u (%s)\n",
base, base + len - 1, len, di->soname);
- vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
+ vg_assert(di->fsm.have_rx_map && di->fsm.rw_map_count);
/* Find mapping where at least one end of the CFSI falls into. */
map = ML_(find_rx_mapping)(di, base, base);
map2 = ML_(find_rx_mapping)(di, base + len - 1,
/* This is assured us by top level steering logic in debuginfo.c,
and it is re-checked at the start of
ML_(read_elf_debug_info). */
- vg_assert(di->fsm.have_rx_map && di->fsm.have_rw_map);
+ vg_assert(di->fsm.have_rx_map && di->fsm.rw_map_count);
if (level > 0 && ML_(find_rx_mapping)(di, aMin, aMax) == NULL) {
if (VG_(clo_verbosity) > 1) {
VG_(message)(Vg_DebugMsg,
varinfo4.stderr.exp-freebsd \
varinfo5.vgtest varinfo5.stdout.exp varinfo5.stderr.exp \
varinfo5.stderr.exp-ppc64 \
+ varinfo5.stderr.exp-freebsd \
varinfo6.vgtest varinfo6.stdout.exp varinfo6.stderr.exp \
varinfo6.stderr.exp-ppc64 \
varinforestrict.vgtest varinforestrict.stderr.exp \
--- /dev/null
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:52)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is 1 bytes inside a block of size 3 alloc'd
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:50)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:55)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside global var "global_u1"
+ declared at varinfo5so.c:38
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:56)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside global var "global_i1"
+ declared at varinfo5so.c:40
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:57)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside global_u2[3],
+ a global variable declared at varinfo5so.c:42
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:58)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside global_i2[7],
+ a global variable declared at varinfo5so.c:44
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: varinfo1_main (tests/varinfo5so.c:59)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:154)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside local var "local"
+ declared at varinfo5so.c:49, in frame #X of thread 1
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo2 (tests/varinfo5so.c:71)
+ by 0x........: varinfo2_main (tests/varinfo5so.c:81)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:155)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside var[7],
+ declared at varinfo5so.c:69, in frame #X of thread 1
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo2 (tests/varinfo5so.c:73)
+ by 0x........: varinfo2_main (tests/varinfo5so.c:81)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:155)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 2 bytes inside var.bar,
+ declared at varinfo5so.c:72, in frame #X of thread 1
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo2 (tests/varinfo5so.c:76)
+ by 0x........: varinfo2_main (tests/varinfo5so.c:81)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:155)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is on thread 1's stack
+ in frame #X, created by foo2 (varinfo5so.c:66)
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo3 (tests/varinfo5so.c:106)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside static_global_def[1],
+ a global variable declared at varinfo5so.c:87
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo3 (tests/varinfo5so.c:107)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside nonstatic_global_def[2],
+ a global variable declared at varinfo5so.c:88
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo3 (tests/varinfo5so.c:108)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside static_global_undef[3],
+ a global variable declared at varinfo5so.c:89
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: foo3 (tests/varinfo5so.c:109)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside nonstatic_global_undef[4],
+ a global variable declared at varinfo5so.c:90
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: bar3 (tests/varinfo5so.c:94)
+ by 0x........: foo3 (tests/varinfo5so.c:110)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is 5 bytes inside data symbol "foo3.static_local_def"
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: bar3 (tests/varinfo5so.c:95)
+ by 0x........: foo3 (tests/varinfo5so.c:110)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is on thread 1's stack
+ in frame #X, created by foo3 (varinfo5so.c:101)
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: bar3 (tests/varinfo5so.c:96)
+ by 0x........: foo3 (tests/varinfo5so.c:110)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is 7 bytes inside data symbol "foo3.static_local_undef"
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: bar3 (tests/varinfo5so.c:97)
+ by 0x........: foo3 (tests/varinfo5so.c:110)
+ by 0x........: varinfo3_main (tests/varinfo5so.c:118)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:156)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is on thread 1's stack
+ in frame #X, created by foo3 (varinfo5so.c:101)
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: blah4 (tests/varinfo5so.c:137)
+ by 0x........: varinfo4_main (tests/varinfo5so.c:146)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:157)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 1 byte inside a[3].xyzzy[21].c1,
+ declared at varinfo5so.c:135, in frame #X of thread 1
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: blah4 (tests/varinfo5so.c:138)
+ by 0x........: varinfo4_main (tests/varinfo5so.c:146)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:157)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 0 bytes inside a[5].bong,
+ declared at varinfo5so.c:135, in frame #X of thread 1
+
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: blah4 (tests/varinfo5so.c:139)
+ by 0x........: varinfo4_main (tests/varinfo5so.c:146)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:157)
+ by 0x........: main (tests/varinfo5.c:5)
+ Location 0x........ is 1 byte inside a[3].xyzzy[21].c2[2],
+ declared at varinfo5so.c:135, in frame #X of thread 1
+
+answer is 0
+Uninitialised byte(s) found during client check request
+ at 0x........: croak (tests/varinfo5so.c:29)
+ by 0x........: fun_c (tests/varinfo5so.c:164)
+ by 0x........: fun_b (./varinfo5so.c:168)
+ by 0x........: fun_a (./varinfo5so.c:172)
+ by 0x........: inlinetest (./varinfo5so.c:178)
+ by 0x........: varinfo5_main (tests/varinfo5so.c:158)
+ by 0x........: main (tests/varinfo5.c:5)
+ Address 0x........ is on thread 1's stack
+ in frame #X, created by inlinetest (varinfo5so.c:176)
+