public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
From: Mark Wielaard <mark@klomp.org>
To: Omar Sandoval <osandov@osandov.com>
Cc: elfutils-devel@sourceware.org
Subject: Re: [PATCH 10/14] libdw: Try .dwp file in __libdw_find_split_unit()
Date: Thu, 2 Nov 2023 20:56:14 +0100	[thread overview]
Message-ID: <20231102195614.GO8429@gnu.wildebeest.org> (raw)
In-Reply-To: <45e13e025847b8fb84cd8acfe66cae87961993d4.1695837512.git.osandov@fb.com>

Hi Omar,

On Wed, Sep 27, 2023 at 11:20:59AM -0700, Omar Sandoval wrote:
> Try opening the file in the location suggested by the standard (the
> skeleton file name + ".dwp") and looking up the unit in the package
> index.  The rest is similar to .dwo files, with slightly different
> cleanup since a single Dwarf handle is shared.

This seems a good default given it is what the standard says.
But do you know of any distro doing this?

The case I am wondering about is for separate .debug files (which
surprisingly isn't standardized). In that case this would be
foobar.debug.dwz (and not foobar.dwz).

It might also be an idea to just create one file with both the
skeletons and the .dwo and dwz index sections.
 
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>  libdw/ChangeLog                   | 11 ++++-
>  libdw/dwarf_begin_elf.c           |  1 +
>  libdw/dwarf_cu_dwp_section_info.c | 19 ++++++++
>  libdw/dwarf_end.c                 | 10 ++++-
>  libdw/libdwP.h                    | 16 ++++++-
>  libdw/libdw_find_split_unit.c     | 75 ++++++++++++++++++++++++++++---
>  6 files changed, 122 insertions(+), 10 deletions(-)
> 
> diff --git a/libdw/ChangeLog b/libdw/ChangeLog
> index f491587f..f37d9411 100644
> --- a/libdw/ChangeLog
> +++ b/libdw/ChangeLog
> @@ -1,6 +1,8 @@
>  2023-09-27  Omar Sandoval  <osandov@fb.com>
>  
>  	* libdw_find_split_unit.c (try_split_file): Make static.
> +	(try_dwp_file): New function.
> +	(__libdw_find_split_unit): Call try_dwp_file.
>  	* dwarf_entrypc.c (dwarf_entrypc): Call dwarf_lowpc.
>  	* dwarf_ranges.c (dwarf_ranges): Use skeleton ranges section for
>  	skeleton units.
> @@ -20,7 +22,8 @@
>  	instead of dbg parameter, which is now unused.
>  	* libdwP.h (Dwarf_Macro_Op_Table): Replace is_64bit with address_size
>  	and offset_size.  Add dbg.
> -	(Dwarf): Add cu_index and tu_index.  Add elfpath.
> +	(Dwarf): Add cu_index and tu_index.  Add elfpath.  Add dwp_dwarf and
> +	dwp_fd.
>  	(Dwarf_CU): Add dwp_row.
>  	(Dwarf_Package_Index): New type.
>  	(DW_SECT_TYPES): New macro.
> @@ -31,6 +34,8 @@
>  	(__libdw_debugdir): Replace declaration with...
>  	(__libdw_elfpath): New declaration.
>  	(__libdw_set_debugdir): New declaration.
> +	(__libdw_dwp_findcu_id): New declaration.
> +	(__libdw_link_skel_split): Handle .debug_addr for dwp.
>  	* dwarf_begin_elf.c (dwarf_scnnames): Add IDX_debug_cu_index and
>  	IDX_debug_tu_index.
>  	(scn_to_string_section_idx): Ditto.
> @@ -43,9 +48,11 @@
>  	(__libdw_set_debugdir): New function.
>  	(valid_p): Call __libdw_elfpath and __libdw_set_debugdir instead of
>  	__libdw_debugdir.
> +	(dwarf_begin_elf): Initialize result->dwp_fd.
>  	* Makefile.am (libdw_a_SOURCES): Add dwarf_cu_dwp_section_info.c.
>  	* dwarf_end.c (dwarf_end): Free dwarf->cu_index and dwarf->tu_index.
> -	Free dwarf->elfpath.
> +	Free dwarf->elfpath.  Free dwarf->dwp_dwarf and close dwarf->dwp_fd.
> +	(cu_free): Don't free split dbg if it is dwp_dwarf.
>  	* dwarf_error.c (errmsgs): Add DWARF_E_UNKNOWN_SECTION.
>  	* libdw.h (dwarf_cu_dwp_section_info): New declaration.
>  	* libdw.map (ELFUTILS_0.190): Add dwarf_cu_dwp_section_info.
> diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
> index 323a91d0..ca2b7e2a 100644
> --- a/libdw/dwarf_begin_elf.c
> +++ b/libdw/dwarf_begin_elf.c
> @@ -567,6 +567,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
>  
>    result->elf = elf;
>    result->alt_fd = -1;
> +  result->dwp_fd = -1;
>  
>    /* Initialize the memory handling.  Initial blocks are allocated on first
>       actual allocation.  */
> diff --git a/libdw/dwarf_cu_dwp_section_info.c b/libdw/dwarf_cu_dwp_section_info.c
> index 6766fb9a..7bf08d9d 100644
> --- a/libdw/dwarf_cu_dwp_section_info.c
> +++ b/libdw/dwarf_cu_dwp_section_info.c
> @@ -340,6 +340,25 @@ __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off,
>  				   abbrev_offsetp, NULL);
>  }
>  
> +Dwarf_CU *
> +internal_function
> +__libdw_dwp_findcu_id (Dwarf *dbg, uint64_t unit_id8)
> +{
> +  Dwarf_Package_Index *index = __libdw_package_index (dbg, false);
> +  uint32_t unit_row;
> +  Dwarf_Off offset;
> +  Dwarf_CU *cu;
> +  if (__libdw_dwp_unit_row (index, unit_id8, &unit_row) == 0
> +      && __libdw_dwp_section_info (index, unit_row, DW_SECT_INFO, &offset,
> +				   NULL) == 0
> +      && (cu = __libdw_findcu (dbg, offset, false)) != NULL
> +      && cu->unit_type == DW_UT_split_compile
> +      && cu->unit_id8 == unit_id8)
> +    return cu;
> +  else
> +    return NULL;
> +}

