1da0c48c4Sopenharmony_ci/* Print symbol information from ELF file in human-readable form. 2da0c48c4Sopenharmony_ci Copyright (C) 2000-2008, 2009, 2011, 2012, 2014, 2015, 2020 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2000. 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 <ar.h> 24da0c48c4Sopenharmony_ci#include <argp.h> 25da0c48c4Sopenharmony_ci#include <assert.h> 26da0c48c4Sopenharmony_ci#include <ctype.h> 27da0c48c4Sopenharmony_ci#include <dwarf.h> 28da0c48c4Sopenharmony_ci#include <errno.h> 29da0c48c4Sopenharmony_ci#include <fcntl.h> 30da0c48c4Sopenharmony_ci#include <gelf.h> 31da0c48c4Sopenharmony_ci#include <inttypes.h> 32da0c48c4Sopenharmony_ci#include <libdw.h> 33da0c48c4Sopenharmony_ci#include <locale.h> 34da0c48c4Sopenharmony_ci#include <obstack.h> 35da0c48c4Sopenharmony_ci#include <search.h> 36da0c48c4Sopenharmony_ci#include <stdbool.h> 37da0c48c4Sopenharmony_ci#include <stdio.h> 38da0c48c4Sopenharmony_ci#include <stdio_ext.h> 39da0c48c4Sopenharmony_ci#include <stdlib.h> 40da0c48c4Sopenharmony_ci#include <string.h> 41da0c48c4Sopenharmony_ci#include <unistd.h> 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci#include <libeu.h> 44da0c48c4Sopenharmony_ci#include <system.h> 45da0c48c4Sopenharmony_ci#include <color.h> 46da0c48c4Sopenharmony_ci#include <printversion.h> 47da0c48c4Sopenharmony_ci#include "../libebl/libeblP.h" 48da0c48c4Sopenharmony_ci#include "../libdwfl/libdwflP.h" 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci/* Name and version of program. */ 52da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 53da0c48c4Sopenharmony_ci 54da0c48c4Sopenharmony_ci/* Bug report address. */ 55da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 56da0c48c4Sopenharmony_ci 57da0c48c4Sopenharmony_ci 58da0c48c4Sopenharmony_ci/* Values for the parameters which have no short form. */ 59da0c48c4Sopenharmony_ci#define OPT_DEFINED 0x100 60da0c48c4Sopenharmony_ci#define OPT_MARK_SPECIAL 0x101 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions. */ 63da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 64da0c48c4Sopenharmony_ci{ 65da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Output selection:"), 0 }, 66da0c48c4Sopenharmony_ci { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 }, 67da0c48c4Sopenharmony_ci { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"), 68da0c48c4Sopenharmony_ci 0 }, 69da0c48c4Sopenharmony_ci { "dynamic", 'D', NULL, 0, 70da0c48c4Sopenharmony_ci N_("Display dynamic symbols instead of normal symbols"), 0 }, 71da0c48c4Sopenharmony_ci { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 }, 72da0c48c4Sopenharmony_ci { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 }, 73da0c48c4Sopenharmony_ci { "print-armap", 's', NULL, 0, 74da0c48c4Sopenharmony_ci N_("Include index for symbols from archive members"), 0 }, 75da0c48c4Sopenharmony_ci 76da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Output format:"), 0 }, 77da0c48c4Sopenharmony_ci { "print-file-name", 'A', NULL, 0, 78da0c48c4Sopenharmony_ci N_("Print name of the input file before every symbol"), 0 }, 79da0c48c4Sopenharmony_ci { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 }, 80da0c48c4Sopenharmony_ci { "format", 'f', "FORMAT", 0, 81da0c48c4Sopenharmony_ci N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"), 82da0c48c4Sopenharmony_ci 0 }, 83da0c48c4Sopenharmony_ci { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 }, 84da0c48c4Sopenharmony_ci { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 }, 85da0c48c4Sopenharmony_ci { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 }, 86da0c48c4Sopenharmony_ci { "mark-special", OPT_MARK_SPECIAL, NULL, 0, N_("Mark special symbols"), 0 }, 87da0c48c4Sopenharmony_ci { "mark-weak", OPT_MARK_SPECIAL, NULL, OPTION_HIDDEN, "", 0 }, 88da0c48c4Sopenharmony_ci { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 }, 89da0c48c4Sopenharmony_ci 90da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Output options:"), 0 }, 91da0c48c4Sopenharmony_ci { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"), 92da0c48c4Sopenharmony_ci 0 }, 93da0c48c4Sopenharmony_ci { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 }, 94da0c48c4Sopenharmony_ci { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 }, 95da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 96da0c48c4Sopenharmony_ci { "demangle", 'C', NULL, 0, 97da0c48c4Sopenharmony_ci N_("Decode low-level symbol names into source code names"), 0 }, 98da0c48c4Sopenharmony_ci#endif 99da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 100da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 101da0c48c4Sopenharmony_ci}; 102da0c48c4Sopenharmony_ci 103da0c48c4Sopenharmony_ci/* Short description of program. */ 104da0c48c4Sopenharmony_cistatic const char doc[] = N_("List symbols from FILEs (a.out by default)."); 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_ci/* Strings for arguments in help texts. */ 107da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[FILE...]"); 108da0c48c4Sopenharmony_ci 109da0c48c4Sopenharmony_ci/* Prototype for option handler. */ 110da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state); 111da0c48c4Sopenharmony_ci 112da0c48c4Sopenharmony_ci/* Parser children. */ 113da0c48c4Sopenharmony_cistatic struct argp_child argp_children[] = 114da0c48c4Sopenharmony_ci { 115da0c48c4Sopenharmony_ci { &color_argp, 0, N_("Output formatting"), 2 }, 116da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0} 117da0c48c4Sopenharmony_ci }; 118da0c48c4Sopenharmony_ci 119da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions. */ 120da0c48c4Sopenharmony_cistatic struct argp argp = 121da0c48c4Sopenharmony_ci{ 122da0c48c4Sopenharmony_ci options, parse_opt, args_doc, doc, argp_children, NULL, NULL 123da0c48c4Sopenharmony_ci}; 124da0c48c4Sopenharmony_ci 125da0c48c4Sopenharmony_ci 126da0c48c4Sopenharmony_ci/* Print symbols in file named FNAME. */ 127da0c48c4Sopenharmony_cistatic int process_file (const char *fname, bool more_than_one); 128da0c48c4Sopenharmony_ci 129da0c48c4Sopenharmony_ci/* Handle content of archive. */ 130da0c48c4Sopenharmony_cistatic int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, 131da0c48c4Sopenharmony_ci const char *suffix); 132da0c48c4Sopenharmony_ci 133da0c48c4Sopenharmony_ci/* Handle ELF file. */ 134da0c48c4Sopenharmony_cistatic int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, 135da0c48c4Sopenharmony_ci const char *suffix); 136da0c48c4Sopenharmony_ci 137da0c48c4Sopenharmony_ci 138da0c48c4Sopenharmony_ci#define INTERNAL_ERROR(fname) \ 139da0c48c4Sopenharmony_ci error_exit (0, _("%s: INTERNAL ERROR %d (%s): %s"), \ 140da0c48c4Sopenharmony_ci fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)) 141da0c48c4Sopenharmony_ci 142da0c48c4Sopenharmony_ci 143da0c48c4Sopenharmony_ci/* Internal representation of symbols. */ 144da0c48c4Sopenharmony_citypedef struct GElf_SymX 145da0c48c4Sopenharmony_ci{ 146da0c48c4Sopenharmony_ci GElf_Sym sym; 147da0c48c4Sopenharmony_ci Elf32_Word xndx; 148da0c48c4Sopenharmony_ci char *where; 149da0c48c4Sopenharmony_ci} GElf_SymX; 150da0c48c4Sopenharmony_ci 151da0c48c4Sopenharmony_ci 152da0c48c4Sopenharmony_ci/* User-selectable options. */ 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci/* The selected output format. */ 155da0c48c4Sopenharmony_cistatic enum 156da0c48c4Sopenharmony_ci{ 157da0c48c4Sopenharmony_ci format_sysv = 0, 158da0c48c4Sopenharmony_ci format_bsd, 159da0c48c4Sopenharmony_ci format_posix 160da0c48c4Sopenharmony_ci} format; 161da0c48c4Sopenharmony_ci 162da0c48c4Sopenharmony_ci/* Print defined, undefined, or both? */ 163da0c48c4Sopenharmony_cistatic bool hide_undefined; 164da0c48c4Sopenharmony_cistatic bool hide_defined; 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci/* Print local symbols also? */ 167da0c48c4Sopenharmony_cistatic bool hide_local; 168da0c48c4Sopenharmony_ci 169da0c48c4Sopenharmony_ci/* Nonzero if full filename should precede every symbol. */ 170da0c48c4Sopenharmony_cistatic bool print_file_name; 171da0c48c4Sopenharmony_ci 172da0c48c4Sopenharmony_ci/* If true print size of defined symbols in BSD format. */ 173da0c48c4Sopenharmony_cistatic bool print_size; 174da0c48c4Sopenharmony_ci 175da0c48c4Sopenharmony_ci/* If true print archive index. */ 176da0c48c4Sopenharmony_cistatic bool print_armap; 177da0c48c4Sopenharmony_ci 178da0c48c4Sopenharmony_ci/* If true reverse sorting. */ 179da0c48c4Sopenharmony_cistatic bool reverse_sort; 180da0c48c4Sopenharmony_ci 181da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 182da0c48c4Sopenharmony_ci/* If true demangle symbols. */ 183da0c48c4Sopenharmony_cistatic bool demangle; 184da0c48c4Sopenharmony_ci#endif 185da0c48c4Sopenharmony_ci 186da0c48c4Sopenharmony_ci/* Type of the section we are printing. */ 187da0c48c4Sopenharmony_cistatic GElf_Word symsec_type = SHT_SYMTAB; 188da0c48c4Sopenharmony_ci 189da0c48c4Sopenharmony_ci/* Sorting selection. */ 190da0c48c4Sopenharmony_cistatic enum 191da0c48c4Sopenharmony_ci{ 192da0c48c4Sopenharmony_ci sort_name = 0, 193da0c48c4Sopenharmony_ci sort_numeric, 194da0c48c4Sopenharmony_ci sort_nosort 195da0c48c4Sopenharmony_ci} sort; 196da0c48c4Sopenharmony_ci 197da0c48c4Sopenharmony_ci/* Radix for printed numbers. */ 198da0c48c4Sopenharmony_cistatic enum 199da0c48c4Sopenharmony_ci{ 200da0c48c4Sopenharmony_ci radix_hex = 0, 201da0c48c4Sopenharmony_ci radix_decimal, 202da0c48c4Sopenharmony_ci radix_octal 203da0c48c4Sopenharmony_ci} radix; 204da0c48c4Sopenharmony_ci 205da0c48c4Sopenharmony_ci/* If nonzero mark special symbols: 206da0c48c4Sopenharmony_ci - weak symbols are distinguished from global symbols by adding 207da0c48c4Sopenharmony_ci a `*' after the identifying letter for the symbol class and type. 208da0c48c4Sopenharmony_ci - TLS symbols are distinguished from normal symbols by adding 209da0c48c4Sopenharmony_ci a '@' after the identifying letter for the symbol class and type. */ 210da0c48c4Sopenharmony_cistatic bool mark_special; 211da0c48c4Sopenharmony_ci 212da0c48c4Sopenharmony_ci 213da0c48c4Sopenharmony_ciint 214da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 215da0c48c4Sopenharmony_ci{ 216da0c48c4Sopenharmony_ci int remaining; 217da0c48c4Sopenharmony_ci int result = 0; 218da0c48c4Sopenharmony_ci 219da0c48c4Sopenharmony_ci /* We use no threads here which can interfere with handling a stream. */ 220da0c48c4Sopenharmony_ci (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 221da0c48c4Sopenharmony_ci (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 222da0c48c4Sopenharmony_ci (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER); 223da0c48c4Sopenharmony_ci 224da0c48c4Sopenharmony_ci /* Set locale. */ 225da0c48c4Sopenharmony_ci (void) setlocale (LC_ALL, ""); 226da0c48c4Sopenharmony_ci 227da0c48c4Sopenharmony_ci /* Make sure the message catalog can be found. */ 228da0c48c4Sopenharmony_ci (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 229da0c48c4Sopenharmony_ci 230da0c48c4Sopenharmony_ci /* Initialize the message catalog. */ 231da0c48c4Sopenharmony_ci (void) textdomain (PACKAGE_TARNAME); 232da0c48c4Sopenharmony_ci 233da0c48c4Sopenharmony_ci /* Parse and process arguments. */ 234da0c48c4Sopenharmony_ci (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL); 235da0c48c4Sopenharmony_ci 236da0c48c4Sopenharmony_ci /* Tell the library which version we are expecting. */ 237da0c48c4Sopenharmony_ci (void) elf_version (EV_CURRENT); 238da0c48c4Sopenharmony_ci 239da0c48c4Sopenharmony_ci if (remaining == argc) 240da0c48c4Sopenharmony_ci /* The user didn't specify a name so we use a.out. */ 241da0c48c4Sopenharmony_ci result = process_file ("a.out", false); 242da0c48c4Sopenharmony_ci else 243da0c48c4Sopenharmony_ci { 244da0c48c4Sopenharmony_ci /* Process all the remaining files. */ 245da0c48c4Sopenharmony_ci const bool more_than_one = remaining + 1 < argc; 246da0c48c4Sopenharmony_ci 247da0c48c4Sopenharmony_ci do 248da0c48c4Sopenharmony_ci result |= process_file (argv[remaining], more_than_one); 249da0c48c4Sopenharmony_ci while (++remaining < argc); 250da0c48c4Sopenharmony_ci } 251da0c48c4Sopenharmony_ci 252da0c48c4Sopenharmony_ci return result; 253da0c48c4Sopenharmony_ci} 254da0c48c4Sopenharmony_ci 255da0c48c4Sopenharmony_ci 256da0c48c4Sopenharmony_ci/* Handle program arguments. */ 257da0c48c4Sopenharmony_cistatic error_t 258da0c48c4Sopenharmony_ciparse_opt (int key, char *arg, 259da0c48c4Sopenharmony_ci struct argp_state *state __attribute__ ((unused))) 260da0c48c4Sopenharmony_ci{ 261da0c48c4Sopenharmony_ci switch (key) 262da0c48c4Sopenharmony_ci { 263da0c48c4Sopenharmony_ci case 'a': 264da0c48c4Sopenharmony_ci /* XXX */ 265da0c48c4Sopenharmony_ci break; 266da0c48c4Sopenharmony_ci 267da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 268da0c48c4Sopenharmony_ci case 'C': 269da0c48c4Sopenharmony_ci demangle = true; 270da0c48c4Sopenharmony_ci break; 271da0c48c4Sopenharmony_ci#endif 272da0c48c4Sopenharmony_ci 273da0c48c4Sopenharmony_ci case 'f': 274da0c48c4Sopenharmony_ci if (strcmp (arg, "bsd") == 0) 275da0c48c4Sopenharmony_ci format = format_bsd; 276da0c48c4Sopenharmony_ci else if (strcmp (arg, "posix") == 0) 277da0c48c4Sopenharmony_ci format = format_posix; 278da0c48c4Sopenharmony_ci else 279da0c48c4Sopenharmony_ci /* Be bug compatible. The BFD implementation also defaulted to 280da0c48c4Sopenharmony_ci using the SysV format if nothing else matches. */ 281da0c48c4Sopenharmony_ci format = format_sysv; 282da0c48c4Sopenharmony_ci break; 283da0c48c4Sopenharmony_ci 284da0c48c4Sopenharmony_ci case 'g': 285da0c48c4Sopenharmony_ci hide_local = true; 286da0c48c4Sopenharmony_ci break; 287da0c48c4Sopenharmony_ci 288da0c48c4Sopenharmony_ci case 'n': 289da0c48c4Sopenharmony_ci sort = sort_numeric; 290da0c48c4Sopenharmony_ci break; 291da0c48c4Sopenharmony_ci 292da0c48c4Sopenharmony_ci case 'p': 293da0c48c4Sopenharmony_ci sort = sort_nosort; 294da0c48c4Sopenharmony_ci break; 295da0c48c4Sopenharmony_ci 296da0c48c4Sopenharmony_ci case 't': 297da0c48c4Sopenharmony_ci if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0) 298da0c48c4Sopenharmony_ci radix = radix_decimal; 299da0c48c4Sopenharmony_ci else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0) 300da0c48c4Sopenharmony_ci radix = radix_octal; 301da0c48c4Sopenharmony_ci else 302da0c48c4Sopenharmony_ci radix = radix_hex; 303da0c48c4Sopenharmony_ci break; 304da0c48c4Sopenharmony_ci 305da0c48c4Sopenharmony_ci case 'u': 306da0c48c4Sopenharmony_ci hide_undefined = false; 307da0c48c4Sopenharmony_ci hide_defined = true; 308da0c48c4Sopenharmony_ci break; 309da0c48c4Sopenharmony_ci 310da0c48c4Sopenharmony_ci case 'A': 311da0c48c4Sopenharmony_ci case 'o': 312da0c48c4Sopenharmony_ci print_file_name = true; 313da0c48c4Sopenharmony_ci break; 314da0c48c4Sopenharmony_ci 315da0c48c4Sopenharmony_ci case 'B': 316da0c48c4Sopenharmony_ci format = format_bsd; 317da0c48c4Sopenharmony_ci break; 318da0c48c4Sopenharmony_ci 319da0c48c4Sopenharmony_ci case 'D': 320da0c48c4Sopenharmony_ci symsec_type = SHT_DYNSYM; 321da0c48c4Sopenharmony_ci break; 322da0c48c4Sopenharmony_ci 323da0c48c4Sopenharmony_ci case 'P': 324da0c48c4Sopenharmony_ci format = format_posix; 325da0c48c4Sopenharmony_ci break; 326da0c48c4Sopenharmony_ci 327da0c48c4Sopenharmony_ci case OPT_DEFINED: 328da0c48c4Sopenharmony_ci hide_undefined = true; 329da0c48c4Sopenharmony_ci hide_defined = false; 330da0c48c4Sopenharmony_ci break; 331da0c48c4Sopenharmony_ci 332da0c48c4Sopenharmony_ci case OPT_MARK_SPECIAL: 333da0c48c4Sopenharmony_ci mark_special = true; 334da0c48c4Sopenharmony_ci break; 335da0c48c4Sopenharmony_ci 336da0c48c4Sopenharmony_ci case 'S': 337da0c48c4Sopenharmony_ci print_size = true; 338da0c48c4Sopenharmony_ci break; 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci case 's': 341da0c48c4Sopenharmony_ci print_armap = true; 342da0c48c4Sopenharmony_ci break; 343da0c48c4Sopenharmony_ci 344da0c48c4Sopenharmony_ci case 'r': 345da0c48c4Sopenharmony_ci reverse_sort = true; 346da0c48c4Sopenharmony_ci break; 347da0c48c4Sopenharmony_ci 348da0c48c4Sopenharmony_ci default: 349da0c48c4Sopenharmony_ci return ARGP_ERR_UNKNOWN; 350da0c48c4Sopenharmony_ci } 351da0c48c4Sopenharmony_ci return 0; 352da0c48c4Sopenharmony_ci} 353da0c48c4Sopenharmony_ci 354da0c48c4Sopenharmony_ci 355da0c48c4Sopenharmony_ci/* Open the file and determine the type. */ 356da0c48c4Sopenharmony_cistatic int 357da0c48c4Sopenharmony_ciprocess_file (const char *fname, bool more_than_one) 358da0c48c4Sopenharmony_ci{ 359da0c48c4Sopenharmony_ci /* Open the file. */ 360da0c48c4Sopenharmony_ci int fd = open (fname, O_RDONLY); 361da0c48c4Sopenharmony_ci if (fd == -1) 362da0c48c4Sopenharmony_ci { 363da0c48c4Sopenharmony_ci error (0, errno, _("cannot open '%s'"), fname); 364da0c48c4Sopenharmony_ci return 1; 365da0c48c4Sopenharmony_ci } 366da0c48c4Sopenharmony_ci 367da0c48c4Sopenharmony_ci /* Now get the ELF descriptor. */ 368da0c48c4Sopenharmony_ci Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); 369da0c48c4Sopenharmony_ci if (elf != NULL) 370da0c48c4Sopenharmony_ci { 371da0c48c4Sopenharmony_ci if (elf_kind (elf) == ELF_K_ELF) 372da0c48c4Sopenharmony_ci { 373da0c48c4Sopenharmony_ci int result = handle_elf (fd, elf, more_than_one ? "" : NULL, 374da0c48c4Sopenharmony_ci fname, NULL); 375da0c48c4Sopenharmony_ci 376da0c48c4Sopenharmony_ci if (elf_end (elf) != 0) 377da0c48c4Sopenharmony_ci INTERNAL_ERROR (fname); 378da0c48c4Sopenharmony_ci 379da0c48c4Sopenharmony_ci if (close (fd) != 0) 380da0c48c4Sopenharmony_ci error_exit (errno, _("while closing '%s'"), fname); 381da0c48c4Sopenharmony_ci 382da0c48c4Sopenharmony_ci return result; 383da0c48c4Sopenharmony_ci } 384da0c48c4Sopenharmony_ci else if (elf_kind (elf) == ELF_K_AR) 385da0c48c4Sopenharmony_ci { 386da0c48c4Sopenharmony_ci int result = handle_ar (fd, elf, NULL, fname, NULL); 387da0c48c4Sopenharmony_ci 388da0c48c4Sopenharmony_ci if (elf_end (elf) != 0) 389da0c48c4Sopenharmony_ci INTERNAL_ERROR (fname); 390da0c48c4Sopenharmony_ci 391da0c48c4Sopenharmony_ci if (close (fd) != 0) 392da0c48c4Sopenharmony_ci error_exit (errno, _("while closing '%s'"), fname); 393da0c48c4Sopenharmony_ci 394da0c48c4Sopenharmony_ci return result; 395da0c48c4Sopenharmony_ci } 396da0c48c4Sopenharmony_ci 397da0c48c4Sopenharmony_ci /* We cannot handle this type. Close the descriptor anyway. */ 398da0c48c4Sopenharmony_ci if (elf_end (elf) != 0) 399da0c48c4Sopenharmony_ci INTERNAL_ERROR (fname); 400da0c48c4Sopenharmony_ci } 401da0c48c4Sopenharmony_ci 402da0c48c4Sopenharmony_ci error (0, 0, _("%s: File format not recognized"), fname); 403da0c48c4Sopenharmony_ci 404da0c48c4Sopenharmony_ci return 1; 405da0c48c4Sopenharmony_ci} 406da0c48c4Sopenharmony_ci 407da0c48c4Sopenharmony_ci 408da0c48c4Sopenharmony_cistatic int 409da0c48c4Sopenharmony_cihandle_ar (int fd, Elf *elf, const char *prefix, const char *fname, 410da0c48c4Sopenharmony_ci const char *suffix) 411da0c48c4Sopenharmony_ci{ 412da0c48c4Sopenharmony_ci size_t fname_len = strlen (fname) + 1; 413da0c48c4Sopenharmony_ci size_t prefix_len = prefix != NULL ? strlen (prefix) : 0; 414da0c48c4Sopenharmony_ci char new_prefix[prefix_len + fname_len + 2]; 415da0c48c4Sopenharmony_ci size_t suffix_len = suffix != NULL ? strlen (suffix) : 0; 416da0c48c4Sopenharmony_ci char new_suffix[suffix_len + 2]; 417da0c48c4Sopenharmony_ci Elf *subelf; 418da0c48c4Sopenharmony_ci Elf_Cmd cmd = ELF_C_READ_MMAP; 419da0c48c4Sopenharmony_ci int result = 0; 420da0c48c4Sopenharmony_ci 421da0c48c4Sopenharmony_ci char *cp = new_prefix; 422da0c48c4Sopenharmony_ci if (prefix != NULL) 423da0c48c4Sopenharmony_ci cp = stpcpy (cp, prefix); 424da0c48c4Sopenharmony_ci cp = stpcpy (cp, fname); 425da0c48c4Sopenharmony_ci stpcpy (cp, "["); 426da0c48c4Sopenharmony_ci 427da0c48c4Sopenharmony_ci cp = new_suffix; 428da0c48c4Sopenharmony_ci if (suffix != NULL) 429da0c48c4Sopenharmony_ci cp = stpcpy (cp, suffix); 430da0c48c4Sopenharmony_ci stpcpy (cp, "]"); 431da0c48c4Sopenharmony_ci 432da0c48c4Sopenharmony_ci /* First print the archive index if this is wanted. */ 433da0c48c4Sopenharmony_ci if (print_armap) 434da0c48c4Sopenharmony_ci { 435da0c48c4Sopenharmony_ci Elf_Arsym *arsym = elf_getarsym (elf, NULL); 436da0c48c4Sopenharmony_ci 437da0c48c4Sopenharmony_ci if (arsym != NULL) 438da0c48c4Sopenharmony_ci { 439da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = NULL; 440da0c48c4Sopenharmony_ci size_t arhdr_off = 0; /* Note: 0 is no valid offset. */ 441da0c48c4Sopenharmony_ci 442da0c48c4Sopenharmony_ci fputs_unlocked (_("\nArchive index:\n"), stdout); 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci while (arsym->as_off != 0) 445da0c48c4Sopenharmony_ci { 446da0c48c4Sopenharmony_ci if (arhdr_off != arsym->as_off 447da0c48c4Sopenharmony_ci && (elf_rand (elf, arsym->as_off) != arsym->as_off 448da0c48c4Sopenharmony_ci || (subelf = elf_begin (fd, cmd, elf)) == NULL 449da0c48c4Sopenharmony_ci || (arhdr = elf_getarhdr (subelf)) == NULL)) 450da0c48c4Sopenharmony_ci { 451da0c48c4Sopenharmony_ci error (0, 0, _("invalid offset %zu for symbol %s"), 452da0c48c4Sopenharmony_ci arsym->as_off, arsym->as_name); 453da0c48c4Sopenharmony_ci break; 454da0c48c4Sopenharmony_ci } 455da0c48c4Sopenharmony_ci 456da0c48c4Sopenharmony_ci printf (_("%s in %s\n"), arsym->as_name, arhdr->ar_name); 457da0c48c4Sopenharmony_ci 458da0c48c4Sopenharmony_ci ++arsym; 459da0c48c4Sopenharmony_ci } 460da0c48c4Sopenharmony_ci 461da0c48c4Sopenharmony_ci if (elf_rand (elf, SARMAG) != SARMAG) 462da0c48c4Sopenharmony_ci { 463da0c48c4Sopenharmony_ci error (0, 0, 464da0c48c4Sopenharmony_ci _("cannot reset archive offset to beginning")); 465da0c48c4Sopenharmony_ci return 1; 466da0c48c4Sopenharmony_ci } 467da0c48c4Sopenharmony_ci } 468da0c48c4Sopenharmony_ci } 469da0c48c4Sopenharmony_ci 470da0c48c4Sopenharmony_ci /* Process all the files contained in the archive. */ 471da0c48c4Sopenharmony_ci while ((subelf = elf_begin (fd, cmd, elf)) != NULL) 472da0c48c4Sopenharmony_ci { 473da0c48c4Sopenharmony_ci /* The the header for this element. */ 474da0c48c4Sopenharmony_ci Elf_Arhdr *arhdr = elf_getarhdr (subelf); 475da0c48c4Sopenharmony_ci 476da0c48c4Sopenharmony_ci /* Skip over the index entries. */ 477da0c48c4Sopenharmony_ci if (strcmp (arhdr->ar_name, "/") != 0 478da0c48c4Sopenharmony_ci && strcmp (arhdr->ar_name, "//") != 0 479da0c48c4Sopenharmony_ci && strcmp (arhdr->ar_name, "/SYM64/") != 0) 480da0c48c4Sopenharmony_ci { 481da0c48c4Sopenharmony_ci if (elf_kind (subelf) == ELF_K_ELF) 482da0c48c4Sopenharmony_ci result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 483da0c48c4Sopenharmony_ci new_suffix); 484da0c48c4Sopenharmony_ci else if (elf_kind (subelf) == ELF_K_AR) 485da0c48c4Sopenharmony_ci result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, 486da0c48c4Sopenharmony_ci new_suffix); 487da0c48c4Sopenharmony_ci else 488da0c48c4Sopenharmony_ci { 489da0c48c4Sopenharmony_ci error (0, 0, _("%s%s%s: file format not recognized"), 490da0c48c4Sopenharmony_ci new_prefix, arhdr->ar_name, new_suffix); 491da0c48c4Sopenharmony_ci result = 1; 492da0c48c4Sopenharmony_ci } 493da0c48c4Sopenharmony_ci } 494da0c48c4Sopenharmony_ci 495da0c48c4Sopenharmony_ci /* Get next archive element. */ 496da0c48c4Sopenharmony_ci cmd = elf_next (subelf); 497da0c48c4Sopenharmony_ci if (elf_end (subelf) != 0) 498da0c48c4Sopenharmony_ci INTERNAL_ERROR (fname); 499da0c48c4Sopenharmony_ci } 500da0c48c4Sopenharmony_ci 501da0c48c4Sopenharmony_ci return result; 502da0c48c4Sopenharmony_ci} 503da0c48c4Sopenharmony_ci 504da0c48c4Sopenharmony_ci 505da0c48c4Sopenharmony_ci/* Mapping of radix and binary class to length. */ 506da0c48c4Sopenharmony_cistatic const int length_map[2][3] = 507da0c48c4Sopenharmony_ci{ 508da0c48c4Sopenharmony_ci [ELFCLASS32 - 1] = 509da0c48c4Sopenharmony_ci { 510da0c48c4Sopenharmony_ci [radix_hex] = 8, 511da0c48c4Sopenharmony_ci [radix_decimal] = 10, 512da0c48c4Sopenharmony_ci [radix_octal] = 11 513da0c48c4Sopenharmony_ci }, 514da0c48c4Sopenharmony_ci [ELFCLASS64 - 1] = 515da0c48c4Sopenharmony_ci { 516da0c48c4Sopenharmony_ci [radix_hex] = 16, 517da0c48c4Sopenharmony_ci [radix_decimal] = 20, 518da0c48c4Sopenharmony_ci [radix_octal] = 22 519da0c48c4Sopenharmony_ci } 520da0c48c4Sopenharmony_ci}; 521da0c48c4Sopenharmony_ci 522da0c48c4Sopenharmony_ci 523da0c48c4Sopenharmony_cistatic int 524da0c48c4Sopenharmony_ciglobal_compare (const void *p1, const void *p2) 525da0c48c4Sopenharmony_ci{ 526da0c48c4Sopenharmony_ci const Dwarf_Global *g1 = (const Dwarf_Global *) p1; 527da0c48c4Sopenharmony_ci const Dwarf_Global *g2 = (const Dwarf_Global *) p2; 528da0c48c4Sopenharmony_ci 529da0c48c4Sopenharmony_ci return strcmp (g1->name, g2->name); 530da0c48c4Sopenharmony_ci} 531da0c48c4Sopenharmony_ci 532da0c48c4Sopenharmony_ci 533da0c48c4Sopenharmony_cistatic void *global_root; 534da0c48c4Sopenharmony_ci 535da0c48c4Sopenharmony_ci 536da0c48c4Sopenharmony_cistatic int 537da0c48c4Sopenharmony_ciget_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global, 538da0c48c4Sopenharmony_ci void *arg __attribute__ ((unused))) 539da0c48c4Sopenharmony_ci{ 540da0c48c4Sopenharmony_ci tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global, 541da0c48c4Sopenharmony_ci sizeof (Dwarf_Global)), 542da0c48c4Sopenharmony_ci &global_root, global_compare); 543da0c48c4Sopenharmony_ci 544da0c48c4Sopenharmony_ci return DWARF_CB_OK; 545da0c48c4Sopenharmony_ci} 546da0c48c4Sopenharmony_ci 547da0c48c4Sopenharmony_ci 548da0c48c4Sopenharmony_cistruct local_name 549da0c48c4Sopenharmony_ci{ 550da0c48c4Sopenharmony_ci const char *name; 551da0c48c4Sopenharmony_ci const char *file; 552da0c48c4Sopenharmony_ci Dwarf_Word lineno; 553da0c48c4Sopenharmony_ci Dwarf_Addr lowpc; 554da0c48c4Sopenharmony_ci Dwarf_Addr highpc; 555da0c48c4Sopenharmony_ci}; 556da0c48c4Sopenharmony_ci 557da0c48c4Sopenharmony_ci 558da0c48c4Sopenharmony_cistatic int 559da0c48c4Sopenharmony_cilocal_compare (const void *p1, const void *p2) 560da0c48c4Sopenharmony_ci{ 561da0c48c4Sopenharmony_ci struct local_name *g1 = (struct local_name *) p1; 562da0c48c4Sopenharmony_ci struct local_name *g2 = (struct local_name *) p2; 563da0c48c4Sopenharmony_ci int result; 564da0c48c4Sopenharmony_ci 565da0c48c4Sopenharmony_ci result = strcmp (g1->name, g2->name); 566da0c48c4Sopenharmony_ci if (result == 0) 567da0c48c4Sopenharmony_ci { 568da0c48c4Sopenharmony_ci if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc) 569da0c48c4Sopenharmony_ci { 570da0c48c4Sopenharmony_ci /* g2 is contained in g1. Update the data. */ 571da0c48c4Sopenharmony_ci g2->lowpc = g1->lowpc; 572da0c48c4Sopenharmony_ci g2->highpc = g1->highpc; 573da0c48c4Sopenharmony_ci result = 0; 574da0c48c4Sopenharmony_ci } 575da0c48c4Sopenharmony_ci else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc) 576da0c48c4Sopenharmony_ci { 577da0c48c4Sopenharmony_ci /* g1 is contained in g2. Update the data. */ 578da0c48c4Sopenharmony_ci g1->lowpc = g2->lowpc; 579da0c48c4Sopenharmony_ci g1->highpc = g2->highpc; 580da0c48c4Sopenharmony_ci result = 0; 581da0c48c4Sopenharmony_ci } 582da0c48c4Sopenharmony_ci else 583da0c48c4Sopenharmony_ci result = g1->lowpc < g2->lowpc ? -1 : 1; 584da0c48c4Sopenharmony_ci } 585da0c48c4Sopenharmony_ci 586da0c48c4Sopenharmony_ci return result; 587da0c48c4Sopenharmony_ci} 588da0c48c4Sopenharmony_ci 589da0c48c4Sopenharmony_ci 590da0c48c4Sopenharmony_cistatic int 591da0c48c4Sopenharmony_ciget_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc) 592da0c48c4Sopenharmony_ci{ 593da0c48c4Sopenharmony_ci Dwarf_Attribute locattr_mem; 594da0c48c4Sopenharmony_ci Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem); 595da0c48c4Sopenharmony_ci if (locattr == NULL) 596da0c48c4Sopenharmony_ci return 1; 597da0c48c4Sopenharmony_ci 598da0c48c4Sopenharmony_ci Dwarf_Op *loc; 599da0c48c4Sopenharmony_ci size_t nloc; 600da0c48c4Sopenharmony_ci if (dwarf_getlocation (locattr, &loc, &nloc) != 0) 601da0c48c4Sopenharmony_ci return 1; 602da0c48c4Sopenharmony_ci 603da0c48c4Sopenharmony_ci /* Interpret the location expressions. */ 604da0c48c4Sopenharmony_ci // XXX For now just the simple one: 605da0c48c4Sopenharmony_ci if (nloc == 1 && loc[0].atom == DW_OP_addr) 606da0c48c4Sopenharmony_ci { 607da0c48c4Sopenharmony_ci *lowpc = *highpc = loc[0].number; 608da0c48c4Sopenharmony_ci return 0; 609da0c48c4Sopenharmony_ci } 610da0c48c4Sopenharmony_ci 611da0c48c4Sopenharmony_ci return 1; 612da0c48c4Sopenharmony_ci} 613da0c48c4Sopenharmony_ci 614da0c48c4Sopenharmony_ci 615da0c48c4Sopenharmony_ci 616da0c48c4Sopenharmony_cistatic void *local_root; 617da0c48c4Sopenharmony_ci 618da0c48c4Sopenharmony_ci 619da0c48c4Sopenharmony_cistatic void 620da0c48c4Sopenharmony_ciget_local_names (Dwarf *dbg) 621da0c48c4Sopenharmony_ci{ 622da0c48c4Sopenharmony_ci Dwarf_Off offset = 0; 623da0c48c4Sopenharmony_ci Dwarf_Off old_offset; 624da0c48c4Sopenharmony_ci size_t hsize; 625da0c48c4Sopenharmony_ci 626da0c48c4Sopenharmony_ci while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, 627da0c48c4Sopenharmony_ci NULL) == 0) 628da0c48c4Sopenharmony_ci { 629da0c48c4Sopenharmony_ci Dwarf_Die cudie_mem; 630da0c48c4Sopenharmony_ci Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem); 631da0c48c4Sopenharmony_ci 632da0c48c4Sopenharmony_ci /* If we cannot get the CU DIE there is no need to go on with 633da0c48c4Sopenharmony_ci this CU. */ 634da0c48c4Sopenharmony_ci if (cudie == NULL) 635da0c48c4Sopenharmony_ci continue; 636da0c48c4Sopenharmony_ci /* This better be a CU DIE. */ 637da0c48c4Sopenharmony_ci if (dwarf_tag (cudie) != DW_TAG_compile_unit) 638da0c48c4Sopenharmony_ci continue; 639da0c48c4Sopenharmony_ci 640da0c48c4Sopenharmony_ci /* Get the line information. */ 641da0c48c4Sopenharmony_ci Dwarf_Files *files; 642da0c48c4Sopenharmony_ci size_t nfiles; 643da0c48c4Sopenharmony_ci if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0) 644da0c48c4Sopenharmony_ci continue; 645da0c48c4Sopenharmony_ci 646da0c48c4Sopenharmony_ci Dwarf_Die die_mem; 647da0c48c4Sopenharmony_ci Dwarf_Die *die = &die_mem; 648da0c48c4Sopenharmony_ci if (dwarf_child (cudie, die) == 0) 649da0c48c4Sopenharmony_ci /* Iterate over all immediate children of the CU DIE. */ 650da0c48c4Sopenharmony_ci do 651da0c48c4Sopenharmony_ci { 652da0c48c4Sopenharmony_ci int tag = dwarf_tag (die); 653da0c48c4Sopenharmony_ci if (tag != DW_TAG_subprogram && tag != DW_TAG_variable) 654da0c48c4Sopenharmony_ci continue; 655da0c48c4Sopenharmony_ci 656da0c48c4Sopenharmony_ci /* We are interested in five attributes: name, decl_file, 657da0c48c4Sopenharmony_ci decl_line, low_pc, and high_pc. */ 658da0c48c4Sopenharmony_ci Dwarf_Attribute attr_mem; 659da0c48c4Sopenharmony_ci Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem); 660da0c48c4Sopenharmony_ci const char *name = dwarf_formstring (attr); 661da0c48c4Sopenharmony_ci if (name == NULL) 662da0c48c4Sopenharmony_ci continue; 663da0c48c4Sopenharmony_ci 664da0c48c4Sopenharmony_ci Dwarf_Word fileidx; 665da0c48c4Sopenharmony_ci attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem); 666da0c48c4Sopenharmony_ci if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles) 667da0c48c4Sopenharmony_ci continue; 668da0c48c4Sopenharmony_ci 669da0c48c4Sopenharmony_ci Dwarf_Word lineno; 670da0c48c4Sopenharmony_ci attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem); 671da0c48c4Sopenharmony_ci if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0) 672da0c48c4Sopenharmony_ci continue; 673da0c48c4Sopenharmony_ci 674da0c48c4Sopenharmony_ci Dwarf_Addr lowpc; 675da0c48c4Sopenharmony_ci Dwarf_Addr highpc; 676da0c48c4Sopenharmony_ci if (tag == DW_TAG_subprogram) 677da0c48c4Sopenharmony_ci { 678da0c48c4Sopenharmony_ci if (dwarf_lowpc (die, &lowpc) != 0 679da0c48c4Sopenharmony_ci || dwarf_highpc (die, &highpc) != 0) 680da0c48c4Sopenharmony_ci continue; 681da0c48c4Sopenharmony_ci } 682da0c48c4Sopenharmony_ci else 683da0c48c4Sopenharmony_ci { 684da0c48c4Sopenharmony_ci if (get_var_range (die, &lowpc, &highpc) != 0) 685da0c48c4Sopenharmony_ci continue; 686da0c48c4Sopenharmony_ci } 687da0c48c4Sopenharmony_ci 688da0c48c4Sopenharmony_ci /* We have all the information. Create a record. */ 689da0c48c4Sopenharmony_ci struct local_name *newp = xmalloc (sizeof (*newp)); 690da0c48c4Sopenharmony_ci newp->name = name; 691da0c48c4Sopenharmony_ci newp->file = dwarf_filesrc (files, fileidx, NULL, NULL); 692da0c48c4Sopenharmony_ci newp->lineno = lineno; 693da0c48c4Sopenharmony_ci newp->lowpc = lowpc; 694da0c48c4Sopenharmony_ci newp->highpc = highpc; 695da0c48c4Sopenharmony_ci 696da0c48c4Sopenharmony_ci /* Check whether a similar local_name is already in the 697da0c48c4Sopenharmony_ci cache. That should not happen. But if it does, we 698da0c48c4Sopenharmony_ci don't want to leak memory. */ 699da0c48c4Sopenharmony_ci struct local_name **tres = tsearch (newp, &local_root, 700da0c48c4Sopenharmony_ci local_compare); 701da0c48c4Sopenharmony_ci if (tres == NULL) 702da0c48c4Sopenharmony_ci error_exit (errno, _("cannot create search tree")); 703da0c48c4Sopenharmony_ci else if (*tres != newp) 704da0c48c4Sopenharmony_ci free (newp); 705da0c48c4Sopenharmony_ci } 706da0c48c4Sopenharmony_ci while (dwarf_siblingof (die, die) == 0); 707da0c48c4Sopenharmony_ci } 708da0c48c4Sopenharmony_ci} 709da0c48c4Sopenharmony_ci 710da0c48c4Sopenharmony_ci/* Do elf_strptr, but return a backup string and never NULL. */ 711da0c48c4Sopenharmony_cistatic const char * 712da0c48c4Sopenharmony_cisym_name (Elf *elf, GElf_Word strndx, GElf_Word st_name, char buf[], size_t n) 713da0c48c4Sopenharmony_ci{ 714da0c48c4Sopenharmony_ci const char *symstr = elf_strptr (elf, strndx, st_name); 715da0c48c4Sopenharmony_ci if (symstr == NULL) 716da0c48c4Sopenharmony_ci { 717da0c48c4Sopenharmony_ci snprintf (buf, n, "[invalid st_name %#" PRIx32 "]", st_name); 718da0c48c4Sopenharmony_ci symstr = buf; 719da0c48c4Sopenharmony_ci } 720da0c48c4Sopenharmony_ci return symstr; 721da0c48c4Sopenharmony_ci} 722da0c48c4Sopenharmony_ci 723da0c48c4Sopenharmony_ci/* Show symbols in SysV format. */ 724da0c48c4Sopenharmony_cistatic void 725da0c48c4Sopenharmony_cishow_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname, 726da0c48c4Sopenharmony_ci GElf_SymX *syms, size_t nsyms, int longest_name, 727da0c48c4Sopenharmony_ci int longest_where) 728da0c48c4Sopenharmony_ci{ 729da0c48c4Sopenharmony_ci size_t shnum; 730da0c48c4Sopenharmony_ci if (elf_getshdrnum (ebl->elf, &shnum) < 0) 731da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 732da0c48c4Sopenharmony_ci 733da0c48c4Sopenharmony_ci bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024; 734da0c48c4Sopenharmony_ci const char **scnnames; 735da0c48c4Sopenharmony_ci if (scnnames_malloced) 736da0c48c4Sopenharmony_ci scnnames = xmalloc (sizeof (const char *) * shnum); 737da0c48c4Sopenharmony_ci else 738da0c48c4Sopenharmony_ci scnnames = (const char **) alloca (sizeof (const char *) * shnum); 739da0c48c4Sopenharmony_ci /* Get the section header string table index. */ 740da0c48c4Sopenharmony_ci size_t shstrndx; 741da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) 742da0c48c4Sopenharmony_ci error_exit (0, _("cannot get section header string table index")); 743da0c48c4Sopenharmony_ci 744da0c48c4Sopenharmony_ci /* Cache the section names. */ 745da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 746da0c48c4Sopenharmony_ci size_t cnt = 1; 747da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (ebl->elf, scn)) != NULL) 748da0c48c4Sopenharmony_ci { 749da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 750da0c48c4Sopenharmony_ci GElf_Shdr *shdr; 751da0c48c4Sopenharmony_ci 752da0c48c4Sopenharmony_ci assert (elf_ndxscn (scn) == cnt); 753da0c48c4Sopenharmony_ci cnt++; 754da0c48c4Sopenharmony_ci 755da0c48c4Sopenharmony_ci char *name = NULL; 756da0c48c4Sopenharmony_ci shdr = gelf_getshdr (scn, &shdr_mem); 757da0c48c4Sopenharmony_ci if (shdr != NULL) 758da0c48c4Sopenharmony_ci name = elf_strptr (ebl->elf, shstrndx, shdr->sh_name); 759da0c48c4Sopenharmony_ci if (unlikely (name == NULL)) 760da0c48c4Sopenharmony_ci name = "[invalid section name]"; 761da0c48c4Sopenharmony_ci scnnames[elf_ndxscn (scn)] = name; 762da0c48c4Sopenharmony_ci } 763da0c48c4Sopenharmony_ci 764da0c48c4Sopenharmony_ci int digits = length_map[gelf_getclass (ebl->elf) - 1][radix]; 765da0c48c4Sopenharmony_ci 766da0c48c4Sopenharmony_ci /* We always print this prolog. */ 767da0c48c4Sopenharmony_ci printf (_("\n\nSymbols from %s:\n\n"), fullname); 768da0c48c4Sopenharmony_ci 769da0c48c4Sopenharmony_ci /* The header line. */ 770da0c48c4Sopenharmony_ci printf (_("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"), 771da0c48c4Sopenharmony_ci print_file_name ? (int) strlen (fullname) + 1: 0, "", 772da0c48c4Sopenharmony_ci longest_name, sgettext ("sysv|Name"), 773da0c48c4Sopenharmony_ci /* TRANS: the "sysv|" parts makes the string unique. */ 774da0c48c4Sopenharmony_ci digits, sgettext ("sysv|Value"), 775da0c48c4Sopenharmony_ci /* TRANS: the "sysv|" parts makes the string unique. */ 776da0c48c4Sopenharmony_ci digits, sgettext ("sysv|Size"), 777da0c48c4Sopenharmony_ci /* TRANS: the "sysv|" parts makes the string unique. */ 778da0c48c4Sopenharmony_ci longest_where, sgettext ("sysv|Line")); 779da0c48c4Sopenharmony_ci 780da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 781da0c48c4Sopenharmony_ci size_t demangle_buffer_len = 0; 782da0c48c4Sopenharmony_ci char *demangle_buffer = NULL; 783da0c48c4Sopenharmony_ci#endif 784da0c48c4Sopenharmony_ci 785da0c48c4Sopenharmony_ci /* Iterate over all symbols. */ 786da0c48c4Sopenharmony_ci for (cnt = 0; cnt < nsyms; ++cnt) 787da0c48c4Sopenharmony_ci { 788da0c48c4Sopenharmony_ci /* In this format SECTION entries are not printed. */ 789da0c48c4Sopenharmony_ci if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_SECTION) 790da0c48c4Sopenharmony_ci continue; 791da0c48c4Sopenharmony_ci 792da0c48c4Sopenharmony_ci char symstrbuf[50]; 793da0c48c4Sopenharmony_ci const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name, 794da0c48c4Sopenharmony_ci symstrbuf, sizeof symstrbuf); 795da0c48c4Sopenharmony_ci 796da0c48c4Sopenharmony_ci /* Printing entries with a zero-length name makes the output 797da0c48c4Sopenharmony_ci not very well parseable. Since these entries don't carry 798da0c48c4Sopenharmony_ci much information we leave them out. */ 799da0c48c4Sopenharmony_ci if (symstr[0] == '\0') 800da0c48c4Sopenharmony_ci continue; 801da0c48c4Sopenharmony_ci 802da0c48c4Sopenharmony_ci /* We do not print the entries for files. */ 803da0c48c4Sopenharmony_ci if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE) 804da0c48c4Sopenharmony_ci continue; 805da0c48c4Sopenharmony_ci 806da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 807da0c48c4Sopenharmony_ci /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */ 808da0c48c4Sopenharmony_ci if (demangle && symstr[0] == '_' && symstr[1] == 'Z') 809da0c48c4Sopenharmony_ci { 810da0c48c4Sopenharmony_ci int status = -1; 811da0c48c4Sopenharmony_ci char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 812da0c48c4Sopenharmony_ci &demangle_buffer_len, &status); 813da0c48c4Sopenharmony_ci 814da0c48c4Sopenharmony_ci if (status == 0) 815da0c48c4Sopenharmony_ci symstr = dmsymstr; 816da0c48c4Sopenharmony_ci } 817da0c48c4Sopenharmony_ci#endif 818da0c48c4Sopenharmony_ci 819da0c48c4Sopenharmony_ci char symbindbuf[50]; 820da0c48c4Sopenharmony_ci char symtypebuf[50]; 821da0c48c4Sopenharmony_ci char secnamebuf[1024]; 822da0c48c4Sopenharmony_ci char addressbuf[(64 + 2) / 3 + 1]; 823da0c48c4Sopenharmony_ci char sizebuf[(64 + 2) / 3 + 1]; 824da0c48c4Sopenharmony_ci 825da0c48c4Sopenharmony_ci /* If we have to precede the line with the file name. */ 826da0c48c4Sopenharmony_ci if (print_file_name) 827da0c48c4Sopenharmony_ci { 828da0c48c4Sopenharmony_ci fputs_unlocked (fullname, stdout); 829da0c48c4Sopenharmony_ci putchar_unlocked (':'); 830da0c48c4Sopenharmony_ci } 831da0c48c4Sopenharmony_ci 832da0c48c4Sopenharmony_ci /* Covert the address. */ 833da0c48c4Sopenharmony_ci if (syms[cnt].sym.st_shndx == SHN_UNDEF) 834da0c48c4Sopenharmony_ci { 835da0c48c4Sopenharmony_ci sprintf (addressbuf, "%*c", digits, ' '); 836da0c48c4Sopenharmony_ci sprintf (sizebuf, "%*c", digits, ' '); 837da0c48c4Sopenharmony_ci } 838da0c48c4Sopenharmony_ci else 839da0c48c4Sopenharmony_ci { 840da0c48c4Sopenharmony_ci snprintf (addressbuf, sizeof (addressbuf), 841da0c48c4Sopenharmony_ci (radix == radix_hex ? "%0*" PRIx64 842da0c48c4Sopenharmony_ci : (radix == radix_decimal ? "%0*" PRId64 843da0c48c4Sopenharmony_ci : "%0*" PRIo64)), 844da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_value); 845da0c48c4Sopenharmony_ci snprintf (sizebuf, sizeof (sizebuf), 846da0c48c4Sopenharmony_ci (radix == radix_hex ? "%0*" PRIx64 847da0c48c4Sopenharmony_ci : (radix == radix_decimal ? "%0*" PRId64 848da0c48c4Sopenharmony_ci : "%0*" PRIo64)), 849da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_size); 850da0c48c4Sopenharmony_ci } 851da0c48c4Sopenharmony_ci 852da0c48c4Sopenharmony_ci /* Print the actual string. */ 853da0c48c4Sopenharmony_ci const char *bind; 854da0c48c4Sopenharmony_ci bind = ebl_symbol_binding_name (ebl, 855da0c48c4Sopenharmony_ci GELF_ST_BIND (syms[cnt].sym.st_info), 856da0c48c4Sopenharmony_ci symbindbuf, sizeof (symbindbuf)); 857da0c48c4Sopenharmony_ci if (bind != NULL && startswith (bind, "GNU_")) 858da0c48c4Sopenharmony_ci bind += strlen ("GNU_"); 859da0c48c4Sopenharmony_ci printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n", 860da0c48c4Sopenharmony_ci longest_name, symstr, addressbuf, bind, 861da0c48c4Sopenharmony_ci ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info), 862da0c48c4Sopenharmony_ci symtypebuf, sizeof (symtypebuf)), 863da0c48c4Sopenharmony_ci sizebuf, longest_where, syms[cnt].where, 864da0c48c4Sopenharmony_ci ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx, 865da0c48c4Sopenharmony_ci secnamebuf, sizeof (secnamebuf), scnnames, 866da0c48c4Sopenharmony_ci shnum)); 867da0c48c4Sopenharmony_ci } 868da0c48c4Sopenharmony_ci 869da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 870da0c48c4Sopenharmony_ci free (demangle_buffer); 871da0c48c4Sopenharmony_ci#endif 872da0c48c4Sopenharmony_ci 873da0c48c4Sopenharmony_ci if (scnnames_malloced) 874da0c48c4Sopenharmony_ci free (scnnames); 875da0c48c4Sopenharmony_ci} 876da0c48c4Sopenharmony_ci 877da0c48c4Sopenharmony_ci 878da0c48c4Sopenharmony_cistatic char 879da0c48c4Sopenharmony_ciclass_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym) 880da0c48c4Sopenharmony_ci{ 881da0c48c4Sopenharmony_ci int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL; 882da0c48c4Sopenharmony_ci 883da0c48c4Sopenharmony_ci /* XXX Add support for architecture specific types and classes. */ 884da0c48c4Sopenharmony_ci if (sym->st_shndx == SHN_ABS) 885da0c48c4Sopenharmony_ci return local_p ? 'a' : 'A'; 886da0c48c4Sopenharmony_ci 887da0c48c4Sopenharmony_ci if (sym->st_shndx == SHN_UNDEF) 888da0c48c4Sopenharmony_ci /* Undefined symbols must be global. */ 889da0c48c4Sopenharmony_ci return 'U'; 890da0c48c4Sopenharmony_ci 891da0c48c4Sopenharmony_ci char result = "NDTSFBD "[GELF_ST_TYPE (sym->st_info)]; 892da0c48c4Sopenharmony_ci 893da0c48c4Sopenharmony_ci if (result == 'D') 894da0c48c4Sopenharmony_ci { 895da0c48c4Sopenharmony_ci /* Special handling: unique data symbols. */ 896da0c48c4Sopenharmony_ci if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX 897da0c48c4Sopenharmony_ci && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE) 898da0c48c4Sopenharmony_ci result = 'u'; 899da0c48c4Sopenharmony_ci else if (GELF_ST_BIND (sym->st_info) == STB_WEAK) 900da0c48c4Sopenharmony_ci result = 'V'; 901da0c48c4Sopenharmony_ci else if (sym->st_shndx == SHN_COMMON) 902da0c48c4Sopenharmony_ci result = 'C'; 903da0c48c4Sopenharmony_ci else 904da0c48c4Sopenharmony_ci { 905da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 906da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, sym->st_shndx), 907da0c48c4Sopenharmony_ci &shdr_mem); 908da0c48c4Sopenharmony_ci if (shdr != NULL) 909da0c48c4Sopenharmony_ci { 910da0c48c4Sopenharmony_ci if ((shdr->sh_flags & SHF_WRITE) == 0) 911da0c48c4Sopenharmony_ci result = 'R'; 912da0c48c4Sopenharmony_ci else if (shdr->sh_type == SHT_NOBITS) 913da0c48c4Sopenharmony_ci result = 'B'; 914da0c48c4Sopenharmony_ci } 915da0c48c4Sopenharmony_ci } 916da0c48c4Sopenharmony_ci } 917da0c48c4Sopenharmony_ci else if (result == 'T') 918da0c48c4Sopenharmony_ci { 919da0c48c4Sopenharmony_ci if (GELF_ST_BIND (sym->st_info) == STB_WEAK) 920da0c48c4Sopenharmony_ci result = 'W'; 921da0c48c4Sopenharmony_ci } 922da0c48c4Sopenharmony_ci 923da0c48c4Sopenharmony_ci return local_p ? tolower (result) : result; 924da0c48c4Sopenharmony_ci} 925da0c48c4Sopenharmony_ci 926da0c48c4Sopenharmony_ci 927da0c48c4Sopenharmony_cistatic void 928da0c48c4Sopenharmony_cishow_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, 929da0c48c4Sopenharmony_ci const char *prefix, const char *fname, const char *fullname, 930da0c48c4Sopenharmony_ci GElf_SymX *syms, size_t nsyms) 931da0c48c4Sopenharmony_ci{ 932da0c48c4Sopenharmony_ci int digits = length_map[gelf_getclass (elf) - 1][radix]; 933da0c48c4Sopenharmony_ci 934da0c48c4Sopenharmony_ci if (prefix != NULL && ! print_file_name) 935da0c48c4Sopenharmony_ci printf ("\n%s:\n", fname); 936da0c48c4Sopenharmony_ci 937da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 938da0c48c4Sopenharmony_ci size_t demangle_buffer_len = 0; 939da0c48c4Sopenharmony_ci char *demangle_buffer = NULL; 940da0c48c4Sopenharmony_ci#endif 941da0c48c4Sopenharmony_ci 942da0c48c4Sopenharmony_ci /* Iterate over all symbols. */ 943da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < nsyms; ++cnt) 944da0c48c4Sopenharmony_ci { 945da0c48c4Sopenharmony_ci char symstrbuf[50]; 946da0c48c4Sopenharmony_ci const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name, 947da0c48c4Sopenharmony_ci symstrbuf, sizeof symstrbuf); 948da0c48c4Sopenharmony_ci 949da0c48c4Sopenharmony_ci /* Printing entries with a zero-length name makes the output 950da0c48c4Sopenharmony_ci not very well parseable. Since these entries don't carry 951da0c48c4Sopenharmony_ci much information we leave them out. */ 952da0c48c4Sopenharmony_ci if (symstr[0] == '\0') 953da0c48c4Sopenharmony_ci continue; 954da0c48c4Sopenharmony_ci 955da0c48c4Sopenharmony_ci /* We do not print the entries for files. */ 956da0c48c4Sopenharmony_ci if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE) 957da0c48c4Sopenharmony_ci continue; 958da0c48c4Sopenharmony_ci 959da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 960da0c48c4Sopenharmony_ci /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */ 961da0c48c4Sopenharmony_ci if (demangle && symstr[0] == '_' && symstr[1] == 'Z') 962da0c48c4Sopenharmony_ci { 963da0c48c4Sopenharmony_ci int status = -1; 964da0c48c4Sopenharmony_ci char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 965da0c48c4Sopenharmony_ci &demangle_buffer_len, &status); 966da0c48c4Sopenharmony_ci 967da0c48c4Sopenharmony_ci if (status == 0) 968da0c48c4Sopenharmony_ci symstr = dmsymstr; 969da0c48c4Sopenharmony_ci } 970da0c48c4Sopenharmony_ci#endif 971da0c48c4Sopenharmony_ci 972da0c48c4Sopenharmony_ci /* If we have to precede the line with the file name. */ 973da0c48c4Sopenharmony_ci if (print_file_name) 974da0c48c4Sopenharmony_ci { 975da0c48c4Sopenharmony_ci fputs_unlocked (fullname, stdout); 976da0c48c4Sopenharmony_ci putchar_unlocked (':'); 977da0c48c4Sopenharmony_ci } 978da0c48c4Sopenharmony_ci 979da0c48c4Sopenharmony_ci bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS; 980da0c48c4Sopenharmony_ci bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK; 981da0c48c4Sopenharmony_ci const char *marker = (mark_special 982da0c48c4Sopenharmony_ci ? (is_tls ? "@" : (is_weak ? "*" : " ")) : ""); 983da0c48c4Sopenharmony_ci 984da0c48c4Sopenharmony_ci if (syms[cnt].sym.st_shndx == SHN_UNDEF) 985da0c48c4Sopenharmony_ci { 986da0c48c4Sopenharmony_ci const char *color = ""; 987da0c48c4Sopenharmony_ci if (color_mode) 988da0c48c4Sopenharmony_ci { 989da0c48c4Sopenharmony_ci if (is_tls) 990da0c48c4Sopenharmony_ci color = color_undef_tls; 991da0c48c4Sopenharmony_ci else if (is_weak) 992da0c48c4Sopenharmony_ci color = color_undef_weak; 993da0c48c4Sopenharmony_ci else 994da0c48c4Sopenharmony_ci color = color_undef; 995da0c48c4Sopenharmony_ci } 996da0c48c4Sopenharmony_ci 997da0c48c4Sopenharmony_ci printf ("%*s %sU%s %s", digits, "", color, marker, symstr); 998da0c48c4Sopenharmony_ci } 999da0c48c4Sopenharmony_ci else 1000da0c48c4Sopenharmony_ci { 1001da0c48c4Sopenharmony_ci const char *color = ""; 1002da0c48c4Sopenharmony_ci if (color_mode) 1003da0c48c4Sopenharmony_ci { 1004da0c48c4Sopenharmony_ci if (is_tls) 1005da0c48c4Sopenharmony_ci color = color_tls; 1006da0c48c4Sopenharmony_ci else if (is_weak) 1007da0c48c4Sopenharmony_ci color = color_weak; 1008da0c48c4Sopenharmony_ci else 1009da0c48c4Sopenharmony_ci color = color_symbol; 1010da0c48c4Sopenharmony_ci } 1011da0c48c4Sopenharmony_ci if (print_size && syms[cnt].sym.st_size != 0) 1012da0c48c4Sopenharmony_ci { 1013da0c48c4Sopenharmony_ci#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %10$0*9$" PRIx64 " %7$s%3$c%4$s %5$s" 1014da0c48c4Sopenharmony_ci#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %10$*9$" PRId64 " %7$s%3$c%4$s %5$s" 1015da0c48c4Sopenharmony_ci#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %10$0*9$" PRIo64 " %7$s%3$c%4$s %5$s" 1016da0c48c4Sopenharmony_ci printf ((radix == radix_hex ? HEXFMT 1017da0c48c4Sopenharmony_ci : (radix == radix_decimal ? DECFMT : OCTFMT)), 1018da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_value, 1019da0c48c4Sopenharmony_ci class_type_char (elf, ehdr, &syms[cnt].sym), marker, 1020da0c48c4Sopenharmony_ci symstr, 1021da0c48c4Sopenharmony_ci color_mode ? color_address : "", 1022da0c48c4Sopenharmony_ci color, 1023da0c48c4Sopenharmony_ci color_mode ? color_off : "", 1024da0c48c4Sopenharmony_ci digits, (uint64_t) syms[cnt].sym.st_size); 1025da0c48c4Sopenharmony_ci#undef HEXFMT 1026da0c48c4Sopenharmony_ci#undef DECFMT 1027da0c48c4Sopenharmony_ci#undef OCTFMT 1028da0c48c4Sopenharmony_ci } 1029da0c48c4Sopenharmony_ci else 1030da0c48c4Sopenharmony_ci { 1031da0c48c4Sopenharmony_ci#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %7$s%3$c%4$s %5$s" 1032da0c48c4Sopenharmony_ci#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %7$s%3$c%4$s %5$s" 1033da0c48c4Sopenharmony_ci#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %7$s%3$c%4$s %5$s" 1034da0c48c4Sopenharmony_ci printf ((radix == radix_hex ? HEXFMT 1035da0c48c4Sopenharmony_ci : (radix == radix_decimal ? DECFMT : OCTFMT)), 1036da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_value, 1037da0c48c4Sopenharmony_ci class_type_char (elf, ehdr, &syms[cnt].sym), marker, 1038da0c48c4Sopenharmony_ci symstr, 1039da0c48c4Sopenharmony_ci color_mode ? color_address : "", 1040da0c48c4Sopenharmony_ci color, 1041da0c48c4Sopenharmony_ci color_mode ? color_off : ""); 1042da0c48c4Sopenharmony_ci#undef HEXFMT 1043da0c48c4Sopenharmony_ci#undef DECFMT 1044da0c48c4Sopenharmony_ci#undef OCTFMT 1045da0c48c4Sopenharmony_ci } 1046da0c48c4Sopenharmony_ci } 1047da0c48c4Sopenharmony_ci 1048da0c48c4Sopenharmony_ci if (color_mode) 1049da0c48c4Sopenharmony_ci fputs_unlocked (color_off, stdout); 1050da0c48c4Sopenharmony_ci putchar_unlocked ('\n'); 1051da0c48c4Sopenharmony_ci } 1052da0c48c4Sopenharmony_ci 1053da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1054da0c48c4Sopenharmony_ci free (demangle_buffer); 1055da0c48c4Sopenharmony_ci#endif 1056da0c48c4Sopenharmony_ci} 1057da0c48c4Sopenharmony_ci 1058da0c48c4Sopenharmony_ci 1059da0c48c4Sopenharmony_cistatic void 1060da0c48c4Sopenharmony_cishow_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx, 1061da0c48c4Sopenharmony_ci const char *prefix, const char *fullname, GElf_SymX *syms, 1062da0c48c4Sopenharmony_ci size_t nsyms) 1063da0c48c4Sopenharmony_ci{ 1064da0c48c4Sopenharmony_ci if (prefix != NULL && ! print_file_name) 1065da0c48c4Sopenharmony_ci printf ("%s:\n", fullname); 1066da0c48c4Sopenharmony_ci 1067da0c48c4Sopenharmony_ci int digits = length_map[gelf_getclass (elf) - 1][radix]; 1068da0c48c4Sopenharmony_ci 1069da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1070da0c48c4Sopenharmony_ci size_t demangle_buffer_len = 0; 1071da0c48c4Sopenharmony_ci char *demangle_buffer = NULL; 1072da0c48c4Sopenharmony_ci#endif 1073da0c48c4Sopenharmony_ci 1074da0c48c4Sopenharmony_ci /* Iterate over all symbols. */ 1075da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < nsyms; ++cnt) 1076da0c48c4Sopenharmony_ci { 1077da0c48c4Sopenharmony_ci char symstrbuf[50]; 1078da0c48c4Sopenharmony_ci const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name, 1079da0c48c4Sopenharmony_ci symstrbuf, sizeof symstrbuf); 1080da0c48c4Sopenharmony_ci 1081da0c48c4Sopenharmony_ci /* Printing entries with a zero-length name makes the output 1082da0c48c4Sopenharmony_ci not very well parseable. Since these entries don't carry 1083da0c48c4Sopenharmony_ci much information we leave them out. */ 1084da0c48c4Sopenharmony_ci if (symstr[0] == '\0') 1085da0c48c4Sopenharmony_ci continue; 1086da0c48c4Sopenharmony_ci 1087da0c48c4Sopenharmony_ci /* We do not print the entries for files. */ 1088da0c48c4Sopenharmony_ci if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE) 1089da0c48c4Sopenharmony_ci continue; 1090da0c48c4Sopenharmony_ci 1091da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1092da0c48c4Sopenharmony_ci /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */ 1093da0c48c4Sopenharmony_ci if (demangle && symstr[0] == '_' && symstr[1] == 'Z') 1094da0c48c4Sopenharmony_ci { 1095da0c48c4Sopenharmony_ci int status = -1; 1096da0c48c4Sopenharmony_ci char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 1097da0c48c4Sopenharmony_ci &demangle_buffer_len, &status); 1098da0c48c4Sopenharmony_ci 1099da0c48c4Sopenharmony_ci if (status == 0) 1100da0c48c4Sopenharmony_ci symstr = dmsymstr; 1101da0c48c4Sopenharmony_ci } 1102da0c48c4Sopenharmony_ci#endif 1103da0c48c4Sopenharmony_ci 1104da0c48c4Sopenharmony_ci /* If we have to precede the line with the file name. */ 1105da0c48c4Sopenharmony_ci if (print_file_name) 1106da0c48c4Sopenharmony_ci { 1107da0c48c4Sopenharmony_ci fputs_unlocked (fullname, stdout); 1108da0c48c4Sopenharmony_ci putchar_unlocked (':'); 1109da0c48c4Sopenharmony_ci putchar_unlocked (' '); 1110da0c48c4Sopenharmony_ci } 1111da0c48c4Sopenharmony_ci 1112da0c48c4Sopenharmony_ci printf ("%s %c%s", symstr, 1113da0c48c4Sopenharmony_ci class_type_char (elf, ehdr, &syms[cnt].sym), 1114da0c48c4Sopenharmony_ci mark_special 1115da0c48c4Sopenharmony_ci ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS 1116da0c48c4Sopenharmony_ci ? "@" 1117da0c48c4Sopenharmony_ci : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK 1118da0c48c4Sopenharmony_ci ? "*" : " ")) 1119da0c48c4Sopenharmony_ci : ""); 1120da0c48c4Sopenharmony_ci if (syms[cnt].sym.st_shndx != SHN_UNDEF) 1121da0c48c4Sopenharmony_ci printf ((radix == radix_hex 1122da0c48c4Sopenharmony_ci ? " %0*" PRIx64 " %0*" PRIx64 1123da0c48c4Sopenharmony_ci : (radix == radix_decimal 1124da0c48c4Sopenharmony_ci ? " %*" PRId64 " %*" PRId64 1125da0c48c4Sopenharmony_ci : " %0*" PRIo64 " %0*" PRIo64)), 1126da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_value, 1127da0c48c4Sopenharmony_ci digits, syms[cnt].sym.st_size); 1128da0c48c4Sopenharmony_ci putchar ('\n'); 1129da0c48c4Sopenharmony_ci } 1130da0c48c4Sopenharmony_ci 1131da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1132da0c48c4Sopenharmony_ci free (demangle_buffer); 1133da0c48c4Sopenharmony_ci#endif 1134da0c48c4Sopenharmony_ci} 1135da0c48c4Sopenharmony_ci 1136da0c48c4Sopenharmony_ci 1137da0c48c4Sopenharmony_ci/* Maximum size of memory we allocate on the stack. */ 1138da0c48c4Sopenharmony_ci#define MAX_STACK_ALLOC 65536 1139da0c48c4Sopenharmony_ci 1140da0c48c4Sopenharmony_cistatic int 1141da0c48c4Sopenharmony_cisort_by_address (const void *p1, const void *p2) 1142da0c48c4Sopenharmony_ci{ 1143da0c48c4Sopenharmony_ci GElf_SymX *s1 = (GElf_SymX *) p1; 1144da0c48c4Sopenharmony_ci GElf_SymX *s2 = (GElf_SymX *) p2; 1145da0c48c4Sopenharmony_ci 1146da0c48c4Sopenharmony_ci int result = (s1->sym.st_value < s2->sym.st_value 1147da0c48c4Sopenharmony_ci ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1)); 1148da0c48c4Sopenharmony_ci 1149da0c48c4Sopenharmony_ci return reverse_sort ? -result : result; 1150da0c48c4Sopenharmony_ci} 1151da0c48c4Sopenharmony_ci 1152da0c48c4Sopenharmony_cistatic Elf *sort_by_name_elf; 1153da0c48c4Sopenharmony_cistatic size_t sort_by_name_ndx; 1154da0c48c4Sopenharmony_ci 1155da0c48c4Sopenharmony_cistatic int 1156da0c48c4Sopenharmony_cisort_by_name (const void *p1, const void *p2) 1157da0c48c4Sopenharmony_ci{ 1158da0c48c4Sopenharmony_ci GElf_SymX *s1 = (GElf_SymX *) p1; 1159da0c48c4Sopenharmony_ci GElf_SymX *s2 = (GElf_SymX *) p2; 1160da0c48c4Sopenharmony_ci 1161da0c48c4Sopenharmony_ci const char *n1 = elf_strptr (sort_by_name_elf, sort_by_name_ndx, 1162da0c48c4Sopenharmony_ci s1->sym.st_name) ?: ""; 1163da0c48c4Sopenharmony_ci const char *n2 = elf_strptr (sort_by_name_elf, sort_by_name_ndx, 1164da0c48c4Sopenharmony_ci s2->sym.st_name) ?: ""; 1165da0c48c4Sopenharmony_ci 1166da0c48c4Sopenharmony_ci int result = strcmp (n1, n2); 1167da0c48c4Sopenharmony_ci 1168da0c48c4Sopenharmony_ci return reverse_sort ? -result : result; 1169da0c48c4Sopenharmony_ci} 1170da0c48c4Sopenharmony_ci 1171da0c48c4Sopenharmony_ci/* Stub libdwfl callback, only the ELF handle already open is ever 1172da0c48c4Sopenharmony_ci used. Only used for finding the alternate debug file if the Dwarf 1173da0c48c4Sopenharmony_ci comes from the main file. We are not interested in separate 1174da0c48c4Sopenharmony_ci debuginfo. */ 1175da0c48c4Sopenharmony_cistatic int 1176da0c48c4Sopenharmony_cifind_no_debuginfo (Dwfl_Module *mod, 1177da0c48c4Sopenharmony_ci void **userdata, 1178da0c48c4Sopenharmony_ci const char *modname, 1179da0c48c4Sopenharmony_ci Dwarf_Addr base, 1180da0c48c4Sopenharmony_ci const char *file_name, 1181da0c48c4Sopenharmony_ci const char *debuglink_file, 1182da0c48c4Sopenharmony_ci GElf_Word debuglink_crc, 1183da0c48c4Sopenharmony_ci char **debuginfo_file_name) 1184da0c48c4Sopenharmony_ci{ 1185da0c48c4Sopenharmony_ci Dwarf_Addr dwbias; 1186da0c48c4Sopenharmony_ci dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL); 1187da0c48c4Sopenharmony_ci 1188da0c48c4Sopenharmony_ci /* We are only interested if the Dwarf has been setup on the main 1189da0c48c4Sopenharmony_ci elf file but is only missing the alternate debug link. If dwbias 1190da0c48c4Sopenharmony_ci hasn't even been setup, this is searching for separate debuginfo 1191da0c48c4Sopenharmony_ci for the main elf. We don't care in that case. */ 1192da0c48c4Sopenharmony_ci if (dwbias == (Dwarf_Addr) -1) 1193da0c48c4Sopenharmony_ci return -1; 1194da0c48c4Sopenharmony_ci 1195da0c48c4Sopenharmony_ci return dwfl_standard_find_debuginfo (mod, userdata, modname, base, 1196da0c48c4Sopenharmony_ci file_name, debuglink_file, 1197da0c48c4Sopenharmony_ci debuglink_crc, debuginfo_file_name); 1198da0c48c4Sopenharmony_ci} 1199da0c48c4Sopenharmony_ci 1200da0c48c4Sopenharmony_ci/* Get the Dwarf for the module/file we want. */ 1201da0c48c4Sopenharmony_cistruct getdbg 1202da0c48c4Sopenharmony_ci{ 1203da0c48c4Sopenharmony_ci const char *name; 1204da0c48c4Sopenharmony_ci Dwarf **dbg; 1205da0c48c4Sopenharmony_ci}; 1206da0c48c4Sopenharmony_ci 1207da0c48c4Sopenharmony_cistatic int 1208da0c48c4Sopenharmony_cigetdbg_dwflmod (Dwfl_Module *dwflmod, 1209da0c48c4Sopenharmony_ci void **userdata __attribute__ ((unused)), 1210da0c48c4Sopenharmony_ci const char *name, 1211da0c48c4Sopenharmony_ci Dwarf_Addr base __attribute__ ((unused)), 1212da0c48c4Sopenharmony_ci void *arg) 1213da0c48c4Sopenharmony_ci{ 1214da0c48c4Sopenharmony_ci struct getdbg *get = (struct getdbg *) arg; 1215da0c48c4Sopenharmony_ci if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0) 1216da0c48c4Sopenharmony_ci { 1217da0c48c4Sopenharmony_ci Dwarf_Addr bias; 1218da0c48c4Sopenharmony_ci *get->dbg = dwfl_module_getdwarf (dwflmod, &bias); 1219da0c48c4Sopenharmony_ci return DWARF_CB_ABORT; 1220da0c48c4Sopenharmony_ci } 1221da0c48c4Sopenharmony_ci 1222da0c48c4Sopenharmony_ci return DWARF_CB_OK; 1223da0c48c4Sopenharmony_ci} 1224da0c48c4Sopenharmony_ci 1225da0c48c4Sopenharmony_cistatic void 1226da0c48c4Sopenharmony_cishow_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr, 1227da0c48c4Sopenharmony_ci Elf_Scn *scn, Elf_Scn *xndxscn, 1228da0c48c4Sopenharmony_ci GElf_Shdr *shdr, const char *prefix, const char *fname, 1229da0c48c4Sopenharmony_ci const char *fullname) 1230da0c48c4Sopenharmony_ci{ 1231da0c48c4Sopenharmony_ci /* Get the section header string table index. */ 1232da0c48c4Sopenharmony_ci size_t shstrndx; 1233da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0) 1234da0c48c4Sopenharmony_ci error_exit (0, _("cannot get section header string table index")); 1235da0c48c4Sopenharmony_ci 1236da0c48c4Sopenharmony_ci /* The section is that large. */ 1237da0c48c4Sopenharmony_ci size_t size = shdr->sh_size; 1238da0c48c4Sopenharmony_ci /* One entry is this large. */ 1239da0c48c4Sopenharmony_ci size_t entsize = shdr->sh_entsize; 1240da0c48c4Sopenharmony_ci 1241da0c48c4Sopenharmony_ci /* Consistency checks. */ 1242da0c48c4Sopenharmony_ci if (entsize == 0 1243da0c48c4Sopenharmony_ci || entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT)) 1244da0c48c4Sopenharmony_ci error (0, 0, 1245da0c48c4Sopenharmony_ci _("%s: entry size in section %zd `%s' is not what we expect"), 1246da0c48c4Sopenharmony_ci fullname, elf_ndxscn (scn), 1247da0c48c4Sopenharmony_ci elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); 1248da0c48c4Sopenharmony_ci else if (size % entsize != 0) 1249da0c48c4Sopenharmony_ci error (0, 0, 1250da0c48c4Sopenharmony_ci _("%s: size of section %zd `%s' is not multiple of entry size"), 1251da0c48c4Sopenharmony_ci fullname, elf_ndxscn (scn), 1252da0c48c4Sopenharmony_ci elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); 1253da0c48c4Sopenharmony_ci 1254da0c48c4Sopenharmony_ci /* Compute number of entries. Handle buggy entsize values. */ 1255da0c48c4Sopenharmony_ci size_t nentries = size / (entsize ?: 1); 1256da0c48c4Sopenharmony_ci 1257da0c48c4Sopenharmony_ci 1258da0c48c4Sopenharmony_ci#define obstack_chunk_alloc xmalloc 1259da0c48c4Sopenharmony_ci#define obstack_chunk_free free 1260da0c48c4Sopenharmony_ci struct obstack whereob; 1261da0c48c4Sopenharmony_ci obstack_init (&whereob); 1262da0c48c4Sopenharmony_ci 1263da0c48c4Sopenharmony_ci /* Get a DWARF debugging descriptor. It's no problem if this isn't 1264da0c48c4Sopenharmony_ci possible. We just won't print any line number information. */ 1265da0c48c4Sopenharmony_ci Dwarf *dbg = NULL; 1266da0c48c4Sopenharmony_ci Dwfl *dwfl = NULL; 1267da0c48c4Sopenharmony_ci if (format == format_sysv) 1268da0c48c4Sopenharmony_ci { 1269da0c48c4Sopenharmony_ci if (ehdr->e_type != ET_REL) 1270da0c48c4Sopenharmony_ci dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); 1271da0c48c4Sopenharmony_ci else 1272da0c48c4Sopenharmony_ci { 1273da0c48c4Sopenharmony_ci /* Abuse libdwfl to do the relocations for us. This is just 1274da0c48c4Sopenharmony_ci for the ET_REL file containing Dwarf, so no need for 1275da0c48c4Sopenharmony_ci fancy lookups. */ 1276da0c48c4Sopenharmony_ci 1277da0c48c4Sopenharmony_ci /* Duplicate an fd for dwfl_report_offline to swallow. */ 1278da0c48c4Sopenharmony_ci int dwfl_fd = dup (fd); 1279da0c48c4Sopenharmony_ci if (likely (dwfl_fd >= 0)) 1280da0c48c4Sopenharmony_ci { 1281da0c48c4Sopenharmony_ci static const Dwfl_Callbacks callbacks = 1282da0c48c4Sopenharmony_ci { 1283da0c48c4Sopenharmony_ci .section_address = dwfl_offline_section_address, 1284da0c48c4Sopenharmony_ci .find_debuginfo = find_no_debuginfo 1285da0c48c4Sopenharmony_ci }; 1286da0c48c4Sopenharmony_ci dwfl = dwfl_begin (&callbacks); 1287da0c48c4Sopenharmony_ci if (likely (dwfl != NULL)) 1288da0c48c4Sopenharmony_ci { 1289da0c48c4Sopenharmony_ci /* Let 0 be the logical address of the file (or 1290da0c48c4Sopenharmony_ci first in archive). */ 1291da0c48c4Sopenharmony_ci dwfl->offline_next_address = 0; 1292da0c48c4Sopenharmony_ci if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) 1293da0c48c4Sopenharmony_ci == NULL) 1294da0c48c4Sopenharmony_ci { 1295da0c48c4Sopenharmony_ci /* Consumed on success, not on failure. */ 1296da0c48c4Sopenharmony_ci close (dwfl_fd); 1297da0c48c4Sopenharmony_ci } 1298da0c48c4Sopenharmony_ci else 1299da0c48c4Sopenharmony_ci { 1300da0c48c4Sopenharmony_ci dwfl_report_end (dwfl, NULL, NULL); 1301da0c48c4Sopenharmony_ci 1302da0c48c4Sopenharmony_ci struct getdbg get = { .name = fname, .dbg = &dbg }; 1303da0c48c4Sopenharmony_ci dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0); 1304da0c48c4Sopenharmony_ci } 1305da0c48c4Sopenharmony_ci } 1306da0c48c4Sopenharmony_ci else 1307da0c48c4Sopenharmony_ci close (dwfl_fd); 1308da0c48c4Sopenharmony_ci } 1309da0c48c4Sopenharmony_ci } 1310da0c48c4Sopenharmony_ci if (dbg != NULL) 1311da0c48c4Sopenharmony_ci { 1312da0c48c4Sopenharmony_ci (void) dwarf_getpubnames (dbg, get_global, NULL, 0); 1313da0c48c4Sopenharmony_ci 1314da0c48c4Sopenharmony_ci get_local_names (dbg); 1315da0c48c4Sopenharmony_ci } 1316da0c48c4Sopenharmony_ci } 1317da0c48c4Sopenharmony_ci 1318da0c48c4Sopenharmony_ci /* Get the data of the section. */ 1319da0c48c4Sopenharmony_ci Elf_Data *data = elf_getdata (scn, NULL); 1320da0c48c4Sopenharmony_ci Elf_Data *xndxdata = elf_getdata (xndxscn, NULL); 1321da0c48c4Sopenharmony_ci if (data == NULL || (xndxscn != NULL && xndxdata == NULL)) 1322da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1323da0c48c4Sopenharmony_ci 1324da0c48c4Sopenharmony_ci /* Allocate the memory. 1325da0c48c4Sopenharmony_ci 1326da0c48c4Sopenharmony_ci XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we 1327da0c48c4Sopenharmony_ci can use the data memory instead of copying again if what we read 1328da0c48c4Sopenharmony_ci is a 64 bit file. */ 1329da0c48c4Sopenharmony_ci if (nentries > SIZE_MAX / sizeof (GElf_SymX)) 1330da0c48c4Sopenharmony_ci error_exit (0, _("%s: entries (%zd) in section %zd `%s' is too large"), 1331da0c48c4Sopenharmony_ci fullname, nentries, elf_ndxscn (scn), 1332da0c48c4Sopenharmony_ci elf_strptr (ebl->elf, shstrndx, shdr->sh_name)); 1333da0c48c4Sopenharmony_ci GElf_SymX *sym_mem; 1334da0c48c4Sopenharmony_ci if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC) 1335da0c48c4Sopenharmony_ci sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX)); 1336da0c48c4Sopenharmony_ci else 1337da0c48c4Sopenharmony_ci sym_mem = xmalloc (nentries * sizeof (GElf_SymX)); 1338da0c48c4Sopenharmony_ci 1339da0c48c4Sopenharmony_ci /* Iterate over all symbols. */ 1340da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1341da0c48c4Sopenharmony_ci size_t demangle_buffer_len = 0; 1342da0c48c4Sopenharmony_ci char *demangle_buffer = NULL; 1343da0c48c4Sopenharmony_ci#endif 1344da0c48c4Sopenharmony_ci int longest_name = 4; 1345da0c48c4Sopenharmony_ci int longest_where = 4; 1346da0c48c4Sopenharmony_ci size_t nentries_used = 0; 1347da0c48c4Sopenharmony_ci for (size_t cnt = 0; cnt < nentries; ++cnt) 1348da0c48c4Sopenharmony_ci { 1349da0c48c4Sopenharmony_ci GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt, 1350da0c48c4Sopenharmony_ci &sym_mem[nentries_used].sym, 1351da0c48c4Sopenharmony_ci &sym_mem[nentries_used].xndx); 1352da0c48c4Sopenharmony_ci if (sym == NULL) 1353da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1354da0c48c4Sopenharmony_ci 1355da0c48c4Sopenharmony_ci /* Filter out administrative symbols without a name and those 1356da0c48c4Sopenharmony_ci deselected by the user with command line options. */ 1357da0c48c4Sopenharmony_ci if ((hide_undefined && sym->st_shndx == SHN_UNDEF) 1358da0c48c4Sopenharmony_ci || (hide_defined && sym->st_shndx != SHN_UNDEF) 1359da0c48c4Sopenharmony_ci || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL)) 1360da0c48c4Sopenharmony_ci continue; 1361da0c48c4Sopenharmony_ci 1362da0c48c4Sopenharmony_ci sym_mem[nentries_used].where = ""; 1363da0c48c4Sopenharmony_ci if (format == format_sysv) 1364da0c48c4Sopenharmony_ci { 1365da0c48c4Sopenharmony_ci const char *symstr = elf_strptr (ebl->elf, shdr->sh_link, 1366da0c48c4Sopenharmony_ci sym->st_name); 1367da0c48c4Sopenharmony_ci if (symstr == NULL) 1368da0c48c4Sopenharmony_ci continue; 1369da0c48c4Sopenharmony_ci 1370da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1371da0c48c4Sopenharmony_ci /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */ 1372da0c48c4Sopenharmony_ci if (demangle && symstr[0] == '_' && symstr[1] == 'Z') 1373da0c48c4Sopenharmony_ci { 1374da0c48c4Sopenharmony_ci int status = -1; 1375da0c48c4Sopenharmony_ci char *dmsymstr = __cxa_demangle (symstr, demangle_buffer, 1376da0c48c4Sopenharmony_ci &demangle_buffer_len, &status); 1377da0c48c4Sopenharmony_ci 1378da0c48c4Sopenharmony_ci if (status == 0) 1379da0c48c4Sopenharmony_ci symstr = dmsymstr; 1380da0c48c4Sopenharmony_ci } 1381da0c48c4Sopenharmony_ci#endif 1382da0c48c4Sopenharmony_ci 1383da0c48c4Sopenharmony_ci longest_name = MAX ((size_t) longest_name, strlen (symstr)); 1384da0c48c4Sopenharmony_ci 1385da0c48c4Sopenharmony_ci if (sym->st_shndx != SHN_UNDEF 1386da0c48c4Sopenharmony_ci && GELF_ST_BIND (sym->st_info) != STB_LOCAL 1387da0c48c4Sopenharmony_ci && global_root != NULL) 1388da0c48c4Sopenharmony_ci { 1389da0c48c4Sopenharmony_ci Dwarf_Global fake = { .name = symstr }; 1390da0c48c4Sopenharmony_ci Dwarf_Global **found = tfind (&fake, &global_root, 1391da0c48c4Sopenharmony_ci global_compare); 1392da0c48c4Sopenharmony_ci if (found != NULL) 1393da0c48c4Sopenharmony_ci { 1394da0c48c4Sopenharmony_ci Dwarf_Die die_mem; 1395da0c48c4Sopenharmony_ci Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset, 1396da0c48c4Sopenharmony_ci &die_mem); 1397da0c48c4Sopenharmony_ci 1398da0c48c4Sopenharmony_ci Dwarf_Die cudie_mem; 1399da0c48c4Sopenharmony_ci Dwarf_Die *cudie = NULL; 1400da0c48c4Sopenharmony_ci 1401da0c48c4Sopenharmony_ci Dwarf_Addr lowpc; 1402da0c48c4Sopenharmony_ci Dwarf_Addr highpc; 1403da0c48c4Sopenharmony_ci if (die != NULL 1404da0c48c4Sopenharmony_ci && dwarf_lowpc (die, &lowpc) == 0 1405da0c48c4Sopenharmony_ci && lowpc <= sym->st_value 1406da0c48c4Sopenharmony_ci && dwarf_highpc (die, &highpc) == 0 1407da0c48c4Sopenharmony_ci && highpc > sym->st_value) 1408da0c48c4Sopenharmony_ci cudie = dwarf_offdie (dbg, (*found)->cu_offset, 1409da0c48c4Sopenharmony_ci &cudie_mem); 1410da0c48c4Sopenharmony_ci if (cudie != NULL) 1411da0c48c4Sopenharmony_ci { 1412da0c48c4Sopenharmony_ci Dwarf_Line *line = dwarf_getsrc_die (cudie, 1413da0c48c4Sopenharmony_ci sym->st_value); 1414da0c48c4Sopenharmony_ci if (line != NULL) 1415da0c48c4Sopenharmony_ci { 1416da0c48c4Sopenharmony_ci /* We found the line. */ 1417da0c48c4Sopenharmony_ci int lineno; 1418da0c48c4Sopenharmony_ci (void) dwarf_lineno (line, &lineno); 1419da0c48c4Sopenharmony_ci const char *file = dwarf_linesrc (line, NULL, NULL); 1420da0c48c4Sopenharmony_ci file = (file != NULL) ? basename (file) : "???"; 1421da0c48c4Sopenharmony_ci int n; 1422da0c48c4Sopenharmony_ci n = obstack_printf (&whereob, "%s:%d%c", file, 1423da0c48c4Sopenharmony_ci lineno, '\0'); 1424da0c48c4Sopenharmony_ci sym_mem[nentries_used].where 1425da0c48c4Sopenharmony_ci = obstack_finish (&whereob); 1426da0c48c4Sopenharmony_ci 1427da0c48c4Sopenharmony_ci /* The return value of obstack_print included the 1428da0c48c4Sopenharmony_ci NUL byte, so subtract one. */ 1429da0c48c4Sopenharmony_ci if (--n > (int) longest_where) 1430da0c48c4Sopenharmony_ci longest_where = (size_t) n; 1431da0c48c4Sopenharmony_ci } 1432da0c48c4Sopenharmony_ci } 1433da0c48c4Sopenharmony_ci } 1434da0c48c4Sopenharmony_ci } 1435da0c48c4Sopenharmony_ci 1436da0c48c4Sopenharmony_ci /* Try to find the symbol among the local symbols. */ 1437da0c48c4Sopenharmony_ci if (sym_mem[nentries_used].where[0] == '\0') 1438da0c48c4Sopenharmony_ci { 1439da0c48c4Sopenharmony_ci struct local_name fake = 1440da0c48c4Sopenharmony_ci { 1441da0c48c4Sopenharmony_ci .name = symstr, 1442da0c48c4Sopenharmony_ci .lowpc = sym->st_value, 1443da0c48c4Sopenharmony_ci .highpc = sym->st_value, 1444da0c48c4Sopenharmony_ci }; 1445da0c48c4Sopenharmony_ci struct local_name **found = tfind (&fake, &local_root, 1446da0c48c4Sopenharmony_ci local_compare); 1447da0c48c4Sopenharmony_ci if (found != NULL) 1448da0c48c4Sopenharmony_ci { 1449da0c48c4Sopenharmony_ci /* We found the line. */ 1450da0c48c4Sopenharmony_ci int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c", 1451da0c48c4Sopenharmony_ci basename ((*found)->file), 1452da0c48c4Sopenharmony_ci (*found)->lineno, 1453da0c48c4Sopenharmony_ci '\0'); 1454da0c48c4Sopenharmony_ci sym_mem[nentries_used].where = obstack_finish (&whereob); 1455da0c48c4Sopenharmony_ci 1456da0c48c4Sopenharmony_ci /* The return value of obstack_print included the 1457da0c48c4Sopenharmony_ci NUL byte, so subtract one. */ 1458da0c48c4Sopenharmony_ci if (--n > (int) longest_where) 1459da0c48c4Sopenharmony_ci longest_where = (size_t) n; 1460da0c48c4Sopenharmony_ci } 1461da0c48c4Sopenharmony_ci } 1462da0c48c4Sopenharmony_ci } 1463da0c48c4Sopenharmony_ci 1464da0c48c4Sopenharmony_ci /* We use this entry. */ 1465da0c48c4Sopenharmony_ci ++nentries_used; 1466da0c48c4Sopenharmony_ci } 1467da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 1468da0c48c4Sopenharmony_ci free (demangle_buffer); 1469da0c48c4Sopenharmony_ci#endif 1470da0c48c4Sopenharmony_ci /* Now we know the exact number. */ 1471da0c48c4Sopenharmony_ci size_t nentries_orig = nentries; 1472da0c48c4Sopenharmony_ci nentries = nentries_used; 1473da0c48c4Sopenharmony_ci 1474da0c48c4Sopenharmony_ci /* Sort the entries according to the users wishes. */ 1475da0c48c4Sopenharmony_ci if (sort == sort_name) 1476da0c48c4Sopenharmony_ci { 1477da0c48c4Sopenharmony_ci sort_by_name_elf = ebl->elf; 1478da0c48c4Sopenharmony_ci sort_by_name_ndx = shdr->sh_link; 1479da0c48c4Sopenharmony_ci qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name); 1480da0c48c4Sopenharmony_ci } 1481da0c48c4Sopenharmony_ci else if (sort == sort_numeric) 1482da0c48c4Sopenharmony_ci qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address); 1483da0c48c4Sopenharmony_ci 1484da0c48c4Sopenharmony_ci /* Finally print according to the users selection. */ 1485da0c48c4Sopenharmony_ci switch (format) 1486da0c48c4Sopenharmony_ci { 1487da0c48c4Sopenharmony_ci case format_sysv: 1488da0c48c4Sopenharmony_ci show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries, 1489da0c48c4Sopenharmony_ci longest_name, longest_where); 1490da0c48c4Sopenharmony_ci break; 1491da0c48c4Sopenharmony_ci 1492da0c48c4Sopenharmony_ci case format_bsd: 1493da0c48c4Sopenharmony_ci show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname, 1494da0c48c4Sopenharmony_ci sym_mem, nentries); 1495da0c48c4Sopenharmony_ci break; 1496da0c48c4Sopenharmony_ci 1497da0c48c4Sopenharmony_ci case format_posix: 1498da0c48c4Sopenharmony_ci default: 1499da0c48c4Sopenharmony_ci assert (format == format_posix); 1500da0c48c4Sopenharmony_ci show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname, 1501da0c48c4Sopenharmony_ci sym_mem, nentries); 1502da0c48c4Sopenharmony_ci break; 1503da0c48c4Sopenharmony_ci } 1504da0c48c4Sopenharmony_ci 1505da0c48c4Sopenharmony_ci /* Free all memory. */ 1506da0c48c4Sopenharmony_ci if (nentries_orig * sizeof (sym_mem[0]) >= MAX_STACK_ALLOC) 1507da0c48c4Sopenharmony_ci free (sym_mem); 1508da0c48c4Sopenharmony_ci 1509da0c48c4Sopenharmony_ci obstack_free (&whereob, NULL); 1510da0c48c4Sopenharmony_ci 1511da0c48c4Sopenharmony_ci if (dbg != NULL) 1512da0c48c4Sopenharmony_ci { 1513da0c48c4Sopenharmony_ci tdestroy (global_root, free); 1514da0c48c4Sopenharmony_ci global_root = NULL; 1515da0c48c4Sopenharmony_ci 1516da0c48c4Sopenharmony_ci tdestroy (local_root, free); 1517da0c48c4Sopenharmony_ci local_root = NULL; 1518da0c48c4Sopenharmony_ci 1519da0c48c4Sopenharmony_ci if (dwfl == NULL) 1520da0c48c4Sopenharmony_ci (void) dwarf_end (dbg); 1521da0c48c4Sopenharmony_ci } 1522da0c48c4Sopenharmony_ci if (dwfl != NULL) 1523da0c48c4Sopenharmony_ci dwfl_end (dwfl); 1524da0c48c4Sopenharmony_ci} 1525da0c48c4Sopenharmony_ci 1526da0c48c4Sopenharmony_ci 1527da0c48c4Sopenharmony_cistatic int 1528da0c48c4Sopenharmony_cihandle_elf (int fd, Elf *elf, const char *prefix, const char *fname, 1529da0c48c4Sopenharmony_ci const char *suffix) 1530da0c48c4Sopenharmony_ci{ 1531da0c48c4Sopenharmony_ci size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); 1532da0c48c4Sopenharmony_ci size_t suffix_len = suffix == NULL ? 0 : strlen (suffix); 1533da0c48c4Sopenharmony_ci size_t fname_len = strlen (fname) + 1; 1534da0c48c4Sopenharmony_ci char fullname[prefix_len + 1 + fname_len + suffix_len]; 1535da0c48c4Sopenharmony_ci char *cp = fullname; 1536da0c48c4Sopenharmony_ci Elf_Scn *scn = NULL; 1537da0c48c4Sopenharmony_ci int any = 0; 1538da0c48c4Sopenharmony_ci int result = 0; 1539da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem; 1540da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr; 1541da0c48c4Sopenharmony_ci Ebl *ebl; 1542da0c48c4Sopenharmony_ci 1543da0c48c4Sopenharmony_ci /* Create the full name of the file. */ 1544da0c48c4Sopenharmony_ci if (prefix != NULL) 1545da0c48c4Sopenharmony_ci cp = mempcpy (cp, prefix, prefix_len); 1546da0c48c4Sopenharmony_ci cp = mempcpy (cp, fname, fname_len); 1547da0c48c4Sopenharmony_ci if (suffix != NULL) 1548da0c48c4Sopenharmony_ci memcpy (cp - 1, suffix, suffix_len + 1); 1549da0c48c4Sopenharmony_ci 1550da0c48c4Sopenharmony_ci /* Get the backend for this object file type. */ 1551da0c48c4Sopenharmony_ci ebl = ebl_openbackend (elf); 1552da0c48c4Sopenharmony_ci if (ebl == NULL) 1553da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1554da0c48c4Sopenharmony_ci 1555da0c48c4Sopenharmony_ci /* We need the ELF header in a few places. */ 1556da0c48c4Sopenharmony_ci ehdr = gelf_getehdr (elf, &ehdr_mem); 1557da0c48c4Sopenharmony_ci if (ehdr == NULL) 1558da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1559da0c48c4Sopenharmony_ci 1560da0c48c4Sopenharmony_ci /* If we are asked to print the dynamic symbol table and this is 1561da0c48c4Sopenharmony_ci executable or dynamic executable, fail. */ 1562da0c48c4Sopenharmony_ci if (symsec_type == SHT_DYNSYM 1563da0c48c4Sopenharmony_ci && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) 1564da0c48c4Sopenharmony_ci { 1565da0c48c4Sopenharmony_ci /* XXX Add machine specific object file types. */ 1566da0c48c4Sopenharmony_ci error (0, 0, _("%s%s%s%s: Invalid operation"), 1567da0c48c4Sopenharmony_ci prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : ""); 1568da0c48c4Sopenharmony_ci result = 1; 1569da0c48c4Sopenharmony_ci goto out; 1570da0c48c4Sopenharmony_ci } 1571da0c48c4Sopenharmony_ci 1572da0c48c4Sopenharmony_ci /* Find the symbol table. 1573da0c48c4Sopenharmony_ci 1574da0c48c4Sopenharmony_ci XXX Can there be more than one? Do we print all? Currently we do. */ 1575da0c48c4Sopenharmony_ci while ((scn = elf_nextscn (elf, scn)) != NULL) 1576da0c48c4Sopenharmony_ci { 1577da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 1578da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 1579da0c48c4Sopenharmony_ci 1580da0c48c4Sopenharmony_ci if (shdr == NULL) 1581da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1582da0c48c4Sopenharmony_ci 1583da0c48c4Sopenharmony_ci if (shdr->sh_type == symsec_type) 1584da0c48c4Sopenharmony_ci { 1585da0c48c4Sopenharmony_ci Elf_Scn *xndxscn = NULL; 1586da0c48c4Sopenharmony_ci 1587da0c48c4Sopenharmony_ci /* We have a symbol table. First make sure we remember this. */ 1588da0c48c4Sopenharmony_ci any = 1; 1589da0c48c4Sopenharmony_ci 1590da0c48c4Sopenharmony_ci /* Look for an extended section index table for this section. */ 1591da0c48c4Sopenharmony_ci if (symsec_type == SHT_SYMTAB) 1592da0c48c4Sopenharmony_ci { 1593da0c48c4Sopenharmony_ci size_t scnndx = elf_ndxscn (scn); 1594da0c48c4Sopenharmony_ci 1595da0c48c4Sopenharmony_ci while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL) 1596da0c48c4Sopenharmony_ci { 1597da0c48c4Sopenharmony_ci GElf_Shdr xndxshdr_mem; 1598da0c48c4Sopenharmony_ci GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem); 1599da0c48c4Sopenharmony_ci 1600da0c48c4Sopenharmony_ci if (xndxshdr == NULL) 1601da0c48c4Sopenharmony_ci INTERNAL_ERROR (fullname); 1602da0c48c4Sopenharmony_ci 1603da0c48c4Sopenharmony_ci if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX 1604da0c48c4Sopenharmony_ci && xndxshdr->sh_link == scnndx) 1605da0c48c4Sopenharmony_ci break; 1606da0c48c4Sopenharmony_ci } 1607da0c48c4Sopenharmony_ci } 1608da0c48c4Sopenharmony_ci 1609da0c48c4Sopenharmony_ci show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname, 1610da0c48c4Sopenharmony_ci fullname); 1611da0c48c4Sopenharmony_ci } 1612da0c48c4Sopenharmony_ci } 1613da0c48c4Sopenharmony_ci 1614da0c48c4Sopenharmony_ci if (! any) 1615da0c48c4Sopenharmony_ci { 1616da0c48c4Sopenharmony_ci error (0, 0, _("%s%s%s: no symbols"), 1617da0c48c4Sopenharmony_ci prefix ?: "", prefix ? ":" : "", fname); 1618da0c48c4Sopenharmony_ci result = 1; 1619da0c48c4Sopenharmony_ci } 1620da0c48c4Sopenharmony_ci 1621da0c48c4Sopenharmony_ci out: 1622da0c48c4Sopenharmony_ci /* Close the ELF backend library descriptor. */ 1623da0c48c4Sopenharmony_ci ebl_closebackend (ebl); 1624da0c48c4Sopenharmony_ci 1625da0c48c4Sopenharmony_ci return result; 1626da0c48c4Sopenharmony_ci} 1627da0c48c4Sopenharmony_ci 1628da0c48c4Sopenharmony_ci 1629da0c48c4Sopenharmony_ci#include "debugpred.h" 1630