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