public inbox for dwz@sourceware.org
 help / color / mirror / Atom feed
From: Mark Wielaard <mark@klomp.org>
To: dwz@sourceware.org
Cc: Mark Wielaard <mark@klomp.org>
Subject: [PATCH 2/2] Write DWARF5 multifile .debug_line if possible.
Date: Mon, 12 Oct 2020 21:06:49 +0200	[thread overview]
Message-ID: <20201012190649.17808-2-mark@klomp.org> (raw)
In-Reply-To: <20201012190649.17808-1-mark@klomp.org>

This write version 5 .debug_line into the multifile if all .debug_line
segments seen before are also version 5. This is more efficient than
version 2, if we don't have to write out the time and size of the files.
But only if there are more than ~25 files because the header is bigger
and there is some overhead for having to handle zero entry dir and file
entries (those do have to exist, but are not directly referenced by
anything).

ChangeLog:

	* dwz.c (lowest_line_version): New static unsigned int, set
	to 5 initially.
	(read_debug_line): Check version and set lowest_line_version.
	(struct line_stats): New.
	(list_line_entries): Update data as struct line_stats.
	(write_multifile_line): Collect time and size stats and write
	out version 5 .debug_line data if lowest_line_version is 5.
---
 dwz.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 129 insertions(+), 16 deletions(-)

diff --git a/dwz.c b/dwz.c
index 9345e6c..e517a47 100644
--- a/dwz.c
+++ b/dwz.c
@@ -484,6 +484,12 @@ typedef struct
    with a single pointer size are handled.  */
 static int ptr_size;
 
+/* Lowest debug_line version we have seen.  When writing out the multi
+   file .debug_line we'll only use a DWARF5 version when there is no
+   lower line table seen (since the debug_line dir and file table is
+   shared between all CUs).  */
+static unsigned int lowest_line_version = 5;
+
 /* Utility functions and macros for reading/writing values in
    given ELF endianity, which might be different from host endianity.
    No specific alignment is expected.  */
@@ -1503,6 +1509,9 @@ read_debug_line (DSO *dso, dw_cu_ref cu, uint32_t off)
     }
   version = value;
 
+  if (version < lowest_line_version)
+    lowest_line_version = version;
+
   if (version >= 5)
     {
       int addr_size, seg_size;
@@ -14371,18 +14380,34 @@ write_multifile_strp (void)
   return ret;
 }
 
-/* Helper to record all strp_entry entries from strp_htab.
+/* Hold some statistics on the line entries so we know whether to emit
+   time and/or sizes.  Used by list_line_entries used by
+   write_multifile_line.  */
+struct line_stats
+{
+  struct line_entry ***end;
+  bool has_time;
+  bool has_size;
+};
+
+/* Helper to find the end of the line_htab entries and other stats.
    Called through htab_traverse.  */
 static int
 list_line_entries (void **slot, void *data)
 {
-  struct line_entry ***end = (struct line_entry ***) data;
-  **end = (struct line_entry *) *slot;
+  struct line_stats *stats = (struct line_stats *) data;
+  struct line_entry *entry = (struct line_entry *) *slot;
+  struct line_entry ***end = stats->end;
+  **end = entry;
   (*end)++;
+  if (entry->file->time != 0)
+    stats->has_time = true;
+  if (entry->file->size != 0)
+    stats->has_size = true;
   return 1;
 }
 
-/* Helper function for write_multifile_strp to sort strp_entry
+/* Helper function for write_multifile_strp to sort line_entry
    by increasing new_id.  */
 static int
 line_id_cmp (const void *p, const void *q)
