1/* Test program for dwarf_die_addr_die.
2   Copyright (C) 2018 Red Hat, Inc.
3   This file is part of elfutils.
4
5   This file is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   elfutils is distributed in the hope that it will be useful, but
11   WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18#include <config.h>
19#include ELFUTILS_HEADER(dw)
20#include <dwarf.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <stdio.h>
25#include <stdint.h>
26#include <stdlib.h>
27#include <assert.h>
28#include <inttypes.h>
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32
33/* The main Dwarf file.  */
34static Dwarf *dwarf;
35
36int
37check_die (Dwarf_Die *die)
38{
39  if (dwarf_tag (die) == DW_TAG_invalid)
40    {
41      printf ("Invalid die\n");
42      return -1;
43    }
44
45  int res = 0;
46  void *addr = die->addr;
47  Dwarf_Die die2;
48  if (dwarf_die_addr_die (dwarf, addr, &die2) == NULL)
49    {
50      printf ("Bad die addr die at offset %" PRIx64 "\n",
51	      dwarf_dieoffset (die));
52      res = -1;
53    }
54
55  if (dwarf_tag (die) != dwarf_tag (&die2))
56    {
57      printf ("Tags differ for die at offset %" PRIx64 "\n",
58	      dwarf_dieoffset (die));
59      res = -1;
60    }
61
62  if (dwarf_cuoffset (die) != dwarf_cuoffset (&die2))
63    {
64      printf ("CU offsets differ for die at offset %" PRIx64 "\n",
65	      dwarf_dieoffset (die));
66      res = -1;
67    }
68
69  Dwarf_Die child;
70  if (dwarf_child (die, &child) == 0)
71    res |= check_die (&child);
72
73  Dwarf_Die sibling;
74  if (dwarf_siblingof (die, &sibling) == 0)
75    res |= check_die (&sibling);
76
77  return res;
78}
79
80int
81check_dbg (Dwarf *dbg)
82{
83  int res = 0;
84  Dwarf_Off off = 0;
85  Dwarf_Off old_off = 0;
86  size_t hsize;
87  Dwarf_Off abbrev;
88  uint8_t addresssize;
89  uint8_t offsetsize;
90  while (dwarf_nextcu (dbg, off, &off, &hsize, &abbrev, &addresssize,
91                       &offsetsize) == 0)
92    {
93      Dwarf_Die die;
94      if (dwarf_offdie (dbg, old_off + hsize, &die) != NULL)
95	{
96	  printf ("checking CU at %" PRIx64 "\n", old_off);
97	  res |= check_die (&die);
98	}
99
100      old_off = off;
101    }
102
103  // Same for type...
104  Dwarf_Half version;
105  uint64_t typesig;
106  Dwarf_Off typeoff;
107  off = 0;
108  old_off = 0;
109  while (dwarf_next_unit (dbg, off, &off, &hsize, &version, &abbrev,
110			  &addresssize, &offsetsize, &typesig, &typeoff) == 0)
111    {
112      Dwarf_Die die;
113      if (dwarf_offdie_types (dbg, old_off + hsize, &die) != NULL)
114	{
115	  printf ("checking TU at %" PRIx64 "\n", old_off);
116	  res |= check_die (&die);
117	}
118
119      // We should have seen this already, but double check...
120      if (dwarf_offdie_types (dbg, old_off + typeoff, &die) != NULL)
121	{
122	  printf ("checking Type DIE at %" PRIx64 "\n",
123		  old_off + hsize + typeoff);
124	  res |= check_die (&die);
125	}
126
127      old_off = off;
128    }
129
130  Dwarf *alt = dwarf_getalt (dbg);
131  if (alt != NULL)
132    {
133      printf ("checking alt debug\n");
134      res |= check_dbg (alt);
135    }
136
137  // Split or Type Dwarf_Dies gotten through dwarf_get_units.
138  Dwarf_CU *cu = NULL;
139  Dwarf_Die subdie;
140  uint8_t unit_type;
141  while (dwarf_get_units (dbg, cu, &cu, NULL,
142                          &unit_type, NULL, &subdie) == 0)
143    {
144      if (dwarf_tag (&subdie) != DW_TAG_invalid)
145        {
146	  printf ("checking %" PRIx8 " subdie\n", unit_type);
147	  res |= check_die (&subdie);
148	}
149    }
150
151  return res;
152}
153
154int
155main (int argc, char *argv[])
156{
157  if (argc < 2)
158    {
159      printf ("No file given.\n");
160      return -1;
161    }
162
163  const char *name = argv[1];
164  int fd = open (name, O_RDONLY);
165  if (fd < 0)
166    {
167      printf ("Cannot open '%s': %s\n", name, strerror (errno));
168      return -1;
169    }
170
171  dwarf = dwarf_begin (fd, DWARF_C_READ);
172  if (dwarf == NULL)
173    {
174      printf ("Not a Dwarf file '%s': %s\n", name, dwarf_errmsg (-1));
175      close (fd);
176      return -1;
177    }
178
179  printf ("checking %s\n", name);
180  int res = check_dbg (dwarf);
181
182  dwarf_end (dwarf);
183  close (fd);
184
185  return res;
186}
187