1da0c48c4Sopenharmony_ci/* Locate source files and line information for given addresses 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2010, 2012, 2013, 2015 Red Hat, Inc. 3da0c48c4Sopenharmony_ci Copyright (C) 2022 Mark J. Wielaard <mark@klomp.org> 4da0c48c4Sopenharmony_ci This file is part of elfutils. 5da0c48c4Sopenharmony_ci Written by Ulrich Drepper <drepper@redhat.com>, 2005. 6da0c48c4Sopenharmony_ci 7da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 8da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 9da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 10da0c48c4Sopenharmony_ci (at your option) any later version. 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 13da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15da0c48c4Sopenharmony_ci GNU General Public License for more details. 16da0c48c4Sopenharmony_ci 17da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 18da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 21da0c48c4Sopenharmony_ci# include <config.h> 22da0c48c4Sopenharmony_ci#endif 23da0c48c4Sopenharmony_ci 24da0c48c4Sopenharmony_ci#include <argp.h> 25da0c48c4Sopenharmony_ci#include <assert.h> 26da0c48c4Sopenharmony_ci#include <errno.h> 27da0c48c4Sopenharmony_ci#include <fcntl.h> 28da0c48c4Sopenharmony_ci#include <inttypes.h> 29da0c48c4Sopenharmony_ci#include <libdwfl.h> 30da0c48c4Sopenharmony_ci#include <dwarf.h> 31da0c48c4Sopenharmony_ci#include <locale.h> 32da0c48c4Sopenharmony_ci#include <stdbool.h> 33da0c48c4Sopenharmony_ci#include <stdio.h> 34da0c48c4Sopenharmony_ci#include <stdio_ext.h> 35da0c48c4Sopenharmony_ci#include <stdlib.h> 36da0c48c4Sopenharmony_ci#include <string.h> 37da0c48c4Sopenharmony_ci#include <unistd.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_ci#include <system.h> 40da0c48c4Sopenharmony_ci#include <printversion.h> 41da0c48c4Sopenharmony_ci 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_ci/* Name and version of program. */ 44da0c48c4Sopenharmony_ciARGP_PROGRAM_VERSION_HOOK_DEF = print_version; 45da0c48c4Sopenharmony_ci 46da0c48c4Sopenharmony_ci/* Bug report address. */ 47da0c48c4Sopenharmony_ciARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; 48da0c48c4Sopenharmony_ci 49da0c48c4Sopenharmony_ci 50da0c48c4Sopenharmony_ci/* Values for the parameters which have no short form. */ 51da0c48c4Sopenharmony_ci#define OPT_DEMANGLER 0x100 52da0c48c4Sopenharmony_ci#define OPT_PRETTY 0x101 /* 'p' is already used to select the process. */ 53da0c48c4Sopenharmony_ci#define OPT_RELATIVE 0x102 /* 'r' is something else in binutils addr2line. */ 54da0c48c4Sopenharmony_ci 55da0c48c4Sopenharmony_ci/* Definitions of arguments for argp functions. */ 56da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 57da0c48c4Sopenharmony_ci{ 58da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Input format options:"), 2 }, 59da0c48c4Sopenharmony_ci { "section", 'j', "NAME", 0, 60da0c48c4Sopenharmony_ci N_("Treat addresses as offsets relative to NAME section."), 0 }, 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Output format options:"), 3 }, 63da0c48c4Sopenharmony_ci { "addresses", 'a', NULL, 0, N_("Print address before each entry"), 0 }, 64da0c48c4Sopenharmony_ci { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, 65da0c48c4Sopenharmony_ci { "absolute", 'A', NULL, 0, 66da0c48c4Sopenharmony_ci N_("Show absolute file names using compilation directory (default)"), 0 }, 67da0c48c4Sopenharmony_ci { "functions", 'f', NULL, 0, N_("Also show function names"), 0 }, 68da0c48c4Sopenharmony_ci { "symbols", 'S', NULL, 0, N_("Also show symbol or section names"), 0 }, 69da0c48c4Sopenharmony_ci { "symbols-sections", 'x', NULL, 0, N_("Also show symbol and the section names"), 0 }, 70da0c48c4Sopenharmony_ci { "flags", 'F', NULL, 0, N_("Also show line table flags"), 0 }, 71da0c48c4Sopenharmony_ci { "inlines", 'i', NULL, 0, 72da0c48c4Sopenharmony_ci N_("Show all source locations that caused inline expansion of subroutines at the address."), 73da0c48c4Sopenharmony_ci 0 }, 74da0c48c4Sopenharmony_ci { "demangle", 'C', "ARG", OPTION_ARG_OPTIONAL, 75da0c48c4Sopenharmony_ci N_("Show demangled symbols (ARG is always ignored)"), 0 }, 76da0c48c4Sopenharmony_ci { "pretty-print", OPT_PRETTY, NULL, 0, 77da0c48c4Sopenharmony_ci N_("Print all information on one line, and indent inlines"), 0 }, 78da0c48c4Sopenharmony_ci { "relative", OPT_RELATIVE, NULL, 0, 79da0c48c4Sopenharmony_ci N_("Show relative file names without compilation directory"), 0 }, 80da0c48c4Sopenharmony_ci 81da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 }, 82da0c48c4Sopenharmony_ci /* Unsupported options. */ 83da0c48c4Sopenharmony_ci { "target", 'b', "ARG", OPTION_HIDDEN, NULL, 0 }, 84da0c48c4Sopenharmony_ci { "demangler", OPT_DEMANGLER, "ARG", OPTION_HIDDEN, NULL, 0 }, 85da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 86da0c48c4Sopenharmony_ci}; 87da0c48c4Sopenharmony_ci 88da0c48c4Sopenharmony_ci/* Short description of program. */ 89da0c48c4Sopenharmony_cistatic const char doc[] = N_("\ 90da0c48c4Sopenharmony_ciLocate source files and line information for ADDRs (in a.out by default)."); 91da0c48c4Sopenharmony_ci 92da0c48c4Sopenharmony_ci/* Strings for arguments in help texts. */ 93da0c48c4Sopenharmony_cistatic const char args_doc[] = N_("[ADDR...]"); 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_ci/* Prototype for option handler. */ 96da0c48c4Sopenharmony_cistatic error_t parse_opt (int key, char *arg, struct argp_state *state); 97da0c48c4Sopenharmony_ci 98da0c48c4Sopenharmony_cistatic struct argp_child argp_children[2]; /* [0] is set in main. */ 99da0c48c4Sopenharmony_ci 100da0c48c4Sopenharmony_ci/* Data structure to communicate with argp functions. */ 101da0c48c4Sopenharmony_cistatic const struct argp argp = 102da0c48c4Sopenharmony_ci{ 103da0c48c4Sopenharmony_ci options, parse_opt, args_doc, doc, argp_children, NULL, NULL 104da0c48c4Sopenharmony_ci}; 105da0c48c4Sopenharmony_ci 106da0c48c4Sopenharmony_ci 107da0c48c4Sopenharmony_ci/* Handle ADDR. */ 108da0c48c4Sopenharmony_cistatic int handle_address (const char *addr, Dwfl *dwfl); 109da0c48c4Sopenharmony_ci 110da0c48c4Sopenharmony_ci/* True when we should print the address for each entry. */ 111da0c48c4Sopenharmony_cistatic bool print_addresses; 112da0c48c4Sopenharmony_ci 113da0c48c4Sopenharmony_ci/* True if only base names of files should be shown. */ 114da0c48c4Sopenharmony_cistatic bool only_basenames; 115da0c48c4Sopenharmony_ci 116da0c48c4Sopenharmony_ci/* True if absolute file names based on DW_AT_comp_dir should be shown. */ 117da0c48c4Sopenharmony_cistatic bool use_comp_dir = true; 118da0c48c4Sopenharmony_ci 119da0c48c4Sopenharmony_ci/* True if line flags should be shown. */ 120da0c48c4Sopenharmony_cistatic bool show_flags; 121da0c48c4Sopenharmony_ci 122da0c48c4Sopenharmony_ci/* True if function names should be shown. */ 123da0c48c4Sopenharmony_cistatic bool show_functions; 124da0c48c4Sopenharmony_ci 125da0c48c4Sopenharmony_ci/* True if ELF symbol or section info should be shown. */ 126da0c48c4Sopenharmony_cistatic bool show_symbols; 127da0c48c4Sopenharmony_ci 128da0c48c4Sopenharmony_ci/* True if section associated with a symbol address should be shown. */ 129da0c48c4Sopenharmony_cistatic bool show_symbol_sections; 130da0c48c4Sopenharmony_ci 131da0c48c4Sopenharmony_ci/* If non-null, take address parameters as relative to named section. */ 132da0c48c4Sopenharmony_cistatic const char *just_section; 133da0c48c4Sopenharmony_ci 134da0c48c4Sopenharmony_ci/* True if all inlined subroutines of the current address should be shown. */ 135da0c48c4Sopenharmony_cistatic bool show_inlines; 136da0c48c4Sopenharmony_ci 137da0c48c4Sopenharmony_ci/* True if all names need to be demangled. */ 138da0c48c4Sopenharmony_cistatic bool demangle; 139da0c48c4Sopenharmony_ci 140da0c48c4Sopenharmony_ci/* True if all information should be printed on one line. */ 141da0c48c4Sopenharmony_cistatic bool pretty; 142da0c48c4Sopenharmony_ci 143da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 144da0c48c4Sopenharmony_cistatic size_t demangle_buffer_len = 0; 145da0c48c4Sopenharmony_cistatic char *demangle_buffer = NULL; 146da0c48c4Sopenharmony_ci#endif 147da0c48c4Sopenharmony_ci 148da0c48c4Sopenharmony_ciint 149da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 150da0c48c4Sopenharmony_ci{ 151da0c48c4Sopenharmony_ci int remaining; 152da0c48c4Sopenharmony_ci int result = 0; 153da0c48c4Sopenharmony_ci 154da0c48c4Sopenharmony_ci /* We use no threads here which can interfere with handling a stream. */ 155da0c48c4Sopenharmony_ci (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER); 156da0c48c4Sopenharmony_ci 157da0c48c4Sopenharmony_ci /* Set locale. */ 158da0c48c4Sopenharmony_ci (void) setlocale (LC_ALL, ""); 159da0c48c4Sopenharmony_ci 160da0c48c4Sopenharmony_ci /* Make sure the message catalog can be found. */ 161da0c48c4Sopenharmony_ci (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR); 162da0c48c4Sopenharmony_ci 163da0c48c4Sopenharmony_ci /* Initialize the message catalog. */ 164da0c48c4Sopenharmony_ci (void) textdomain (PACKAGE_TARNAME); 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci /* Parse and process arguments. This includes opening the modules. */ 167da0c48c4Sopenharmony_ci argp_children[0].argp = dwfl_standard_argp (); 168da0c48c4Sopenharmony_ci argp_children[0].group = 1; 169da0c48c4Sopenharmony_ci Dwfl *dwfl = NULL; 170da0c48c4Sopenharmony_ci (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); 171da0c48c4Sopenharmony_ci assert (dwfl != NULL); 172da0c48c4Sopenharmony_ci 173da0c48c4Sopenharmony_ci /* Now handle the addresses. In case none are given on the command 174da0c48c4Sopenharmony_ci line, read from stdin. */ 175da0c48c4Sopenharmony_ci if (remaining == argc) 176da0c48c4Sopenharmony_ci { 177da0c48c4Sopenharmony_ci /* We use no threads here which can interfere with handling a stream. */ 178da0c48c4Sopenharmony_ci (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER); 179da0c48c4Sopenharmony_ci 180da0c48c4Sopenharmony_ci char *buf = NULL; 181da0c48c4Sopenharmony_ci size_t len = 0; 182da0c48c4Sopenharmony_ci ssize_t chars; 183da0c48c4Sopenharmony_ci while (!feof_unlocked (stdin)) 184da0c48c4Sopenharmony_ci { 185da0c48c4Sopenharmony_ci if ((chars = getline (&buf, &len, stdin)) < 0) 186da0c48c4Sopenharmony_ci break; 187da0c48c4Sopenharmony_ci 188da0c48c4Sopenharmony_ci if (buf[chars - 1] == '\n') 189da0c48c4Sopenharmony_ci buf[chars - 1] = '\0'; 190da0c48c4Sopenharmony_ci 191da0c48c4Sopenharmony_ci result = handle_address (buf, dwfl); 192da0c48c4Sopenharmony_ci fflush (stdout); 193da0c48c4Sopenharmony_ci } 194da0c48c4Sopenharmony_ci 195da0c48c4Sopenharmony_ci free (buf); 196da0c48c4Sopenharmony_ci } 197da0c48c4Sopenharmony_ci else 198da0c48c4Sopenharmony_ci { 199da0c48c4Sopenharmony_ci do 200da0c48c4Sopenharmony_ci result = handle_address (argv[remaining], dwfl); 201da0c48c4Sopenharmony_ci while (++remaining < argc); 202da0c48c4Sopenharmony_ci } 203da0c48c4Sopenharmony_ci 204da0c48c4Sopenharmony_ci dwfl_end (dwfl); 205da0c48c4Sopenharmony_ci 206da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 207da0c48c4Sopenharmony_ci free (demangle_buffer); 208da0c48c4Sopenharmony_ci#endif 209da0c48c4Sopenharmony_ci 210da0c48c4Sopenharmony_ci return result; 211da0c48c4Sopenharmony_ci} 212da0c48c4Sopenharmony_ci 213da0c48c4Sopenharmony_ci 214da0c48c4Sopenharmony_ci/* Handle program arguments. */ 215da0c48c4Sopenharmony_cistatic error_t 216da0c48c4Sopenharmony_ciparse_opt (int key, char *arg, struct argp_state *state) 217da0c48c4Sopenharmony_ci{ 218da0c48c4Sopenharmony_ci switch (key) 219da0c48c4Sopenharmony_ci { 220da0c48c4Sopenharmony_ci case ARGP_KEY_INIT: 221da0c48c4Sopenharmony_ci state->child_inputs[0] = state->input; 222da0c48c4Sopenharmony_ci break; 223da0c48c4Sopenharmony_ci 224da0c48c4Sopenharmony_ci case 'a': 225da0c48c4Sopenharmony_ci print_addresses = true; 226da0c48c4Sopenharmony_ci break; 227da0c48c4Sopenharmony_ci 228da0c48c4Sopenharmony_ci case 'b': 229da0c48c4Sopenharmony_ci case 'C': 230da0c48c4Sopenharmony_ci case OPT_DEMANGLER: 231da0c48c4Sopenharmony_ci demangle = true; 232da0c48c4Sopenharmony_ci break; 233da0c48c4Sopenharmony_ci 234da0c48c4Sopenharmony_ci case 's': 235da0c48c4Sopenharmony_ci only_basenames = true; 236da0c48c4Sopenharmony_ci break; 237da0c48c4Sopenharmony_ci 238da0c48c4Sopenharmony_ci case 'A': 239da0c48c4Sopenharmony_ci use_comp_dir = true; 240da0c48c4Sopenharmony_ci break; 241da0c48c4Sopenharmony_ci 242da0c48c4Sopenharmony_ci case OPT_RELATIVE: 243da0c48c4Sopenharmony_ci use_comp_dir = false; 244da0c48c4Sopenharmony_ci break; 245da0c48c4Sopenharmony_ci 246da0c48c4Sopenharmony_ci case 'f': 247da0c48c4Sopenharmony_ci show_functions = true; 248da0c48c4Sopenharmony_ci break; 249da0c48c4Sopenharmony_ci 250da0c48c4Sopenharmony_ci case 'F': 251da0c48c4Sopenharmony_ci show_flags = true; 252da0c48c4Sopenharmony_ci break; 253da0c48c4Sopenharmony_ci 254da0c48c4Sopenharmony_ci case 'S': 255da0c48c4Sopenharmony_ci show_symbols = true; 256da0c48c4Sopenharmony_ci break; 257da0c48c4Sopenharmony_ci 258da0c48c4Sopenharmony_ci case 'x': 259da0c48c4Sopenharmony_ci show_symbols = true; 260da0c48c4Sopenharmony_ci show_symbol_sections = true; 261da0c48c4Sopenharmony_ci break; 262da0c48c4Sopenharmony_ci 263da0c48c4Sopenharmony_ci case 'j': 264da0c48c4Sopenharmony_ci just_section = arg; 265da0c48c4Sopenharmony_ci break; 266da0c48c4Sopenharmony_ci 267da0c48c4Sopenharmony_ci case 'i': 268da0c48c4Sopenharmony_ci show_inlines = true; 269da0c48c4Sopenharmony_ci break; 270da0c48c4Sopenharmony_ci 271da0c48c4Sopenharmony_ci case OPT_PRETTY: 272da0c48c4Sopenharmony_ci pretty = true; 273da0c48c4Sopenharmony_ci break; 274da0c48c4Sopenharmony_ci 275da0c48c4Sopenharmony_ci default: 276da0c48c4Sopenharmony_ci return ARGP_ERR_UNKNOWN; 277da0c48c4Sopenharmony_ci } 278da0c48c4Sopenharmony_ci return 0; 279da0c48c4Sopenharmony_ci} 280da0c48c4Sopenharmony_ci 281da0c48c4Sopenharmony_cistatic const char * 282da0c48c4Sopenharmony_cisymname (const char *name) 283da0c48c4Sopenharmony_ci{ 284da0c48c4Sopenharmony_ci#ifdef USE_DEMANGLE 285da0c48c4Sopenharmony_ci // Require GNU v3 ABI by the "_Z" prefix. 286da0c48c4Sopenharmony_ci if (demangle && name[0] == '_' && name[1] == 'Z') 287da0c48c4Sopenharmony_ci { 288da0c48c4Sopenharmony_ci int status = -1; 289da0c48c4Sopenharmony_ci char *dsymname = __cxa_demangle (name, demangle_buffer, 290da0c48c4Sopenharmony_ci &demangle_buffer_len, &status); 291da0c48c4Sopenharmony_ci if (status == 0) 292da0c48c4Sopenharmony_ci name = demangle_buffer = dsymname; 293da0c48c4Sopenharmony_ci } 294da0c48c4Sopenharmony_ci#endif 295da0c48c4Sopenharmony_ci return name; 296da0c48c4Sopenharmony_ci} 297da0c48c4Sopenharmony_ci 298da0c48c4Sopenharmony_cistatic const char * 299da0c48c4Sopenharmony_ciget_diename (Dwarf_Die *die) 300da0c48c4Sopenharmony_ci{ 301da0c48c4Sopenharmony_ci Dwarf_Attribute attr; 302da0c48c4Sopenharmony_ci const char *name; 303da0c48c4Sopenharmony_ci 304da0c48c4Sopenharmony_ci name = dwarf_formstring (dwarf_attr_integrate (die, DW_AT_MIPS_linkage_name, 305da0c48c4Sopenharmony_ci &attr) 306da0c48c4Sopenharmony_ci ?: dwarf_attr_integrate (die, DW_AT_linkage_name, 307da0c48c4Sopenharmony_ci &attr)); 308da0c48c4Sopenharmony_ci 309da0c48c4Sopenharmony_ci if (name == NULL) 310da0c48c4Sopenharmony_ci name = dwarf_diename (die) ?: "??"; 311da0c48c4Sopenharmony_ci 312da0c48c4Sopenharmony_ci return name; 313da0c48c4Sopenharmony_ci} 314da0c48c4Sopenharmony_ci 315da0c48c4Sopenharmony_cistatic bool 316da0c48c4Sopenharmony_ciprint_dwarf_function (Dwfl_Module *mod, Dwarf_Addr addr) 317da0c48c4Sopenharmony_ci{ 318da0c48c4Sopenharmony_ci Dwarf_Addr bias = 0; 319da0c48c4Sopenharmony_ci Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias); 320da0c48c4Sopenharmony_ci 321da0c48c4Sopenharmony_ci Dwarf_Die *scopes; 322da0c48c4Sopenharmony_ci int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes); 323da0c48c4Sopenharmony_ci if (nscopes <= 0) 324da0c48c4Sopenharmony_ci return false; 325da0c48c4Sopenharmony_ci 326da0c48c4Sopenharmony_ci bool res = false; 327da0c48c4Sopenharmony_ci for (int i = 0; i < nscopes; ++i) 328da0c48c4Sopenharmony_ci switch (dwarf_tag (&scopes[i])) 329da0c48c4Sopenharmony_ci { 330da0c48c4Sopenharmony_ci case DW_TAG_subprogram: 331da0c48c4Sopenharmony_ci { 332da0c48c4Sopenharmony_ci const char *name = get_diename (&scopes[i]); 333da0c48c4Sopenharmony_ci if (name == NULL) 334da0c48c4Sopenharmony_ci goto done; 335da0c48c4Sopenharmony_ci printf ("%s%c", symname (name), pretty ? ' ' : '\n'); 336da0c48c4Sopenharmony_ci res = true; 337da0c48c4Sopenharmony_ci goto done; 338da0c48c4Sopenharmony_ci } 339da0c48c4Sopenharmony_ci 340da0c48c4Sopenharmony_ci case DW_TAG_inlined_subroutine: 341da0c48c4Sopenharmony_ci { 342da0c48c4Sopenharmony_ci const char *name = get_diename (&scopes[i]); 343da0c48c4Sopenharmony_ci if (name == NULL) 344da0c48c4Sopenharmony_ci goto done; 345da0c48c4Sopenharmony_ci 346da0c48c4Sopenharmony_ci /* When using --pretty-print we only show inlines on their 347da0c48c4Sopenharmony_ci own line. Just print the first subroutine name. */ 348da0c48c4Sopenharmony_ci if (pretty) 349da0c48c4Sopenharmony_ci { 350da0c48c4Sopenharmony_ci printf ("%s ", symname (name)); 351da0c48c4Sopenharmony_ci res = true; 352da0c48c4Sopenharmony_ci goto done; 353da0c48c4Sopenharmony_ci } 354da0c48c4Sopenharmony_ci else 355da0c48c4Sopenharmony_ci printf ("%s inlined", symname (name)); 356da0c48c4Sopenharmony_ci 357da0c48c4Sopenharmony_ci Dwarf_Files *files; 358da0c48c4Sopenharmony_ci if (dwarf_getsrcfiles (cudie, &files, NULL) == 0) 359da0c48c4Sopenharmony_ci { 360da0c48c4Sopenharmony_ci Dwarf_Attribute attr_mem; 361da0c48c4Sopenharmony_ci Dwarf_Word val; 362da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (&scopes[i], 363da0c48c4Sopenharmony_ci DW_AT_call_file, 364da0c48c4Sopenharmony_ci &attr_mem), &val) == 0) 365da0c48c4Sopenharmony_ci { 366da0c48c4Sopenharmony_ci const char *file = dwarf_filesrc (files, val, NULL, NULL); 367da0c48c4Sopenharmony_ci unsigned int lineno = 0; 368da0c48c4Sopenharmony_ci unsigned int colno = 0; 369da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (&scopes[i], 370da0c48c4Sopenharmony_ci DW_AT_call_line, 371da0c48c4Sopenharmony_ci &attr_mem), &val) == 0) 372da0c48c4Sopenharmony_ci lineno = val; 373da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (&scopes[i], 374da0c48c4Sopenharmony_ci DW_AT_call_column, 375da0c48c4Sopenharmony_ci &attr_mem), &val) == 0) 376da0c48c4Sopenharmony_ci colno = val; 377da0c48c4Sopenharmony_ci 378da0c48c4Sopenharmony_ci const char *comp_dir = ""; 379da0c48c4Sopenharmony_ci const char *comp_dir_sep = ""; 380da0c48c4Sopenharmony_ci 381da0c48c4Sopenharmony_ci if (file == NULL) 382da0c48c4Sopenharmony_ci file = "???"; 383da0c48c4Sopenharmony_ci else if (only_basenames) 384da0c48c4Sopenharmony_ci file = basename (file); 385da0c48c4Sopenharmony_ci else if (use_comp_dir && file[0] != '/') 386da0c48c4Sopenharmony_ci { 387da0c48c4Sopenharmony_ci const char *const *dirs; 388da0c48c4Sopenharmony_ci size_t ndirs; 389da0c48c4Sopenharmony_ci if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 390da0c48c4Sopenharmony_ci && dirs[0] != NULL) 391da0c48c4Sopenharmony_ci { 392da0c48c4Sopenharmony_ci comp_dir = dirs[0]; 393da0c48c4Sopenharmony_ci comp_dir_sep = "/"; 394da0c48c4Sopenharmony_ci } 395da0c48c4Sopenharmony_ci } 396da0c48c4Sopenharmony_ci 397da0c48c4Sopenharmony_ci if (lineno == 0) 398da0c48c4Sopenharmony_ci printf (" from %s%s%s", 399da0c48c4Sopenharmony_ci comp_dir, comp_dir_sep, file); 400da0c48c4Sopenharmony_ci else if (colno == 0) 401da0c48c4Sopenharmony_ci printf (" at %s%s%s:%u", 402da0c48c4Sopenharmony_ci comp_dir, comp_dir_sep, file, lineno); 403da0c48c4Sopenharmony_ci else 404da0c48c4Sopenharmony_ci printf (" at %s%s%s:%u:%u", 405da0c48c4Sopenharmony_ci comp_dir, comp_dir_sep, file, lineno, colno); 406da0c48c4Sopenharmony_ci } 407da0c48c4Sopenharmony_ci } 408da0c48c4Sopenharmony_ci printf (" in "); 409da0c48c4Sopenharmony_ci continue; 410da0c48c4Sopenharmony_ci } 411da0c48c4Sopenharmony_ci } 412da0c48c4Sopenharmony_ci 413da0c48c4Sopenharmony_cidone: 414da0c48c4Sopenharmony_ci free (scopes); 415da0c48c4Sopenharmony_ci return res; 416da0c48c4Sopenharmony_ci} 417da0c48c4Sopenharmony_ci 418da0c48c4Sopenharmony_cistatic void 419da0c48c4Sopenharmony_ciprint_addrsym (Dwfl_Module *mod, GElf_Addr addr) 420da0c48c4Sopenharmony_ci{ 421da0c48c4Sopenharmony_ci GElf_Sym s; 422da0c48c4Sopenharmony_ci GElf_Off off; 423da0c48c4Sopenharmony_ci const char *name = dwfl_module_addrinfo (mod, addr, &off, &s, 424da0c48c4Sopenharmony_ci NULL, NULL, NULL); 425da0c48c4Sopenharmony_ci if (name == NULL) 426da0c48c4Sopenharmony_ci { 427da0c48c4Sopenharmony_ci /* No symbol name. Get a section name instead. */ 428da0c48c4Sopenharmony_ci int i = dwfl_module_relocate_address (mod, &addr); 429da0c48c4Sopenharmony_ci if (i >= 0) 430da0c48c4Sopenharmony_ci name = dwfl_module_relocation_info (mod, i, NULL); 431da0c48c4Sopenharmony_ci if (name == NULL) 432da0c48c4Sopenharmony_ci printf ("??%c", pretty ? ' ': '\n'); 433da0c48c4Sopenharmony_ci else 434da0c48c4Sopenharmony_ci printf ("(%s)+%#" PRIx64 "%c", name, addr, pretty ? ' ' : '\n'); 435da0c48c4Sopenharmony_ci } 436da0c48c4Sopenharmony_ci else 437da0c48c4Sopenharmony_ci { 438da0c48c4Sopenharmony_ci name = symname (name); 439da0c48c4Sopenharmony_ci if (off == 0) 440da0c48c4Sopenharmony_ci printf ("%s", name); 441da0c48c4Sopenharmony_ci else 442da0c48c4Sopenharmony_ci printf ("%s+%#" PRIx64 "", name, off); 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci // Also show section name for address. 445da0c48c4Sopenharmony_ci if (show_symbol_sections) 446da0c48c4Sopenharmony_ci { 447da0c48c4Sopenharmony_ci Dwarf_Addr ebias; 448da0c48c4Sopenharmony_ci Elf_Scn *scn = dwfl_module_address_section (mod, &addr, &ebias); 449da0c48c4Sopenharmony_ci if (scn != NULL) 450da0c48c4Sopenharmony_ci { 451da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 452da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 453da0c48c4Sopenharmony_ci if (shdr != NULL) 454da0c48c4Sopenharmony_ci { 455da0c48c4Sopenharmony_ci Elf *elf = dwfl_module_getelf (mod, &ebias); 456da0c48c4Sopenharmony_ci size_t shstrndx; 457da0c48c4Sopenharmony_ci if (elf_getshdrstrndx (elf, &shstrndx) >= 0) 458da0c48c4Sopenharmony_ci printf (" (%s)", elf_strptr (elf, shstrndx, 459da0c48c4Sopenharmony_ci shdr->sh_name)); 460da0c48c4Sopenharmony_ci } 461da0c48c4Sopenharmony_ci } 462da0c48c4Sopenharmony_ci } 463da0c48c4Sopenharmony_ci printf ("%c", pretty ? ' ' : '\n'); 464da0c48c4Sopenharmony_ci } 465da0c48c4Sopenharmony_ci} 466da0c48c4Sopenharmony_ci 467da0c48c4Sopenharmony_cistatic int 468da0c48c4Sopenharmony_cisee_one_module (Dwfl_Module *mod, 469da0c48c4Sopenharmony_ci void **userdata __attribute__ ((unused)), 470da0c48c4Sopenharmony_ci const char *name __attribute__ ((unused)), 471da0c48c4Sopenharmony_ci Dwarf_Addr start __attribute__ ((unused)), 472da0c48c4Sopenharmony_ci void *arg) 473da0c48c4Sopenharmony_ci{ 474da0c48c4Sopenharmony_ci Dwfl_Module **result = arg; 475da0c48c4Sopenharmony_ci if (*result != NULL) 476da0c48c4Sopenharmony_ci return DWARF_CB_ABORT; 477da0c48c4Sopenharmony_ci *result = mod; 478da0c48c4Sopenharmony_ci return DWARF_CB_OK; 479da0c48c4Sopenharmony_ci} 480da0c48c4Sopenharmony_ci 481da0c48c4Sopenharmony_cistatic int 482da0c48c4Sopenharmony_cifind_symbol (Dwfl_Module *mod, 483da0c48c4Sopenharmony_ci void **userdata __attribute__ ((unused)), 484da0c48c4Sopenharmony_ci const char *name __attribute__ ((unused)), 485da0c48c4Sopenharmony_ci Dwarf_Addr start __attribute__ ((unused)), 486da0c48c4Sopenharmony_ci void *arg) 487da0c48c4Sopenharmony_ci{ 488da0c48c4Sopenharmony_ci const char *looking_for = ((void **) arg)[0]; 489da0c48c4Sopenharmony_ci GElf_Sym *symbol = ((void **) arg)[1]; 490da0c48c4Sopenharmony_ci GElf_Addr *value = ((void **) arg)[2]; 491da0c48c4Sopenharmony_ci 492da0c48c4Sopenharmony_ci int n = dwfl_module_getsymtab (mod); 493da0c48c4Sopenharmony_ci for (int i = 1; i < n; ++i) 494da0c48c4Sopenharmony_ci { 495da0c48c4Sopenharmony_ci const char *symbol_name = dwfl_module_getsym_info (mod, i, symbol, 496da0c48c4Sopenharmony_ci value, NULL, NULL, 497da0c48c4Sopenharmony_ci NULL); 498da0c48c4Sopenharmony_ci if (symbol_name == NULL || symbol_name[0] == '\0') 499da0c48c4Sopenharmony_ci continue; 500da0c48c4Sopenharmony_ci switch (GELF_ST_TYPE (symbol->st_info)) 501da0c48c4Sopenharmony_ci { 502da0c48c4Sopenharmony_ci case STT_SECTION: 503da0c48c4Sopenharmony_ci case STT_FILE: 504da0c48c4Sopenharmony_ci case STT_TLS: 505da0c48c4Sopenharmony_ci break; 506da0c48c4Sopenharmony_ci default: 507da0c48c4Sopenharmony_ci if (!strcmp (symbol_name, looking_for)) 508da0c48c4Sopenharmony_ci { 509da0c48c4Sopenharmony_ci ((void **) arg)[0] = NULL; 510da0c48c4Sopenharmony_ci return DWARF_CB_ABORT; 511da0c48c4Sopenharmony_ci } 512da0c48c4Sopenharmony_ci } 513da0c48c4Sopenharmony_ci } 514da0c48c4Sopenharmony_ci 515da0c48c4Sopenharmony_ci return DWARF_CB_OK; 516da0c48c4Sopenharmony_ci} 517da0c48c4Sopenharmony_ci 518da0c48c4Sopenharmony_cistatic bool 519da0c48c4Sopenharmony_ciadjust_to_section (const char *name, uintmax_t *addr, Dwfl *dwfl) 520da0c48c4Sopenharmony_ci{ 521da0c48c4Sopenharmony_ci /* It was (section)+offset. This makes sense if there is 522da0c48c4Sopenharmony_ci only one module to look in for a section. */ 523da0c48c4Sopenharmony_ci Dwfl_Module *mod = NULL; 524da0c48c4Sopenharmony_ci if (dwfl_getmodules (dwfl, &see_one_module, &mod, 0) != 0 525da0c48c4Sopenharmony_ci || mod == NULL) 526da0c48c4Sopenharmony_ci error_exit (0, _("Section syntax requires exactly one module")); 527da0c48c4Sopenharmony_ci 528da0c48c4Sopenharmony_ci int nscn = dwfl_module_relocations (mod); 529da0c48c4Sopenharmony_ci for (int i = 0; i < nscn; ++i) 530da0c48c4Sopenharmony_ci { 531da0c48c4Sopenharmony_ci GElf_Word shndx; 532da0c48c4Sopenharmony_ci const char *scn = dwfl_module_relocation_info (mod, i, &shndx); 533da0c48c4Sopenharmony_ci if (unlikely (scn == NULL)) 534da0c48c4Sopenharmony_ci break; 535da0c48c4Sopenharmony_ci if (!strcmp (scn, name)) 536da0c48c4Sopenharmony_ci { 537da0c48c4Sopenharmony_ci /* Found the section. */ 538da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 539da0c48c4Sopenharmony_ci GElf_Addr shdr_bias; 540da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr 541da0c48c4Sopenharmony_ci (elf_getscn (dwfl_module_getelf (mod, &shdr_bias), shndx), 542da0c48c4Sopenharmony_ci &shdr_mem); 543da0c48c4Sopenharmony_ci if (unlikely (shdr == NULL)) 544da0c48c4Sopenharmony_ci break; 545da0c48c4Sopenharmony_ci 546da0c48c4Sopenharmony_ci if (*addr >= shdr->sh_size) 547da0c48c4Sopenharmony_ci error (0, 0, 548da0c48c4Sopenharmony_ci _("offset %#" PRIxMAX " lies outside" 549da0c48c4Sopenharmony_ci " section '%s'"), 550da0c48c4Sopenharmony_ci *addr, scn); 551da0c48c4Sopenharmony_ci 552da0c48c4Sopenharmony_ci *addr += shdr->sh_addr + shdr_bias; 553da0c48c4Sopenharmony_ci return true; 554da0c48c4Sopenharmony_ci } 555da0c48c4Sopenharmony_ci } 556da0c48c4Sopenharmony_ci 557da0c48c4Sopenharmony_ci return false; 558da0c48c4Sopenharmony_ci} 559da0c48c4Sopenharmony_ci 560da0c48c4Sopenharmony_cistatic void 561da0c48c4Sopenharmony_ciprint_src (const char *src, int lineno, int linecol, Dwarf_Die *cu) 562da0c48c4Sopenharmony_ci{ 563da0c48c4Sopenharmony_ci const char *comp_dir = ""; 564da0c48c4Sopenharmony_ci const char *comp_dir_sep = ""; 565da0c48c4Sopenharmony_ci 566da0c48c4Sopenharmony_ci if (only_basenames) 567da0c48c4Sopenharmony_ci src = basename (src); 568da0c48c4Sopenharmony_ci else if (use_comp_dir && src[0] != '/') 569da0c48c4Sopenharmony_ci { 570da0c48c4Sopenharmony_ci Dwarf_Attribute attr; 571da0c48c4Sopenharmony_ci comp_dir = dwarf_formstring (dwarf_attr (cu, DW_AT_comp_dir, &attr)); 572da0c48c4Sopenharmony_ci if (comp_dir != NULL) 573da0c48c4Sopenharmony_ci comp_dir_sep = "/"; 574da0c48c4Sopenharmony_ci } 575da0c48c4Sopenharmony_ci 576da0c48c4Sopenharmony_ci if (linecol != 0) 577da0c48c4Sopenharmony_ci printf ("%s%s%s:%d:%d", 578da0c48c4Sopenharmony_ci comp_dir, comp_dir_sep, src, lineno, linecol); 579da0c48c4Sopenharmony_ci else 580da0c48c4Sopenharmony_ci printf ("%s%s%s:%d", 581da0c48c4Sopenharmony_ci comp_dir, comp_dir_sep, src, lineno); 582da0c48c4Sopenharmony_ci} 583da0c48c4Sopenharmony_ci 584da0c48c4Sopenharmony_cistatic int 585da0c48c4Sopenharmony_ciget_addr_width (Dwfl_Module *mod) 586da0c48c4Sopenharmony_ci{ 587da0c48c4Sopenharmony_ci // Try to find the address width if possible. 588da0c48c4Sopenharmony_ci static int width = 0; 589da0c48c4Sopenharmony_ci if (width == 0 && mod != NULL) 590da0c48c4Sopenharmony_ci { 591da0c48c4Sopenharmony_ci Dwarf_Addr bias; 592da0c48c4Sopenharmony_ci Elf *elf = dwfl_module_getelf (mod, &bias); 593da0c48c4Sopenharmony_ci if (elf != NULL) 594da0c48c4Sopenharmony_ci { 595da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem; 596da0c48c4Sopenharmony_ci GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 597da0c48c4Sopenharmony_ci if (ehdr != NULL) 598da0c48c4Sopenharmony_ci width = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 8 : 16; 599da0c48c4Sopenharmony_ci } 600da0c48c4Sopenharmony_ci } 601da0c48c4Sopenharmony_ci if (width == 0) 602da0c48c4Sopenharmony_ci width = 16; 603da0c48c4Sopenharmony_ci 604da0c48c4Sopenharmony_ci return width; 605da0c48c4Sopenharmony_ci} 606da0c48c4Sopenharmony_ci 607da0c48c4Sopenharmony_cistatic inline void 608da0c48c4Sopenharmony_cishow_note (int (*get) (Dwarf_Line *, bool *), 609da0c48c4Sopenharmony_ci Dwarf_Line *info, 610da0c48c4Sopenharmony_ci const char *note) 611da0c48c4Sopenharmony_ci{ 612da0c48c4Sopenharmony_ci bool flag; 613da0c48c4Sopenharmony_ci if ((*get) (info, &flag) == 0 && flag) 614da0c48c4Sopenharmony_ci fputs (note, stdout); 615da0c48c4Sopenharmony_ci} 616da0c48c4Sopenharmony_ci 617da0c48c4Sopenharmony_cistatic inline void 618da0c48c4Sopenharmony_cishow_int (int (*get) (Dwarf_Line *, unsigned int *), 619da0c48c4Sopenharmony_ci Dwarf_Line *info, 620da0c48c4Sopenharmony_ci const char *name) 621da0c48c4Sopenharmony_ci{ 622da0c48c4Sopenharmony_ci unsigned int val; 623da0c48c4Sopenharmony_ci if ((*get) (info, &val) == 0 && val != 0) 624da0c48c4Sopenharmony_ci printf (" (%s %u)", name, val); 625da0c48c4Sopenharmony_ci} 626da0c48c4Sopenharmony_ci 627da0c48c4Sopenharmony_cistatic int 628da0c48c4Sopenharmony_cihandle_address (const char *string, Dwfl *dwfl) 629da0c48c4Sopenharmony_ci{ 630da0c48c4Sopenharmony_ci char *endp; 631da0c48c4Sopenharmony_ci uintmax_t addr = strtoumax (string, &endp, 16); 632da0c48c4Sopenharmony_ci if (endp == string || *endp != '\0') 633da0c48c4Sopenharmony_ci { 634da0c48c4Sopenharmony_ci bool parsed = false; 635da0c48c4Sopenharmony_ci int i, j; 636da0c48c4Sopenharmony_ci char *name = NULL; 637da0c48c4Sopenharmony_ci if (sscanf (string, "(%m[^)])%" PRIiMAX "%n", &name, &addr, &i) == 2 638da0c48c4Sopenharmony_ci && string[i] == '\0') 639da0c48c4Sopenharmony_ci parsed = adjust_to_section (name, &addr, dwfl); 640da0c48c4Sopenharmony_ci switch (sscanf (string, "%m[^-+]%n%" PRIiMAX "%n", &name, &i, &addr, &j)) 641da0c48c4Sopenharmony_ci { 642da0c48c4Sopenharmony_ci default: 643da0c48c4Sopenharmony_ci break; 644da0c48c4Sopenharmony_ci case 1: 645da0c48c4Sopenharmony_ci addr = 0; 646da0c48c4Sopenharmony_ci j = i; 647da0c48c4Sopenharmony_ci FALLTHROUGH; 648da0c48c4Sopenharmony_ci case 2: 649da0c48c4Sopenharmony_ci if (string[j] != '\0') 650da0c48c4Sopenharmony_ci break; 651da0c48c4Sopenharmony_ci 652da0c48c4Sopenharmony_ci /* It was symbol[+offset]. */ 653da0c48c4Sopenharmony_ci GElf_Sym sym; 654da0c48c4Sopenharmony_ci GElf_Addr value = 0; 655da0c48c4Sopenharmony_ci void *arg[3] = { name, &sym, &value }; 656da0c48c4Sopenharmony_ci (void) dwfl_getmodules (dwfl, &find_symbol, arg, 0); 657da0c48c4Sopenharmony_ci if (arg[0] != NULL) 658da0c48c4Sopenharmony_ci error (0, 0, _("cannot find symbol '%s'"), name); 659da0c48c4Sopenharmony_ci else 660da0c48c4Sopenharmony_ci { 661da0c48c4Sopenharmony_ci if (sym.st_size != 0 && addr >= sym.st_size) 662da0c48c4Sopenharmony_ci error (0, 0, 663da0c48c4Sopenharmony_ci _("offset %#" PRIxMAX " lies outside" 664da0c48c4Sopenharmony_ci " contents of '%s'"), 665da0c48c4Sopenharmony_ci addr, name); 666da0c48c4Sopenharmony_ci addr += value; 667da0c48c4Sopenharmony_ci parsed = true; 668da0c48c4Sopenharmony_ci } 669da0c48c4Sopenharmony_ci break; 670da0c48c4Sopenharmony_ci } 671da0c48c4Sopenharmony_ci 672da0c48c4Sopenharmony_ci free (name); 673da0c48c4Sopenharmony_ci if (!parsed) 674da0c48c4Sopenharmony_ci return 1; 675da0c48c4Sopenharmony_ci } 676da0c48c4Sopenharmony_ci else if (just_section != NULL 677da0c48c4Sopenharmony_ci && !adjust_to_section (just_section, &addr, dwfl)) 678da0c48c4Sopenharmony_ci return 1; 679da0c48c4Sopenharmony_ci 680da0c48c4Sopenharmony_ci Dwfl_Module *mod = dwfl_addrmodule (dwfl, addr); 681da0c48c4Sopenharmony_ci 682da0c48c4Sopenharmony_ci if (print_addresses) 683da0c48c4Sopenharmony_ci { 684da0c48c4Sopenharmony_ci int width = get_addr_width (mod); 685da0c48c4Sopenharmony_ci printf ("0x%.*" PRIx64 "%s", width, addr, pretty ? ": " : "\n"); 686da0c48c4Sopenharmony_ci } 687da0c48c4Sopenharmony_ci 688da0c48c4Sopenharmony_ci if (show_functions) 689da0c48c4Sopenharmony_ci { 690da0c48c4Sopenharmony_ci /* First determine the function name. Use the DWARF information if 691da0c48c4Sopenharmony_ci possible. */ 692da0c48c4Sopenharmony_ci if (! print_dwarf_function (mod, addr) && !show_symbols) 693da0c48c4Sopenharmony_ci { 694da0c48c4Sopenharmony_ci const char *name = dwfl_module_addrname (mod, addr); 695da0c48c4Sopenharmony_ci name = name != NULL ? symname (name) : "??"; 696da0c48c4Sopenharmony_ci printf ("%s%c", name, pretty ? ' ' : '\n'); 697da0c48c4Sopenharmony_ci } 698da0c48c4Sopenharmony_ci } 699da0c48c4Sopenharmony_ci 700da0c48c4Sopenharmony_ci if (show_symbols) 701da0c48c4Sopenharmony_ci print_addrsym (mod, addr); 702da0c48c4Sopenharmony_ci 703da0c48c4Sopenharmony_ci if ((show_functions || show_symbols) && pretty) 704da0c48c4Sopenharmony_ci printf ("at "); 705da0c48c4Sopenharmony_ci 706da0c48c4Sopenharmony_ci Dwfl_Line *line = dwfl_module_getsrc (mod, addr); 707da0c48c4Sopenharmony_ci 708da0c48c4Sopenharmony_ci const char *src; 709da0c48c4Sopenharmony_ci int lineno, linecol; 710da0c48c4Sopenharmony_ci 711da0c48c4Sopenharmony_ci if (line != NULL && (src = dwfl_lineinfo (line, &addr, &lineno, &linecol, 712da0c48c4Sopenharmony_ci NULL, NULL)) != NULL) 713da0c48c4Sopenharmony_ci { 714da0c48c4Sopenharmony_ci print_src (src, lineno, linecol, dwfl_linecu (line)); 715da0c48c4Sopenharmony_ci if (show_flags) 716da0c48c4Sopenharmony_ci { 717da0c48c4Sopenharmony_ci Dwarf_Addr bias; 718da0c48c4Sopenharmony_ci Dwarf_Line *info = dwfl_dwarf_line (line, &bias); 719da0c48c4Sopenharmony_ci assert (info != NULL); 720da0c48c4Sopenharmony_ci 721da0c48c4Sopenharmony_ci show_note (&dwarf_linebeginstatement, info, " (is_stmt)"); 722da0c48c4Sopenharmony_ci show_note (&dwarf_lineblock, info, " (basic_block)"); 723da0c48c4Sopenharmony_ci show_note (&dwarf_lineprologueend, info, " (prologue_end)"); 724da0c48c4Sopenharmony_ci show_note (&dwarf_lineepiloguebegin, info, " (epilogue_begin)"); 725da0c48c4Sopenharmony_ci show_int (&dwarf_lineisa, info, "isa"); 726da0c48c4Sopenharmony_ci show_int (&dwarf_linediscriminator, info, "discriminator"); 727da0c48c4Sopenharmony_ci } 728da0c48c4Sopenharmony_ci putchar ('\n'); 729da0c48c4Sopenharmony_ci } 730da0c48c4Sopenharmony_ci else 731da0c48c4Sopenharmony_ci puts ("??:0"); 732da0c48c4Sopenharmony_ci 733da0c48c4Sopenharmony_ci if (show_inlines) 734da0c48c4Sopenharmony_ci { 735da0c48c4Sopenharmony_ci Dwarf_Addr bias = 0; 736da0c48c4Sopenharmony_ci Dwarf_Die *cudie = dwfl_module_addrdie (mod, addr, &bias); 737da0c48c4Sopenharmony_ci 738da0c48c4Sopenharmony_ci Dwarf_Die *scopes = NULL; 739da0c48c4Sopenharmony_ci int nscopes = dwarf_getscopes (cudie, addr - bias, &scopes); 740da0c48c4Sopenharmony_ci if (nscopes < 0) 741da0c48c4Sopenharmony_ci return 1; 742da0c48c4Sopenharmony_ci 743da0c48c4Sopenharmony_ci if (nscopes > 0) 744da0c48c4Sopenharmony_ci { 745da0c48c4Sopenharmony_ci Dwarf_Die subroutine; 746da0c48c4Sopenharmony_ci Dwarf_Off dieoff = dwarf_dieoffset (&scopes[0]); 747da0c48c4Sopenharmony_ci dwarf_offdie (dwfl_module_getdwarf (mod, &bias), 748da0c48c4Sopenharmony_ci dieoff, &subroutine); 749da0c48c4Sopenharmony_ci free (scopes); 750da0c48c4Sopenharmony_ci scopes = NULL; 751da0c48c4Sopenharmony_ci 752da0c48c4Sopenharmony_ci nscopes = dwarf_getscopes_die (&subroutine, &scopes); 753da0c48c4Sopenharmony_ci if (nscopes > 1) 754da0c48c4Sopenharmony_ci { 755da0c48c4Sopenharmony_ci Dwarf_Die cu; 756da0c48c4Sopenharmony_ci Dwarf_Files *files; 757da0c48c4Sopenharmony_ci if (dwarf_diecu (&scopes[0], &cu, NULL, NULL) != NULL 758da0c48c4Sopenharmony_ci && dwarf_getsrcfiles (cudie, &files, NULL) == 0) 759da0c48c4Sopenharmony_ci { 760da0c48c4Sopenharmony_ci for (int i = 0; i < nscopes - 1; i++) 761da0c48c4Sopenharmony_ci { 762da0c48c4Sopenharmony_ci Dwarf_Word val; 763da0c48c4Sopenharmony_ci Dwarf_Attribute attr; 764da0c48c4Sopenharmony_ci Dwarf_Die *die = &scopes[i]; 765da0c48c4Sopenharmony_ci if (dwarf_tag (die) != DW_TAG_inlined_subroutine) 766da0c48c4Sopenharmony_ci continue; 767da0c48c4Sopenharmony_ci 768da0c48c4Sopenharmony_ci if (pretty) 769da0c48c4Sopenharmony_ci printf (" (inlined by) "); 770da0c48c4Sopenharmony_ci 771da0c48c4Sopenharmony_ci if (show_functions) 772da0c48c4Sopenharmony_ci { 773da0c48c4Sopenharmony_ci /* Search for the parent inline or function. It 774da0c48c4Sopenharmony_ci might not be directly above this inline -- e.g. 775da0c48c4Sopenharmony_ci there could be a lexical_block in between. */ 776da0c48c4Sopenharmony_ci for (int j = i + 1; j < nscopes; j++) 777da0c48c4Sopenharmony_ci { 778da0c48c4Sopenharmony_ci Dwarf_Die *parent = &scopes[j]; 779da0c48c4Sopenharmony_ci int tag = dwarf_tag (parent); 780da0c48c4Sopenharmony_ci if (tag == DW_TAG_inlined_subroutine 781da0c48c4Sopenharmony_ci || tag == DW_TAG_entry_point 782da0c48c4Sopenharmony_ci || tag == DW_TAG_subprogram) 783da0c48c4Sopenharmony_ci { 784da0c48c4Sopenharmony_ci printf ("%s%s", 785da0c48c4Sopenharmony_ci symname (get_diename (parent)), 786da0c48c4Sopenharmony_ci pretty ? " at " : "\n"); 787da0c48c4Sopenharmony_ci break; 788da0c48c4Sopenharmony_ci } 789da0c48c4Sopenharmony_ci } 790da0c48c4Sopenharmony_ci } 791da0c48c4Sopenharmony_ci 792da0c48c4Sopenharmony_ci src = NULL; 793da0c48c4Sopenharmony_ci lineno = 0; 794da0c48c4Sopenharmony_ci linecol = 0; 795da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (die, DW_AT_call_file, 796da0c48c4Sopenharmony_ci &attr), &val) == 0) 797da0c48c4Sopenharmony_ci src = dwarf_filesrc (files, val, NULL, NULL); 798da0c48c4Sopenharmony_ci 799da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (die, DW_AT_call_line, 800da0c48c4Sopenharmony_ci &attr), &val) == 0) 801da0c48c4Sopenharmony_ci lineno = val; 802da0c48c4Sopenharmony_ci 803da0c48c4Sopenharmony_ci if (dwarf_formudata (dwarf_attr (die, DW_AT_call_column, 804da0c48c4Sopenharmony_ci &attr), &val) == 0) 805da0c48c4Sopenharmony_ci linecol = val; 806da0c48c4Sopenharmony_ci 807da0c48c4Sopenharmony_ci if (src != NULL) 808da0c48c4Sopenharmony_ci { 809da0c48c4Sopenharmony_ci print_src (src, lineno, linecol, &cu); 810da0c48c4Sopenharmony_ci putchar ('\n'); 811da0c48c4Sopenharmony_ci } 812da0c48c4Sopenharmony_ci else 813da0c48c4Sopenharmony_ci puts ("??:0"); 814da0c48c4Sopenharmony_ci } 815da0c48c4Sopenharmony_ci } 816da0c48c4Sopenharmony_ci } 817da0c48c4Sopenharmony_ci } 818da0c48c4Sopenharmony_ci free (scopes); 819da0c48c4Sopenharmony_ci } 820da0c48c4Sopenharmony_ci 821da0c48c4Sopenharmony_ci return 0; 822da0c48c4Sopenharmony_ci} 823da0c48c4Sopenharmony_ci 824da0c48c4Sopenharmony_ci 825da0c48c4Sopenharmony_ci#include "debugpred.h" 826