@@ -14405,13 +14430,15 @@ static int
 write_multifile_line (void)
 {
   unsigned int filecnt = 0, dircnt = 0, filetbllen = 0, dirtbllen = 0;
-  unsigned int len, i, j;
+  unsigned int header_len, len, i, j;
   unsigned char *line, *ptr;
   struct line_entry **filearr = NULL;
+  struct line_stats line_stats;
   unsigned int *diridx = NULL, *dirarr = NULL;
   unsigned char buf[17];
   int ret = 0;
 
+  line_stats.has_time = line_stats.has_size = false;
   if (line_htab)
     {
       struct line_entry **end;
@@ -14419,7 +14446,8 @@ write_multifile_line (void)
       filearr = (struct line_entry **)
 		obstack_alloc (&ob, filecnt * sizeof (*filearr));
       end = filearr;
-      htab_traverse (line_htab, list_line_entries, (void *) &end);
+      line_stats.end = &end;
+      htab_traverse (line_htab, list_line_entries, (void *) &line_stats);
       assert (filearr + filecnt == end);
       diridx = (unsigned int *)
 	       obstack_alloc (&ob, filecnt * sizeof (*diridx));
@@ -14476,13 +14504,45 @@ write_multifile_line (void)
 	    }
 	  filetbllen += strlen (file) + 1;
 	  filetbllen += size_of_uleb128 (diridx[i]);
-	  filetbllen += size_of_uleb128 (filearr[i]->file->time);
-	  filetbllen += size_of_uleb128 (filearr[i]->file->size);
+	  if (lowest_line_version < 5 || line_stats.has_time)
+	    filetbllen += size_of_uleb128 (filearr[i]->file->time);
+	  if (lowest_line_version < 5 || line_stats.has_size)
+	    filetbllen += size_of_uleb128 (filearr[i]->file->size);
 	}
       dirarr = (unsigned int *) obstack_finish (&ob);
     }
 
-  len = 17 + filetbllen + dirtbllen;
+  /* standard .debug_line "header" length (both version 2 and 5):
+     unit_length (4) + version (2) + header_length (4) +
+     min_instr_length (1) + default_is_stmt (1) + line_base (1) +
+     line_range (1) + opcode_base (1) = 15
+
+     version 2 adds 2 bytes, one zero byte to terminate dir and file lists.
+
+     version 5 adds at least 11 bytes, max_ops_per_instr (1) +
+     address_size (1) + segment_size (1) + dir_entry_format_cnt (1) +
+     format_pair (2), file_entry_format_cnt (1) + file_format_pairs
+     (4). Plus dircnt (uleb128) + format_pair (2) if has_time +
+     format_pair (2) if has_size) + filecnt (uleb128).
+
+     version 5 also has 2 extra 6 byte "<dwz>" string entries for dir
+     and file entry zero, plus one for the zero file entry dir idx.
+  */
+  header_len = 15;
+  if (lowest_line_version < 5)
+    header_len += 2;
+  else
+    {
+      header_len += 11;
+      header_len += size_of_uleb128 (dircnt + 1);
+      header_len += size_of_uleb128 (filecnt + 1);
+      if (line_stats.has_time)
+	header_len += 2;
+      if (line_stats.has_size)
+	header_len += 2;
+      header_len += 2 * 6 + 1;
+    }
+  len = header_len + filetbllen + dirtbllen;
   if (unlikely (op_multifile))
     {
       debug_sections[DEBUG_LINE].new_size = len;
@@ -14500,20 +14560,41 @@ write_multifile_line (void)
 	  return 1;
 	}
 
-      if (len == 17)
+      if (len == header_len)
 	line = buf;
       else
 	line = (unsigned char *) obstack_alloc (&ob, len);
     }
   ptr = line;
   write_32 (ptr, len - 4);	/* Total length.  */
-  write_16 (ptr, 2);		/* DWARF version.  */
-  write_32 (ptr, len - 10);	/* Header length.  */
+  if (lowest_line_version < 5)
+    write_16 (ptr, 2);		/* DWARF version.  */
+  else
+    {
+      write_16 (ptr, 5);	/* DWARF version.  */
+      write_8 (ptr, multi_ptr_size);	/* Address size.  */
+      write_8 (ptr, 0);	       	/* Segment size.  */
+    }
+  write_32 (ptr,		/* Header length.  */
+	    len - (lowest_line_version < 5 ? 10 : 12));
   write_8 (ptr, 1);		/* Minimum insn length.  */
