/* Common code for ARM software single stepping support.
- Copyright (C) 1988-2016 Free Software Foundation, Inc.
+ Copyright (C) 1988-2020 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "common-defs.h"
-#include "gdb_vecs.h"
-#include "common-regcache.h"
+#include "gdbsupport/common-defs.h"
+#include "gdbsupport/gdb_vecs.h"
+#include "gdbsupport/common-regcache.h"
#include "arm.h"
#include "arm-get-next-pcs.h"
+#include "count-one-bits.h"
/* See arm-get-next-pcs.h. */
struct arm_get_next_pcs_ops *ops,
int byte_order,
int byte_order_for_code,
- const gdb_byte *arm_thumb2_breakpoint,
+ int has_thumb2_breakpoint,
struct regcache *regcache)
{
self->ops = ops;
self->byte_order = byte_order;
self->byte_order_for_code = byte_order_for_code;
- self->arm_thumb2_breakpoint = arm_thumb2_breakpoint;
+ self->has_thumb2_breakpoint = has_thumb2_breakpoint;
self->regcache = regcache;
}
is found, attempt to step through it. The end of the sequence address is
added to the next_pcs list. */
-static VEC (CORE_ADDR) *
-thumb_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self,
- CORE_ADDR pc)
+static std::vector<CORE_ADDR>
+thumb_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self)
{
int byte_order_for_code = self->byte_order_for_code;
- CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX};
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
CORE_ADDR loc = pc;
unsigned short insn1, insn2;
int insn_count;
int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
const int atomic_sequence_length = 16; /* Instruction sequence length. */
ULONGEST status, itstate;
- VEC (CORE_ADDR) *next_pcs = NULL;
/* We currently do not support atomic sequences within an IT block. */
status = regcache_raw_get_unsigned (self->regcache, ARM_PS_REGNUM);
itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
if (itstate & 0x0f)
- return NULL;
+ return {};
/* Assume all atomic sequences start with a ldrex{,b,h,d} instruction. */
insn1 = self->ops->read_mem_uint (loc, 2, byte_order_for_code);
loc += 2;
if (thumb_insn_size (insn1) != 4)
- return NULL;
+ return {};
insn2 = self->ops->read_mem_uint (loc, 2, byte_order_for_code);
loc += 2;
if (!((insn1 & 0xfff0) == 0xe850
|| ((insn1 & 0xfff0) == 0xe8d0 && (insn2 & 0x00c0) == 0x0040)))
- return NULL;
+ return {};
/* Assume that no atomic sequence is longer than "atomic_sequence_length"
instructions. */
if ((insn1 & 0xf000) == 0xd000 && bits (insn1, 8, 11) != 0x0f)
{
if (last_breakpoint > 0)
- return NULL; /* More than one conditional branch found,
- fallback to the standard code. */
+ return {}; /* More than one conditional branch found,
+ fallback to the standard code. */
breaks[1] = loc + 2 + (sbits (insn1, 0, 7) << 1);
last_breakpoint++;
Fall back to standard code to avoid losing control of
execution. */
else if (thumb_instruction_changes_pc (insn1))
- return NULL;
+ return {};
}
else
{
offset += (imm1 << 12) + (imm2 << 1);
if (last_breakpoint > 0)
- return 0; /* More than one conditional branch found,
- fallback to the standard code. */
+ return {}; /* More than one conditional branch found,
+ fallback to the standard code. */
breaks[1] = loc + offset;
last_breakpoint++;
Fall back to standard code to avoid losing control of
execution. */
else if (thumb2_instruction_changes_pc (insn1, insn2))
- return NULL;
+ return {};
/* If we find a strex{,b,h,d}, we're done. */
if ((insn1 & 0xfff0) == 0xe840
/* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */
if (insn_count == atomic_sequence_length)
- return NULL;
+ return {};
/* Insert a breakpoint right after the end of the atomic sequence. */
breaks[0] = loc;
|| (breaks[1] >= pc && breaks[1] < loc)))
last_breakpoint = 0;
+ std::vector<CORE_ADDR> next_pcs;
+
/* Adds the breakpoints to the list to be inserted. */
for (index = 0; index <= last_breakpoint; index++)
- VEC_safe_push (CORE_ADDR, next_pcs, MAKE_THUMB_ADDR (breaks[index]));
+ next_pcs.push_back (MAKE_THUMB_ADDR (breaks[index]));
return next_pcs;
}
is found, attempt to step through it. The end of the sequence address is
added to the next_pcs list. */
-static VEC (CORE_ADDR) *
-arm_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self,
- CORE_ADDR pc)
+static std::vector<CORE_ADDR>
+arm_deal_with_atomic_sequence_raw (struct arm_get_next_pcs *self)
{
int byte_order_for_code = self->byte_order_for_code;
- CORE_ADDR breaks[2] = {-1, -1};
+ CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX};
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
CORE_ADDR loc = pc;
unsigned int insn;
int insn_count;
int index;
int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */
const int atomic_sequence_length = 16; /* Instruction sequence length. */
- VEC (CORE_ADDR) *next_pcs = NULL;
/* Assume all atomic sequences start with a ldrex{,b,h,d} instruction.
Note that we do not currently support conditionally executed atomic
loc += 4;
if ((insn & 0xff9000f0) != 0xe1900090)
- return NULL;
+ return {};
/* Assume that no atomic sequence is longer than "atomic_sequence_length"
instructions. */
if (bits (insn, 24, 27) == 0xa)
{
if (last_breakpoint > 0)
- return NULL; /* More than one conditional branch found, fallback
- to the standard single-step code. */
+ return {}; /* More than one conditional branch found, fallback
+ to the standard single-step code. */
breaks[1] = BranchDest (loc - 4, insn);
last_breakpoint++;
but conditional branches to change the PC. Fall back to standard
code to avoid losing control of execution. */
else if (arm_instruction_changes_pc (insn))
- return NULL;
+ return {};
/* If we find a strex{,b,h,d}, we're done. */
if ((insn & 0xff9000f0) == 0xe1800090)
/* If we didn't find the strex{,b,h,d}, we cannot handle the sequence. */
if (insn_count == atomic_sequence_length)
- return NULL;
+ return {};
/* Insert a breakpoint right after the end of the atomic sequence. */
breaks[0] = loc;
|| (breaks[1] >= pc && breaks[1] < loc)))
last_breakpoint = 0;
+ std::vector<CORE_ADDR> next_pcs;
+
/* Adds the breakpoints to the list to be inserted. */
for (index = 0; index <= last_breakpoint; index++)
- VEC_safe_push (CORE_ADDR, next_pcs, breaks[index]);
+ next_pcs.push_back (breaks[index]);
return next_pcs;
}
/* Find the next possible PCs for thumb mode. */
-static VEC (CORE_ADDR) *
-thumb_get_next_pcs_raw (struct arm_get_next_pcs *self, CORE_ADDR pc)
+static std::vector<CORE_ADDR>
+thumb_get_next_pcs_raw (struct arm_get_next_pcs *self)
{
int byte_order = self->byte_order;
int byte_order_for_code = self->byte_order_for_code;
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
unsigned short inst1;
CORE_ADDR nextpc = pc + 2; /* Default is next instruction. */
- unsigned long offset;
ULONGEST status, itstate;
struct regcache *regcache = self->regcache;
- VEC (CORE_ADDR) * next_pcs = NULL;
+ std::vector<CORE_ADDR> next_pcs;
nextpc = MAKE_THUMB_ADDR (nextpc);
pc_val = MAKE_THUMB_ADDR (pc_val);
flags, affecting the execution of further instructions, we may
need to set two breakpoints. */
- if (self->arm_thumb2_breakpoint != NULL)
+ if (self->has_thumb2_breakpoint)
{
if ((inst1 & 0xff00) == 0xbf00 && (inst1 & 0x000f) != 0)
{
itstate = thumb_advance_itstate (itstate);
}
- VEC_safe_push (CORE_ADDR, next_pcs, MAKE_THUMB_ADDR (pc));
+ next_pcs.push_back (MAKE_THUMB_ADDR (pc));
return next_pcs;
}
else if (itstate != 0)
itstate = thumb_advance_itstate (itstate);
}
- VEC_safe_push (CORE_ADDR, next_pcs, MAKE_THUMB_ADDR (pc));
+ next_pcs.push_back (MAKE_THUMB_ADDR (pc));
return next_pcs;
}
else if ((itstate & 0x0f) == 0x08)
/* Set a breakpoint on the following instruction. */
gdb_assert ((itstate & 0x0f) != 0);
- VEC_safe_push (CORE_ADDR, next_pcs, MAKE_THUMB_ADDR (pc));
+ next_pcs.push_back (MAKE_THUMB_ADDR (pc));
cond_negated = (itstate >> 4) & 1;
}
while (itstate != 0 && ((itstate >> 4) & 1) == cond_negated);
- VEC_safe_push (CORE_ADDR, next_pcs, MAKE_THUMB_ADDR (pc));
+ next_pcs.push_back (MAKE_THUMB_ADDR (pc));
return next_pcs;
}
{
/* Advance to the next instruction. All the 32-bit
instructions share a common prefix. */
- VEC_safe_push (CORE_ADDR, next_pcs,
- MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));
+ next_pcs.push_back (MAKE_THUMB_ADDR (pc + thumb_insn_size (inst1)));
}
return next_pcs;
/* Fetch the saved PC from the stack. It's stored above
all of the other registers. */
- offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
+ unsigned long offset
+ = count_one_bits (bits (inst1, 0, 7)) * ARM_INT_REGISTER_SIZE;
sp = regcache_raw_get_unsigned (regcache, ARM_SP_REGNUM);
nextpc = self->ops->read_mem_uint (sp + offset, 4, byte_order);
}
unsigned long cond = bits (inst1, 8, 11);
if (cond == 0x0f) /* 0x0f = SWI */
{
- nextpc = self->ops->syscall_next_pc (self, pc);
+ nextpc = self->ops->syscall_next_pc (self);
}
else if (cond != 0x0f && condition_true (cond, status))
nextpc = pc_val + (sbits (inst1, 0, 7) << 1);
j1 = bit (inst2, 13);
j2 = bit (inst2, 11);
- offset = ((imm1 << 12) + (imm2 << 1));
+ unsigned long offset = ((imm1 << 12) + (imm2 << 1));
offset ^= ((!j2) << 22) | ((!j1) << 23);
nextpc = pc_val + offset;
j1 = bit (inst2, 13);
j2 = bit (inst2, 11);
- offset = (sign << 20) + (j2 << 19) + (j1 << 18);
+ unsigned long offset
+ = (sign << 20) + (j2 << 19) + (j1 << 18);
offset += (imm1 << 12) + (imm2 << 1);
nextpc = pc_val + offset;
/* LDMIA or POP */
if (!bit (inst2, 15))
load_pc = 0;
- offset = bitcount (inst2) * 4 - 4;
+ offset = count_one_bits (inst2) * 4 - 4;
}
else if (!bit (inst1, 7) && bit (inst1, 8))
{
nextpc = pc_val + imm;
}
- VEC_safe_push (CORE_ADDR, next_pcs, nextpc);
+ next_pcs.push_back (nextpc);
return next_pcs;
}
in Thumb-State, and gdbarch_addr_bits_remove () to get the plain memory
address in GDB and arm_addr_bits_remove in GDBServer. */
-static VEC (CORE_ADDR) *
-arm_get_next_pcs_raw (struct arm_get_next_pcs *self, CORE_ADDR pc)
+static std::vector<CORE_ADDR>
+arm_get_next_pcs_raw (struct arm_get_next_pcs *self)
{
int byte_order = self->byte_order;
int byte_order_for_code = self->byte_order_for_code;
unsigned long status;
CORE_ADDR nextpc;
struct regcache *regcache = self->regcache;
- VEC (CORE_ADDR) *next_pcs = NULL;
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
+ std::vector<CORE_ADDR> next_pcs;
pc_val = (unsigned long) pc;
this_instr = self->ops->read_mem_uint (pc, 4, byte_order_for_code);
? (pc_val + 8)
: regcache_raw_get_unsigned (regcache, rn));
- VEC_safe_push (CORE_ADDR, next_pcs, nextpc);
+ next_pcs.push_back (nextpc);
return next_pcs;
}
{
/* up */
unsigned long reglist = bits (this_instr, 0, 14);
- offset = bitcount (reglist) * 4;
+ offset = count_one_bits_l (reglist) * 4;
if (bit (this_instr, 24)) /* pre */
offset += 4;
}
break;
case 0xf: /* SWI */
{
- nextpc = self->ops->syscall_next_pc (self, pc);
+ nextpc = self->ops->syscall_next_pc (self);
}
break;
}
}
- VEC_safe_push (CORE_ADDR, next_pcs, nextpc);
+ next_pcs.push_back (nextpc);
+
return next_pcs;
}
/* See arm-get-next-pcs.h. */
-VEC (CORE_ADDR) *
-arm_get_next_pcs (struct arm_get_next_pcs *self, CORE_ADDR pc)
+std::vector<CORE_ADDR>
+arm_get_next_pcs (struct arm_get_next_pcs *self)
{
- VEC (CORE_ADDR) *next_pcs = NULL;
+ std::vector<CORE_ADDR> next_pcs;
if (self->ops->is_thumb (self))
{
- next_pcs = thumb_deal_with_atomic_sequence_raw (self, pc);
- if (next_pcs == NULL)
- next_pcs = thumb_get_next_pcs_raw (self, pc);
+ next_pcs = thumb_deal_with_atomic_sequence_raw (self);
+ if (next_pcs.empty ())
+ next_pcs = thumb_get_next_pcs_raw (self);
}
else
{
- next_pcs = arm_deal_with_atomic_sequence_raw (self, pc);
- if (next_pcs == NULL)
- next_pcs = arm_get_next_pcs_raw (self, pc);
+ next_pcs = arm_deal_with_atomic_sequence_raw (self);
+ if (next_pcs.empty ())
+ next_pcs = arm_get_next_pcs_raw (self);
+ }
+
+ if (self->ops->fixup != NULL)
+ {
+ for (CORE_ADDR &pc_ref : next_pcs)
+ pc_ref = self->ops->fixup (self, pc_ref);
}
return next_pcs;