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.
40static Dwarf *dw;
41Dwarf_CFI *cfi_debug;
42Dwarf_CFI *cfi_eh;
43Dwarf_Addr cfi_eh_bias;
44
45// Whether the current function has a DW_AT_frame_base defined.
46// Needed for DW_OP_fbreg.
47bool has_frame_base;
48
49static void
50print_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
62static const char *
63dwarf_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.  */
79static void
80print_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
106static const char *
107dwarf_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.
123static void print_expr (Dwarf_Attribute *, Dwarf_Op *, Dwarf_Addr);
124
125static void
126print_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
138static void
139print_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
148static void
149print_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. */
550static void
551print_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
724static int
725handle_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
733static int
734handle_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
762int
763main (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