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