public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Cc: Tom Tromey <tromey@adacore.com>
Subject: [PATCH] Allow out-of-order reads of CIEs
Date: Fri, 11 Oct 2019 13:49:00 -0000	[thread overview]
Message-ID: <20191011134930.4279-1-tromey@adacore.com> (raw)

Currently gdb has an assertion that requires CIEs to be read in the
order in which they appear in the debug info:

   gdb_assert (n < 1
               || cie_table->entries[n - 1]->cie_pointer < cie->cie_pointer);

This assertion ensures that the table will be sorted, which is
important because it is later searched using bsearch.

However, a customer provided an executable that causes this assertion
to trigger.  This executable causes decode_frame_entry_1 to call
decode_frame_entry to find the CIE, resulting in an out-of-order read.

I don't know a good way to construct a reproducer, but this can happen
if the FDE appears before its CIE.  See
https://sourceware.org/bugzilla/show_bug.cgi?id=16563

This patch fixes the problem by storing CIEs in an unordered map.  The
CIE table is discarded after the frame section is parsed, so this
seemed both simple and straightforward.

gdb/ChangeLog
2019-10-11  Tom Tromey  <tromey@adacore.com>

	* dwarf2-frame.c (dwarf2_cie_table): Now a typedef.
	(bsearch_cie_cmp, add_cie): Remove.
	(find_cie): Reimplement.
	(decode_frame_entry_1, decode_frame_entry): Change type.  Update.
	(dwarf2_build_frame_info): Update.
---
 gdb/ChangeLog      |  8 ++++
 gdb/dwarf2-frame.c | 92 +++++++++-------------------------------------
 2 files changed, 25 insertions(+), 75 deletions(-)

diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 34b8cbcb768..29fdb43608f 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -43,6 +43,7 @@
 #include "gdbsupport/selftest.h"
 #include "selftest-arch.h"
 #endif
+#include <unordered_map>
 
 struct comp_unit;
 
@@ -98,11 +99,9 @@ struct dwarf2_cie
   unsigned char segment_size;
 };
 
-struct dwarf2_cie_table
-{
-  int num_entries;
-  struct dwarf2_cie **entries;
-};
+/* The CIE table is used to find CIEs during parsing, but then
+   discarded.  It maps from the CIE's offset to the CIE.  */
+typedef std::unordered_map<ULONGEST, dwarf2_cie *> dwarf2_cie_table;
 
 /* Frame Description Entry (FDE).  */
 
@@ -1641,55 +1640,16 @@ read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
 }
 \f
 
-static int
-bsearch_cie_cmp (const void *key, const void *element)
-{
-  ULONGEST cie_pointer = *(ULONGEST *) key;
-  struct dwarf2_cie *cie = *(struct dwarf2_cie **) element;
-
-  if (cie_pointer == cie->cie_pointer)
-    return 0;
-
-  return (cie_pointer < cie->cie_pointer) ? -1 : 1;
-}
-
 /* Find CIE with the given CIE_POINTER in CIE_TABLE.  */
 static struct dwarf2_cie *
-find_cie (struct dwarf2_cie_table *cie_table, ULONGEST cie_pointer)
+find_cie (const dwarf2_cie_table &cie_table, ULONGEST cie_pointer)
 {
-  struct dwarf2_cie **p_cie;
-
-  /* The C standard (ISO/IEC 9899:TC2) requires the BASE argument to
-     bsearch be non-NULL.  */
-  if (cie_table->entries == NULL)
-    {
-      gdb_assert (cie_table->num_entries == 0);
-      return NULL;
-    }
-
-  p_cie = ((struct dwarf2_cie **)
-	   bsearch (&cie_pointer, cie_table->entries, cie_table->num_entries,
-		    sizeof (cie_table->entries[0]), bsearch_cie_cmp));
-  if (p_cie != NULL)
-    return *p_cie;
+  auto iter = cie_table.find (cie_pointer);
+  if (iter != cie_table.end ())
+    return iter->second;
   return NULL;
 }
 
