1da0c48c4Sopenharmony_ci/* Locate source files or functions which caused text relocations. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2010, 2012, 2014, 2018 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2005. 5da0c48c4Sopenharmony_ci 6da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 7da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 8da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 9da0c48c4Sopenharmony_ci (at your option) any later version. 10da0c48c4Sopenharmony_ci 11da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 12da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 13da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14da0c48c4Sopenharmony_ci GNU General Public License for more details. 15da0c48c4Sopenharmony_ci 16da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 17da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18da0c48c4Sopenharmony_ci 19da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 20da0c48c4Sopenharmony_ci# include <config.h> 21da0c48c4Sopenharmony_ci#endif 22da0c48c4Sopenharmony_ci 23da0c48c4Sopenharmony_ci#include <argp.h> 24da0c48c4Sopenharmony_ci#include <assert.h> 25da0c48c4Sopenharmony_ci#include <errno.h> 26da0c48c4Sopenharmony_ci#include <fcntl.h> 27da0c48c4Sopenharmony_ci#include <gelf.h> 28da0c48c4Sopenharmony_ci#include <libdw.h> 29da0c48c4Sopenharmony_ci#include <locale.h> 30da0c48c4Sopenharmony_ci#include <search.h> 31da0c48c4Sopenharmony_ci#include <stdbool.h> 32da0c48c4Sopenharmony_ci#include <stdio.h> 33da0c48c4Sopenharmony_ci#include <stdlib.h> 34da0c48c4Sopenharmony_ci#include <string.h> 35da0c48c4Sopenharmony_ci#include <unistd.h> 36da0c48c4Sopenharmony_ci 37da0c48c4Sopenharmony_ci#include <printversion.h> 38da0c48c4Sopenharmony_ci#include "libeu.h" 39da0c48c4Sopenharmony_ci#include "system.h" 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_cistruct segments 42da0c48c4Sopenharmony_ci{ 43da0c48c4Sopenharmony_ci GElf_Addr from; 44da0c48c4Sopenharmony_ci GElf_Addr to; 45da0c48c4Sopenharmony_ci}; 46da0c48c4Sopenharmony_ci 47da0c48c4Sopenharmony_ci 48da0c48c4Sopenharmony_ci/* Name and version of program. */ 49da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci/* Bug report address. */ 52da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 53da0c48c4Sopenharmony_ci 54da0c48c4Sopenharmony_ci/* Values for the parameters which have no short form. */ 55da0c48c4Sopenharmony_ci#define OPT_DEBUGINFO 0x100 56da0c48c4Sopenharmony_ci 57da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions. */ 58da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 59da0c48c4Sopenharmony_ci{ 60da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Input Selection:"), 0 }, 61da0c48c4Sopenharmony_ci { "root", 'r', "PATH", 0, N_("Prepend PATH to all file names"), 0 }, 62da0c48c4Sopenharmony_ci { "debuginfo", OPT_DEBUGINFO, "PATH", 0, 63da0c48c4Sopenharmony_ci N_("Use PATH as root of debuginfo hierarchy"), 0 }, 64da0c48c4Sopenharmony_ci 65da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 66da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 67da0c48c4Sopenharmony_ci}; 68da0c48c4Sopenharmony_ci 69da0c48c4Sopenharmony_ci/* Short description of program. */ 70da0c48c4Sopenharmony_cistatic const char doc[] = N_("\ 71da0c48c4Sopenharmony_ciLocate source of text relocations in FILEs (a.out by default)."); 72da0c48c4Sopenharmony_ci 73da0c48c4Sopenharmony_ci/* Strings for arguments in help texts. */ 74da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[FILE...]"); 75da0c48c4Sopenharmony_ci 76da0c48c4Sopenharmony_ci/* Prototype for option handler. */ 77da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state); 78da0c48c4Sopenharmony_ci 79da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions. */ 80da0c48c4Sopenharmony_cistatic struct argp argp = 81da0c48c4Sopenharmony_ci{ 82da0c48c4Sopenharmony_ci options, parse_opt, args_doc, doc, NULL, NULL, NULL 83da0c48c4Sopenharmony_ci}; 84da0c48c4Sopenharmony_ci 85da0c48c4Sopenharmony_ci 86da0c48c4Sopenharmony_ci/* Print symbols in file named FNAME. */ 87da0c48c4Sopenharmony_cistatic int process_file (const char *fname, bool more_than_one); 88da0c48c4Sopenharmony_ci 89da0c48c4Sopenharmony_ci/* Check for text relocations in the given file. The segment 90da0c48c4Sopenharmony_ci information is known. */ 91da0c48c4Sopenharmony_cistatic void check_rel (size_t nsegments, struct segments segments[nsegments], 92da0c48c4Sopenharmony_ci GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw, 93da0c48c4Sopenharmony_ci const char *fname, bool more_than_one, 94da0c48c4Sopenharmony_ci void **knownsrcs); 95da0c48c4Sopenharmony_ci 96da0c48c4Sopenharmony_ci 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_ci/* User-provided root directory. */ 99da0c48c4Sopenharmony_cistatic const char *rootdir = "/"; 100da0c48c4Sopenharmony_ci 101da0c48c4Sopenharmony_ci/* Root of debuginfo directory hierarchy. */ 102da0c48c4Sopenharmony_cistatic const char *debuginfo_root; 103da0c48c4Sopenharmony_ci 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ciint 106da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 107da0c48c4Sopenharmony_ci{ 108da0c48c4Sopenharmony_ci int remaining; 109da0c48c4Sopenharmony_ci int result = 0; 110da0c48c4Sopenharmony_ci 111da0c48c4Sopenharmony_ci /* Set locale. */ 112da0c48c4Sopenharmony_ci (void) setlocale (LC_ALL, ""); 113da0c48c4Sopenharmony_ci 114da0c48c4Sopenharmony_ci /* Make sure the message catalog can be found. */ 115da0c48c4Sopenharmony_ci (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 116da0c48c4Sopenharmony_ci 117da0c48c4Sopenharmony_ci /* Initialize the message catalog. */ 118da0c48c4Sopenharmony_ci (void) textdomain (PACKAGE_TARNAME); 119da0c48c4Sopenharmony_ci 120da0c48c4Sopenharmony_ci /* Parse and process arguments. */ 121da0c48c4Sopenharmony_ci (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ci /* Tell the library which version we are expecting. */ 124da0c48c4Sopenharmony_ci elf_version (EV_CURRENT); 125da0c48c4Sopenharmony_ci 126da0c48c4Sopenharmony_ci /* If the user has not specified the root directory for the 127da0c48c4Sopenharmony_ci debuginfo hierarchy, we have to determine it ourselves. */ 128da0c48c4Sopenharmony_ci if (debuginfo_root == NULL) 129da0c48c4Sopenharmony_ci { 130da0c48c4Sopenharmony_ci // XXX The runtime should provide this information. 131da0c48c4Sopenharmony_ci#if defined __ia64__ || defined __alpha__ 132da0c48c4Sopenharmony_ci debuginfo_root = "/usr/lib/debug"; 133da0c48c4Sopenharmony_ci#else 134da0c48c4Sopenharmony_ci debuginfo_root = (sizeof (long int) == 4 135da0c48c4Sopenharmony_ci ? "/usr/lib/debug" : "/usr/lib64/debug"); 136da0c48c4Sopenharmony_ci#endif 137da0c48c4Sopenharmony_ci } 138da0c48c4Sopenharmony_ci 139da0c48c4Sopenharmony_ci if (remaining == argc) 140da0c48c4Sopenharmony_ci result = process_file ("a.out", false); 141da0c48c4Sopenharmony_ci else 142da0c48c4Sopenharmony_ci { 143da0c48c4Sopenharmony_ci /* Process all the remaining files. */ 144da0c48c4Sopenharmony_ci const bool more_than_one = remaining + 1 < argc; 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_ci do 147da0c48c4Sopenharmony_ci result |= process_file (argv[remaining], more_than_one); 148da0c48c4Sopenharmony_ci while (++remaining < argc); 149da0c48c4Sopenharmony_ci } 150da0c48c4Sopenharmony_ci 151da0c48c4Sopenharmony_ci return result; 152da0c48c4Sopenharmony_ci} 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci 155da0c48c4Sopenharmony_ci/* Handle program arguments. */ 156da0c48c4Sopenharmony_cistatic error_t 157da0c48c4Sopenharmony_ciparse_opt (int key, char *arg, 158da0c48c4Sopenharmony_ci struct argp_state *state __attribute__ ((unused))) 159da0c48c4Sopenharmony_ci{ 160da0c48c4Sopenharmony_ci switch (key) 161da0c48c4Sopenharmony_ci { 162da0c48c4Sopenharmony_ci case 'r': 163da0c48c4Sopenharmony_ci rootdir = arg; 164da0c48c4Sopenharmony_ci break; 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci case OPT_DEBUGINFO: 167da0c48c4Sopenharmony_ci debuginfo_root = arg; 168da0c48c4Sopenharmony_ci break; 169da0c48c4Sopenharmony_ci 170da0c48c4Sopenharmony_ci default: 171da0c48c4Sopenharmony_ci return ARGP_ERR_UNKNOWN; 172da0c48c4Sopenharmony_ci } 173da0c48c4Sopenharmony_ci return 0; 174da0c48c4Sopenharmony_ci} 175da0c48c4Sopenharmony_ci 176da0c48c4Sopenharmony_ci 177da0c48c4Sopenharmony_cistatic void 178da0c48c4Sopenharmony_cinoop (void *arg __attribute__ ((unused))) 179da0c48c4Sopenharmony_ci{ 180da0c48c4Sopenharmony_ci} 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci 183da0c48c4Sopenharmony_cistatic int 184da0c48c4Sopenharmony_ciopen_rootdir_file (const char *fname) 185da0c48c4Sopenharmony_ci{ 186da0c48c4Sopenharmony_ci char *new_fname = NULL; 187da0c48c4Sopenharmony_ci const char *real_fname = fname; 188da0c48c4Sopenharmony_ci 189da0c48c4Sopenharmony_ci if (fname[0] == '/' && (rootdir[0] != '/' || rootdir[1] != '\0')) 190da0c48c4Sopenharmony_ci real_fname = new_fname = xasprintf ("%s/%s", rootdir, fname); 191da0c48c4Sopenharmony_ci 192da0c48c4Sopenharmony_ci int fd = open (real_fname, O_RDONLY); 193da0c48c4Sopenharmony_ci if (fd == -1) 194da0c48c4Sopenharmony_ci error (0, errno, _("cannot open '%s'"), fname); 195da0c48c4Sopenharmony_ci 196da0c48c4Sopenharmony_ci free (new_fname); 197da0c48c4Sopenharmony_ci return fd; 198da0c48c4Sopenharmony_ci} 199da0c48c4Sopenharmony_ci 200da0c48c4Sopenharmony_ci 201da0c48c4Sopenharmony_cistatic int 202da0c48c4Sopenharmony_ciprocess_file (const char *fname, bool more_than_one) 203da0c48c4Sopenharmony_ci{ 204da0c48c4Sopenharmony_ci int result = 0; 205da0c48c4Sopenharmony_ci void *knownsrcs = NULL; 206da0c48c4Sopenharmony_ci int fd = open_rootdir_file (fname); 207da0c48c4Sopenharmony_ci if (fd == -1) 208da0c48c4Sopenharmony_ci return 1; 209da0c48c4Sopenharmony_ci 210da0c48c4Sopenharmony_ci Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); 211da0c48c4Sopenharmony_ci if (elf == NULL) 212da0c48c4Sopenharmony_ci { 213da0c48c4Sopenharmony_ci error (0, 0, _("cannot create ELF descriptor for '%s': %s"), 214da0c48c4Sopenharmony_ci fname, elf_errmsg (-1)); 215da0c48c4Sopenharmony_ci goto err_close; 216da0c48c4Sopenharmony_ci } 217da0c48c4Sopenharmony_ci 218da0c48c4Sopenharmony_ci /* Make sure the file is a DSO. */ 219da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem; 220da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 221da0c48c4Sopenharmony_ci if (ehdr == NULL) 222da0c48c4Sopenharmony_ci { 223da0c48c4Sopenharmony_ci error (0, 0, _("cannot get ELF header '%s': %s"), 224da0c48c4Sopenharmony_ci fname, elf_errmsg (-1)); 225da0c48c4Sopenharmony_ci err_elf_close: 226da0c48c4Sopenharmony_ci elf_end (elf); 227da0c48c4Sopenharmony_ci err_close: 228da0c48c4Sopenharmony_ci close (fd); 229da0c48c4Sopenharmony_ci return 1; 230da0c48c4Sopenharmony_ci } 231da0c48c4Sopenharmony_ci 232da0c48c4Sopenharmony_ci if (ehdr->e_type != ET_DYN) 233da0c48c4Sopenharmony_ci { 234da0c48c4Sopenharmony_ci error (0, 0, _("'%s' is not a DSO or PIE"), fname); 235da0c48c4Sopenharmony_ci goto err_elf_close; 236da0c48c4Sopenharmony_ci } 237da0c48c4Sopenharmony_ci 238da0c48c4Sopenharmony_ci /* Determine whether the DSO has text relocations at all and locate 239da0c48c4Sopenharmony_ci the symbol table. */ 240da0c48c4Sopenharmony_ci Elf_Scn *symscn = NULL; 241da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 242da0c48c4Sopenharmony_ci bool seen_dynamic = false; 243da0c48c4Sopenharmony_ci bool have_textrel = false; 244da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (elf, scn)) != NULL 245da0c48c4Sopenharmony_ci && (!seen_dynamic || symscn == NULL)) 246da0c48c4Sopenharmony_ci { 247da0c48c4Sopenharmony_ci /* Handle the section if it is a symbol table. */ 248da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 249da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 250da0c48c4Sopenharmony_ci 251da0c48c4Sopenharmony_ci if (shdr == NULL) 252da0c48c4Sopenharmony_ci { 253da0c48c4Sopenharmony_ci error (0, 0, 254da0c48c4Sopenharmony_ci _("getting get section header of section %zu: %s"), 255da0c48c4Sopenharmony_ci elf_ndxscn (scn), elf_errmsg (-1)); 256da0c48c4Sopenharmony_ci goto err_elf_close; 257da0c48c4Sopenharmony_ci } 258da0c48c4Sopenharmony_ci 259da0c48c4Sopenharmony_ci switch (shdr->sh_type) 260da0c48c4Sopenharmony_ci { 261da0c48c4Sopenharmony_ci case SHT_DYNAMIC: 262da0c48c4Sopenharmony_ci if (!seen_dynamic) 263da0c48c4Sopenharmony_ci { 264da0c48c4Sopenharmony_ci seen_dynamic = true; 265da0c48c4Sopenharmony_ci 266da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata (scn, NULL); 267da0c48c4Sopenharmony_ci size_t entries = (shdr->sh_entsize == 0 268da0c48c4Sopenharmony_ci ? 0 : shdr->sh_size / shdr->sh_entsize); 269da0c48c4Sopenharmony_ci 270da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < entries; ++cnt) 271da0c48c4Sopenharmony_ci { 272da0c48c4Sopenharmony_ci GElf_Dyn dynmem; 273da0c48c4Sopenharmony_ci GElf_Dyn *dyn; 274da0c48c4Sopenharmony_ci 275da0c48c4Sopenharmony_ci dyn = gelf_getdyn (data, cnt, &dynmem); 276da0c48c4Sopenharmony_ci if (dyn == NULL) 277da0c48c4Sopenharmony_ci { 278da0c48c4Sopenharmony_ci error (0, 0, _("cannot read dynamic section: %s"), 279da0c48c4Sopenharmony_ci elf_errmsg (-1)); 280da0c48c4Sopenharmony_ci goto err_elf_close; 281da0c48c4Sopenharmony_ci } 282da0c48c4Sopenharmony_ci 283da0c48c4Sopenharmony_ci if (dyn->d_tag == DT_TEXTREL 284da0c48c4Sopenharmony_ci || (dyn->d_tag == DT_FLAGS 285da0c48c4Sopenharmony_ci && (dyn->d_un.d_val & DF_TEXTREL) != 0)) 286da0c48c4Sopenharmony_ci have_textrel = true; 287da0c48c4Sopenharmony_ci } 288da0c48c4Sopenharmony_ci } 289da0c48c4Sopenharmony_ci break; 290da0c48c4Sopenharmony_ci 291da0c48c4Sopenharmony_ci case SHT_SYMTAB: 292da0c48c4Sopenharmony_ci symscn = scn; 293da0c48c4Sopenharmony_ci break; 294da0c48c4Sopenharmony_ci } 295da0c48c4Sopenharmony_ci } 296da0c48c4Sopenharmony_ci 297da0c48c4Sopenharmony_ci if (!have_textrel) 298da0c48c4Sopenharmony_ci { 299da0c48c4Sopenharmony_ci error (0, 0, _("no text relocations reported in '%s'"), fname); 300da0c48c4Sopenharmony_ci goto err_elf_close; 301da0c48c4Sopenharmony_ci } 302da0c48c4Sopenharmony_ci 303da0c48c4Sopenharmony_ci int fd2 = -1; 304da0c48c4Sopenharmony_ci Elf *elf2 = NULL; 305da0c48c4Sopenharmony_ci /* Get the address ranges for the loaded segments. */ 306da0c48c4Sopenharmony_ci size_t nsegments_max = 10; 307da0c48c4Sopenharmony_ci size_t nsegments = 0; 308da0c48c4Sopenharmony_ci struct segments *segments = malloc (nsegments_max * sizeof (segments[0])); 309da0c48c4Sopenharmony_ci if (segments == NULL) 310da0c48c4Sopenharmony_ci error (1, errno, _("while reading ELF file")); 311da0c48c4Sopenharmony_ci 312da0c48c4Sopenharmony_ci size_t phnum; 313da0c48c4Sopenharmony_ci if (elf_getphdrnum (elf, &phnum) != 0) 314da0c48c4Sopenharmony_ci error (1, 0, _("cannot get program header count: %s"), 315da0c48c4Sopenharmony_ci elf_errmsg (-1)); 316da0c48c4Sopenharmony_ci 317da0c48c4Sopenharmony_ci 318da0c48c4Sopenharmony_ci for (size_t i = 0; i < phnum; ++i) 319da0c48c4Sopenharmony_ci { 320da0c48c4Sopenharmony_ci GElf_Phdr phdr_mem; 321da0c48c4Sopenharmony_ci GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); 322da0c48c4Sopenharmony_ci if (phdr == NULL) 323da0c48c4Sopenharmony_ci { 324da0c48c4Sopenharmony_ci error (0, 0, 325da0c48c4Sopenharmony_ci _("cannot get program header index at offset %zd: %s"), 326da0c48c4Sopenharmony_ci i, elf_errmsg (-1)); 327da0c48c4Sopenharmony_ci result = 1; 328da0c48c4Sopenharmony_ci goto next; 329da0c48c4Sopenharmony_ci } 330da0c48c4Sopenharmony_ci 331da0c48c4Sopenharmony_ci if (phdr->p_type == PT_LOAD && (phdr->p_flags & PF_W) == 0) 332da0c48c4Sopenharmony_ci { 333da0c48c4Sopenharmony_ci if (nsegments == nsegments_max) 334da0c48c4Sopenharmony_ci { 335da0c48c4Sopenharmony_ci nsegments_max *= 2; 336da0c48c4Sopenharmony_ci segments 337da0c48c4Sopenharmony_ci = realloc (segments, nsegments_max * sizeof (segments[0])); 338da0c48c4Sopenharmony_ci if (segments == NULL) 339da0c48c4Sopenharmony_ci { 340da0c48c4Sopenharmony_ci error (0, 0, _("\ 341da0c48c4Sopenharmony_cicannot get program header index at offset %zd: %s"), 342da0c48c4Sopenharmony_ci i, elf_errmsg (-1)); 343da0c48c4Sopenharmony_ci result = 1; 344da0c48c4Sopenharmony_ci goto next; 345da0c48c4Sopenharmony_ci } 346da0c48c4Sopenharmony_ci } 347da0c48c4Sopenharmony_ci 348da0c48c4Sopenharmony_ci segments[nsegments].from = phdr->p_vaddr; 349da0c48c4Sopenharmony_ci segments[nsegments].to = phdr->p_vaddr + phdr->p_memsz; 350da0c48c4Sopenharmony_ci ++nsegments; 351da0c48c4Sopenharmony_ci } 352da0c48c4Sopenharmony_ci } 353da0c48c4Sopenharmony_ci 354da0c48c4Sopenharmony_ci if (nsegments > 0) 355da0c48c4Sopenharmony_ci { 356da0c48c4Sopenharmony_ci 357da0c48c4Sopenharmony_ci Dwarf *dw = dwarf_begin_elf (elf, DWARF_C_READ, NULL); 358da0c48c4Sopenharmony_ci /* Look for debuginfo files if the information is not the in 359da0c48c4Sopenharmony_ci opened file itself. This makes only sense if the input file 360da0c48c4Sopenharmony_ci is specified with an absolute path. */ 361da0c48c4Sopenharmony_ci if (dw == NULL && fname[0] == '/') 362da0c48c4Sopenharmony_ci { 363da0c48c4Sopenharmony_ci char *difname = 364da0c48c4Sopenharmony_ci xasprintf("%s%s/%s.debug", rootdir, debuginfo_root, fname); 365da0c48c4Sopenharmony_ci fd2 = open (difname, O_RDONLY); 366da0c48c4Sopenharmony_ci free (difname); 367da0c48c4Sopenharmony_ci if (fd2 != -1 368da0c48c4Sopenharmony_ci && (elf2 = elf_begin (fd2, ELF_C_READ_MMAP, NULL)) != NULL) 369da0c48c4Sopenharmony_ci dw = dwarf_begin_elf (elf2, DWARF_C_READ, NULL); 370da0c48c4Sopenharmony_ci } 371da0c48c4Sopenharmony_ci 372da0c48c4Sopenharmony_ci /* Look at all relocations and determine which modify 373da0c48c4Sopenharmony_ci write-protected segments. */ 374da0c48c4Sopenharmony_ci scn = NULL; 375da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (elf, scn)) != NULL) 376da0c48c4Sopenharmony_ci { 377da0c48c4Sopenharmony_ci /* Handle the section if it is a symbol table. */ 378da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 379da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 380da0c48c4Sopenharmony_ci 381da0c48c4Sopenharmony_ci if (shdr == NULL) 382da0c48c4Sopenharmony_ci { 383da0c48c4Sopenharmony_ci error (0, 0, 384da0c48c4Sopenharmony_ci _("cannot get section header of section %zu: %s"), 385da0c48c4Sopenharmony_ci elf_ndxscn (scn), elf_errmsg (-1)); 386da0c48c4Sopenharmony_ci result = 1; 387da0c48c4Sopenharmony_ci goto next; 388da0c48c4Sopenharmony_ci } 389da0c48c4Sopenharmony_ci 390da0c48c4Sopenharmony_ci if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) 391da0c48c4Sopenharmony_ci && symscn == NULL) 392da0c48c4Sopenharmony_ci { 393da0c48c4Sopenharmony_ci symscn = elf_getscn (elf, shdr->sh_link); 394da0c48c4Sopenharmony_ci if (symscn == NULL) 395da0c48c4Sopenharmony_ci { 396da0c48c4Sopenharmony_ci error (0, 0, _("\ 397da0c48c4Sopenharmony_cicannot get symbol table section %zu in '%s': %s"), 398da0c48c4Sopenharmony_ci (size_t) shdr->sh_link, fname, elf_errmsg (-1)); 399da0c48c4Sopenharmony_ci result = 1; 400da0c48c4Sopenharmony_ci goto next; 401da0c48c4Sopenharmony_ci } 402da0c48c4Sopenharmony_ci } 403da0c48c4Sopenharmony_ci 404da0c48c4Sopenharmony_ci if (shdr->sh_type == SHT_REL) 405da0c48c4Sopenharmony_ci { 406da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata (scn, NULL); 407da0c48c4Sopenharmony_ci size_t entries = (shdr->sh_entsize == 0 408da0c48c4Sopenharmony_ci ? 0 : shdr->sh_size / shdr->sh_entsize); 409da0c48c4Sopenharmony_ci 410da0c48c4Sopenharmony_ci for (int cnt = 0; 411da0c48c4Sopenharmony_ci (size_t) cnt < entries; ++cnt) 412da0c48c4Sopenharmony_ci { 413da0c48c4Sopenharmony_ci GElf_Rel rel_mem; 414da0c48c4Sopenharmony_ci GElf_Rel *rel = gelf_getrel (data, cnt, &rel_mem); 415da0c48c4Sopenharmony_ci if (rel == NULL) 416da0c48c4Sopenharmony_ci { 417da0c48c4Sopenharmony_ci error (0, 0, _("\ 418da0c48c4Sopenharmony_cicannot get relocation at index %d in section %zu in '%s': %s"), 419da0c48c4Sopenharmony_ci cnt, elf_ndxscn (scn), fname, elf_errmsg (-1)); 420da0c48c4Sopenharmony_ci result = 1; 421da0c48c4Sopenharmony_ci goto next; 422da0c48c4Sopenharmony_ci } 423da0c48c4Sopenharmony_ci 424da0c48c4Sopenharmony_ci check_rel (nsegments, segments, rel->r_offset, elf, 425da0c48c4Sopenharmony_ci symscn, dw, fname, more_than_one, &knownsrcs); 426da0c48c4Sopenharmony_ci } 427da0c48c4Sopenharmony_ci } 428da0c48c4Sopenharmony_ci else if (shdr->sh_type == SHT_RELA) 429da0c48c4Sopenharmony_ci { 430da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata (scn, NULL); 431da0c48c4Sopenharmony_ci size_t entries = (shdr->sh_entsize == 0 432da0c48c4Sopenharmony_ci ? 0 : shdr->sh_size / shdr->sh_entsize); 433da0c48c4Sopenharmony_ci 434da0c48c4Sopenharmony_ci for (int cnt = 0; (size_t) cnt < entries; ++cnt) 435da0c48c4Sopenharmony_ci { 436da0c48c4Sopenharmony_ci GElf_Rela rela_mem; 437da0c48c4Sopenharmony_ci GElf_Rela *rela = gelf_getrela (data, cnt, &rela_mem); 438da0c48c4Sopenharmony_ci if (rela == NULL) 439da0c48c4Sopenharmony_ci { 440da0c48c4Sopenharmony_ci error (0, 0, _("\ 441da0c48c4Sopenharmony_cicannot get relocation at index %d in section %zu in '%s': %s"), 442da0c48c4Sopenharmony_ci cnt, elf_ndxscn (scn), fname, elf_errmsg (-1)); 443da0c48c4Sopenharmony_ci result = 1; 444da0c48c4Sopenharmony_ci goto next; 445da0c48c4Sopenharmony_ci } 446da0c48c4Sopenharmony_ci 447da0c48c4Sopenharmony_ci check_rel (nsegments, segments, rela->r_offset, elf, 448da0c48c4Sopenharmony_ci symscn, dw, fname, more_than_one, &knownsrcs); 449da0c48c4Sopenharmony_ci } 450da0c48c4Sopenharmony_ci } 451da0c48c4Sopenharmony_ci } 452da0c48c4Sopenharmony_ci 453da0c48c4Sopenharmony_ci dwarf_end (dw); 454da0c48c4Sopenharmony_ci } 455da0c48c4Sopenharmony_ci 456da0c48c4Sopenharmony_ci next: 457da0c48c4Sopenharmony_ci elf_end (elf); 458da0c48c4Sopenharmony_ci elf_end (elf2); 459da0c48c4Sopenharmony_ci close (fd); 460da0c48c4Sopenharmony_ci if (fd2 != -1) 461da0c48c4Sopenharmony_ci close (fd2); 462da0c48c4Sopenharmony_ci 463da0c48c4Sopenharmony_ci free (segments); 464da0c48c4Sopenharmony_ci tdestroy (knownsrcs, noop); 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci return result; 467da0c48c4Sopenharmony_ci} 468da0c48c4Sopenharmony_ci 469da0c48c4Sopenharmony_ci 470da0c48c4Sopenharmony_cistatic int 471da0c48c4Sopenharmony_ciptrcompare (const void *p1, const void *p2) 472da0c48c4Sopenharmony_ci{ 473da0c48c4Sopenharmony_ci if ((uintptr_t) p1 < (uintptr_t) p2) 474da0c48c4Sopenharmony_ci return -1; 475da0c48c4Sopenharmony_ci if ((uintptr_t) p1 > (uintptr_t) p2) 476da0c48c4Sopenharmony_ci return 1; 477da0c48c4Sopenharmony_ci return 0; 478da0c48c4Sopenharmony_ci} 479da0c48c4Sopenharmony_ci 480da0c48c4Sopenharmony_ci 481da0c48c4Sopenharmony_cistatic void 482da0c48c4Sopenharmony_cicheck_rel (size_t nsegments, struct segments segments[nsegments], 483da0c48c4Sopenharmony_ci GElf_Addr addr, Elf *elf, Elf_Scn *symscn, Dwarf *dw, 484da0c48c4Sopenharmony_ci const char *fname, bool more_than_one, void **knownsrcs) 485da0c48c4Sopenharmony_ci{ 486da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < nsegments; ++cnt) 487da0c48c4Sopenharmony_ci if (segments[cnt].from <= addr && segments[cnt].to > addr) 488da0c48c4Sopenharmony_ci { 489da0c48c4Sopenharmony_ci Dwarf_Die die_mem; 490da0c48c4Sopenharmony_ci Dwarf_Die *die; 491da0c48c4Sopenharmony_ci Dwarf_Line *line; 492da0c48c4Sopenharmony_ci const char *src; 493da0c48c4Sopenharmony_ci 494da0c48c4Sopenharmony_ci if (more_than_one) 495da0c48c4Sopenharmony_ci printf ("%s: ", fname); 496da0c48c4Sopenharmony_ci 497da0c48c4Sopenharmony_ci if ((die = dwarf_addrdie (dw, addr, &die_mem)) != NULL 498da0c48c4Sopenharmony_ci && (line = dwarf_getsrc_die (die, addr)) != NULL 499da0c48c4Sopenharmony_ci && (src = dwarf_linesrc (line, NULL, NULL)) != NULL) 500da0c48c4Sopenharmony_ci { 501da0c48c4Sopenharmony_ci /* There can be more than one relocation against one file. 502da0c48c4Sopenharmony_ci Try to avoid multiple messages. And yes, the code uses 503da0c48c4Sopenharmony_ci pointer comparison. */ 504da0c48c4Sopenharmony_ci if (tfind (src, knownsrcs, ptrcompare) == NULL) 505da0c48c4Sopenharmony_ci { 506da0c48c4Sopenharmony_ci printf (_("%s not compiled with -fpic/-fPIC\n"), src); 507da0c48c4Sopenharmony_ci tsearch (src, knownsrcs, ptrcompare); 508da0c48c4Sopenharmony_ci } 509da0c48c4Sopenharmony_ci return; 510da0c48c4Sopenharmony_ci } 511da0c48c4Sopenharmony_ci else 512da0c48c4Sopenharmony_ci { 513da0c48c4Sopenharmony_ci /* At least look at the symbol table to see which function 514da0c48c4Sopenharmony_ci the modified address is in. */ 515da0c48c4Sopenharmony_ci Elf_Data *symdata = elf_getdata (symscn, NULL); 516da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 517da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (symscn, &shdr_mem); 518da0c48c4Sopenharmony_ci if (shdr != NULL) 519da0c48c4Sopenharmony_ci { 520da0c48c4Sopenharmony_ci GElf_Addr lowaddr = 0; 521da0c48c4Sopenharmony_ci int lowidx = -1; 522da0c48c4Sopenharmony_ci GElf_Addr highaddr = ~0ul; 523da0c48c4Sopenharmony_ci int highidx = -1; 524da0c48c4Sopenharmony_ci GElf_Sym sym_mem; 525da0c48c4Sopenharmony_ci GElf_Sym *sym; 526da0c48c4Sopenharmony_ci size_t entries = (shdr->sh_entsize == 0 527da0c48c4Sopenharmony_ci ? 0 : shdr->sh_size / shdr->sh_entsize); 528da0c48c4Sopenharmony_ci 529da0c48c4Sopenharmony_ci for (int i = 0; (size_t) i < entries; ++i) 530da0c48c4Sopenharmony_ci { 531da0c48c4Sopenharmony_ci sym = gelf_getsym (symdata, i, &sym_mem); 532da0c48c4Sopenharmony_ci if (sym == NULL) 533da0c48c4Sopenharmony_ci continue; 534da0c48c4Sopenharmony_ci 535da0c48c4Sopenharmony_ci if (sym->st_value < addr && sym->st_value > lowaddr) 536da0c48c4Sopenharmony_ci { 537da0c48c4Sopenharmony_ci lowaddr = sym->st_value; 538da0c48c4Sopenharmony_ci lowidx = i; 539da0c48c4Sopenharmony_ci } 540da0c48c4Sopenharmony_ci if (sym->st_value > addr && sym->st_value < highaddr) 541da0c48c4Sopenharmony_ci { 542da0c48c4Sopenharmony_ci highaddr = sym->st_value; 543da0c48c4Sopenharmony_ci highidx = i; 544da0c48c4Sopenharmony_ci } 545da0c48c4Sopenharmony_ci } 546da0c48c4Sopenharmony_ci 547da0c48c4Sopenharmony_ci if (lowidx != -1) 548da0c48c4Sopenharmony_ci { 549da0c48c4Sopenharmony_ci sym = gelf_getsym (symdata, lowidx, &sym_mem); 550da0c48c4Sopenharmony_ci assert (sym != NULL); 551da0c48c4Sopenharmony_ci 552da0c48c4Sopenharmony_ci const char *lowstr = elf_strptr (elf, shdr->sh_link, 553da0c48c4Sopenharmony_ci sym->st_name); 554da0c48c4Sopenharmony_ci 555da0c48c4Sopenharmony_ci if (sym->st_value + sym->st_size > addr) 556da0c48c4Sopenharmony_ci { 557da0c48c4Sopenharmony_ci /* It is this function. */ 558da0c48c4Sopenharmony_ci if (tfind (lowstr, knownsrcs, ptrcompare) == NULL) 559da0c48c4Sopenharmony_ci { 560da0c48c4Sopenharmony_ci printf (_("\ 561da0c48c4Sopenharmony_cithe file containing the function '%s' is not compiled with -fpic/-fPIC\n"), 562da0c48c4Sopenharmony_ci lowstr); 563da0c48c4Sopenharmony_ci tsearch (lowstr, knownsrcs, ptrcompare); 564da0c48c4Sopenharmony_ci } 565da0c48c4Sopenharmony_ci } 566da0c48c4Sopenharmony_ci else if (highidx == -1) 567da0c48c4Sopenharmony_ci printf (_("\ 568da0c48c4Sopenharmony_cithe file containing the function '%s' might not be compiled with -fpic/-fPIC\n"), 569da0c48c4Sopenharmony_ci lowstr); 570da0c48c4Sopenharmony_ci else 571da0c48c4Sopenharmony_ci { 572da0c48c4Sopenharmony_ci sym = gelf_getsym (symdata, highidx, &sym_mem); 573da0c48c4Sopenharmony_ci assert (sym != NULL); 574da0c48c4Sopenharmony_ci 575da0c48c4Sopenharmony_ci printf (_("\ 576da0c48c4Sopenharmony_cieither the file containing the function '%s' or the file containing the function '%s' is not compiled with -fpic/-fPIC\n"), 577da0c48c4Sopenharmony_ci lowstr, elf_strptr (elf, shdr->sh_link, 578da0c48c4Sopenharmony_ci sym->st_name)); 579da0c48c4Sopenharmony_ci } 580da0c48c4Sopenharmony_ci return; 581da0c48c4Sopenharmony_ci } 582da0c48c4Sopenharmony_ci else if (highidx != -1) 583da0c48c4Sopenharmony_ci { 584da0c48c4Sopenharmony_ci sym = gelf_getsym (symdata, highidx, &sym_mem); 585da0c48c4Sopenharmony_ci assert (sym != NULL); 586da0c48c4Sopenharmony_ci 587da0c48c4Sopenharmony_ci printf (_("\ 588da0c48c4Sopenharmony_cithe file containing the function '%s' might not be compiled with -fpic/-fPIC\n"), 589da0c48c4Sopenharmony_ci elf_strptr (elf, shdr->sh_link, sym->st_name)); 590da0c48c4Sopenharmony_ci return; 591da0c48c4Sopenharmony_ci } 592da0c48c4Sopenharmony_ci } 593da0c48c4Sopenharmony_ci } 594da0c48c4Sopenharmony_ci 595da0c48c4Sopenharmony_ci printf (_("\ 596da0c48c4Sopenharmony_cia relocation modifies memory at offset %llu in a write-protected segment\n"), 597da0c48c4Sopenharmony_ci (unsigned long long int) addr); 598da0c48c4Sopenharmony_ci break; 599da0c48c4Sopenharmony_ci } 600da0c48c4Sopenharmony_ci} 601da0c48c4Sopenharmony_ci 602da0c48c4Sopenharmony_ci 603da0c48c4Sopenharmony_ci#include "debugpred.h" 604