1da0c48c4Sopenharmony_ci/* Find debugging and symbol information for a module in libdwfl. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include "libdwflP.h" 34da0c48c4Sopenharmony_ci#include <inttypes.h> 35da0c48c4Sopenharmony_ci#include <fcntl.h> 36da0c48c4Sopenharmony_ci#include <string.h> 37da0c48c4Sopenharmony_ci#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ 38da0c48c4Sopenharmony_ci#include "../libelf/libelfP.h" 39da0c48c4Sopenharmony_ci#include "system.h" 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_cistatic inline Dwfl_Error 42da0c48c4Sopenharmony_ciopen_elf_file (Elf **elf, int *fd, char **name) 43da0c48c4Sopenharmony_ci{ 44da0c48c4Sopenharmony_ci if (*elf == NULL) 45da0c48c4Sopenharmony_ci { 46da0c48c4Sopenharmony_ci /* CBFAIL uses errno if it's set, so clear it first in case we don't 47da0c48c4Sopenharmony_ci set it with an open failure below. */ 48da0c48c4Sopenharmony_ci errno = 0; 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci /* If there was a pre-primed file name left that the callback left 51da0c48c4Sopenharmony_ci behind, try to open that file name. */ 52da0c48c4Sopenharmony_ci if (*fd < 0 && *name != NULL) 53da0c48c4Sopenharmony_ci *fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY)); 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci if (*fd < 0) 56da0c48c4Sopenharmony_ci return CBFAIL; 57da0c48c4Sopenharmony_ci 58da0c48c4Sopenharmony_ci return __libdw_open_file (fd, elf, true, false); 59da0c48c4Sopenharmony_ci } 60da0c48c4Sopenharmony_ci else if (unlikely (elf_kind (*elf) != ELF_K_ELF)) 61da0c48c4Sopenharmony_ci { 62da0c48c4Sopenharmony_ci elf_end (*elf); 63da0c48c4Sopenharmony_ci *elf = NULL; 64da0c48c4Sopenharmony_ci close (*fd); 65da0c48c4Sopenharmony_ci *fd = -1; 66da0c48c4Sopenharmony_ci return DWFL_E_BADELF; 67da0c48c4Sopenharmony_ci } 68da0c48c4Sopenharmony_ci 69da0c48c4Sopenharmony_ci /* Elf file already open and looks fine. */ 70da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 71da0c48c4Sopenharmony_ci} 72da0c48c4Sopenharmony_ci 73da0c48c4Sopenharmony_ci/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD. 74da0c48c4Sopenharmony_ci When we return success, FILE->elf and FILE->vaddr are set up. */ 75da0c48c4Sopenharmony_cistatic inline Dwfl_Error 76da0c48c4Sopenharmony_ciopen_elf (Dwfl_Module *mod, struct dwfl_file *file) 77da0c48c4Sopenharmony_ci{ 78da0c48c4Sopenharmony_ci Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name); 79da0c48c4Sopenharmony_ci if (error != DWFL_E_NOERROR) 80da0c48c4Sopenharmony_ci return error; 81da0c48c4Sopenharmony_ci 82da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem); 83da0c48c4Sopenharmony_ci if (ehdr == NULL) 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci elf_error: 86da0c48c4Sopenharmony_ci elf_end (file->elf); 87da0c48c4Sopenharmony_ci file->elf = NULL; 88da0c48c4Sopenharmony_ci close (file->fd); 89da0c48c4Sopenharmony_ci file->fd = -1; 90da0c48c4Sopenharmony_ci return DWFL_E (LIBELF, elf_errno ()); 91da0c48c4Sopenharmony_ci } 92da0c48c4Sopenharmony_ci 93da0c48c4Sopenharmony_ci if (ehdr->e_type != ET_REL) 94da0c48c4Sopenharmony_ci { 95da0c48c4Sopenharmony_ci /* In any non-ET_REL file, we compute the "synchronization address". 96da0c48c4Sopenharmony_ci 97da0c48c4Sopenharmony_ci We start with the address at the end of the first PT_LOAD 98da0c48c4Sopenharmony_ci segment. When prelink converts REL to RELA in an ET_DYN 99da0c48c4Sopenharmony_ci file, it expands the space between the beginning of the 100da0c48c4Sopenharmony_ci segment and the actual code/data addresses. Since that 101da0c48c4Sopenharmony_ci change wasn't made in the debug file, the distance from 102da0c48c4Sopenharmony_ci p_vaddr to an address of interest (in an st_value or DWARF 103da0c48c4Sopenharmony_ci data) now differs between the main and debug files. The 104da0c48c4Sopenharmony_ci distance from address_sync to an address of interest remains 105da0c48c4Sopenharmony_ci consistent. 106da0c48c4Sopenharmony_ci 107da0c48c4Sopenharmony_ci If there are no section headers at all (full stripping), then 108da0c48c4Sopenharmony_ci the end of the first segment is a valid synchronization address. 109da0c48c4Sopenharmony_ci This cannot happen in a prelinked file, since prelink itself 110da0c48c4Sopenharmony_ci relies on section headers for prelinking and for undoing it. 111da0c48c4Sopenharmony_ci (If you do full stripping on a prelinked file, then you get what 112da0c48c4Sopenharmony_ci you deserve--you can neither undo the prelinking, nor expect to 113da0c48c4Sopenharmony_ci line it up with a debug file separated before prelinking.) 114da0c48c4Sopenharmony_ci 115da0c48c4Sopenharmony_ci However, when prelink processes an ET_EXEC file, it can do 116da0c48c4Sopenharmony_ci something different. There it juggles the "special" sections 117da0c48c4Sopenharmony_ci (SHT_DYNSYM et al) to make space for the additional prelink 118da0c48c4Sopenharmony_ci special sections. Sometimes it will do this by moving a special 119da0c48c4Sopenharmony_ci section like .dynstr after the real program sections in the first 120da0c48c4Sopenharmony_ci PT_LOAD segment--i.e. to the end. That changes the end address of 121da0c48c4Sopenharmony_ci the segment, so it no longer lines up correctly and is not a valid 122da0c48c4Sopenharmony_ci synchronization address to use. Because of this, we need to apply 123da0c48c4Sopenharmony_ci a different prelink-savvy means to discover the synchronization 124da0c48c4Sopenharmony_ci address when there is a separate debug file and a prelinked main 125da0c48c4Sopenharmony_ci file. That is done in find_debuginfo, below. */ 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ci size_t phnum; 128da0c48c4Sopenharmony_ci if (unlikely (elf_getphdrnum (file->elf, &phnum) != 0)) 129da0c48c4Sopenharmony_ci goto elf_error; 130da0c48c4Sopenharmony_ci 131da0c48c4Sopenharmony_ci file->vaddr = file->address_sync = 0; 132da0c48c4Sopenharmony_ci for (size_t i = 0; i < phnum; ++i) 133da0c48c4Sopenharmony_ci { 134da0c48c4Sopenharmony_ci GElf_Phdr ph_mem; 135da0c48c4Sopenharmony_ci GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem); 136da0c48c4Sopenharmony_ci if (unlikely (ph == NULL)) 137da0c48c4Sopenharmony_ci goto elf_error; 138da0c48c4Sopenharmony_ci if (ph->p_type == PT_LOAD) 139da0c48c4Sopenharmony_ci { 140da0c48c4Sopenharmony_ci file->vaddr = ph->p_vaddr & -ph->p_align; 141da0c48c4Sopenharmony_ci file->address_sync = ph->p_vaddr + ph->p_memsz; 142da0c48c4Sopenharmony_ci break; 143da0c48c4Sopenharmony_ci } 144da0c48c4Sopenharmony_ci } 145da0c48c4Sopenharmony_ci } 146da0c48c4Sopenharmony_ci 147da0c48c4Sopenharmony_ci /* We only want to set the module e_type explicitly once, derived from 148da0c48c4Sopenharmony_ci the main ELF file. (It might be changed for the kernel, because 149da0c48c4Sopenharmony_ci that is special - see below.) open_elf is always called first for 150da0c48c4Sopenharmony_ci the main ELF file, because both find_dw and find_symtab call 151da0c48c4Sopenharmony_ci __libdwfl_getelf first to open the main file. So don't let debug 152da0c48c4Sopenharmony_ci or aux files override the module e_type. The kernel heuristic 153da0c48c4Sopenharmony_ci below could otherwise trigger for non-kernel/non-main files, since 154da0c48c4Sopenharmony_ci their phdrs might not match the actual load addresses. */ 155da0c48c4Sopenharmony_ci if (file == &mod->main) 156da0c48c4Sopenharmony_ci { 157da0c48c4Sopenharmony_ci mod->e_type = ehdr->e_type; 158da0c48c4Sopenharmony_ci 159da0c48c4Sopenharmony_ci /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */ 160da0c48c4Sopenharmony_ci if (mod->e_type == ET_EXEC && file->vaddr != mod->low_addr) 161da0c48c4Sopenharmony_ci mod->e_type = ET_DYN; 162da0c48c4Sopenharmony_ci } 163da0c48c4Sopenharmony_ci else 164da0c48c4Sopenharmony_ci assert (mod->main.elf != NULL); 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 167da0c48c4Sopenharmony_ci} 168da0c48c4Sopenharmony_ci 169da0c48c4Sopenharmony_ci/* We have an authoritative build ID for this module MOD, so don't use 170da0c48c4Sopenharmony_ci a file by name that doesn't match that ID. */ 171da0c48c4Sopenharmony_cistatic void 172da0c48c4Sopenharmony_cimod_verify_build_id (Dwfl_Module *mod) 173da0c48c4Sopenharmony_ci{ 174da0c48c4Sopenharmony_ci assert (mod->build_id_len > 0); 175da0c48c4Sopenharmony_ci 176da0c48c4Sopenharmony_ci switch (__builtin_expect (__libdwfl_find_build_id (mod, false, 177da0c48c4Sopenharmony_ci mod->main.elf), 2)) 178da0c48c4Sopenharmony_ci { 179da0c48c4Sopenharmony_ci case 2: 180da0c48c4Sopenharmony_ci /* Build ID matches as it should. */ 181da0c48c4Sopenharmony_ci return; 182da0c48c4Sopenharmony_ci 183da0c48c4Sopenharmony_ci case -1: /* ELF error. */ 184da0c48c4Sopenharmony_ci mod->elferr = INTUSE(dwfl_errno) (); 185da0c48c4Sopenharmony_ci break; 186da0c48c4Sopenharmony_ci 187da0c48c4Sopenharmony_ci case 0: /* File has no build ID note. */ 188da0c48c4Sopenharmony_ci case 1: /* FIle has a build ID that does not match. */ 189da0c48c4Sopenharmony_ci mod->elferr = DWFL_E_WRONG_ID_ELF; 190da0c48c4Sopenharmony_ci break; 191da0c48c4Sopenharmony_ci 192da0c48c4Sopenharmony_ci default: 193da0c48c4Sopenharmony_ci abort (); 194da0c48c4Sopenharmony_ci } 195da0c48c4Sopenharmony_ci 196da0c48c4Sopenharmony_ci /* We get here when it was the right ELF file. Clear it out. */ 197da0c48c4Sopenharmony_ci elf_end (mod->main.elf); 198da0c48c4Sopenharmony_ci mod->main.elf = NULL; 199da0c48c4Sopenharmony_ci if (mod->main.fd >= 0) 200da0c48c4Sopenharmony_ci { 201da0c48c4Sopenharmony_ci close (mod->main.fd); 202da0c48c4Sopenharmony_ci mod->main.fd = -1; 203da0c48c4Sopenharmony_ci } 204da0c48c4Sopenharmony_ci} 205da0c48c4Sopenharmony_ci 206da0c48c4Sopenharmony_ci/* Find the main ELF file for this module and open libelf on it. 207da0c48c4Sopenharmony_ci When we return success, MOD->main.elf and MOD->main.bias are set up. */ 208da0c48c4Sopenharmony_civoid 209da0c48c4Sopenharmony_ciinternal_function 210da0c48c4Sopenharmony_ci__libdwfl_getelf (Dwfl_Module *mod) 211da0c48c4Sopenharmony_ci{ 212da0c48c4Sopenharmony_ci if (mod->main.elf != NULL /* Already done. */ 213da0c48c4Sopenharmony_ci || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */ 214da0c48c4Sopenharmony_ci return; 215da0c48c4Sopenharmony_ci 216da0c48c4Sopenharmony_ci mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), 217da0c48c4Sopenharmony_ci &mod->main.name, 218da0c48c4Sopenharmony_ci &mod->main.elf); 219da0c48c4Sopenharmony_ci const bool fallback = mod->main.elf == NULL && mod->main.fd < 0; 220da0c48c4Sopenharmony_ci mod->elferr = open_elf (mod, &mod->main); 221da0c48c4Sopenharmony_ci if (mod->elferr != DWFL_E_NOERROR) 222da0c48c4Sopenharmony_ci return; 223da0c48c4Sopenharmony_ci 224da0c48c4Sopenharmony_ci if (!mod->main.valid) 225da0c48c4Sopenharmony_ci { 226da0c48c4Sopenharmony_ci /* Clear any explicitly reported build ID, just in case it was wrong. 227da0c48c4Sopenharmony_ci We'll fetch it from the file when asked. */ 228da0c48c4Sopenharmony_ci free (mod->build_id_bits); 229da0c48c4Sopenharmony_ci mod->build_id_bits = NULL; 230da0c48c4Sopenharmony_ci mod->build_id_len = 0; 231da0c48c4Sopenharmony_ci } 232da0c48c4Sopenharmony_ci else if (fallback) 233da0c48c4Sopenharmony_ci mod_verify_build_id (mod); 234da0c48c4Sopenharmony_ci 235da0c48c4Sopenharmony_ci mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr; 236da0c48c4Sopenharmony_ci} 237da0c48c4Sopenharmony_ci 238da0c48c4Sopenharmony_cistatic inline void 239da0c48c4Sopenharmony_ciconsider_shdr (GElf_Addr interp, 240da0c48c4Sopenharmony_ci GElf_Word sh_type, 241da0c48c4Sopenharmony_ci GElf_Xword sh_flags, 242da0c48c4Sopenharmony_ci GElf_Addr sh_addr, 243da0c48c4Sopenharmony_ci GElf_Xword sh_size, 244da0c48c4Sopenharmony_ci GElf_Addr *phighest) 245da0c48c4Sopenharmony_ci{ 246da0c48c4Sopenharmony_ci if ((sh_flags & SHF_ALLOC) 247da0c48c4Sopenharmony_ci && ((sh_type == SHT_PROGBITS && sh_addr != interp) 248da0c48c4Sopenharmony_ci || sh_type == SHT_NOBITS)) 249da0c48c4Sopenharmony_ci { 250da0c48c4Sopenharmony_ci const GElf_Addr sh_end = sh_addr + sh_size; 251da0c48c4Sopenharmony_ci if (sh_end > *phighest) 252da0c48c4Sopenharmony_ci *phighest = sh_end; 253da0c48c4Sopenharmony_ci } 254da0c48c4Sopenharmony_ci} 255da0c48c4Sopenharmony_ci 256da0c48c4Sopenharmony_ci/* If the main file might have been prelinked, then we need to 257da0c48c4Sopenharmony_ci discover the correct synchronization address between the main and 258da0c48c4Sopenharmony_ci debug files. Because of prelink's section juggling, we cannot rely 259da0c48c4Sopenharmony_ci on the address_sync computed from PT_LOAD segments (see open_elf). 260da0c48c4Sopenharmony_ci 261da0c48c4Sopenharmony_ci We will attempt to discover a synchronization address based on the 262da0c48c4Sopenharmony_ci section headers instead. But finding a section address that is 263da0c48c4Sopenharmony_ci safe to use requires identifying which sections are SHT_PROGBITS. 264da0c48c4Sopenharmony_ci We can do that in the main file, but in the debug file all the 265da0c48c4Sopenharmony_ci allocated sections have been transformed into SHT_NOBITS so we have 266da0c48c4Sopenharmony_ci lost the means to match them up correctly. 267da0c48c4Sopenharmony_ci 268da0c48c4Sopenharmony_ci The only method left to us is to decode the .gnu.prelink_undo 269da0c48c4Sopenharmony_ci section in the prelinked main file. This shows what the sections 270da0c48c4Sopenharmony_ci looked like before prelink juggled them--when they still had a 271da0c48c4Sopenharmony_ci direct correspondence to the debug file. */ 272da0c48c4Sopenharmony_cistatic Dwfl_Error 273da0c48c4Sopenharmony_cifind_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) 274da0c48c4Sopenharmony_ci{ 275da0c48c4Sopenharmony_ci /* The magic section is only identified by name. */ 276da0c48c4Sopenharmony_ci size_t shstrndx; 277da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0) 278da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 279da0c48c4Sopenharmony_ci 280da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 281da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) 282da0c48c4Sopenharmony_ci { 283da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 284da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 285da0c48c4Sopenharmony_ci if (unlikely (shdr == NULL)) 286da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 287da0c48c4Sopenharmony_ci if (shdr->sh_type == SHT_PROGBITS 288da0c48c4Sopenharmony_ci && !(shdr->sh_flags & SHF_ALLOC) 289da0c48c4Sopenharmony_ci && shdr->sh_name != 0) 290da0c48c4Sopenharmony_ci { 291da0c48c4Sopenharmony_ci const char *secname = elf_strptr (mod->main.elf, shstrndx, 292da0c48c4Sopenharmony_ci shdr->sh_name); 293da0c48c4Sopenharmony_ci if (unlikely (secname == NULL)) 294da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 295da0c48c4Sopenharmony_ci if (!strcmp (secname, ".gnu.prelink_undo")) 296da0c48c4Sopenharmony_ci break; 297da0c48c4Sopenharmony_ci } 298da0c48c4Sopenharmony_ci } 299da0c48c4Sopenharmony_ci 300da0c48c4Sopenharmony_ci if (scn == NULL) 301da0c48c4Sopenharmony_ci /* There was no .gnu.prelink_undo section. */ 302da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 303da0c48c4Sopenharmony_ci 304da0c48c4Sopenharmony_ci Elf_Data *undodata = elf_rawdata (scn, NULL); 305da0c48c4Sopenharmony_ci if (unlikely (undodata == NULL)) 306da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 307da0c48c4Sopenharmony_ci 308da0c48c4Sopenharmony_ci /* Decode the section. It consists of the original ehdr, phdrs, 309da0c48c4Sopenharmony_ci and shdrs (but omits section 0). */ 310da0c48c4Sopenharmony_ci 311da0c48c4Sopenharmony_ci union 312da0c48c4Sopenharmony_ci { 313da0c48c4Sopenharmony_ci Elf32_Ehdr e32; 314da0c48c4Sopenharmony_ci Elf64_Ehdr e64; 315da0c48c4Sopenharmony_ci } ehdr; 316da0c48c4Sopenharmony_ci Elf_Data dst = 317da0c48c4Sopenharmony_ci { 318da0c48c4Sopenharmony_ci .d_buf = &ehdr, 319da0c48c4Sopenharmony_ci .d_size = sizeof ehdr, 320da0c48c4Sopenharmony_ci .d_type = ELF_T_EHDR, 321da0c48c4Sopenharmony_ci .d_version = EV_CURRENT 322da0c48c4Sopenharmony_ci }; 323da0c48c4Sopenharmony_ci Elf_Data src = *undodata; 324da0c48c4Sopenharmony_ci src.d_size = gelf_fsize (mod->main.elf, ELF_T_EHDR, 1, EV_CURRENT); 325da0c48c4Sopenharmony_ci src.d_type = ELF_T_EHDR; 326da0c48c4Sopenharmony_ci if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, 327da0c48c4Sopenharmony_ci elf_getident (mod->main.elf, NULL)[EI_DATA]) 328da0c48c4Sopenharmony_ci == NULL)) 329da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 330da0c48c4Sopenharmony_ci 331da0c48c4Sopenharmony_ci size_t shentsize = gelf_fsize (mod->main.elf, ELF_T_SHDR, 1, EV_CURRENT); 332da0c48c4Sopenharmony_ci size_t phentsize = gelf_fsize (mod->main.elf, ELF_T_PHDR, 1, EV_CURRENT); 333da0c48c4Sopenharmony_ci 334da0c48c4Sopenharmony_ci uint_fast16_t phnum; 335da0c48c4Sopenharmony_ci uint_fast16_t shnum; 336da0c48c4Sopenharmony_ci if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) 337da0c48c4Sopenharmony_ci { 338da0c48c4Sopenharmony_ci if (ehdr.e32.e_shentsize != shentsize 339da0c48c4Sopenharmony_ci || ehdr.e32.e_phentsize != phentsize) 340da0c48c4Sopenharmony_ci return DWFL_E_BAD_PRELINK; 341da0c48c4Sopenharmony_ci phnum = ehdr.e32.e_phnum; 342da0c48c4Sopenharmony_ci shnum = ehdr.e32.e_shnum; 343da0c48c4Sopenharmony_ci } 344da0c48c4Sopenharmony_ci else 345da0c48c4Sopenharmony_ci { 346da0c48c4Sopenharmony_ci if (ehdr.e64.e_shentsize != shentsize 347da0c48c4Sopenharmony_ci || ehdr.e64.e_phentsize != phentsize) 348da0c48c4Sopenharmony_ci return DWFL_E_BAD_PRELINK; 349da0c48c4Sopenharmony_ci phnum = ehdr.e64.e_phnum; 350da0c48c4Sopenharmony_ci shnum = ehdr.e64.e_shnum; 351da0c48c4Sopenharmony_ci } 352da0c48c4Sopenharmony_ci 353da0c48c4Sopenharmony_ci /* Since prelink does not store the zeroth section header in the undo 354da0c48c4Sopenharmony_ci section, it cannot support SHN_XINDEX encoding. */ 355da0c48c4Sopenharmony_ci if (unlikely (shnum >= SHN_LORESERVE) || unlikely(shnum == 0) 356da0c48c4Sopenharmony_ci || unlikely (undodata->d_size != (src.d_size 357da0c48c4Sopenharmony_ci + phnum * phentsize 358da0c48c4Sopenharmony_ci + (shnum - 1) * shentsize))) 359da0c48c4Sopenharmony_ci return DWFL_E_BAD_PRELINK; 360da0c48c4Sopenharmony_ci 361da0c48c4Sopenharmony_ci --shnum; 362da0c48c4Sopenharmony_ci 363da0c48c4Sopenharmony_ci /* We look at the allocated SHT_PROGBITS (or SHT_NOBITS) sections. (Most 364da0c48c4Sopenharmony_ci every file will have some SHT_PROGBITS sections, but it's possible to 365da0c48c4Sopenharmony_ci have one with nothing but .bss, i.e. SHT_NOBITS.) The special sections 366da0c48c4Sopenharmony_ci that can be moved around have different sh_type values--except for 367da0c48c4Sopenharmony_ci .interp, the section that became the PT_INTERP segment. So we exclude 368da0c48c4Sopenharmony_ci the SHT_PROGBITS section whose address matches the PT_INTERP p_vaddr. 369da0c48c4Sopenharmony_ci For this reason, we must examine the phdrs first to find PT_INTERP. */ 370da0c48c4Sopenharmony_ci 371da0c48c4Sopenharmony_ci GElf_Addr main_interp = 0; 372da0c48c4Sopenharmony_ci { 373da0c48c4Sopenharmony_ci size_t main_phnum; 374da0c48c4Sopenharmony_ci if (unlikely (elf_getphdrnum (mod->main.elf, &main_phnum))) 375da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 376da0c48c4Sopenharmony_ci for (size_t i = 0; i < main_phnum; ++i) 377da0c48c4Sopenharmony_ci { 378da0c48c4Sopenharmony_ci GElf_Phdr phdr; 379da0c48c4Sopenharmony_ci if (unlikely (gelf_getphdr (mod->main.elf, i, &phdr) == NULL)) 380da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 381da0c48c4Sopenharmony_ci if (phdr.p_type == PT_INTERP) 382da0c48c4Sopenharmony_ci { 383da0c48c4Sopenharmony_ci main_interp = phdr.p_vaddr; 384da0c48c4Sopenharmony_ci break; 385da0c48c4Sopenharmony_ci } 386da0c48c4Sopenharmony_ci } 387da0c48c4Sopenharmony_ci } 388da0c48c4Sopenharmony_ci 389da0c48c4Sopenharmony_ci src.d_buf += src.d_size; 390da0c48c4Sopenharmony_ci src.d_type = ELF_T_PHDR; 391da0c48c4Sopenharmony_ci src.d_size = phnum * phentsize; 392da0c48c4Sopenharmony_ci 393da0c48c4Sopenharmony_ci GElf_Addr undo_interp = 0; 394da0c48c4Sopenharmony_ci bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32; 395da0c48c4Sopenharmony_ci { 396da0c48c4Sopenharmony_ci size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr); 397da0c48c4Sopenharmony_ci if (unlikely (phnum > SIZE_MAX / phdr_size)) 398da0c48c4Sopenharmony_ci return DWFL_E_NOMEM; 399da0c48c4Sopenharmony_ci const size_t phdrs_bytes = phnum * phdr_size; 400da0c48c4Sopenharmony_ci void *phdrs = malloc (phdrs_bytes); 401da0c48c4Sopenharmony_ci if (unlikely (phdrs == NULL)) 402da0c48c4Sopenharmony_ci return DWFL_E_NOMEM; 403da0c48c4Sopenharmony_ci dst.d_buf = phdrs; 404da0c48c4Sopenharmony_ci dst.d_size = phdrs_bytes; 405da0c48c4Sopenharmony_ci if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, 406da0c48c4Sopenharmony_ci ehdr.e32.e_ident[EI_DATA]) == NULL)) 407da0c48c4Sopenharmony_ci { 408da0c48c4Sopenharmony_ci free (phdrs); 409da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 410da0c48c4Sopenharmony_ci } 411da0c48c4Sopenharmony_ci if (class32) 412da0c48c4Sopenharmony_ci { 413da0c48c4Sopenharmony_ci Elf32_Phdr (*p32)[phnum] = phdrs; 414da0c48c4Sopenharmony_ci for (uint_fast16_t i = 0; i < phnum; ++i) 415da0c48c4Sopenharmony_ci if ((*p32)[i].p_type == PT_INTERP) 416da0c48c4Sopenharmony_ci { 417da0c48c4Sopenharmony_ci undo_interp = (*p32)[i].p_vaddr; 418da0c48c4Sopenharmony_ci break; 419da0c48c4Sopenharmony_ci } 420da0c48c4Sopenharmony_ci } 421da0c48c4Sopenharmony_ci else 422da0c48c4Sopenharmony_ci { 423da0c48c4Sopenharmony_ci Elf64_Phdr (*p64)[phnum] = phdrs; 424da0c48c4Sopenharmony_ci for (uint_fast16_t i = 0; i < phnum; ++i) 425da0c48c4Sopenharmony_ci if ((*p64)[i].p_type == PT_INTERP) 426da0c48c4Sopenharmony_ci { 427da0c48c4Sopenharmony_ci undo_interp = (*p64)[i].p_vaddr; 428da0c48c4Sopenharmony_ci break; 429da0c48c4Sopenharmony_ci } 430da0c48c4Sopenharmony_ci } 431da0c48c4Sopenharmony_ci free (phdrs); 432da0c48c4Sopenharmony_ci } 433da0c48c4Sopenharmony_ci 434da0c48c4Sopenharmony_ci if (unlikely ((main_interp == 0) != (undo_interp == 0))) 435da0c48c4Sopenharmony_ci return DWFL_E_BAD_PRELINK; 436da0c48c4Sopenharmony_ci 437da0c48c4Sopenharmony_ci src.d_buf += src.d_size; 438da0c48c4Sopenharmony_ci src.d_type = ELF_T_SHDR; 439da0c48c4Sopenharmony_ci src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum, EV_CURRENT); 440da0c48c4Sopenharmony_ci 441da0c48c4Sopenharmony_ci size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr); 442da0c48c4Sopenharmony_ci if (unlikely (shnum > SIZE_MAX / shdr_size)) 443da0c48c4Sopenharmony_ci return DWFL_E_NOMEM; 444da0c48c4Sopenharmony_ci const size_t shdrs_bytes = shnum * shdr_size; 445da0c48c4Sopenharmony_ci void *shdrs = malloc (shdrs_bytes); 446da0c48c4Sopenharmony_ci if (unlikely (shdrs == NULL)) 447da0c48c4Sopenharmony_ci return DWFL_E_NOMEM; 448da0c48c4Sopenharmony_ci dst.d_buf = shdrs; 449da0c48c4Sopenharmony_ci dst.d_size = shdrs_bytes; 450da0c48c4Sopenharmony_ci if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, 451da0c48c4Sopenharmony_ci ehdr.e32.e_ident[EI_DATA]) == NULL)) 452da0c48c4Sopenharmony_ci { 453da0c48c4Sopenharmony_ci free (shdrs); 454da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 455da0c48c4Sopenharmony_ci } 456da0c48c4Sopenharmony_ci 457da0c48c4Sopenharmony_ci /* Now we can look at the original section headers of the main file 458da0c48c4Sopenharmony_ci before it was prelinked. First we'll apply our method to the main 459da0c48c4Sopenharmony_ci file sections as they are after prelinking, to calculate the 460da0c48c4Sopenharmony_ci synchronization address of the main file. Then we'll apply that 461da0c48c4Sopenharmony_ci same method to the saved section headers, to calculate the matching 462da0c48c4Sopenharmony_ci synchronization address of the debug file. 463da0c48c4Sopenharmony_ci 464da0c48c4Sopenharmony_ci The method is to consider SHF_ALLOC sections that are either 465da0c48c4Sopenharmony_ci SHT_PROGBITS or SHT_NOBITS, excluding the section whose sh_addr 466da0c48c4Sopenharmony_ci matches the PT_INTERP p_vaddr. The special sections that can be 467da0c48c4Sopenharmony_ci moved by prelink have other types, except for .interp (which 468da0c48c4Sopenharmony_ci becomes PT_INTERP). The "real" sections cannot move as such, but 469da0c48c4Sopenharmony_ci .bss can be split into .dynbss and .bss, with the total memory 470da0c48c4Sopenharmony_ci image remaining the same but being spread across the two sections. 471da0c48c4Sopenharmony_ci So we consider the highest section end, which still matches up. */ 472da0c48c4Sopenharmony_ci 473da0c48c4Sopenharmony_ci GElf_Addr highest; 474da0c48c4Sopenharmony_ci 475da0c48c4Sopenharmony_ci highest = 0; 476da0c48c4Sopenharmony_ci scn = NULL; 477da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) 478da0c48c4Sopenharmony_ci { 479da0c48c4Sopenharmony_ci GElf_Shdr sh_mem; 480da0c48c4Sopenharmony_ci GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem); 481da0c48c4Sopenharmony_ci if (unlikely (sh == NULL)) 482da0c48c4Sopenharmony_ci { 483da0c48c4Sopenharmony_ci free (shdrs); 484da0c48c4Sopenharmony_ci return DWFL_E_LIBELF; 485da0c48c4Sopenharmony_ci } 486da0c48c4Sopenharmony_ci consider_shdr (main_interp, sh->sh_type, sh->sh_flags, 487da0c48c4Sopenharmony_ci sh->sh_addr, sh->sh_size, &highest); 488da0c48c4Sopenharmony_ci } 489da0c48c4Sopenharmony_ci if (highest > mod->main.vaddr) 490da0c48c4Sopenharmony_ci { 491da0c48c4Sopenharmony_ci mod->main.address_sync = highest; 492da0c48c4Sopenharmony_ci 493da0c48c4Sopenharmony_ci highest = 0; 494da0c48c4Sopenharmony_ci if (class32) 495da0c48c4Sopenharmony_ci { 496da0c48c4Sopenharmony_ci Elf32_Shdr (*s32)[shnum] = shdrs; 497da0c48c4Sopenharmony_ci for (size_t i = 0; i < shnum; ++i) 498da0c48c4Sopenharmony_ci consider_shdr (undo_interp, (*s32)[i].sh_type, 499da0c48c4Sopenharmony_ci (*s32)[i].sh_flags, (*s32)[i].sh_addr, 500da0c48c4Sopenharmony_ci (*s32)[i].sh_size, &highest); 501da0c48c4Sopenharmony_ci } 502da0c48c4Sopenharmony_ci else 503da0c48c4Sopenharmony_ci { 504da0c48c4Sopenharmony_ci Elf64_Shdr (*s64)[shnum] = shdrs; 505da0c48c4Sopenharmony_ci for (size_t i = 0; i < shnum; ++i) 506da0c48c4Sopenharmony_ci consider_shdr (undo_interp, (*s64)[i].sh_type, 507da0c48c4Sopenharmony_ci (*s64)[i].sh_flags, (*s64)[i].sh_addr, 508da0c48c4Sopenharmony_ci (*s64)[i].sh_size, &highest); 509da0c48c4Sopenharmony_ci } 510da0c48c4Sopenharmony_ci 511da0c48c4Sopenharmony_ci if (highest > file->vaddr) 512da0c48c4Sopenharmony_ci file->address_sync = highest; 513da0c48c4Sopenharmony_ci else 514da0c48c4Sopenharmony_ci { 515da0c48c4Sopenharmony_ci free (shdrs); 516da0c48c4Sopenharmony_ci return DWFL_E_BAD_PRELINK; 517da0c48c4Sopenharmony_ci } 518da0c48c4Sopenharmony_ci } 519da0c48c4Sopenharmony_ci 520da0c48c4Sopenharmony_ci free (shdrs); 521da0c48c4Sopenharmony_ci 522da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 523da0c48c4Sopenharmony_ci} 524da0c48c4Sopenharmony_ci 525da0c48c4Sopenharmony_ci/* Find the separate debuginfo file for this module and open libelf on it. 526da0c48c4Sopenharmony_ci When we return success, MOD->debug is set up. */ 527da0c48c4Sopenharmony_cistatic Dwfl_Error 528da0c48c4Sopenharmony_cifind_debuginfo (Dwfl_Module *mod) 529da0c48c4Sopenharmony_ci{ 530da0c48c4Sopenharmony_ci if (mod->debug.elf != NULL) 531da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 532da0c48c4Sopenharmony_ci 533da0c48c4Sopenharmony_ci GElf_Word debuglink_crc = 0; 534da0c48c4Sopenharmony_ci const char *debuglink_file; 535da0c48c4Sopenharmony_ci debuglink_file = INTUSE(dwelf_elf_gnu_debuglink) (mod->main.elf, 536da0c48c4Sopenharmony_ci &debuglink_crc); 537da0c48c4Sopenharmony_ci 538da0c48c4Sopenharmony_ci mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), 539da0c48c4Sopenharmony_ci mod->main.name, 540da0c48c4Sopenharmony_ci debuglink_file, 541da0c48c4Sopenharmony_ci debuglink_crc, 542da0c48c4Sopenharmony_ci &mod->debug.name); 543da0c48c4Sopenharmony_ci Dwfl_Error result = open_elf (mod, &mod->debug); 544da0c48c4Sopenharmony_ci if (result == DWFL_E_NOERROR && mod->debug.address_sync != 0) 545da0c48c4Sopenharmony_ci result = find_prelink_address_sync (mod, &mod->debug); 546da0c48c4Sopenharmony_ci return result; 547da0c48c4Sopenharmony_ci} 548da0c48c4Sopenharmony_ci 549da0c48c4Sopenharmony_ci/* Try to find the alternative debug link for the given DWARF and set 550da0c48c4Sopenharmony_ci it if found. Only called when mod->dw is already setup but still 551da0c48c4Sopenharmony_ci might need an alternative (dwz multi) debug file. filename is either 552da0c48c4Sopenharmony_ci the main or debug name from which the Dwarf was created. */ 553da0c48c4Sopenharmony_cistatic void 554da0c48c4Sopenharmony_cifind_debug_altlink (Dwfl_Module *mod, const char *filename) 555da0c48c4Sopenharmony_ci{ 556da0c48c4Sopenharmony_ci assert (mod->dw != NULL); 557da0c48c4Sopenharmony_ci 558da0c48c4Sopenharmony_ci const char *altname; 559da0c48c4Sopenharmony_ci const void *build_id; 560da0c48c4Sopenharmony_ci ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, 561da0c48c4Sopenharmony_ci &altname, 562da0c48c4Sopenharmony_ci &build_id); 563da0c48c4Sopenharmony_ci 564da0c48c4Sopenharmony_ci if (build_id_len > 0) 565da0c48c4Sopenharmony_ci { 566da0c48c4Sopenharmony_ci /* We could store altfile in the module, but don't really need it. */ 567da0c48c4Sopenharmony_ci char *altfile = NULL; 568da0c48c4Sopenharmony_ci mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), 569da0c48c4Sopenharmony_ci filename, 570da0c48c4Sopenharmony_ci altname, 571da0c48c4Sopenharmony_ci 0, 572da0c48c4Sopenharmony_ci &altfile); 573da0c48c4Sopenharmony_ci 574da0c48c4Sopenharmony_ci /* The (internal) callbacks might just set mod->alt_elf directly 575da0c48c4Sopenharmony_ci because they open the Elf anyway for sanity checking. 576da0c48c4Sopenharmony_ci Otherwise open either the given file name or use the fd 577da0c48c4Sopenharmony_ci returned. */ 578da0c48c4Sopenharmony_ci Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd, 579da0c48c4Sopenharmony_ci &altfile); 580da0c48c4Sopenharmony_ci if (error == DWFL_E_NOERROR) 581da0c48c4Sopenharmony_ci { 582da0c48c4Sopenharmony_ci mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf, 583da0c48c4Sopenharmony_ci DWARF_C_READ, NULL); 584da0c48c4Sopenharmony_ci if (mod->alt == NULL) 585da0c48c4Sopenharmony_ci { 586da0c48c4Sopenharmony_ci elf_end (mod->alt_elf); 587da0c48c4Sopenharmony_ci mod->alt_elf = NULL; 588da0c48c4Sopenharmony_ci close (mod->alt_fd); 589da0c48c4Sopenharmony_ci mod->alt_fd = -1; 590da0c48c4Sopenharmony_ci } 591da0c48c4Sopenharmony_ci else 592da0c48c4Sopenharmony_ci dwarf_setalt (mod->dw, mod->alt); 593da0c48c4Sopenharmony_ci } 594da0c48c4Sopenharmony_ci 595da0c48c4Sopenharmony_ci free (altfile); /* See above, we don't really need it. */ 596da0c48c4Sopenharmony_ci } 597da0c48c4Sopenharmony_ci} 598da0c48c4Sopenharmony_ci 599da0c48c4Sopenharmony_ci/* Try to find a symbol table in FILE. 600da0c48c4Sopenharmony_ci Returns DWFL_E_NOERROR if a proper one is found. 601da0c48c4Sopenharmony_ci Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */ 602da0c48c4Sopenharmony_cistatic Dwfl_Error 603da0c48c4Sopenharmony_ciload_symtab (struct dwfl_file *file, struct dwfl_file **symfile, 604da0c48c4Sopenharmony_ci Elf_Scn **symscn, Elf_Scn **xndxscn, 605da0c48c4Sopenharmony_ci size_t *syments, int *first_global, GElf_Word *strshndx) 606da0c48c4Sopenharmony_ci{ 607da0c48c4Sopenharmony_ci bool symtab = false; 608da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 609da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (file->elf, scn)) != NULL) 610da0c48c4Sopenharmony_ci { 611da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); 612da0c48c4Sopenharmony_ci if (shdr != NULL) 613da0c48c4Sopenharmony_ci switch (shdr->sh_type) 614da0c48c4Sopenharmony_ci { 615da0c48c4Sopenharmony_ci case SHT_SYMTAB: 616da0c48c4Sopenharmony_ci if (shdr->sh_entsize == 0) 617da0c48c4Sopenharmony_ci break; 618da0c48c4Sopenharmony_ci symtab = true; 619da0c48c4Sopenharmony_ci *symscn = scn; 620da0c48c4Sopenharmony_ci *symfile = file; 621da0c48c4Sopenharmony_ci *strshndx = shdr->sh_link; 622da0c48c4Sopenharmony_ci *syments = shdr->sh_size / shdr->sh_entsize; 623da0c48c4Sopenharmony_ci *first_global = shdr->sh_info; 624da0c48c4Sopenharmony_ci if (*xndxscn != NULL) 625da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 626da0c48c4Sopenharmony_ci break; 627da0c48c4Sopenharmony_ci 628da0c48c4Sopenharmony_ci case SHT_DYNSYM: 629da0c48c4Sopenharmony_ci if (symtab) 630da0c48c4Sopenharmony_ci break; 631da0c48c4Sopenharmony_ci /* Use this if need be, but keep looking for SHT_SYMTAB. */ 632da0c48c4Sopenharmony_ci if (shdr->sh_entsize == 0) 633da0c48c4Sopenharmony_ci break; 634da0c48c4Sopenharmony_ci *symscn = scn; 635da0c48c4Sopenharmony_ci *symfile = file; 636da0c48c4Sopenharmony_ci *strshndx = shdr->sh_link; 637da0c48c4Sopenharmony_ci *syments = shdr->sh_size / shdr->sh_entsize; 638da0c48c4Sopenharmony_ci *first_global = shdr->sh_info; 639da0c48c4Sopenharmony_ci break; 640da0c48c4Sopenharmony_ci 641da0c48c4Sopenharmony_ci case SHT_SYMTAB_SHNDX: 642da0c48c4Sopenharmony_ci *xndxscn = scn; 643da0c48c4Sopenharmony_ci if (symtab) 644da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 645da0c48c4Sopenharmony_ci break; 646da0c48c4Sopenharmony_ci 647da0c48c4Sopenharmony_ci default: 648da0c48c4Sopenharmony_ci break; 649da0c48c4Sopenharmony_ci } 650da0c48c4Sopenharmony_ci } 651da0c48c4Sopenharmony_ci 652da0c48c4Sopenharmony_ci if (symtab) 653da0c48c4Sopenharmony_ci /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */ 654da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 655da0c48c4Sopenharmony_ci 656da0c48c4Sopenharmony_ci /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus. 657da0c48c4Sopenharmony_ci We might have found an SHT_DYNSYM and set *SYMSCN et al though. */ 658da0c48c4Sopenharmony_ci *xndxscn = NULL; 659da0c48c4Sopenharmony_ci return DWFL_E_NO_SYMTAB; 660da0c48c4Sopenharmony_ci} 661da0c48c4Sopenharmony_ci 662da0c48c4Sopenharmony_ci 663da0c48c4Sopenharmony_ci/* Translate addresses into file offsets. 664da0c48c4Sopenharmony_ci OFFS[*] start out zero and remain zero if unresolved. */ 665da0c48c4Sopenharmony_cistatic void 666da0c48c4Sopenharmony_cifind_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, 667da0c48c4Sopenharmony_ci GElf_Addr addrs[n], GElf_Off offs[n]) 668da0c48c4Sopenharmony_ci{ 669da0c48c4Sopenharmony_ci size_t unsolved = n; 670da0c48c4Sopenharmony_ci for (size_t i = 0; i < phnum; ++i) 671da0c48c4Sopenharmony_ci { 672da0c48c4Sopenharmony_ci GElf_Phdr phdr_mem; 673da0c48c4Sopenharmony_ci GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); 674da0c48c4Sopenharmony_ci if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0) 675da0c48c4Sopenharmony_ci for (size_t j = 0; j < n; ++j) 676da0c48c4Sopenharmony_ci if (offs[j] == 0 677da0c48c4Sopenharmony_ci && addrs[j] >= phdr->p_vaddr + main_bias 678da0c48c4Sopenharmony_ci && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz) 679da0c48c4Sopenharmony_ci { 680da0c48c4Sopenharmony_ci offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset; 681da0c48c4Sopenharmony_ci if (--unsolved == 0) 682da0c48c4Sopenharmony_ci break; 683da0c48c4Sopenharmony_ci } 684da0c48c4Sopenharmony_ci } 685da0c48c4Sopenharmony_ci} 686da0c48c4Sopenharmony_ci 687da0c48c4Sopenharmony_ci/* Various addresses we might want to pull from the dynamic segment. */ 688da0c48c4Sopenharmony_cienum 689da0c48c4Sopenharmony_ci{ 690da0c48c4Sopenharmony_ci i_symtab, 691da0c48c4Sopenharmony_ci i_strtab, 692da0c48c4Sopenharmony_ci i_hash, 693da0c48c4Sopenharmony_ci i_gnu_hash, 694da0c48c4Sopenharmony_ci i_max 695da0c48c4Sopenharmony_ci}; 696da0c48c4Sopenharmony_ci 697da0c48c4Sopenharmony_ci/* Translate pointers into file offsets. ADJUST is either zero 698da0c48c4Sopenharmony_ci in case the dynamic segment wasn't adjusted or mod->main_bias. 699da0c48c4Sopenharmony_ci Will set mod->symfile if the translated offsets can be used as 700da0c48c4Sopenharmony_ci symbol table. */ 701da0c48c4Sopenharmony_cistatic void 702da0c48c4Sopenharmony_citranslate_offs (GElf_Addr adjust, 703da0c48c4Sopenharmony_ci Dwfl_Module *mod, size_t phnum, 704da0c48c4Sopenharmony_ci GElf_Addr addrs[i_max], GElf_Xword strsz, 705da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr) 706da0c48c4Sopenharmony_ci{ 707da0c48c4Sopenharmony_ci GElf_Off offs[i_max] = { 0, }; 708da0c48c4Sopenharmony_ci find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); 709da0c48c4Sopenharmony_ci 710da0c48c4Sopenharmony_ci /* Figure out the size of the symbol table. */ 711da0c48c4Sopenharmony_ci if (offs[i_hash] != 0) 712da0c48c4Sopenharmony_ci { 713da0c48c4Sopenharmony_ci /* In the original format, .hash says the size of .dynsym. */ 714da0c48c4Sopenharmony_ci 715da0c48c4Sopenharmony_ci size_t entsz = SH_ENTSIZE_HASH (ehdr); 716da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, 717da0c48c4Sopenharmony_ci offs[i_hash] + entsz, entsz, 718da0c48c4Sopenharmony_ci (entsz == 4 719da0c48c4Sopenharmony_ci ? ELF_T_WORD : ELF_T_XWORD)); 720da0c48c4Sopenharmony_ci if (data != NULL) 721da0c48c4Sopenharmony_ci mod->syments = (entsz == 4 722da0c48c4Sopenharmony_ci ? *(const GElf_Word *) data->d_buf 723da0c48c4Sopenharmony_ci : *(const GElf_Xword *) data->d_buf); 724da0c48c4Sopenharmony_ci } 725da0c48c4Sopenharmony_ci if (offs[i_gnu_hash] != 0 && mod->syments == 0) 726da0c48c4Sopenharmony_ci { 727da0c48c4Sopenharmony_ci /* In the new format, we can derive it with some work. */ 728da0c48c4Sopenharmony_ci 729da0c48c4Sopenharmony_ci const struct 730da0c48c4Sopenharmony_ci { 731da0c48c4Sopenharmony_ci Elf32_Word nbuckets; 732da0c48c4Sopenharmony_ci Elf32_Word symndx; 733da0c48c4Sopenharmony_ci Elf32_Word maskwords; 734da0c48c4Sopenharmony_ci Elf32_Word shift2; 735da0c48c4Sopenharmony_ci } *header; 736da0c48c4Sopenharmony_ci 737da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], 738da0c48c4Sopenharmony_ci sizeof *header, ELF_T_WORD); 739da0c48c4Sopenharmony_ci if (data != NULL) 740da0c48c4Sopenharmony_ci { 741da0c48c4Sopenharmony_ci header = data->d_buf; 742da0c48c4Sopenharmony_ci Elf32_Word nbuckets = header->nbuckets; 743da0c48c4Sopenharmony_ci Elf32_Word symndx = header->symndx; 744da0c48c4Sopenharmony_ci GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header 745da0c48c4Sopenharmony_ci + (gelf_getclass (mod->main.elf) 746da0c48c4Sopenharmony_ci * sizeof (Elf32_Word) 747da0c48c4Sopenharmony_ci * header->maskwords)); 748da0c48c4Sopenharmony_ci 749da0c48c4Sopenharmony_ci // elf_getdata_rawchunk takes a size_t, make sure it 750da0c48c4Sopenharmony_ci // doesn't overflow. 751da0c48c4Sopenharmony_ci#if SIZE_MAX <= UINT32_MAX 752da0c48c4Sopenharmony_ci if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) 753da0c48c4Sopenharmony_ci data = NULL; 754da0c48c4Sopenharmony_ci else 755da0c48c4Sopenharmony_ci#endif 756da0c48c4Sopenharmony_ci data = elf_getdata_rawchunk (mod->main.elf, buckets_at, 757da0c48c4Sopenharmony_ci nbuckets * sizeof (Elf32_Word), 758da0c48c4Sopenharmony_ci ELF_T_WORD); 759da0c48c4Sopenharmony_ci if (data != NULL && symndx < nbuckets) 760da0c48c4Sopenharmony_ci { 761da0c48c4Sopenharmony_ci const Elf32_Word *const buckets = data->d_buf; 762da0c48c4Sopenharmony_ci Elf32_Word maxndx = symndx; 763da0c48c4Sopenharmony_ci for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) 764da0c48c4Sopenharmony_ci if (buckets[bucket] > maxndx) 765da0c48c4Sopenharmony_ci maxndx = buckets[bucket]; 766da0c48c4Sopenharmony_ci 767da0c48c4Sopenharmony_ci GElf_Off hasharr_at = (buckets_at 768da0c48c4Sopenharmony_ci + nbuckets * sizeof (Elf32_Word)); 769da0c48c4Sopenharmony_ci hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); 770da0c48c4Sopenharmony_ci do 771da0c48c4Sopenharmony_ci { 772da0c48c4Sopenharmony_ci data = elf_getdata_rawchunk (mod->main.elf, 773da0c48c4Sopenharmony_ci hasharr_at, 774da0c48c4Sopenharmony_ci sizeof (Elf32_Word), 775da0c48c4Sopenharmony_ci ELF_T_WORD); 776da0c48c4Sopenharmony_ci if (data != NULL 777da0c48c4Sopenharmony_ci && (*(const Elf32_Word *) data->d_buf & 1u)) 778da0c48c4Sopenharmony_ci { 779da0c48c4Sopenharmony_ci mod->syments = maxndx + 1; 780da0c48c4Sopenharmony_ci break; 781da0c48c4Sopenharmony_ci } 782da0c48c4Sopenharmony_ci ++maxndx; 783da0c48c4Sopenharmony_ci hasharr_at += sizeof (Elf32_Word); 784da0c48c4Sopenharmony_ci } 785da0c48c4Sopenharmony_ci while (data != NULL); 786da0c48c4Sopenharmony_ci } 787da0c48c4Sopenharmony_ci } 788da0c48c4Sopenharmony_ci } 789da0c48c4Sopenharmony_ci if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) 790da0c48c4Sopenharmony_ci mod->syments = ((offs[i_strtab] - offs[i_symtab]) 791da0c48c4Sopenharmony_ci / gelf_fsize (mod->main.elf, 792da0c48c4Sopenharmony_ci ELF_T_SYM, 1, EV_CURRENT)); 793da0c48c4Sopenharmony_ci 794da0c48c4Sopenharmony_ci if (mod->syments > 0) 795da0c48c4Sopenharmony_ci { 796da0c48c4Sopenharmony_ci mod->symdata = elf_getdata_rawchunk (mod->main.elf, 797da0c48c4Sopenharmony_ci offs[i_symtab], 798da0c48c4Sopenharmony_ci gelf_fsize (mod->main.elf, 799da0c48c4Sopenharmony_ci ELF_T_SYM, 800da0c48c4Sopenharmony_ci mod->syments, 801da0c48c4Sopenharmony_ci EV_CURRENT), 802da0c48c4Sopenharmony_ci ELF_T_SYM); 803da0c48c4Sopenharmony_ci if (mod->symdata != NULL) 804da0c48c4Sopenharmony_ci { 805da0c48c4Sopenharmony_ci mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, 806da0c48c4Sopenharmony_ci offs[i_strtab], 807da0c48c4Sopenharmony_ci strsz, 808da0c48c4Sopenharmony_ci ELF_T_BYTE); 809da0c48c4Sopenharmony_ci if (mod->symstrdata == NULL) 810da0c48c4Sopenharmony_ci mod->symdata = NULL; 811da0c48c4Sopenharmony_ci } 812da0c48c4Sopenharmony_ci if (mod->symdata == NULL) 813da0c48c4Sopenharmony_ci mod->symerr = DWFL_E (LIBELF, elf_errno ()); 814da0c48c4Sopenharmony_ci else 815da0c48c4Sopenharmony_ci { 816da0c48c4Sopenharmony_ci mod->symfile = &mod->main; 817da0c48c4Sopenharmony_ci mod->symerr = DWFL_E_NOERROR; 818da0c48c4Sopenharmony_ci } 819da0c48c4Sopenharmony_ci } 820da0c48c4Sopenharmony_ci} 821da0c48c4Sopenharmony_ci 822da0c48c4Sopenharmony_ci/* Try to find a dynamic symbol table via phdrs. */ 823da0c48c4Sopenharmony_cistatic void 824da0c48c4Sopenharmony_cifind_dynsym (Dwfl_Module *mod) 825da0c48c4Sopenharmony_ci{ 826da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem; 827da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); 828da0c48c4Sopenharmony_ci 829da0c48c4Sopenharmony_ci size_t phnum; 830da0c48c4Sopenharmony_ci if (unlikely (elf_getphdrnum (mod->main.elf, &phnum) != 0)) 831da0c48c4Sopenharmony_ci return; 832da0c48c4Sopenharmony_ci 833da0c48c4Sopenharmony_ci for (size_t i = 0; i < phnum; ++i) 834da0c48c4Sopenharmony_ci { 835da0c48c4Sopenharmony_ci GElf_Phdr phdr_mem; 836da0c48c4Sopenharmony_ci GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); 837da0c48c4Sopenharmony_ci if (phdr == NULL) 838da0c48c4Sopenharmony_ci break; 839da0c48c4Sopenharmony_ci 840da0c48c4Sopenharmony_ci if (phdr->p_type == PT_DYNAMIC) 841da0c48c4Sopenharmony_ci { 842da0c48c4Sopenharmony_ci /* Examine the dynamic section for the pointers we need. */ 843da0c48c4Sopenharmony_ci 844da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, 845da0c48c4Sopenharmony_ci phdr->p_offset, phdr->p_filesz, 846da0c48c4Sopenharmony_ci ELF_T_DYN); 847da0c48c4Sopenharmony_ci if (data == NULL) 848da0c48c4Sopenharmony_ci continue; 849da0c48c4Sopenharmony_ci 850da0c48c4Sopenharmony_ci GElf_Addr addrs[i_max] = { 0, }; 851da0c48c4Sopenharmony_ci GElf_Xword strsz = 0; 852da0c48c4Sopenharmony_ci size_t n = data->d_size / gelf_fsize (mod->main.elf, 853da0c48c4Sopenharmony_ci ELF_T_DYN, 1, EV_CURRENT); 854da0c48c4Sopenharmony_ci for (size_t j = 0; j < n; ++j) 855da0c48c4Sopenharmony_ci { 856da0c48c4Sopenharmony_ci GElf_Dyn dyn_mem; 857da0c48c4Sopenharmony_ci GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); 858da0c48c4Sopenharmony_ci if (dyn != NULL) 859da0c48c4Sopenharmony_ci switch (dyn->d_tag) 860da0c48c4Sopenharmony_ci { 861da0c48c4Sopenharmony_ci case DT_SYMTAB: 862da0c48c4Sopenharmony_ci addrs[i_symtab] = dyn->d_un.d_ptr; 863da0c48c4Sopenharmony_ci continue; 864da0c48c4Sopenharmony_ci 865da0c48c4Sopenharmony_ci case DT_HASH: 866da0c48c4Sopenharmony_ci addrs[i_hash] = dyn->d_un.d_ptr; 867da0c48c4Sopenharmony_ci continue; 868da0c48c4Sopenharmony_ci 869da0c48c4Sopenharmony_ci case DT_GNU_HASH: 870da0c48c4Sopenharmony_ci addrs[i_gnu_hash] = dyn->d_un.d_ptr; 871da0c48c4Sopenharmony_ci continue; 872da0c48c4Sopenharmony_ci 873da0c48c4Sopenharmony_ci case DT_STRTAB: 874da0c48c4Sopenharmony_ci addrs[i_strtab] = dyn->d_un.d_ptr; 875da0c48c4Sopenharmony_ci continue; 876da0c48c4Sopenharmony_ci 877da0c48c4Sopenharmony_ci case DT_STRSZ: 878da0c48c4Sopenharmony_ci strsz = dyn->d_un.d_val; 879da0c48c4Sopenharmony_ci continue; 880da0c48c4Sopenharmony_ci 881da0c48c4Sopenharmony_ci default: 882da0c48c4Sopenharmony_ci continue; 883da0c48c4Sopenharmony_ci 884da0c48c4Sopenharmony_ci case DT_NULL: 885da0c48c4Sopenharmony_ci break; 886da0c48c4Sopenharmony_ci } 887da0c48c4Sopenharmony_ci break; 888da0c48c4Sopenharmony_ci } 889da0c48c4Sopenharmony_ci 890da0c48c4Sopenharmony_ci /* First try unadjusted, like ELF files from disk, vdso. 891da0c48c4Sopenharmony_ci Then try for already adjusted dynamic section, like ELF 892da0c48c4Sopenharmony_ci from remote memory. */ 893da0c48c4Sopenharmony_ci translate_offs (0, mod, phnum, addrs, strsz, ehdr); 894da0c48c4Sopenharmony_ci if (mod->symfile == NULL) 895da0c48c4Sopenharmony_ci translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr); 896da0c48c4Sopenharmony_ci 897da0c48c4Sopenharmony_ci return; 898da0c48c4Sopenharmony_ci } 899da0c48c4Sopenharmony_ci } 900da0c48c4Sopenharmony_ci} 901da0c48c4Sopenharmony_ci 902da0c48c4Sopenharmony_ci 903da0c48c4Sopenharmony_ci#if USE_LZMA 904da0c48c4Sopenharmony_ci/* Try to find the offset between the main file and .gnu_debugdata. */ 905da0c48c4Sopenharmony_cistatic bool 906da0c48c4Sopenharmony_cifind_aux_address_sync (Dwfl_Module *mod) 907da0c48c4Sopenharmony_ci{ 908da0c48c4Sopenharmony_ci /* Don't trust the phdrs in the minisymtab elf file to be setup correctly. 909da0c48c4Sopenharmony_ci The address_sync is equal to the main file it is embedded in at first. */ 910da0c48c4Sopenharmony_ci mod->aux_sym.address_sync = mod->main.address_sync; 911da0c48c4Sopenharmony_ci 912da0c48c4Sopenharmony_ci /* Adjust address_sync for the difference in entry addresses, attempting to 913da0c48c4Sopenharmony_ci account for ELF relocation changes after aux was split. */ 914da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_main, ehdr_aux; 915da0c48c4Sopenharmony_ci if (unlikely (gelf_getehdr (mod->main.elf, &ehdr_main) == NULL) 916da0c48c4Sopenharmony_ci || unlikely (gelf_getehdr (mod->aux_sym.elf, &ehdr_aux) == NULL)) 917da0c48c4Sopenharmony_ci return false; 918da0c48c4Sopenharmony_ci mod->aux_sym.address_sync += ehdr_aux.e_entry - ehdr_main.e_entry; 919da0c48c4Sopenharmony_ci 920da0c48c4Sopenharmony_ci /* The shdrs are setup OK to make find_prelink_address_sync () do the right 921da0c48c4Sopenharmony_ci thing, which is possibly more reliable, but it needs .gnu.prelink_undo. */ 922da0c48c4Sopenharmony_ci if (mod->aux_sym.address_sync != 0) 923da0c48c4Sopenharmony_ci return find_prelink_address_sync (mod, &mod->aux_sym) == DWFL_E_NOERROR; 924da0c48c4Sopenharmony_ci 925da0c48c4Sopenharmony_ci return true; 926da0c48c4Sopenharmony_ci} 927da0c48c4Sopenharmony_ci#endif 928da0c48c4Sopenharmony_ci 929da0c48c4Sopenharmony_ci/* Try to find the auxiliary symbol table embedded in the main elf file 930da0c48c4Sopenharmony_ci section .gnu_debugdata. Only matters if the symbol information comes 931da0c48c4Sopenharmony_ci from the main file dynsym. No harm done if not found. */ 932da0c48c4Sopenharmony_cistatic void 933da0c48c4Sopenharmony_cifind_aux_sym (Dwfl_Module *mod __attribute__ ((unused)), 934da0c48c4Sopenharmony_ci Elf_Scn **aux_symscn __attribute__ ((unused)), 935da0c48c4Sopenharmony_ci Elf_Scn **aux_xndxscn __attribute__ ((unused)), 936da0c48c4Sopenharmony_ci GElf_Word *aux_strshndx __attribute__ ((unused))) 937da0c48c4Sopenharmony_ci{ 938da0c48c4Sopenharmony_ci /* Since a .gnu_debugdata section is compressed using lzma don't do 939da0c48c4Sopenharmony_ci anything unless we have support for that. */ 940da0c48c4Sopenharmony_ci#if USE_LZMA 941da0c48c4Sopenharmony_ci Elf *elf = mod->main.elf; 942da0c48c4Sopenharmony_ci 943da0c48c4Sopenharmony_ci size_t shstrndx; 944da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (elf, &shstrndx) < 0) 945da0c48c4Sopenharmony_ci return; 946da0c48c4Sopenharmony_ci 947da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 948da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (elf, scn)) != NULL) 949da0c48c4Sopenharmony_ci { 950da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 951da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 952da0c48c4Sopenharmony_ci if (shdr == NULL) 953da0c48c4Sopenharmony_ci return; 954da0c48c4Sopenharmony_ci 955da0c48c4Sopenharmony_ci const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); 956da0c48c4Sopenharmony_ci if (name == NULL) 957da0c48c4Sopenharmony_ci return; 958da0c48c4Sopenharmony_ci 959da0c48c4Sopenharmony_ci if (!strcmp (name, ".gnu_debugdata")) 960da0c48c4Sopenharmony_ci break; 961da0c48c4Sopenharmony_ci } 962da0c48c4Sopenharmony_ci 963da0c48c4Sopenharmony_ci if (scn == NULL) 964da0c48c4Sopenharmony_ci return; 965da0c48c4Sopenharmony_ci 966da0c48c4Sopenharmony_ci /* Found the .gnu_debugdata section. Uncompress the lzma image and 967da0c48c4Sopenharmony_ci turn it into an ELF image. */ 968da0c48c4Sopenharmony_ci Elf_Data *rawdata = elf_rawdata (scn, NULL); 969da0c48c4Sopenharmony_ci if (rawdata == NULL) 970da0c48c4Sopenharmony_ci return; 971da0c48c4Sopenharmony_ci 972da0c48c4Sopenharmony_ci Dwfl_Error error; 973da0c48c4Sopenharmony_ci void *buffer = NULL; 974da0c48c4Sopenharmony_ci size_t size = 0; 975da0c48c4Sopenharmony_ci error = __libdw_unlzma (-1, 0, rawdata->d_buf, rawdata->d_size, 976da0c48c4Sopenharmony_ci &buffer, &size); 977da0c48c4Sopenharmony_ci if (error == DWFL_E_NOERROR) 978da0c48c4Sopenharmony_ci { 979da0c48c4Sopenharmony_ci if (unlikely (size == 0)) 980da0c48c4Sopenharmony_ci free (buffer); 981da0c48c4Sopenharmony_ci else 982da0c48c4Sopenharmony_ci { 983da0c48c4Sopenharmony_ci mod->aux_sym.elf = elf_memory (buffer, size); 984da0c48c4Sopenharmony_ci if (mod->aux_sym.elf == NULL) 985da0c48c4Sopenharmony_ci free (buffer); 986da0c48c4Sopenharmony_ci else 987da0c48c4Sopenharmony_ci { 988da0c48c4Sopenharmony_ci mod->aux_sym.fd = -1; 989da0c48c4Sopenharmony_ci mod->aux_sym.elf->flags |= ELF_F_MALLOCED; 990da0c48c4Sopenharmony_ci if (open_elf (mod, &mod->aux_sym) != DWFL_E_NOERROR) 991da0c48c4Sopenharmony_ci return; 992da0c48c4Sopenharmony_ci if (! find_aux_address_sync (mod)) 993da0c48c4Sopenharmony_ci { 994da0c48c4Sopenharmony_ci elf_end (mod->aux_sym.elf); 995da0c48c4Sopenharmony_ci mod->aux_sym.elf = NULL; 996da0c48c4Sopenharmony_ci return; 997da0c48c4Sopenharmony_ci } 998da0c48c4Sopenharmony_ci 999da0c48c4Sopenharmony_ci /* So far, so good. Get minisymtab table data and cache it. */ 1000da0c48c4Sopenharmony_ci bool minisymtab = false; 1001da0c48c4Sopenharmony_ci scn = NULL; 1002da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (mod->aux_sym.elf, scn)) != NULL) 1003da0c48c4Sopenharmony_ci { 1004da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); 1005da0c48c4Sopenharmony_ci if (shdr != NULL) 1006da0c48c4Sopenharmony_ci switch (shdr->sh_type) 1007da0c48c4Sopenharmony_ci { 1008da0c48c4Sopenharmony_ci case SHT_SYMTAB: 1009da0c48c4Sopenharmony_ci if (shdr->sh_entsize == 0) 1010da0c48c4Sopenharmony_ci return; 1011da0c48c4Sopenharmony_ci minisymtab = true; 1012da0c48c4Sopenharmony_ci *aux_symscn = scn; 1013da0c48c4Sopenharmony_ci *aux_strshndx = shdr->sh_link; 1014da0c48c4Sopenharmony_ci mod->aux_syments = shdr->sh_size / shdr->sh_entsize; 1015da0c48c4Sopenharmony_ci mod->aux_first_global = shdr->sh_info; 1016da0c48c4Sopenharmony_ci if (*aux_xndxscn != NULL) 1017da0c48c4Sopenharmony_ci return; 1018da0c48c4Sopenharmony_ci break; 1019da0c48c4Sopenharmony_ci 1020da0c48c4Sopenharmony_ci case SHT_SYMTAB_SHNDX: 1021da0c48c4Sopenharmony_ci *aux_xndxscn = scn; 1022da0c48c4Sopenharmony_ci if (minisymtab) 1023da0c48c4Sopenharmony_ci return; 1024da0c48c4Sopenharmony_ci break; 1025da0c48c4Sopenharmony_ci 1026da0c48c4Sopenharmony_ci default: 1027da0c48c4Sopenharmony_ci break; 1028da0c48c4Sopenharmony_ci } 1029da0c48c4Sopenharmony_ci } 1030da0c48c4Sopenharmony_ci 1031da0c48c4Sopenharmony_ci if (minisymtab) 1032da0c48c4Sopenharmony_ci /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */ 1033da0c48c4Sopenharmony_ci return; 1034da0c48c4Sopenharmony_ci 1035da0c48c4Sopenharmony_ci /* We found no SHT_SYMTAB, so everything else is bogus. */ 1036da0c48c4Sopenharmony_ci *aux_xndxscn = NULL; 1037da0c48c4Sopenharmony_ci *aux_strshndx = 0; 1038da0c48c4Sopenharmony_ci mod->aux_syments = 0; 1039da0c48c4Sopenharmony_ci elf_end (mod->aux_sym.elf); 1040da0c48c4Sopenharmony_ci mod->aux_sym.elf = NULL; 1041da0c48c4Sopenharmony_ci return; 1042da0c48c4Sopenharmony_ci } 1043da0c48c4Sopenharmony_ci } 1044da0c48c4Sopenharmony_ci } 1045da0c48c4Sopenharmony_ci else 1046da0c48c4Sopenharmony_ci free (buffer); 1047da0c48c4Sopenharmony_ci#endif 1048da0c48c4Sopenharmony_ci} 1049da0c48c4Sopenharmony_ci 1050da0c48c4Sopenharmony_ci/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */ 1051da0c48c4Sopenharmony_cistatic void 1052da0c48c4Sopenharmony_cifind_symtab (Dwfl_Module *mod) 1053da0c48c4Sopenharmony_ci{ 1054da0c48c4Sopenharmony_ci if (mod->symdata != NULL || mod->aux_symdata != NULL /* Already done. */ 1055da0c48c4Sopenharmony_ci || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */ 1056da0c48c4Sopenharmony_ci return; 1057da0c48c4Sopenharmony_ci 1058da0c48c4Sopenharmony_ci __libdwfl_getelf (mod); 1059da0c48c4Sopenharmony_ci mod->symerr = mod->elferr; 1060da0c48c4Sopenharmony_ci if (mod->symerr != DWFL_E_NOERROR) 1061da0c48c4Sopenharmony_ci return; 1062da0c48c4Sopenharmony_ci 1063da0c48c4Sopenharmony_ci /* First see if the main ELF file has the debugging information. */ 1064da0c48c4Sopenharmony_ci Elf_Scn *symscn = NULL, *xndxscn = NULL; 1065da0c48c4Sopenharmony_ci Elf_Scn *aux_symscn = NULL, *aux_xndxscn = NULL; 1066da0c48c4Sopenharmony_ci GElf_Word strshndx, aux_strshndx = 0; 1067da0c48c4Sopenharmony_ci mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn, 1068da0c48c4Sopenharmony_ci &xndxscn, &mod->syments, &mod->first_global, 1069da0c48c4Sopenharmony_ci &strshndx); 1070da0c48c4Sopenharmony_ci switch (mod->symerr) 1071da0c48c4Sopenharmony_ci { 1072da0c48c4Sopenharmony_ci default: 1073da0c48c4Sopenharmony_ci return; 1074da0c48c4Sopenharmony_ci 1075da0c48c4Sopenharmony_ci case DWFL_E_NOERROR: 1076da0c48c4Sopenharmony_ci break; 1077da0c48c4Sopenharmony_ci 1078da0c48c4Sopenharmony_ci case DWFL_E_NO_SYMTAB: 1079da0c48c4Sopenharmony_ci /* Now we have to look for a separate debuginfo file. */ 1080da0c48c4Sopenharmony_ci mod->symerr = find_debuginfo (mod); 1081da0c48c4Sopenharmony_ci switch (mod->symerr) 1082da0c48c4Sopenharmony_ci { 1083da0c48c4Sopenharmony_ci default: 1084da0c48c4Sopenharmony_ci return; 1085da0c48c4Sopenharmony_ci 1086da0c48c4Sopenharmony_ci case DWFL_E_NOERROR: 1087da0c48c4Sopenharmony_ci mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn, 1088da0c48c4Sopenharmony_ci &xndxscn, &mod->syments, 1089da0c48c4Sopenharmony_ci &mod->first_global, &strshndx); 1090da0c48c4Sopenharmony_ci break; 1091da0c48c4Sopenharmony_ci 1092da0c48c4Sopenharmony_ci case DWFL_E_CB: /* The find_debuginfo hook failed. */ 1093da0c48c4Sopenharmony_ci mod->symerr = DWFL_E_NO_SYMTAB; 1094da0c48c4Sopenharmony_ci break; 1095da0c48c4Sopenharmony_ci } 1096da0c48c4Sopenharmony_ci 1097da0c48c4Sopenharmony_ci switch (mod->symerr) 1098da0c48c4Sopenharmony_ci { 1099da0c48c4Sopenharmony_ci default: 1100da0c48c4Sopenharmony_ci return; 1101da0c48c4Sopenharmony_ci 1102da0c48c4Sopenharmony_ci case DWFL_E_NOERROR: 1103da0c48c4Sopenharmony_ci break; 1104da0c48c4Sopenharmony_ci 1105da0c48c4Sopenharmony_ci case DWFL_E_NO_SYMTAB: 1106da0c48c4Sopenharmony_ci /* There might be an auxiliary table. */ 1107da0c48c4Sopenharmony_ci find_aux_sym (mod, &aux_symscn, &aux_xndxscn, &aux_strshndx); 1108da0c48c4Sopenharmony_ci 1109da0c48c4Sopenharmony_ci if (symscn != NULL) 1110da0c48c4Sopenharmony_ci { 1111da0c48c4Sopenharmony_ci /* We still have the dynamic symbol table. */ 1112da0c48c4Sopenharmony_ci mod->symerr = DWFL_E_NOERROR; 1113da0c48c4Sopenharmony_ci break; 1114da0c48c4Sopenharmony_ci } 1115da0c48c4Sopenharmony_ci 1116da0c48c4Sopenharmony_ci if (aux_symscn != NULL) 1117da0c48c4Sopenharmony_ci { 1118da0c48c4Sopenharmony_ci /* We still have the auxiliary symbol table. */ 1119da0c48c4Sopenharmony_ci mod->symerr = DWFL_E_NOERROR; 1120da0c48c4Sopenharmony_ci goto aux_cache; 1121da0c48c4Sopenharmony_ci } 1122da0c48c4Sopenharmony_ci 1123da0c48c4Sopenharmony_ci /* Last ditch, look for dynamic symbols without section headers. */ 1124da0c48c4Sopenharmony_ci find_dynsym (mod); 1125da0c48c4Sopenharmony_ci return; 1126da0c48c4Sopenharmony_ci } 1127da0c48c4Sopenharmony_ci break; 1128da0c48c4Sopenharmony_ci } 1129da0c48c4Sopenharmony_ci 1130da0c48c4Sopenharmony_ci /* This does some sanity checks on the string table section. */ 1131da0c48c4Sopenharmony_ci if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) 1132da0c48c4Sopenharmony_ci { 1133da0c48c4Sopenharmony_ci elferr: 1134da0c48c4Sopenharmony_ci mod->symdata = NULL; 1135da0c48c4Sopenharmony_ci mod->syments = 0; 1136da0c48c4Sopenharmony_ci mod->first_global = 0; 1137da0c48c4Sopenharmony_ci mod->symerr = DWFL_E (LIBELF, elf_errno ()); 1138da0c48c4Sopenharmony_ci goto aux_cleanup; /* This cleans up some more and tries find_dynsym. */ 1139da0c48c4Sopenharmony_ci } 1140da0c48c4Sopenharmony_ci 1141da0c48c4Sopenharmony_ci /* Cache the data; MOD->syments and MOD->first_global were set 1142da0c48c4Sopenharmony_ci above. If any of the sections is compressed, uncompress it 1143da0c48c4Sopenharmony_ci first. Only the string data section could theoretically be 1144da0c48c4Sopenharmony_ci compressed GNU style (as .zdebug_str). Everything else only ELF 1145da0c48c4Sopenharmony_ci gabi style (SHF_COMPRESSED). */ 1146da0c48c4Sopenharmony_ci 1147da0c48c4Sopenharmony_ci Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx); 1148da0c48c4Sopenharmony_ci if (symstrscn == NULL) 1149da0c48c4Sopenharmony_ci goto elferr; 1150da0c48c4Sopenharmony_ci 1151da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 1152da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem); 1153da0c48c4Sopenharmony_ci if (shdr == NULL) 1154da0c48c4Sopenharmony_ci goto elferr; 1155da0c48c4Sopenharmony_ci 1156da0c48c4Sopenharmony_ci size_t shstrndx; 1157da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0) 1158da0c48c4Sopenharmony_ci goto elferr; 1159da0c48c4Sopenharmony_ci 1160da0c48c4Sopenharmony_ci const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name); 1161da0c48c4Sopenharmony_ci if (sname == NULL) 1162da0c48c4Sopenharmony_ci goto elferr; 1163da0c48c4Sopenharmony_ci 1164da0c48c4Sopenharmony_ci if (startswith (sname, ".zdebug")) 1165da0c48c4Sopenharmony_ci /* Try to uncompress, but it might already have been, an error 1166da0c48c4Sopenharmony_ci might just indicate, already uncompressed. */ 1167da0c48c4Sopenharmony_ci elf_compress_gnu (symstrscn, 0, 0); 1168da0c48c4Sopenharmony_ci 1169da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1170da0c48c4Sopenharmony_ci if (elf_compress (symstrscn, 0, 0) < 0) 1171da0c48c4Sopenharmony_ci goto elferr; 1172da0c48c4Sopenharmony_ci 1173da0c48c4Sopenharmony_ci mod->symstrdata = elf_getdata (symstrscn, NULL); 1174da0c48c4Sopenharmony_ci if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL) 1175da0c48c4Sopenharmony_ci goto elferr; 1176da0c48c4Sopenharmony_ci 1177da0c48c4Sopenharmony_ci if (xndxscn == NULL) 1178da0c48c4Sopenharmony_ci mod->symxndxdata = NULL; 1179da0c48c4Sopenharmony_ci else 1180da0c48c4Sopenharmony_ci { 1181da0c48c4Sopenharmony_ci shdr = gelf_getshdr (xndxscn, &shdr_mem); 1182da0c48c4Sopenharmony_ci if (shdr == NULL) 1183da0c48c4Sopenharmony_ci goto elferr; 1184da0c48c4Sopenharmony_ci 1185da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1186da0c48c4Sopenharmony_ci if (elf_compress (xndxscn, 0, 0) < 0) 1187da0c48c4Sopenharmony_ci goto elferr; 1188da0c48c4Sopenharmony_ci 1189da0c48c4Sopenharmony_ci mod->symxndxdata = elf_getdata (xndxscn, NULL); 1190da0c48c4Sopenharmony_ci if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL) 1191da0c48c4Sopenharmony_ci goto elferr; 1192da0c48c4Sopenharmony_ci } 1193da0c48c4Sopenharmony_ci 1194da0c48c4Sopenharmony_ci shdr = gelf_getshdr (symscn, &shdr_mem); 1195da0c48c4Sopenharmony_ci if (shdr == NULL) 1196da0c48c4Sopenharmony_ci goto elferr; 1197da0c48c4Sopenharmony_ci 1198da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1199da0c48c4Sopenharmony_ci if (elf_compress (symscn, 0, 0) < 0) 1200da0c48c4Sopenharmony_ci goto elferr; 1201da0c48c4Sopenharmony_ci 1202da0c48c4Sopenharmony_ci mod->symdata = elf_getdata (symscn, NULL); 1203da0c48c4Sopenharmony_ci if (mod->symdata == NULL || mod->symdata->d_buf == NULL) 1204da0c48c4Sopenharmony_ci goto elferr; 1205da0c48c4Sopenharmony_ci 1206da0c48c4Sopenharmony_ci // Sanity check number of symbols. 1207da0c48c4Sopenharmony_ci shdr = gelf_getshdr (symscn, &shdr_mem); 1208da0c48c4Sopenharmony_ci if (shdr == NULL || shdr->sh_entsize == 0 1209da0c48c4Sopenharmony_ci || mod->syments > mod->symdata->d_size / shdr->sh_entsize 1210da0c48c4Sopenharmony_ci || (size_t) mod->first_global > mod->syments) 1211da0c48c4Sopenharmony_ci goto elferr; 1212da0c48c4Sopenharmony_ci 1213da0c48c4Sopenharmony_ci /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym. */ 1214da0c48c4Sopenharmony_ci if (aux_symscn != NULL) 1215da0c48c4Sopenharmony_ci { 1216da0c48c4Sopenharmony_ci aux_cache: 1217da0c48c4Sopenharmony_ci /* This does some sanity checks on the string table section. */ 1218da0c48c4Sopenharmony_ci if (elf_strptr (mod->aux_sym.elf, aux_strshndx, 0) == NULL) 1219da0c48c4Sopenharmony_ci { 1220da0c48c4Sopenharmony_ci aux_cleanup: 1221da0c48c4Sopenharmony_ci mod->aux_syments = 0; 1222da0c48c4Sopenharmony_ci elf_end (mod->aux_sym.elf); 1223da0c48c4Sopenharmony_ci mod->aux_sym.elf = NULL; 1224da0c48c4Sopenharmony_ci /* We thought we had something through shdrs, but it failed... 1225da0c48c4Sopenharmony_ci Last ditch, look for dynamic symbols without section headers. */ 1226da0c48c4Sopenharmony_ci find_dynsym (mod); 1227da0c48c4Sopenharmony_ci return; 1228da0c48c4Sopenharmony_ci } 1229da0c48c4Sopenharmony_ci 1230da0c48c4Sopenharmony_ci Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx); 1231da0c48c4Sopenharmony_ci if (aux_strscn == NULL) 1232da0c48c4Sopenharmony_ci goto elferr; 1233da0c48c4Sopenharmony_ci 1234da0c48c4Sopenharmony_ci shdr = gelf_getshdr (aux_strscn, &shdr_mem); 1235da0c48c4Sopenharmony_ci if (shdr == NULL) 1236da0c48c4Sopenharmony_ci goto elferr; 1237da0c48c4Sopenharmony_ci 1238da0c48c4Sopenharmony_ci size_t aux_shstrndx; 1239da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0) 1240da0c48c4Sopenharmony_ci goto elferr; 1241da0c48c4Sopenharmony_ci 1242da0c48c4Sopenharmony_ci sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx, 1243da0c48c4Sopenharmony_ci shdr->sh_name); 1244da0c48c4Sopenharmony_ci if (sname == NULL) 1245da0c48c4Sopenharmony_ci goto elferr; 1246da0c48c4Sopenharmony_ci 1247da0c48c4Sopenharmony_ci if (startswith (sname, ".zdebug")) 1248da0c48c4Sopenharmony_ci /* Try to uncompress, but it might already have been, an error 1249da0c48c4Sopenharmony_ci might just indicate, already uncompressed. */ 1250da0c48c4Sopenharmony_ci elf_compress_gnu (aux_strscn, 0, 0); 1251da0c48c4Sopenharmony_ci 1252da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1253da0c48c4Sopenharmony_ci if (elf_compress (aux_strscn, 0, 0) < 0) 1254da0c48c4Sopenharmony_ci goto elferr; 1255da0c48c4Sopenharmony_ci 1256da0c48c4Sopenharmony_ci mod->aux_symstrdata = elf_getdata (aux_strscn, NULL); 1257da0c48c4Sopenharmony_ci if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL) 1258da0c48c4Sopenharmony_ci goto aux_cleanup; 1259da0c48c4Sopenharmony_ci 1260da0c48c4Sopenharmony_ci if (aux_xndxscn == NULL) 1261da0c48c4Sopenharmony_ci mod->aux_symxndxdata = NULL; 1262da0c48c4Sopenharmony_ci else 1263da0c48c4Sopenharmony_ci { 1264da0c48c4Sopenharmony_ci shdr = gelf_getshdr (aux_xndxscn, &shdr_mem); 1265da0c48c4Sopenharmony_ci if (shdr == NULL) 1266da0c48c4Sopenharmony_ci goto elferr; 1267da0c48c4Sopenharmony_ci 1268da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1269da0c48c4Sopenharmony_ci if (elf_compress (aux_xndxscn, 0, 0) < 0) 1270da0c48c4Sopenharmony_ci goto elferr; 1271da0c48c4Sopenharmony_ci 1272da0c48c4Sopenharmony_ci mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL); 1273da0c48c4Sopenharmony_ci if (mod->aux_symxndxdata == NULL 1274da0c48c4Sopenharmony_ci || mod->aux_symxndxdata->d_buf == NULL) 1275da0c48c4Sopenharmony_ci goto aux_cleanup; 1276da0c48c4Sopenharmony_ci } 1277da0c48c4Sopenharmony_ci 1278da0c48c4Sopenharmony_ci shdr = gelf_getshdr (aux_symscn, &shdr_mem); 1279da0c48c4Sopenharmony_ci if (shdr == NULL) 1280da0c48c4Sopenharmony_ci goto elferr; 1281da0c48c4Sopenharmony_ci 1282da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_COMPRESSED) != 0) 1283da0c48c4Sopenharmony_ci if (elf_compress (aux_symscn, 0, 0) < 0) 1284da0c48c4Sopenharmony_ci goto elferr; 1285da0c48c4Sopenharmony_ci 1286da0c48c4Sopenharmony_ci mod->aux_symdata = elf_getdata (aux_symscn, NULL); 1287da0c48c4Sopenharmony_ci if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL) 1288da0c48c4Sopenharmony_ci goto aux_cleanup; 1289da0c48c4Sopenharmony_ci 1290da0c48c4Sopenharmony_ci // Sanity check number of aux symbols. 1291da0c48c4Sopenharmony_ci shdr = gelf_getshdr (aux_symscn, &shdr_mem); 1292da0c48c4Sopenharmony_ci if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize 1293da0c48c4Sopenharmony_ci || (size_t) mod->aux_first_global > mod->aux_syments) 1294da0c48c4Sopenharmony_ci goto aux_cleanup; 1295da0c48c4Sopenharmony_ci } 1296da0c48c4Sopenharmony_ci} 1297da0c48c4Sopenharmony_ci 1298da0c48c4Sopenharmony_ci 1299da0c48c4Sopenharmony_ci/* Try to open a libebl backend for MOD. */ 1300da0c48c4Sopenharmony_ciDwfl_Error 1301da0c48c4Sopenharmony_ciinternal_function 1302da0c48c4Sopenharmony_ci__libdwfl_module_getebl (Dwfl_Module *mod) 1303da0c48c4Sopenharmony_ci{ 1304da0c48c4Sopenharmony_ci if (mod->ebl == NULL) 1305da0c48c4Sopenharmony_ci { 1306da0c48c4Sopenharmony_ci __libdwfl_getelf (mod); 1307da0c48c4Sopenharmony_ci if (mod->elferr != DWFL_E_NOERROR) 1308da0c48c4Sopenharmony_ci return mod->elferr; 1309da0c48c4Sopenharmony_ci 1310da0c48c4Sopenharmony_ci mod->ebl = ebl_openbackend (mod->main.elf); 1311da0c48c4Sopenharmony_ci if (mod->ebl == NULL) 1312da0c48c4Sopenharmony_ci return DWFL_E_LIBEBL; 1313da0c48c4Sopenharmony_ci } 1314da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 1315da0c48c4Sopenharmony_ci} 1316da0c48c4Sopenharmony_ci 1317da0c48c4Sopenharmony_ci/* Try to start up libdw on DEBUGFILE. */ 1318da0c48c4Sopenharmony_cistatic Dwfl_Error 1319da0c48c4Sopenharmony_ciload_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) 1320da0c48c4Sopenharmony_ci{ 1321da0c48c4Sopenharmony_ci if (mod->e_type == ET_REL && !debugfile->relocated) 1322da0c48c4Sopenharmony_ci { 1323da0c48c4Sopenharmony_ci const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; 1324da0c48c4Sopenharmony_ci 1325da0c48c4Sopenharmony_ci /* The debugging sections have to be relocated. */ 1326da0c48c4Sopenharmony_ci if (cb->section_address == NULL) 1327da0c48c4Sopenharmony_ci return DWFL_E_NOREL; 1328da0c48c4Sopenharmony_ci 1329da0c48c4Sopenharmony_ci Dwfl_Error error = __libdwfl_module_getebl (mod); 1330da0c48c4Sopenharmony_ci if (error != DWFL_E_NOERROR) 1331da0c48c4Sopenharmony_ci return error; 1332da0c48c4Sopenharmony_ci 1333da0c48c4Sopenharmony_ci find_symtab (mod); 1334da0c48c4Sopenharmony_ci Dwfl_Error result = mod->symerr; 1335da0c48c4Sopenharmony_ci if (result == DWFL_E_NOERROR) 1336da0c48c4Sopenharmony_ci result = __libdwfl_relocate (mod, debugfile->elf, true); 1337da0c48c4Sopenharmony_ci if (result != DWFL_E_NOERROR) 1338da0c48c4Sopenharmony_ci return result; 1339da0c48c4Sopenharmony_ci } 1340da0c48c4Sopenharmony_ci 1341da0c48c4Sopenharmony_ci mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL); 1342da0c48c4Sopenharmony_ci if (mod->dw == NULL) 1343da0c48c4Sopenharmony_ci { 1344da0c48c4Sopenharmony_ci int err = INTUSE(dwarf_errno) (); 1345da0c48c4Sopenharmony_ci return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); 1346da0c48c4Sopenharmony_ci } 1347da0c48c4Sopenharmony_ci 1348da0c48c4Sopenharmony_ci /* Do this after dwarf_begin_elf has a chance to process the fd. */ 1349da0c48c4Sopenharmony_ci if (mod->e_type == ET_REL && !debugfile->relocated) 1350da0c48c4Sopenharmony_ci { 1351da0c48c4Sopenharmony_ci /* Don't keep the file descriptors around. */ 1352da0c48c4Sopenharmony_ci if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) 1353da0c48c4Sopenharmony_ci { 1354da0c48c4Sopenharmony_ci close (mod->main.fd); 1355da0c48c4Sopenharmony_ci mod->main.fd = -1; 1356da0c48c4Sopenharmony_ci } 1357da0c48c4Sopenharmony_ci if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0) 1358da0c48c4Sopenharmony_ci { 1359da0c48c4Sopenharmony_ci close (debugfile->fd); 1360da0c48c4Sopenharmony_ci debugfile->fd = -1; 1361da0c48c4Sopenharmony_ci } 1362da0c48c4Sopenharmony_ci } 1363da0c48c4Sopenharmony_ci 1364da0c48c4Sopenharmony_ci /* We might have already closed the fd when we asked dwarf_begin_elf to 1365da0c48c4Sopenharmony_ci create an Dwarf. Help out a little in case we need to find an alt or 1366da0c48c4Sopenharmony_ci dwo file later. */ 1367da0c48c4Sopenharmony_ci if (mod->dw->debugdir == NULL && mod->elfdir != NULL 1368da0c48c4Sopenharmony_ci && debugfile == &mod->main) 1369da0c48c4Sopenharmony_ci mod->dw->debugdir = strdup (mod->elfdir); 1370da0c48c4Sopenharmony_ci 1371da0c48c4Sopenharmony_ci /* Until we have iterated through all CU's, we might do lazy lookups. */ 1372da0c48c4Sopenharmony_ci mod->lazycu = 1; 1373da0c48c4Sopenharmony_ci 1374da0c48c4Sopenharmony_ci return DWFL_E_NOERROR; 1375da0c48c4Sopenharmony_ci} 1376da0c48c4Sopenharmony_ci 1377da0c48c4Sopenharmony_ci/* Try to start up libdw on either the main file or the debuginfo file. */ 1378da0c48c4Sopenharmony_cistatic void 1379da0c48c4Sopenharmony_cifind_dw (Dwfl_Module *mod) 1380da0c48c4Sopenharmony_ci{ 1381da0c48c4Sopenharmony_ci if (mod->dw != NULL /* Already done. */ 1382da0c48c4Sopenharmony_ci || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */ 1383da0c48c4Sopenharmony_ci return; 1384da0c48c4Sopenharmony_ci 1385da0c48c4Sopenharmony_ci __libdwfl_getelf (mod); 1386da0c48c4Sopenharmony_ci mod->dwerr = mod->elferr; 1387da0c48c4Sopenharmony_ci if (mod->dwerr != DWFL_E_NOERROR) 1388da0c48c4Sopenharmony_ci return; 1389da0c48c4Sopenharmony_ci 1390da0c48c4Sopenharmony_ci /* First see if the main ELF file has the debugging information. */ 1391da0c48c4Sopenharmony_ci mod->dwerr = load_dw (mod, &mod->main); 1392da0c48c4Sopenharmony_ci switch (mod->dwerr) 1393da0c48c4Sopenharmony_ci { 1394da0c48c4Sopenharmony_ci case DWFL_E_NOERROR: 1395da0c48c4Sopenharmony_ci mod->debug.elf = mod->main.elf; 1396da0c48c4Sopenharmony_ci mod->debug.address_sync = mod->main.address_sync; 1397da0c48c4Sopenharmony_ci 1398da0c48c4Sopenharmony_ci /* The Dwarf might need an alt debug file, find that now after 1399da0c48c4Sopenharmony_ci everything about the debug file has been setup (the 1400da0c48c4Sopenharmony_ci find_debuginfo callback might need it). */ 1401da0c48c4Sopenharmony_ci find_debug_altlink (mod, mod->main.name); 1402da0c48c4Sopenharmony_ci return; 1403da0c48c4Sopenharmony_ci 1404da0c48c4Sopenharmony_ci case DWFL_E_NO_DWARF: 1405da0c48c4Sopenharmony_ci break; 1406da0c48c4Sopenharmony_ci 1407da0c48c4Sopenharmony_ci default: 1408da0c48c4Sopenharmony_ci goto canonicalize; 1409da0c48c4Sopenharmony_ci } 1410da0c48c4Sopenharmony_ci 1411da0c48c4Sopenharmony_ci /* Now we have to look for a separate debuginfo file. */ 1412da0c48c4Sopenharmony_ci mod->dwerr = find_debuginfo (mod); 1413da0c48c4Sopenharmony_ci switch (mod->dwerr) 1414da0c48c4Sopenharmony_ci { 1415da0c48c4Sopenharmony_ci case DWFL_E_NOERROR: 1416da0c48c4Sopenharmony_ci mod->dwerr = load_dw (mod, &mod->debug); 1417da0c48c4Sopenharmony_ci if (mod->dwerr == DWFL_E_NOERROR) 1418da0c48c4Sopenharmony_ci { 1419da0c48c4Sopenharmony_ci /* The Dwarf might need an alt debug file, find that now after 1420da0c48c4Sopenharmony_ci everything about the debug file has been setup (the 1421da0c48c4Sopenharmony_ci find_debuginfo callback might need it). */ 1422da0c48c4Sopenharmony_ci find_debug_altlink (mod, mod->debug.name); 1423da0c48c4Sopenharmony_ci return; 1424da0c48c4Sopenharmony_ci } 1425da0c48c4Sopenharmony_ci 1426da0c48c4Sopenharmony_ci break; 1427da0c48c4Sopenharmony_ci 1428da0c48c4Sopenharmony_ci case DWFL_E_CB: /* The find_debuginfo hook failed. */ 1429da0c48c4Sopenharmony_ci mod->dwerr = DWFL_E_NO_DWARF; 1430da0c48c4Sopenharmony_ci return; 1431da0c48c4Sopenharmony_ci 1432da0c48c4Sopenharmony_ci default: 1433da0c48c4Sopenharmony_ci break; 1434da0c48c4Sopenharmony_ci } 1435da0c48c4Sopenharmony_ci 1436da0c48c4Sopenharmony_ci canonicalize: 1437da0c48c4Sopenharmony_ci mod->dwerr = __libdwfl_canon_error (mod->dwerr); 1438da0c48c4Sopenharmony_ci} 1439da0c48c4Sopenharmony_ci 1440da0c48c4Sopenharmony_ciDwarf * 1441da0c48c4Sopenharmony_cidwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias) 1442da0c48c4Sopenharmony_ci{ 1443da0c48c4Sopenharmony_ci if (mod == NULL) 1444da0c48c4Sopenharmony_ci return NULL; 1445da0c48c4Sopenharmony_ci 1446da0c48c4Sopenharmony_ci find_dw (mod); 1447da0c48c4Sopenharmony_ci if (mod->dwerr == DWFL_E_NOERROR) 1448da0c48c4Sopenharmony_ci { 1449da0c48c4Sopenharmony_ci /* If dwfl_module_getelf was used previously, then partial apply 1450da0c48c4Sopenharmony_ci relocation to miscellaneous sections in the debug file too. */ 1451da0c48c4Sopenharmony_ci if (mod->e_type == ET_REL 1452da0c48c4Sopenharmony_ci && mod->main.relocated && ! mod->debug.relocated) 1453da0c48c4Sopenharmony_ci { 1454da0c48c4Sopenharmony_ci mod->debug.relocated = true; 1455da0c48c4Sopenharmony_ci if (mod->debug.elf != mod->main.elf) 1456da0c48c4Sopenharmony_ci (void) __libdwfl_relocate (mod, mod->debug.elf, false); 1457da0c48c4Sopenharmony_ci } 1458da0c48c4Sopenharmony_ci 1459da0c48c4Sopenharmony_ci *bias = dwfl_adjusted_dwarf_addr (mod, 0); 1460da0c48c4Sopenharmony_ci return mod->dw; 1461da0c48c4Sopenharmony_ci } 1462da0c48c4Sopenharmony_ci 1463da0c48c4Sopenharmony_ci __libdwfl_seterrno (mod->dwerr); 1464da0c48c4Sopenharmony_ci return NULL; 1465da0c48c4Sopenharmony_ci} 1466da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getdwarf) 1467da0c48c4Sopenharmony_ci 1468da0c48c4Sopenharmony_ciint 1469da0c48c4Sopenharmony_cidwfl_module_getsymtab (Dwfl_Module *mod) 1470da0c48c4Sopenharmony_ci{ 1471da0c48c4Sopenharmony_ci if (mod == NULL) 1472da0c48c4Sopenharmony_ci return -1; 1473da0c48c4Sopenharmony_ci 1474da0c48c4Sopenharmony_ci find_symtab (mod); 1475da0c48c4Sopenharmony_ci if (mod->symerr == DWFL_E_NOERROR) 1476da0c48c4Sopenharmony_ci /* We will skip the auxiliary zero entry if there is another one. */ 1477da0c48c4Sopenharmony_ci return (mod->syments + mod->aux_syments 1478da0c48c4Sopenharmony_ci - (mod->syments > 0 && mod->aux_syments > 0 ? 1 : 0)); 1479da0c48c4Sopenharmony_ci 1480da0c48c4Sopenharmony_ci __libdwfl_seterrno (mod->symerr); 1481da0c48c4Sopenharmony_ci return -1; 1482da0c48c4Sopenharmony_ci} 1483da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsymtab) 1484da0c48c4Sopenharmony_ci 1485da0c48c4Sopenharmony_ciint 1486da0c48c4Sopenharmony_cidwfl_module_getsymtab_first_global (Dwfl_Module *mod) 1487da0c48c4Sopenharmony_ci{ 1488da0c48c4Sopenharmony_ci if (mod == NULL) 1489da0c48c4Sopenharmony_ci return -1; 1490da0c48c4Sopenharmony_ci 1491da0c48c4Sopenharmony_ci find_symtab (mod); 1492da0c48c4Sopenharmony_ci if (mod->symerr == DWFL_E_NOERROR) 1493da0c48c4Sopenharmony_ci { 1494da0c48c4Sopenharmony_ci /* All local symbols should come before all global symbols. If 1495da0c48c4Sopenharmony_ci we have an auxiliary table make sure all the main locals come 1496da0c48c4Sopenharmony_ci first, then all aux locals, then all main globals and finally all 1497da0c48c4Sopenharmony_ci aux globals. And skip the auxiliary table zero undefined 1498da0c48c4Sopenharmony_ci entry. */ 1499da0c48c4Sopenharmony_ci int skip_aux_zero = (mod->syments > 0 && mod->aux_syments > 0) ? 1 : 0; 1500da0c48c4Sopenharmony_ci return mod->first_global + mod->aux_first_global - skip_aux_zero; 1501da0c48c4Sopenharmony_ci } 1502da0c48c4Sopenharmony_ci 1503da0c48c4Sopenharmony_ci __libdwfl_seterrno (mod->symerr); 1504da0c48c4Sopenharmony_ci return -1; 1505da0c48c4Sopenharmony_ci} 1506da0c48c4Sopenharmony_ciINTDEF (dwfl_module_getsymtab_first_global) 1507