LCOV - code coverage report
Current view: top level - libdwfl - link_map.c (source / functions) Hit Total Coverage
Test: elfutils-0.192 Lines: 312 478 65.3 %
Date: 2024-12-02 18:41:01 Functions: 8 10 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 252 436 57.8 %

           Branch data     Line data    Source code
       1                 :            : /* Report modules by examining dynamic linker data structures.
       2                 :            :    Copyright (C) 2008-2016 Red Hat, Inc.
       3                 :            :    Copyright (C) 2021 Mark J. Wielaard <mark@klomp.org>
       4                 :            :    This file is part of elfutils.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of either
       8                 :            : 
       9                 :            :      * the GNU Lesser General Public License as published by the Free
      10                 :            :        Software Foundation; either version 3 of the License, or (at
      11                 :            :        your option) any later version
      12                 :            : 
      13                 :            :    or
      14                 :            : 
      15                 :            :      * the GNU General Public License as published by the Free
      16                 :            :        Software Foundation; either version 2 of the License, or (at
      17                 :            :        your option) any later version
      18                 :            : 
      19                 :            :    or both in parallel, as here.
      20                 :            : 
      21                 :            :    elfutils is distributed in the hope that it will be useful, but
      22                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24                 :            :    General Public License for more details.
      25                 :            : 
      26                 :            :    You should have received copies of the GNU General Public License and
      27                 :            :    the GNU Lesser General Public License along with this program.  If
      28                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      29                 :            : 
      30                 :            : #include <config.h>
      31                 :            : #include "libdwflP.h"
      32                 :            : #include "memory-access.h"
      33                 :            : #include "system.h"
      34                 :            : 
      35                 :            : #include <fcntl.h>
      36                 :            : 
      37                 :            : /* This element is always provided and always has a constant value.
      38                 :            :    This makes it an easy thing to scan for to discern the format.  */
      39                 :            : #define PROBE_TYPE      AT_PHENT
      40                 :            : #define PROBE_VAL32     sizeof (Elf32_Phdr)
      41                 :            : #define PROBE_VAL64     sizeof (Elf64_Phdr)
      42                 :            : 
      43                 :            : 
      44                 :            : static inline bool
      45                 :        464 : do_check64 (const char *a64, uint_fast8_t *elfdata)
      46                 :            : {
      47                 :            :   /* The AUXV pointer might not even be naturally aligned for 64-bit
      48                 :            :      data, because note payloads in a core file are not aligned.  */
      49                 :        464 :   const char *typep = a64 + offsetof (Elf64_auxv_t, a_type);
      50                 :        464 :   uint64_t type = read_8ubyte_unaligned_noncvt (typep);
      51                 :        464 :   const char *valp = a64 + offsetof (Elf64_auxv_t, a_un.a_val);
      52                 :        464 :   uint64_t val = read_8ubyte_unaligned_noncvt (valp);
      53                 :            : 
      54         [ +  + ]:        464 :   if (type == BE64 (PROBE_TYPE)
      55         [ +  - ]:          8 :       && val == BE64 (PROBE_VAL64))
      56                 :            :     {
      57                 :          8 :       *elfdata = ELFDATA2MSB;
      58                 :          8 :       return true;
      59                 :            :     }
      60                 :            : 
      61                 :        456 :   if (type == LE64 (PROBE_TYPE)
      62         [ +  + ]:        456 :       && val == LE64 (PROBE_VAL64))
      63                 :            :     {
      64                 :         54 :       *elfdata = ELFDATA2LSB;
      65                 :         54 :       return true;
      66                 :            :     }
      67                 :            : 
      68                 :            :   return false;
      69                 :            : }
      70                 :            : 
      71                 :            : static inline bool
      72                 :        794 : do_check32 (const char *a32, uint_fast8_t *elfdata)
      73                 :            : {
      74                 :            :   /* The AUXV pointer might not even be naturally aligned for 32-bit
      75                 :            :      data, because note payloads in a core file are not aligned.  */
      76                 :        794 :   const char *typep = a32 + offsetof (Elf32_auxv_t, a_type);
      77                 :        794 :   uint32_t type = read_4ubyte_unaligned_noncvt (typep);
      78                 :        794 :   const char *valp = a32 + offsetof (Elf32_auxv_t, a_un.a_val);
      79                 :        794 :   uint32_t val = read_4ubyte_unaligned_noncvt (valp);
      80                 :            : 
      81         [ +  + ]:        794 :   if (type == BE32 (PROBE_TYPE)
      82         [ +  - ]:          6 :       && val == BE32 (PROBE_VAL32))
      83                 :            :     {
      84                 :          6 :       *elfdata = ELFDATA2MSB;
      85                 :          6 :       return true;
      86                 :            :     }
      87                 :            : 
      88                 :        788 :   if (type == LE32 (PROBE_TYPE)
      89         [ +  + ]:        788 :       && val == LE32 (PROBE_VAL32))
      90                 :            :     {
      91                 :          8 :       *elfdata = ELFDATA2LSB;
      92                 :          8 :       return true;
      93                 :            :     }
      94                 :            : 
      95                 :            :   return false;
      96                 :            : }
      97                 :            : 
      98                 :            : /* Examine an auxv data block and determine its format.
      99                 :            :    Return true iff we figured it out.  */
     100                 :            : static bool
     101                 :         76 : auxv_format_probe (const void *auxv, size_t size,
     102                 :            :                    uint_fast8_t *elfclass, uint_fast8_t *elfdata)
     103                 :            : {
     104         [ +  - ]:        464 :   for (size_t i = 0; i < size / sizeof (Elf64_auxv_t); ++i)
     105                 :            :     {
     106         [ +  + ]:        464 :       if (do_check64 (auxv + i * sizeof (Elf64_auxv_t), elfdata))
     107                 :            :         {
     108                 :         62 :           *elfclass = ELFCLASS64;
     109                 :         62 :           return true;
     110                 :            :         }
     111                 :            : 
     112         [ +  + ]:        402 :       if (do_check32 (auxv + (i * 2) * sizeof (Elf32_auxv_t), elfdata)
     113         [ +  + ]:        392 :           || do_check32 (auxv + (i * 2 + 1) * sizeof (Elf32_auxv_t), elfdata))
     114                 :            :         {
     115                 :         14 :           *elfclass = ELFCLASS32;
     116                 :         14 :           return true;
     117                 :            :         }
     118                 :            :     }
     119                 :            : 
     120                 :            :   return false;
     121                 :            : }
     122                 :            : 
     123                 :            : /* This is a Dwfl_Memory_Callback that wraps another memory callback.
     124                 :            :    If the underlying callback cannot fill the data, then this will
     125                 :            :    fall back to fetching data from module files.  */
     126                 :            : 
     127                 :            : struct integrated_memory_callback
     128                 :            : {
     129                 :            :   Dwfl_Memory_Callback *memory_callback;
     130                 :            :   void *memory_callback_arg;
     131                 :            :   void *buffer;
     132                 :            : };
     133                 :            : 
     134                 :            : static bool
     135                 :       1136 : integrated_memory_callback (Dwfl *dwfl, int ndx,
     136                 :            :                                void **buffer, size_t *buffer_available,
     137                 :            :                                GElf_Addr vaddr,
     138                 :            :                                size_t minread,
     139                 :            :                                void *arg)
     140                 :            : {
     141                 :       1136 :   struct integrated_memory_callback *info = arg;
     142                 :            : 
     143         [ +  + ]:       1136 :   if (ndx == -1)
     144                 :            :     {
     145                 :            :       /* Called for cleanup.  */
     146         [ +  + ]:        538 :       if (info->buffer != NULL)
     147                 :            :         {
     148                 :            :           /* The last probe buffer came from the underlying callback.
     149                 :            :              Let it do its cleanup.  */
     150         [ -  + ]:        506 :           assert (*buffer == info->buffer); /* XXX */
     151                 :        506 :           *buffer = info->buffer;
     152                 :        506 :           info->buffer = NULL;
     153                 :        506 :           return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
     154                 :            :                                            vaddr, minread,
     155                 :            :                                            info->memory_callback_arg);
     156                 :            :         }
     157                 :         32 :       *buffer = NULL;
     158                 :         32 :       *buffer_available = 0;
     159                 :         32 :       return false;
     160                 :            :     }
     161                 :            : 
     162         [ -  + ]:        598 :   if (*buffer != NULL)
     163                 :            :     /* For a final-read request, we only use the underlying callback.  */
     164                 :          0 :     return (*info->memory_callback) (dwfl, ndx, buffer, buffer_available,
     165                 :            :                                      vaddr, minread, info->memory_callback_arg);
     166                 :            : 
     167                 :            :   /* Let the underlying callback try to fill this request.  */
     168         [ +  + ]:        598 :   if ((*info->memory_callback) (dwfl, ndx, &info->buffer, buffer_available,
     169                 :            :                                 vaddr, minread, info->memory_callback_arg))
     170                 :            :     {
     171                 :        506 :       *buffer = info->buffer;
     172                 :        506 :       return true;
     173                 :            :     }
     174                 :            : 
     175                 :            :   /* Now look for module text covering this address.  */
     176                 :            : 
     177                 :         92 :   Dwfl_Module *mod;
     178                 :         92 :   (void) INTUSE(dwfl_addrsegment) (dwfl, vaddr, &mod);
     179         [ +  - ]:         92 :   if (mod == NULL)
     180                 :            :     return false;
     181                 :            : 
     182                 :          0 :   Dwarf_Addr bias;
     183                 :          0 :   Elf_Scn *scn = INTUSE(dwfl_module_address_section) (mod, &vaddr, &bias);
     184         [ #  # ]:          0 :   if (unlikely (scn == NULL))
     185                 :            :     {
     186                 :            : #if 0 // XXX would have to handle ndx=-1 cleanup calls passed down.
     187                 :            :       /* If we have no sections we can try to fill it from the module file
     188                 :            :          based on its phdr mappings.  */
     189                 :            :       if (likely (mod->e_type != ET_REL) && mod->main.elf != NULL)
     190                 :            :         return INTUSE(dwfl_elf_phdr_memory_callback)
     191                 :            :           (dwfl, 0, buffer, buffer_available,
     192                 :            :            vaddr - mod->main.bias, minread, mod->main.elf);
     193                 :            : #endif
     194                 :            :       return false;
     195                 :            :     }
     196                 :            : 
     197                 :          0 :   Elf_Data *data = elf_rawdata (scn, NULL);
     198         [ #  # ]:          0 :   if (unlikely (data == NULL))
     199                 :            :     // XXX throw error?
     200                 :            :     return false;
     201                 :            : 
     202         [ #  # ]:          0 :   if (unlikely (data->d_size < vaddr))
     203                 :            :     return false;
     204                 :            : 
     205                 :            :   /* Provide as much data as we have.  */
     206                 :          0 :   void *contents = data->d_buf + vaddr;
     207                 :          0 :   size_t avail = data->d_size - vaddr;
     208         [ #  # ]:          0 :   if (unlikely (avail < minread))
     209                 :            :     return false;
     210                 :            : 
     211                 :            :   /* If probing for a string, make sure it's terminated.  */
     212   [ #  #  #  # ]:          0 :   if (minread == 0 && unlikely (memchr (contents, '\0', avail) == NULL))
     213                 :            :     return false;
     214                 :            : 
     215                 :            :   /* We have it! */
     216                 :          0 :   *buffer = contents;
     217                 :          0 :   *buffer_available = avail;
     218                 :          0 :   return true;
     219                 :            : }
     220                 :            : 
     221                 :            : static size_t
     222                 :        382 : addrsize (uint_fast8_t elfclass)
     223                 :            : {
     224                 :        382 :   return elfclass * 4;
     225                 :            : }
     226                 :            : 
     227                 :            : struct memory_closure
     228                 :            : {
     229                 :            :   Dwfl *dwfl;
     230                 :            :   Dwfl_Memory_Callback *callback;
     231                 :            :   void *arg;
     232                 :            : };
     233                 :            : 
     234                 :            : static inline int
     235                 :        716 : release_buffer (struct memory_closure *closure,
     236                 :            :                 void **buffer, size_t *buffer_available, int result)
     237                 :            : {
     238         [ +  + ]:        716 :   if (*buffer != NULL)
     239                 :        506 :     (*closure->callback) (closure->dwfl, -1, buffer, buffer_available, 0, 0,
     240                 :            :                           closure->arg);
     241                 :            : 
     242                 :        716 :   return result;
     243                 :            : }
     244                 :            : 
     245                 :            : static inline bool
     246                 :        332 : read_addrs (struct memory_closure *closure,
     247                 :            :             uint_fast8_t elfclass, uint_fast8_t elfdata,
     248                 :            :             void **buffer, size_t *buffer_available,
     249                 :            :             GElf_Addr vaddr, GElf_Addr *read_vaddr,
     250                 :            :             size_t n, GElf_Addr *addrs /* [4] */)
     251                 :            : {
     252                 :        332 :   size_t nb = n * addrsize (elfclass); /* Address words -> bytes to read.  */
     253                 :        332 :   Dwfl *dwfl = closure->dwfl;
     254                 :            : 
     255                 :            :   /* Read a new buffer if the old one doesn't cover these words.  */
     256         [ +  + ]:        332 :   if (*buffer == NULL
     257         [ +  + ]:        192 :       || vaddr < *read_vaddr
     258         [ +  + ]:        104 :       || nb > *buffer_available
     259         [ +  + ]:         56 :       || vaddr - (*read_vaddr) > *buffer_available - nb)
     260                 :            :     {
     261                 :        286 :       release_buffer (closure, buffer, buffer_available, 0);
     262                 :            : 
     263                 :        286 :       *read_vaddr = vaddr;
     264                 :        286 :       int segndx = INTUSE(dwfl_addrsegment) (dwfl, vaddr, NULL);
     265         [ +  - ]:        286 :       if (unlikely (segndx < 0)
     266         [ -  + ]:        286 :           || unlikely (! (*closure->callback) (dwfl, segndx,
     267                 :            :                                                buffer, buffer_available,
     268                 :            :                                                vaddr, nb, closure->arg)))
     269                 :          0 :         return true;
     270                 :            :     }
     271                 :            : 
     272                 :        332 :   unsigned char *addr = vaddr - (*read_vaddr) + (*buffer);
     273                 :            : 
     274         [ +  + ]:        332 :   if (elfclass == ELFCLASS32)
     275                 :            :     {
     276         [ +  + ]:         28 :       if (elfdata == ELFDATA2MSB)
     277         [ +  + ]:         64 :         for (size_t i = 0; i < n; ++i)
     278                 :         50 :           addrs[i] = BE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
     279                 :            :       else
     280         [ +  + ]:         64 :         for (size_t i = 0; i < n; ++i)
     281                 :         50 :           addrs[i] = LE32 (read_4ubyte_unaligned_noncvt (addr + i * 4));
     282                 :            :     }
     283                 :            :   else
     284                 :            :     {
     285         [ +  + ]:        304 :       if (elfdata == ELFDATA2MSB)
     286         [ +  + ]:         48 :         for (size_t i = 0; i < n; ++i)
     287                 :         36 :           addrs[i] = BE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
     288                 :            :       else
     289         [ +  + ]:       1334 :         for (size_t i = 0; i < n; ++i)
     290                 :       1042 :           addrs[i] = LE64 (read_8ubyte_unaligned_noncvt (addr + i * 8));
     291                 :            :     }
     292                 :            : 
     293                 :            :   return false;
     294                 :            : }
     295                 :            : 
     296                 :            : /* Report a module for each struct link_map in the linked list at r_map
     297                 :            :    in the struct r_debug at R_DEBUG_VADDR.  For r_debug_info description
     298                 :            :    see dwfl_link_map_report in libdwflP.h.  If R_DEBUG_INFO is not NULL then no
     299                 :            :    modules get added to DWFL, caller has to add them from filled in
     300                 :            :    R_DEBUG_INFO.
     301                 :            : 
     302                 :            :    For each link_map entry, if an existing module resides at its address,
     303                 :            :    this just modifies that module's name and suggested file name.  If
     304                 :            :    no such module exists, this calls dwfl_report_elf on the l_name string.
     305                 :            : 
     306                 :            :    Returns the number of modules found, or -1 for errors.  */
     307                 :            : 
     308                 :            : static int
     309                 :         50 : report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
     310                 :            :                 Dwfl *dwfl, GElf_Addr r_debug_vaddr,
     311                 :            :                 Dwfl_Memory_Callback *memory_callback,
     312                 :            :                 void *memory_callback_arg,
     313                 :            :                 struct r_debug_info *r_debug_info)
     314                 :            : {
     315                 :            :   /* Skip r_version, to aligned r_map field.  */
     316                 :         50 :   GElf_Addr read_vaddr = r_debug_vaddr + addrsize (elfclass);
     317                 :            : 
     318                 :         50 :   void *buffer = NULL;
     319                 :         50 :   size_t buffer_available = 0;
     320                 :         50 :   GElf_Addr addrs[4];
     321                 :         50 :   struct memory_closure memory_closure = { dwfl, memory_callback,
     322                 :            :                                            memory_callback_arg };
     323         [ -  + ]:         50 :   if (unlikely (read_addrs (&memory_closure, elfclass, elfdata,
     324                 :            :                             &buffer, &buffer_available, read_vaddr, &read_vaddr,
     325                 :            :                             1, addrs)))
     326                 :          0 :     return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
     327                 :            : 
     328                 :         50 :   GElf_Addr next = addrs[0];
     329                 :            : 
     330                 :         50 :   Dwfl_Module **lastmodp = &dwfl->modulelist;
     331                 :         50 :   int result = 0;
     332                 :            : 
     333                 :            :   /* There can't be more elements in the link_map list than there are
     334                 :            :      segments.  A segment is created for each PT_LOAD and there can be
     335                 :            :      up to 5 per module (-z separate-code, tends to create four LOAD
     336                 :            :      segments, gold has -z text-unlikely-segment, which might result
     337                 :            :      in creating that number of load segments) DWFL->lookup_elts is
     338                 :            :      probably twice the number of modules, so that multiplied by max
     339                 :            :      PT_LOADs is certainly above the upper bound.  If we iterate too
     340                 :            :      many times, there must be a loop in the pointers due to link_map
     341                 :            :      clobberation.  */
     342                 :            : #define MAX_PT_LOAD 5
     343                 :         50 :   size_t iterations = 0;
     344   [ +  +  +  - ]:        332 :   while (next != 0 && ++iterations < dwfl->lookup_elts * MAX_PT_LOAD)
     345                 :            :     {
     346         [ -  + ]:        282 :       if (read_addrs (&memory_closure, elfclass, elfdata,
     347                 :            :                       &buffer, &buffer_available, next, &read_vaddr,
     348                 :            :                       4, addrs))
     349                 :          0 :         return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
     350                 :            : 
     351                 :            :       /* Unused: l_addr is the difference between the address in memory
     352                 :            :          and the ELF file when the core was created. We need to
     353                 :            :          recalculate the difference below because the ELF file we use
     354                 :            :          might be differently pre-linked.  */
     355                 :            :       // GElf_Addr l_addr = addrs[0];
     356                 :        282 :       GElf_Addr l_name = addrs[1];
     357                 :        282 :       GElf_Addr l_ld = addrs[2];
     358                 :        282 :       next = addrs[3];
     359                 :            : 
     360                 :            :       /* If a clobbered or truncated memory image has no useful pointer,
     361                 :            :          just skip this element.  */
     362         [ +  + ]:        282 :       if (l_ld == 0)
     363                 :          2 :         continue;
     364                 :            : 
     365                 :            :       /* Fetch the string at the l_name address.  */
     366                 :        280 :       const char *name = NULL;
     367         [ +  - ]:        280 :       if (buffer != NULL
     368         [ +  + ]:        280 :           && read_vaddr <= l_name
     369         [ +  + ]:         36 :           && l_name + 1 - read_vaddr < buffer_available
     370                 :          4 :           && memchr (l_name - read_vaddr + buffer, '\0',
     371         [ -  + ]:          4 :                      buffer_available - (l_name - read_vaddr)) != NULL)
     372                 :            :         name = l_name - read_vaddr + buffer;
     373                 :            :       else
     374                 :            :         {
     375                 :        276 :           release_buffer (&memory_closure, &buffer, &buffer_available, 0);
     376                 :        276 :           read_vaddr = l_name;
     377                 :        276 :           int segndx = INTUSE(dwfl_addrsegment) (dwfl, l_name, NULL);
     378         [ +  - ]:        276 :           if (likely (segndx >= 0)
     379         [ +  + ]:        276 :               && (*memory_callback) (dwfl, segndx,
     380                 :            :                                      &buffer, &buffer_available,
     381                 :            :                                      l_name, 0, memory_callback_arg))
     382                 :        184 :             name = buffer;
     383                 :            :         }
     384                 :            : 
     385   [ -  +  +  + ]:        188 :       if (name != NULL && name[0] == '\0')
     386                 :         94 :         name = NULL;
     387                 :            : 
     388         [ +  + ]:        280 :       if (iterations == 1
     389         [ +  + ]:         46 :           && dwfl->user_core != NULL
     390         [ -  + ]:         36 :           && dwfl->user_core->executable_for_core != NULL)
     391                 :        280 :         name = dwfl->user_core->executable_for_core;
     392                 :            : 
     393                 :        280 :       struct r_debug_info_module *r_debug_info_module = NULL;
     394         [ +  - ]:        280 :       if (r_debug_info != NULL)
     395                 :            :         {
     396                 :            :           /* Save link map information about valid shared library (or
     397                 :            :              executable) which has not been found on disk.  */
     398         [ +  + ]:        280 :           const char *name1 = name == NULL ? "" : name;
     399                 :        280 :           r_debug_info_module = malloc (sizeof (*r_debug_info_module)
     400                 :        280 :                                         + strlen (name1) + 1);
     401         [ -  + ]:        280 :           if (unlikely (r_debug_info_module == NULL))
     402                 :          0 :             release_buffer (&memory_closure, &buffer,
     403                 :            :                             &buffer_available, result);
     404                 :        280 :           r_debug_info_module->fd = -1;
     405                 :        280 :           r_debug_info_module->elf = NULL;
     406                 :        280 :           r_debug_info_module->l_ld = l_ld;
     407                 :        280 :           r_debug_info_module->start = 0;
     408                 :        280 :           r_debug_info_module->end = 0;
     409                 :        280 :           r_debug_info_module->disk_file_has_build_id = false;
     410                 :        280 :           strcpy (r_debug_info_module->name, name1);
     411                 :        280 :           r_debug_info_module->next = r_debug_info->module;
     412                 :        280 :           r_debug_info->module = r_debug_info_module;
     413                 :            :         }
     414                 :            : 
     415                 :        280 :       Dwfl_Module *mod = NULL;
     416         [ +  + ]:        280 :       if (name != NULL)
     417                 :            :         {
     418                 :            :           /* This code is mostly inlined dwfl_report_elf.  */
     419                 :        222 :           char *sysroot_name = NULL;
     420                 :        222 :           const char *sysroot = dwfl->sysroot;
     421                 :            : 
     422                 :            :           /* Don't use the sysroot if the path is already inside it.  */
     423   [ +  +  +  - ]:        222 :           bool name_in_sysroot = sysroot && startswith (name, sysroot);
     424                 :            : 
     425         [ +  + ]:        222 :           if (sysroot && !name_in_sysroot)
     426                 :            :             {
     427         [ -  + ]:          8 :               if (asprintf (&sysroot_name, "%s%s", sysroot, name) < 0)
     428                 :          0 :                 return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
     429                 :            : 
     430                 :          8 :               name = sysroot_name;
     431                 :            :             }
     432                 :            : 
     433                 :        222 :           int fd = open (name, O_RDONLY);
     434         [ +  + ]:        222 :           if (fd >= 0)
     435                 :            :             {
     436                 :         74 :               Elf *elf;
     437                 :         74 :               Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
     438                 :         74 :               GElf_Addr elf_dynamic_vaddr;
     439         [ -  + ]:         74 :               if (error == DWFL_E_NOERROR
     440         [ -  + ]:         74 :                   && __libdwfl_dynamic_vaddr_get (elf, &elf_dynamic_vaddr))
     441                 :            :                 {
     442                 :         74 :                   const void *build_id_bits;
     443                 :         74 :                   GElf_Addr build_id_elfaddr;
     444                 :         74 :                   int build_id_len;
     445                 :         74 :                   bool valid = true;
     446                 :            : 
     447         [ +  + ]:         74 :                   if (__libdwfl_find_elf_build_id (NULL, elf, &build_id_bits,
     448                 :            :                                                    &build_id_elfaddr,
     449                 :            :                                                    &build_id_len) > 0
     450         [ +  - ]:         68 :                       && build_id_elfaddr != 0)
     451                 :            :                     {
     452         [ +  - ]:         68 :                       if (r_debug_info_module != NULL)
     453                 :         68 :                         r_debug_info_module->disk_file_has_build_id = true;
     454                 :         68 :                       GElf_Addr build_id_vaddr = (build_id_elfaddr
     455                 :         68 :                                                   - elf_dynamic_vaddr + l_ld);
     456                 :            : 
     457                 :         68 :                       release_buffer (&memory_closure, &buffer,
     458                 :            :                                       &buffer_available, 0);
     459                 :         68 :                       int segndx = INTUSE(dwfl_addrsegment) (dwfl,
     460                 :            :                                                              build_id_vaddr,
     461                 :            :                                                              NULL);
     462         [ +  + ]:         68 :                       if (! (*memory_callback) (dwfl, segndx,
     463                 :            :                                                 &buffer, &buffer_available,
     464                 :            :                                                 build_id_vaddr, build_id_len,
     465                 :            :                                                 memory_callback_arg))
     466                 :            :                         {
     467                 :            :                           /* File has valid build-id which cannot be read from
     468                 :            :                              memory.  This happens for core files without bit 4
     469                 :            :                              (0x10) set in Linux /proc/PID/coredump_filter.  */
     470                 :            :                         }
     471                 :            :                       else
     472                 :            :                         {
     473         [ -  + ]:         36 :                           if (memcmp (build_id_bits, buffer, build_id_len) != 0)
     474                 :            :                             /* File has valid build-id which does not match
     475                 :            :                                the one in memory.  */
     476                 :          0 :                             valid = false;
     477                 :         36 :                           release_buffer (&memory_closure, &buffer,
     478                 :            :                                           &buffer_available, 0);
     479                 :            : 
     480                 :            :                         }
     481                 :            :                     }
     482                 :            : 
     483         [ -  + ]:         36 :                   if (valid)
     484                 :            :                     {
     485                 :            :                       // It is like l_addr but it handles differently prelinked
     486                 :            :                       // files at core dumping vs. core loading time.
     487                 :         74 :                       GElf_Addr base = l_ld - elf_dynamic_vaddr;
     488         [ -  + ]:         74 :                       if (r_debug_info_module == NULL)
     489                 :            :                         {
     490                 :            :                           // XXX hook for sysroot
     491                 :          0 :                           mod = __libdwfl_report_elf (dwfl, xbasename (name),
     492                 :            :                                                       name, fd, elf, base,
     493                 :            :                                                       true, true);
     494         [ #  # ]:          0 :                           if (mod != NULL)
     495                 :            :                             {
     496                 :          0 :                               elf = NULL;
     497                 :          0 :                               fd = -1;
     498                 :            :                             }
     499                 :            :                         }
     500         [ -  + ]:         74 :                       else if (__libdwfl_elf_address_range (elf, base, true,
     501                 :            :                                                             true, NULL, NULL,
     502                 :            :                                                     &r_debug_info_module->start,
     503                 :            :                                                     &r_debug_info_module->end,
     504                 :            :                                                             NULL, NULL))
     505                 :            :                         {
     506                 :         74 :                           r_debug_info_module->elf = elf;
     507                 :         74 :                           r_debug_info_module->fd = fd;
     508                 :         74 :                           elf = NULL;
     509                 :         74 :                           fd = -1;
     510                 :            :                         }
     511                 :            :                     }
     512         [ -  + ]:         74 :                   if (elf != NULL)
     513                 :          0 :                     elf_end (elf);
     514         [ -  + ]:         74 :                   if (fd != -1)
     515                 :          0 :                     close (fd);
     516                 :            :                 }
     517                 :            :             }
     518                 :        222 :           free(sysroot_name);
     519                 :            :         }
     520                 :            : 
     521         [ +  - ]:        280 :       if (mod != NULL)
     522                 :            :         {
     523                 :          0 :           ++result;
     524                 :            : 
     525                 :            :           /* Move this module to the end of the list, so that we end
     526                 :            :              up with a list in the same order as the link_map chain.  */
     527         [ #  # ]:          0 :           if (mod->next != NULL)
     528                 :            :             {
     529         [ #  # ]:          0 :               if (*lastmodp != mod)
     530                 :            :                 {
     531                 :            :                   lastmodp = &dwfl->modulelist;
     532         [ #  # ]:          0 :                   while (*lastmodp != mod)
     533                 :          0 :                     lastmodp = &(*lastmodp)->next;
     534                 :            :                 }
     535                 :          0 :               *lastmodp = mod->next;
     536                 :          0 :               mod->next = NULL;
     537         [ #  # ]:          0 :               while (*lastmodp != NULL)
     538                 :          0 :                 lastmodp = &(*lastmodp)->next;
     539                 :          0 :               *lastmodp = mod;
     540                 :            :             }
     541                 :            : 
     542                 :          0 :           lastmodp = &mod->next;
     543                 :            :         }
     544                 :            :     }
     545                 :            : 
     546                 :         50 :   return release_buffer (&memory_closure, &buffer, &buffer_available, result);
     547                 :            : }
     548                 :            : 
     549                 :            : static GElf_Addr
     550                 :          0 : consider_executable (Dwfl_Module *mod, GElf_Addr at_phdr, GElf_Addr at_entry,
     551                 :            :                      uint_fast8_t *elfclass, uint_fast8_t *elfdata,
     552                 :            :                      Dwfl_Memory_Callback *memory_callback,
     553                 :            :                      void *memory_callback_arg)
     554                 :            : {
     555                 :          0 :   GElf_Ehdr ehdr;
     556         [ #  # ]:          0 :   if (unlikely (gelf_getehdr (mod->main.elf, &ehdr) == NULL))
     557                 :            :     return 0;
     558                 :            : 
     559         [ #  # ]:          0 :   if (at_entry != 0)
     560                 :            :     {
     561                 :            :       /* If we have an AT_ENTRY value, reject this executable if
     562                 :            :          its entry point address could not have supplied that.  */
     563                 :            : 
     564         [ #  # ]:          0 :       if (ehdr.e_entry == 0)
     565                 :            :         return 0;
     566                 :            : 
     567         [ #  # ]:          0 :       if (mod->e_type == ET_EXEC)
     568                 :            :         {
     569         [ #  # ]:          0 :           if (ehdr.e_entry != at_entry)
     570                 :            :             return 0;
     571                 :            :         }
     572                 :            :       else
     573                 :            :         {
     574                 :            :           /* It could be a PIE.  */
     575                 :          0 :         }
     576                 :            :     }
     577                 :            : 
     578                 :            :   // XXX this could be saved in the file cache: phdr vaddr, DT_DEBUG d_val vaddr
     579                 :            :   /* Find the vaddr of the DT_DEBUG's d_ptr.  This is the memory
     580                 :            :      address where &r_debug was written at runtime.  */
     581                 :          0 :   GElf_Xword align = mod->dwfl->segment_align;
     582                 :          0 :   GElf_Addr d_val_vaddr = 0;
     583                 :          0 :   size_t phnum;
     584         [ #  # ]:          0 :   if (elf_getphdrnum (mod->main.elf, &phnum) != 0)
     585                 :            :     return 0;
     586                 :            : 
     587         [ #  # ]:          0 :   for (size_t i = 0; i < phnum; ++i)
     588                 :            :     {
     589                 :          0 :       GElf_Phdr phdr_mem;
     590                 :          0 :       GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem);
     591         [ #  # ]:          0 :       if (phdr == NULL)
     592                 :            :         break;
     593                 :            : 
     594   [ #  #  #  # ]:          0 :       if (phdr->p_align > 1 && (align == 0 || phdr->p_align < align))
     595                 :          0 :         align = phdr->p_align;
     596                 :            : 
     597         [ #  # ]:          0 :       if (at_phdr != 0
     598         [ #  # ]:          0 :           && phdr->p_type == PT_LOAD
     599         [ #  # ]:          0 :           && (phdr->p_offset & -align) == (ehdr.e_phoff & -align))
     600                 :            :         {
     601                 :            :           /* This is the segment that would map the phdrs.
     602                 :            :              If we have an AT_PHDR value, reject this executable
     603                 :            :              if its phdr mapping could not have supplied that.  */
     604         [ #  # ]:          0 :           if (mod->e_type == ET_EXEC)
     605                 :            :             {
     606         [ #  # ]:          0 :               if (ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr != at_phdr)
     607                 :          0 :                 return 0;
     608                 :            :             }
     609                 :            :           else
     610                 :            :             {
     611                 :            :               /* It could be a PIE.  If the AT_PHDR value and our
     612                 :            :                  phdr address don't match modulo ALIGN, then this
     613                 :            :                  could not have been the right PIE.  */
     614                 :          0 :               if (((ehdr.e_phoff - phdr->p_offset + phdr->p_vaddr) & -align)
     615         [ #  # ]:          0 :                   != (at_phdr & -align))
     616                 :            :                 return 0;
     617                 :            : 
     618                 :            :               /* Calculate the bias applied to the PIE's p_vaddr values.  */
     619                 :          0 :               GElf_Addr bias = (at_phdr - (ehdr.e_phoff - phdr->p_offset
     620                 :          0 :                                            + phdr->p_vaddr));
     621                 :            : 
     622                 :            :               /* Final sanity check: if we have an AT_ENTRY value,
     623                 :            :                  reject this PIE unless its biased e_entry matches.  */
     624   [ #  #  #  # ]:          0 :               if (at_entry != 0 && at_entry != ehdr.e_entry + bias)
     625                 :            :                 return 0;
     626                 :            : 
     627                 :            :               /* If we're changing the module's address range,
     628                 :            :                  we've just invalidated the module lookup table.  */
     629         [ #  # ]:          0 :               GElf_Addr mod_bias = dwfl_adjusted_address (mod, 0);
     630         [ #  # ]:          0 :               if (bias != mod_bias)
     631                 :            :                 {
     632                 :          0 :                   mod->low_addr -= mod_bias;
     633                 :          0 :                   mod->high_addr -= mod_bias;
     634                 :          0 :                   mod->low_addr += bias;
     635                 :          0 :                   mod->high_addr += bias;
     636                 :            : 
     637                 :          0 :                   free (mod->dwfl->lookup_module);
     638                 :          0 :                   mod->dwfl->lookup_module = NULL;
     639                 :            :                 }
     640                 :            :             }
     641                 :            :         }
     642                 :            : 
     643         [ #  # ]:          0 :       if (phdr->p_type == PT_DYNAMIC)
     644                 :            :         {
     645                 :          0 :           Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, phdr->p_offset,
     646                 :            :                                                  phdr->p_filesz, ELF_T_DYN);
     647         [ #  # ]:          0 :           if (data == NULL)
     648                 :          0 :             continue;
     649                 :          0 :           const size_t entsize = gelf_fsize (mod->main.elf,
     650                 :            :                                              ELF_T_DYN, 1, EV_CURRENT);
     651                 :          0 :           const size_t n = data->d_size / entsize;
     652         [ #  # ]:          0 :           for (size_t j = 0; j < n; ++j)
     653                 :            :             {
     654                 :          0 :               GElf_Dyn dyn_mem;
     655                 :          0 :               GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem);
     656   [ #  #  #  # ]:          0 :               if (dyn != NULL && dyn->d_tag == DT_DEBUG)
     657                 :            :                 {
     658                 :          0 :                   d_val_vaddr = phdr->p_vaddr + entsize * j + entsize / 2;
     659                 :          0 :                   break;
     660                 :            :                 }
     661                 :            :             }
     662                 :            :         }
     663                 :            :     }
     664                 :            : 
     665         [ #  # ]:          0 :   if (d_val_vaddr != 0)
     666                 :            :     {
     667                 :            :       /* Now we have the final address from which to read &r_debug.  */
     668                 :          0 :       d_val_vaddr = dwfl_adjusted_address (mod, d_val_vaddr);
     669                 :            : 
     670                 :          0 :       void *buffer = NULL;
     671                 :          0 :       size_t buffer_available = addrsize (ehdr.e_ident[EI_CLASS]);
     672                 :            : 
     673                 :          0 :       int segndx = INTUSE(dwfl_addrsegment) (mod->dwfl, d_val_vaddr, NULL);
     674                 :            : 
     675         [ #  # ]:          0 :       if ((*memory_callback) (mod->dwfl, segndx,
     676                 :            :                               &buffer, &buffer_available,
     677                 :            :                               d_val_vaddr, buffer_available,
     678                 :            :                               memory_callback_arg))
     679                 :            :         {
     680                 :          0 :           const union
     681                 :            :           {
     682                 :            :             Elf32_Addr a32;
     683                 :            :             Elf64_Addr a64;
     684                 :          0 :           } *u = buffer;
     685                 :            : 
     686                 :          0 :           GElf_Addr vaddr;
     687         [ #  # ]:          0 :           if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
     688                 :          0 :             vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
     689         [ #  # ]:          0 :                      ? BE32 (u->a32) : LE32 (u->a32));
     690                 :            :           else
     691                 :          0 :             vaddr = (ehdr.e_ident[EI_DATA] == ELFDATA2MSB
     692         [ #  # ]:          0 :                      ? BE64 (u->a64) : LE64 (u->a64));
     693                 :            : 
     694                 :          0 :           (*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
     695                 :            :                               memory_callback_arg);
     696                 :            : 
     697         [ #  # ]:          0 :           if (*elfclass == ELFCLASSNONE)
     698                 :          0 :             *elfclass = ehdr.e_ident[EI_CLASS];
     699         [ #  # ]:          0 :           else if (*elfclass != ehdr.e_ident[EI_CLASS])
     700                 :          0 :             return 0;
     701                 :            : 
     702         [ #  # ]:          0 :           if (*elfdata == ELFDATANONE)
     703                 :          0 :             *elfdata = ehdr.e_ident[EI_DATA];
     704         [ #  # ]:          0 :           else if (*elfdata != ehdr.e_ident[EI_DATA])
     705                 :            :             return 0;
     706                 :            : 
     707                 :          0 :           return vaddr;
     708                 :            :         }
     709                 :            :     }
     710                 :            : 
     711                 :            :   return 0;
     712                 :            : }
     713                 :            : 
     714                 :            : /* Try to find an existing executable module with a DT_DEBUG.  */
     715                 :            : static GElf_Addr
     716                 :          0 : find_executable (Dwfl *dwfl, GElf_Addr at_phdr, GElf_Addr at_entry,
     717                 :            :                  uint_fast8_t *elfclass, uint_fast8_t *elfdata,
     718                 :            :                  Dwfl_Memory_Callback *memory_callback,
     719                 :            :                  void *memory_callback_arg)
     720                 :            : {
     721         [ #  # ]:          0 :   for (Dwfl_Module *mod = dwfl->modulelist; mod != NULL; mod = mod->next)
     722         [ #  # ]:          0 :     if (mod->main.elf != NULL)
     723                 :            :       {
     724                 :          0 :         GElf_Addr r_debug_vaddr = consider_executable (mod, at_phdr, at_entry,
     725                 :            :                                                        elfclass, elfdata,
     726                 :            :                                                        memory_callback,
     727                 :            :                                                        memory_callback_arg);
     728         [ #  # ]:          0 :         if (r_debug_vaddr != 0)
     729                 :          0 :           return r_debug_vaddr;
     730                 :            :       }
     731                 :            : 
     732                 :            :   return 0;
     733                 :            : }
     734                 :            : 
     735                 :            : 
     736                 :            : int
     737                 :         76 : dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
     738                 :            :                       Dwfl_Memory_Callback *memory_callback,
     739                 :            :                       void *memory_callback_arg,
     740                 :            :                       struct r_debug_info *r_debug_info)
     741                 :            : {
     742                 :         76 :   GElf_Addr r_debug_vaddr = 0;
     743                 :            : 
     744                 :         76 :   uint_fast8_t elfclass = ELFCLASSNONE;
     745                 :         76 :   uint_fast8_t elfdata = ELFDATANONE;
     746         [ +  - ]:         76 :   if (likely (auxv != NULL)
     747         [ +  - ]:         76 :       && likely (auxv_format_probe (auxv, auxv_size, &elfclass, &elfdata)))
     748                 :            :     {
     749                 :         76 :       GElf_Addr entry = 0;
     750                 :         76 :       GElf_Addr phdr = 0;
     751                 :         76 :       GElf_Xword phent = 0;
     752                 :         76 :       GElf_Xword phnum = 0;
     753                 :            : 
     754                 :            : #define READ_AUXV32(ptr)        read_4ubyte_unaligned_noncvt (ptr)
     755                 :            : #define READ_AUXV64(ptr)        read_8ubyte_unaligned_noncvt (ptr)
     756                 :            : #define AUXV_SCAN(NN, BL) do                                            \
     757                 :            :         {                                                               \
     758                 :            :           const Elf##NN##_auxv_t *av = auxv;                            \
     759                 :            :           for (size_t i = 0; i < auxv_size / sizeof av[0]; ++i)         \
     760                 :            :             {                                                           \
     761                 :            :               const char *typep = auxv + i * sizeof (Elf##NN##_auxv_t); \
     762                 :            :               typep += offsetof (Elf##NN##_auxv_t, a_type);             \
     763                 :            :               uint##NN##_t type = READ_AUXV##NN (typep);                \
     764                 :            :               const char *valp = auxv + i * sizeof (Elf##NN##_auxv_t);  \
     765                 :            :               valp += offsetof (Elf##NN##_auxv_t, a_un.a_val);          \
     766                 :            :               uint##NN##_t val = BL##NN (READ_AUXV##NN (valp));         \
     767                 :            :               if (type == BL##NN (AT_ENTRY))                            \
     768                 :            :                 entry = val;                                            \
     769                 :            :               else if (type == BL##NN (AT_PHDR))                        \
     770                 :            :                 phdr = val;                                             \
     771                 :            :               else if (type == BL##NN (AT_PHNUM))                       \
     772                 :            :                 phnum = val;                                            \
     773                 :            :               else if (type == BL##NN (AT_PHENT))                       \
     774                 :            :                 phent = val;                                            \
     775                 :            :               else if (type == BL##NN (AT_PAGESZ))                      \
     776                 :            :                 {                                                       \
     777                 :            :                   if (val > 1                                           \
     778                 :            :                       && (dwfl->segment_align == 0                      \
     779                 :            :                           || val < dwfl->segment_align))                \
     780                 :            :                     dwfl->segment_align = val;                          \
     781                 :            :                 }                                                       \
     782                 :            :             }                                                           \
     783                 :            :         }                                                               \
     784                 :            :       while (0)
     785                 :            : 
     786         [ +  + ]:         76 :       if (elfclass == ELFCLASS32)
     787                 :            :         {
     788         [ +  + ]:         14 :           if (elfdata == ELFDATA2MSB)
     789   [ +  +  +  +  :        146 :             AUXV_SCAN (32, BE);
          +  +  +  +  +  
          +  -  +  +  -  
             +  -  +  + ]
     790                 :            :           else
     791   [ +  +  +  +  :        166 :             AUXV_SCAN (32, LE);
          +  +  +  +  +  
          +  -  +  +  -  
             +  -  +  + ]
     792                 :            :         }
     793                 :            :       else
     794                 :            :         {
     795         [ +  + ]:         62 :           if (elfdata == ELFDATA2MSB)
     796   [ +  +  +  +  :        182 :             AUXV_SCAN (64, BE);
          +  +  +  +  +  
          +  -  +  +  -  
             +  -  +  + ]
     797                 :            :           else
     798   [ +  +  +  +  :       1106 :             AUXV_SCAN (64, LE);
          +  +  +  +  +  
          +  -  +  +  -  
             +  -  +  + ]
     799                 :            :         }
     800                 :            : 
     801                 :            :       /* If we found the phdr dimensions, search phdrs for PT_DYNAMIC.  */
     802                 :         76 :       GElf_Addr dyn_vaddr = 0;
     803                 :         76 :       GElf_Xword dyn_filesz = 0;
     804                 :         76 :       GElf_Addr dyn_bias = (GElf_Addr) -1;
     805                 :            : 
     806         [ +  - ]:         76 :       if (phdr != 0 && phnum != 0
     807   [ +  +  -  + ]:         76 :           && ((elfclass == ELFCLASS32 && phent == sizeof (Elf32_Phdr))
     808   [ +  -  +  - ]:         62 :               || (elfclass == ELFCLASS64 && phent == sizeof (Elf64_Phdr))))
     809                 :            :         {
     810                 :         76 :           Dwfl_Module *phdr_mod;
     811                 :         76 :           int phdr_segndx = INTUSE(dwfl_addrsegment) (dwfl, phdr, &phdr_mod);
     812                 :         76 :           Elf_Data in =
     813                 :            :             {
     814                 :            :               .d_type = ELF_T_PHDR,
     815                 :            :               .d_version = EV_CURRENT,
     816                 :         76 :               .d_size = phnum * phent,
     817                 :            :               .d_buf = NULL
     818                 :            :             };
     819                 :         76 :           bool in_ok = (*memory_callback) (dwfl, phdr_segndx, &in.d_buf,
     820                 :            :                                            &in.d_size, phdr, phnum * phent,
     821                 :            :                                            memory_callback_arg);
     822                 :         76 :           bool in_from_exec = false;
     823         [ +  + ]:         76 :           if (! in_ok
     824         [ +  - ]:          4 :               && dwfl->user_core != NULL
     825         [ +  - ]:          4 :               && dwfl->user_core->executable_for_core != NULL)
     826                 :            :             {
     827                 :            :               /* AUXV -> PHDR -> DYNAMIC
     828                 :            :                  Both AUXV and DYNAMIC should be always present in a core file.
     829                 :            :                  PHDR may be missing in core file, try to read it from
     830                 :            :                  EXECUTABLE_FOR_CORE to find where DYNAMIC is located in the
     831                 :            :                  core file.  */
     832                 :            : 
     833                 :          4 :               int fd = open (dwfl->user_core->executable_for_core, O_RDONLY);
     834                 :          4 :               Elf *elf;
     835                 :          4 :               Dwfl_Error error = DWFL_E_ERRNO;
     836         [ +  - ]:          4 :               if (fd != -1)
     837                 :          4 :                 error = __libdw_open_file (&fd, &elf, true, false);
     838         [ -  + ]:          4 :               if (error != DWFL_E_NOERROR)
     839                 :            :                 {
     840                 :          0 :                   __libdwfl_seterrno (error);
     841                 :          0 :                   return false;
     842                 :            :                 }
     843                 :          4 :               GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
     844         [ -  + ]:          4 :               if (ehdr == NULL)
     845                 :            :                 {
     846                 :          0 :                   elf_end (elf);
     847                 :          0 :                   close (fd);
     848                 :          0 :                   __libdwfl_seterrno (DWFL_E_LIBELF);
     849                 :          0 :                   return false;
     850                 :            :                 }
     851                 :          4 :               size_t e_phnum;
     852         [ -  + ]:          4 :               if (elf_getphdrnum (elf, &e_phnum) != 0)
     853                 :            :                 {
     854                 :          0 :                   elf_end (elf);
     855                 :          0 :                   close (fd);
     856                 :          0 :                   __libdwfl_seterrno (DWFL_E_LIBELF);
     857                 :          0 :                   return false;
     858                 :            :                 }
     859   [ +  -  -  + ]:          4 :               if (e_phnum != phnum || ehdr->e_phentsize != phent)
     860                 :            :                 {
     861                 :          0 :                   elf_end (elf);
     862                 :          0 :                   close (fd);
     863                 :          0 :                   __libdwfl_seterrno (DWFL_E_BADELF);
     864                 :          0 :                   return false;
     865                 :            :                 }
     866                 :          4 :               off_t off = ehdr->e_phoff;
     867         [ -  + ]:          4 :               assert (in.d_buf == NULL);
     868                 :            :               /* Note this in the !in_ok path.  That means memory_callback
     869                 :            :                  failed.  But the callback might still have reset the d_size
     870                 :            :                  value (to zero).  So explicitly set it here again.  */
     871         [ -  + ]:          4 :               if (unlikely (phnum > SIZE_MAX / phent))
     872                 :            :                 {
     873                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
     874                 :          0 :                   return false;
     875                 :            :                 }
     876                 :          4 :               in.d_size = phnum * phent;
     877                 :          4 :               in.d_buf = malloc (in.d_size);
     878         [ -  + ]:          4 :               if (unlikely (in.d_buf == NULL))
     879                 :            :                 {
     880                 :          0 :                   elf_end (elf);
     881                 :          0 :                   close (fd);
     882                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
     883                 :          0 :                   return false;
     884                 :            :                 }
     885                 :          4 :               ssize_t nread = pread_retry (fd, in.d_buf, in.d_size, off);
     886                 :          4 :               elf_end (elf);
     887                 :          4 :               close (fd);
     888         [ -  + ]:          4 :               if (nread != (ssize_t) in.d_size)
     889                 :            :                 {
     890                 :          0 :                   free (in.d_buf);
     891                 :          0 :                   __libdwfl_seterrno (DWFL_E_ERRNO);
     892                 :          0 :                   return false;
     893                 :            :                 }
     894                 :          4 :               in_ok = true;
     895                 :          4 :               in_from_exec = true;
     896                 :            :             }
     897                 :          4 :           if (in_ok)
     898                 :            :             {
     899         [ -  + ]:         76 :               if (unlikely (phnum > SIZE_MAX / phent))
     900                 :            :                 {
     901                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
     902                 :          0 :                   return false;
     903                 :            :                 }
     904                 :         76 :               size_t nbytes = phnum * phent;
     905                 :            :               /* We can only process as many bytes/phnum as there are
     906                 :            :                  in in.d_size. The data might have been truncated.  */
     907         [ -  + ]:         76 :               if (nbytes > in.d_size)
     908                 :            :                 {
     909                 :          0 :                   nbytes = in.d_size;
     910                 :          0 :                   phnum = nbytes / phent;
     911         [ #  # ]:          0 :                   if (phnum == 0)
     912                 :            :                     {
     913                 :          0 :                       __libdwfl_seterrno (DWFL_E_BADELF);
     914                 :          0 :                       return false;
     915                 :            :                     }
     916                 :            :                 }
     917                 :         76 :               void *buf = malloc (nbytes);
     918                 :         76 :               Elf32_Phdr (*p32)[phnum] = buf;
     919                 :         76 :               Elf64_Phdr (*p64)[phnum] = buf;
     920         [ -  + ]:         76 :               if (unlikely (buf == NULL))
     921                 :            :                 {
     922                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
     923                 :          0 :                   return false;
     924                 :            :                 }
     925                 :         76 :               Elf_Data out =
     926                 :            :                 {
     927                 :            :                   .d_type = ELF_T_PHDR,
     928                 :            :                   .d_version = EV_CURRENT,
     929                 :            :                   .d_size = nbytes,
     930                 :            :                   .d_buf = buf
     931                 :            :                 };
     932         [ +  + ]:         76 :               if (in.d_size > out.d_size)
     933                 :            :                 {
     934                 :         70 :                   in.d_size = out.d_size;
     935                 :         70 :                   phnum = in.d_size / phent;
     936         [ -  + ]:         70 :                   if (phnum == 0)
     937                 :            :                     {
     938                 :          0 :                       free (buf);
     939                 :          0 :                       __libdwfl_seterrno (DWFL_E_BADELF);
     940                 :          0 :                       return false;
     941                 :            :                     }
     942                 :            :                 }
     943                 :         76 :               bool is32 = (elfclass == ELFCLASS32);
     944                 :        152 :               size_t phdr_align = (is32
     945                 :            :                                    ? __alignof__ (Elf32_Phdr)
     946         [ +  + ]:         76 :                                    : __alignof__ (Elf64_Phdr));
     947         [ +  + ]:         76 :               if (!in_from_exec
     948         [ -  + ]:         72 :                   && ((uintptr_t) in.d_buf & (phdr_align - 1)) != 0)
     949                 :            :                 {
     950                 :          0 :                   memcpy (out.d_buf, in.d_buf, in.d_size);
     951                 :          0 :                   in.d_buf = out.d_buf;
     952                 :            :                 }
     953   [ +  +  +  - ]:        138 :               if (likely ((elfclass == ELFCLASS32
     954                 :            :                            ? elf32_xlatetom : elf64_xlatetom)
     955                 :            :                           (&out, &in, elfdata) != NULL))
     956                 :            :                 {
     957         [ +  + ]:        410 :                   for (size_t i = 0; i < phnum; ++i)
     958                 :            :                     {
     959                 :        768 :                       GElf_Word type = (is32
     960                 :            :                                         ? (*p32)[i].p_type
     961         [ +  + ]:        384 :                                         : (*p64)[i].p_type);
     962                 :        768 :                       GElf_Addr vaddr = (is32
     963                 :         74 :                                          ? (*p32)[i].p_vaddr
     964         [ +  + ]:        384 :                                          : (*p64)[i].p_vaddr);
     965                 :        768 :                       GElf_Xword filesz = (is32
     966                 :         74 :                                            ? (*p32)[i].p_filesz
     967         [ +  + ]:        384 :                                            : (*p64)[i].p_filesz);
     968                 :            : 
     969         [ +  + ]:        384 :                       if (type == PT_PHDR)
     970                 :            :                         {
     971         [ +  - ]:         50 :                           if (dyn_bias == (GElf_Addr) -1
     972                 :            :                               /* Do a sanity check on the putative address.  */
     973                 :         50 :                               && ((vaddr & (dwfl->segment_align - 1))
     974         [ +  - ]:         50 :                                   == (phdr & (dwfl->segment_align - 1))))
     975                 :            :                             {
     976                 :         50 :                               dyn_bias = phdr - vaddr;
     977         [ +  - ]:         50 :                               if (dyn_vaddr != 0)
     978                 :            :                                 break;
     979                 :            :                             }
     980                 :            : 
     981                 :            :                         }
     982         [ +  + ]:        334 :                       else if (type == PT_DYNAMIC)
     983                 :            :                         {
     984                 :         50 :                           dyn_vaddr = vaddr;
     985                 :         50 :                           dyn_filesz = filesz;
     986         [ -  + ]:         50 :                           if (dyn_bias != (GElf_Addr) -1)
     987                 :            :                             break;
     988                 :            :                         }
     989                 :            :                     }
     990                 :            :                 }
     991                 :            : 
     992         [ +  + ]:         76 :               if (in_from_exec)
     993                 :          4 :                 free (in.d_buf);
     994                 :            :               else
     995                 :         72 :                 (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
     996                 :            :                                     memory_callback_arg);
     997                 :         76 :               free (buf);
     998                 :            :             }
     999                 :            :           else
    1000                 :            :             /* We could not read the executable's phdrs from the
    1001                 :            :                memory image.  If we have a presupplied executable,
    1002                 :            :                we can still use the AT_PHDR and AT_ENTRY values to
    1003                 :            :                verify it, and to adjust its bias if it's a PIE.
    1004                 :            : 
    1005                 :            :                If there was an ET_EXEC module presupplied that contains
    1006                 :            :                the AT_PHDR address, then we only consider that one.
    1007                 :            :                We'll either accept it if its phdr location and e_entry
    1008                 :            :                make sense or reject it if they don't.  If there is no
    1009                 :            :                presupplied ET_EXEC, then look for a presupplied module,
    1010                 :            :                which might be a PIE (ET_DYN) that needs its bias adjusted.  */
    1011                 :          0 :             r_debug_vaddr = ((phdr_mod == NULL
    1012         [ #  # ]:          0 :                               || phdr_mod->main.elf == NULL
    1013         [ #  # ]:          0 :                               || phdr_mod->e_type != ET_EXEC)
    1014                 :          0 :                              ? find_executable (dwfl, phdr, entry,
    1015                 :            :                                                 &elfclass, &elfdata,
    1016                 :            :                                                 memory_callback,
    1017                 :            :                                                 memory_callback_arg)
    1018         [ #  # ]:          0 :                              : consider_executable (phdr_mod, phdr, entry,
    1019                 :            :                                                     &elfclass, &elfdata,
    1020                 :            :                                                     memory_callback,
    1021                 :            :                                                     memory_callback_arg));
    1022                 :            :         }
    1023                 :            : 
    1024                 :            :       /* If we found PT_DYNAMIC, search it for DT_DEBUG.  */
    1025         [ +  + ]:         76 :       if (dyn_filesz != 0)
    1026                 :            :         {
    1027         [ +  - ]:         50 :           if (dyn_bias != (GElf_Addr) -1)
    1028                 :         50 :             dyn_vaddr += dyn_bias;
    1029                 :            : 
    1030                 :         50 :           Elf_Data in =
    1031                 :            :             {
    1032                 :            :               .d_type = ELF_T_DYN,
    1033                 :            :               .d_version = EV_CURRENT,
    1034                 :            :               .d_size = dyn_filesz,
    1035                 :            :               .d_buf = NULL
    1036                 :            :             };
    1037                 :         50 :           int dyn_segndx = dwfl_addrsegment (dwfl, dyn_vaddr, NULL);
    1038         [ +  - ]:         50 :           if ((*memory_callback) (dwfl, dyn_segndx, &in.d_buf, &in.d_size,
    1039                 :            :                                   dyn_vaddr, dyn_filesz, memory_callback_arg))
    1040                 :            :             {
    1041                 :        100 :               size_t entsize = (elfclass == ELFCLASS32
    1042         [ +  + ]:         50 :                                 ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn));
    1043         [ -  + ]:         50 :               if (unlikely (dyn_filesz > SIZE_MAX / entsize))
    1044                 :            :                 {
    1045                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
    1046                 :          0 :                   return false;
    1047                 :            :                 }
    1048                 :            :               /* We can only process as many bytes as there are in
    1049                 :            :                  in.d_size. The data might have been truncated.  */
    1050                 :         50 :               if (dyn_filesz > in.d_size)
    1051                 :            :                 dyn_filesz = in.d_size;
    1052         [ -  + ]:         50 :               if (dyn_filesz / entsize == 0)
    1053                 :            :                 {
    1054                 :          0 :                   __libdwfl_seterrno (DWFL_E_BADELF);
    1055                 :          0 :                   return false;
    1056                 :            :                 }
    1057                 :         50 :               void *buf = malloc (dyn_filesz);
    1058         [ -  + ]:         50 :               if (unlikely (buf == NULL))
    1059                 :            :                 {
    1060                 :          0 :                   __libdwfl_seterrno (DWFL_E_NOMEM);
    1061                 :          0 :                   return false;
    1062                 :            :                 }
    1063                 :         50 :               Elf_Data out =
    1064                 :            :                 {
    1065                 :            :                   .d_type = ELF_T_DYN,
    1066                 :            :                   .d_version = EV_CURRENT,
    1067                 :            :                   .d_size = dyn_filesz,
    1068                 :            :                   .d_buf = buf
    1069                 :            :                 };
    1070         [ +  + ]:         50 :               if (in.d_size > out.d_size)
    1071                 :         48 :                 in.d_size = out.d_size;
    1072                 :        100 :               size_t dyn_align = (elfclass == ELFCLASS32
    1073                 :            :                                   ? __alignof__ (Elf32_Dyn)
    1074         [ +  + ]:         50 :                                   : __alignof__ (Elf64_Dyn));
    1075         [ -  + ]:         50 :               if (((uintptr_t) in.d_buf & (dyn_align - 1)) != 0)
    1076                 :            :                 {
    1077                 :          0 :                   memcpy (out.d_buf, in.d_buf, in.d_size);
    1078                 :          0 :                   in.d_buf = out.d_buf;
    1079                 :            :                 }
    1080   [ +  +  +  - ]:         96 :               if (likely ((elfclass == ELFCLASS32
    1081                 :            :                            ? elf32_xlatetom : elf64_xlatetom)
    1082                 :            :                           (&out, &in, elfdata) != NULL))
    1083                 :            :                 {
    1084                 :            :                   /* We are looking for DT_DEBUG.  */
    1085         [ +  + ]:         50 :                   if (elfclass == ELFCLASS32)
    1086                 :            :                     {
    1087                 :          4 :                       Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = buf;
    1088                 :          4 :                       size_t n = dyn_filesz / sizeof (Elf32_Dyn);
    1089         [ +  - ]:         56 :                       for (size_t i = 0; i < n; ++i)
    1090         [ +  + ]:         56 :                         if ((*d32)[i].d_tag == DT_DEBUG)
    1091                 :            :                           {
    1092                 :          4 :                             r_debug_vaddr = (*d32)[i].d_un.d_val;
    1093                 :          4 :                             break;
    1094                 :            :                           }
    1095                 :            :                     }
    1096                 :            :                   else
    1097                 :            :                     {
    1098                 :         46 :                       Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = buf;
    1099                 :         46 :                       size_t n = dyn_filesz / sizeof (Elf64_Dyn);
    1100         [ +  - ]:        634 :                       for (size_t i = 0; i < n; ++i)
    1101         [ +  + ]:        634 :                         if ((*d64)[i].d_tag == DT_DEBUG)
    1102                 :            :                           {
    1103                 :         46 :                             r_debug_vaddr = (*d64)[i].d_un.d_val;
    1104                 :         46 :                             break;
    1105                 :            :                           }
    1106                 :            :                     }
    1107                 :            :                 }
    1108                 :            : 
    1109                 :         50 :               (*memory_callback) (dwfl, -1, &in.d_buf, &in.d_size, 0, 0,
    1110                 :            :                                   memory_callback_arg);
    1111                 :         50 :               free (buf);
    1112                 :            :             }
    1113                 :            :         }
    1114                 :            :     }
    1115                 :            :   else
    1116                 :            :     /* We have to look for a presupplied executable file to determine
    1117                 :            :        the vaddr of its dynamic section and DT_DEBUG therein.  */
    1118                 :          0 :     r_debug_vaddr = find_executable (dwfl, 0, 0, &elfclass, &elfdata,
    1119                 :            :                                      memory_callback, memory_callback_arg);
    1120                 :            : 
    1121         [ +  + ]:         76 :   if (r_debug_vaddr == 0)
    1122                 :            :     return 0;
    1123                 :            : 
    1124                 :            :   /* For following pointers from struct link_map, we will use an
    1125                 :            :      integrated memory access callback that can consult module text
    1126                 :            :      elided from the core file.  This is necessary when the l_name
    1127                 :            :      pointer for the dynamic linker's own entry is a pointer into the
    1128                 :            :      executable's .interp section.  */
    1129                 :         50 :   struct integrated_memory_callback mcb =
    1130                 :            :     {
    1131                 :            :       .memory_callback = memory_callback,
    1132                 :            :       .memory_callback_arg = memory_callback_arg
    1133                 :            :     };
    1134                 :            : 
    1135                 :            :   /* Now we can follow the dynamic linker's library list.  */
    1136                 :         50 :   return report_r_debug (elfclass, elfdata, dwfl, r_debug_vaddr,
    1137                 :            :                          &integrated_memory_callback, &mcb, r_debug_info);
    1138                 :            : }
    1139                 :            : INTDEF (dwfl_link_map_report)

Generated by: LCOV version 1.16