LCOV - code coverage report
Current view: top level - libdwfl - link_map.c (source / functions) Hit Total Coverage
Test: elfutils-0.193 Lines: 323 490 65.9 %
Date: 2025-06-06 18:30:13 Functions: 8 10 80.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 256 442 57.9 %

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

Generated by: LCOV version 1.16