--- /dev/null
+/* Iterate through the CU units for a given Dwarf.
+ Copyright (C) 2016, 2017 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#include "libdwP.h"
+
+int
+dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+{
+ Dwarf_Off off;
+ bool v4type;
+ if (cu == NULL)
+ {
+ off = 0;
+ v4type = false;
+ }
+ else
+ {
+ off = cu->end;
+ v4type = cu->sec_idx != IDX_debug_info;
+
+ /* Make sure we got a real (not fake) CU. */
+ if (cu->sec_idx != IDX_debug_info && cu->sec_idx != IDX_debug_types)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* Do we have to switch to the other section, or are we at the end? */
+ if (! v4type)
+ {
+ if (off >= cu->dbg->sectiondata[IDX_debug_info]->d_size)
+ {
+ if (cu->dbg->sectiondata[IDX_debug_types] == NULL)
+ return 1;
+
+ off = 0;
+ v4type = true;
+ }
+ }
+ else
+ if (off >= cu->dbg->sectiondata[IDX_debug_types]->d_size)
+ return 1;
+ }
+
+ *next_cu = __libdw_findcu (dwarf, off, v4type);
+ if (*next_cu == NULL)
+ return -1;
+
+ Dwarf_CU *next = (*next_cu);
+
+ if (version != NULL)
+ *version = next->version;
+
+ if (unit_type != NULL)
+ *unit_type = next->unit_type;
+
+ if (cudie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5
+ && next->unit_type >= DW_UT_compile
+ && next->unit_type <= DW_UT_split_type)
+ *cudie = CUDIE (next);
+ else
+ memset (cudie, '\0', sizeof (Dwarf_Die));
+ }
+
+ if (subdie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5
+ && (next->unit_type == DW_UT_type
+ || next->unit_type == DW_UT_split_type))
+ *subdie = SUBDIE(next);
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+
+ return 0;
+}
__nonnull_attribute__ (3);
+/* Gets the next Dwarf_CU (unit), version, unit type and if available
+ the CU DIE and sub (type) DIE of the unit. Returns 0 on success,
+ -1 on error or 1 if there are no more units. To start iterating
+ provide NULL for CU. If version < 5 the unit type is set from the
+ CU DIE if available (DW_UT_compile for DW_TAG_compile_unit,
+ DW_UT_type for DW_TAG_type_unit or DW_UT_partial for
+ DW_TAG_partial_unit), otherwise it is set to zero. If unavailable
+ (the version or unit type is unknown) the CU DIE is cleared.
+ Likewise ff the sub DIE isn't isn't available (the unit type is not
+ DW_UT_type or DW_UT_split_type) the sub DIE tag is cleared. */
+extern int dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+ __nonnull_attribute__ (3);
+
/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
The E_IDENT from the originating ELF file indicates the address
size and byte order used in the CFI section contained in DATA;
}
+static const char *
+dwarf_unit_string (unsigned int type)
+{
+ switch (type)
+ {
+#define DWARF_ONE_KNOWN_DW_UT(NAME, CODE) case CODE: return #NAME;
+ DWARF_ALL_KNOWN_DW_UT
+#undef DWARF_ONE_KNOWN_DW_UT
+ default:
+ return NULL;
+ }
+}
+
+
/* Used by all dwarf_foo_name functions. */
static const char *
string_or_unknown (const char *known, unsigned int code,
}
+static const char *
+dwarf_unit_name (unsigned int type)
+{
+ const char *ret = dwarf_unit_string (type);
+ return string_or_unknown (ret, type, DW_UT_lo_user, DW_UT_hi_user, true);
+}
+
+
static void
print_block (size_t n, const void *block)
{
int maxdies = 20;
Dwarf_Die *dies = (Dwarf_Die *) xmalloc (maxdies * sizeof (Dwarf_Die));
- Dwarf_Off offset = 0;
-
/* New compilation unit. */
- size_t cuhl;
Dwarf_Half version;
+
+ Dwarf_Die result;
Dwarf_Off abbroffset;
uint8_t addrsize;
uint8_t offsize;
- Dwarf_Off nextcu;
- uint64_t typesig;
- Dwarf_Off typeoff;
+ uint64_t unit_id;
+ Dwarf_Off subdie_off;
+
+ int unit_res;
+ Dwarf_CU *cu;
+ Dwarf_CU cu_mem;
+ uint8_t unit_type;
+ Dwarf_Die cudie;
+ Dwarf_Die subdie;
+
+ /* We cheat a little because we want to see only the CUs from .debug_info
+ or .debug_types. We know the Dwarf_CU struct layout. Set it up at
+ the end of .debug_info if we want .debug_types only. Check the returned
+ Dwarf_CU is still in the expected section. */
+ if (debug_types)
+ {
+ cu_mem.dbg = dbg;
+ cu_mem.end = dbg->sectiondata[IDX_debug_info]->d_size;
+ cu_mem.sec_idx = IDX_debug_info;
+ cu = &cu_mem;
+ }
+ else
+ cu = NULL;
+
next_cu:
- if (dwarf_next_unit (dbg, offset, &nextcu, &cuhl, &version,
- &abbroffset, &addrsize, &offsize,
- debug_types ? &typesig : NULL,
- debug_types ? &typeoff : NULL) != 0)
+ unit_res = dwarf_get_units (dbg, cu, &cu, &version, &unit_type,
+ &cudie, &subdie);
+ if (unit_res == 1)
+ goto do_return;
+
+ if (unit_res == -1)
+ {
+ if (!silent)
+ error (0, 0, gettext ("cannot get next unit: %s"), dwarf_errmsg (-1));
+ goto do_return;
+ }
+
+ if (cu->sec_idx != (size_t) (debug_types ? IDX_debug_types : IDX_debug_info))
goto do_return;
+ dwarf_cu_die (cu, &result, NULL, &abbroffset, &addrsize, &offsize,
+ &unit_id, &subdie_off);
+
if (!silent)
{
- if (debug_types)
+ Dwarf_Off offset = cu->start;
+ if (debug_types && version < 5)
printf (gettext (" Type unit at offset %" PRIu64 ":\n"
" Version: %" PRIu16 ", Abbreviation section offset: %"
PRIu64 ", Address size: %" PRIu8
", Offset size: %" PRIu8
"\n Type signature: %#" PRIx64
- ", Type offset: %#" PRIx64 "\n"),
+ ", Type offset: %#" PRIx64 " [%" PRIx64 "]\n"),
(uint64_t) offset, version, abbroffset, addrsize, offsize,
- typesig, (uint64_t) typeoff);
+ unit_id, (uint64_t) subdie_off, dwarf_dieoffset (&subdie));
else
- printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
- " Version: %" PRIu16 ", Abbreviation section offset: %"
- PRIu64 ", Address size: %" PRIu8
- ", Offset size: %" PRIu8 "\n"),
- (uint64_t) offset, version, abbroffset, addrsize, offsize);
+ {
+ printf (gettext (" Compilation unit at offset %" PRIu64 ":\n"
+ " Version: %" PRIu16
+ ", Abbreviation section offset: %" PRIu64
+ ", Address size: %" PRIu8
+ ", Offset size: %" PRIu8 "\n"),
+ (uint64_t) offset, version, abbroffset, addrsize, offsize);
+
+ if (version >= 5)
+ {
+ printf (gettext (" Unit type: %s (%" PRIu8 ")"),
+ dwarf_unit_name (unit_type), unit_type);
+ if (unit_type == DW_UT_type
+ || unit_type == DW_UT_skeleton
+ || unit_type == DW_UT_split_compile
+ || unit_type == DW_UT_split_type)
+ printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
+ if (unit_type == DW_UT_type
+ || unit_type == DW_UT_split_type)
+ printf (", Unit DIE off: %#" PRIx64 " [%" PRIx64 "]",
+ subdie_off, dwarf_dieoffset (&subdie));
+ printf ("\n");
+ }
+ }
+ }
+
+ if (version < 2 || version > 5
+ || unit_type < DW_UT_compile || unit_type > DW_UT_split_type)
+ {
+ if (!silent)
+ error (0, 0, gettext ("unknown version (%d) or unit type (%d)"),
+ version, unit_type);
+ goto next_cu;
}
struct attrcb_args args =
.offset_size = offsize
};
- offset += cuhl;
-
int level = 0;
-
- if (unlikely ((debug_types ? dwarf_offdie_types : dwarf_offdie)
- (dbg, offset, &dies[level]) == NULL))
- {
- if (!silent)
- error (0, 0, gettext ("cannot get DIE at offset %" PRIu64
- " in section '%s': %s"),
- (uint64_t) offset, secname, dwarf_errmsg (-1));
- goto do_return;
- }
-
+ dies[0] = cudie;
args.cu = dies[0].cu;
do
{
- offset = dwarf_dieoffset (&dies[level]);
+ Dwarf_Off offset = dwarf_dieoffset (&dies[level]);
if (unlikely (offset == ~0ul))
{
if (!silent)
}
while (level >= 0);
- offset = nextcu;
- if (offset != 0)
- goto next_cu;
+ /* And again... */
+ goto next_cu;
do_return:
free (dies);