No lookup for split_type?

>  int
>  dwarf_cu_dwp_section_info (Dwarf_CU *cu, unsigned int section,
>  			   Dwarf_Off *offsetp, Dwarf_Off *sizep)
> diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
> index b7f817d9..78224ddb 100644
> --- a/libdw/dwarf_end.c
> +++ b/libdw/dwarf_end.c
> @@ -66,7 +66,9 @@ cu_free (void *arg)
>  	  /* The fake_addr_cu might be shared, only release one.  */
>  	  if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
>  	    p->split->dbg->fake_addr_cu = NULL;
> -	  INTUSE(dwarf_end) (p->split->dbg);
> +	  /* There is only one DWP file. We free it later.  */
> +	  if (p->split->dbg != p->dbg->dwp_dwarf)
> +	    INTUSE(dwarf_end) (p->split->dbg);
>  	}
>      }
>  }
> @@ -147,6 +149,12 @@ dwarf_end (Dwarf *dwarf)
>  	  close (dwarf->alt_fd);
>  	}
>  
> +      if (dwarf->dwp_fd != -1)
> +	{
> +	  INTUSE(dwarf_end) (dwarf->dwp_dwarf);
> +	  close (dwarf->dwp_fd);
> +	}
> +
>        /* The cached path and dir we found the Dwarf ELF file in.  */
>        free (dwarf->elfpath);
>        free (dwarf->debugdir);

OK

> diff --git a/libdw/libdwP.h b/libdw/libdwP.h
> index 214d1711..16355274 100644
> --- a/libdw/libdwP.h
> +++ b/libdw/libdwP.h
> @@ -180,6 +180,9 @@ struct Dwarf
>    /* dwz alternate DWARF file.  */
>    Dwarf *alt_dwarf;
>  
> +  /* DWARF package file.  */
> +  Dwarf *dwp_dwarf;
> +
>    /* The section data.  */
>    Elf_Data *sectiondata[IDX_last];
>  
> @@ -197,6 +200,9 @@ struct Dwarf
>       close this file descriptor.  */
>    int alt_fd;
>  
> +  /* File descriptor of DWARF package file.  */
> +  int dwp_fd;
> +
>    /* Information for traversing the .debug_pubnames section.  This is
>       an array and separately allocated with malloc.  */
>    struct pubnames_s
> @@ -719,6 +725,10 @@ extern int __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off,
>  				  Dwarf_Off *abbrev_offsetp)
>       __nonnull_attribute__ (1, 7, 8) internal_function;
>  
> +/* Find the compilation unit in a DWARF package file with the given id.  */
> +extern Dwarf_CU *__libdw_dwp_findcu_id (Dwarf *dbg, uint64_t unit_id8)
> +     __nonnull_attribute__ (1) internal_function;
> +
>  /* Get abbreviation with given code.  */
>  extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
>  					 unsigned int code)

