From 1c90d9f022469629c255d44664b4452998168359 Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Fri, 11 Aug 2017 09:30:02 +0100 Subject: [PATCH] Class-fy dwarf2_frame_state_reg_info 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-08-11 Yao Qi * 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. : New method. : 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/ChangeLog | 28 ++++++++ gdb/dwarf2-frame.c | 164 +++++++++++++++++++++++---------------------- gdb/dwarf2-frame.h | 90 +++++++++++++++++++++---- gdb/sparc-tdep.c | 2 +- 4 files changed, 189 insertions(+), 95 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index e198117728d..b08f72b4eae 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,31 @@ +2017-08-11 Yao Qi + + * 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. + : New method. + : 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. + 2017-08-11 Yao Qi * dwarf2-frame.c (dwarf2_frame_state_free): Remove. diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 486d60b9fc7..0cb40d91e50 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 = 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 = 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 = 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, ®); - 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, ®); - 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, ®); - 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 c952a20e87c..2c3d14c9a9f 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 6135e0b9fb6..1f08865f9aa 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; -- 2.30.2