1da0c48c4Sopenharmony_ci/* Sniff out modules from ELF headers visible in memory segments. 2da0c48c4Sopenharmony_ci Copyright (C) 2008-2012, 2014, 2015, 2018 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 "../libelf/libelfP.h" /* For NOTE_ALIGN4 and NOTE_ALIGN8. */ 32da0c48c4Sopenharmony_ci#undef _ 33da0c48c4Sopenharmony_ci#include "libdwflP.h" 34da0c48c4Sopenharmony_ci#include "common.h" 35da0c48c4Sopenharmony_ci 36da0c48c4Sopenharmony_ci#include <elf.h> 37da0c48c4Sopenharmony_ci#include <gelf.h> 38da0c48c4Sopenharmony_ci#include <inttypes.h> 39da0c48c4Sopenharmony_ci#include <fcntl.h> 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_ci#include <system.h> 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci 44da0c48c4Sopenharmony_ci/* A good size for the initial read from memory, if it's not too costly. 45da0c48c4Sopenharmony_ci This more than covers the phdrs and note segment in the average 64-bit 46da0c48c4Sopenharmony_ci binary. */ 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci#define INITIAL_READ 1024 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN 51da0c48c4Sopenharmony_ci# define MY_ELFDATA ELFDATA2LSB 52da0c48c4Sopenharmony_ci#else 53da0c48c4Sopenharmony_ci# define MY_ELFDATA ELFDATA2MSB 54da0c48c4Sopenharmony_ci#endif 55da0c48c4Sopenharmony_ci 56da0c48c4Sopenharmony_cistruct elf_build_id 57da0c48c4Sopenharmony_ci{ 58da0c48c4Sopenharmony_ci void *memory; 59da0c48c4Sopenharmony_ci size_t len; 60da0c48c4Sopenharmony_ci GElf_Addr vaddr; 61da0c48c4Sopenharmony_ci}; 62da0c48c4Sopenharmony_ci 63da0c48c4Sopenharmony_cistruct read_state 64da0c48c4Sopenharmony_ci{ 65da0c48c4Sopenharmony_ci Dwfl *dwfl; 66da0c48c4Sopenharmony_ci Dwfl_Memory_Callback *memory_callback; 67da0c48c4Sopenharmony_ci void *memory_callback_arg; 68da0c48c4Sopenharmony_ci void **buffer; 69da0c48c4Sopenharmony_ci size_t *buffer_available; 70da0c48c4Sopenharmony_ci}; 71da0c48c4Sopenharmony_ci 72da0c48c4Sopenharmony_ci/* Return user segment index closest to ADDR but not above it. 73da0c48c4Sopenharmony_ci If NEXT, return the closest to ADDR but not below it. */ 74da0c48c4Sopenharmony_cistatic int 75da0c48c4Sopenharmony_ciaddr_segndx (Dwfl *dwfl, size_t segment, GElf_Addr addr, bool next) 76da0c48c4Sopenharmony_ci{ 77da0c48c4Sopenharmony_ci int ndx = -1; 78da0c48c4Sopenharmony_ci do 79da0c48c4Sopenharmony_ci { 80da0c48c4Sopenharmony_ci if (dwfl->lookup_segndx[segment] >= 0) 81da0c48c4Sopenharmony_ci ndx = dwfl->lookup_segndx[segment]; 82da0c48c4Sopenharmony_ci if (++segment >= dwfl->lookup_elts - 1) 83da0c48c4Sopenharmony_ci return next ? ndx + 1 : ndx; 84da0c48c4Sopenharmony_ci } 85da0c48c4Sopenharmony_ci while (dwfl->lookup_addr[segment] < addr); 86da0c48c4Sopenharmony_ci 87da0c48c4Sopenharmony_ci if (next) 88da0c48c4Sopenharmony_ci { 89da0c48c4Sopenharmony_ci while (dwfl->lookup_segndx[segment] < 0) 90da0c48c4Sopenharmony_ci if (++segment >= dwfl->lookup_elts - 1) 91da0c48c4Sopenharmony_ci return ndx + 1; 92da0c48c4Sopenharmony_ci ndx = dwfl->lookup_segndx[segment]; 93da0c48c4Sopenharmony_ci } 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_ci return ndx; 96da0c48c4Sopenharmony_ci} 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci/* Return whether there is SZ bytes available at PTR till END. */ 99da0c48c4Sopenharmony_ci 100da0c48c4Sopenharmony_cistatic bool 101da0c48c4Sopenharmony_cibuf_has_data (const void *ptr, const void *end, size_t sz) 102da0c48c4Sopenharmony_ci{ 103da0c48c4Sopenharmony_ci return ptr < end && (size_t) (end - ptr) >= sz; 104da0c48c4Sopenharmony_ci} 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_ci/* Read SZ bytes into *RETP from *PTRP (limited by END) in format EI_DATA. 107da0c48c4Sopenharmony_ci Function comes from src/readelf.c . */ 108da0c48c4Sopenharmony_ci 109da0c48c4Sopenharmony_cistatic bool 110da0c48c4Sopenharmony_cibuf_read_ulong (unsigned char ei_data, size_t sz, 111da0c48c4Sopenharmony_ci const void **ptrp, const void *end, uint64_t *retp) 112da0c48c4Sopenharmony_ci{ 113da0c48c4Sopenharmony_ci if (! buf_has_data (*ptrp, end, sz)) 114da0c48c4Sopenharmony_ci return false; 115da0c48c4Sopenharmony_ci 116da0c48c4Sopenharmony_ci union 117da0c48c4Sopenharmony_ci { 118da0c48c4Sopenharmony_ci uint64_t u64; 119da0c48c4Sopenharmony_ci uint32_t u32; 120da0c48c4Sopenharmony_ci } u; 121da0c48c4Sopenharmony_ci 122da0c48c4Sopenharmony_ci memcpy (&u, *ptrp, sz); 123da0c48c4Sopenharmony_ci (*ptrp) += sz; 124da0c48c4Sopenharmony_ci 125da0c48c4Sopenharmony_ci if (retp == NULL) 126da0c48c4Sopenharmony_ci return true; 127da0c48c4Sopenharmony_ci 128da0c48c4Sopenharmony_ci if (MY_ELFDATA != ei_data) 129da0c48c4Sopenharmony_ci { 130da0c48c4Sopenharmony_ci if (sz == 4) 131da0c48c4Sopenharmony_ci CONVERT (u.u32); 132da0c48c4Sopenharmony_ci else 133da0c48c4Sopenharmony_ci CONVERT (u.u64); 134da0c48c4Sopenharmony_ci } 135da0c48c4Sopenharmony_ci if (sz == 4) 136da0c48c4Sopenharmony_ci *retp = u.u32; 137da0c48c4Sopenharmony_ci else 138da0c48c4Sopenharmony_ci *retp = u.u64; 139da0c48c4Sopenharmony_ci return true; 140da0c48c4Sopenharmony_ci} 141da0c48c4Sopenharmony_ci 142da0c48c4Sopenharmony_ci/* Try to find matching entry for module from address MODULE_START to 143da0c48c4Sopenharmony_ci MODULE_END in NT_FILE note located at NOTE_FILE of NOTE_FILE_SIZE 144da0c48c4Sopenharmony_ci bytes in format EI_CLASS and EI_DATA. */ 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_cistatic const char * 147da0c48c4Sopenharmony_cihandle_file_note (GElf_Addr module_start, GElf_Addr module_end, 148da0c48c4Sopenharmony_ci unsigned char ei_class, unsigned char ei_data, 149da0c48c4Sopenharmony_ci const void *note_file, size_t note_file_size) 150da0c48c4Sopenharmony_ci{ 151da0c48c4Sopenharmony_ci if (note_file == NULL) 152da0c48c4Sopenharmony_ci return NULL; 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci size_t sz; 155da0c48c4Sopenharmony_ci switch (ei_class) 156da0c48c4Sopenharmony_ci { 157da0c48c4Sopenharmony_ci case ELFCLASS32: 158da0c48c4Sopenharmony_ci sz = 4; 159da0c48c4Sopenharmony_ci break; 160da0c48c4Sopenharmony_ci case ELFCLASS64: 161da0c48c4Sopenharmony_ci sz = 8; 162da0c48c4Sopenharmony_ci break; 163da0c48c4Sopenharmony_ci default: 164da0c48c4Sopenharmony_ci return NULL; 165da0c48c4Sopenharmony_ci } 166da0c48c4Sopenharmony_ci 167da0c48c4Sopenharmony_ci const void *ptr = note_file; 168da0c48c4Sopenharmony_ci const void *end = note_file + note_file_size; 169da0c48c4Sopenharmony_ci uint64_t count; 170da0c48c4Sopenharmony_ci if (! buf_read_ulong (ei_data, sz, &ptr, end, &count)) 171da0c48c4Sopenharmony_ci return NULL; 172da0c48c4Sopenharmony_ci if (! buf_read_ulong (ei_data, sz, &ptr, end, NULL)) // page_size 173da0c48c4Sopenharmony_ci return NULL; 174da0c48c4Sopenharmony_ci 175da0c48c4Sopenharmony_ci uint64_t maxcount = (size_t) (end - ptr) / (3 * sz); 176da0c48c4Sopenharmony_ci if (count > maxcount) 177da0c48c4Sopenharmony_ci return NULL; 178da0c48c4Sopenharmony_ci 179da0c48c4Sopenharmony_ci /* Where file names are stored. */ 180da0c48c4Sopenharmony_ci const char *fptr = ptr + 3 * count * sz; 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci ssize_t firstix = -1; 183da0c48c4Sopenharmony_ci ssize_t lastix = -1; 184da0c48c4Sopenharmony_ci for (size_t mix = 0; mix < count; mix++) 185da0c48c4Sopenharmony_ci { 186da0c48c4Sopenharmony_ci uint64_t mstart, mend, moffset; 187da0c48c4Sopenharmony_ci if (! buf_read_ulong (ei_data, sz, &ptr, fptr, &mstart) 188da0c48c4Sopenharmony_ci || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &mend) 189da0c48c4Sopenharmony_ci || ! buf_read_ulong (ei_data, sz, &ptr, fptr, &moffset)) 190da0c48c4Sopenharmony_ci return NULL; 191da0c48c4Sopenharmony_ci if (mstart == module_start && moffset == 0) 192da0c48c4Sopenharmony_ci firstix = lastix = mix; 193da0c48c4Sopenharmony_ci if (firstix != -1 && mstart < module_end) 194da0c48c4Sopenharmony_ci lastix = mix; 195da0c48c4Sopenharmony_ci if (mend >= module_end) 196da0c48c4Sopenharmony_ci break; 197da0c48c4Sopenharmony_ci } 198da0c48c4Sopenharmony_ci if (firstix == -1) 199da0c48c4Sopenharmony_ci return NULL; 200da0c48c4Sopenharmony_ci 201da0c48c4Sopenharmony_ci const char *retval = NULL; 202da0c48c4Sopenharmony_ci for (ssize_t mix = 0; mix <= lastix; mix++) 203da0c48c4Sopenharmony_ci { 204da0c48c4Sopenharmony_ci const char *fnext = memchr (fptr, 0, (const char *) end - fptr); 205da0c48c4Sopenharmony_ci if (fnext == NULL) 206da0c48c4Sopenharmony_ci return NULL; 207da0c48c4Sopenharmony_ci if (mix == firstix) 208da0c48c4Sopenharmony_ci retval = fptr; 209da0c48c4Sopenharmony_ci if (firstix < mix && mix <= lastix && strcmp (fptr, retval) != 0) 210da0c48c4Sopenharmony_ci return NULL; 211da0c48c4Sopenharmony_ci fptr = fnext + 1; 212da0c48c4Sopenharmony_ci } 213da0c48c4Sopenharmony_ci return retval; 214da0c48c4Sopenharmony_ci} 215da0c48c4Sopenharmony_ci 216da0c48c4Sopenharmony_ci/* Return true iff we are certain ELF cannot match BUILD_ID of 217da0c48c4Sopenharmony_ci BUILD_ID_LEN bytes. Pass DISK_FILE_HAS_BUILD_ID as false if it is 218da0c48c4Sopenharmony_ci certain ELF does not contain build-id (it is only a performance hit 219da0c48c4Sopenharmony_ci to pass it always as true). */ 220da0c48c4Sopenharmony_ci 221da0c48c4Sopenharmony_cistatic bool 222da0c48c4Sopenharmony_ciinvalid_elf (Elf *elf, bool disk_file_has_build_id, 223da0c48c4Sopenharmony_ci struct elf_build_id *build_id) 224da0c48c4Sopenharmony_ci{ 225da0c48c4Sopenharmony_ci if (! disk_file_has_build_id && build_id->len > 0) 226da0c48c4Sopenharmony_ci { 227da0c48c4Sopenharmony_ci /* Module found in segments with build-id is more reliable 228da0c48c4Sopenharmony_ci than a module found via DT_DEBUG on disk without any 229da0c48c4Sopenharmony_ci build-id. */ 230da0c48c4Sopenharmony_ci return true; 231da0c48c4Sopenharmony_ci } 232da0c48c4Sopenharmony_ci if (disk_file_has_build_id && build_id->len > 0) 233da0c48c4Sopenharmony_ci { 234da0c48c4Sopenharmony_ci const void *elf_build_id; 235da0c48c4Sopenharmony_ci ssize_t elf_build_id_len; 236da0c48c4Sopenharmony_ci 237da0c48c4Sopenharmony_ci /* If there is a build id in the elf file, check it. */ 238da0c48c4Sopenharmony_ci elf_build_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id); 239da0c48c4Sopenharmony_ci if (elf_build_id_len > 0) 240da0c48c4Sopenharmony_ci { 241da0c48c4Sopenharmony_ci if (build_id->len != (size_t) elf_build_id_len 242da0c48c4Sopenharmony_ci || memcmp (build_id->memory, elf_build_id, build_id->len) != 0) 243da0c48c4Sopenharmony_ci return true; 244da0c48c4Sopenharmony_ci } 245da0c48c4Sopenharmony_ci } 246da0c48c4Sopenharmony_ci return false; 247da0c48c4Sopenharmony_ci} 248da0c48c4Sopenharmony_ci 249da0c48c4Sopenharmony_cistatic void 250da0c48c4Sopenharmony_cifinish_portion (struct read_state *read_state, 251da0c48c4Sopenharmony_ci void **data, size_t *data_size) 252da0c48c4Sopenharmony_ci{ 253da0c48c4Sopenharmony_ci if (*data_size != 0 && *data != NULL) 254da0c48c4Sopenharmony_ci (*read_state->memory_callback) (read_state->dwfl, -1, data, data_size, 255da0c48c4Sopenharmony_ci 0, 0, read_state->memory_callback_arg); 256da0c48c4Sopenharmony_ci} 257da0c48c4Sopenharmony_ci 258da0c48c4Sopenharmony_cistatic inline bool 259da0c48c4Sopenharmony_ciread_portion (struct read_state *read_state, 260da0c48c4Sopenharmony_ci void **data, size_t *data_size, 261da0c48c4Sopenharmony_ci GElf_Addr start, size_t segment, 262da0c48c4Sopenharmony_ci GElf_Addr vaddr, size_t filesz) 263da0c48c4Sopenharmony_ci{ 264da0c48c4Sopenharmony_ci /* Check whether we will have to read the segment data, or if it 265da0c48c4Sopenharmony_ci can be returned from the existing buffer. */ 266da0c48c4Sopenharmony_ci if (filesz > *read_state->buffer_available 267da0c48c4Sopenharmony_ci || vaddr - start > *read_state->buffer_available - filesz 268da0c48c4Sopenharmony_ci /* If we're in string mode, then don't consider the buffer we have 269da0c48c4Sopenharmony_ci sufficient unless it contains the terminator of the string. */ 270da0c48c4Sopenharmony_ci || (filesz == 0 && memchr (vaddr - start + *read_state->buffer, '\0', 271da0c48c4Sopenharmony_ci (*read_state->buffer_available 272da0c48c4Sopenharmony_ci - (vaddr - start))) == NULL)) 273da0c48c4Sopenharmony_ci { 274da0c48c4Sopenharmony_ci *data = NULL; 275da0c48c4Sopenharmony_ci *data_size = filesz; 276da0c48c4Sopenharmony_ci return !(*read_state->memory_callback) (read_state->dwfl, 277da0c48c4Sopenharmony_ci addr_segndx (read_state->dwfl, 278da0c48c4Sopenharmony_ci segment, vaddr, 279da0c48c4Sopenharmony_ci false), 280da0c48c4Sopenharmony_ci data, data_size, vaddr, filesz, 281da0c48c4Sopenharmony_ci read_state->memory_callback_arg); 282da0c48c4Sopenharmony_ci } 283da0c48c4Sopenharmony_ci 284da0c48c4Sopenharmony_ci /* We already have this whole note segment from our initial read. */ 285da0c48c4Sopenharmony_ci *data = vaddr - start + (*read_state->buffer); 286da0c48c4Sopenharmony_ci *data_size = 0; 287da0c48c4Sopenharmony_ci return false; 288da0c48c4Sopenharmony_ci} 289da0c48c4Sopenharmony_ci 290da0c48c4Sopenharmony_ciint 291da0c48c4Sopenharmony_cidwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, 292da0c48c4Sopenharmony_ci Dwfl_Memory_Callback *memory_callback, 293da0c48c4Sopenharmony_ci void *memory_callback_arg, 294da0c48c4Sopenharmony_ci Dwfl_Module_Callback *read_eagerly, 295da0c48c4Sopenharmony_ci void *read_eagerly_arg, 296da0c48c4Sopenharmony_ci size_t maxread, 297da0c48c4Sopenharmony_ci const void *note_file, size_t note_file_size, 298da0c48c4Sopenharmony_ci const struct r_debug_info *r_debug_info) 299da0c48c4Sopenharmony_ci{ 300da0c48c4Sopenharmony_ci size_t segment = ndx; 301da0c48c4Sopenharmony_ci struct read_state read_state; 302da0c48c4Sopenharmony_ci 303da0c48c4Sopenharmony_ci if (segment >= dwfl->lookup_elts) 304da0c48c4Sopenharmony_ci segment = dwfl->lookup_elts - 1; 305da0c48c4Sopenharmony_ci 306da0c48c4Sopenharmony_ci while (segment > 0 307da0c48c4Sopenharmony_ci && (dwfl->lookup_segndx[segment] > ndx 308da0c48c4Sopenharmony_ci || dwfl->lookup_segndx[segment] == -1)) 309da0c48c4Sopenharmony_ci --segment; 310da0c48c4Sopenharmony_ci 311da0c48c4Sopenharmony_ci while (dwfl->lookup_segndx[segment] < ndx) 312da0c48c4Sopenharmony_ci if (++segment == dwfl->lookup_elts) 313da0c48c4Sopenharmony_ci return 0; 314da0c48c4Sopenharmony_ci 315da0c48c4Sopenharmony_ci GElf_Addr start = dwfl->lookup_addr[segment]; 316da0c48c4Sopenharmony_ci 317da0c48c4Sopenharmony_ci /* First read in the file header and check its sanity. */ 318da0c48c4Sopenharmony_ci 319da0c48c4Sopenharmony_ci void *buffer = NULL; 320da0c48c4Sopenharmony_ci size_t buffer_available = INITIAL_READ; 321da0c48c4Sopenharmony_ci Elf *elf = NULL; 322da0c48c4Sopenharmony_ci int fd = -1; 323da0c48c4Sopenharmony_ci 324da0c48c4Sopenharmony_ci read_state.dwfl = dwfl; 325da0c48c4Sopenharmony_ci read_state.memory_callback = memory_callback; 326da0c48c4Sopenharmony_ci read_state.memory_callback_arg = memory_callback_arg; 327da0c48c4Sopenharmony_ci read_state.buffer = &buffer; 328da0c48c4Sopenharmony_ci read_state.buffer_available = &buffer_available; 329da0c48c4Sopenharmony_ci 330da0c48c4Sopenharmony_ci /* We might have to reserve some memory for the phdrs. Set to NULL 331da0c48c4Sopenharmony_ci here so we can always safely free it. */ 332da0c48c4Sopenharmony_ci void *phdrsp = NULL; 333da0c48c4Sopenharmony_ci 334da0c48c4Sopenharmony_ci /* Collect the build ID bits here. */ 335da0c48c4Sopenharmony_ci struct elf_build_id build_id; 336da0c48c4Sopenharmony_ci build_id.memory = NULL; 337da0c48c4Sopenharmony_ci build_id.len = 0; 338da0c48c4Sopenharmony_ci build_id.vaddr = 0; 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci if (! (*memory_callback) (dwfl, ndx, &buffer, &buffer_available, 341da0c48c4Sopenharmony_ci start, sizeof (Elf64_Ehdr), memory_callback_arg) 342da0c48c4Sopenharmony_ci || memcmp (buffer, ELFMAG, SELFMAG) != 0) 343da0c48c4Sopenharmony_ci goto out; 344da0c48c4Sopenharmony_ci 345da0c48c4Sopenharmony_ci /* Extract the information we need from the file header. */ 346da0c48c4Sopenharmony_ci const unsigned char *e_ident; 347da0c48c4Sopenharmony_ci unsigned char ei_class; 348da0c48c4Sopenharmony_ci unsigned char ei_data; 349da0c48c4Sopenharmony_ci uint16_t e_type; 350da0c48c4Sopenharmony_ci union 351da0c48c4Sopenharmony_ci { 352da0c48c4Sopenharmony_ci Elf32_Ehdr e32; 353da0c48c4Sopenharmony_ci Elf64_Ehdr e64; 354da0c48c4Sopenharmony_ci } ehdr; 355da0c48c4Sopenharmony_ci GElf_Off phoff; 356da0c48c4Sopenharmony_ci uint_fast16_t phnum; 357da0c48c4Sopenharmony_ci uint_fast16_t phentsize; 358da0c48c4Sopenharmony_ci GElf_Off shdrs_end; 359da0c48c4Sopenharmony_ci Elf_Data xlatefrom = 360da0c48c4Sopenharmony_ci { 361da0c48c4Sopenharmony_ci .d_type = ELF_T_EHDR, 362da0c48c4Sopenharmony_ci .d_buf = (void *) buffer, 363da0c48c4Sopenharmony_ci .d_version = EV_CURRENT, 364da0c48c4Sopenharmony_ci }; 365da0c48c4Sopenharmony_ci Elf_Data xlateto = 366da0c48c4Sopenharmony_ci { 367da0c48c4Sopenharmony_ci .d_type = ELF_T_EHDR, 368da0c48c4Sopenharmony_ci .d_buf = &ehdr, 369da0c48c4Sopenharmony_ci .d_size = sizeof ehdr, 370da0c48c4Sopenharmony_ci .d_version = EV_CURRENT, 371da0c48c4Sopenharmony_ci }; 372da0c48c4Sopenharmony_ci e_ident = ((const unsigned char *) buffer); 373da0c48c4Sopenharmony_ci ei_class = e_ident[EI_CLASS]; 374da0c48c4Sopenharmony_ci ei_data = e_ident[EI_DATA]; 375da0c48c4Sopenharmony_ci /* buffer may be unaligned, in which case xlatetom would not work. 376da0c48c4Sopenharmony_ci xlatetom does work when the in and out d_buf are equal (but not 377da0c48c4Sopenharmony_ci for any other overlap). */ 378da0c48c4Sopenharmony_ci size_t ehdr_align = (ei_class == ELFCLASS32 379da0c48c4Sopenharmony_ci ? __alignof__ (Elf32_Ehdr) 380da0c48c4Sopenharmony_ci : __alignof__ (Elf64_Ehdr)); 381da0c48c4Sopenharmony_ci if (((uintptr_t) buffer & (ehdr_align - 1)) != 0) 382da0c48c4Sopenharmony_ci { 383da0c48c4Sopenharmony_ci memcpy (&ehdr, buffer, 384da0c48c4Sopenharmony_ci (ei_class == ELFCLASS32 385da0c48c4Sopenharmony_ci ? sizeof (Elf32_Ehdr) 386da0c48c4Sopenharmony_ci : sizeof (Elf64_Ehdr))); 387da0c48c4Sopenharmony_ci xlatefrom.d_buf = &ehdr; 388da0c48c4Sopenharmony_ci } 389da0c48c4Sopenharmony_ci switch (ei_class) 390da0c48c4Sopenharmony_ci { 391da0c48c4Sopenharmony_ci case ELFCLASS32: 392da0c48c4Sopenharmony_ci xlatefrom.d_size = sizeof (Elf32_Ehdr); 393da0c48c4Sopenharmony_ci if (elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) 394da0c48c4Sopenharmony_ci goto out; 395da0c48c4Sopenharmony_ci e_type = ehdr.e32.e_type; 396da0c48c4Sopenharmony_ci phoff = ehdr.e32.e_phoff; 397da0c48c4Sopenharmony_ci phnum = ehdr.e32.e_phnum; 398da0c48c4Sopenharmony_ci phentsize = ehdr.e32.e_phentsize; 399da0c48c4Sopenharmony_ci if (phentsize != sizeof (Elf32_Phdr)) 400da0c48c4Sopenharmony_ci goto out; 401da0c48c4Sopenharmony_ci /* NOTE if the number of sections is > 0xff00 then e_shnum 402da0c48c4Sopenharmony_ci is zero and the actual number would come from the section 403da0c48c4Sopenharmony_ci zero sh_size field. We ignore this here because getting shdrs 404da0c48c4Sopenharmony_ci is just a nice bonus (see below in the type == PT_LOAD case 405da0c48c4Sopenharmony_ci where we trim the last segment). */ 406da0c48c4Sopenharmony_ci shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * sizeof (Elf32_Shdr); 407da0c48c4Sopenharmony_ci break; 408da0c48c4Sopenharmony_ci 409da0c48c4Sopenharmony_ci case ELFCLASS64: 410da0c48c4Sopenharmony_ci xlatefrom.d_size = sizeof (Elf64_Ehdr); 411da0c48c4Sopenharmony_ci if (elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) 412da0c48c4Sopenharmony_ci goto out; 413da0c48c4Sopenharmony_ci e_type = ehdr.e64.e_type; 414da0c48c4Sopenharmony_ci phoff = ehdr.e64.e_phoff; 415da0c48c4Sopenharmony_ci phnum = ehdr.e64.e_phnum; 416da0c48c4Sopenharmony_ci phentsize = ehdr.e64.e_phentsize; 417da0c48c4Sopenharmony_ci if (phentsize != sizeof (Elf64_Phdr)) 418da0c48c4Sopenharmony_ci goto out; 419da0c48c4Sopenharmony_ci /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum. */ 420da0c48c4Sopenharmony_ci shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * sizeof (Elf64_Shdr); 421da0c48c4Sopenharmony_ci break; 422da0c48c4Sopenharmony_ci 423da0c48c4Sopenharmony_ci default: 424da0c48c4Sopenharmony_ci goto out; 425da0c48c4Sopenharmony_ci } 426da0c48c4Sopenharmony_ci 427da0c48c4Sopenharmony_ci /* The file header tells where to find the program headers. 428da0c48c4Sopenharmony_ci These are what we need to find the boundaries of the module. 429da0c48c4Sopenharmony_ci Without them, we don't have a module to report. */ 430da0c48c4Sopenharmony_ci 431da0c48c4Sopenharmony_ci if (phnum == 0) 432da0c48c4Sopenharmony_ci goto out; 433da0c48c4Sopenharmony_ci 434da0c48c4Sopenharmony_ci xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; 435da0c48c4Sopenharmony_ci xlatefrom.d_size = phnum * phentsize; 436da0c48c4Sopenharmony_ci 437da0c48c4Sopenharmony_ci void *ph_buffer = NULL; 438da0c48c4Sopenharmony_ci size_t ph_buffer_size = 0; 439da0c48c4Sopenharmony_ci if (read_portion (&read_state, &ph_buffer, &ph_buffer_size, 440da0c48c4Sopenharmony_ci start, segment, 441da0c48c4Sopenharmony_ci start + phoff, xlatefrom.d_size)) 442da0c48c4Sopenharmony_ci goto out; 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci /* ph_buffer_size will be zero if we got everything from the initial 445da0c48c4Sopenharmony_ci buffer, otherwise it will be the size of the new buffer that 446da0c48c4Sopenharmony_ci could be read. */ 447da0c48c4Sopenharmony_ci if (ph_buffer_size != 0) 448da0c48c4Sopenharmony_ci { 449da0c48c4Sopenharmony_ci phnum = ph_buffer_size / phentsize; 450da0c48c4Sopenharmony_ci if (phnum == 0) 451da0c48c4Sopenharmony_ci goto out; 452da0c48c4Sopenharmony_ci xlatefrom.d_size = ph_buffer_size; 453da0c48c4Sopenharmony_ci } 454da0c48c4Sopenharmony_ci 455da0c48c4Sopenharmony_ci xlatefrom.d_buf = ph_buffer; 456da0c48c4Sopenharmony_ci 457da0c48c4Sopenharmony_ci bool class32 = ei_class == ELFCLASS32; 458da0c48c4Sopenharmony_ci size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr); 459da0c48c4Sopenharmony_ci if (unlikely (phnum > SIZE_MAX / phdr_size)) 460da0c48c4Sopenharmony_ci goto out; 461da0c48c4Sopenharmony_ci const size_t phdrsp_bytes = phnum * phdr_size; 462da0c48c4Sopenharmony_ci phdrsp = malloc (phdrsp_bytes); 463da0c48c4Sopenharmony_ci if (unlikely (phdrsp == NULL)) 464da0c48c4Sopenharmony_ci goto out; 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci xlateto.d_buf = phdrsp; 467da0c48c4Sopenharmony_ci xlateto.d_size = phdrsp_bytes; 468da0c48c4Sopenharmony_ci 469da0c48c4Sopenharmony_ci /* ph_ buffer may be unaligned, in which case xlatetom would not work. 470da0c48c4Sopenharmony_ci xlatetom does work when the in and out d_buf are equal (but not 471da0c48c4Sopenharmony_ci for any other overlap). */ 472da0c48c4Sopenharmony_ci size_t phdr_align = (class32 473da0c48c4Sopenharmony_ci ? __alignof__ (Elf32_Phdr) 474da0c48c4Sopenharmony_ci : __alignof__ (Elf64_Phdr)); 475da0c48c4Sopenharmony_ci if (((uintptr_t) ph_buffer & (phdr_align - 1)) != 0) 476da0c48c4Sopenharmony_ci { 477da0c48c4Sopenharmony_ci memcpy (phdrsp, ph_buffer, phdrsp_bytes); 478da0c48c4Sopenharmony_ci xlatefrom.d_buf = phdrsp; 479da0c48c4Sopenharmony_ci } 480da0c48c4Sopenharmony_ci 481da0c48c4Sopenharmony_ci /* Track the bounds of the file visible in memory. */ 482da0c48c4Sopenharmony_ci GElf_Off file_trimmed_end = 0; /* Proper p_vaddr + p_filesz end. */ 483da0c48c4Sopenharmony_ci GElf_Off file_end = 0; /* Rounded up to effective page size. */ 484da0c48c4Sopenharmony_ci GElf_Off contiguous = 0; /* Visible as contiguous file from START. */ 485da0c48c4Sopenharmony_ci GElf_Off total_filesz = 0; /* Total size of data to read. */ 486da0c48c4Sopenharmony_ci 487da0c48c4Sopenharmony_ci /* Collect the bias between START and the containing PT_LOAD's p_vaddr. */ 488da0c48c4Sopenharmony_ci GElf_Addr bias = 0; 489da0c48c4Sopenharmony_ci bool found_bias = false; 490da0c48c4Sopenharmony_ci 491da0c48c4Sopenharmony_ci /* Collect the unbiased bounds of the module here. */ 492da0c48c4Sopenharmony_ci GElf_Addr module_start = -1l; 493da0c48c4Sopenharmony_ci GElf_Addr module_end = 0; 494da0c48c4Sopenharmony_ci GElf_Addr module_address_sync = 0; 495da0c48c4Sopenharmony_ci 496da0c48c4Sopenharmony_ci /* If we see PT_DYNAMIC, record it here. */ 497da0c48c4Sopenharmony_ci GElf_Addr dyn_vaddr = 0; 498da0c48c4Sopenharmony_ci GElf_Xword dyn_filesz = 0; 499da0c48c4Sopenharmony_ci 500da0c48c4Sopenharmony_ci Elf32_Phdr *p32 = phdrsp; 501da0c48c4Sopenharmony_ci Elf64_Phdr *p64 = phdrsp; 502da0c48c4Sopenharmony_ci if ((ei_class == ELFCLASS32 503da0c48c4Sopenharmony_ci && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL) 504da0c48c4Sopenharmony_ci || (ei_class == ELFCLASS64 505da0c48c4Sopenharmony_ci && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) == NULL)) 506da0c48c4Sopenharmony_ci { 507da0c48c4Sopenharmony_ci found_bias = false; /* Trigger error check */ 508da0c48c4Sopenharmony_ci } 509da0c48c4Sopenharmony_ci else 510da0c48c4Sopenharmony_ci { 511da0c48c4Sopenharmony_ci /* Consider each of the program headers we've read from the image. */ 512da0c48c4Sopenharmony_ci for (uint_fast16_t i = 0; i < phnum; ++i) 513da0c48c4Sopenharmony_ci { 514da0c48c4Sopenharmony_ci bool is32 = (ei_class == ELFCLASS32); 515da0c48c4Sopenharmony_ci GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type; 516da0c48c4Sopenharmony_ci GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr; 517da0c48c4Sopenharmony_ci GElf_Xword memsz = is32 ? p32[i].p_memsz : p64[i].p_memsz; 518da0c48c4Sopenharmony_ci GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset; 519da0c48c4Sopenharmony_ci GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz; 520da0c48c4Sopenharmony_ci GElf_Xword align = is32 ? p32[i].p_align : p64[i].p_align; 521da0c48c4Sopenharmony_ci 522da0c48c4Sopenharmony_ci if (type == PT_DYNAMIC) 523da0c48c4Sopenharmony_ci { 524da0c48c4Sopenharmony_ci dyn_vaddr = vaddr; 525da0c48c4Sopenharmony_ci dyn_filesz = filesz; 526da0c48c4Sopenharmony_ci } 527da0c48c4Sopenharmony_ci else if (type == PT_NOTE) 528da0c48c4Sopenharmony_ci { 529da0c48c4Sopenharmony_ci /* If we have already seen a build ID, we don't care any more. */ 530da0c48c4Sopenharmony_ci if (build_id.memory != NULL || filesz == 0) 531da0c48c4Sopenharmony_ci continue; /* Next header */ 532da0c48c4Sopenharmony_ci 533da0c48c4Sopenharmony_ci /* We calculate from the p_offset of the note segment, 534da0c48c4Sopenharmony_ci because we don't yet know the bias for its p_vaddr. */ 535da0c48c4Sopenharmony_ci const GElf_Addr note_vaddr = start + offset; 536da0c48c4Sopenharmony_ci void *data; 537da0c48c4Sopenharmony_ci size_t data_size; 538da0c48c4Sopenharmony_ci if (read_portion (&read_state, &data, &data_size, 539da0c48c4Sopenharmony_ci start, segment, note_vaddr, filesz)) 540da0c48c4Sopenharmony_ci continue; /* Next header */ 541da0c48c4Sopenharmony_ci 542da0c48c4Sopenharmony_ci /* data_size will be zero if we got everything from the initial 543da0c48c4Sopenharmony_ci buffer, otherwise it will be the size of the new buffer that 544da0c48c4Sopenharmony_ci could be read. */ 545da0c48c4Sopenharmony_ci if (data_size != 0) 546da0c48c4Sopenharmony_ci filesz = data_size; 547da0c48c4Sopenharmony_ci 548da0c48c4Sopenharmony_ci if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr)) 549da0c48c4Sopenharmony_ci continue; 550da0c48c4Sopenharmony_ci 551da0c48c4Sopenharmony_ci assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); 552da0c48c4Sopenharmony_ci 553da0c48c4Sopenharmony_ci void *notes; 554da0c48c4Sopenharmony_ci if (ei_data == MY_ELFDATA 555da0c48c4Sopenharmony_ci && (uintptr_t) data == (align == 8 556da0c48c4Sopenharmony_ci ? NOTE_ALIGN8 ((uintptr_t) data) 557da0c48c4Sopenharmony_ci : NOTE_ALIGN4 ((uintptr_t) data))) 558da0c48c4Sopenharmony_ci notes = data; 559da0c48c4Sopenharmony_ci else 560da0c48c4Sopenharmony_ci { 561da0c48c4Sopenharmony_ci const unsigned int xencoding = ehdr.e32.e_ident[EI_DATA]; 562da0c48c4Sopenharmony_ci 563da0c48c4Sopenharmony_ci if (filesz > SIZE_MAX / sizeof (Elf32_Nhdr)) 564da0c48c4Sopenharmony_ci continue; 565da0c48c4Sopenharmony_ci notes = malloc (filesz); 566da0c48c4Sopenharmony_ci if (unlikely (notes == NULL)) 567da0c48c4Sopenharmony_ci continue; /* Next header */ 568da0c48c4Sopenharmony_ci xlatefrom.d_type = xlateto.d_type = (align == 8 569da0c48c4Sopenharmony_ci ? ELF_T_NHDR8 570da0c48c4Sopenharmony_ci : ELF_T_NHDR); 571da0c48c4Sopenharmony_ci xlatefrom.d_buf = (void *) data; 572da0c48c4Sopenharmony_ci xlatefrom.d_size = filesz; 573da0c48c4Sopenharmony_ci xlateto.d_buf = notes; 574da0c48c4Sopenharmony_ci xlateto.d_size = filesz; 575da0c48c4Sopenharmony_ci 576da0c48c4Sopenharmony_ci /* data may be unaligned, in which case xlatetom would not work. 577da0c48c4Sopenharmony_ci xlatetom does work when the in and out d_buf are equal (but not 578da0c48c4Sopenharmony_ci for any other overlap). */ 579da0c48c4Sopenharmony_ci if ((uintptr_t) data != (align == 8 580da0c48c4Sopenharmony_ci ? NOTE_ALIGN8 ((uintptr_t) data) 581da0c48c4Sopenharmony_ci : NOTE_ALIGN4 ((uintptr_t) data))) 582da0c48c4Sopenharmony_ci { 583da0c48c4Sopenharmony_ci memcpy (notes, data, filesz); 584da0c48c4Sopenharmony_ci xlatefrom.d_buf = notes; 585da0c48c4Sopenharmony_ci } 586da0c48c4Sopenharmony_ci 587da0c48c4Sopenharmony_ci if (elf32_xlatetom (&xlateto, &xlatefrom, xencoding) == NULL) 588da0c48c4Sopenharmony_ci { 589da0c48c4Sopenharmony_ci free (notes); 590da0c48c4Sopenharmony_ci finish_portion (&read_state, &data, &data_size); 591da0c48c4Sopenharmony_ci continue; 592da0c48c4Sopenharmony_ci } 593da0c48c4Sopenharmony_ci } 594da0c48c4Sopenharmony_ci 595da0c48c4Sopenharmony_ci const GElf_Nhdr *nh = notes; 596da0c48c4Sopenharmony_ci size_t len = 0; 597da0c48c4Sopenharmony_ci while (filesz - len > sizeof (*nh)) 598da0c48c4Sopenharmony_ci { 599da0c48c4Sopenharmony_ci len += sizeof (*nh); 600da0c48c4Sopenharmony_ci 601da0c48c4Sopenharmony_ci size_t namesz = nh->n_namesz; 602da0c48c4Sopenharmony_ci namesz = align == 8 ? NOTE_ALIGN8 (namesz) : NOTE_ALIGN4 (namesz); 603da0c48c4Sopenharmony_ci if (namesz > filesz - len || len + namesz < namesz) 604da0c48c4Sopenharmony_ci break; 605da0c48c4Sopenharmony_ci 606da0c48c4Sopenharmony_ci void *note_name = notes + len; 607da0c48c4Sopenharmony_ci len += namesz; 608da0c48c4Sopenharmony_ci 609da0c48c4Sopenharmony_ci size_t descsz = nh->n_descsz; 610da0c48c4Sopenharmony_ci descsz = align == 8 ? NOTE_ALIGN8 (descsz) : NOTE_ALIGN4 (descsz); 611da0c48c4Sopenharmony_ci if (descsz > filesz - len || len + descsz < descsz) 612da0c48c4Sopenharmony_ci break; 613da0c48c4Sopenharmony_ci 614da0c48c4Sopenharmony_ci void *note_desc = notes + len; 615da0c48c4Sopenharmony_ci len += descsz; 616da0c48c4Sopenharmony_ci 617da0c48c4Sopenharmony_ci /* We don't handle very short or really large build-ids. We need at 618da0c48c4Sopenharmony_ci at least 3 and allow for up to 64 (normally ids are 20 long). */ 619da0c48c4Sopenharmony_ci#define MIN_BUILD_ID_BYTES 3 620da0c48c4Sopenharmony_ci#define MAX_BUILD_ID_BYTES 64 621da0c48c4Sopenharmony_ci if (nh->n_type == NT_GNU_BUILD_ID 622da0c48c4Sopenharmony_ci && nh->n_descsz >= MIN_BUILD_ID_BYTES 623da0c48c4Sopenharmony_ci && nh->n_descsz <= MAX_BUILD_ID_BYTES 624da0c48c4Sopenharmony_ci && nh->n_namesz == sizeof "GNU" 625da0c48c4Sopenharmony_ci && !memcmp (note_name, "GNU", sizeof "GNU")) 626da0c48c4Sopenharmony_ci { 627da0c48c4Sopenharmony_ci build_id.vaddr = (note_desc 628da0c48c4Sopenharmony_ci - (const void *) notes 629da0c48c4Sopenharmony_ci + note_vaddr); 630da0c48c4Sopenharmony_ci build_id.len = nh->n_descsz; 631da0c48c4Sopenharmony_ci build_id.memory = malloc (build_id.len); 632da0c48c4Sopenharmony_ci if (likely (build_id.memory != NULL)) 633da0c48c4Sopenharmony_ci memcpy (build_id.memory, note_desc, build_id.len); 634da0c48c4Sopenharmony_ci break; 635da0c48c4Sopenharmony_ci } 636da0c48c4Sopenharmony_ci 637da0c48c4Sopenharmony_ci nh = (void *) notes + len; 638da0c48c4Sopenharmony_ci } 639da0c48c4Sopenharmony_ci 640da0c48c4Sopenharmony_ci if (notes != data) 641da0c48c4Sopenharmony_ci free (notes); 642da0c48c4Sopenharmony_ci finish_portion (&read_state, &data, &data_size); 643da0c48c4Sopenharmony_ci } 644da0c48c4Sopenharmony_ci else if (type == PT_LOAD) 645da0c48c4Sopenharmony_ci { 646da0c48c4Sopenharmony_ci align = (dwfl->segment_align > 1 647da0c48c4Sopenharmony_ci ? dwfl->segment_align : (align ?: 1)); 648da0c48c4Sopenharmony_ci 649da0c48c4Sopenharmony_ci GElf_Addr vaddr_end = (vaddr + memsz + align - 1) & -align; 650da0c48c4Sopenharmony_ci GElf_Addr filesz_vaddr = (filesz < memsz 651da0c48c4Sopenharmony_ci ? vaddr + filesz : vaddr_end); 652da0c48c4Sopenharmony_ci GElf_Off filesz_offset = filesz_vaddr - vaddr + offset; 653da0c48c4Sopenharmony_ci 654da0c48c4Sopenharmony_ci if (file_trimmed_end < offset + filesz) 655da0c48c4Sopenharmony_ci { 656da0c48c4Sopenharmony_ci file_trimmed_end = offset + filesz; 657da0c48c4Sopenharmony_ci 658da0c48c4Sopenharmony_ci /* Trim the last segment so we don't bother with zeros 659da0c48c4Sopenharmony_ci in the last page that are off the end of the file. 660da0c48c4Sopenharmony_ci However, if the extra bit in that page includes the 661da0c48c4Sopenharmony_ci section headers, keep them. */ 662da0c48c4Sopenharmony_ci if (shdrs_end <= filesz_offset 663da0c48c4Sopenharmony_ci && shdrs_end > file_trimmed_end) 664da0c48c4Sopenharmony_ci { 665da0c48c4Sopenharmony_ci filesz += shdrs_end - file_trimmed_end; 666da0c48c4Sopenharmony_ci file_trimmed_end = shdrs_end; 667da0c48c4Sopenharmony_ci } 668da0c48c4Sopenharmony_ci } 669da0c48c4Sopenharmony_ci 670da0c48c4Sopenharmony_ci total_filesz += filesz; 671da0c48c4Sopenharmony_ci 672da0c48c4Sopenharmony_ci if (file_end < filesz_offset) 673da0c48c4Sopenharmony_ci { 674da0c48c4Sopenharmony_ci file_end = filesz_offset; 675da0c48c4Sopenharmony_ci if (filesz_vaddr - start == filesz_offset) 676da0c48c4Sopenharmony_ci contiguous = file_end; 677da0c48c4Sopenharmony_ci } 678da0c48c4Sopenharmony_ci 679da0c48c4Sopenharmony_ci if (!found_bias && (offset & -align) == 0 680da0c48c4Sopenharmony_ci && likely (filesz_offset >= phoff + phnum * phentsize)) 681da0c48c4Sopenharmony_ci { 682da0c48c4Sopenharmony_ci bias = start - vaddr; 683da0c48c4Sopenharmony_ci found_bias = true; 684da0c48c4Sopenharmony_ci } 685da0c48c4Sopenharmony_ci 686da0c48c4Sopenharmony_ci if ((vaddr & -align) < module_start) 687da0c48c4Sopenharmony_ci { 688da0c48c4Sopenharmony_ci module_start = vaddr & -align; 689da0c48c4Sopenharmony_ci module_address_sync = vaddr + memsz; 690da0c48c4Sopenharmony_ci } 691da0c48c4Sopenharmony_ci 692da0c48c4Sopenharmony_ci if (module_end < vaddr_end) 693da0c48c4Sopenharmony_ci module_end = vaddr_end; 694da0c48c4Sopenharmony_ci } 695da0c48c4Sopenharmony_ci } 696da0c48c4Sopenharmony_ci } 697da0c48c4Sopenharmony_ci 698da0c48c4Sopenharmony_ci finish_portion (&read_state, &ph_buffer, &ph_buffer_size); 699da0c48c4Sopenharmony_ci 700da0c48c4Sopenharmony_ci /* We must have seen the segment covering offset 0, or else the ELF 701da0c48c4Sopenharmony_ci header we read at START was not produced by these program headers. */ 702da0c48c4Sopenharmony_ci if (unlikely (!found_bias)) 703da0c48c4Sopenharmony_ci goto out; 704da0c48c4Sopenharmony_ci 705da0c48c4Sopenharmony_ci /* Now we know enough to report a module for sure: its bounds. */ 706da0c48c4Sopenharmony_ci module_start += bias; 707da0c48c4Sopenharmony_ci module_end += bias; 708da0c48c4Sopenharmony_ci 709da0c48c4Sopenharmony_ci dyn_vaddr += bias; 710da0c48c4Sopenharmony_ci 711da0c48c4Sopenharmony_ci /* NAME found from link map has precedence over DT_SONAME possibly read 712da0c48c4Sopenharmony_ci below. */ 713da0c48c4Sopenharmony_ci bool name_is_final = false; 714da0c48c4Sopenharmony_ci 715da0c48c4Sopenharmony_ci /* Try to match up DYN_VADDR against L_LD as found in link map. 716da0c48c4Sopenharmony_ci Segments sniffing may guess invalid address as the first read-only memory 717da0c48c4Sopenharmony_ci mapping may not be dumped to the core file (if ELF headers are not dumped) 718da0c48c4Sopenharmony_ci and the ELF header is dumped first with the read/write mapping of the same 719da0c48c4Sopenharmony_ci file at higher addresses. */ 720da0c48c4Sopenharmony_ci if (r_debug_info != NULL) 721da0c48c4Sopenharmony_ci for (const struct r_debug_info_module *module = r_debug_info->module; 722da0c48c4Sopenharmony_ci module != NULL; module = module->next) 723da0c48c4Sopenharmony_ci if (module_start <= module->l_ld && module->l_ld < module_end) 724da0c48c4Sopenharmony_ci { 725da0c48c4Sopenharmony_ci /* L_LD read from link map must be right while DYN_VADDR is unsafe. 726da0c48c4Sopenharmony_ci Therefore subtract DYN_VADDR and add L_LD to get a possibly 727da0c48c4Sopenharmony_ci corrective displacement for all addresses computed so far. */ 728da0c48c4Sopenharmony_ci GElf_Addr fixup = module->l_ld - dyn_vaddr; 729da0c48c4Sopenharmony_ci if ((fixup & (dwfl->segment_align - 1)) == 0 730da0c48c4Sopenharmony_ci && module_start + fixup <= module->l_ld 731da0c48c4Sopenharmony_ci && module->l_ld < module_end + fixup) 732da0c48c4Sopenharmony_ci { 733da0c48c4Sopenharmony_ci module_start += fixup; 734da0c48c4Sopenharmony_ci module_end += fixup; 735da0c48c4Sopenharmony_ci dyn_vaddr += fixup; 736da0c48c4Sopenharmony_ci bias += fixup; 737da0c48c4Sopenharmony_ci if (module->name[0] != '\0') 738da0c48c4Sopenharmony_ci { 739da0c48c4Sopenharmony_ci name = basename (module->name); 740da0c48c4Sopenharmony_ci name_is_final = true; 741da0c48c4Sopenharmony_ci } 742da0c48c4Sopenharmony_ci break; 743da0c48c4Sopenharmony_ci } 744da0c48c4Sopenharmony_ci } 745da0c48c4Sopenharmony_ci 746da0c48c4Sopenharmony_ci if (r_debug_info != NULL) 747da0c48c4Sopenharmony_ci { 748da0c48c4Sopenharmony_ci bool skip_this_module = false; 749da0c48c4Sopenharmony_ci for (struct r_debug_info_module *module = r_debug_info->module; 750da0c48c4Sopenharmony_ci module != NULL; module = module->next) 751da0c48c4Sopenharmony_ci if ((module_end > module->start && module_start < module->end) 752da0c48c4Sopenharmony_ci || dyn_vaddr == module->l_ld) 753da0c48c4Sopenharmony_ci { 754da0c48c4Sopenharmony_ci if (module->elf != NULL 755da0c48c4Sopenharmony_ci && invalid_elf (module->elf, module->disk_file_has_build_id, 756da0c48c4Sopenharmony_ci &build_id)) 757da0c48c4Sopenharmony_ci { 758da0c48c4Sopenharmony_ci elf_end (module->elf); 759da0c48c4Sopenharmony_ci close (module->fd); 760da0c48c4Sopenharmony_ci module->elf = NULL; 761da0c48c4Sopenharmony_ci module->fd = -1; 762da0c48c4Sopenharmony_ci } 763da0c48c4Sopenharmony_ci if (module->elf != NULL) 764da0c48c4Sopenharmony_ci { 765da0c48c4Sopenharmony_ci /* Ignore this found module if it would conflict in address 766da0c48c4Sopenharmony_ci space with any already existing module of DWFL. */ 767da0c48c4Sopenharmony_ci skip_this_module = true; 768da0c48c4Sopenharmony_ci } 769da0c48c4Sopenharmony_ci } 770da0c48c4Sopenharmony_ci if (skip_this_module) 771da0c48c4Sopenharmony_ci goto out; 772da0c48c4Sopenharmony_ci } 773da0c48c4Sopenharmony_ci 774da0c48c4Sopenharmony_ci const char *file_note_name = handle_file_note (module_start, module_end, 775da0c48c4Sopenharmony_ci ei_class, ei_data, 776da0c48c4Sopenharmony_ci note_file, note_file_size); 777da0c48c4Sopenharmony_ci if (file_note_name) 778da0c48c4Sopenharmony_ci { 779da0c48c4Sopenharmony_ci name = file_note_name; 780da0c48c4Sopenharmony_ci name_is_final = true; 781da0c48c4Sopenharmony_ci bool invalid = false; 782da0c48c4Sopenharmony_ci fd = open (name, O_RDONLY); 783da0c48c4Sopenharmony_ci if (fd >= 0) 784da0c48c4Sopenharmony_ci { 785da0c48c4Sopenharmony_ci Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false); 786da0c48c4Sopenharmony_ci if (error == DWFL_E_NOERROR) 787da0c48c4Sopenharmony_ci invalid = invalid_elf (elf, true /* disk_file_has_build_id */, 788da0c48c4Sopenharmony_ci &build_id); 789da0c48c4Sopenharmony_ci } 790da0c48c4Sopenharmony_ci if (invalid) 791da0c48c4Sopenharmony_ci { 792da0c48c4Sopenharmony_ci /* The file was there, but the build_id didn't match. We 793da0c48c4Sopenharmony_ci still want to report the module, but need to get the ELF 794da0c48c4Sopenharmony_ci some other way if possible. */ 795da0c48c4Sopenharmony_ci close (fd); 796da0c48c4Sopenharmony_ci fd = -1; 797da0c48c4Sopenharmony_ci elf_end (elf); 798da0c48c4Sopenharmony_ci elf = NULL; 799da0c48c4Sopenharmony_ci } 800da0c48c4Sopenharmony_ci } 801da0c48c4Sopenharmony_ci 802da0c48c4Sopenharmony_ci /* Our return value now says to skip the segments contained 803da0c48c4Sopenharmony_ci within the module. */ 804da0c48c4Sopenharmony_ci ndx = addr_segndx (dwfl, segment, module_end, true); 805da0c48c4Sopenharmony_ci 806da0c48c4Sopenharmony_ci /* Examine its .dynamic section to get more interesting details. 807da0c48c4Sopenharmony_ci If it has DT_SONAME, we'll use that as the module name. 808da0c48c4Sopenharmony_ci If it has a DT_DEBUG, then it's actually a PIE rather than a DSO. 809da0c48c4Sopenharmony_ci We need its DT_STRTAB and DT_STRSZ to decipher DT_SONAME, 810da0c48c4Sopenharmony_ci and they also tell us the essential portion of the file 811da0c48c4Sopenharmony_ci for fetching symbols. */ 812da0c48c4Sopenharmony_ci GElf_Addr soname_stroff = 0; 813da0c48c4Sopenharmony_ci GElf_Addr dynstr_vaddr = 0; 814da0c48c4Sopenharmony_ci GElf_Xword dynstrsz = 0; 815da0c48c4Sopenharmony_ci bool execlike = false; 816da0c48c4Sopenharmony_ci const size_t dyn_entsize = (ei_class == ELFCLASS32 817da0c48c4Sopenharmony_ci ? sizeof (Elf32_Dyn) : sizeof (Elf64_Dyn)); 818da0c48c4Sopenharmony_ci void *dyn_data = NULL; 819da0c48c4Sopenharmony_ci size_t dyn_data_size = 0; 820da0c48c4Sopenharmony_ci if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0 821da0c48c4Sopenharmony_ci && ! read_portion (&read_state, &dyn_data, &dyn_data_size, 822da0c48c4Sopenharmony_ci start, segment, dyn_vaddr, dyn_filesz)) 823da0c48c4Sopenharmony_ci { 824da0c48c4Sopenharmony_ci /* dyn_data_size will be zero if we got everything from the initial 825da0c48c4Sopenharmony_ci buffer, otherwise it will be the size of the new buffer that 826da0c48c4Sopenharmony_ci could be read. */ 827da0c48c4Sopenharmony_ci if (dyn_data_size != 0) 828da0c48c4Sopenharmony_ci dyn_filesz = dyn_data_size; 829da0c48c4Sopenharmony_ci 830da0c48c4Sopenharmony_ci if ((dyn_filesz / dyn_entsize) == 0 831da0c48c4Sopenharmony_ci || dyn_filesz > (SIZE_MAX / dyn_entsize)) 832da0c48c4Sopenharmony_ci goto out; 833da0c48c4Sopenharmony_ci void *dyns = malloc (dyn_filesz); 834da0c48c4Sopenharmony_ci Elf32_Dyn *d32 = dyns; 835da0c48c4Sopenharmony_ci Elf64_Dyn *d64 = dyns; 836da0c48c4Sopenharmony_ci if (unlikely (dyns == NULL)) 837da0c48c4Sopenharmony_ci goto out; 838da0c48c4Sopenharmony_ci 839da0c48c4Sopenharmony_ci xlatefrom.d_type = xlateto.d_type = ELF_T_DYN; 840da0c48c4Sopenharmony_ci xlatefrom.d_buf = (void *) dyn_data; 841da0c48c4Sopenharmony_ci xlatefrom.d_size = dyn_filesz; 842da0c48c4Sopenharmony_ci xlateto.d_buf = dyns; 843da0c48c4Sopenharmony_ci xlateto.d_size = dyn_filesz; 844da0c48c4Sopenharmony_ci 845da0c48c4Sopenharmony_ci /* dyn_data may be unaligned, in which case xlatetom would not work. 846da0c48c4Sopenharmony_ci xlatetom does work when the in and out d_buf are equal (but not 847da0c48c4Sopenharmony_ci for any other overlap). */ 848da0c48c4Sopenharmony_ci bool is32 = (ei_class == ELFCLASS32); 849da0c48c4Sopenharmony_ci size_t dyn_align = (is32 850da0c48c4Sopenharmony_ci ? __alignof__ (Elf32_Dyn) 851da0c48c4Sopenharmony_ci : __alignof__ (Elf64_Dyn)); 852da0c48c4Sopenharmony_ci if (((uintptr_t) dyn_data & (dyn_align - 1)) != 0) 853da0c48c4Sopenharmony_ci { 854da0c48c4Sopenharmony_ci memcpy (dyns, dyn_data, dyn_filesz); 855da0c48c4Sopenharmony_ci xlatefrom.d_buf = dyns; 856da0c48c4Sopenharmony_ci } 857da0c48c4Sopenharmony_ci 858da0c48c4Sopenharmony_ci if ((is32 && elf32_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL) 859da0c48c4Sopenharmony_ci || (!is32 && elf64_xlatetom (&xlateto, &xlatefrom, ei_data) != NULL)) 860da0c48c4Sopenharmony_ci { 861da0c48c4Sopenharmony_ci size_t n = (is32 862da0c48c4Sopenharmony_ci ? (dyn_filesz / sizeof (Elf32_Dyn)) 863da0c48c4Sopenharmony_ci : (dyn_filesz / sizeof (Elf64_Dyn))); 864da0c48c4Sopenharmony_ci for (size_t i = 0; i < n; ++i) 865da0c48c4Sopenharmony_ci { 866da0c48c4Sopenharmony_ci GElf_Sxword tag = is32 ? d32[i].d_tag : d64[i].d_tag; 867da0c48c4Sopenharmony_ci GElf_Xword val = is32 ? d32[i].d_un.d_val : d64[i].d_un.d_val; 868da0c48c4Sopenharmony_ci 869da0c48c4Sopenharmony_ci if (tag == DT_DEBUG) 870da0c48c4Sopenharmony_ci execlike = true; 871da0c48c4Sopenharmony_ci else if (tag == DT_SONAME) 872da0c48c4Sopenharmony_ci soname_stroff = val; 873da0c48c4Sopenharmony_ci else if (tag == DT_STRTAB) 874da0c48c4Sopenharmony_ci dynstr_vaddr = val; 875da0c48c4Sopenharmony_ci else if (tag == DT_STRSZ) 876da0c48c4Sopenharmony_ci dynstrsz = val; 877da0c48c4Sopenharmony_ci else 878da0c48c4Sopenharmony_ci continue; 879da0c48c4Sopenharmony_ci 880da0c48c4Sopenharmony_ci if (soname_stroff != 0 && dynstr_vaddr != 0 && dynstrsz != 0) 881da0c48c4Sopenharmony_ci break; 882da0c48c4Sopenharmony_ci } 883da0c48c4Sopenharmony_ci } 884da0c48c4Sopenharmony_ci free (dyns); 885da0c48c4Sopenharmony_ci } 886da0c48c4Sopenharmony_ci finish_portion (&read_state, &dyn_data, &dyn_data_size); 887da0c48c4Sopenharmony_ci 888da0c48c4Sopenharmony_ci /* We'll use the name passed in or a stupid default if not DT_SONAME. */ 889da0c48c4Sopenharmony_ci if (name == NULL) 890da0c48c4Sopenharmony_ci name = e_type == ET_EXEC ? "[exe]" : execlike ? "[pie]" : "[dso]"; 891da0c48c4Sopenharmony_ci 892da0c48c4Sopenharmony_ci void *soname = NULL; 893da0c48c4Sopenharmony_ci size_t soname_size = 0; 894da0c48c4Sopenharmony_ci if (! name_is_final && dynstrsz != 0 && dynstr_vaddr != 0) 895da0c48c4Sopenharmony_ci { 896da0c48c4Sopenharmony_ci /* We know the bounds of the .dynstr section. 897da0c48c4Sopenharmony_ci 898da0c48c4Sopenharmony_ci The DYNSTR_VADDR pointer comes from the .dynamic section 899da0c48c4Sopenharmony_ci (DT_STRTAB, detected above). Ordinarily the dynamic linker 900da0c48c4Sopenharmony_ci will have adjusted this pointer in place so it's now an 901da0c48c4Sopenharmony_ci absolute address. But sometimes .dynamic is read-only (in 902da0c48c4Sopenharmony_ci vDSOs and odd architectures), and sometimes the adjustment 903da0c48c4Sopenharmony_ci just hasn't happened yet in the memory image we looked at. 904da0c48c4Sopenharmony_ci So treat DYNSTR_VADDR as an absolute address if it falls 905da0c48c4Sopenharmony_ci within the module bounds, or try applying the phdr bias 906da0c48c4Sopenharmony_ci when that adjusts it to fall within the module bounds. */ 907da0c48c4Sopenharmony_ci 908da0c48c4Sopenharmony_ci if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end) 909da0c48c4Sopenharmony_ci && dynstr_vaddr + bias >= module_start 910da0c48c4Sopenharmony_ci && dynstr_vaddr + bias < module_end) 911da0c48c4Sopenharmony_ci dynstr_vaddr += bias; 912da0c48c4Sopenharmony_ci 913da0c48c4Sopenharmony_ci if (unlikely (dynstr_vaddr + dynstrsz > module_end)) 914da0c48c4Sopenharmony_ci dynstrsz = 0; 915da0c48c4Sopenharmony_ci 916da0c48c4Sopenharmony_ci /* Try to get the DT_SONAME string. */ 917da0c48c4Sopenharmony_ci if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz 918da0c48c4Sopenharmony_ci && ! read_portion (&read_state, &soname, &soname_size, 919da0c48c4Sopenharmony_ci start, segment, 920da0c48c4Sopenharmony_ci dynstr_vaddr + soname_stroff, 0)) 921da0c48c4Sopenharmony_ci name = soname; 922da0c48c4Sopenharmony_ci } 923da0c48c4Sopenharmony_ci 924da0c48c4Sopenharmony_ci /* Now that we have chosen the module's name and bounds, report it. 925da0c48c4Sopenharmony_ci If we found a build ID, report that too. */ 926da0c48c4Sopenharmony_ci 927da0c48c4Sopenharmony_ci Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, name, 928da0c48c4Sopenharmony_ci module_start, module_end); 929da0c48c4Sopenharmony_ci 930da0c48c4Sopenharmony_ci // !execlike && ET_EXEC is PIE. 931da0c48c4Sopenharmony_ci // execlike && !ET_EXEC is a static executable. 932da0c48c4Sopenharmony_ci if (mod != NULL && (execlike || ehdr.e32.e_type == ET_EXEC)) 933da0c48c4Sopenharmony_ci mod->is_executable = true; 934da0c48c4Sopenharmony_ci 935da0c48c4Sopenharmony_ci if (likely (mod != NULL) && build_id.memory != NULL 936da0c48c4Sopenharmony_ci && unlikely (INTUSE(dwfl_module_report_build_id) (mod, 937da0c48c4Sopenharmony_ci build_id.memory, 938da0c48c4Sopenharmony_ci build_id.len, 939da0c48c4Sopenharmony_ci build_id.vaddr))) 940da0c48c4Sopenharmony_ci { 941da0c48c4Sopenharmony_ci mod->gc = true; 942da0c48c4Sopenharmony_ci mod = NULL; 943da0c48c4Sopenharmony_ci } 944da0c48c4Sopenharmony_ci 945da0c48c4Sopenharmony_ci /* At this point we do not need BUILD_ID or NAME any more. 946da0c48c4Sopenharmony_ci They have been copied. */ 947da0c48c4Sopenharmony_ci free (build_id.memory); 948da0c48c4Sopenharmony_ci build_id.memory = NULL; 949da0c48c4Sopenharmony_ci finish_portion (&read_state, &soname, &soname_size); 950da0c48c4Sopenharmony_ci 951da0c48c4Sopenharmony_ci if (unlikely (mod == NULL)) 952da0c48c4Sopenharmony_ci { 953da0c48c4Sopenharmony_ci ndx = -1; 954da0c48c4Sopenharmony_ci goto out; 955da0c48c4Sopenharmony_ci } 956da0c48c4Sopenharmony_ci 957da0c48c4Sopenharmony_ci /* We have reported the module. Now let the caller decide whether we 958da0c48c4Sopenharmony_ci should read the whole thing in right now. */ 959da0c48c4Sopenharmony_ci 960da0c48c4Sopenharmony_ci const GElf_Off cost = (contiguous < file_trimmed_end ? total_filesz 961da0c48c4Sopenharmony_ci : buffer_available >= contiguous ? 0 962da0c48c4Sopenharmony_ci : contiguous - buffer_available); 963da0c48c4Sopenharmony_ci const GElf_Off worthwhile = ((dynstr_vaddr == 0 || dynstrsz == 0) ? 0 964da0c48c4Sopenharmony_ci : dynstr_vaddr + dynstrsz - start); 965da0c48c4Sopenharmony_ci const GElf_Off whole = MAX (file_trimmed_end, shdrs_end); 966da0c48c4Sopenharmony_ci 967da0c48c4Sopenharmony_ci if (elf == NULL 968da0c48c4Sopenharmony_ci && (*read_eagerly) (MODCB_ARGS (mod), &buffer, &buffer_available, 969da0c48c4Sopenharmony_ci cost, worthwhile, whole, contiguous, 970da0c48c4Sopenharmony_ci read_eagerly_arg, &elf) 971da0c48c4Sopenharmony_ci && elf == NULL) 972da0c48c4Sopenharmony_ci { 973da0c48c4Sopenharmony_ci /* The caller wants to read the whole file in right now, but hasn't 974da0c48c4Sopenharmony_ci done it for us. Fill in a local image of the virtual file. */ 975da0c48c4Sopenharmony_ci 976da0c48c4Sopenharmony_ci if (file_trimmed_end > maxread) 977da0c48c4Sopenharmony_ci file_trimmed_end = maxread; 978da0c48c4Sopenharmony_ci 979da0c48c4Sopenharmony_ci void *contents = calloc (1, file_trimmed_end); 980da0c48c4Sopenharmony_ci if (unlikely (contents == NULL)) 981da0c48c4Sopenharmony_ci goto out; 982da0c48c4Sopenharmony_ci 983da0c48c4Sopenharmony_ci if (contiguous < file_trimmed_end) 984da0c48c4Sopenharmony_ci { 985da0c48c4Sopenharmony_ci /* We can't use the memory image verbatim as the file image. 986da0c48c4Sopenharmony_ci So we'll be reading into a local image of the virtual file. */ 987da0c48c4Sopenharmony_ci for (uint_fast16_t i = 0; i < phnum; ++i) 988da0c48c4Sopenharmony_ci { 989da0c48c4Sopenharmony_ci bool is32 = (ei_class == ELFCLASS32); 990da0c48c4Sopenharmony_ci GElf_Word type = is32 ? p32[i].p_type : p64[i].p_type; 991da0c48c4Sopenharmony_ci 992da0c48c4Sopenharmony_ci if (type != PT_LOAD) 993da0c48c4Sopenharmony_ci continue; 994da0c48c4Sopenharmony_ci 995da0c48c4Sopenharmony_ci GElf_Addr vaddr = is32 ? p32[i].p_vaddr : p64[i].p_vaddr; 996da0c48c4Sopenharmony_ci GElf_Off offset = is32 ? p32[i].p_offset : p64[i].p_offset; 997da0c48c4Sopenharmony_ci GElf_Xword filesz = is32 ? p32[i].p_filesz : p64[i].p_filesz; 998da0c48c4Sopenharmony_ci 999da0c48c4Sopenharmony_ci /* Don't try to read beyond the actual end of file. */ 1000da0c48c4Sopenharmony_ci if (offset >= file_trimmed_end) 1001da0c48c4Sopenharmony_ci continue; 1002da0c48c4Sopenharmony_ci 1003da0c48c4Sopenharmony_ci void *into = contents + offset; 1004da0c48c4Sopenharmony_ci size_t read_size = MIN (filesz, file_trimmed_end - offset); 1005da0c48c4Sopenharmony_ci (*memory_callback) (dwfl, addr_segndx (dwfl, segment, 1006da0c48c4Sopenharmony_ci vaddr + bias, false), 1007da0c48c4Sopenharmony_ci &into, &read_size, vaddr + bias, read_size, 1008da0c48c4Sopenharmony_ci memory_callback_arg); 1009da0c48c4Sopenharmony_ci } 1010da0c48c4Sopenharmony_ci } 1011da0c48c4Sopenharmony_ci else 1012da0c48c4Sopenharmony_ci { 1013da0c48c4Sopenharmony_ci /* The whole file sits contiguous in memory, 1014da0c48c4Sopenharmony_ci but the caller didn't want to just do it. */ 1015da0c48c4Sopenharmony_ci 1016da0c48c4Sopenharmony_ci const size_t have = MIN (buffer_available, file_trimmed_end); 1017da0c48c4Sopenharmony_ci memcpy (contents, buffer, have); 1018da0c48c4Sopenharmony_ci 1019da0c48c4Sopenharmony_ci if (have < file_trimmed_end) 1020da0c48c4Sopenharmony_ci { 1021da0c48c4Sopenharmony_ci void *into = contents + have; 1022da0c48c4Sopenharmony_ci size_t read_size = file_trimmed_end - have; 1023da0c48c4Sopenharmony_ci (*memory_callback) (dwfl, 1024da0c48c4Sopenharmony_ci addr_segndx (dwfl, segment, 1025da0c48c4Sopenharmony_ci start + have, false), 1026da0c48c4Sopenharmony_ci &into, &read_size, start + have, 1027da0c48c4Sopenharmony_ci read_size, memory_callback_arg); 1028da0c48c4Sopenharmony_ci } 1029da0c48c4Sopenharmony_ci } 1030da0c48c4Sopenharmony_ci 1031da0c48c4Sopenharmony_ci elf = elf_memory (contents, file_trimmed_end); 1032da0c48c4Sopenharmony_ci if (unlikely (elf == NULL)) 1033da0c48c4Sopenharmony_ci free (contents); 1034da0c48c4Sopenharmony_ci else 1035da0c48c4Sopenharmony_ci elf->flags |= ELF_F_MALLOCED; 1036da0c48c4Sopenharmony_ci } 1037da0c48c4Sopenharmony_ci 1038da0c48c4Sopenharmony_ci if (elf != NULL && mod->main.elf == NULL) 1039da0c48c4Sopenharmony_ci { 1040da0c48c4Sopenharmony_ci /* Install the file in the module. */ 1041da0c48c4Sopenharmony_ci mod->main.elf = elf; 1042da0c48c4Sopenharmony_ci mod->main.fd = fd; 1043da0c48c4Sopenharmony_ci elf = NULL; 1044da0c48c4Sopenharmony_ci fd = -1; 1045da0c48c4Sopenharmony_ci mod->main.vaddr = module_start - bias; 1046da0c48c4Sopenharmony_ci mod->main.address_sync = module_address_sync; 1047da0c48c4Sopenharmony_ci mod->main_bias = bias; 1048da0c48c4Sopenharmony_ci } 1049da0c48c4Sopenharmony_ci 1050da0c48c4Sopenharmony_ciout: 1051da0c48c4Sopenharmony_ci if (build_id.memory != NULL) 1052da0c48c4Sopenharmony_ci free (build_id.memory); 1053da0c48c4Sopenharmony_ci free (phdrsp); 1054da0c48c4Sopenharmony_ci if (buffer != NULL) 1055da0c48c4Sopenharmony_ci (*memory_callback) (dwfl, -1, &buffer, &buffer_available, 0, 0, 1056da0c48c4Sopenharmony_ci memory_callback_arg); 1057da0c48c4Sopenharmony_ci 1058da0c48c4Sopenharmony_ci if (elf != NULL) 1059da0c48c4Sopenharmony_ci elf_end (elf); 1060da0c48c4Sopenharmony_ci if (fd != -1) 1061da0c48c4Sopenharmony_ci close (fd); 1062da0c48c4Sopenharmony_ci return ndx; 1063da0c48c4Sopenharmony_ci} 1064