OK.

> @@ -1373,8 +1383,10 @@ __libdw_link_skel_split (Dwarf_CU *skel, Dwarf_CU *split)
>       There is only one per split debug.  */
>    Dwarf *dbg = skel->dbg;
>    Dwarf *sdbg = split->dbg;
> -  if (sdbg->sectiondata[IDX_debug_addr] == NULL
> -      && dbg->sectiondata[IDX_debug_addr] != NULL)
> +  if (dbg->sectiondata[IDX_debug_addr] != NULL
> +      && (sdbg->sectiondata[IDX_debug_addr] == NULL
> +	  || (sdbg->sectiondata[IDX_debug_addr]
> +	      == dbg->sectiondata[IDX_debug_addr])))
>      {
>        sdbg->sectiondata[IDX_debug_addr]
>  	= dbg->sectiondata[IDX_debug_addr];

ehe? What exactly are we checking here?

> diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
> index 533f8072..e1e78951 100644
> --- a/libdw/libdw_find_split_unit.c
> +++ b/libdw/libdw_find_split_unit.c
> @@ -85,6 +85,67 @@ try_split_file (Dwarf_CU *cu, const char *dwo_path)
>      }
>  }
>  
> +static void
> +try_dwp_file (Dwarf_CU *cu)
> +{
> +  if (cu->dbg->dwp_dwarf == NULL)
> +    {
> +      if (cu->dbg->elfpath != NULL)
> +	{
> +	  /* The DWARF 5 standard says "the package file is typically placed in
> +	     the same directory as the application, and is given the same name
> +	     with a '.dwp' extension".  */
> +	  size_t elfpath_len = strlen (cu->dbg->elfpath);
> +	  char *dwp_path = malloc (elfpath_len + 5);
> +	  if (dwp_path == NULL)
> +	    {
> +	      __libdw_seterrno (DWARF_E_NOMEM);
> +	      return;
> +	    }

Yes, but the caller doesn't check for errors. So the seterrno is not
very useful.

> +	  memcpy (dwp_path, cu->dbg->elfpath, elfpath_len);
> +	  strcpy (dwp_path + elfpath_len, ".dwp");
> +	  int dwp_fd = open (dwp_path, O_RDONLY);
> +	  free (dwp_path);
> +	  if (dwp_fd != -1)
> +	    {
> +	      Dwarf *dwp_dwarf = dwarf_begin (dwp_fd, DWARF_C_READ);
> +	      /* There's no way to know whether we got the correct file until
> +		 we look up the unit, but it should at least be a dwp file.  */
> +	      if (dwp_dwarf != NULL
> +		  && (dwp_dwarf->sectiondata[IDX_debug_cu_index] != NULL
> +		      || dwp_dwarf->sectiondata[IDX_debug_tu_index] != NULL))
> +		{
> +		  cu->dbg->dwp_dwarf = dwp_dwarf;
> +		  cu->dbg->dwp_fd = dwp_fd;
> +		}
> +	      else
> +		close (dwp_fd);
> +	    }
> +	}
> +      if (cu->dbg->dwp_dwarf == NULL)
> +	cu->dbg->dwp_dwarf = (Dwarf *) -1;
> +    }
> +
> +  if (cu->dbg->dwp_dwarf != (Dwarf *) -1)
> +    {
> +      Dwarf_CU *split = __libdw_dwp_findcu_id (cu->dbg->dwp_dwarf,
> +					       cu->unit_id8);
> +      if (split != NULL)
> +	{
> +	  if (tsearch (split->dbg, &cu->dbg->split_tree,
> +		       __libdw_finddbg_cb) == NULL)
> +	    {
> +	      /* Something went wrong.  Don't link.  */
> +	      __libdw_seterrno (DWARF_E_NOMEM);
> +	      return;
> +	    }

Same as above.

> +	  /* Link skeleton and split compile units.  */
> +	  __libdw_link_skel_split (cu, split);
> +	}
> +    }
> +}

OK.

