[3/9] Class-fy dwarf2_frame_state_reg_info

Message ID 1501539715-8049-4-git-send-email-yao.qi@linaro.org
State New, archived
Headers

Commit Message

Yao Qi July 31, 2017, 10:21 p.m. UTC
  This patch adds dwarf2_frame_state_reg_info ctor, dtor, copy ctor,
assignment operator, and move assignment.  This patch also adds unit test
to execute_cfa_program to cover the changes.

gdb:

2017-07-21  Yao Qi  <yao.qi@linaro.org>

	* dwarf2-frame.c (dwarf2_frame_state_alloc_regs): Remove.
	(dwarf2_frame_state_copy_regs): Remove.
	(dwarf2_frame_state_free_regs): Remove.
	(dwarf2_frame_state::~dwarf2_frame_state): Remove.
	(dwarf2_restore_rule): Call method .alloc_regs instead of
	dwarf2_frame_state_alloc_regs.
	(execute_cfa_program): Likewise.  Call dwarf2_frame_state_reg_info
	constructor.  Call std::move.
	(dwarf2_fetch_cfa_info): Don't call dwarf2_frame_state_copy_regs.
	(dwarf2_frame_cache): Likewise.

	[GDB_SELF_TEST]: Include selftest.h and
	selftest-arch.h.
	[GDB_SELF_TEST] (execute_cfa_program_test): New function.
	(_initialize_dwarf2_frame) [GDB_SELF_TEST]: Register
	execute_cfa_program_test.

	* dwarf2-frame.h (dwarf2_frame_state_reg_info): Add ctor, dtor,
	copy ctor, assignment operator, move assignment.
	<alloc_regs>: New method.
	<swap>: New method.
	(struct dwarf2_frame_state): Delete dtor.
	(dwarf2_frame_state_alloc_regs): Remove declaration.
	* sparc-tdep.c (sparc_execute_dwarf_cfa_vendor_op): Don't call
	dwarf2_frame_state_alloc_regs, use .alloc_regs instead.
---
 gdb/dwarf2-frame.c | 164 +++++++++++++++++++++++++++--------------------------
 gdb/dwarf2-frame.h |  90 ++++++++++++++++++++++++-----
 gdb/sparc-tdep.c   |   2 +-
 3 files changed, 161 insertions(+), 95 deletions(-)
  

Patch

diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 486d60b..0cb40d9 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -38,6 +38,10 @@ 
 #include "ax.h"
 #include "dwarf2loc.h"
 #include "dwarf2-frame-tailcall.h"
+#if GDB_SELF_TEST
+#include "selftest.h"
+#include "selftest-arch.h"
+#endif
 
 struct comp_unit;
 
@@ -169,69 +173,12 @@  static CORE_ADDR read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
    which is unused in that case.  */
 #define cfa_exp_len cfa_reg
 
-/* Assert that the register set RS is large enough to store gdbarch_num_regs
-   columns.  If necessary, enlarge the register set.  */
-
-void
-dwarf2_frame_state_alloc_regs (struct dwarf2_frame_state_reg_info *rs,
-			       int num_regs)
-{
-  size_t size = sizeof (struct dwarf2_frame_state_reg);
-
-  if (num_regs <= rs->num_regs)
-    return;
-
-  rs->reg = (struct dwarf2_frame_state_reg *)
-    xrealloc (rs->reg, num_regs * size);
-
-  /* Initialize newly allocated registers.  */
-  memset (rs->reg + rs->num_regs, 0, (num_regs - rs->num_regs) * size);
-  rs->num_regs = num_regs;
-}
-
-/* Copy the register columns in register set RS into newly allocated
-   memory and return a pointer to this newly created copy.  */
-
-static struct dwarf2_frame_state_reg *
-dwarf2_frame_state_copy_regs (struct dwarf2_frame_state_reg_info *rs)
-{
-  size_t size = rs->num_regs * sizeof (struct dwarf2_frame_state_reg);
-  struct dwarf2_frame_state_reg *reg;
-
-  reg = (struct dwarf2_frame_state_reg *) xmalloc (size);
-  memcpy (reg, rs->reg, size);
-
-  return reg;
-}
-
-/* Release the memory allocated to register set RS.  */
-
-static void
-dwarf2_frame_state_free_regs (struct dwarf2_frame_state_reg_info *rs)
-{
-  if (rs)
-    {
-      dwarf2_frame_state_free_regs (rs->prev);
-
-      xfree (rs->reg);
-      xfree (rs);
-    }
-}
-
 dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
   : pc (pc_), data_align (cie->data_alignment_factor),
     code_align (cie->code_alignment_factor),
     retaddr_column (cie->return_address_register)
 {
 }