+  if (lowest_line_version >= 5)
+    write_8 (ptr, 1);		/* Maximum ops per instr.  */
   write_8 (ptr, 1);		/* Default is_stmt.  */
   write_8 (ptr, 0);		/* Line base.  */
   write_8 (ptr, 1);		/* Line range.  */
   write_8 (ptr, 1);		/* Opcode base.  */
+
+  if (lowest_line_version >= 5)
+    {
+      write_8 (ptr, 1);		/* Dir entry format count.  */
+      write_uleb128 (ptr, DW_LNCT_path);
+      write_uleb128 (ptr, DW_FORM_string);
+      write_uleb128 (ptr, dircnt + 1); /* Dir cnt.  */
+      memcpy (ptr, "<dwz>", 6);	/* Zero entry empty dir path.  */
+      ptr += 6;
+    }
+
   for (i = 0; i < dircnt; i++)
     {
       unsigned int l;
@@ -14535,7 +14616,36 @@ write_multifile_line (void)
 	}
       ptr += l;
     }
-  write_8 (ptr, 0);		/* Terminate dir table.  */
+  if (lowest_line_version < 5)
+    write_8 (ptr, 0);		/* Terminate dir table.  */
+  else
+    {
+      unsigned int format_cnt = 2 + line_stats.has_size + line_stats.has_time;
+      write_8 (ptr, format_cnt);	/* File entry format count.  */
+      write_uleb128 (ptr, DW_LNCT_path);
+      write_uleb128 (ptr, DW_FORM_string);
+      write_uleb128 (ptr, DW_LNCT_directory_index);
+      write_uleb128 (ptr, DW_FORM_udata);
+      if (line_stats.has_time)
+	{
+	  write_uleb128 (ptr, DW_LNCT_timestamp);
+	  write_uleb128 (ptr, DW_FORM_udata);
+	}
+      if (line_stats.has_size)
+	{
+	  write_uleb128 (ptr, DW_LNCT_size);
+	  write_uleb128 (ptr, DW_FORM_udata);
+	}
+      write_uleb128 (ptr, filecnt + 1); /* File names cnt.  */
+      memcpy (ptr, "<dwz>", 6);		/* Zero entry empty file path.  */
+      ptr += 6;
+      write_8 (ptr, 0);	       		/* Zero entry zero diridx.  */
+      if (line_stats.has_time)
+	write_8 (ptr, 0);
+      if (line_stats.has_size)
+	write_8 (ptr, 0);
+    }
+
   for (i = 0; i < filecnt; i++)
     {
       const char *file = filearr[i]->file->file;
@@ -14546,10 +14656,13 @@ write_multifile_line (void)
       memcpy (ptr, file, l);
       ptr += l;
       write_uleb128 (ptr, diridx[i]);
-      write_uleb128 (ptr, filearr[i]->file->time);
-      write_uleb128 (ptr, filearr[i]->file->size);
+      if (lowest_line_version < 5 || line_stats.has_time)
+	write_uleb128 (ptr, filearr[i]->file->time);
+      if (lowest_line_version < 5 || line_stats.has_size)
+	write_uleb128 (ptr, filearr[i]->file->size);
     }
-  write_8 (ptr, 0);		/* Terminate file table.  */
+  if (lowest_line_version < 5)
+    write_8 (ptr, 0);		/* Terminate file table.  */
   assert (ptr == line + len);
 
   if (likely (!op_multifile))
-- 
2.18.4


  reply	other threads:[~2020-10-12 19:07 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-10-12 19:06 [PATCH 1/2] Read DWARF5 .debug_line Mark Wielaard
2020-10-12 19:06 ` Mark Wielaard [this message]
2020-10-13 14:23   ` [PATCH 2/2] Write DWARF5 multifile .debug_line if possible Jakub Jelinek
2020-10-13 14:19 ` [PATCH 1/2] Read DWARF5 .debug_line Jakub Jelinek
2020-10-13 21:14   ` Mark Wielaard

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=20201012190649.17808-2-mark@klomp.org \
    --to=mark@klomp.org \
    --cc=dwz@sourceware.org \
    /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).