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