-
-dwarf2_frame_state::~dwarf2_frame_state ()
-{
-  dwarf2_frame_state_free_regs (initial.prev);
-  dwarf2_frame_state_free_regs (regs.prev);
-  xfree (initial.reg);
-  xfree (regs.reg);
-}
 
 
 /* Helper functions for execute_stack_op.  */
@@ -255,7 +202,7 @@  dwarf2_restore_rule (struct gdbarch *gdbarch, ULONGEST reg_num,
 
   gdb_assert (fs->initial.reg);
   reg = dwarf2_frame_adjust_regnum (gdbarch, reg_num, eh_frame_p);
-  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+  fs->regs.alloc_regs (reg + 1);
 
   /* Check if this register was explicitly initialized in the
   CIE initial instructions.  If not, default the rule to
@@ -409,7 +356,7 @@  execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
 	  reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	  insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	  offset = utmp * fs->data_align;
-	  dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	  fs->regs.alloc_regs (reg + 1);
 	  fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
 	  fs->regs.reg[reg].loc.offset = offset;
 	}
@@ -453,7 +400,7 @@  execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      offset = utmp * fs->data_align;
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
 	      fs->regs.reg[reg].loc.offset = offset;
 	      break;
@@ -466,14 +413,14 @@  execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
 	    case DW_CFA_undefined:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNDEFINED;
 	      break;
 
 	    case DW_CFA_same_value:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAME_VALUE;
 	      break;
 
@@ -482,7 +429,7 @@  execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      utmp = dwarf2_frame_adjust_regnum (gdbarch, utmp, eh_frame_p);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;
 	      fs->regs.reg[reg].loc.reg = utmp;
 	      break;
@@ -491,9 +438,7 @@  execute_cfa_program (struct dwarf2_fde *fde, const gdb_byte *insn_ptr,
 	      {
 		struct dwarf2_frame_state_reg_info *new_rs;
 
-		new_rs = XNEW (struct dwarf2_frame_state_reg_info);
-		*new_rs = fs->regs;
-		fs->regs.reg = dwarf2_frame_state_copy_regs (&fs->regs);
+		new_rs = new dwarf2_frame_state_reg_info (fs->regs);
 		fs->regs.prev = new_rs;
 	      }
 	      break;
@@ -509,11 +454,7 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 			       paddress (gdbarch, fs->pc));
 		  }
 		else
-		  {
-		    xfree (fs->regs.reg);
-		    fs->regs = *old_rs;
-		    xfree (old_rs);
-		  }
+		  fs->regs = std::move (*old_rs);
 	      }
 	      break;
 
@@ -560,7 +501,7 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 	    case DW_CFA_expression:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      fs->regs.reg[reg].loc.exp.start = insn_ptr;
 	      fs->regs.reg[reg].loc.exp.len = utmp;
@@ -573,14 +514,14 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset);
 	      offset *= fs->data_align;
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
 	      fs->regs.reg[reg].loc.offset = offset;
 	      break;
 
 	    case DW_CFA_val_offset:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      offset = utmp * fs->data_align;
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET;
@@ -589,7 +530,7 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 
 	    case DW_CFA_val_offset_sf:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      insn_ptr = safe_read_sleb128 (insn_ptr, insn_end, &offset);
 	      offset *= fs->data_align;
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_VAL_OFFSET;
@@ -598,7 +539,7 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 
 	    case DW_CFA_val_expression:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &reg);
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      fs->regs.reg[reg].loc.exp.start = insn_ptr;
 	      fs->regs.reg[reg].loc.exp.len = utmp;
@@ -631,7 +572,7 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
 	      reg = dwarf2_frame_adjust_regnum (gdbarch, reg, eh_frame_p);
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
 	      offset = utmp * fs->data_align;
-	      dwarf2_frame_state_alloc_regs (&fs->regs, reg + 1);
+	      fs->regs.alloc_regs (reg + 1);
 	      fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_OFFSET;
 	      fs->regs.reg[reg].loc.offset = -offset;
 	      break;
@@ -655,12 +596,73 @@  bad CFI data; mismatched DW_CFA_restore_state at %s"),
   if (fs->initial.reg == NULL)
     {
       /* Don't allow remember/restore between CIE and FDE programs.  */
-      dwarf2_frame_state_free_regs (fs->regs.prev);
+      delete fs->regs.prev;
       fs->regs.prev = NULL;
     }
 
   return insn_ptr;
 }
