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