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