+
+#if GDB_SELF_TEST
+
+namespace selftests {
+
+/* Unit test to function execute_cfa_program.  */
+
+static void
+execute_cfa_program_test (struct gdbarch *gdbarch)
+{
+  struct dwarf2_fde fde;
+  struct dwarf2_cie cie;
+
+  memset (&fde, 0, sizeof fde);
+  memset (&cie, 0, sizeof cie);
+
+  cie.data_alignment_factor = -4;
+  cie.code_alignment_factor = 2;
+  fde.cie = &cie;
+
+  dwarf2_frame_state fs (0, fde.cie);
+
+  gdb_byte insns[] =
+    {
+      DW_CFA_def_cfa, 1, 4,  /* DW_CFA_def_cfa: r1 ofs 4 */
+      DW_CFA_offset | 0x2, 1,  /* DW_CFA_offset: r2 at cfa-4 */
+      DW_CFA_remember_state,
+      DW_CFA_restore_state,
+    };
+
+  const gdb_byte *insn_end = insns + sizeof (insns);
+  const gdb_byte *out = execute_cfa_program (&fde, insns, insn_end, gdbarch,
+					     0, &fs);
+
+  SELF_CHECK (out == insn_end);
+  SELF_CHECK (fs.pc == 0);
+
+  /* The instructions above only use r1 and r2, but the register numbers
+     used are adjusted by dwarf2_frame_adjust_regnum.  */
+  auto r1 = dwarf2_frame_adjust_regnum (gdbarch, 1, fde.eh_frame_p);
+  auto r2 = dwarf2_frame_adjust_regnum (gdbarch, 2, fde.eh_frame_p);
+
+  SELF_CHECK (fs.regs.num_regs == (std::max (r1, r2) + 1));
+
+  SELF_CHECK (fs.regs.reg[r2].how == DWARF2_FRAME_REG_SAVED_OFFSET);
+  SELF_CHECK (fs.regs.reg[r2].loc.offset == -4);
+
+  for (auto i = 0; i < fs.regs.num_regs; i++)
+    if (i != r2)
+      SELF_CHECK (fs.regs.reg[i].how == DWARF2_FRAME_REG_UNSPECIFIED);
+
+  SELF_CHECK (fs.regs.cfa_reg == 1);
+  SELF_CHECK (fs.regs.cfa_offset == 4);
+  SELF_CHECK (fs.regs.cfa_how == CFA_REG_OFFSET);
+  SELF_CHECK (fs.regs.cfa_exp == NULL);
+  SELF_CHECK (fs.regs.prev == NULL);
+}
+
+} // namespace selftests
+#endif /* GDB_SELF_TEST */
+
 
 
 /* Architecture-specific operations.  */
@@ -884,7 +886,6 @@  dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
 
   /* Save the initialized register set.  */
   fs.initial = fs.regs;
-  fs.initial.reg = dwarf2_frame_state_copy_regs (&fs.regs);
 
   /* Then decode the insns in the FDE up to our target PC.  */
   execute_cfa_program (fde, fde->instructions, fde->end, gdbarch, pc, &fs);
@@ -1026,7 +1027,6 @@  dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
 
   /* Save the initialized register set.  */
   fs.initial = fs.regs;
