1da0c48c4Sopenharmony_ci/* Test program for dwarf location functions. 2da0c48c4Sopenharmony_ci Copyright (C) 2013, 2015, 2017, 2018 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of the GNU General Public License as published by 7da0c48c4Sopenharmony_ci the Free Software Foundation; either version 3 of the License, or 8da0c48c4Sopenharmony_ci (at your option) any later version. 9da0c48c4Sopenharmony_ci 10da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 11da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 12da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13da0c48c4Sopenharmony_ci GNU General Public License for more details. 14da0c48c4Sopenharmony_ci 15da0c48c4Sopenharmony_ci You should have received a copy of the GNU General Public License 16da0c48c4Sopenharmony_ci along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci#include <config.h> 19da0c48c4Sopenharmony_ci#include <assert.h> 20da0c48c4Sopenharmony_ci#include <argp.h> 21da0c48c4Sopenharmony_ci#include <inttypes.h> 22da0c48c4Sopenharmony_ci#include <errno.h> 23da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dw) 24da0c48c4Sopenharmony_ci#include ELFUTILS_HEADER(dwfl) 25da0c48c4Sopenharmony_ci#include <dwarf.h> 26da0c48c4Sopenharmony_ci#include <stdio.h> 27da0c48c4Sopenharmony_ci#include <stdlib.h> 28da0c48c4Sopenharmony_ci#include <string.h> 29da0c48c4Sopenharmony_ci#include <sys/types.h> 30da0c48c4Sopenharmony_ci#include <sys/stat.h> 31da0c48c4Sopenharmony_ci#include <fcntl.h> 32da0c48c4Sopenharmony_ci#include <unistd.h> 33da0c48c4Sopenharmony_ci 34da0c48c4Sopenharmony_ci#include "system.h" 35da0c48c4Sopenharmony_ci#include "../libdw/known-dwarf.h" 36da0c48c4Sopenharmony_ci 37da0c48c4Sopenharmony_ci// The Dwarf, Dwarf_CFIs and address bias of 38da0c48c4Sopenharmony_ci// cfi table to adjust DWARF addresses against. 39da0c48c4Sopenharmony_ci// Needed for DW_OP_call_frame_cfa. 40da0c48c4Sopenharmony_cistatic Dwarf *dw; 41da0c48c4Sopenharmony_ciDwarf_CFI *cfi_debug; 42da0c48c4Sopenharmony_ciDwarf_Addr cfi_debug_bias; 43da0c48c4Sopenharmony_ciDwarf_CFI *cfi_eh; 44da0c48c4Sopenharmony_ciDwarf_Addr cfi_eh_bias; 45da0c48c4Sopenharmony_ci 46da0c48c4Sopenharmony_cibool is_ET_REL; 47da0c48c4Sopenharmony_cibool is_debug; 48da0c48c4Sopenharmony_ci 49da0c48c4Sopenharmony_ci// Whether the current function has a DW_AT_frame_base defined. 50da0c48c4Sopenharmony_ci// Needed for DW_OP_fbreg. 51da0c48c4Sopenharmony_cibool has_frame_base; 52da0c48c4Sopenharmony_ci 53da0c48c4Sopenharmony_cistatic void 54da0c48c4Sopenharmony_ciprint_die (Dwarf_Die *die, const char *what, int indent) 55da0c48c4Sopenharmony_ci{ 56da0c48c4Sopenharmony_ci Dwarf_Addr entrypc; 57da0c48c4Sopenharmony_ci const char *name = dwarf_diename (die) ?: "<unknown>"; 58da0c48c4Sopenharmony_ci if (dwarf_entrypc (die, &entrypc) == 0) 59da0c48c4Sopenharmony_ci printf ("%*s[%" PRIx64 "] %s '%s'@%" PRIx64 "\n", indent * 2, "", 60da0c48c4Sopenharmony_ci dwarf_dieoffset (die), what, name, entrypc); 61da0c48c4Sopenharmony_ci else 62da0c48c4Sopenharmony_ci printf ("%*s[%" PRIx64 "] %s '%s'\n", indent * 2, "", 63da0c48c4Sopenharmony_ci dwarf_dieoffset (die), what, name); 64da0c48c4Sopenharmony_ci} 65da0c48c4Sopenharmony_ci 66da0c48c4Sopenharmony_cistatic const char * 67da0c48c4Sopenharmony_cidwarf_encoding_string (unsigned int code) 68da0c48c4Sopenharmony_ci{ 69da0c48c4Sopenharmony_ci static const char *const known[] = 70da0c48c4Sopenharmony_ci { 71da0c48c4Sopenharmony_ci#define DWARF_ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME, 72da0c48c4Sopenharmony_ci DWARF_ALL_KNOWN_DW_ATE 73da0c48c4Sopenharmony_ci#undef DWARF_ONE_KNOWN_DW_ATE 74da0c48c4Sopenharmony_ci }; 75da0c48c4Sopenharmony_ci 76da0c48c4Sopenharmony_ci if (likely (code < sizeof (known) / sizeof (known[0]))) 77da0c48c4Sopenharmony_ci return known[code]; 78da0c48c4Sopenharmony_ci 79da0c48c4Sopenharmony_ci return "<unknown encoding>"; 80da0c48c4Sopenharmony_ci} 81da0c48c4Sopenharmony_ci 82da0c48c4Sopenharmony_cistatic const char * 83da0c48c4Sopenharmony_cidwarf_tag_string (unsigned int tag) 84da0c48c4Sopenharmony_ci{ 85da0c48c4Sopenharmony_ci switch (tag) 86da0c48c4Sopenharmony_ci { 87da0c48c4Sopenharmony_ci#define DWARF_ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME; 88da0c48c4Sopenharmony_ci DWARF_ALL_KNOWN_DW_TAG 89da0c48c4Sopenharmony_ci#undef DWARF_ONE_KNOWN_DW_TAG 90da0c48c4Sopenharmony_ci default: 91da0c48c4Sopenharmony_ci return "<unknown tag>"; 92da0c48c4Sopenharmony_ci } 93da0c48c4Sopenharmony_ci} 94da0c48c4Sopenharmony_ci 95da0c48c4Sopenharmony_cistatic const char * 96da0c48c4Sopenharmony_cidwarf_attr_string (unsigned int attrnum) 97da0c48c4Sopenharmony_ci{ 98da0c48c4Sopenharmony_ci switch (attrnum) 99da0c48c4Sopenharmony_ci { 100da0c48c4Sopenharmony_ci#define DWARF_ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME; 101da0c48c4Sopenharmony_ci DWARF_ALL_KNOWN_DW_AT 102da0c48c4Sopenharmony_ci#undef DWARF_ONE_KNOWN_DW_AT 103da0c48c4Sopenharmony_ci default: 104da0c48c4Sopenharmony_ci return "<unknown attr>"; 105da0c48c4Sopenharmony_ci } 106da0c48c4Sopenharmony_ci} 107da0c48c4Sopenharmony_ci 108da0c48c4Sopenharmony_cistatic const char * 109da0c48c4Sopenharmony_cidwarf_form_string (unsigned int form) 110da0c48c4Sopenharmony_ci{ 111da0c48c4Sopenharmony_ci switch (form) 112da0c48c4Sopenharmony_ci { 113da0c48c4Sopenharmony_ci#define DWARF_ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME; 114da0c48c4Sopenharmony_ci DWARF_ALL_KNOWN_DW_FORM 115da0c48c4Sopenharmony_ci#undef DWARF_ONE_KNOWN_DW_FORM 116da0c48c4Sopenharmony_ci default: 117da0c48c4Sopenharmony_ci return "<unknown form>"; 118da0c48c4Sopenharmony_ci } 119da0c48c4Sopenharmony_ci} 120da0c48c4Sopenharmony_ci 121da0c48c4Sopenharmony_ci/* BASE must be a base type DIE referenced by a typed DWARF expression op. */ 122da0c48c4Sopenharmony_cistatic void 123da0c48c4Sopenharmony_ciprint_base_type (Dwarf_Die *base) 124da0c48c4Sopenharmony_ci{ 125da0c48c4Sopenharmony_ci if (dwarf_tag (base) != DW_TAG_base_type) 126da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "not a base type"); 127da0c48c4Sopenharmony_ci 128da0c48c4Sopenharmony_ci Dwarf_Attribute encoding; 129da0c48c4Sopenharmony_ci Dwarf_Word enctype = 0; 130da0c48c4Sopenharmony_ci if (dwarf_attr (base, DW_AT_encoding, &encoding) == NULL 131da0c48c4Sopenharmony_ci || dwarf_formudata (&encoding, &enctype) != 0) 132da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "base type without encoding"); 133da0c48c4Sopenharmony_ci 134da0c48c4Sopenharmony_ci Dwarf_Attribute bsize; 135da0c48c4Sopenharmony_ci Dwarf_Word bits; 136da0c48c4Sopenharmony_ci if (dwarf_attr (base, DW_AT_byte_size, &bsize) != NULL 137da0c48c4Sopenharmony_ci && dwarf_formudata (&bsize, &bits) == 0) 138da0c48c4Sopenharmony_ci bits *= 8; 139da0c48c4Sopenharmony_ci else if (dwarf_attr (base, DW_AT_bit_size, &bsize) == NULL 140da0c48c4Sopenharmony_ci || dwarf_formudata (&bsize, &bits) != 0) 141da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "base type without byte or bit size"); 142da0c48c4Sopenharmony_ci 143da0c48c4Sopenharmony_ci printf ("{%s,%s,%" PRIu64 "@[%" PRIx64 "]}", 144da0c48c4Sopenharmony_ci dwarf_diename (base), 145da0c48c4Sopenharmony_ci dwarf_encoding_string (enctype), 146da0c48c4Sopenharmony_ci bits, 147da0c48c4Sopenharmony_ci dwarf_dieoffset (base)); 148da0c48c4Sopenharmony_ci} 149da0c48c4Sopenharmony_ci 150da0c48c4Sopenharmony_cistatic const char * 151da0c48c4Sopenharmony_cidwarf_opcode_string (unsigned int code) 152da0c48c4Sopenharmony_ci{ 153da0c48c4Sopenharmony_ci static const char *const known[] = 154da0c48c4Sopenharmony_ci { 155da0c48c4Sopenharmony_ci#define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME, 156da0c48c4Sopenharmony_ci DWARF_ALL_KNOWN_DW_OP 157da0c48c4Sopenharmony_ci#undef DWARF_ONE_KNOWN_DW_OP 158da0c48c4Sopenharmony_ci }; 159da0c48c4Sopenharmony_ci 160da0c48c4Sopenharmony_ci if (likely (code < sizeof (known) / sizeof (known[0]))) 161da0c48c4Sopenharmony_ci return known[code]; 162da0c48c4Sopenharmony_ci 163da0c48c4Sopenharmony_ci return "<unknown opcode>"; 164da0c48c4Sopenharmony_ci} 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci// Forward reference for print_expr_block. 167da0c48c4Sopenharmony_cistatic void print_expr (Dwarf_Attribute *, Dwarf_Op *, Dwarf_Addr, int); 168da0c48c4Sopenharmony_ci 169da0c48c4Sopenharmony_cistatic void 170da0c48c4Sopenharmony_ciprint_expr_block (Dwarf_Attribute *attr, Dwarf_Op *exprs, int len, 171da0c48c4Sopenharmony_ci Dwarf_Addr addr, int depth) 172da0c48c4Sopenharmony_ci{ 173da0c48c4Sopenharmony_ci printf ("{"); 174da0c48c4Sopenharmony_ci for (int i = 0; i < len; i++) 175da0c48c4Sopenharmony_ci { 176da0c48c4Sopenharmony_ci print_expr (attr, &exprs[i], addr, depth); 177da0c48c4Sopenharmony_ci printf ("%s", (i + 1 < len ? ", " : "")); 178da0c48c4Sopenharmony_ci } 179da0c48c4Sopenharmony_ci printf ("}"); 180da0c48c4Sopenharmony_ci} 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_cistatic void 183da0c48c4Sopenharmony_ciprint_expr_block_addrs (Dwarf_Attribute *attr, 184da0c48c4Sopenharmony_ci Dwarf_Addr begin, Dwarf_Addr end, 185da0c48c4Sopenharmony_ci Dwarf_Op *exprs, int len) 186da0c48c4Sopenharmony_ci{ 187da0c48c4Sopenharmony_ci printf (" [%" PRIx64 ",%" PRIx64 ") ", begin, end); 188da0c48c4Sopenharmony_ci print_expr_block (attr, exprs, len, begin, 0); 189da0c48c4Sopenharmony_ci printf ("\n"); 190da0c48c4Sopenharmony_ci} 191da0c48c4Sopenharmony_ci 192da0c48c4Sopenharmony_cistatic void 193da0c48c4Sopenharmony_ciprint_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr, int depth) 194da0c48c4Sopenharmony_ci{ 195da0c48c4Sopenharmony_ci#define MAX_DEPTH 64 196da0c48c4Sopenharmony_ci if (depth++ > MAX_DEPTH) 197da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "print_expr recursion depth exceeded"); 198da0c48c4Sopenharmony_ci 199da0c48c4Sopenharmony_ci uint8_t atom = expr->atom; 200da0c48c4Sopenharmony_ci const char *opname = dwarf_opcode_string (atom); 201da0c48c4Sopenharmony_ci 202da0c48c4Sopenharmony_ci switch (atom) 203da0c48c4Sopenharmony_ci { 204da0c48c4Sopenharmony_ci case DW_OP_deref: 205da0c48c4Sopenharmony_ci case DW_OP_dup: 206da0c48c4Sopenharmony_ci case DW_OP_drop: 207da0c48c4Sopenharmony_ci case DW_OP_over: 208da0c48c4Sopenharmony_ci case DW_OP_swap: 209da0c48c4Sopenharmony_ci case DW_OP_rot: 210da0c48c4Sopenharmony_ci case DW_OP_xderef: 211da0c48c4Sopenharmony_ci case DW_OP_abs: 212da0c48c4Sopenharmony_ci case DW_OP_and: 213da0c48c4Sopenharmony_ci case DW_OP_div: 214da0c48c4Sopenharmony_ci case DW_OP_minus: 215da0c48c4Sopenharmony_ci case DW_OP_mod: 216da0c48c4Sopenharmony_ci case DW_OP_mul: 217da0c48c4Sopenharmony_ci case DW_OP_neg: 218da0c48c4Sopenharmony_ci case DW_OP_not: 219da0c48c4Sopenharmony_ci case DW_OP_or: 220da0c48c4Sopenharmony_ci case DW_OP_plus: 221da0c48c4Sopenharmony_ci case DW_OP_shl: 222da0c48c4Sopenharmony_ci case DW_OP_shr: 223da0c48c4Sopenharmony_ci case DW_OP_shra: 224da0c48c4Sopenharmony_ci case DW_OP_xor: 225da0c48c4Sopenharmony_ci case DW_OP_eq: 226da0c48c4Sopenharmony_ci case DW_OP_ge: 227da0c48c4Sopenharmony_ci case DW_OP_gt: 228da0c48c4Sopenharmony_ci case DW_OP_le: 229da0c48c4Sopenharmony_ci case DW_OP_lt: 230da0c48c4Sopenharmony_ci case DW_OP_ne: 231da0c48c4Sopenharmony_ci case DW_OP_lit0 ... DW_OP_lit31: 232da0c48c4Sopenharmony_ci case DW_OP_reg0 ... DW_OP_reg31: 233da0c48c4Sopenharmony_ci case DW_OP_nop: 234da0c48c4Sopenharmony_ci case DW_OP_stack_value: 235da0c48c4Sopenharmony_ci /* No arguments. */ 236da0c48c4Sopenharmony_ci printf ("%s", opname); 237da0c48c4Sopenharmony_ci break; 238da0c48c4Sopenharmony_ci 239da0c48c4Sopenharmony_ci case DW_OP_form_tls_address: 240da0c48c4Sopenharmony_ci /* No arguments. Special. Pops an address and pushes the 241da0c48c4Sopenharmony_ci corresponding address in the current thread local 242da0c48c4Sopenharmony_ci storage. Uses the thread local storage block of the defining 243da0c48c4Sopenharmony_ci module (executable, shared library). */ 244da0c48c4Sopenharmony_ci printf ("%s", opname); 245da0c48c4Sopenharmony_ci break; 246da0c48c4Sopenharmony_ci 247da0c48c4Sopenharmony_ci case DW_OP_GNU_push_tls_address: 248da0c48c4Sopenharmony_ci /* No arguments. Special. Not the same as DW_OP_form_tls_address. 249da0c48c4Sopenharmony_ci Pops an offset into the current thread local strorage and 250da0c48c4Sopenharmony_ci pushes back the actual address. */ 251da0c48c4Sopenharmony_ci printf ("%s", opname); 252da0c48c4Sopenharmony_ci break; 253da0c48c4Sopenharmony_ci 254da0c48c4Sopenharmony_ci case DW_OP_call_frame_cfa: 255da0c48c4Sopenharmony_ci /* No arguments. Special. Pushes Call Frame Address as computed 256da0c48c4Sopenharmony_ci by CFI data (dwarf_cfi_addrframe will fetch that info (either from 257da0c48c4Sopenharmony_ci the .eh_frame or .debug_frame CFI) and dwarf_frame_cfa translatesr 258da0c48c4Sopenharmony_ci the CFI instructions into a plain DWARF expression. 259da0c48c4Sopenharmony_ci Never used in CFI itself. */ 260da0c48c4Sopenharmony_ci 261da0c48c4Sopenharmony_ci if (attr == NULL) 262da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 263da0c48c4Sopenharmony_ci 264da0c48c4Sopenharmony_ci printf ("%s ", opname); 265da0c48c4Sopenharmony_ci if (cfi_eh == NULL && cfi_debug == NULL && !is_debug) 266da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found."); 267da0c48c4Sopenharmony_ci 268da0c48c4Sopenharmony_ci Dwarf_Frame *frame; 269da0c48c4Sopenharmony_ci if (dwarf_cfi_addrframe (cfi_eh, addr + cfi_eh_bias, &frame) == 0 270da0c48c4Sopenharmony_ci || dwarf_cfi_addrframe (cfi_debug, addr + cfi_debug_bias, 271da0c48c4Sopenharmony_ci &frame) == 0) 272da0c48c4Sopenharmony_ci { 273da0c48c4Sopenharmony_ci Dwarf_Op *cfa_ops; 274da0c48c4Sopenharmony_ci size_t cfa_nops; 275da0c48c4Sopenharmony_ci if (dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0) 276da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_frame_cfa 0x%" PRIx64 ": %s", 277da0c48c4Sopenharmony_ci addr, dwarf_errmsg (-1)); 278da0c48c4Sopenharmony_ci if (cfa_nops < 1) 279da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_frame_cfa no ops"); 280da0c48c4Sopenharmony_ci print_expr_block (NULL, cfa_ops, cfa_nops, 0, depth); 281da0c48c4Sopenharmony_ci free (frame); 282da0c48c4Sopenharmony_ci } 283da0c48c4Sopenharmony_ci else if (is_ET_REL || is_debug) 284da0c48c4Sopenharmony_ci { 285da0c48c4Sopenharmony_ci /* XXX In ET_REL files there might be an .eh_frame with relocations 286da0c48c4Sopenharmony_ci we don't handle (e.g. X86_64_PC32). Maybe we should? */ 287da0c48c4Sopenharmony_ci printf ("{...}"); 288da0c48c4Sopenharmony_ci } 289da0c48c4Sopenharmony_ci else 290da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s", 291da0c48c4Sopenharmony_ci addr, dwarf_errmsg (-1)); 292da0c48c4Sopenharmony_ci break; 293da0c48c4Sopenharmony_ci 294da0c48c4Sopenharmony_ci case DW_OP_push_object_address: 295da0c48c4Sopenharmony_ci /* No arguments. Special. Pushes object address explicitly. 296da0c48c4Sopenharmony_ci Normally only done implicitly by DW_AT_data_member_location. 297da0c48c4Sopenharmony_ci Never used in CFI. */ 298da0c48c4Sopenharmony_ci if (attr == NULL) 299da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 300da0c48c4Sopenharmony_ci printf ("%s", opname); 301da0c48c4Sopenharmony_ci break; 302da0c48c4Sopenharmony_ci 303da0c48c4Sopenharmony_ci case DW_OP_addr: 304da0c48c4Sopenharmony_ci /* 1 address argument. */ 305da0c48c4Sopenharmony_ci printf ("%s(0x%" PRIx64 ")", opname, (Dwarf_Addr) expr->number); 306da0c48c4Sopenharmony_ci break; 307da0c48c4Sopenharmony_ci 308da0c48c4Sopenharmony_ci case DW_OP_const1u: 309da0c48c4Sopenharmony_ci case DW_OP_const2u: 310da0c48c4Sopenharmony_ci case DW_OP_const4u: 311da0c48c4Sopenharmony_ci case DW_OP_const8u: 312da0c48c4Sopenharmony_ci case DW_OP_constu: 313da0c48c4Sopenharmony_ci case DW_OP_pick: 314da0c48c4Sopenharmony_ci case DW_OP_plus_uconst: 315da0c48c4Sopenharmony_ci case DW_OP_regx: 316da0c48c4Sopenharmony_ci case DW_OP_piece: 317da0c48c4Sopenharmony_ci case DW_OP_deref_size: 318da0c48c4Sopenharmony_ci case DW_OP_xderef_size: 319da0c48c4Sopenharmony_ci /* 1 numeric unsigned argument. */ 320da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 ")", opname, expr->number); 321da0c48c4Sopenharmony_ci break; 322da0c48c4Sopenharmony_ci 323da0c48c4Sopenharmony_ci case DW_OP_call2: 324da0c48c4Sopenharmony_ci case DW_OP_call4: 325da0c48c4Sopenharmony_ci case DW_OP_call_ref: 326da0c48c4Sopenharmony_ci /* 1 DIE offset argument for more ops in location attribute of DIE. 327da0c48c4Sopenharmony_ci Never used in CFI. */ 328da0c48c4Sopenharmony_ci { 329da0c48c4Sopenharmony_ci if (attr == NULL) 330da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 331da0c48c4Sopenharmony_ci 332da0c48c4Sopenharmony_ci Dwarf_Attribute call_attr; 333da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &call_attr) != 0) 334da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for %s error %s", 335da0c48c4Sopenharmony_ci opname, dwarf_errmsg (-1)); 336da0c48c4Sopenharmony_ci 337da0c48c4Sopenharmony_ci Dwarf_Die call_die; 338da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &call_die) != 0) 339da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die for %s error %s", 340da0c48c4Sopenharmony_ci opname, dwarf_errmsg (-1)); 341da0c48c4Sopenharmony_ci 342da0c48c4Sopenharmony_ci Dwarf_Op *call_ops; 343da0c48c4Sopenharmony_ci size_t call_len; 344da0c48c4Sopenharmony_ci if (dwarf_getlocation (&call_attr, &call_ops, &call_len) != 0) 345da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s", 346da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 347da0c48c4Sopenharmony_ci 348da0c48c4Sopenharmony_ci printf ("%s([%" PRIx64 "]) ", opname, dwarf_dieoffset (&call_die)); 349da0c48c4Sopenharmony_ci print_expr_block (&call_attr, call_ops, call_len, addr, depth); 350da0c48c4Sopenharmony_ci } 351da0c48c4Sopenharmony_ci break; 352da0c48c4Sopenharmony_ci 353da0c48c4Sopenharmony_ci case DW_OP_const1s: 354da0c48c4Sopenharmony_ci case DW_OP_const2s: 355da0c48c4Sopenharmony_ci case DW_OP_const4s: 356da0c48c4Sopenharmony_ci case DW_OP_const8s: 357da0c48c4Sopenharmony_ci case DW_OP_consts: 358da0c48c4Sopenharmony_ci case DW_OP_skip: 359da0c48c4Sopenharmony_ci case DW_OP_bra: 360da0c48c4Sopenharmony_ci case DW_OP_breg0 ... DW_OP_breg31: 361da0c48c4Sopenharmony_ci /* 1 numeric signed argument. */ 362da0c48c4Sopenharmony_ci printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number); 363da0c48c4Sopenharmony_ci break; 364da0c48c4Sopenharmony_ci 365da0c48c4Sopenharmony_ci case DW_OP_fbreg: 366da0c48c4Sopenharmony_ci /* 1 numeric signed argument. Offset from frame base. */ 367da0c48c4Sopenharmony_ci if (attr == NULL) 368da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 369da0c48c4Sopenharmony_ci 370da0c48c4Sopenharmony_ci if (! has_frame_base) 371da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "DW_OP_fbreg used without a frame base"); 372da0c48c4Sopenharmony_ci 373da0c48c4Sopenharmony_ci printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number); 374da0c48c4Sopenharmony_ci break; 375da0c48c4Sopenharmony_ci 376da0c48c4Sopenharmony_ci case DW_OP_bregx: 377da0c48c4Sopenharmony_ci /* 2 arguments, unsigned register number, signed offset. */ 378da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 ",%" PRId64 ")", opname, 379da0c48c4Sopenharmony_ci expr->number, (Dwarf_Sword) expr->number2); 380da0c48c4Sopenharmony_ci break; 381da0c48c4Sopenharmony_ci 382da0c48c4Sopenharmony_ci case DW_OP_bit_piece: 383da0c48c4Sopenharmony_ci /* 2 arguments, unsigned size, unsigned offset. */ 384da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 ",%" PRIu64 ")", opname, 385da0c48c4Sopenharmony_ci expr->number, expr->number2); 386da0c48c4Sopenharmony_ci break; 387da0c48c4Sopenharmony_ci 388da0c48c4Sopenharmony_ci case DW_OP_implicit_value: 389da0c48c4Sopenharmony_ci /* Special, unsigned size plus block. */ 390da0c48c4Sopenharmony_ci { 391da0c48c4Sopenharmony_ci Dwarf_Attribute const_attr; 392da0c48c4Sopenharmony_ci Dwarf_Block block; 393da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0) 394da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", 395da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 396da0c48c4Sopenharmony_ci 397da0c48c4Sopenharmony_ci if (dwarf_formblock (&const_attr, &block) != 0) 398da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_formblock: %s", 399da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 400da0c48c4Sopenharmony_ci 401da0c48c4Sopenharmony_ci /* This is the "old" way. Check they result in the same. */ 402da0c48c4Sopenharmony_ci Dwarf_Block block_impl; 403da0c48c4Sopenharmony_ci if (dwarf_getlocation_implicit_value (attr, expr, &block_impl) != 0) 404da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_value: %s", 405da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 406da0c48c4Sopenharmony_ci 407da0c48c4Sopenharmony_ci assert (expr->number == block.length); 408da0c48c4Sopenharmony_ci assert (block.length == block_impl.length); 409da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 "){", opname, block.length); 410da0c48c4Sopenharmony_ci for (size_t i = 0; i < block.length; i++) 411da0c48c4Sopenharmony_ci { 412da0c48c4Sopenharmony_ci printf ("%02x", block.data[i]); 413da0c48c4Sopenharmony_ci assert (block.data[i] == block_impl.data[i]); 414da0c48c4Sopenharmony_ci } 415da0c48c4Sopenharmony_ci printf("}"); 416da0c48c4Sopenharmony_ci } 417da0c48c4Sopenharmony_ci break; 418da0c48c4Sopenharmony_ci 419da0c48c4Sopenharmony_ci case DW_OP_implicit_pointer: 420da0c48c4Sopenharmony_ci case DW_OP_GNU_implicit_pointer: 421da0c48c4Sopenharmony_ci /* Special, DIE offset, signed offset. Referenced DIE has a 422da0c48c4Sopenharmony_ci location or const_value attribute. */ 423da0c48c4Sopenharmony_ci { 424da0c48c4Sopenharmony_ci if (attr == NULL) 425da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 426da0c48c4Sopenharmony_ci 427da0c48c4Sopenharmony_ci Dwarf_Attribute attrval; 428da0c48c4Sopenharmony_ci if (dwarf_getlocation_implicit_pointer (attr, expr, &attrval) != 0) 429da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_pointer: %s", 430da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 431da0c48c4Sopenharmony_ci 432da0c48c4Sopenharmony_ci // Sanity check, results should be the same. 433da0c48c4Sopenharmony_ci Dwarf_Attribute attrval2; 434da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &attrval2) != 0) 435da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", 436da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 437da0c48c4Sopenharmony_ci 438da0c48c4Sopenharmony_ci assert (dwarf_whatattr (&attrval) == dwarf_whatattr (&attrval2)); 439da0c48c4Sopenharmony_ci assert (dwarf_whatform (&attrval) == dwarf_whatform (&attrval2)); 440da0c48c4Sopenharmony_ci // In theory two different valp pointers could point to the same 441da0c48c4Sopenharmony_ci // value. But here we really expect them to be the equal. 442da0c48c4Sopenharmony_ci assert (attrval.valp == attrval2.valp); 443da0c48c4Sopenharmony_ci 444da0c48c4Sopenharmony_ci Dwarf_Die impl_die; 445da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &impl_die) != 0) 446da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 447da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 448da0c48c4Sopenharmony_ci 449da0c48c4Sopenharmony_ci printf ("%s([%" PRIx64 "],%" PRId64 ") ", opname, 450da0c48c4Sopenharmony_ci dwarf_dieoffset (&impl_die), expr->number2); 451da0c48c4Sopenharmony_ci 452da0c48c4Sopenharmony_ci if (dwarf_whatattr (&attrval) == DW_AT_const_value) 453da0c48c4Sopenharmony_ci printf ("<constant value>"); // Lookup type... 454da0c48c4Sopenharmony_ci else 455da0c48c4Sopenharmony_ci { 456da0c48c4Sopenharmony_ci // Lookup the location description at the current address. 457da0c48c4Sopenharmony_ci Dwarf_Op *exprval; 458da0c48c4Sopenharmony_ci size_t exprval_len; 459da0c48c4Sopenharmony_ci int locs = dwarf_getlocation_addr (&attrval, addr, 460da0c48c4Sopenharmony_ci &exprval, &exprval_len, 1); 461da0c48c4Sopenharmony_ci if (locs == 0) 462da0c48c4Sopenharmony_ci printf ("<no location>"); // This means "optimized out". 463da0c48c4Sopenharmony_ci else if (locs == 1) 464da0c48c4Sopenharmony_ci print_expr_block (&attrval, exprval, exprval_len, addr, depth); 465da0c48c4Sopenharmony_ci else 466da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, 467da0c48c4Sopenharmony_ci "dwarf_getlocation_addr attrval at addr 0x%" PRIx64 468da0c48c4Sopenharmony_ci ", locs (%d): %s", addr, locs, dwarf_errmsg (-1)); 469da0c48c4Sopenharmony_ci } 470da0c48c4Sopenharmony_ci } 471da0c48c4Sopenharmony_ci break; 472da0c48c4Sopenharmony_ci 473da0c48c4Sopenharmony_ci case DW_OP_GNU_variable_value: 474da0c48c4Sopenharmony_ci /* Special, DIE offset. Referenced DIE has a location or const_value 475da0c48c4Sopenharmony_ci attribute. */ 476da0c48c4Sopenharmony_ci { 477da0c48c4Sopenharmony_ci if (attr == NULL) 478da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "%s used in CFI", opname); 479da0c48c4Sopenharmony_ci 480da0c48c4Sopenharmony_ci Dwarf_Attribute attrval; 481da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &attrval) != 0) 482da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", 483da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 484da0c48c4Sopenharmony_ci 485da0c48c4Sopenharmony_ci Dwarf_Die impl_die; 486da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &impl_die) != 0) 487da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 488da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 489da0c48c4Sopenharmony_ci 490da0c48c4Sopenharmony_ci printf ("%s([%" PRIx64 "]) ", opname, dwarf_dieoffset (&impl_die)); 491da0c48c4Sopenharmony_ci 492da0c48c4Sopenharmony_ci if (dwarf_whatattr (&attrval) == DW_AT_const_value) 493da0c48c4Sopenharmony_ci printf ("<constant value>"); // Lookup type... 494da0c48c4Sopenharmony_ci else 495da0c48c4Sopenharmony_ci { 496da0c48c4Sopenharmony_ci // Lookup the location description at the current address. 497da0c48c4Sopenharmony_ci Dwarf_Op *exprval; 498da0c48c4Sopenharmony_ci size_t exprval_len; 499da0c48c4Sopenharmony_ci int locs = dwarf_getlocation_addr (&attrval, addr, 500da0c48c4Sopenharmony_ci &exprval, &exprval_len, 1); 501da0c48c4Sopenharmony_ci if (locs == 0) 502da0c48c4Sopenharmony_ci printf ("<no location>"); // This means "optimized out". 503da0c48c4Sopenharmony_ci else if (locs == 1) 504da0c48c4Sopenharmony_ci print_expr_block (&attrval, exprval, exprval_len, addr, depth); 505da0c48c4Sopenharmony_ci else 506da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, 507da0c48c4Sopenharmony_ci "dwarf_getlocation_addr attrval at addr 0x%" PRIx64 508da0c48c4Sopenharmony_ci ", locs (%d): %s", addr, locs, dwarf_errmsg (-1)); 509da0c48c4Sopenharmony_ci } 510da0c48c4Sopenharmony_ci } 511da0c48c4Sopenharmony_ci break; 512da0c48c4Sopenharmony_ci 513da0c48c4Sopenharmony_ci case DW_OP_entry_value: 514da0c48c4Sopenharmony_ci case DW_OP_GNU_entry_value: 515da0c48c4Sopenharmony_ci /* Special, unsigned size plus expression block. All registers 516da0c48c4Sopenharmony_ci inside the block should be interpreted as they had on 517da0c48c4Sopenharmony_ci entering the function. dwarf_getlocation_attr will return an 518da0c48c4Sopenharmony_ci attribute containing the block as locexpr which can be 519da0c48c4Sopenharmony_ci retrieved with dwarf_getlocation. */ 520da0c48c4Sopenharmony_ci { 521da0c48c4Sopenharmony_ci Dwarf_Attribute entry_attr; 522da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &entry_attr) != 0) 523da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s", 524da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 525da0c48c4Sopenharmony_ci 526da0c48c4Sopenharmony_ci Dwarf_Op *entry_ops; 527da0c48c4Sopenharmony_ci size_t entry_len; 528da0c48c4Sopenharmony_ci if (dwarf_getlocation (&entry_attr, &entry_ops, &entry_len) != 0) 529da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s", 530da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 531da0c48c4Sopenharmony_ci 532da0c48c4Sopenharmony_ci printf ("%s(%zd) ", opname, entry_len); 533da0c48c4Sopenharmony_ci print_expr_block (attr, entry_ops, entry_len, addr, depth); 534da0c48c4Sopenharmony_ci } 535da0c48c4Sopenharmony_ci break; 536da0c48c4Sopenharmony_ci 537da0c48c4Sopenharmony_ci case DW_OP_GNU_parameter_ref: 538da0c48c4Sopenharmony_ci /* Special, unsigned CU relative DIE offset pointing to a 539da0c48c4Sopenharmony_ci DW_TAG_formal_parameter. The value that parameter had at the 540da0c48c4Sopenharmony_ci call site of the current function will be put on the DWARF 541da0c48c4Sopenharmony_ci stack. The value can be retrieved by finding the 542da0c48c4Sopenharmony_ci DW_TAG_GNU_call_site_parameter which has as 543da0c48c4Sopenharmony_ci DW_AT_abstract_origin the same formal parameter DIE. */ 544da0c48c4Sopenharmony_ci { 545da0c48c4Sopenharmony_ci Dwarf_Die param; 546da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, ¶m) != 0) 547da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 548da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 549da0c48c4Sopenharmony_ci // XXX actually lookup DW_TAG_GNU_call_site_parameter 550da0c48c4Sopenharmony_ci printf ("%s[%" PRIx64 "]", opname, dwarf_dieoffset (¶m)); 551da0c48c4Sopenharmony_ci assert (expr->number == dwarf_cuoffset (¶m)); 552da0c48c4Sopenharmony_ci if (dwarf_tag (¶m) != DW_TAG_formal_parameter) 553da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "Not a formal parameter"); 554da0c48c4Sopenharmony_ci } 555da0c48c4Sopenharmony_ci break; 556da0c48c4Sopenharmony_ci 557da0c48c4Sopenharmony_ci case DW_OP_convert: 558da0c48c4Sopenharmony_ci case DW_OP_GNU_convert: 559da0c48c4Sopenharmony_ci case DW_OP_reinterpret: 560da0c48c4Sopenharmony_ci case DW_OP_GNU_reinterpret: 561da0c48c4Sopenharmony_ci /* Special, unsigned CU relative DIE offset pointing to a 562da0c48c4Sopenharmony_ci DW_TAG_base_type. Pops a value, converts or reinterprets the 563da0c48c4Sopenharmony_ci value to the given type. When the argument is zero the value 564da0c48c4Sopenharmony_ci becomes untyped again. */ 565da0c48c4Sopenharmony_ci { 566da0c48c4Sopenharmony_ci Dwarf_Die type; 567da0c48c4Sopenharmony_ci Dwarf_Off off = expr->number; 568da0c48c4Sopenharmony_ci if (off != 0) 569da0c48c4Sopenharmony_ci { 570da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &type) != 0) 571da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 572da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 573da0c48c4Sopenharmony_ci off = dwarf_dieoffset (&type); 574da0c48c4Sopenharmony_ci assert (expr->number == dwarf_cuoffset (&type)); 575da0c48c4Sopenharmony_ci printf ("%s", opname); 576da0c48c4Sopenharmony_ci print_base_type (&type); 577da0c48c4Sopenharmony_ci } 578da0c48c4Sopenharmony_ci else 579da0c48c4Sopenharmony_ci printf ("%s[%" PRIu64 "]", opname, off); 580da0c48c4Sopenharmony_ci 581da0c48c4Sopenharmony_ci } 582da0c48c4Sopenharmony_ci break; 583da0c48c4Sopenharmony_ci 584da0c48c4Sopenharmony_ci case DW_OP_regval_type: 585da0c48c4Sopenharmony_ci case DW_OP_GNU_regval_type: 586da0c48c4Sopenharmony_ci /* Special, unsigned register number plus unsigned CU relative 587da0c48c4Sopenharmony_ci DIE offset pointing to a DW_TAG_base_type. */ 588da0c48c4Sopenharmony_ci { 589da0c48c4Sopenharmony_ci Dwarf_Die type; 590da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &type) != 0) 591da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 592da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 593da0c48c4Sopenharmony_ci assert (expr->number2 == dwarf_cuoffset (&type)); 594da0c48c4Sopenharmony_ci // XXX check size against base_type size? 595da0c48c4Sopenharmony_ci printf ("%s(reg%" PRIu64 ")", opname, expr->number); 596da0c48c4Sopenharmony_ci print_base_type (&type); 597da0c48c4Sopenharmony_ci } 598da0c48c4Sopenharmony_ci break; 599da0c48c4Sopenharmony_ci 600da0c48c4Sopenharmony_ci case DW_OP_deref_type: 601da0c48c4Sopenharmony_ci case DW_OP_GNU_deref_type: 602da0c48c4Sopenharmony_ci /* Special, unsigned size plus unsigned CU relative DIE offset 603da0c48c4Sopenharmony_ci pointing to a DW_TAG_base_type. */ 604da0c48c4Sopenharmony_ci { 605da0c48c4Sopenharmony_ci Dwarf_Die type; 606da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &type) != 0) 607da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 608da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 609da0c48c4Sopenharmony_ci assert (expr->number2 == dwarf_cuoffset (&type)); 610da0c48c4Sopenharmony_ci // XXX check size against base_type size? 611da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 ")", opname, expr->number); 612da0c48c4Sopenharmony_ci print_base_type (&type); 613da0c48c4Sopenharmony_ci } 614da0c48c4Sopenharmony_ci break; 615da0c48c4Sopenharmony_ci 616da0c48c4Sopenharmony_ci case DW_OP_xderef_type: 617da0c48c4Sopenharmony_ci /* Special, unsigned size plus unsigned DIE offset 618da0c48c4Sopenharmony_ci pointing to a DW_TAG_base_type. */ 619da0c48c4Sopenharmony_ci { 620da0c48c4Sopenharmony_ci Dwarf_Die type; 621da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &type) != 0) 622da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 623da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 624da0c48c4Sopenharmony_ci // XXX check size against base_type size? 625da0c48c4Sopenharmony_ci printf ("%s(%" PRIu64 ")", opname, expr->number); 626da0c48c4Sopenharmony_ci print_base_type (&type); 627da0c48c4Sopenharmony_ci } 628da0c48c4Sopenharmony_ci break; 629da0c48c4Sopenharmony_ci 630da0c48c4Sopenharmony_ci case DW_OP_const_type: 631da0c48c4Sopenharmony_ci case DW_OP_GNU_const_type: 632da0c48c4Sopenharmony_ci /* Special, unsigned CU relative DIE offset pointing to a 633da0c48c4Sopenharmony_ci DW_TAG_base_type, an unsigned size length plus a block with 634da0c48c4Sopenharmony_ci the constant value. */ 635da0c48c4Sopenharmony_ci { 636da0c48c4Sopenharmony_ci Dwarf_Die type; 637da0c48c4Sopenharmony_ci if (dwarf_getlocation_die (attr, expr, &type) != 0) 638da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s", 639da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 640da0c48c4Sopenharmony_ci assert (expr->number == dwarf_cuoffset (&type)); 641da0c48c4Sopenharmony_ci 642da0c48c4Sopenharmony_ci Dwarf_Attribute const_attr; 643da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0) 644da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for type: %s", 645da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 646da0c48c4Sopenharmony_ci 647da0c48c4Sopenharmony_ci Dwarf_Block block; 648da0c48c4Sopenharmony_ci if (dwarf_formblock (&const_attr, &block) != 0) 649da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_formblock for type: %s", 650da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 651da0c48c4Sopenharmony_ci 652da0c48c4Sopenharmony_ci printf ("%s", opname); 653da0c48c4Sopenharmony_ci print_base_type (&type); 654da0c48c4Sopenharmony_ci printf ("(%" PRIu64 ")[", block.length); 655da0c48c4Sopenharmony_ci for (size_t i = 0; i < block.length; i++) 656da0c48c4Sopenharmony_ci printf ("%02x", block.data[i]); 657da0c48c4Sopenharmony_ci printf("]"); 658da0c48c4Sopenharmony_ci } 659da0c48c4Sopenharmony_ci break; 660da0c48c4Sopenharmony_ci 661da0c48c4Sopenharmony_ci case DW_OP_GNU_addr_index: 662da0c48c4Sopenharmony_ci case DW_OP_addrx: 663da0c48c4Sopenharmony_ci /* Address from the .debug_addr section (indexed based on CU). */ 664da0c48c4Sopenharmony_ci { 665da0c48c4Sopenharmony_ci Dwarf_Attribute addr_attr; 666da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &addr_attr) != 0) 667da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for addr: %s", 668da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 669da0c48c4Sopenharmony_ci 670da0c48c4Sopenharmony_ci Dwarf_Addr address; 671da0c48c4Sopenharmony_ci if (dwarf_formaddr (&addr_attr, &address) != 0) 672da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_formaddr address failed: %s", 673da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 674da0c48c4Sopenharmony_ci 675da0c48c4Sopenharmony_ci printf ("addr: 0x%" PRIx64, address); 676da0c48c4Sopenharmony_ci } 677da0c48c4Sopenharmony_ci break; 678da0c48c4Sopenharmony_ci 679da0c48c4Sopenharmony_ci case DW_OP_GNU_const_index: 680da0c48c4Sopenharmony_ci case DW_OP_constx: 681da0c48c4Sopenharmony_ci /* Constant from the .debug_addr section (indexed based on CU). */ 682da0c48c4Sopenharmony_ci { 683da0c48c4Sopenharmony_ci Dwarf_Attribute addr_attr; 684da0c48c4Sopenharmony_ci if (dwarf_getlocation_attr (attr, expr, &addr_attr) != 0) 685da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for addr: %s", 686da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 687da0c48c4Sopenharmony_ci 688da0c48c4Sopenharmony_ci Dwarf_Word constant; 689da0c48c4Sopenharmony_ci if (dwarf_formudata (&addr_attr, &constant) != 0) 690da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_formudata constant failed: %s", 691da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 692da0c48c4Sopenharmony_ci 693da0c48c4Sopenharmony_ci printf ("const: 0x%" PRIx64, constant); 694da0c48c4Sopenharmony_ci } 695da0c48c4Sopenharmony_ci break; 696da0c48c4Sopenharmony_ci 697da0c48c4Sopenharmony_ci default: 698da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "unhandled opcode: DW_OP_%s (0x%x)", 699da0c48c4Sopenharmony_ci opname, atom); 700da0c48c4Sopenharmony_ci } 701da0c48c4Sopenharmony_ci} 702da0c48c4Sopenharmony_ci 703da0c48c4Sopenharmony_ci/* Get all variables and print their value expressions. */ 704da0c48c4Sopenharmony_cistatic void 705da0c48c4Sopenharmony_ciprint_varlocs (Dwarf_Die *funcdie) 706da0c48c4Sopenharmony_ci{ 707da0c48c4Sopenharmony_ci // Display frame base for function if it exists. 708da0c48c4Sopenharmony_ci // Should be used for DW_OP_fbreg. 709da0c48c4Sopenharmony_ci has_frame_base = dwarf_hasattr (funcdie, DW_AT_frame_base); 710da0c48c4Sopenharmony_ci if (has_frame_base) 711da0c48c4Sopenharmony_ci { 712da0c48c4Sopenharmony_ci Dwarf_Attribute fb_attr; 713da0c48c4Sopenharmony_ci if (dwarf_attr (funcdie, DW_AT_frame_base, &fb_attr) == NULL) 714da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_attr fb: %s", dwarf_errmsg (-1)); 715da0c48c4Sopenharmony_ci 716da0c48c4Sopenharmony_ci Dwarf_Op *fb_expr; 717da0c48c4Sopenharmony_ci size_t fb_exprlen; 718da0c48c4Sopenharmony_ci if (dwarf_getlocation (&fb_attr, &fb_expr, &fb_exprlen) == 0) 719da0c48c4Sopenharmony_ci { 720da0c48c4Sopenharmony_ci // Covers all of function. 721da0c48c4Sopenharmony_ci Dwarf_Addr entrypc; 722da0c48c4Sopenharmony_ci if (dwarf_entrypc (funcdie, &entrypc) != 0) 723da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_entrypc: %s", dwarf_errmsg (-1)); 724da0c48c4Sopenharmony_ci 725da0c48c4Sopenharmony_ci printf (" frame_base: "); 726da0c48c4Sopenharmony_ci if (entrypc == 0) 727da0c48c4Sopenharmony_ci printf ("XXX zero address"); // XXX bad DWARF? 728da0c48c4Sopenharmony_ci else 729da0c48c4Sopenharmony_ci print_expr_block (&fb_attr, fb_expr, fb_exprlen, entrypc, 0); 730da0c48c4Sopenharmony_ci printf ("\n"); 731da0c48c4Sopenharmony_ci } 732da0c48c4Sopenharmony_ci else 733da0c48c4Sopenharmony_ci { 734da0c48c4Sopenharmony_ci Dwarf_Addr base, start, end; 735da0c48c4Sopenharmony_ci ptrdiff_t off = 0; 736da0c48c4Sopenharmony_ci printf (" frame_base:\n"); 737da0c48c4Sopenharmony_ci while ((off = dwarf_getlocations (&fb_attr, off, &base, 738da0c48c4Sopenharmony_ci &start, &end, 739da0c48c4Sopenharmony_ci &fb_expr, &fb_exprlen)) > 0) 740da0c48c4Sopenharmony_ci { 741da0c48c4Sopenharmony_ci printf (" (%" PRIx64 ",%" PRIx64 ") ", start, end); 742da0c48c4Sopenharmony_ci print_expr_block (&fb_attr, fb_expr, fb_exprlen, start, 0); 743da0c48c4Sopenharmony_ci printf ("\n"); 744da0c48c4Sopenharmony_ci } 745da0c48c4Sopenharmony_ci 746da0c48c4Sopenharmony_ci if (off < 0) 747da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocations fb: %s", 748da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 749da0c48c4Sopenharmony_ci } 750da0c48c4Sopenharmony_ci } 751da0c48c4Sopenharmony_ci else if (dwarf_tag (funcdie) == DW_TAG_inlined_subroutine) 752da0c48c4Sopenharmony_ci { 753da0c48c4Sopenharmony_ci // See whether the subprogram we are inlined into has a frame 754da0c48c4Sopenharmony_ci // base we should use. 755da0c48c4Sopenharmony_ci Dwarf_Die *scopes; 756da0c48c4Sopenharmony_ci int n = dwarf_getscopes_die (funcdie, &scopes); 757da0c48c4Sopenharmony_ci if (n <= 0) 758da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getscopes_die: %s", dwarf_errmsg (-1)); 759da0c48c4Sopenharmony_ci 760da0c48c4Sopenharmony_ci while (n-- > 0) 761da0c48c4Sopenharmony_ci if (dwarf_tag (&scopes[n]) == DW_TAG_subprogram 762da0c48c4Sopenharmony_ci && dwarf_hasattr (&scopes[n], DW_AT_frame_base)) 763da0c48c4Sopenharmony_ci { 764da0c48c4Sopenharmony_ci has_frame_base = true; 765da0c48c4Sopenharmony_ci break; 766da0c48c4Sopenharmony_ci } 767da0c48c4Sopenharmony_ci free (scopes); 768da0c48c4Sopenharmony_ci } 769da0c48c4Sopenharmony_ci 770da0c48c4Sopenharmony_ci if (! dwarf_haschildren (funcdie)) 771da0c48c4Sopenharmony_ci return; 772da0c48c4Sopenharmony_ci 773da0c48c4Sopenharmony_ci Dwarf_Die child; 774da0c48c4Sopenharmony_ci int res = dwarf_child (funcdie, &child); 775da0c48c4Sopenharmony_ci if (res < 0) 776da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_child: %s", dwarf_errmsg (-1)); 777da0c48c4Sopenharmony_ci 778da0c48c4Sopenharmony_ci /* We thought there was a child, but the child list was actually 779da0c48c4Sopenharmony_ci empty. This isn't technically an error in the DWARF, but it is 780da0c48c4Sopenharmony_ci certainly non-optimimal. */ 781da0c48c4Sopenharmony_ci if (res == 1) 782da0c48c4Sopenharmony_ci return; 783da0c48c4Sopenharmony_ci 784da0c48c4Sopenharmony_ci do 785da0c48c4Sopenharmony_ci { 786da0c48c4Sopenharmony_ci int tag = dwarf_tag (&child); 787da0c48c4Sopenharmony_ci if (tag == DW_TAG_variable || tag == DW_TAG_formal_parameter) 788da0c48c4Sopenharmony_ci { 789da0c48c4Sopenharmony_ci const char *what = tag == DW_TAG_variable ? "variable" : "parameter"; 790da0c48c4Sopenharmony_ci print_die (&child, what, 2); 791da0c48c4Sopenharmony_ci 792da0c48c4Sopenharmony_ci if (dwarf_hasattr (&child, DW_AT_location)) 793da0c48c4Sopenharmony_ci { 794da0c48c4Sopenharmony_ci Dwarf_Attribute attr; 795da0c48c4Sopenharmony_ci if (dwarf_attr (&child, DW_AT_location, &attr) == NULL) 796da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_attr: %s", dwarf_errmsg (-1)); 797da0c48c4Sopenharmony_ci 798da0c48c4Sopenharmony_ci Dwarf_Op *expr; 799da0c48c4Sopenharmony_ci size_t exprlen; 800da0c48c4Sopenharmony_ci if (dwarf_getlocation (&attr, &expr, &exprlen) == 0) 801da0c48c4Sopenharmony_ci { 802da0c48c4Sopenharmony_ci // Covers all ranges of the function. 803da0c48c4Sopenharmony_ci // Evaluate the expression block for each range. 804da0c48c4Sopenharmony_ci ptrdiff_t offset = 0; 805da0c48c4Sopenharmony_ci Dwarf_Addr base, begin, end; 806da0c48c4Sopenharmony_ci do 807da0c48c4Sopenharmony_ci { 808da0c48c4Sopenharmony_ci offset = dwarf_ranges (funcdie, offset, &base, 809da0c48c4Sopenharmony_ci &begin, &end); 810da0c48c4Sopenharmony_ci if (offset < 0) 811da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_ranges: %s", 812da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 813da0c48c4Sopenharmony_ci 814da0c48c4Sopenharmony_ci if (offset > 0) 815da0c48c4Sopenharmony_ci { 816da0c48c4Sopenharmony_ci if (exprlen == 0) 817da0c48c4Sopenharmony_ci printf (" (%" 818da0c48c4Sopenharmony_ci PRIx64 ",%" PRIx64 819da0c48c4Sopenharmony_ci ") <empty expression>\n", begin, end); 820da0c48c4Sopenharmony_ci else 821da0c48c4Sopenharmony_ci print_expr_block_addrs (&attr, begin, end, 822da0c48c4Sopenharmony_ci expr, exprlen); 823da0c48c4Sopenharmony_ci } 824da0c48c4Sopenharmony_ci } 825da0c48c4Sopenharmony_ci while (offset > 0); 826da0c48c4Sopenharmony_ci 827da0c48c4Sopenharmony_ci if (offset < 0) 828da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_ranges: %s", 829da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 830da0c48c4Sopenharmony_ci } 831da0c48c4Sopenharmony_ci else 832da0c48c4Sopenharmony_ci { 833da0c48c4Sopenharmony_ci Dwarf_Addr base, begin, end; 834da0c48c4Sopenharmony_ci ptrdiff_t offset = 0; 835da0c48c4Sopenharmony_ci while ((offset = dwarf_getlocations (&attr, offset, 836da0c48c4Sopenharmony_ci &base, &begin, &end, 837da0c48c4Sopenharmony_ci &expr, &exprlen)) > 0) 838da0c48c4Sopenharmony_ci if (begin >= end) 839da0c48c4Sopenharmony_ci printf (" (%" PRIx64 ",%" PRIx64 840da0c48c4Sopenharmony_ci ") <empty range>\n", begin, end); // XXX report? 841da0c48c4Sopenharmony_ci else 842da0c48c4Sopenharmony_ci { 843da0c48c4Sopenharmony_ci print_expr_block_addrs (&attr, begin, end, 844da0c48c4Sopenharmony_ci expr, exprlen); 845da0c48c4Sopenharmony_ci 846da0c48c4Sopenharmony_ci // Extra sanity check for dwarf_getlocation_addr 847da0c48c4Sopenharmony_ci // Must at least find one range for begin and end-1. 848da0c48c4Sopenharmony_ci Dwarf_Op *expraddr; 849da0c48c4Sopenharmony_ci size_t expraddr_len; 850da0c48c4Sopenharmony_ci int locs = dwarf_getlocation_addr (&attr, begin, 851da0c48c4Sopenharmony_ci &expraddr, 852da0c48c4Sopenharmony_ci &expraddr_len, 1); 853da0c48c4Sopenharmony_ci assert (locs == 1); 854da0c48c4Sopenharmony_ci locs = dwarf_getlocation_addr (&attr, end - 1, 855da0c48c4Sopenharmony_ci &expraddr, 856da0c48c4Sopenharmony_ci &expraddr_len, 1); 857da0c48c4Sopenharmony_ci assert (locs == 1); 858da0c48c4Sopenharmony_ci } 859da0c48c4Sopenharmony_ci 860da0c48c4Sopenharmony_ci if (offset < 0) 861da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getlocations: %s", 862da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 863da0c48c4Sopenharmony_ci } 864da0c48c4Sopenharmony_ci } 865da0c48c4Sopenharmony_ci else if (dwarf_hasattr (&child, DW_AT_const_value)) 866da0c48c4Sopenharmony_ci { 867da0c48c4Sopenharmony_ci printf (" <constant value>\n"); // Lookup type and print. 868da0c48c4Sopenharmony_ci } 869da0c48c4Sopenharmony_ci else 870da0c48c4Sopenharmony_ci { 871da0c48c4Sopenharmony_ci printf (" <no value>\n"); 872da0c48c4Sopenharmony_ci } 873da0c48c4Sopenharmony_ci } 874da0c48c4Sopenharmony_ci } 875da0c48c4Sopenharmony_ci while (dwarf_siblingof (&child, &child) == 0); 876da0c48c4Sopenharmony_ci} 877da0c48c4Sopenharmony_ci 878da0c48c4Sopenharmony_cistatic int 879da0c48c4Sopenharmony_cihandle_instance (Dwarf_Die *funcdie, void *arg __attribute__ ((unused))) 880da0c48c4Sopenharmony_ci{ 881da0c48c4Sopenharmony_ci print_die (funcdie, "inlined function", 1); 882da0c48c4Sopenharmony_ci print_varlocs (funcdie); 883da0c48c4Sopenharmony_ci 884da0c48c4Sopenharmony_ci return DWARF_CB_OK; 885da0c48c4Sopenharmony_ci} 886da0c48c4Sopenharmony_ci 887da0c48c4Sopenharmony_cistatic int 888da0c48c4Sopenharmony_cihandle_function (Dwarf_Die *funcdie, void *arg __attribute__((unused))) 889da0c48c4Sopenharmony_ci{ 890da0c48c4Sopenharmony_ci if (dwarf_func_inline (funcdie) > 0) 891da0c48c4Sopenharmony_ci { 892da0c48c4Sopenharmony_ci // abstract inline definition, find all inlined instances. 893da0c48c4Sopenharmony_ci 894da0c48c4Sopenharmony_ci // Note this is convenient for listing all instances together 895da0c48c4Sopenharmony_ci // so you can easily compare the location expressions describing 896da0c48c4Sopenharmony_ci // the variables and parameters, but it isn't very efficient 897da0c48c4Sopenharmony_ci // since it will walk the DIE tree multiple times. 898da0c48c4Sopenharmony_ci if (dwarf_func_inline_instances (funcdie, &handle_instance, NULL) != 0) 899da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_func_inline_instances: %s", 900da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 901da0c48c4Sopenharmony_ci } 902da0c48c4Sopenharmony_ci else 903da0c48c4Sopenharmony_ci { 904da0c48c4Sopenharmony_ci // Contains actual code, not just a declaration? 905da0c48c4Sopenharmony_ci Dwarf_Addr entrypc; 906da0c48c4Sopenharmony_ci if (dwarf_entrypc (funcdie, &entrypc) == 0) 907da0c48c4Sopenharmony_ci { 908da0c48c4Sopenharmony_ci print_die (funcdie, "function", 1); 909da0c48c4Sopenharmony_ci print_varlocs (funcdie); 910da0c48c4Sopenharmony_ci } 911da0c48c4Sopenharmony_ci } 912da0c48c4Sopenharmony_ci 913da0c48c4Sopenharmony_ci return DWARF_CB_OK; 914da0c48c4Sopenharmony_ci} 915da0c48c4Sopenharmony_ci 916da0c48c4Sopenharmony_cistruct attr_arg 917da0c48c4Sopenharmony_ci{ 918da0c48c4Sopenharmony_ci int depth; 919da0c48c4Sopenharmony_ci Dwarf_Addr entrypc; 920da0c48c4Sopenharmony_ci}; 921da0c48c4Sopenharmony_ci 922da0c48c4Sopenharmony_cistatic int 923da0c48c4Sopenharmony_cihandle_attr (Dwarf_Attribute *attr, void *arg) 924da0c48c4Sopenharmony_ci{ 925da0c48c4Sopenharmony_ci int depth = ((struct attr_arg *) arg)->depth; 926da0c48c4Sopenharmony_ci Dwarf_Addr entrypc = ((struct attr_arg *) arg)->entrypc; 927da0c48c4Sopenharmony_ci 928da0c48c4Sopenharmony_ci unsigned int code = dwarf_whatattr (attr); 929da0c48c4Sopenharmony_ci unsigned int form = dwarf_whatform (attr); 930da0c48c4Sopenharmony_ci 931da0c48c4Sopenharmony_ci printf ("%*s%s (%s)", depth * 2, "", 932da0c48c4Sopenharmony_ci dwarf_attr_string (code), dwarf_form_string (form)); 933da0c48c4Sopenharmony_ci 934da0c48c4Sopenharmony_ci /* If we can get an DWARF expression (or location lists) from this 935da0c48c4Sopenharmony_ci attribute we'll print it, otherwise we'll ignore it. But if 936da0c48c4Sopenharmony_ci there is an error while the attribute has the "correct" form then 937da0c48c4Sopenharmony_ci we'll report an error (we can only really check DW_FORM_exprloc 938da0c48c4Sopenharmony_ci other forms can be ambiguous). */ 939da0c48c4Sopenharmony_ci Dwarf_Op *expr; 940da0c48c4Sopenharmony_ci size_t exprlen; 941da0c48c4Sopenharmony_ci bool printed = false; 942da0c48c4Sopenharmony_ci int res = dwarf_getlocation (attr, &expr, &exprlen); 943da0c48c4Sopenharmony_ci if (res == 0) 944da0c48c4Sopenharmony_ci { 945da0c48c4Sopenharmony_ci printf (" "); 946da0c48c4Sopenharmony_ci print_expr_block (attr, expr, exprlen, entrypc, 0); 947da0c48c4Sopenharmony_ci printf ("\n"); 948da0c48c4Sopenharmony_ci printed = true; 949da0c48c4Sopenharmony_ci } 950da0c48c4Sopenharmony_ci else if (form == DW_FORM_exprloc) 951da0c48c4Sopenharmony_ci { 952da0c48c4Sopenharmony_ci error (0, 0, "%s dwarf_getlocation failed: %s", 953da0c48c4Sopenharmony_ci dwarf_attr_string (code), dwarf_errmsg (-1)); 954da0c48c4Sopenharmony_ci return DWARF_CB_ABORT; 955da0c48c4Sopenharmony_ci } 956da0c48c4Sopenharmony_ci else 957da0c48c4Sopenharmony_ci { 958da0c48c4Sopenharmony_ci Dwarf_Addr base, begin, end; 959da0c48c4Sopenharmony_ci ptrdiff_t offset = 0; 960da0c48c4Sopenharmony_ci while ((offset = dwarf_getlocations (attr, offset, 961da0c48c4Sopenharmony_ci &base, &begin, &end, 962da0c48c4Sopenharmony_ci &expr, &exprlen)) > 0) 963da0c48c4Sopenharmony_ci { 964da0c48c4Sopenharmony_ci if (! printed) 965da0c48c4Sopenharmony_ci printf ("\n"); 966da0c48c4Sopenharmony_ci printf ("%*s", depth * 2, ""); 967da0c48c4Sopenharmony_ci print_expr_block_addrs (attr, begin, end, expr, exprlen); 968da0c48c4Sopenharmony_ci printed = true; 969da0c48c4Sopenharmony_ci } 970da0c48c4Sopenharmony_ci } 971da0c48c4Sopenharmony_ci 972da0c48c4Sopenharmony_ci if (! printed) 973da0c48c4Sopenharmony_ci printf ("\n"); 974da0c48c4Sopenharmony_ci 975da0c48c4Sopenharmony_ci return DWARF_CB_OK; 976da0c48c4Sopenharmony_ci} 977da0c48c4Sopenharmony_ci 978da0c48c4Sopenharmony_cistatic void 979da0c48c4Sopenharmony_cihandle_die (Dwarf_Die *die, int depth, bool outer_has_frame_base, 980da0c48c4Sopenharmony_ci Dwarf_Addr outer_entrypc) 981da0c48c4Sopenharmony_ci{ 982da0c48c4Sopenharmony_ci /* CU DIE already printed. */ 983da0c48c4Sopenharmony_ci if (depth > 0) 984da0c48c4Sopenharmony_ci { 985da0c48c4Sopenharmony_ci const char *name = dwarf_diename (die); 986da0c48c4Sopenharmony_ci if (name != NULL) 987da0c48c4Sopenharmony_ci printf ("%*s[%" PRIx64 "] %s \"%s\"\n", depth * 2, "", 988da0c48c4Sopenharmony_ci dwarf_dieoffset (die), dwarf_tag_string (dwarf_tag (die)), 989da0c48c4Sopenharmony_ci name); 990da0c48c4Sopenharmony_ci else 991da0c48c4Sopenharmony_ci printf ("%*s[%" PRIx64 "] %s\n", depth * 2, "", 992da0c48c4Sopenharmony_ci dwarf_dieoffset (die), dwarf_tag_string (dwarf_tag (die))); 993da0c48c4Sopenharmony_ci } 994da0c48c4Sopenharmony_ci 995da0c48c4Sopenharmony_ci struct attr_arg arg; 996da0c48c4Sopenharmony_ci arg.depth = depth + 1; 997da0c48c4Sopenharmony_ci 998da0c48c4Sopenharmony_ci /* The (lowest) address to use for (looking up) operands that depend 999da0c48c4Sopenharmony_ci on address. */ 1000da0c48c4Sopenharmony_ci Dwarf_Addr die_entrypc; 1001da0c48c4Sopenharmony_ci if (dwarf_entrypc (die, &die_entrypc) != 0 || die_entrypc == 0) 1002da0c48c4Sopenharmony_ci { 1003da0c48c4Sopenharmony_ci /* Try to get the lowest address of the first range covered. */ 1004da0c48c4Sopenharmony_ci Dwarf_Addr base, start, end; 1005da0c48c4Sopenharmony_ci if (dwarf_ranges (die, 0, &base, &start, &end) <= 0 || start == 0) 1006da0c48c4Sopenharmony_ci die_entrypc = outer_entrypc; 1007da0c48c4Sopenharmony_ci else 1008da0c48c4Sopenharmony_ci die_entrypc = start; 1009da0c48c4Sopenharmony_ci } 1010da0c48c4Sopenharmony_ci arg.entrypc = die_entrypc; 1011da0c48c4Sopenharmony_ci 1012da0c48c4Sopenharmony_ci /* Whether this or the any outer DIE has a frame base. Used as 1013da0c48c4Sopenharmony_ci sanity check when printing expressions that use DW_OP_fbreg. */ 1014da0c48c4Sopenharmony_ci bool die_has_frame_base = dwarf_hasattr (die, DW_AT_frame_base); 1015da0c48c4Sopenharmony_ci die_has_frame_base |= outer_has_frame_base; 1016da0c48c4Sopenharmony_ci has_frame_base = die_has_frame_base; 1017da0c48c4Sopenharmony_ci 1018da0c48c4Sopenharmony_ci /* Look through all attributes to find those that contain DWARF 1019da0c48c4Sopenharmony_ci expressions and print those. We expect to handle all attributes, 1020da0c48c4Sopenharmony_ci anything else is an error. */ 1021da0c48c4Sopenharmony_ci if (dwarf_getattrs (die, handle_attr, &arg, 0) != 1) 1022da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "Couldn't get all attributes: %s", 1023da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 1024da0c48c4Sopenharmony_ci 1025da0c48c4Sopenharmony_ci /* Handle children and siblings recursively depth first. */ 1026da0c48c4Sopenharmony_ci Dwarf_Die child; 1027da0c48c4Sopenharmony_ci if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0) 1028da0c48c4Sopenharmony_ci handle_die (&child, depth + 1, die_has_frame_base, die_entrypc); 1029da0c48c4Sopenharmony_ci 1030da0c48c4Sopenharmony_ci Dwarf_Die sibling; 1031da0c48c4Sopenharmony_ci if (dwarf_siblingof (die, &sibling) == 0) 1032da0c48c4Sopenharmony_ci handle_die (&sibling, depth, outer_has_frame_base, outer_entrypc); 1033da0c48c4Sopenharmony_ci} 1034da0c48c4Sopenharmony_ci 1035da0c48c4Sopenharmony_ciint 1036da0c48c4Sopenharmony_cimain (int argc, char *argv[]) 1037da0c48c4Sopenharmony_ci{ 1038da0c48c4Sopenharmony_ci /* With --exprlocs we process all DIEs looking for any attribute 1039da0c48c4Sopenharmony_ci which contains an DWARF expression (but not location lists) and 1040da0c48c4Sopenharmony_ci print those. Otherwise we process all function DIEs and print 1041da0c48c4Sopenharmony_ci all DWARF expressions and location lists associated with 1042da0c48c4Sopenharmony_ci parameters and variables). It must be the first argument, 1043da0c48c4Sopenharmony_ci or the second, after --debug. */ 1044da0c48c4Sopenharmony_ci bool exprlocs = false; 1045da0c48c4Sopenharmony_ci 1046da0c48c4Sopenharmony_ci /* With --debug we ignore not being able to find .eh_frame. 1047da0c48c4Sopenharmony_ci It must come as first argument. */ 1048da0c48c4Sopenharmony_ci is_debug = false; 1049da0c48c4Sopenharmony_ci if (argc > 1) 1050da0c48c4Sopenharmony_ci { 1051da0c48c4Sopenharmony_ci if (strcmp ("--exprlocs", argv[1]) == 0) 1052da0c48c4Sopenharmony_ci { 1053da0c48c4Sopenharmony_ci exprlocs = true; 1054da0c48c4Sopenharmony_ci argv[1] = ""; 1055da0c48c4Sopenharmony_ci } 1056da0c48c4Sopenharmony_ci else if (strcmp ("--debug", argv[1]) == 0) 1057da0c48c4Sopenharmony_ci { 1058da0c48c4Sopenharmony_ci is_debug = true; 1059da0c48c4Sopenharmony_ci argv[1] = ""; 1060da0c48c4Sopenharmony_ci } 1061da0c48c4Sopenharmony_ci } 1062da0c48c4Sopenharmony_ci 1063da0c48c4Sopenharmony_ci if (argc > 2) 1064da0c48c4Sopenharmony_ci { 1065da0c48c4Sopenharmony_ci if (strcmp ("--exprlocs", argv[2]) == 0) 1066da0c48c4Sopenharmony_ci { 1067da0c48c4Sopenharmony_ci exprlocs = true; 1068da0c48c4Sopenharmony_ci argv[2] = ""; 1069da0c48c4Sopenharmony_ci } 1070da0c48c4Sopenharmony_ci } 1071da0c48c4Sopenharmony_ci 1072da0c48c4Sopenharmony_ci int remaining; 1073da0c48c4Sopenharmony_ci Dwfl *dwfl; 1074da0c48c4Sopenharmony_ci (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining, 1075da0c48c4Sopenharmony_ci &dwfl); 1076da0c48c4Sopenharmony_ci assert (dwfl != NULL); 1077da0c48c4Sopenharmony_ci 1078da0c48c4Sopenharmony_ci Dwarf_Die *cu = NULL; 1079da0c48c4Sopenharmony_ci Dwarf_Addr dwbias; 1080da0c48c4Sopenharmony_ci bool found_cu = false; 1081da0c48c4Sopenharmony_ci while ((cu = dwfl_nextcu (dwfl, cu, &dwbias)) != NULL) 1082da0c48c4Sopenharmony_ci { 1083da0c48c4Sopenharmony_ci /* Only walk actual compile units (not partial units) that 1084da0c48c4Sopenharmony_ci contain code if we are only interested in the function variable 1085da0c48c4Sopenharmony_ci locations. */ 1086da0c48c4Sopenharmony_ci Dwarf_Die cudie; 1087da0c48c4Sopenharmony_ci Dwarf_Die subdie; 1088da0c48c4Sopenharmony_ci uint8_t unit_type; 1089da0c48c4Sopenharmony_ci if (dwarf_cu_info (cu->cu, NULL, &unit_type, &cudie, &subdie, 1090da0c48c4Sopenharmony_ci NULL, NULL, NULL) != 0) 1091da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_cu_info: %s", dwarf_errmsg (-1)); 1092da0c48c4Sopenharmony_ci if (unit_type == DW_UT_skeleton) 1093da0c48c4Sopenharmony_ci cudie = subdie; 1094da0c48c4Sopenharmony_ci 1095da0c48c4Sopenharmony_ci Dwarf_Addr cubase; 1096da0c48c4Sopenharmony_ci if (dwarf_tag (&cudie) == DW_TAG_compile_unit 1097da0c48c4Sopenharmony_ci && (exprlocs || dwarf_lowpc (&cudie, &cubase) == 0)) 1098da0c48c4Sopenharmony_ci { 1099da0c48c4Sopenharmony_ci found_cu = true; 1100da0c48c4Sopenharmony_ci 1101da0c48c4Sopenharmony_ci Dwfl_Module *mod = dwfl_cumodule (cu); 1102da0c48c4Sopenharmony_ci Dwarf_Addr modbias; 1103da0c48c4Sopenharmony_ci dw = dwfl_module_getdwarf (mod, &modbias); 1104da0c48c4Sopenharmony_ci assert (dwbias == modbias); 1105da0c48c4Sopenharmony_ci 1106da0c48c4Sopenharmony_ci const char *mainfile; 1107da0c48c4Sopenharmony_ci const char *modname = dwfl_module_info (mod, NULL, 1108da0c48c4Sopenharmony_ci NULL, NULL, 1109da0c48c4Sopenharmony_ci NULL, NULL, 1110da0c48c4Sopenharmony_ci &mainfile, 1111da0c48c4Sopenharmony_ci NULL); 1112da0c48c4Sopenharmony_ci if (modname == NULL) 1113da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwfl_module_info: %s", dwarf_errmsg (-1)); 1114da0c48c4Sopenharmony_ci 1115da0c48c4Sopenharmony_ci const char *name = (modname[0] != '\0' 1116da0c48c4Sopenharmony_ci ? modname 1117da0c48c4Sopenharmony_ci : basename (mainfile)); 1118da0c48c4Sopenharmony_ci printf ("module '%s'\n", name); 1119da0c48c4Sopenharmony_ci print_die (&cudie, "CU", 0); 1120da0c48c4Sopenharmony_ci 1121da0c48c4Sopenharmony_ci Dwarf_Addr elfbias; 1122da0c48c4Sopenharmony_ci Elf *elf = dwfl_module_getelf (mod, &elfbias); 1123da0c48c4Sopenharmony_ci 1124da0c48c4Sopenharmony_ci // CFI. We need both since sometimes neither is complete. 1125da0c48c4Sopenharmony_ci cfi_debug = dwfl_module_dwarf_cfi (mod, &cfi_debug_bias); 1126da0c48c4Sopenharmony_ci cfi_eh = dwfl_module_eh_cfi (mod, &cfi_eh_bias); 1127da0c48c4Sopenharmony_ci 1128da0c48c4Sopenharmony_ci // No bias needed, same file. 1129da0c48c4Sopenharmony_ci assert (cfi_debug == NULL || cfi_debug_bias == 0); 1130da0c48c4Sopenharmony_ci 1131da0c48c4Sopenharmony_ci // We are a bit forgiving for object files. There might be 1132da0c48c4Sopenharmony_ci // relocations we don't handle that are needed in some 1133da0c48c4Sopenharmony_ci // places... 1134da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); 1135da0c48c4Sopenharmony_ci is_ET_REL = ehdr->e_type == ET_REL; 1136da0c48c4Sopenharmony_ci 1137da0c48c4Sopenharmony_ci if (exprlocs) 1138da0c48c4Sopenharmony_ci { 1139da0c48c4Sopenharmony_ci Dwarf_Addr entrypc; 1140da0c48c4Sopenharmony_ci if (dwarf_entrypc (&cudie, &entrypc) != 0) 1141da0c48c4Sopenharmony_ci entrypc = 0; 1142da0c48c4Sopenharmony_ci 1143da0c48c4Sopenharmony_ci /* XXX - Passing true for has_frame_base is not really true. 1144da0c48c4Sopenharmony_ci We do it because we want to resolve all DIEs and all 1145da0c48c4Sopenharmony_ci attributes. Technically we should check that the DIE 1146da0c48c4Sopenharmony_ci (types) are referenced from variables that are defined in 1147da0c48c4Sopenharmony_ci a context (function) that has a frame base. */ 1148da0c48c4Sopenharmony_ci handle_die (&cudie, 0, true /* Should be false */, entrypc); 1149da0c48c4Sopenharmony_ci } 1150da0c48c4Sopenharmony_ci else if (dwarf_getfuncs (&cudie, handle_function, NULL, 0) != 0) 1151da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "dwarf_getfuncs %s", 1152da0c48c4Sopenharmony_ci dwarf_errmsg (-1)); 1153da0c48c4Sopenharmony_ci } 1154da0c48c4Sopenharmony_ci } 1155da0c48c4Sopenharmony_ci 1156da0c48c4Sopenharmony_ci if (! found_cu) 1157da0c48c4Sopenharmony_ci error (EXIT_FAILURE, 0, "No DWARF CU found?"); 1158da0c48c4Sopenharmony_ci 1159da0c48c4Sopenharmony_ci dwfl_end (dwfl); 1160da0c48c4Sopenharmony_ci return 0; 1161da0c48c4Sopenharmony_ci} 1162