This introduces three new libdw functions dwarf_begin_type,
dwarf_begin_elf_type and dwarf_type.

When a file contained multiple types of DWARF, plain DWARF, DWO or
GNU_LTO, dwarf_begin and dwarf_begin_elf would use the plain DWARF
when available, otherwise use the DWO sections and finally the GNU_LTO
sections to construct a Dwarf handle. This meant that if a file
contained multiple types you would only be able to get one. And you
couldn't explicitly say you only wanted a Dwarf handle for a specific
type. Also you had no clear way of determining which type of Dwarf
handle you got.

The new dwarf_begin_type and dwarf_begin_elf_type allow explicitly
specifying a specific type of DWARF you want. And the dwarf_type
function will return the actual type of DWARF you got.

        * libdw/libdw.h (Dwarf_Type): New enum.
        (dwarf_begin_type): New function declaration.
        (dwarf_begin_elf_type): Likewise.
        (dwarf_get_type): Likewise.
        * libdw/libdw.map (ELFUTILS_0.196): New section with new
        function symbols based on ELFUTILS_0.194_EXPERIMENTAL.
        * libdw/libdwP.h (enum dwarf_type): Removed.
        (struct Dwarf): Make Dwarf_Type type.
        (INTDECL): dwarf_begin_elf_type, dwarf_begin_type,
        dwarf_get_type.
        * libdw/dwarf_begin.c (dwarf_begin): Rename to and make a
        wrapper around...
        (dwarf_begin_type): ... this new function.
        * libdw/dwarf_begin_elf.c (scn_dwarf_type): Return a
        Dwarf_Type.
        (check_section): Use Dwarf_Type instead of enum dwarf_type.
        (global_read): Add requested_type argument. Split in
        DWARF_T_AUTO case and specific type case.
        (scngrp_read): Likewise.
        (dwarf_begin_elf): Rename to and make a wrapper around..,
        (dwarf_begin_elf_type): ...     this new function.
        (dwarf_get_type): New function.
        * tests/Makefile.am (check_PROGRAMS): Add dwarf-type.
        (TESTS): Add run-dwarf-type.sh.
        (EXTRA_DIST): Likewise.
        (dwarf_type_LDADD): New.
        * tests/dwarf-type.c: New test.
        * tests/run-dwarf-type.sh: New test wrapper.

https://sourceware.org/bugzilla/show_bug.cgi?id=28573

Signed-off-by: Mark Wielaard <[email protected]>

Two remaining issues:

- Maybe we want a dedicated DWP type? Currently DWARF_T_DWO covers
  both single DWO and DWP/multi-DWO types. But this might not be a
  detail "real" users care about (only possibly useful for eu-dwp).

- Currently seeing a .debug_dwp section always assumes it is a dwo/dwp
  file, but it could be a plain DWARF file with a DWP reference. Need
  to actually inspect the .debug_dwp section to see which it is.
---
 libdw/dwarf_begin.c     |  12 +++-
 libdw/dwarf_begin_elf.c | 147 +++++++++++++++++++++++++++++++---------
 libdw/libdw.h           |  38 ++++++++++-
 libdw/libdw.map         |   7 ++
 libdw/libdwP.h          |  14 ++--
 tests/Makefile.am       |   4 ++
 tests/dwarf-type.c      |  84 +++++++++++++++++++++++
 tests/run-dwarf-type.sh |  53 +++++++++++++++
 8 files changed, 312 insertions(+), 47 deletions(-)
 create mode 100644 tests/dwarf-type.c
 create mode 100755 tests/run-dwarf-type.sh

diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c
index 19d16e5c511c..fbf1b0f05c90 100644
--- a/libdw/dwarf_begin.c
+++ b/libdw/dwarf_begin.c
@@ -1,5 +1,6 @@
 /* Create descriptor from file descriptor for processing file.
    Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
+   Copyright (C) 2026 Mark J. Wielaard <[email protected]>
    This file is part of elfutils.
    Written by Ulrich Drepper <[email protected]>, 2002.
 
@@ -39,7 +40,7 @@
 
 
 Dwarf *
-dwarf_begin (int fd, Dwarf_Cmd cmd)
+dwarf_begin_type (int fd, Dwarf_Cmd cmd, Dwarf_Type type)
 {
   Elf *elf;
   Elf_Cmd elfcmd;
@@ -85,7 +86,7 @@ dwarf_begin (int fd, Dwarf_Cmd cmd)
   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)
@@ -96,4 +97,11 @@ dwarf_begin (int fd, Dwarf_Cmd cmd)
 
   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)
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 7b58ad2e2218..5586ed66ec19 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -1,6 +1,6 @@
 /* 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 <[email protected]>
+   Copyright (C) 2023, 2026 Mark J. Wielaard <[email protected]>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -99,37 +99,37 @@ static const enum string_section_index 
scn_to_string_section_idx[IDX_last] =
   [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)
@@ -186,11 +186,11 @@ 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]);
@@ -217,7 +217,7 @@ check_section (Dwarf *result, size_t shstrndx, Elf_Scn 
*scn, bool inscngrp)
               && 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;
        }
     }
@@ -482,17 +482,44 @@ valid_p (Dwarf *result)
 
 
 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;
@@ -504,7 +531,8 @@ global_read (Dwarf *result, Elf *elf, size_t shstrndx)
 
 
 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);
@@ -541,24 +569,58 @@ scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, 
Elf_Scn *scngrp)
   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)
@@ -575,7 +637,8 @@ scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, 
Elf_Scn *scngrp)
 
 
 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;
@@ -644,9 +707,9 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
         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)
     {
@@ -661,4 +724,22 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
   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)
+
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 9096f301f6e3..bcd76138d717 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -1,5 +1,6 @@
 /* Interfaces for libdw.
    Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
+   Copyright (C) 2026 Mark J. Wielaard <[email protected]>
    This file is part of elfutils.
 
    This file is free software; you can redistribute it and/or modify
@@ -43,6 +44,19 @@ typedef enum
   }
 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
@@ -234,12 +248,32 @@ typedef void (*__noreturn_attribute__ Dwarf_OOM) (void);
 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);
 
diff --git a/libdw/libdw.map b/libdw/libdw.map
index b45647e6fa4c..404b4c1056a9 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -411,3 +411,10 @@ ELFUTILS_0.194_EXPERIMENTAL {
   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;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 628777b069da..8501337f4990 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -154,15 +154,6 @@ enum
 
 #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
@@ -257,7 +248,7 @@ 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
@@ -486,6 +477,8 @@ INTDECL (dwarf_attr)
 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)
@@ -508,6 +501,7 @@ INTDECL (dwarf_getaranges)
 INTDECL (dwarf_getlocation_die)
 INTDECL (dwarf_getsrcfiles)
 INTDECL (dwarf_getsrclines)
+INTDECL (dwarf_get_type)
 INTDECL (dwarf_get_units)
 INTDECL (dwarf_hasattr)
 INTDECL (dwarf_haschildren)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d3ecd35bbf42..4493f895ce10 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -58,6 +58,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames 
sectiondump \
                  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 \
@@ -211,6 +212,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile 
test-nlist \
        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 \
@@ -584,6 +586,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.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 \
@@ -893,6 +896,7 @@ fillfile_LDADD = $(libelf)
 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)
diff --git a/tests/dwarf-type.c b/tests/dwarf-type.c
new file mode 100644
index 000000000000..9fff663e2a90
--- /dev/null
+++ b/tests/dwarf-type.c
@@ -0,0 +1,84 @@
+/* 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;
+}
diff --git a/tests/run-dwarf-type.sh b/tests/run-dwarf-type.sh
new file mode 100755
index 000000000000..954d78519a4c
--- /dev/null
+++ b/tests/run-dwarf-type.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Copyright (C) 2026 Mark J. Wielaard <[email protected]>
+# 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
-- 
2.54.0

Reply via email to