-  fs.initial.reg = dwarf2_frame_state_copy_regs (&fs.regs);
 
   if (get_frame_func_if_available (this_frame, &entry_pc))
     {
@@ -2418,4 +2418,8 @@  _initialize_dwarf2_frame (void)
 {
   dwarf2_frame_data = gdbarch_data_register_pre_init (dwarf2_frame_init);
   dwarf2_frame_objfile_data = register_objfile_data ();
+
+#if GDB_SELF_TEST
+  register_self_test_foreach_arch (selftests::execute_cfa_program_test);
+#endif
 }
diff --git a/gdb/dwarf2-frame.h b/gdb/dwarf2-frame.h
index c952a20..2c3d14c 100644
--- a/gdb/dwarf2-frame.h
+++ b/gdb/dwarf2-frame.h
@@ -94,16 +94,85 @@  enum cfa_how_kind
 
 struct dwarf2_frame_state_reg_info
 {
-  struct dwarf2_frame_state_reg *reg;
-  int num_regs;
+  dwarf2_frame_state_reg_info () = default;
+  ~dwarf2_frame_state_reg_info ()
+  {
+    delete prev;
+    xfree (reg);
+  }
+
+  /* Copy constructor.  */
+  dwarf2_frame_state_reg_info (const dwarf2_frame_state_reg_info &src)
+    : num_regs (src.num_regs), cfa_offset (src.cfa_offset),
+      cfa_reg (src.cfa_reg), cfa_how (src.cfa_how), cfa_exp (src.cfa_exp),
+      prev (src.prev)
+  {
+    size_t size = src.num_regs * sizeof (struct dwarf2_frame_state_reg);
+
+    reg = (struct dwarf2_frame_state_reg *) xmalloc (size);
+    memcpy (reg, src.reg, size);
+  }
+
+  /* Assignment operator for both move-assignment and copy-assignment.  */
+  dwarf2_frame_state_reg_info&
+  operator= (dwarf2_frame_state_reg_info rhs)
+  {
+    swap (*this, rhs);
+    return *this;
+  }
+
+  /* Move constructor.  */
+  dwarf2_frame_state_reg_info (dwarf2_frame_state_reg_info &&rhs) noexcept
+    : reg (rhs.reg), num_regs (rhs.num_regs), cfa_offset (rhs.cfa_offset),
+      cfa_reg (rhs.cfa_reg), cfa_how (rhs.cfa_how), cfa_exp (rhs.cfa_exp),
+      prev (rhs.prev)
+  {
+    rhs.prev = nullptr;
+    rhs.reg = nullptr;
+  }
 
-  LONGEST cfa_offset;
-  ULONGEST cfa_reg;
-  enum cfa_how_kind cfa_how;
-  const gdb_byte *cfa_exp;
+/* Assert that the register set RS is large enough to store gdbarch_num_regs
+   columns.  If necessary, enlarge the register set.  */
+  void alloc_regs (int num_regs_requested)
+  {
+    if (num_regs_requested <= num_regs)
+      return;
+
+    size_t size = sizeof (struct dwarf2_frame_state_reg);
+
+    reg = (struct dwarf2_frame_state_reg *)
+      xrealloc (reg, num_regs_requested * size);
+
+    /* Initialize newly allocated registers.  */
+    memset (reg + num_regs, 0, (num_regs_requested - num_regs) * size);
+    num_regs = num_regs_requested;
+  }
+
+  struct dwarf2_frame_state_reg *reg = NULL;
+  int num_regs = 0;
+
+  LONGEST cfa_offset = 0;
+  ULONGEST cfa_reg = 0;
+  enum cfa_how_kind cfa_how = CFA_UNSET;
+  const gdb_byte *cfa_exp = NULL;
 
   /* Used to implement DW_CFA_remember_state.  */
-  struct dwarf2_frame_state_reg_info *prev;
+  struct dwarf2_frame_state_reg_info *prev = NULL;
+
+private:
+  friend void swap (dwarf2_frame_state_reg_info& lhs,
+		    dwarf2_frame_state_reg_info& rhs)
+  {
+    using std::swap;
+
+    swap (lhs.reg, rhs.reg);
+    swap (lhs.num_regs, rhs.num_regs);
+    swap (lhs.cfa_offset, rhs.cfa_offset);
+    swap (lhs.cfa_reg, rhs.cfa_reg);
+    swap (lhs.cfa_how, rhs.cfa_how);
+    swap (lhs.cfa_exp, rhs.cfa_exp);
+    swap (lhs.prev, rhs.prev);
+  }
 };
 
 struct dwarf2_cie;
@@ -113,7 +182,6 @@  struct dwarf2_cie;
 struct dwarf2_frame_state
 {
   dwarf2_frame_state (CORE_ADDR pc, struct dwarf2_cie *cie);
-  ~dwarf2_frame_state ();
 
   /* Each register save state can be described in terms of a CFA slot,
      another register, or a location expression.  */
@@ -180,12 +248,6 @@  extern const struct frame_base *
 
 CORE_ADDR dwarf2_frame_cfa (struct frame_info *this_frame);
 
-/* Assert that the register set RS is large enough to store gdbarch_num_regs
-   columns.  If necessary, enlarge the register set.  */
-
-void dwarf2_frame_state_alloc_regs (struct dwarf2_frame_state_reg_info *rs,
-				    int num_regs);
-
 /* Find the CFA information for PC.
 
    Return 1 if a register is used for the CFA, or 0 if another
diff --git a/gdb/sparc-tdep.c b/gdb/sparc-tdep.c
index dce8527..d751669 100644
--- a/gdb/sparc-tdep.c
+++ b/gdb/sparc-tdep.c
@@ -1588,7 +1588,7 @@  sparc_execute_dwarf_cfa_vendor_op (struct gdbarch *gdbarch, gdb_byte op,
   uint64_t reg;
   int size = register_size (gdbarch, 0);
 
-  dwarf2_frame_state_alloc_regs (&fs->regs, 32);
+  fs->regs.alloc_regs (32);
   for (reg = 8; reg < 16; reg++)
     {
       fs->regs.reg[reg].how = DWARF2_FRAME_REG_SAVED_REG;