Home | History | Annotate | Download | only in tests
      1 /* Test program for dwarf location functions.
      2    Copyright (C) 2013, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 #include <config.h>
     19 #include <assert.h>
     20 #include <argp.h>
     21 #include <inttypes.h>
     22 #include <errno.h>
     23 #include ELFUTILS_HEADER(dw)
     24 #include ELFUTILS_HEADER(dwfl)
     25 #include <dwarf.h>
     26 #include <stdio.h>
     27 #include <stdlib.h>
     28 #include <error.h>
     29 #include <string.h>
     30 #include <sys/types.h>
     31 #include <sys/stat.h>
     32 #include <fcntl.h>
     33 #include <unistd.h>
     34 
     35 #include "../libdw/known-dwarf.h"
     36 
     37 // The Dwarf, Dwarf_CFIs and address bias of
     38 // cfi table to adjust DWARF addresses against.
     39 // Needed for DW_OP_call_frame_cfa.
     40 static Dwarf *dw;
     41 Dwarf_CFI *cfi_debug;
     42 Dwarf_CFI *cfi_eh;
     43 Dwarf_Addr cfi_eh_bias;
     44 
     45 // Whether the current function has a DW_AT_frame_base defined.
     46 // Needed for DW_OP_fbreg.
     47 bool has_frame_base;
     48 
     49 static void
     50 print_die (Dwarf_Die *die, const char *what, int indent)
     51 {
     52   Dwarf_Addr entrypc;
     53   const char *name = dwarf_diename (die) ?: "<unknown>";
     54   if (dwarf_entrypc (die, &entrypc) == 0)
     55     printf ("%*s[%" PRIx64 "] %s '%s'@%" PRIx64 "\n", indent * 2, "",
     56 	    dwarf_dieoffset (die), what, name, entrypc);
     57   else
     58     printf ("%*s[%" PRIx64 "] %s '%s'\n", indent * 2, "",
     59 	    dwarf_dieoffset (die), what, name);
     60 }
     61 
     62 static const char *
     63 dwarf_encoding_string (unsigned int code)
     64 {
     65   static const char *const known[] =
     66     {
     67 #define DWARF_ONE_KNOWN_DW_ATE(NAME, CODE) [CODE] = #NAME,
     68       DWARF_ALL_KNOWN_DW_ATE
     69 #undef DWARF_ONE_KNOWN_DW_ATE
     70     };
     71 
     72   if (likely (code < sizeof (known) / sizeof (known[0])))
     73     return known[code];
     74 
     75   return NULL;
     76 }
     77 
     78 /* BASE must be a base type DIE referenced by a typed DWARF expression op.  */
     79 static void
     80 print_base_type (Dwarf_Die *base)
     81 {
     82   assert (dwarf_tag (base) == DW_TAG_base_type);
     83 
     84   Dwarf_Attribute encoding;
     85   Dwarf_Word enctype = 0;
     86   if (dwarf_attr (base, DW_AT_encoding, &encoding) == NULL
     87       || dwarf_formudata (&encoding, &enctype) != 0)
     88     error (EXIT_FAILURE, 0, "base type without encoding");
     89 
     90   Dwarf_Attribute bsize;
     91   Dwarf_Word bits;
     92   if (dwarf_attr (base, DW_AT_byte_size, &bsize) != NULL
     93       && dwarf_formudata (&bsize, &bits) == 0)
     94     bits *= 8;
     95   else if (dwarf_attr (base, DW_AT_bit_size, &bsize) == NULL
     96 	   || dwarf_formudata (&bsize, &bits) != 0)
     97     error (EXIT_FAILURE, 0, "base type without byte or bit size");
     98 
     99   printf ("{%s,%s,%" PRIu64 "@[%" PRIx64 "]}",
    100 	  dwarf_diename (base),
    101 	  dwarf_encoding_string (enctype),
    102 	  bits,
    103 	  dwarf_dieoffset (base));
    104 }
    105 
    106 static const char *
    107 dwarf_opcode_string (unsigned int code)
    108 {
    109   static const char *const known[] =
    110     {
    111 #define DWARF_ONE_KNOWN_DW_OP(NAME, CODE) [CODE] = #NAME,
    112       DWARF_ALL_KNOWN_DW_OP
    113 #undef DWARF_ONE_KNOWN_DW_OP
    114     };
    115 
    116   if (likely (code < sizeof (known) / sizeof (known[0])))
    117     return known[code];
    118 
    119   return NULL;
    120 }
    121 
    122 // Forward reference for print_expr_block.
    123 static void print_expr (Dwarf_Attribute *, Dwarf_Op *, Dwarf_Addr);
    124 
    125 static void
    126 print_expr_block (Dwarf_Attribute *attr, Dwarf_Op *exprs, int len,
    127 		  Dwarf_Addr addr)
    128 {
    129   printf ("{");
    130   for (int i = 0; i < len; i++)
    131     {
    132       print_expr (attr, &exprs[i], addr);
    133       printf ("%s", (i + 1 < len ? ", " : ""));
    134     }
    135   printf ("}");
    136 }
    137 
    138 static void
    139 print_expr_block_addrs (Dwarf_Attribute *attr,
    140 			Dwarf_Addr begin, Dwarf_Addr end,
    141 			Dwarf_Op *exprs, int len)
    142 {
    143   printf ("      [%" PRIx64 ",%" PRIx64 ") ", begin, end);
    144   print_expr_block (attr, exprs, len, begin);
    145   printf ("\n");
    146 }
    147 
    148 static void
    149 print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
    150 {
    151   uint8_t atom = expr->atom;
    152   const char *opname = dwarf_opcode_string (atom);
    153   assert (opname != NULL);
    154 
    155   switch (atom)
    156     {
    157     case DW_OP_deref:
    158     case DW_OP_dup:
    159     case DW_OP_drop:
    160     case DW_OP_over:
    161     case DW_OP_swap:
    162     case DW_OP_rot:
    163     case DW_OP_xderef:
    164     case DW_OP_abs:
    165     case DW_OP_and:
    166     case DW_OP_div:
    167     case DW_OP_minus:
    168     case DW_OP_mod:
    169     case DW_OP_mul:
    170     case DW_OP_neg:
    171     case DW_OP_not:
    172     case DW_OP_or:
    173     case DW_OP_plus:
    174     case DW_OP_shl:
    175     case DW_OP_shr:
    176     case DW_OP_shra:
    177     case DW_OP_xor:
    178     case DW_OP_eq:
    179     case DW_OP_ge:
    180     case DW_OP_gt:
    181     case DW_OP_le:
    182     case DW_OP_lt:
    183     case DW_OP_ne:
    184     case DW_OP_lit0 ... DW_OP_lit31:
    185     case DW_OP_reg0 ... DW_OP_reg31:
    186     case DW_OP_nop:
    187     case DW_OP_stack_value:
    188       /* No arguments. */
    189       printf ("%s", opname);
    190       break;
    191 
    192     case DW_OP_form_tls_address:
    193       /* No arguments. Special. Pops an address and pushes the
    194 	 corresponding address in the current thread local
    195 	 storage. Uses the thread local storage block of the defining
    196 	 module (executable, shared library). */
    197       printf ("%s", opname);
    198       break;
    199 
    200     case DW_OP_GNU_push_tls_address:
    201       /* No arguments. Special. Not the same as DW_OP_form_tls_address.
    202 	 Pops an offset into the current thread local strorage and
    203 	 pushes back the actual address. */
    204       printf ("%s", opname);
    205       break;
    206 
    207     case DW_OP_call_frame_cfa:
    208       /* No arguments. Special. Pushes Call Frame Address as computed
    209 	 by CFI data (dwarf_cfi_addrframe will fetch that info (either from
    210 	 the .eh_frame or .debug_frame CFI) and dwarf_frame_cfa translatesr
    211          the CFI instructions into a plain DWARF expression.
    212 	 Never used in CFI itself. */
    213 
    214       if (attr == NULL)
    215 	error (EXIT_FAILURE, 0, "%s used in CFI", opname);
    216 
    217       printf ("%s ", opname);
    218       if (cfi_eh == NULL && cfi_debug == NULL)
    219 	error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found.");
    220 
    221       Dwarf_Frame *frame;
    222       if (dwarf_cfi_addrframe (cfi_eh, addr + cfi_eh_bias, &frame) != 0
    223 	  && dwarf_cfi_addrframe (cfi_debug, addr, &frame) != 0)
    224 	error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s",
    225 	       addr, dwarf_errmsg (-1));
    226 
    227       Dwarf_Op *cfa_ops;
    228       size_t cfa_nops;
    229       if (dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0)
    230 	error (EXIT_FAILURE, 0, "dwarf_frame_cfa 0x%" PRIx64 ": %s",
    231 	       addr, dwarf_errmsg (-1));
    232       if (cfa_nops < 1)
    233 	error (EXIT_FAILURE, 0, "dwarf_frame_cfa no ops");
    234       print_expr_block (NULL, cfa_ops, cfa_nops, 0);
    235       free (frame);
    236       break;
    237 
    238     case DW_OP_push_object_address:
    239       /* No arguments. Special. Pushes object address explicitly.
    240        Normally only done implicitly by DW_AT_data_member_location.
    241        Never used in CFI. */
    242       if (attr == NULL)
    243 	error (EXIT_FAILURE, 0, "%s used in CFI", opname);
    244       printf ("%s", opname);
    245       break;
    246 
    247     case DW_OP_addr:
    248       /* 1 address argument. */
    249       printf ("%s(0x%" PRIx64 ")", opname, (Dwarf_Addr) expr->number);
    250       break;
    251 
    252     case DW_OP_const1u:
    253     case DW_OP_const2u:
    254     case DW_OP_const4u:
    255     case DW_OP_const8u:
    256     case DW_OP_constu:
    257     case DW_OP_pick:
    258     case DW_OP_plus_uconst:
    259     case DW_OP_regx:
    260     case DW_OP_piece:
    261     case DW_OP_deref_size:
    262     case DW_OP_xderef_size:
    263       /* 1 numeric unsigned argument. */
    264       printf ("%s(%" PRIu64 ")", opname, expr->number);
    265       break;
    266 
    267     case DW_OP_call2:
    268     case DW_OP_call4:
    269     case DW_OP_call_ref:
    270       /* 1 DIE offset argument for more ops in location attribute of DIE.
    271          Never used in CFI.  */
    272       {
    273 	if (attr == NULL)
    274 	  error (EXIT_FAILURE, 0, "%s used in CFI", opname);
    275 
    276 	Dwarf_Attribute call_attr;
    277 	if (dwarf_getlocation_attr (attr, expr, &call_attr) != 0)
    278 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for %s error %s",
    279 		 opname, dwarf_errmsg (-1));
    280 
    281 	Dwarf_Die call_die;
    282 	if (dwarf_getlocation_die (attr, expr, &call_die) != 0)
    283 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die for %s error %s",
    284 		 opname, dwarf_errmsg (-1));
    285 
    286 	Dwarf_Op *call_ops;
    287 	size_t call_len;
    288 	if (dwarf_getlocation (&call_attr, &call_ops, &call_len) != 0)
    289 	  error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s",
    290 		 dwarf_errmsg (-1));
    291 
    292 	printf ("%s([%" PRIx64 "]) ", opname, dwarf_dieoffset (&call_die));
    293 	print_expr_block (&call_attr, call_ops, call_len, addr);
    294       }
    295       break;
    296 
    297     case DW_OP_const1s:
    298     case DW_OP_const2s:
    299     case DW_OP_const4s:
    300     case DW_OP_const8s:
    301     case DW_OP_consts:
    302     case DW_OP_skip:
    303     case DW_OP_bra:
    304     case DW_OP_breg0 ... DW_OP_breg31:
    305       /* 1 numeric signed argument. */
    306       printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number);
    307       break;
    308 
    309     case DW_OP_fbreg:
    310       /* 1 numeric signed argument. Offset from frame base. */
    311       if (attr == NULL)
    312 	  error (EXIT_FAILURE, 0, "%s used in CFI", opname);
    313 
    314       if (! has_frame_base)
    315 	error (EXIT_FAILURE, 0, "DW_OP_fbreg used without a frame base");
    316 
    317       printf ("%s(%" PRId64 ")", opname, (Dwarf_Sword) expr->number);
    318       break;
    319 
    320     case DW_OP_bregx:
    321       /* 2 arguments, unsigned register number, signed offset. */
    322       printf ("%s(%" PRIu64 ",%" PRId64 ")", opname,
    323 	      expr->number, (Dwarf_Sword) expr->number2);
    324       break;
    325 
    326     case DW_OP_bit_piece:
    327       /* 2 arguments, unsigned size, unsigned offset. */
    328       printf ("%s(%" PRIu64 ",%" PRIu64 ")", opname,
    329 	      expr->number, expr->number2);
    330       break;
    331 
    332     case DW_OP_implicit_value:
    333       /* Special, unsigned size plus block. */
    334       {
    335 	Dwarf_Attribute const_attr;
    336 	Dwarf_Block block;
    337 	if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0)
    338 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s",
    339 		 dwarf_errmsg (-1));
    340 
    341 	if (dwarf_formblock (&const_attr, &block) != 0)
    342 	  error (EXIT_FAILURE, 0, "dwarf_formblock: %s",
    343 		 dwarf_errmsg (-1));
    344 
    345 	/* This is the "old" way. Check they result in the same.  */
    346 	Dwarf_Block block_impl;
    347 	if (dwarf_getlocation_implicit_value (attr, expr, &block_impl) != 0)
    348 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_value: %s",
    349 		 dwarf_errmsg (-1));
    350 
    351 	assert (expr->number == block.length);
    352 	assert (block.length == block_impl.length);
    353 	printf ("%s(%" PRIu64 "){", opname, block.length);
    354 	for (size_t i = 0; i < block.length; i++)
    355 	  {
    356 	    printf ("%02x", block.data[i]);
    357 	    assert (block.data[i] == block_impl.data[i]);
    358 	  }
    359 	printf("}");
    360       }
    361       break;
    362 
    363     case DW_OP_GNU_implicit_pointer:
    364       /* Special, DIE offset, signed offset. Referenced DIE has a
    365 	 location or const_value attribute. */
    366       {
    367 	if (attr == NULL)
    368 	  error (EXIT_FAILURE, 0, "%s used in CFI", opname);
    369 
    370 	Dwarf_Attribute attrval;
    371 	if (dwarf_getlocation_implicit_pointer (attr, expr, &attrval) != 0)
    372 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_implicit_pointer: %s",
    373 		 dwarf_errmsg (-1));
    374 
    375 	// Sanity check, results should be the same.
    376 	Dwarf_Attribute attrval2;
    377 	if (dwarf_getlocation_attr (attr, expr, &attrval2) != 0)
    378 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s",
    379 		 dwarf_errmsg (-1));
    380 
    381 	assert (dwarf_whatattr (&attrval) == dwarf_whatattr (&attrval2));
    382 	assert (dwarf_whatform (&attrval) == dwarf_whatform (&attrval2));
    383 	// In theory two different valp pointers could point to the same
    384 	// value. But here we really expect them to be the equal.
    385 	assert (attrval.valp == attrval2.valp);
    386 
    387 	Dwarf_Die impl_die;
    388 	if (dwarf_getlocation_die (attr, expr, &impl_die) != 0)
    389 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_due: %s",
    390 		 dwarf_errmsg (-1));
    391 
    392 	printf ("%s([%" PRIx64 "],%" PRId64 ") ", opname,
    393 		dwarf_dieoffset (&impl_die), expr->number2);
    394 
    395 	if (dwarf_whatattr (&attrval) == DW_AT_const_value)
    396 	  printf ("<constant value>"); // Lookup type...
    397 	else
    398 	  {
    399 	    // Lookup the location description at the current address.
    400 	    Dwarf_Op *exprval;
    401 	    size_t exprval_len;
    402 	    int locs = dwarf_getlocation_addr (&attrval, addr,
    403 					       &exprval, &exprval_len, 1);
    404 	    if (locs == 0)
    405 	      printf ("<no location>"); // This means "optimized out".
    406 	    else if (locs == 1)
    407 	      print_expr_block (&attrval, exprval, exprval_len, addr);
    408 	    else
    409 	      error (EXIT_FAILURE, 0,
    410 		     "dwarf_getlocation_addr attrval at addr 0x%" PRIx64
    411 		     ", locs (%d): %s", addr, locs, dwarf_errmsg (-1));
    412 	  }
    413       }
    414       break;
    415 
    416     case DW_OP_GNU_entry_value:
    417       /* Special, unsigned size plus expression block. All registers
    418 	 inside the block should be interpreted as they had on
    419 	 entering the function. dwarf_getlocation_attr will return an
    420 	 attribute containing the block as locexpr which can be
    421 	 retrieved with dwarf_getlocation.  */
    422       {
    423 	Dwarf_Attribute entry_attr;
    424 	if (dwarf_getlocation_attr (attr, expr, &entry_attr) != 0)
    425 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s",
    426 		 dwarf_errmsg (-1));
    427 
    428 	Dwarf_Op *entry_ops;
    429 	size_t entry_len;
    430 	if (dwarf_getlocation (&entry_attr, &entry_ops, &entry_len) != 0)
    431 	  error (EXIT_FAILURE, 0, "dwarf_getlocation for entry: %s",
    432 		 dwarf_errmsg (-1));
    433 
    434 	printf ("%s(%zd) ", opname, entry_len);
    435 	print_expr_block (attr, entry_ops, entry_len, addr);
    436       }
    437       break;
    438 
    439     case DW_OP_GNU_parameter_ref:
    440       /* Special, unsigned CU relative DIE offset pointing to a
    441 	 DW_TAG_formal_parameter. The value that parameter had at the
    442 	 call site of the current function will be put on the DWARF
    443 	 stack. The value can be retrieved by finding the
    444 	 DW_TAG_GNU_call_site_parameter which has as
    445 	 DW_AT_abstract_origin the same formal parameter DIE. */
    446       {
    447 	Dwarf_Die param;
    448 	if (dwarf_getlocation_die (attr, expr, &param) != 0)
    449 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
    450 		 dwarf_errmsg (-1));
    451 	// XXX actually lookup DW_TAG_GNU_call_site_parameter
    452 	printf ("%s[%" PRIx64 "]", opname, dwarf_dieoffset (&param));
    453 	assert (expr->number == dwarf_cuoffset (&param));
    454 	assert (dwarf_tag (&param) == DW_TAG_formal_parameter);
    455       }
    456       break;
    457 
    458     case DW_OP_GNU_convert:
    459     case DW_OP_GNU_reinterpret:
    460       /* Special, unsigned CU relative DIE offset pointing to a
    461 	 DW_TAG_base_type. Pops a value, converts or reinterprets the
    462 	 value to the given type. When the argument is zero the value
    463 	 becomes untyped again. */
    464       {
    465 	Dwarf_Die type;
    466 	Dwarf_Off off = expr->number;
    467 	if (off != 0)
    468 	  {
    469 	    if (dwarf_getlocation_die (attr, expr, &type) != 0)
    470 	      error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
    471 		     dwarf_errmsg (-1));
    472 	    off = dwarf_dieoffset (&type);
    473 	    assert (expr->number == dwarf_cuoffset (&type));
    474 	    printf ("%s", opname);
    475 	    print_base_type (&type);
    476 	  }
    477 	else
    478 	  printf ("%s[%" PRIu64 "]", opname, off);
    479 
    480       }
    481       break;
    482 
    483     case DW_OP_GNU_regval_type:
    484       /* Special, unsigned register number plus unsigned CU relative
    485          DIE offset pointing to a DW_TAG_base_type. */
    486       {
    487 	Dwarf_Die type;
    488 	if (dwarf_getlocation_die (attr, expr, &type) != 0)
    489 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
    490 		 dwarf_errmsg (-1));
    491 	assert (expr->number2 == dwarf_cuoffset (&type));
    492 	// XXX check size against base_type size?
    493 	printf ("%s(reg%" PRIu64 ")", opname, expr->number);
    494 	print_base_type (&type);
    495       }
    496       break;
    497 
    498     case DW_OP_GNU_deref_type:
    499       /* Special, unsigned size plus unsigned CU relative DIE offset
    500 	 pointing to a DW_TAG_base_type. */
    501       {
    502 	Dwarf_Die type;
    503 	if (dwarf_getlocation_die (attr, expr, &type) != 0)
    504 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
    505 		 dwarf_errmsg (-1));
    506 	assert (expr->number2 == dwarf_cuoffset (&type));
    507 	// XXX check size against base_type size?
    508 	printf ("%s(%" PRIu64 ")", opname, expr->number);
    509 	print_base_type (&type);
    510       }
    511       break;
    512 
    513     case DW_OP_GNU_const_type:
    514       /* Special, unsigned CU relative DIE offset pointing to a
    515 	 DW_TAG_base_type, an unsigned size length plus a block with
    516 	 the constant value. */
    517       {
    518 	Dwarf_Die type;
    519 	if (dwarf_getlocation_die (attr, expr, &type) != 0)
    520 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
    521 		 dwarf_errmsg (-1));
    522 	assert (expr->number == dwarf_cuoffset (&type));
    523 
    524 	Dwarf_Attribute const_attr;
    525 	if (dwarf_getlocation_attr (attr, expr, &const_attr) != 0)
    526 	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr for type: %s",
    527 		 dwarf_errmsg (-1));
    528 
    529 	Dwarf_Block block;
    530 	if (dwarf_formblock (&const_attr, &block) != 0)
    531 	  error (EXIT_FAILURE, 0, "dwarf_formblock for type: %s",
    532 		 dwarf_errmsg (-1));
    533 
    534 	printf ("%s", opname);
    535 	print_base_type (&type);
    536 	printf ("(%" PRIu64 ")[", block.length);
    537 	for (size_t i = 0; i < block.length; i++)
    538 	  printf ("%02x", block.data[i]);
    539 	printf("]");
    540       }
    541       break;
    542 
    543     default:
    544       error (EXIT_FAILURE, 0, "unhandled opcode: DW_OP_%s (0x%x)",
    545 	     opname, atom);
    546     }
    547 }
    548 
    549 /* Get all variables and print their value expressions. */
    550 static void
    551 print_varlocs (Dwarf_Die *funcdie)
    552 {
    553   // Display frame base for function if it exists.
    554   // Should be used for DW_OP_fbreg.
    555   has_frame_base = dwarf_hasattr (funcdie, DW_AT_frame_base);
    556   if (has_frame_base)
    557     {
    558       Dwarf_Attribute fb_attr;
    559       if (dwarf_attr (funcdie, DW_AT_frame_base, &fb_attr) == NULL)
    560 	error (EXIT_FAILURE, 0, "dwarf_attr fb: %s", dwarf_errmsg (-1));
    561 
    562       Dwarf_Op *fb_expr;
    563       size_t fb_exprlen;
    564       if (dwarf_getlocation (&fb_attr, &fb_expr, &fb_exprlen) == 0)
    565 	{
    566 	  // Covers all of function.
    567 	  Dwarf_Addr entrypc;
    568 	  if (dwarf_entrypc (funcdie, &entrypc) != 0)
    569 	    error (EXIT_FAILURE, 0, "dwarf_entrypc: %s", dwarf_errmsg (-1));
    570 
    571 	  printf ("    frame_base: ");
    572 	  if (entrypc == 0)
    573 	    printf ("XXX zero address"); // XXX bad DWARF?
    574 	  else
    575 	    print_expr_block (&fb_attr, fb_expr, fb_exprlen, entrypc);
    576 	  printf ("\n");
    577 	}
    578       else
    579 	{
    580 	  Dwarf_Addr base, start, end;
    581 	  ptrdiff_t off = 0;
    582 	  printf ("    frame_base:\n");
    583           while ((off = dwarf_getlocations (&fb_attr, off, &base,
    584 					    &start, &end,
    585 					    &fb_expr, &fb_exprlen)) > 0)
    586 	    {
    587 	      printf ("      (%" PRIx64 ",%" PRIx64 ") ", start, end);
    588 	      print_expr_block (&fb_attr, fb_expr, fb_exprlen, start);
    589 	      printf ("\n");
    590 	    }
    591 
    592 	  if (off < 0)
    593 	    error (EXIT_FAILURE, 0, "dwarf_getlocations fb: %s",
    594 		   dwarf_errmsg (-1));
    595 	}
    596     }
    597   else if (dwarf_tag (funcdie) == DW_TAG_inlined_subroutine)
    598     {
    599       // See whether the subprogram we are inlined into has a frame
    600       // base we should use.
    601       Dwarf_Die *scopes;
    602       int n = dwarf_getscopes_die (funcdie, &scopes);
    603       if (n <= 0)
    604 	error (EXIT_FAILURE, 0, "dwarf_getscopes_die: %s", dwarf_errmsg (-1));
    605 
    606       while (n-- > 0)
    607 	if (dwarf_tag (&scopes[n]) == DW_TAG_subprogram
    608 	    && dwarf_hasattr (&scopes[n], DW_AT_frame_base))
    609 	  {
    610 	    has_frame_base = true;
    611 	    break;
    612 	  }
    613       free (scopes);
    614     }
    615 
    616   if (! dwarf_haschildren (funcdie))
    617     return;
    618 
    619   Dwarf_Die child;
    620   int res = dwarf_child (funcdie, &child);
    621   if (res < 0)
    622     error (EXIT_FAILURE, 0, "dwarf_child: %s", dwarf_errmsg (-1));
    623 
    624   /* We thought there was a child, but the child list was actually
    625      empty. This isn't technically an error in the DWARF, but it is
    626      certainly non-optimimal.  */
    627   if (res == 1)
    628     return;
    629 
    630   do
    631     {
    632       int tag = dwarf_tag (&child);
    633       if (tag == DW_TAG_variable || tag == DW_TAG_formal_parameter)
    634 	{
    635 	  const char *what = tag == DW_TAG_variable ? "variable" : "parameter";
    636 	  print_die (&child, what, 2);
    637 
    638 	  if (dwarf_hasattr (&child, DW_AT_location))
    639 	    {
    640 	      Dwarf_Attribute attr;
    641 	      if (dwarf_attr (&child, DW_AT_location, &attr) == NULL)
    642 		error (EXIT_FAILURE, 0, "dwarf_attr: %s", dwarf_errmsg (-1));
    643 
    644 	      Dwarf_Op *expr;
    645 	      size_t exprlen;
    646 	      if (dwarf_getlocation (&attr, &expr, &exprlen) == 0)
    647 		{
    648 		  // Covers all ranges of the function.
    649 		  // Evaluate the expression block for each range.
    650 		  ptrdiff_t offset = 0;
    651 		  Dwarf_Addr base, begin, end;
    652 		  do
    653 		    {
    654 		      offset = dwarf_ranges (funcdie, offset, &base,
    655 					     &begin, &end);
    656 		      if (offset < 0)
    657 			error (EXIT_FAILURE, 0, "dwarf_ranges: %s",
    658 			       dwarf_errmsg (-1));
    659 
    660 		      if (offset > 0)
    661 			{
    662 			  if (exprlen == 0)
    663 			    printf ("      (%"
    664 				    PRIx64 ",%" PRIx64
    665 				    ") <empty expression>\n", begin, end);
    666 			  else
    667 			    print_expr_block_addrs (&attr, begin, end,
    668 						    expr, exprlen);
    669 			}
    670 		    }
    671 		  while (offset > 0);
    672 
    673 		  if (offset < 0)
    674 		    error (EXIT_FAILURE, 0, "dwarf_ranges: %s",
    675 			   dwarf_errmsg (-1));
    676 		}
    677 	      else
    678 		{
    679 		  Dwarf_Addr base, begin, end;
    680 		  ptrdiff_t offset = 0;
    681 		  while ((offset = dwarf_getlocations (&attr, offset,
    682 						       &base, &begin, &end,
    683 						       &expr, &exprlen)) > 0)
    684 		    if (begin >= end)
    685 		      printf ("      (%" PRIx64 ",%" PRIx64
    686 			      ") <empty range>\n", begin, end); // XXX report?
    687 		    else
    688 		      {
    689 			print_expr_block_addrs (&attr, begin, end,
    690 						expr, exprlen);
    691 
    692 			// Extra sanity check for dwarf_getlocation_addr
    693 			// Must at least find one range for begin and end-1.
    694 			Dwarf_Op *expraddr;
    695 			size_t expraddr_len;
    696 			int locs = dwarf_getlocation_addr (&attr, begin,
    697 							   &expraddr,
    698 							   &expraddr_len, 1);
    699 			assert (locs == 1);
    700 			locs = dwarf_getlocation_addr (&attr, end - 1,
    701 						       &expraddr,
    702 						       &expraddr_len, 1);
    703 			assert (locs == 1);
    704 		      }
    705 
    706 		  if (offset < 0)
    707 		    error (EXIT_FAILURE, 0, "dwarf_getlocations: %s",
    708 			   dwarf_errmsg (-1));
    709 		}
    710 	    }
    711 	  else if (dwarf_hasattr (&child, DW_AT_const_value))
    712 	    {
    713 	      printf ("      <constant value>\n"); // Lookup type and print.
    714 	    }
    715 	  else
    716 	    {
    717 	      printf ("      <no value>\n");
    718 	    }
    719 	}
    720     }
    721   while (dwarf_siblingof (&child, &child) == 0);
    722 }
    723 
    724 static int
    725 handle_instance (Dwarf_Die *funcdie, void *arg __attribute__ ((unused)))
    726 {
    727   print_die (funcdie, "inlined function", 1);
    728   print_varlocs (funcdie);
    729 
    730   return DWARF_CB_OK;
    731 }
    732 
    733 static int
    734 handle_function (Dwarf_Die *funcdie, void *arg __attribute__((unused)))
    735 {
    736   if (dwarf_func_inline (funcdie) > 0)
    737     {
    738       // abstract inline definition, find all inlined instances.
    739 
    740       // Note this is convenient for listing all instances together
    741       // so you can easily compare the location expressions describing
    742       // the variables and parameters, but it isn't very efficient
    743       // since it will walk the DIE tree multiple times.
    744       if (dwarf_func_inline_instances (funcdie, &handle_instance, NULL) != 0)
    745 	error (EXIT_FAILURE, 0, "dwarf_func_inline_instances: %s",
    746 	       dwarf_errmsg (-1));
    747     }
    748   else
    749     {
    750       // Contains actual code, not just a declaration?
    751       Dwarf_Addr entrypc;
    752       if (dwarf_entrypc (funcdie, &entrypc) == 0)
    753 	{
    754 	  print_die (funcdie, "function", 1);
    755 	  print_varlocs (funcdie);
    756 	}
    757     }
    758 
    759   return DWARF_CB_OK;
    760 }
    761 
    762 int
    763 main (int argc, char *argv[])
    764 {
    765   int remaining;
    766   Dwfl *dwfl;
    767   (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
    768                      &dwfl);
    769   assert (dwfl != NULL);
    770 
    771   Dwarf_Die *cu = NULL;
    772   Dwarf_Addr dwbias;
    773   while ((cu = dwfl_nextcu (dwfl, cu, &dwbias)) != NULL)
    774     {
    775       /* Only walk actual compile units (not partial units) that
    776 	 contain code.  */
    777       Dwarf_Addr cubase;
    778       if (dwarf_tag (cu) == DW_TAG_compile_unit
    779 	  && dwarf_lowpc (cu, &cubase) == 0)
    780 	{
    781 	  Dwfl_Module *mod = dwfl_cumodule (cu);
    782 	  Dwarf_Addr modbias;
    783 	  dw = dwfl_module_getdwarf (mod, &modbias);
    784 	  assert (dwbias == modbias);
    785 
    786 	  const char *mainfile;
    787 	  const char *modname = dwfl_module_info (mod, NULL,
    788 						  NULL, NULL,
    789 						  NULL, NULL,
    790 						  &mainfile,
    791 						  NULL);
    792 	  if (modname == NULL)
    793 	    error (EXIT_FAILURE, 0, "dwfl_module_info: %s", dwarf_errmsg (-1));
    794 
    795 	  const char *name = (modname[0] != '\0'
    796 			      ? modname
    797 			      :  basename (mainfile));
    798 	  printf ("module '%s'\n", name);
    799 	  print_die (cu, "CU", 0);
    800 
    801 	  Dwarf_Addr elfbias;
    802 	  Elf *elf = dwfl_module_getelf (mod, &elfbias);
    803 
    804 	  // CFI. We need both since sometimes neither is complete.
    805 	  cfi_debug = dwarf_getcfi (dw); // No bias needed, same file.
    806 	  cfi_eh = dwarf_getcfi_elf (elf);
    807 	  cfi_eh_bias = dwbias - elfbias;
    808 
    809 	  // Get the actual CU DIE and walk all functions inside it.
    810 	  Dwarf_Die cudie;
    811 	  uint8_t offsize;
    812 	  uint8_t addrsize;
    813 	  if (dwarf_diecu (cu, &cudie, &addrsize, &offsize) == NULL)
    814 	    error (EXIT_FAILURE, 0, "dwarf_diecu %s", dwarf_errmsg (-1));
    815 
    816 	  if (dwarf_getfuncs (cu, handle_function, NULL, 0) != 0)
    817 	    error (EXIT_FAILURE, 0, "dwarf_getfuncs %s",
    818 		   dwarf_errmsg (-1));
    819 	}
    820     }
    821 
    822   dwfl_end (dwfl);
    823   return 0;
    824 }
    825