/* Create descriptor from file descriptor for processing file.
Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
+ Copyright (C) 2026 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
Dwarf *
-dwarf_begin (int fd, Dwarf_Cmd cmd)
+dwarf_begin_type (int fd, Dwarf_Cmd cmd, Dwarf_Type type)
{
Elf *elf;
Elf_Cmd elfcmd;
else
{
/* Do the real work now that we have an ELF descriptor. */
- result = INTUSE(dwarf_begin_elf) (elf, cmd, NULL);
+ result = INTUSE(dwarf_begin_elf_type) (elf, cmd, type, NULL);
/* If this failed, free the resources. */
if (result == NULL)
return result;
}
+INTDEF(dwarf_begin_type)
+
+Dwarf *
+dwarf_begin (int fd, Dwarf_Cmd cmd)
+{
+ return INTUSE(dwarf_begin_type) (fd, cmd, DWARF_T_AUTO);
+}
INTDEF(dwarf_begin)
/* Create descriptor from ELF descriptor for processing file.
Copyright (C) 2002-2011, 2014, 2015, 2017, 2018 Red Hat, Inc.
- Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org>
+ Copyright (C) 2023, 2026 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
[IDX_gnu_debugaltlink] = STR_SCN_IDX_last
};
-static enum dwarf_type
+static Dwarf_Type
scn_dwarf_type (Dwarf *result, size_t shstrndx, Elf_Scn *scn)
{
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr == NULL)
- return TYPE_UNKNOWN;
+ return DWARF_T_AUTO;
const char *scnname = elf_strptr (result->elf, shstrndx,
shdr->sh_name);
if (scnname != NULL)
{
if (startswith (scnname, ".gnu.debuglto_.debug"))
- return TYPE_GNU_LTO;
+ return DWARF_T_GNU_LTO;
else if (strcmp (scnname, ".debug_cu_index") == 0
|| strcmp (scnname, ".debug_tu_index") == 0
|| strcmp (scnname, ".debug_dwp") == 0
|| strcmp (scnname, ".zdebug_cu_index") == 0
|| strcmp (scnname, ".zdebug_tu_index") == 0
|| strcmp (scnname, ".zdebug_dwp") == 0)
- return TYPE_DWO;
+ return DWARF_T_DWO;
else if (startswith (scnname, ".debug_") || startswith (scnname, ".zdebug_"))
{
size_t len = strlen (scnname);
if (strcmp (scnname + len - 4, ".dwo") == 0)
- return TYPE_DWO;
+ return DWARF_T_DWO;
else
- return TYPE_PLAIN;
+ return DWARF_T_PLAIN;
}
}
- return TYPE_UNKNOWN;
+ return DWARF_T_AUTO;
}
static Dwarf *
check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp)
{
/* .debug_cu_index and .debug_tu_index don't have a .dwo suffix,
but they are for DWO. */
- if (result->type != TYPE_DWO
+ if (result->type != DWARF_T_DWO
&& (cnt == IDX_debug_cu_index || cnt == IDX_debug_tu_index))
continue;
bool need_dot_dwo =
- (result->type == TYPE_DWO
+ (result->type == DWARF_T_DWO
&& cnt != IDX_debug_cu_index
&& cnt != IDX_debug_tu_index);
size_t dbglen = strlen (dwarf_scnnames[cnt]);
&& startswith (scnname, ".gnu.debuglto_")
&& strcmp (&scnname[14], dwarf_scnnames[cnt]) == 0)
{
- if (result->type == TYPE_GNU_LTO)
+ if (result->type == DWARF_T_GNU_LTO)
break;
}
}
static Dwarf *
-global_read (Dwarf *result, Elf *elf, size_t shstrndx)
+global_read (Dwarf *result, Elf *elf, size_t shstrndx,
+ Dwarf_Type requested_type)
{
Elf_Scn *scn = NULL;
- /* First check the type (PLAIN, DWO, LTO) we are looking for. We
- prefer PLAIN if available over DWO, over LTO. */
- while ((scn = elf_nextscn (elf, scn)) != NULL && result->type != TYPE_PLAIN)
+ if (requested_type == DWARF_T_AUTO)
{
- enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn);
- if (type > result->type)
- result->type = type;
+ /* First check the type (PLAIN, DWO, LTO) we are looking for. We
+ prefer PLAIN if available over DWO, over LTO. */
+ while ((scn = elf_nextscn (elf, scn)) != NULL
+ && result->type != DWARF_T_PLAIN)
+ {
+ Dwarf_Type type = scn_dwarf_type (result, shstrndx, scn);
+ if (type > result->type)
+ result->type = type;
+ }
+ }
+ else
+ {
+ /* Check there is at least one section of the requested type. */
+ bool found = false;
+ while ((scn = elf_nextscn (elf, scn)) != NULL && !found)
+ {
+ Dwarf_Type type = scn_dwarf_type (result, shstrndx, scn);
+ if (type == requested_type)
+ found = true;
+ }
+
+ if (!found)
+ {
+ /* Requested type not available. */
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_NO_DWARF);
+ free (result);
+ return NULL;
+ }
+
+ result->type = requested_type;
}
scn = NULL;
static Dwarf *
-scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, Elf_Scn *scngrp)
+scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx,
+ Dwarf_Type requested_type, Elf_Scn *scngrp)
{
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scngrp, &shdr_mem);
Elf32_Word *scnidx = (Elf32_Word *) data->d_buf;
size_t cnt;
- /* First check the type (PLAIN, DWO, LTO) we are looking for. We
- prefer PLAIN if available over DWO, over LTO. */
- for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt)
+ if (requested_type == DWARF_T_AUTO)
{
- Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]);
- if (scn == NULL)
+ /* First check the type (PLAIN, DWO, LTO) we are looking for. We
+ prefer PLAIN if available over DWO, over LTO. */
+ for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt)
{
- /* A section group refers to a non-existing section. Should
- never happen. */
+ Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]);
+ if (scn == NULL)
+ {
+ /* A section group refers to a non-existing section. Should
+ never happen. */
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_INVALID_ELF);
+ free (result);
+ return NULL;
+ }
+
+ Dwarf_Type type = scn_dwarf_type (result, shstrndx, scn);
+ if (type > result->type)
+ result->type = type;
+ }
+ }
+ else
+ {
+ /* Check there is at least one section of the requested type. */
+ bool found = false;
+ for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size && !found; ++cnt)
+ {
+ Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]);
+ if (scn == NULL)
+ {
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_INVALID_ELF);
+ free (result);
+ return NULL;
+ }
+
+ Dwarf_Type type = scn_dwarf_type (result, shstrndx, scn);
+ if (type == requested_type)
+ found = true;
+ }
+
+ if (!found)
+ {
+ /* Requested type not available. */
Dwarf_Sig8_Hash_free (&result->sig8_hash);
- __libdw_seterrno (DWARF_E_INVALID_ELF);
+ __libdw_seterrno (DWARF_E_NO_DWARF);
free (result);
return NULL;
}
- enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn);
- if (type > result->type)
- result->type = type;
+ result->type = requested_type;
}
for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size && result != NULL; ++cnt)
Dwarf *
-dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
+dwarf_begin_elf_type (Elf *elf, Dwarf_Cmd cmd, Dwarf_Type type,
+ Elf_Scn *scngrp)
{
GElf_Ehdr *ehdr;
GElf_Ehdr ehdr_mem;
sections with the name are ignored. The DWARF specification
does not really say this is allowed. */
if (scngrp == NULL)
- return global_read (result, elf, shstrndx);
+ return global_read (result, elf, shstrndx, type);
else
- return scngrp_read (result, elf, shstrndx, scngrp);
+ return scngrp_read (result, elf, shstrndx, type, scngrp);
}
else if (cmd == DWARF_C_WRITE)
{
free (result);
return NULL;
}
+INTDEF(dwarf_begin_elf_type)
+
+Dwarf *
+dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
+{
+ return dwarf_begin_elf_type (elf, cmd, DWARF_T_AUTO, scngrp);
+}
INTDEF(dwarf_begin_elf)
+
+Dwarf_Type
+dwarf_get_type (Dwarf *dwarf)
+{
+ if (dwarf == NULL)
+ return DWARF_T_AUTO;
+
+ return dwarf->type;
+}
+INTDEF(dwarf_get_type)
+
/* Interfaces for libdw.
Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
+ Copyright (C) 2026 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
}
Dwarf_Cmd;
+/* DWARF type. Either plain DWARF, split DWARF DWOs or GNU LTO. When
+ used with dwarf_begin_type or dwarf_begin_elf_type DWARF_T_AUTO
+ tries to get PLAIN, DWO, GNU_LTO in that order. Enum values have a
+ numeric value indicating their priority in auto mode. */
+typedef enum
+ {
+ DWARF_T_AUTO = 0, /* Automatic selection (PLAIN > DWO > GNU_LTO). */
+ DWARF_T_GNU_LTO = 16, /* GNU LTO (.gnu.debuglto_.debug_*). */
+ DWARF_T_DWO = 32, /* Split DWARF (.debug_*.dwo). */
+ DWARF_T_PLAIN = 64, /* Standard DWARF (.debug_*). */
+ }
+Dwarf_Type;
+
/* Callback results. */
enum
extern "C" {
#endif
-/* Create a handle for a new debug session. */
+/* Create a handle for a new debug session.
+ Calls dwarf_begin_type (fildes, cmd, DWARF_T_AUTO). */
extern Dwarf *dwarf_begin (int fildes, Dwarf_Cmd cmd);
-/* Create a handle for a new debug session for an ELF file. */
+/* Create a handle for a new debug session given a specific type.
+ When type is DWARF_T_AUTO will try to get PLAIN, DWO, GNU_LTO in
+ that order. Will return NULL if the requested type is not available
+ in the file. */
+extern Dwarf *dwarf_begin_type (int fildes, Dwarf_Cmd cmd, Dwarf_Type type);
+
+/* Create a handle for a new debug session for an ELF file.
+ Calls dwarf_begin_type (elf, cmd, DWARF_T_AUTO, scngrp). */
extern Dwarf *dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp);
+/* Create a handle for a new debug session given a specific type.
+ When type is DWARF_T_AUTO will try to get PLAIN, DWO, GNU_LTO in
+ that order. Will return NULL if the requested type is not available
+ in the file. If scngrp isn't NULL it must be a SHT_GROUP section
+ and only sections in this group will be used. */
+extern Dwarf *dwarf_begin_elf_type (Elf *elf, Dwarf_Cmd cmd, Dwarf_Type type,
+ Elf_Scn *scngrp);
+
+/* Returns the DWARF type of the givn Dwarf descriptor. Return
+ DWARF_T_AUTO (zero) if the descriptor is NULL. */
+extern Dwarf_Type dwarf_get_type (Dwarf *dwarf);
+
/* Retrieve ELF descriptor used for DWARF access. */
extern Elf *dwarf_getelf (Dwarf *dwarf);
global:
dwflst_sample_getframes;
} ELFUTILS_0.193_EXPERIMENTAL;
+
+ELFUTILS_0.196 {
+ global:
+ dwarf_begin_elf_type;
+ dwarf_begin_type;
+ dwarf_get_type;
+} ELFUTILS_0.194_EXPERIMENTAL;
#include "dwarf_sig8_hash.h"
-/* The type of Dwarf object, sorted by preference
- (if there is a higher order type, we pick that one over the others). */
-enum dwarf_type
- {
- TYPE_UNKNOWN = 0,
- TYPE_GNU_LTO = 16,
- TYPE_DWO = 32,
- TYPE_PLAIN = 64,
- };
/* This is the structure representing the debugging state. */
struct Dwarf
/* Similar for addrx/constx, which will come from .debug_addr section. */
struct Dwarf_CU *fake_addr_cu;
- enum dwarf_type type;
+ Dwarf_Type type;
/* Supporting lock for internal memory handling. Ensures threads that have
an entry in the mem_tails array are not disturbed by new threads doing
INTDECL (dwarf_attr_integrate)
INTDECL (dwarf_begin)
INTDECL (dwarf_begin_elf)
+INTDECL (dwarf_begin_elf_type)
+INTDECL (dwarf_begin_type)
INTDECL (dwarf_child)
INTDECL (dwarf_cu_dwp_section_info)
INTDECL (dwarf_default_lower_bound)
INTDECL (dwarf_getlocation_die)
INTDECL (dwarf_getsrcfiles)
INTDECL (dwarf_getsrclines)
+INTDECL (dwarf_get_type)
INTDECL (dwarf_get_units)
INTDECL (dwarf_hasattr)
INTDECL (dwarf_haschildren)
elfgetzdata elfputzdata zstrptr emptyfile vendorelf \
fillfile dwarf_default_lower_bound \
dwarf_language_lower_bound dwarf-die-addr-die \
+ dwarf-type \
get-units-invalid get-units-split attr-integrate-skel \
all-dwarf-ranges unit-info next_cfi \
elfcopy addsections xlate_notes elfrdwrnop \
emptyfile vendorelf fillfile dwarf_default_lower_bound \
dwarf_language_lower_bound \
run-dwarf-die-addr-die.sh \
+ run-dwarf-type.sh \
run-get-units-invalid.sh run-get-units-split.sh \
run-attr-integrate-skel.sh \
run-all-dwarf-ranges.sh run-unit-info.sh \
testfile-bpf-reloc.expect.bz2 testfile-bpf-reloc.o.bz2 \
testfile-m68k-core.bz2 testfile-m68k.bz2 testfile-m68k-s.bz2 \
run-dwarf-die-addr-die.sh \
+ run-dwarf-type.sh \
run-get-units-invalid.sh run-get-units-split.sh \
testfile-hello4.dwo.bz2 testfile-hello5.dwo.bz2 \
testfile-splitdwarf-4.bz2 testfile-splitdwarf-5.bz2 \
dwarf_default_lower_bound_LDADD = $(libdw)
dwarf_language_lower_bound_LDADD = $(libdw)
dwarf_die_addr_die_LDADD = $(libdw)
+dwarf_type_LDADD = $(libdw)
get_units_invalid_LDADD = $(libdw)
get_units_split_LDADD = $(libdw)
attr_integrate_skel_LDADD = $(libdw)
--- /dev/null
+/* Test dwarf_begin_type and dwarf_get_type functionality.
+ Copyright (C) 2024 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 the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 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 a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <dwarf.h>
+#include <libdw.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static const char *
+type_name (Dwarf_Type type)
+{
+ switch (type)
+ {
+ case DWARF_T_AUTO: return "AUTO";
+ case DWARF_T_PLAIN: return "PLAIN";
+ case DWARF_T_DWO: return "DWO";
+ case DWARF_T_GNU_LTO: return "GNU_LTO";
+ default: return "UNKNOWN";
+ }
+}
+
+Dwarf_Type
+name_type (const char *name)
+{
+ if (strcmp (name, "AUTO") == 0)
+ return DWARF_T_AUTO;
+ else if (strcmp (name, "PLAIN") == 0)
+ return DWARF_T_PLAIN;
+ else if (strcmp (name, "DWO") == 0)
+ return DWARF_T_DWO;
+ else if (strcmp (name, "GNU_LTO") == 0)
+ return DWARF_T_GNU_LTO;
+ else
+ {
+ printf ("Unknown type name: %s\n", name);
+ exit (1);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ fprintf (stderr, "Need <type> and <testfile>\n");
+ return 1;
+ }
+
+ const char *tname = argv[1];
+ const char *file = argv[2];
+ Dwarf_Type type = name_type (tname);
+
+ int fd = open (file, O_RDONLY);
+ if (fd < 0)
+ {
+ printf ("Cannot open %s\n", file);
+ return 1;
+ }
+
+ Dwarf *dbg = dwarf_begin_type (fd, DWARF_C_READ, type);
+ Dwarf_Type dwarf_type = dwarf_get_type (dbg);
+ printf ("%s: %s -> %s\n", file, type_name (type), type_name (dwarf_type));
+ dwarf_end (dbg);
+ close (fd);
+ return 0;
+}
--- /dev/null
+#!/bin/sh
+# Copyright (C) 2026 Mark J. Wielaard <mark@klomp.org>
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# Test dwarf_begin_type and dwarf_get_type with fat LTO file
+# (file with both PLAIN and GNU_LTO sections)
+testfiles testfile-dwarf5-fat-lto.o
+
+testrun_compare ${abs_builddir}/dwarf-type AUTO testfile-dwarf5-fat-lto.o <<\EOF
+testfile-dwarf5-fat-lto.o: AUTO -> PLAIN
+EOF
+testrun_compare ${abs_builddir}/dwarf-type PLAIN testfile-dwarf5-fat-lto.o <<\EOF
+testfile-dwarf5-fat-lto.o: PLAIN -> PLAIN
+EOF
+testrun_compare ${abs_builddir}/dwarf-type DWO testfile-dwarf5-fat-lto.o <<\EOF
+testfile-dwarf5-fat-lto.o: DWO -> AUTO
+EOF
+testrun_compare ${abs_builddir}/dwarf-type GNU_LTO testfile-dwarf5-fat-lto.o <<\EOF
+testfile-dwarf5-fat-lto.o: GNU_LTO -> GNU_LTO
+EOF
+
+# Test dwarf_begin_type and dwarf_get_type with DWO (only) file
+testfiles testfile-hello5.dwo
+
+testrun_compare ${abs_builddir}/dwarf-type AUTO testfile-hello5.dwo <<\EOF
+testfile-hello5.dwo: AUTO -> DWO
+EOF
+testrun_compare ${abs_builddir}/dwarf-type PLAIN testfile-hello5.dwo <<\EOF
+testfile-hello5.dwo: PLAIN -> AUTO
+EOF
+testrun_compare ${abs_builddir}/dwarf-type DWO testfile-hello5.dwo <<\EOF
+testfile-hello5.dwo: DWO -> DWO
+EOF
+testrun_compare ${abs_builddir}/dwarf-type GNU_LTO testfile-hello5.dwo <<\EOF
+testfile-hello5.dwo: GNU_LTO -> AUTO
+EOF
+
+exit 0