Home | History | Annotate | Download | only in libdwfl
      1 /* Sniff out modules from ELF headers visible in memory segments.
      2    Copyright (C) 2008-2010 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 #include <config.h>
     51 #include "../libelf/libelfP.h"	/* For NOTE_ALIGN.  */
     52 #undef	_
     53 #include "libdwflP.h"
     54 
     55 #include <elf.h>
     56 #include <gelf.h>
     57 #include <inttypes.h>
     58 #include <sys/param.h>
     59 #include <alloca.h>
     60 #include <endian.h>
     61 
     62 
     63 /* A good size for the initial read from memory, if it's not too costly.
     64    This more than covers the phdrs and note segment in the average 64-bit
     65    binary.  */
     66 
     67 #define INITIAL_READ	1024
     68 
     69 #if __BYTE_ORDER == __LITTLE_ENDIAN
     70 # define MY_ELFDATA	ELFDATA2LSB
     71 #else
     72 # define MY_ELFDATA	ELFDATA2MSB
     73 #endif
     74 
     75 
     76 /* Return user segment index closest to ADDR but not above it.
     77    If NEXT, return the closest to ADDR but not below it.  */
     78 static int
     79 addr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next)
     80 {
     81   int ndx = -1;
     82   do
     83     {
     84       if (dwfl->lookup_segndx[segment] >= 0)
     85 	ndx = dwfl->lookup_segndx[segment];
     86       if (++segment >= dwfl->lookup_elts - 1)
     87 	return next ? ndx + 1 : ndx;
     88     }
     89   while (dwfl->lookup_addr[segment] < addr);
     90 
     91   if (next)
     92     {
     93       while (dwfl->lookup_segndx[segment] < 0)
     94 	if (++segment >= dwfl->lookup_elts - 1)
     95 	  return ndx + 1;
     96       ndx = dwfl->lookup_segndx[segment];
     97     }
     98 
     99   return ndx;
    100 }
    101 
    102 int
    103 dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
    104 			    Dwfl_Memory_Callback *memory_callback,
    105 			    void *memory_callback_arg,
    106 			    Dwfl_Module_Callback *read_eagerly,
    107 			    void *read_eagerly_arg)
    108 {
    109   size_t segment = ndx;
    110 
    111   if (segment >= dwfl->lookup_elts)
    112     segment = dwfl->lookup_elts - 1;
    113 
    114   while (segment > 0
    115 	 && (dwfl->lookup_segndx[segment] > ndx
    116 	     || dwfl->lookup_segndx[segment] == -1))
    117     --segment;
    118 
    119   while (dwfl->lookup_segndx[segment] < ndx)
    120     if (++segment == dwfl->lookup_elts)
    121       return 0;
    122 
    123   GElf_Addr start = dwfl->lookup_addr[segment];
    124 
    125   inline bool segment_read (int segndx,
    126 			    void **buffer, size_t *buffer_available,
    127 			    GElf_Addr addr, size_t minread)
    128   {
    129     return ! (*memory_callback) (dwfl, segndx, buffer, buffer_available,
    130 				 addr, minread, memory_callback_arg);
    131   }
    132 
    133   inline void release_buffer (void **buffer, size_t *buffer_available)
    134   {
    135     if (*buffer != NULL)
    136       (void) segment_read (-1, buffer, buffer_available, 0, 0);
    137   }
    138 
    139   /* First read in the file header and check its sanity.  */
    140 
    141   void *buffer = NULL;
    142   size_t buffer_available = INITIAL_READ;
    143 
    144   inline int finish (void)
    145   {
    146     release_buffer (&buffer, &buffer_available);
    147     return ndx;
    148   }
    149 
    150   if (segment_read (ndx, &buffer, &buffer_available,
    151 		    start, sizeof (Elf64_Ehdr))
    152       || memcmp (buffer, ELFMAG, SELFMAG) != 0)
    153     return finish ();
    154 
    155   inline bool read_portion (void **data, size_t *data_size,
    156 			    GElf_Addr vaddr, size_t filesz)
    157   {
    158     if (vaddr - start + filesz > buffer_available)
    159       {
    160 	*data = NULL;
    161 	*data_size = filesz;
    162 	return segment_read (addr_segndx (dwfl, segment, vaddr, false),
    163 			     data, data_size, vaddr, filesz);
    164       }
    165 
    166     /* We already have this whole note segment from our initial read.  */
    167     *data = vaddr - start + buffer;
    168     *data_size = 0;
    169     return false;
    170   }
    171 
    172   inline void finish_portion (void **data, size_t *data_size)
    173   {
    174     if (*data_size != 0)
    175       release_buffer (data, data_size);
    176   }
    177 
    178   /* Extract the information we need from the file header.  */
    179   union
    180   {
    181     Elf32_Ehdr e32;
    182     Elf64_Ehdr e64;
    183   } ehdr;
    184   GElf_Off phoff;
    185   uint_fast16_t phnum;
    186   uint_fast16_t phentsize;
    187   GElf_Off shdrs_end;
    188   Elf_Data xlatefrom =
    189     {
    190       .d_type = ELF_T_EHDR,
    191       .d_buf = (void *) buffer,
    192       .d_version = EV_CURRENT,
    193     };
    194   Elf_Data xlateto =
    195     {
    196       .d_type = ELF_T_EHDR,
    197       .d_buf = &ehdr,
    198       .d_size = sizeof ehdr,
    199       .d_version = EV_CURRENT,
    200     };
    201   switch (((const unsigned char *) buffer)[EI_CLASS])
    202     {
    203     case ELFCLASS32:
    204       xlatefrom.d_size = sizeof (Elf32_Ehdr);
    205       if (elf32_xlatetom (&xlateto, &xlatefrom,
    206 			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
    207 	return finish ();
    208       phoff = ehdr.e32.e_phoff;
    209       phnum = ehdr.e32.e_phnum;
    210       phentsize = ehdr.e32.e_phentsize;
    211       if (phentsize != sizeof (Elf32_Phdr))
    212 	return finish ();
    213       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
    214       break;
    215 
    216     case ELFCLASS64:
    217       xlatefrom.d_size = sizeof (Elf64_Ehdr);
    218       if (elf64_xlatetom (&xlateto, &xlatefrom,
    219 			  ((const unsigned char *) buffer)[EI_DATA]) == NULL)
    220 	return finish ();
    221       phoff = ehdr.e64.e_phoff;
    222       phnum = ehdr.e64.e_phnum;
    223       phentsize = ehdr.e64.e_phentsize;
    224       if (phentsize != sizeof (Elf64_Phdr))
    225 	return finish ();
    226       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
    227       break;
    228 
    229     default:
    230       return finish ();
    231     }
    232 
    233   /* The file header tells where to find the program headers.
    234      These are what we need to find the boundaries of the module.
    235      Without them, we don't have a module to report.  */
    236 
    237   if (phnum == 0)
    238     return finish ();
    239 
    240   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
    241   xlatefrom.d_size = phnum * phentsize;
    242 
    243   void *ph_buffer = NULL;
    244   size_t ph_buffer_size = 0;
    245   if (read_portion (&ph_buffer, &ph_buffer_size,
    246 		    start + phoff, xlatefrom.d_size))
    247     return finish ();
    248 
    249   xlatefrom.d_buf = ph_buffer;
    250 
    251   union
    252   {
    253     Elf32_Phdr p32[phnum];
    254     Elf64_Phdr p64[phnum];
    255   } phdrs;
    256 
    257   xlateto.d_buf = &phdrs;
    258   xlateto.d_size = sizeof phdrs;
    259 
    260   /* Track the bounds of the file visible in memory.  */
    261   GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end.  */
    262   GElf_Off file_end = 0;	 /* Rounded up to effective page size.  */
    263   GElf_Off contiguous = 0;	 /* Visible as contiguous file from START.  */
    264   GElf_Off total_filesz = 0;	 /* Total size of data to read.  */
    265 
    266   /* Collect the bias between START and the containing PT_LOAD's p_vaddr.  */
    267   GElf_Addr bias = 0;
    268   bool found_bias = false;
    269 
    270   /* Collect the unbiased bounds of the module here.  */
    271   GElf_Addr module_start = -1l;
    272   GElf_Addr module_end = 0;
    273   GElf_Addr module_address_sync = 0;
    274 
    275   /* If we see PT_DYNAMIC, record it here.  */
    276   GElf_Addr dyn_vaddr = 0;
    277   GElf_Xword dyn_filesz = 0;
    278 
    279   /* Collect the build ID bits here.  */
    280   void *build_id = NULL;
    281   size_t build_id_len = 0;
    282   GElf_Addr build_id_vaddr = 0;
    283 
    284   /* Consider a PT_NOTE we've found in the image.  */
    285   inline void consider_notes (GElf_Addr vaddr, GElf_Xword filesz)
    286   {
    287     /* If we have already seen a build ID, we don't care any more.  */
    288     if (build_id != NULL || filesz == 0)
    289       return;
    290 
    291     void *data;
    292     size_t data_size;
    293     if (read_portion (&data, &data_size, vaddr, filesz))
    294       return;
    295 
    296     assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr));
    297 
    298     void *notes;
    299     if (ehdr.e32.e_ident[EI_DATA] == MY_ELFDATA)
    300       notes = data;
    301     else
    302       {
    303 	notes = malloc (filesz);
    304 	if (unlikely (notes == NULL))
    305 	  return;
    306 	xlatefrom.d_type = xlateto.d_type = ELF_T_NHDR;
    307 	xlatefrom.d_buf = (void *) data;
    308 	xlatefrom.d_size = filesz;
    309 	xlateto.d_buf = notes;
    310 	xlateto.d_size = filesz;
    311 	if (elf32_xlatetom (&xlateto, &xlatefrom,
    312 			    ehdr.e32.e_ident[EI_DATA]) == NULL)
    313 	  goto done;
    314       }
    315 
    316     const GElf_Nhdr *nh = notes;
    317     while ((const void *) nh < (const void *) notes + filesz)
    318      {
    319 	const void *note_name = nh + 1;
    320 	const void *note_desc = note_name + NOTE_ALIGN (nh->n_namesz);
    321 	if (unlikely ((size_t) ((const void *) notes + filesz
    322 				- note_desc) < nh->n_descsz))
    323 	  break;
    324 
    325 	if (nh->n_type == NT_GNU_BUILD_ID
    326 	    && nh->n_descsz > 0
    327 	    && nh->n_namesz == sizeof "GNU"
    328 	    && !memcmp (note_name, "GNU", sizeof "GNU"))
    329 	  {
    330 	    build_id_vaddr = note_desc - (const void *) notes + vaddr;
    331 	    build_id_len = nh->n_descsz;
    332 	    build_id = malloc (nh->n_descsz);
    333 	    if (likely (build_id != NULL))
    334 	      memcpy (build_id, note_desc, build_id_len);
    335 	    break;
    336 	  }
    337 
    338 	nh = note_desc + NOTE_ALIGN (nh->n_descsz);
    339       }
    340 
    341   done:
    342     if (notes != data)
    343       free (notes);
    344     finish_portion (&data, &data_size);
    345   }
    346 
    347   /* Consider each of the program headers we've read from the image.  */
    348   inline void consider_phdr (GElf_Word type,
    349 			     GElf_Addr vaddr, GElf_Xword memsz,
    350 			     GElf_Off offset, GElf_Xword filesz,
    351 			     GElf_Xword align)
    352   {
    353     switch (type)
    354       {
    355       case PT_DYNAMIC:
    356 	dyn_vaddr = vaddr;
    357 	dyn_filesz = filesz;
    358 	break;
    359 
    360       case PT_NOTE:
    361 	/* We calculate from the p_offset of the note segment,
    362 	   because we don't yet know the bias for its p_vaddr.  */
    363 	consider_notes (start + offset, filesz);
    364 	break;
    365 
    366       case PT_LOAD:
    367 	align = dwfl->segment_align > 1 ? dwfl->segment_align : align ?: 1;
    368 
    369 	GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align;
    370 	GElf_Addr filesz_vaddr = filesz < memsz ? vaddr + filesz : vaddr_end;
    371 	GElf_Off filesz_offset = filesz_vaddr - vaddr + offset;
    372 
    373 	if (file_trimmed_end < offset + filesz)
    374 	  {
    375 	    file_trimmed_end = offset + filesz;
    376 
    377 	    /* Trim the last segment so we don't bother with zeros
    378 	       in the last page that are off the end of the file.
    379 	       However, if the extra bit in that page includes the
    380 	       section headers, keep them.  */
    381 	    if (shdrs_end <= filesz_offset && shdrs_end > file_trimmed_end)
    382 	      {
    383 		filesz += shdrs_end - file_trimmed_end;
    384 		file_trimmed_end = shdrs_end;
    385 	      }
    386 	  }
    387 
    388 	total_filesz += filesz;
    389 
    390 	if (file_end < filesz_offset)
    391 	  {
    392 	    file_end = filesz_offset;
    393 	    if (filesz_vaddr - start == filesz_offset)
    394 	      contiguous = file_end;
    395 	  }
    396 
    397 	if (!found_bias && (offset & -align) == 0
    398 	    && likely (filesz_offset >= phoff + phnum * phentsize))
    399 	  {
    400 	    bias = start - vaddr;
    401 	    found_bias = true;
    402 	  }
    403 
    404 	if ((vaddr & -align) < module_start)
    405 	  {
    406 	    module_start = vaddr & -align;
    407 	    module_address_sync = vaddr + memsz;
    408 	  }
    409 
    410 	if (module_end < vaddr_end)
    411 	  module_end = vaddr_end;
    412 	break;
    413       }
    414   }
    415   if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
    416     {
    417       if (elf32_xlatetom (&xlateto, &xlatefrom,
    418 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
    419 	found_bias = false;	/* Trigger error check.  */
    420       else
    421 	for (uint_fast16_t i = 0; i < phnum; ++i)
    422 	  consider_phdr (phdrs.p32[i].p_type,
    423 			 phdrs.p32[i].p_vaddr, phdrs.p32[i].p_memsz,
    424 			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz,
    425 			 phdrs.p32[i].p_align);
    426     }
    427   else
    428     {
    429       if (elf64_xlatetom (&xlateto, &xlatefrom,
    430 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
    431 	found_bias = false;	/* Trigger error check.  */
    432       else
    433 	for (uint_fast16_t i = 0; i < phnum; ++i)
    434 	  consider_phdr (phdrs.p64[i].p_type,
    435 			 phdrs.p64[i].p_vaddr, phdrs.p64[i].p_memsz,
    436 			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz,
    437 			 phdrs.p64[i].p_align);
    438     }
    439 
    440   finish_portion (&ph_buffer, &ph_buffer_size);
    441 
    442   /* We must have seen the segment covering offset 0, or else the ELF
    443      header we read at START was not produced by these program headers.  */
    444   if (unlikely (!found_bias))
    445     return finish ();
    446 
    447   /* Now we know enough to report a module for sure: its bounds.  */
    448   module_start += bias;
    449   module_end += bias;
    450 
    451   dyn_vaddr += bias;
    452 
    453   /* Our return value now says to skip the segments contained
    454      within the module.  */
    455   ndx = addr_segndx (dwfl, segment, module_end, true);
    456 
    457   /* Examine its .dynamic section to get more interesting details.
    458      If it has DT_SONAME, we'll use that as the module name.
    459      If it has a DT_DEBUG, then it's actually a PIE rather than a DSO.
    460      We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME,
    461      and they also tell us the essential portion of the file
    462      for fetching symbols.  */
    463   GElf_Addr soname_stroff = 0;
    464   GElf_Addr dynstr_vaddr = 0;
    465   GElf_Xword dynstrsz = 0;
    466   bool execlike = false;
    467   inline bool consider_dyn (GElf_Sxword tag, GElf_Xword val)
    468   {
    469     switch (tag)
    470       {
    471       default:
    472 	return false;
    473 
    474       case DT_DEBUG:
    475 	execlike = true;
    476 	break;
    477 
    478       case DT_SONAME:
    479 	soname_stroff = val;
    480 	break;
    481 
    482       case DT_STRTAB:
    483 	dynstr_vaddr = val;
    484 	break;
    485 
    486       case DT_STRSZ:
    487 	dynstrsz = val;
    488 	break;
    489       }
    490 
    491     return soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0;
    492   }
    493 
    494   const size_t dyn_entsize = (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32
    495 			      ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
    496   void *dyn_data = NULL;
    497   size_t dyn_data_size = 0;
    498   if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0
    499       && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz))
    500     {
    501       union
    502       {
    503 	Elf32_Dyn d32[dyn_filesz / sizeof (Elf32_Dyn)];
    504 	Elf64_Dyn d64[dyn_filesz / sizeof (Elf64_Dyn)];
    505       } dyn;
    506 
    507       xlatefrom.d_type = xlateto.d_type = ELF_T_DYN;
    508       xlatefrom.d_buf = (void *) dyn_data;
    509       xlatefrom.d_size = dyn_filesz;
    510       xlateto.d_buf = &dyn;
    511       xlateto.d_size = sizeof dyn;
    512 
    513       if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
    514 	{
    515 	  if (elf32_xlatetom (&xlateto, &xlatefrom,
    516 			      ehdr.e32.e_ident[EI_DATA]) != NULL)
    517 	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d32[0]; ++i)
    518 	      if (consider_dyn (dyn.d32[i].d_tag, dyn.d32[i].d_un.d_val))
    519 		break;
    520 	}
    521       else
    522 	{
    523 	  if (elf64_xlatetom (&xlateto, &xlatefrom,
    524 			      ehdr.e32.e_ident[EI_DATA]) != NULL)
    525 	    for (size_t i = 0; i < dyn_filesz / sizeof dyn.d64[0]; ++i)
    526 	      if (consider_dyn (dyn.d64[i].d_tag, dyn.d64[i].d_un.d_val))
    527 		break;
    528 	}
    529     }
    530   finish_portion (&dyn_data, &dyn_data_size);
    531 
    532   /* We'll use the name passed in or a stupid default if not DT_SONAME.  */
    533   if (name == NULL)
    534     name = ehdr.e32.e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]";
    535 
    536   void *soname = NULL;
    537   size_t soname_size = 0;
    538   if (dynstrsz != 0 && dynstr_vaddr != 0)
    539     {
    540       /* We know the bounds of the .dynstr section.
    541 
    542 	 The DYNSTR_VADDR pointer comes from the .dynamic section
    543 	 (DT_STRTAB, detected above).  Ordinarily the dynamic linker
    544 	 will have adjusted this pointer in place so it's now an
    545 	 absolute address.  But sometimes .dynamic is read-only (in
    546 	 vDSOs and odd architectures), and sometimes the adjustment
    547 	 just hasn't happened yet in the memory image we looked at.
    548 	 So treat DYNSTR_VADDR as an absolute address if it falls
    549 	 within the module bounds, or try applying the phdr bias
    550 	 when that adjusts it to fall within the module bounds.  */
    551 
    552       if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
    553 	  && dynstr_vaddr + bias >= module_start
    554 	  && dynstr_vaddr + bias < module_end)
    555 	dynstr_vaddr += bias;
    556 
    557       if (unlikely (dynstr_vaddr + dynstrsz > module_end))
    558 	dynstrsz = 0;
    559 
    560       /* Try to get the DT_SONAME string.  */
    561       if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
    562 	  && ! read_portion (&soname, &soname_size,
    563 			     dynstr_vaddr + soname_stroff, 0))
    564 	name = soname;
    565     }
    566 
    567   /* Now that we have chosen the module's name and bounds, report it.
    568      If we found a build ID, report that too.  */
    569 
    570   Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name,
    571 						 module_start, module_end);
    572   if (likely (mod != NULL) && build_id != NULL
    573       && unlikely (INTUSE(dwfl_module_report_build_id) (mod,
    574 							build_id,
    575 							build_id_len,
    576 							build_id_vaddr)))
    577     {
    578       mod->gc = true;
    579       mod = NULL;
    580     }
    581 
    582   /* At this point we do not need BUILD_ID or NAME any more.
    583      They have been copied.  */
    584   free (build_id);
    585   finish_portion (&soname, &soname_size);
    586 
    587   if (unlikely (mod == NULL))
    588     {
    589       ndx = -1;
    590       return finish ();
    591     }
    592 
    593   /* We have reported the module.  Now let the caller decide whether we
    594      should read the whole thing in right now.  */
    595 
    596   const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz
    597 			 : buffer_available >= contiguous ? 0
    598 			 : contiguous - buffer_available);
    599   const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0
    600 			       : dynstr_vaddr + dynstrsz - start);
    601   const GElf_Off whole = MAX (file_trimmed_end, shdrs_end);
    602 
    603   Elf *elf = NULL;
    604   if ((*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available,
    605 		       cost, worthwhile, whole, contiguous,
    606 		       read_eagerly_arg, &elf)
    607       && elf == NULL)
    608     {
    609       /* The caller wants to read the whole file in right now, but hasn't
    610 	 done it for us.  Fill in a local image of the virtual file.  */
    611 
    612       void *contents = calloc (1, file_trimmed_end);
    613       if (unlikely (contents == NULL))
    614 	return finish ();
    615 
    616       inline void final_read (size_t offset, GElf_Addr vaddr, size_t size)
    617       {
    618 	void *into = contents + offset;
    619 	size_t read_size = size;
    620 	(void) segment_read (addr_segndx (dwfl, segment, vaddr, false),
    621 			     &into, &read_size, vaddr, size);
    622       }
    623 
    624       if (contiguous < file_trimmed_end)
    625 	{
    626 	  /* We can't use the memory image verbatim as the file image.
    627 	     So we'll be reading into a local image of the virtual file.  */
    628 
    629 	  inline void read_phdr (GElf_Word type, GElf_Addr vaddr,
    630 				 GElf_Off offset, GElf_Xword filesz)
    631 	  {
    632 	    if (type == PT_LOAD)
    633 	      final_read (offset, vaddr + bias, filesz);
    634 	  }
    635 
    636 	  if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32)
    637 	    for (uint_fast16_t i = 0; i < phnum; ++i)
    638 	      read_phdr (phdrs.p32[i].p_type, phdrs.p32[i].p_vaddr,
    639 			 phdrs.p32[i].p_offset, phdrs.p32[i].p_filesz);
    640 	  else
    641 	    for (uint_fast16_t i = 0; i < phnum; ++i)
    642 	      read_phdr (phdrs.p64[i].p_type, phdrs.p64[i].p_vaddr,
    643 			 phdrs.p64[i].p_offset, phdrs.p64[i].p_filesz);
    644 	}
    645       else
    646 	{
    647 	  /* The whole file sits contiguous in memory,
    648 	     but the caller didn't want to just do it.  */
    649 
    650 	  const size_t have = MIN (buffer_available, file_trimmed_end);
    651 	  memcpy (contents, buffer, have);
    652 
    653 	  if (have < file_trimmed_end)
    654 	    final_read (have, start + have, file_trimmed_end - have);
    655 	}
    656 
    657       elf = elf_memory (contents, file_trimmed_end);
    658       if (unlikely (elf == NULL))
    659 	free (contents);
    660       else
    661 	elf->flags |= ELF_F_MALLOCED;
    662     }
    663 
    664   if (elf != NULL)
    665     {
    666       /* Install the file in the module.  */
    667       mod->main.elf = elf;
    668       mod->main.vaddr = module_start - bias;
    669       mod->main.address_sync = module_address_sync;
    670     }
    671 
    672   return finish ();
    673 }
    674