-/* Add a pointer to new CIE to the CIE_TABLE, allocating space for it.  */
-static void
-add_cie (struct dwarf2_cie_table *cie_table, struct dwarf2_cie *cie)
-{
-  const int n = cie_table->num_entries;
-
-  gdb_assert (n < 1
-              || cie_table->entries[n - 1]->cie_pointer < cie->cie_pointer);
-
-  cie_table->entries
-    = XRESIZEVEC (struct dwarf2_cie *, cie_table->entries, n + 1);
-  cie_table->entries[n] = cie;
-  cie_table->num_entries = n + 1;
-}
-
 static int
 bsearch_fde_cmp (const void *key, const void *element)
 {
@@ -1778,7 +1738,7 @@ enum eh_frame_type
 static const gdb_byte *decode_frame_entry (struct comp_unit *unit,
 					   const gdb_byte *start,
 					   int eh_frame_p,
-					   struct dwarf2_cie_table *cie_table,
+					   dwarf2_cie_table &cie_table,
 					   struct dwarf2_fde_table *fde_table,
 					   enum eh_frame_type entry_type);
 
@@ -1788,7 +1748,7 @@ static const gdb_byte *decode_frame_entry (struct comp_unit *unit,
 static const gdb_byte *
 decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start,
 		      int eh_frame_p,
-                      struct dwarf2_cie_table *cie_table,
+                      dwarf2_cie_table &cie_table,
                       struct dwarf2_fde_table *fde_table,
                       enum eh_frame_type entry_type)
 {
@@ -2007,7 +1967,7 @@ decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start,
       cie->end = end;
       cie->unit = unit;
 
-      add_cie (cie_table, cie);
+      cie_table[cie->cie_pointer] = cie;
     }
   else
     {
@@ -2090,7 +2050,7 @@ decode_frame_entry_1 (struct comp_unit *unit, const gdb_byte *start,
 static const gdb_byte *
 decode_frame_entry (struct comp_unit *unit, const gdb_byte *start,
 		    int eh_frame_p,
-                    struct dwarf2_cie_table *cie_table,
+		    dwarf2_cie_table &cie_table,
                     struct dwarf2_fde_table *fde_table,
                     enum eh_frame_type entry_type)
 {
@@ -2207,13 +2167,10 @@ dwarf2_build_frame_info (struct objfile *objfile)
 {
   struct comp_unit *unit;
   const gdb_byte *frame_ptr;
-  struct dwarf2_cie_table cie_table;
+  dwarf2_cie_table cie_table;
   struct dwarf2_fde_table fde_table;
   struct dwarf2_fde_table *fde_table2;
 
-  cie_table.num_entries = 0;
-  cie_table.entries = NULL;
-
   fde_table.num_entries = 0;
   fde_table.entries = NULL;
 
@@ -2255,7 +2212,7 @@ dwarf2_build_frame_info (struct objfile *objfile)
 	      frame_ptr = unit->dwarf_frame_buffer;
 	      while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
 		frame_ptr = decode_frame_entry (unit, frame_ptr, 1,
-						&cie_table, &fde_table,
+						cie_table, &fde_table,
 						EH_CIE_OR_FDE_TYPE_ID);
 	    }
 
@@ -2270,16 +2227,10 @@ dwarf2_build_frame_info (struct objfile *objfile)
 		  fde_table.entries = NULL;
 		  fde_table.num_entries = 0;
 		}
-	      /* The cie_table is discarded by the next if.  */
+	      /* The cie_table is discarded below.  */
 	    }
 
-          if (cie_table.num_entries != 0)
-            {
-              /* Reinit cie_table: debug_frame has different CIEs.  */
-              xfree (cie_table.entries);
-              cie_table.num_entries = 0;
-              cie_table.entries = NULL;
-            }
+	  cie_table.clear ();
         }
     }
 
@@ -2296,7 +2247,7 @@ dwarf2_build_frame_info (struct objfile *objfile)
 	  frame_ptr = unit->dwarf_frame_buffer;
 	  while (frame_ptr < unit->dwarf_frame_buffer + unit->dwarf_frame_size)
 	    frame_ptr = decode_frame_entry (unit, frame_ptr, 0,
-					    &cie_table, &fde_table,
+					    cie_table, &fde_table,
 					    EH_CIE_OR_FDE_TYPE_ID);
 	}
       catch (const gdb_exception_error &e)
@@ -2320,18 +2271,9 @@ dwarf2_build_frame_info (struct objfile *objfile)
 		}
 	    }
 	  fde_table.num_entries = num_old_fde_entries;
-	  /* The cie_table is discarded by the next if.  */
 	}
     }
 
-  /* Discard the cie_table, it is no longer needed.  */
-  if (cie_table.num_entries != 0)
-    {
-      xfree (cie_table.entries);
-      cie_table.entries = NULL;   /* Paranoia.  */
-      cie_table.num_entries = 0;  /* Paranoia.  */
-    }
-
   /* Copy fde_table to obstack: it is needed at runtime.  */
   fde_table2 = XOBNEW (&objfile->objfile_obstack, struct dwarf2_fde_table);
 
-- 
2.20.1

             reply	other threads:[~2019-10-11 13:49 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-11 13:49 Tom Tromey [this message]
2019-10-25 14:29 ` Tom Tromey

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=20191011134930.4279-1-tromey@adacore.com \
    --to=tromey@adacore.com \
    --cc=gdb-patches@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).