Hi Mark,

On Wed, Jul 1, 2026 at 8:01 AM Mark Wielaard <[email protected]> wrote:
>
> 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).

I'm leaning towards not adding a DWP type because libdw already
transparently handles DWP. I can't think of anything that a typical
(non-eu-dwp) user would need a DWO/DWP type distinction for. And even
if this distinction ends up being important one can always check for
.debug_{cu,tu}_index.

>
> - 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).  */

If we don't plan on ever adding a DWP type, this comment could be
expanded to mention that DWARF_T_DWO includes DWP.

> +    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;

Should ELFUTILS_0.196 chain on to ELFUTILS_0.193 instead? It's the
last non-experimental node. The idea of the experimental nodes was to
keep them separate from the official branch in case we want to remove
them. Although due to RHEL's ABI guarantees full removal may not
happen in any case.

> 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)

This should be `argc < 3`.

Aaron

> +    {
> +      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