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