>  Dwarf_CU *
>  internal_function
>  __libdw_find_split_unit (Dwarf_CU *cu)
> @@ -98,14 +159,18 @@ __libdw_find_split_unit (Dwarf_CU *cu)
>       same id as the skeleton.  */
>    if (cu->unit_type == DW_UT_skeleton)
>      {
> +      /* First, try the dwp file.  */
> +      try_dwp_file (cu);
> +
>        Dwarf_Die cudie = CUDIE (cu);
>        Dwarf_Attribute dwo_name;
> -      /* It is fine if dwo_dir doesn't exists, but then dwo_name needs
> -	 to be an absolute path.  */
> -      if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
> -	  || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL)
> +      /* Try a dwo file.  It is fine if dwo_dir doesn't exist, but then
> +	 dwo_name needs to be an absolute path.  */
> +      if (cu->split == (Dwarf_CU *) -1
> +	  && (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
> +	      || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL))
>  	{
> -	  /* First try the dwo file name in the same directory
> +	  /* Try the dwo file name in the same directory
>  	     as we found the skeleton file.  */
>  	  const char *dwo_file = dwarf_formstring (&dwo_name);
>  	  const char *debugdir = cu->dbg->debugdir;

OK. Because try_dwp_file will call __libdw_link_skel_split to set
cu->split.

This again will have to be analyzed carefully when we add the
thread-safety work.

Thanks,

Mark

  reply	other threads:[~2023-11-02 19:56 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-09-27 18:20 [PATCH 00/14] elfutils: DWARF package (.dwp) file support Omar Sandoval
2023-09-27 18:20 ` [PATCH 01/14] libdw: Make try_split_file static Omar Sandoval
2023-10-03 16:09   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 02/14] libdw: Handle split DWARF in dwarf_entrypc Omar Sandoval
2023-10-03 16:10   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 03/14] libdw: Handle DW_AT_ranges in split DWARF 5 skeleton in dwarf_ranges Omar Sandoval
2023-10-03 16:10   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 04/14] libdw: Handle other string forms in dwarf_macro_param2 Omar Sandoval
2023-10-03 16:11   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 05/14] libdw: Fix dwarf_macro_getsrcfiles for DWARF 5 Omar Sandoval
2023-10-03 21:29   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 06/14] libdw: Handle split DWARF in dwarf_macro_getsrcfiles Omar Sandoval
2023-10-03 21:49   ` Mark Wielaard
2023-09-27 18:20 ` [PATCH 07/14] libdw: Recognize .debug_[ct]u_index sections in dwarf_elf_begin Omar Sandoval
2023-11-01 14:03   ` Mark Wielaard
2023-11-01 17:30     ` Omar Sandoval
2023-09-27 18:20 ` [PATCH 08/14] libdw: Parse DWARF package file index sections Omar Sandoval
2023-11-01 23:07   ` Mark Wielaard
2023-11-07  6:45     ` Omar Sandoval
2023-09-27 18:20 ` [PATCH 09/14] libdw, libdwfl: Save original path of ELF file Omar Sandoval
2023-11-02 17:04   ` Mark Wielaard
2023-11-07  6:46     ` Omar Sandoval
2023-09-27 18:20 ` [PATCH 10/14] libdw: Try .dwp file in __libdw_find_split_unit() Omar Sandoval
2023-11-02 19:56   ` Mark Wielaard [this message]
2023-11-07  7:07     ` Omar Sandoval
2023-09-27 18:21 ` [PATCH 11/14] tests: Handle DW_MACRO_{define,undef}_{strx,sup} in dwarf-getmacros Omar Sandoval
2023-11-02 20:30   ` [PATCH 11/14] tests: Handle DW_MACRO_{define, undef}_{strx, sup} " Mark Wielaard
2023-09-27 18:21 ` [PATCH 12/14] tests: Optionally dump all units " Omar Sandoval
2023-11-02 20:39   ` Mark Wielaard
2023-09-27 18:21 ` [PATCH 13/14] libdw: Apply DWARF package file section offsets where appropriate Omar Sandoval
2023-11-02 22:20   ` Mark Wielaard
2023-11-07 16:55     ` Omar Sandoval
2023-09-27 18:21 ` [PATCH 14/14] libdw: Handle overflowed DW_SECT_INFO offsets in DWARF package file indexes Omar Sandoval
2023-09-27 19:20 ` [PATCH 00/14] elfutils: DWARF package (.dwp) file support Frank Ch. Eigler
2023-09-27 20:17   ` Omar Sandoval
2023-10-03 21:54 ` Mark Wielaard
2023-11-02 23:05 ` Mark Wielaard
2023-11-07 17:13   ` Omar Sandoval

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231102195614.GO8429@gnu.wildebeest.org \
    --to=mark@klomp.org \
    --cc=elfutils-devel@sourceware.org \
    --cc=osandov@osandov.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).