/* Target dependent code for ARC arhitecture, for GDB.
- Copyright 2005-2017 Free Software Foundation, Inc.
+ Copyright 2005-2018 Free Software Foundation, Inc.
Contributed by Synopsys Inc.
This file is part of GDB.
"lp_count", "reserved", "limm", "pcl",
};
+static char *arc_disassembler_options = NULL;
+
/* Functions are sorted in the order as they are used in the
_initialize_arc_tdep (), which uses the same order as gdbarch.h. Static
functions are defined before the first invocation. */
static void
arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
if (arc_debug)
debug_printf ("arc: Writing PC, new value=%s\n",
addr = pv_add_constant (regs[base_reg],
arc_insn_get_memory_offset (insn));
- if (pv_area_store_would_trash (stack, addr))
+ if (stack->store_would_trash (addr))
return false;
if (insn.data_size_mode != ARC_SCALING_D)
else
size = ARC_REGISTER_SIZE;
- pv_area_store (stack, addr, size, store_value);
+ stack->store (addr, size, store_value);
}
else
{
/* If this is a double store, than write N+1 register as well. */
pv_t store_value1 = regs[insn.operands[0].value];
pv_t store_value2 = regs[insn.operands[0].value + 1];
- pv_area_store (stack, addr, ARC_REGISTER_SIZE, store_value1);
- pv_area_store (stack,
- pv_add_constant (addr, ARC_REGISTER_SIZE),
- ARC_REGISTER_SIZE, store_value2);
+ stack->store (addr, ARC_REGISTER_SIZE, store_value1);
+ stack->store (pv_add_constant (addr, ARC_REGISTER_SIZE),
+ ARC_REGISTER_SIZE, store_value2);
}
else
{
pv_t store_value
= pv_constant (arc_insn_get_operand_value (insn, 0));
- pv_area_store (stack, addr, ARC_REGISTER_SIZE * 2, store_value);
+ stack->store (addr, ARC_REGISTER_SIZE * 2, store_value);
}
}
/* Assume that if the last register (closest to new SP) can be written,
then it is possible to write all of them. */
- if (pv_area_store_would_trash (stack, new_sp))
+ if (stack->store_would_trash (new_sp))
return false;
/* Current store address. */
if (is_fp_saved)
{
addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- pv_area_store (stack, addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]);
+ stack->store (addr, ARC_REGISTER_SIZE, regs[ARC_FP_REGNUM]);
}
/* Registers are stored in backward order: from GP (R26) to R13. */
for (int i = ARC_R13_REGNUM + regs_saved - 1; i >= ARC_R13_REGNUM; i--)
{
addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- pv_area_store (stack, addr, ARC_REGISTER_SIZE, regs[i]);
+ stack->store (addr, ARC_REGISTER_SIZE, regs[i]);
}
if (is_blink_saved)
{
addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
- pv_area_store (stack, addr, ARC_REGISTER_SIZE,
- regs[ARC_BLINK_REGNUM]);
+ stack->store (addr, ARC_REGISTER_SIZE,
+ regs[ARC_BLINK_REGNUM]);
}
gdb_assert (pv_is_identical (addr, new_sp));
pv_t regs[ARC_LAST_CORE_REGNUM + 1];
for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
regs[i] = pv_register (i, 0);
- struct pv_area *stack = make_pv_area (ARC_SP_REGNUM,
- gdbarch_addr_bit (gdbarch));
- struct cleanup *back_to = make_cleanup_free_pv_area (stack);
+ pv_area stack (ARC_SP_REGNUM, gdbarch_addr_bit (gdbarch));
CORE_ADDR current_prologue_end = entrypoint;
/* If this instruction is in the prologue, fields in the cache will be
updated, and the saved registers mask may be updated. */
- if (!arc_is_in_prologue (gdbarch, insn, regs, stack))
+ if (!arc_is_in_prologue (gdbarch, insn, regs, &stack))
{
/* Found an instruction that is not in the prologue. */
if (arc_debug)
for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
{
CORE_ADDR offset;
- if (pv_area_find_reg (stack, gdbarch, i, &offset))
+ if (stack.find_reg (gdbarch, i, &offset))
cache->saved_regs[i].addr = offset;
}
}
- do_cleanups (back_to);
return current_prologue_end;
}
int
arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
{
- int (*print_insn) (bfd_vma, struct disassemble_info *);
- /* exec_bfd may be null, if GDB is run without a target BFD file. Opcodes
- will handle NULL value gracefully. */
- print_insn = arc_get_disassembler (exec_bfd);
- gdb_assert (print_insn != NULL);
- return print_insn (addr, info);
+ /* Standard BFD "machine number" field allows libocodes disassembler to
+ distinguish ARC 600, 700 and v2 cores, however v2 encompasses both ARC EM
+ and HS, which have some difference between. There are two ways to specify
+ what is the target core:
+ 1) via the disassemble_info->disassembler_options;
+ 2) otherwise libopcodes will use private (architecture-specific) ELF
+ header.
+
+ Using disassembler_options is preferable, because it comes directly from
+ GDBserver which scanned an actual ARC core identification info. However,
+ not all GDBservers report core architecture, so as a fallback GDB still
+ should support analysis of ELF header. The libopcodes disassembly code
+ uses the section to find the BFD and the BFD to find the ELF header,
+ therefore this function should set disassemble_info->section properly.
+
+ disassembler_options was already set by non-target specific code with
+ proper options obtained via gdbarch_disassembler_options ().
+
+ This function might be called multiple times in a sequence, reusing same
+ disassemble_info. */
+ if ((info->disassembler_options == NULL) && (info->section == NULL))
+ {
+ struct obj_section *s = find_pc_section (addr);
+ if (s != NULL)
+ info->section = s->the_bfd_section;
+ }
+
+ return default_print_insn (addr, info);
}
/* Baremetal breakpoint instructions.
/* Dump the frame info. Used for internal debugging only. */
static void
-arc_print_frame_cache (struct gdbarch *gdbarch, char *message,
+arc_print_frame_cache (struct gdbarch *gdbarch, const char *message,
struct arc_frame_cache *cache, int addresses_known)
{
debug_printf ("arc: frame_info %s\n", message);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, arc_get_longjmp_target);
+ /* Disassembler options. Enforce CPU if it was specified in XML target
+ description, otherwise use default method of determining CPU (ELF private
+ header). */
+ if (info.target_desc != NULL)
+ {
+ const struct bfd_arch_info *tdesc_arch
+ = tdesc_architecture (info.target_desc);
+ if (tdesc_arch != NULL)
+ {
+ xfree (arc_disassembler_options);
+ /* FIXME: It is not really good to change disassembler options
+ behind the scene, because that might override options
+ specified by the user. However as of now ARC doesn't support
+ `set disassembler-options' hence this code is the only place
+ where options are changed. It also changes options for all
+ existing gdbarches, which also can be problematic, if
+ arc_gdbarch_init will start reusing existing gdbarch
+ instances. */
+ /* Target description specifies a BFD architecture, which is
+ different from ARC cpu, as accepted by disassembler (and most
+ other ARC tools), because cpu values are much more fine grained -
+ there can be multiple cpu values per single BFD architecture. As
+ a result this code should translate architecture to some cpu
+ value. Since there is no info on exact cpu configuration, it is
+ best to use the most feature-rich CPU, so that disassembler will
+ recognize all instructions available to the specified
+ architecture. */
+ switch (tdesc_arch->mach)
+ {
+ case bfd_mach_arc_arc601:
+ arc_disassembler_options = xstrdup ("cpu=arc601");
+ break;
+ case bfd_mach_arc_arc600:
+ arc_disassembler_options = xstrdup ("cpu=arc600");
+ break;
+ case bfd_mach_arc_arc700:
+ arc_disassembler_options = xstrdup ("cpu=arc700");
+ break;
+ case bfd_mach_arc_arcv2:
+ /* Machine arcv2 has three arches: ARCv2, EM and HS; where ARCv2
+ is treated as EM. */
+ if (arc_arch_is_hs (tdesc_arch))
+ arc_disassembler_options = xstrdup ("cpu=hs38_linux");
+ else
+ arc_disassembler_options = xstrdup ("cpu=em4_fpuda");
+ break;
+ default:
+ arc_disassembler_options = NULL;
+ break;
+ }
+ set_gdbarch_disassembler_options (gdbarch,
+ &arc_disassembler_options);
+ }
+ }
+
tdesc_use_registers (gdbarch, tdesc, tdesc_data);
return gdbarch;
/* Wrapper for "maintenance print arc" list of commands. */
static void
-maintenance_print_arc_command (char *args, int from_tty)
+maintenance_print_arc_command (const char *args, int from_tty)
{
cmd_show_list (maintenance_print_arc_list, from_tty, "");
}
disassemble. */
static void
-dump_arc_instruction_command (char *args, int from_tty)
+dump_arc_instruction_command (const char *args, int from_tty)
{
struct value *val;
if (args != NULL && strlen (args) > 0)
arc_insn_dump (insn);
}
-/* Suppress warning from -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_arc_tdep;
-
void
_initialize_arc_tdep (void)
{