-/* Target dependent code for ARC arhitecture, for GDB.
+/* Target dependent code for ARC architecture, for GDB.
- Copyright 2005-2017 Free Software Foundation, Inc.
+ Copyright 2005-2022 Free Software Foundation, Inc.
Contributed by Synopsys Inc.
This file is part of GDB.
/* GDB header files. */
#include "defs.h"
#include "arch-utils.h"
+#include "elf-bfd.h"
#include "disasm.h"
-#include "dwarf2-frame.h"
+#include "dwarf2/frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "gdbcore.h"
+#include "reggroups.h"
#include "gdbcmd.h"
#include "objfiles.h"
+#include "osabi.h"
#include "prologue-value.h"
+#include "target-descriptions.h"
#include "trad-frame.h"
/* ARC header files. */
#include "opcode/arc.h"
#include "opcodes/arc-dis.h"
#include "arc-tdep.h"
+#include "arch/arc.h"
/* Standard headers. */
#include <algorithm>
-
-/* Default target descriptions. */
-#include "features/arc-v2.c"
-#include "features/arc-arcompact.c"
+#include <sstream>
/* The frame unwind cache for ARC. */
/* Store addresses for registers saved in prologue. During prologue analysis
GDB stores offsets relatively to "old SP", then after old SP is evaluated,
offsets are replaced with absolute addresses. */
- struct trad_frame_saved_reg *saved_regs;
+ trad_frame_saved_reg *saved_regs;
};
/* Global debug flag. */
-int arc_debug;
+bool arc_debug;
/* List of "maintenance print arc" commands. */
static struct cmd_list_element *maintenance_print_arc_list = NULL;
-/* XML target description features. */
-
-static const char core_v2_feature_name[] = "org.gnu.gdb.arc.core.v2";
-static const char
- core_reduced_v2_feature_name[] = "org.gnu.gdb.arc.core-reduced.v2";
-static const char
- core_arcompact_feature_name[] = "org.gnu.gdb.arc.core.arcompact";
-static const char aux_minimal_feature_name[] = "org.gnu.gdb.arc.aux-minimal";
-
-/* XML target description known registers. */
-
-static const char *const core_v2_register_names[] = {
- "r0", "r1", "r2", "r3",
- "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11",
- "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19",
- "r20", "r21", "r22", "r23",
- "r24", "r25", "gp", "fp",
- "sp", "ilink", "r30", "blink",
- "r32", "r33", "r34", "r35",
- "r36", "r37", "r38", "r39",
- "r40", "r41", "r42", "r43",
- "r44", "r45", "r46", "r47",
- "r48", "r49", "r50", "r51",
- "r52", "r53", "r54", "r55",
- "r56", "r57", "accl", "acch",
- "lp_count", "reserved", "limm", "pcl",
+/* A set of registers that we expect to find in a tdesc_feature. These
+ are used in ARC_TDESC_INIT when processing the target description. */
+
+struct arc_register_feature
+{
+ /* Information for a single register. */
+ struct register_info
+ {
+ /* The GDB register number for this register. */
+ int regnum;
+
+ /* List of names for this register. The first name in this list is the
+ preferred name, the name GDB will use when describing this register. */
+ std::vector<const char *> names;
+
+ /* When true, this register must be present in this feature set. */
+ bool required_p;
+ };
+
+ /* The name for this feature. This is the name used to find this feature
+ within the target description. */
+ const char *name;
+
+ /* List of all the registers that we expect to encounter in this register
+ set. */
+ std::vector<struct register_info> registers;
+};
+
+/* Obsolete feature names for backward compatibility. */
+static const char *ARC_CORE_V1_OBSOLETE_FEATURE_NAME
+ = "org.gnu.gdb.arc.core.arcompact";
+static const char *ARC_CORE_V2_OBSOLETE_FEATURE_NAME
+ = "org.gnu.gdb.arc.core.v2";
+static const char *ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME
+ = "org.gnu.gdb.arc.core-reduced.v2";
+static const char *ARC_AUX_OBSOLETE_FEATURE_NAME
+ = "org.gnu.gdb.arc.aux-minimal";
+/* Modern feature names. */
+static const char *ARC_CORE_FEATURE_NAME = "org.gnu.gdb.arc.core";
+static const char *ARC_AUX_FEATURE_NAME = "org.gnu.gdb.arc.aux";
+
+/* ARCv1 (ARC600, ARC601, ARC700) general core registers feature set.
+ See also arc_update_acc_reg_names() for "accl/acch" names. */
+
+static struct arc_register_feature arc_v1_core_reg_feature =
+{
+ ARC_CORE_FEATURE_NAME,
+ {
+ { ARC_R0_REGNUM + 0, { "r0" }, true },
+ { ARC_R0_REGNUM + 1, { "r1" }, true },
+ { ARC_R0_REGNUM + 2, { "r2" }, true },
+ { ARC_R0_REGNUM + 3, { "r3" }, true },
+ { ARC_R0_REGNUM + 4, { "r4" }, false },
+ { ARC_R0_REGNUM + 5, { "r5" }, false },
+ { ARC_R0_REGNUM + 6, { "r6" }, false },
+ { ARC_R0_REGNUM + 7, { "r7" }, false },
+ { ARC_R0_REGNUM + 8, { "r8" }, false },
+ { ARC_R0_REGNUM + 9, { "r9" }, false },
+ { ARC_R0_REGNUM + 10, { "r10" }, true },
+ { ARC_R0_REGNUM + 11, { "r11" }, true },
+ { ARC_R0_REGNUM + 12, { "r12" }, true },
+ { ARC_R0_REGNUM + 13, { "r13" }, true },
+ { ARC_R0_REGNUM + 14, { "r14" }, true },
+ { ARC_R0_REGNUM + 15, { "r15" }, true },
+ { ARC_R0_REGNUM + 16, { "r16" }, false },
+ { ARC_R0_REGNUM + 17, { "r17" }, false },
+ { ARC_R0_REGNUM + 18, { "r18" }, false },
+ { ARC_R0_REGNUM + 19, { "r19" }, false },
+ { ARC_R0_REGNUM + 20, { "r20" }, false },
+ { ARC_R0_REGNUM + 21, { "r21" }, false },
+ { ARC_R0_REGNUM + 22, { "r22" }, false },
+ { ARC_R0_REGNUM + 23, { "r23" }, false },
+ { ARC_R0_REGNUM + 24, { "r24" }, false },
+ { ARC_R0_REGNUM + 25, { "r25" }, false },
+ { ARC_R0_REGNUM + 26, { "gp" }, true },
+ { ARC_R0_REGNUM + 27, { "fp" }, true },
+ { ARC_R0_REGNUM + 28, { "sp" }, true },
+ { ARC_R0_REGNUM + 29, { "ilink1" }, false },
+ { ARC_R0_REGNUM + 30, { "ilink2" }, false },
+ { ARC_R0_REGNUM + 31, { "blink" }, true },
+ { ARC_R0_REGNUM + 32, { "r32" }, false },
+ { ARC_R0_REGNUM + 33, { "r33" }, false },
+ { ARC_R0_REGNUM + 34, { "r34" }, false },
+ { ARC_R0_REGNUM + 35, { "r35" }, false },
+ { ARC_R0_REGNUM + 36, { "r36" }, false },
+ { ARC_R0_REGNUM + 37, { "r37" }, false },
+ { ARC_R0_REGNUM + 38, { "r38" }, false },
+ { ARC_R0_REGNUM + 39, { "r39" }, false },
+ { ARC_R0_REGNUM + 40, { "r40" }, false },
+ { ARC_R0_REGNUM + 41, { "r41" }, false },
+ { ARC_R0_REGNUM + 42, { "r42" }, false },
+ { ARC_R0_REGNUM + 43, { "r43" }, false },
+ { ARC_R0_REGNUM + 44, { "r44" }, false },
+ { ARC_R0_REGNUM + 45, { "r45" }, false },
+ { ARC_R0_REGNUM + 46, { "r46" }, false },
+ { ARC_R0_REGNUM + 47, { "r47" }, false },
+ { ARC_R0_REGNUM + 48, { "r48" }, false },
+ { ARC_R0_REGNUM + 49, { "r49" }, false },
+ { ARC_R0_REGNUM + 50, { "r50" }, false },
+ { ARC_R0_REGNUM + 51, { "r51" }, false },
+ { ARC_R0_REGNUM + 52, { "r52" }, false },
+ { ARC_R0_REGNUM + 53, { "r53" }, false },
+ { ARC_R0_REGNUM + 54, { "r54" }, false },
+ { ARC_R0_REGNUM + 55, { "r55" }, false },
+ { ARC_R0_REGNUM + 56, { "r56" }, false },
+ { ARC_R0_REGNUM + 57, { "r57" }, false },
+ { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
+ { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
+ { ARC_R0_REGNUM + 60, { "lp_count" }, false },
+ { ARC_R0_REGNUM + 61, { "reserved" }, false },
+ { ARC_R0_REGNUM + 62, { "limm" }, false },
+ { ARC_R0_REGNUM + 63, { "pcl" }, true }
+ }
};
-static const char *const aux_minimal_register_names[] = {
- "pc", "status32",
+/* ARCv2 (ARCHS) general core registers feature set. See also
+ arc_update_acc_reg_names() for "accl/acch" names. */
+
+static struct arc_register_feature arc_v2_core_reg_feature =
+{
+ ARC_CORE_FEATURE_NAME,
+ {
+ { ARC_R0_REGNUM + 0, { "r0" }, true },
+ { ARC_R0_REGNUM + 1, { "r1" }, true },
+ { ARC_R0_REGNUM + 2, { "r2" }, true },
+ { ARC_R0_REGNUM + 3, { "r3" }, true },
+ { ARC_R0_REGNUM + 4, { "r4" }, false },
+ { ARC_R0_REGNUM + 5, { "r5" }, false },
+ { ARC_R0_REGNUM + 6, { "r6" }, false },
+ { ARC_R0_REGNUM + 7, { "r7" }, false },
+ { ARC_R0_REGNUM + 8, { "r8" }, false },
+ { ARC_R0_REGNUM + 9, { "r9" }, false },
+ { ARC_R0_REGNUM + 10, { "r10" }, true },
+ { ARC_R0_REGNUM + 11, { "r11" }, true },
+ { ARC_R0_REGNUM + 12, { "r12" }, true },
+ { ARC_R0_REGNUM + 13, { "r13" }, true },
+ { ARC_R0_REGNUM + 14, { "r14" }, true },
+ { ARC_R0_REGNUM + 15, { "r15" }, true },
+ { ARC_R0_REGNUM + 16, { "r16" }, false },
+ { ARC_R0_REGNUM + 17, { "r17" }, false },
+ { ARC_R0_REGNUM + 18, { "r18" }, false },
+ { ARC_R0_REGNUM + 19, { "r19" }, false },
+ { ARC_R0_REGNUM + 20, { "r20" }, false },
+ { ARC_R0_REGNUM + 21, { "r21" }, false },
+ { ARC_R0_REGNUM + 22, { "r22" }, false },
+ { ARC_R0_REGNUM + 23, { "r23" }, false },
+ { ARC_R0_REGNUM + 24, { "r24" }, false },
+ { ARC_R0_REGNUM + 25, { "r25" }, false },
+ { ARC_R0_REGNUM + 26, { "gp" }, true },
+ { ARC_R0_REGNUM + 27, { "fp" }, true },
+ { ARC_R0_REGNUM + 28, { "sp" }, true },
+ { ARC_R0_REGNUM + 29, { "ilink" }, false },
+ { ARC_R0_REGNUM + 30, { "r30" }, true },
+ { ARC_R0_REGNUM + 31, { "blink" }, true },
+ { ARC_R0_REGNUM + 32, { "r32" }, false },
+ { ARC_R0_REGNUM + 33, { "r33" }, false },
+ { ARC_R0_REGNUM + 34, { "r34" }, false },
+ { ARC_R0_REGNUM + 35, { "r35" }, false },
+ { ARC_R0_REGNUM + 36, { "r36" }, false },
+ { ARC_R0_REGNUM + 37, { "r37" }, false },
+ { ARC_R0_REGNUM + 38, { "r38" }, false },
+ { ARC_R0_REGNUM + 39, { "r39" }, false },
+ { ARC_R0_REGNUM + 40, { "r40" }, false },
+ { ARC_R0_REGNUM + 41, { "r41" }, false },
+ { ARC_R0_REGNUM + 42, { "r42" }, false },
+ { ARC_R0_REGNUM + 43, { "r43" }, false },
+ { ARC_R0_REGNUM + 44, { "r44" }, false },
+ { ARC_R0_REGNUM + 45, { "r45" }, false },
+ { ARC_R0_REGNUM + 46, { "r46" }, false },
+ { ARC_R0_REGNUM + 47, { "r47" }, false },
+ { ARC_R0_REGNUM + 48, { "r48" }, false },
+ { ARC_R0_REGNUM + 49, { "r49" }, false },
+ { ARC_R0_REGNUM + 50, { "r50" }, false },
+ { ARC_R0_REGNUM + 51, { "r51" }, false },
+ { ARC_R0_REGNUM + 52, { "r52" }, false },
+ { ARC_R0_REGNUM + 53, { "r53" }, false },
+ { ARC_R0_REGNUM + 54, { "r54" }, false },
+ { ARC_R0_REGNUM + 55, { "r55" }, false },
+ { ARC_R0_REGNUM + 56, { "r56" }, false },
+ { ARC_R0_REGNUM + 57, { "r57" }, false },
+ { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
+ { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
+ { ARC_R0_REGNUM + 60, { "lp_count" }, false },
+ { ARC_R0_REGNUM + 61, { "reserved" }, false },
+ { ARC_R0_REGNUM + 62, { "limm" }, false },
+ { ARC_R0_REGNUM + 63, { "pcl" }, true }
+ }
};
-static const char *const core_arcompact_register_names[] = {
- "r0", "r1", "r2", "r3",
- "r4", "r5", "r6", "r7",
- "r8", "r9", "r10", "r11",
- "r12", "r13", "r14", "r15",
- "r16", "r17", "r18", "r19",
- "r20", "r21", "r22", "r23",
- "r24", "r25", "gp", "fp",
- "sp", "ilink1", "ilink2", "blink",
- "r32", "r33", "r34", "r35",
- "r36", "r37", "r38", "r39",
- "r40", "r41", "r42", "r43",
- "r44", "r45", "r46", "r47",
- "r48", "r49", "r50", "r51",
- "r52", "r53", "r54", "r55",
- "r56", "r57", "r58", "r59",
- "lp_count", "reserved", "limm", "pcl",
+/* The common auxiliary registers feature set. The REGNUM field
+ must match the ARC_REGNUM enum in arc-tdep.h. */
+
+static const struct arc_register_feature arc_common_aux_reg_feature =
+{
+ ARC_AUX_FEATURE_NAME,
+ {
+ { ARC_FIRST_AUX_REGNUM + 0, { "pc" }, true },
+ { ARC_FIRST_AUX_REGNUM + 1, { "status32" }, true },
+ { ARC_FIRST_AUX_REGNUM + 2, { "lp_start" }, false },
+ { ARC_FIRST_AUX_REGNUM + 3, { "lp_end" }, false },
+ { ARC_FIRST_AUX_REGNUM + 4, { "bta" }, false }
+ }
};
+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. */
/* Get register with base address of memory operation. */
-int
+static int
arc_insn_get_memory_base_reg (const struct arc_instruction &insn)
{
/* POP_S and PUSH_S have SP as an implicit argument in a disassembler. */
/* Get offset of a memory operation INSN. */
-CORE_ADDR
+static CORE_ADDR
arc_insn_get_memory_offset (const struct arc_instruction &insn)
{
/* POP_S and PUSH_S have offset as an implicit argument in a
/* JLI and EI depend on optional AUX registers. Not supported right now. */
else if (insn.insn_class == JLI)
{
- fprintf_unfiltered (gdb_stderr,
- "JLI_S instruction is not supported by the GDB.");
+ gdb_printf (gdb_stderr,
+ "JLI_S instruction is not supported by the GDB.");
return 0;
}
else if (insn.insn_class == EI)
{
- fprintf_unfiltered (gdb_stderr,
- "EI_S instruction is not supported by the GDB.");
+ gdb_printf (gdb_stderr,
+ "EI_S instruction is not supported by the GDB.");
return 0;
}
/* LEAVE_S: PC = BLINK. */
/* Dump INSN into gdb_stdlog. */
-void
+static void
arc_insn_dump (const struct arc_instruction &insn)
{
struct gdbarch *gdbarch = target_gdbarch ();
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",
- paddress (gdbarch, new_pc));
+ arc_debug_printf ("Writing PC, new value=%s",
+ paddress (gdbarch, new_pc));
regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
new_pc);
regcache_cooked_read_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
&status32);
- /* Mask for DE bit is 0x40. */
- if (status32 & 0x40)
+ if ((status32 & ARC_STATUS32_DE_MASK) != 0)
{
- if (arc_debug)
- {
- debug_printf ("arc: Changing PC while in delay slot. Will "
+ arc_debug_printf ("Changing PC while in delay slot. Will "
"reset STATUS32.DE bit to zero. Value of STATUS32 "
- "register is 0x%s\n",
+ "register is 0x%s",
phex (status32, ARC_REGISTER_SIZE));
- }
/* Reset bit and write to the cache. */
status32 &= ~0x40;
*offset_ptr = 0;
}
-/* Implement the "dummy_id" gdbarch method.
-
- Tear down a dummy frame created by arc_push_dummy_call (). This data has
- to be constructed manually from the data in our hand. The stack pointer
- and program counter can be obtained from the frame info. */
-
-static struct frame_id
-arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
-{
- return frame_id_build (get_frame_sp (this_frame),
- get_frame_pc (this_frame));
-}
-
/* Implement the "push_dummy_call" gdbarch method.
Stack Frame Layout
The stack grows downward, so SP points below FP in memory; SP always
points to the last used word on the stack, not the first one.
- | | |
- | arg word N | | caller's
- | : | | frame
- | arg word 10 | |
- | arg word 9 | |
- old SP ---> +-----------------------+ --+
- | | |
- | callee-saved | |
- | registers | |
- | including fp, blink | |
- | | | callee's
- new FP ---> +-----------------------+ | frame
- | | |
- | local | |
- | variables | |
- | | |
- | register | |
- | spill area | |
- | | |
- | outgoing args | |
- | | |
- new SP ---> +-----------------------+ --+
- | |
- | unused |
- | |
- |
- |
- V
- downwards
+ | | |
+ | arg word N | | caller's
+ | : | | frame
+ | arg word 10 | |
+ | arg word 9 | |
+ old SP ---> +-----------------------+ --+
+ | | |
+ | callee-saved | |
+ | registers | |
+ | including fp, blink | |
+ | | | callee's
+ new FP ---> +-----------------------+ | frame
+ | | |
+ | local | |
+ | variables | |
+ | | |
+ | register | |
+ | spill area | |
+ | | |
+ | outgoing args | |
+ | | |
+ new SP ---> +-----------------------+ --+
+ | |
+ | unused |
+ | |
+ |
+ |
+ V
+ downwards
The list of arguments to be passed to a function is considered to be a
sequence of _N_ words (as though all the parameters were stored in order in
static CORE_ADDR
arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
+ struct value **args, CORE_ADDR sp,
+ function_call_return_method return_method,
CORE_ADDR struct_addr)
{
- if (arc_debug)
- debug_printf ("arc: push_dummy_call (nargs = %d)\n", nargs);
+ arc_debug_printf ("nargs = %d", nargs);
int arg_reg = ARC_FIRST_ARG_REGNUM;
value return? If so, struct_addr is the address of the reserved space for
the return structure to be written on the stack, and that address is
passed to that function as a hidden first argument. */
- if (struct_return)
+ if (return_method == return_method_struct)
{
/* Pass the return address in the first argument register. */
regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
- if (arc_debug)
- debug_printf ("arc: struct return address %s passed in R%d",
- print_core_address (gdbarch, struct_addr), arg_reg);
+ arc_debug_printf ("struct return address %s passed in R%d",
+ print_core_address (gdbarch, struct_addr), arg_reg);
arg_reg++;
}
total_space += space;
- if (arc_debug)
- debug_printf ("arc: arg %d: %u bytes -> %u\n", i, len, space);
+ arc_debug_printf ("arg %d: %u bytes -> %u", i, len, space);
}
/* Allocate a buffer to hold a memory image of the arguments. */
unsigned int len = TYPE_LENGTH (value_type (args[i]));
unsigned int space = align_up (len, 4);
- memcpy (data, value_contents (args[i]), (size_t) len);
- if (arc_debug)
- debug_printf ("arc: copying arg %d, val 0x%08x, len %d to mem\n",
- i, *((int *) value_contents (args[i])), len);
+ memcpy (data, value_contents (args[i]).data (), (size_t) len);
+ arc_debug_printf ("copying arg %d, val 0x%08x, len %d to mem",
+ i, *((int *) value_contents (args[i]).data ()),
+ len);
data += space;
}
data = memory_image;
while (arg_reg <= ARC_LAST_ARG_REGNUM)
{
- if (arc_debug)
- debug_printf ("arc: passing 0x%02x%02x%02x%02x in register R%d\n",
- data[0], data[1], data[2], data[3], arg_reg);
+ arc_debug_printf ("passing 0x%02x%02x%02x%02x in register R%d",
+ data[0], data[1], data[2], data[3], arg_reg);
/* Note we don't use write_unsigned here, since that would convert
the byte order, but we are already in the correct byte order. */
- regcache_cooked_write (regcache, arg_reg, data);
+ regcache->cooked_write (arg_reg, data);
data += ARC_REGISTER_SIZE;
total_space -= ARC_REGISTER_SIZE;
operation). */
if (total_space > 0)
{
- if (arc_debug)
- debug_printf ("arc: passing %d bytes on stack\n", total_space);
+ arc_debug_printf ("passing %d bytes on stack\n", total_space);
sp -= total_space;
write_memory (sp, data, (int) total_space);
{
unsigned int len = TYPE_LENGTH (type);
- if (arc_debug)
- debug_printf ("arc: extract_return_value\n");
+ arc_debug_printf ("called");
if (len <= ARC_REGISTER_SIZE)
{
store_unsigned_integer (valbuf, (int) len,
gdbarch_byte_order (gdbarch), val);
- if (arc_debug)
- debug_printf ("arc: returning 0x%s\n", phex (val, ARC_REGISTER_SIZE));
+ arc_debug_printf ("returning 0x%s", phex (val, ARC_REGISTER_SIZE));
}
else if (len <= ARC_REGISTER_SIZE * 2)
{
(int) len - ARC_REGISTER_SIZE,
gdbarch_byte_order (gdbarch), high);
- if (arc_debug)
- debug_printf ("arc: returning 0x%s%s\n",
- phex (high, ARC_REGISTER_SIZE),
- phex (low, ARC_REGISTER_SIZE));
+ arc_debug_printf ("returning 0x%s%s",
+ phex (high, ARC_REGISTER_SIZE),
+ phex (low, ARC_REGISTER_SIZE));
}
else
error (_("arc: extract_return_value: type length %u too large"), len);
{
unsigned int len = TYPE_LENGTH (type);
- if (arc_debug)
- debug_printf ("arc: store_return_value\n");
+ arc_debug_printf ("called");
if (len <= ARC_REGISTER_SIZE)
{
gdbarch_byte_order (gdbarch));
regcache_cooked_write_unsigned (regcache, ARC_R0_REGNUM, val);
- if (arc_debug)
- debug_printf ("arc: storing 0x%s\n", phex (val, ARC_REGISTER_SIZE));
+ arc_debug_printf ("storing 0x%s", phex (val, ARC_REGISTER_SIZE));
}
else if (len <= ARC_REGISTER_SIZE * 2)
{
regcache_cooked_write_unsigned (regcache, ARC_R0_REGNUM, low);
regcache_cooked_write_unsigned (regcache, ARC_R1_REGNUM, high);
- if (arc_debug)
- debug_printf ("arc: storing 0x%s%s\n",
- phex (high, ARC_REGISTER_SIZE),
- phex (low, ARC_REGISTER_SIZE));
+ arc_debug_printf ("storing 0x%s%s",
+ phex (high, ARC_REGISTER_SIZE),
+ phex (low, ARC_REGISTER_SIZE));
}
else
error (_("arc_store_return_value: type length too large."));
static int
arc_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
{
- if (arc_debug)
- debug_printf ("arc: get_longjmp_target\n");
+ arc_debug_printf ("called");
struct gdbarch *gdbarch = get_frame_arch (frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
int pc_offset = tdep->jb_pc * ARC_REGISTER_SIZE;
gdb_byte buf[ARC_REGISTER_SIZE];
CORE_ADDR jb_addr = get_frame_register_unsigned (frame, ARC_FIRST_ARG_REGNUM);
function passes a hidden first parameter to the callee (in R0). That
parameter is the address at which the value being returned should be
stored. Otherwise, the result is returned in registers. */
- int is_struct_return = (TYPE_CODE (valtype) == TYPE_CODE_STRUCT
- || TYPE_CODE (valtype) == TYPE_CODE_UNION
+ int is_struct_return = (valtype->code () == TYPE_CODE_STRUCT
+ || valtype->code () == TYPE_CODE_UNION
|| TYPE_LENGTH (valtype) > 2 * ARC_REGISTER_SIZE);
- if (arc_debug)
- debug_printf ("arc: return_value (readbuf = %s, writebuf = %s)\n",
- host_address_to_string (readbuf),
- host_address_to_string (writebuf));
+ arc_debug_printf ("readbuf = %s, writebuf = %s",
+ host_address_to_string (readbuf),
+ host_address_to_string (writebuf));
if (writebuf != NULL)
{
/* Store of some register. May or may not update base address register. */
if (insn.insn_class == STORE || insn.insn_class == PUSH)
{
- /* There is definetely at least one operand - register/value being
+ /* There is definitely at least one operand - register/value being
stored. */
gdb_assert (insn.operands_count > 0);
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));
return false;
}
-/* Copy of gdb_buffered_insn_length_fprintf from disasm.c. */
-
-static int ATTRIBUTE_PRINTF (2, 3)
-arc_fprintf_disasm (void *stream, const char *format, ...)
-{
- return 0;
-}
+/* See arc-tdep.h. */
struct disassemble_info
arc_disassemble_info (struct gdbarch *gdbarch)
{
struct disassemble_info di;
- init_disassemble_info (&di, &null_stream, arc_fprintf_disasm);
+ init_disassemble_info_for_no_printing (&di);
di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
di.endian = gdbarch_byte_order (gdbarch);
If CACHE is not NULL, then it will be filled with information about saved
registers.
- There are several variations of prologue which GDB may encouter. "Full"
+ There are several variations of prologue which GDB may encounter. "Full"
prologue looks like this:
sub sp,sp,<imm> ; Space for variadic arguments.
store, that doesn't update SP. Like this:
- sub sp,sp,8 ; Create space for calee-saved registers.
+ sub sp,sp,8 ; Create space for callee-saved registers.
st r13,[sp,4] ; Store callee saved registers (up to R26/GP).
st r14,[sp,0]
arc_analyze_prologue (struct gdbarch *gdbarch, const CORE_ADDR entrypoint,
const CORE_ADDR limit_pc, struct arc_frame_cache *cache)
{
- if (arc_debug)
- debug_printf ("arc: analyze_prologue (entrypoint=%s, limit_pc=%s)\n",
- paddress (gdbarch, entrypoint),
- paddress (gdbarch, limit_pc));
+ arc_debug_printf ("entrypoint=%s, limit_pc=%s",
+ paddress (gdbarch, entrypoint),
+ paddress (gdbarch, limit_pc));
/* Prologue values. Only core registers can be stored. */
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;
arc_insn_decode (current_prologue_end, &di, arc_delayed_print_insn,
&insn);
- if (arc_debug >= 2)
+ if (arc_debug)
arc_insn_dump (insn);
/* 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)
- debug_printf ("arc: End of prologue reached at address %s\n",
- paddress (gdbarch, insn.address));
+ arc_debug_printf ("End of prologue reached at address %s",
+ paddress (gdbarch, insn.address));
break;
}
for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
{
CORE_ADDR offset;
- if (pv_area_find_reg (stack, gdbarch, i, &offset))
- cache->saved_regs[i].addr = offset;
+ if (stack.find_reg (gdbarch, i, &offset))
+ cache->saved_regs[i].set_addr (offset);
}
}
- do_cleanups (back_to);
return current_prologue_end;
}
static CORE_ADDR
arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- if (arc_debug)
- debug_printf ("arc: skip_prologue\n");
+ arc_debug_printf ("pc = %s", paddress (gdbarch, pc));
CORE_ADDR func_addr;
const char *func_name;
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 libopcodes 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.
static const gdb_byte *
arc_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
{
+ gdb_assert (kind == 2 || kind == 4);
*size = kind;
if (kind == sizeof (arc_brk_le))
}
}
-/* Implement the "unwind_pc" gdbarch method. */
-
-static CORE_ADDR
-arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- int pc_regnum = gdbarch_pc_regnum (gdbarch);
- CORE_ADDR pc = frame_unwind_register_unsigned (next_frame, pc_regnum);
-
- if (arc_debug)
- debug_printf ("arc: unwind PC: %s\n", paddress (gdbarch, pc));
-
- return pc;
-}
-
-/* Implement the "unwind_sp" gdbarch method. */
-
-static CORE_ADDR
-arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- int sp_regnum = gdbarch_sp_regnum (gdbarch);
- CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, sp_regnum);
-
- if (arc_debug)
- debug_printf ("arc: unwind SP: %s\n", paddress (gdbarch, sp));
-
- return sp;
-}
-
/* Implement the "frame_align" gdbarch method. */
static CORE_ADDR
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);
- debug_printf ("arc: prev_sp = %s\n", paddress (gdbarch, cache->prev_sp));
- debug_printf ("arc: frame_base_reg = %i\n", cache->frame_base_reg);
- debug_printf ("arc: frame_base_offset = %s\n",
- plongest (cache->frame_base_offset));
+ arc_debug_printf ("frame_info %s", message);
+ arc_debug_printf ("prev_sp = %s", paddress (gdbarch, cache->prev_sp));
+ arc_debug_printf ("frame_base_reg = %i", cache->frame_base_reg);
+ arc_debug_printf ("frame_base_offset = %s",
+ plongest (cache->frame_base_offset));
for (int i = 0; i <= ARC_BLINK_REGNUM; i++)
{
- if (trad_frame_addr_p (cache->saved_regs, i))
- debug_printf ("arc: saved register %s at %s %s\n",
- gdbarch_register_name (gdbarch, i),
- (addresses_known) ? "address" : "offset",
- paddress (gdbarch, cache->saved_regs[i].addr));
+ if (cache->saved_regs[i].is_addr ())
+ arc_debug_printf ("saved register %s at %s %s",
+ gdbarch_register_name (gdbarch, i),
+ (addresses_known) ? "address" : "offset",
+ paddress (gdbarch, cache->saved_regs[i].addr ()));
}
}
static struct arc_frame_cache *
arc_make_frame_cache (struct frame_info *this_frame)
{
- if (arc_debug)
- debug_printf ("arc: frame_cache\n");
+ arc_debug_printf ("called");
struct gdbarch *gdbarch = get_frame_arch (this_frame);
for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
{
- if (trad_frame_addr_p (cache->saved_regs, i))
- cache->saved_regs[i].addr += cache->prev_sp;
+ if (cache->saved_regs[i].is_addr ())
+ cache->saved_regs[i].set_addr (cache->saved_regs[i].addr ()
+ + cache->prev_sp);
}
if (arc_debug)
arc_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
- if (arc_debug)
- debug_printf ("arc: frame_this_id\n");
+ arc_debug_printf ("called");
struct gdbarch *gdbarch = get_frame_arch (this_frame);
reg->how = DWARF2_FRAME_REG_CFA;
}
+/* Signal trampoline frame unwinder. Allows frame unwinding to happen
+ from within signal handlers. */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+ arc_debug_printf ("called");
+
+ gdbarch *arch = get_frame_arch (this_frame);
+ arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
+
+ /* Allocate new frame cache instance and space for saved register info. */
+ struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+ /* Get the stack pointer and use it as the frame base. */
+ cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+ /* If the ARC-private target-dependent info doesn't have a table of
+ offsets of saved register contents within an OS signal context
+ structure, then there is nothing to analyze. */
+ if (tdep->sc_reg_offset == NULL)
+ return cache;
+
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+ for (int i = 0; i < tdep->sc_num_regs; i++)
+ {
+ if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+ cache->saved_regs[i].set_addr (addr + tdep->sc_reg_offset[i]);
+ }
+
+ return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+ frames. */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+ void **this_cache, struct frame_id *this_id)
+{
+ arc_debug_printf ("called");
+
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ CORE_ADDR stack_addr = cache->prev_sp;
+ CORE_ADDR code_addr
+ = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+ *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame. */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ arc_debug_printf ("regnum = %d", regnum);
+
+ /* Make sure we've initialized the cache. */
+ if (*this_cache == NULL)
+ *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+ struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+ return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame. Only recognize a frame if we
+ have a sigcontext_addr handler in the target dependency. */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
+{
+ arc_debug_printf ("called");
+
+ gdbarch *arch = get_frame_arch (this_frame);
+ arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
+
+ /* If we have a sigcontext_addr handler, then just return 1 (same as the
+ "default_frame_sniffer ()"). */
+ return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
+ && tdep->is_sigtramp (this_frame));
+}
+
/* Structure defining the ARC ordinary frame unwind functions. Since we are
the fallback unwinder, we use the default frame sniffer, which always
accepts the frame. */
static const struct frame_unwind arc_frame_unwind = {
+ "arc prologue",
NORMAL_FRAME,
default_frame_unwind_stop_reason,
arc_frame_this_id,
NULL
};
+/* Structure defining the ARC signal frame unwind functions. Custom
+ sniffer is used, because this frame must be accepted only in the right
+ context. */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+ "arc sigtramp",
+ SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
+ arc_sigtramp_frame_this_id,
+ arc_sigtramp_frame_prev_register,
+ NULL,
+ arc_sigtramp_frame_sniffer,
+ NULL,
+ NULL
+};
+
static const struct frame_base arc_normal_base = {
&arc_frame_unwind,
arc_frame_base_address
};
-/* Initialize target description for the ARC.
-
- Returns TRUE if input tdesc was valid and in this case it will assign TDESC
- and TDESC_DATA output parameters. */
-
-static int
-arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
- struct tdesc_arch_data **tdesc_data)
+static enum arc_isa
+mach_type_to_arc_isa (const unsigned long mach)
{
- if (arc_debug)
- debug_printf ("arc: Target description initialization.\n");
+ switch (mach)
+ {
+ case bfd_mach_arc_arc600:
+ case bfd_mach_arc_arc601:
+ case bfd_mach_arc_arc700:
+ return ARC_ISA_ARCV1;
+ case bfd_mach_arc_arcv2:
+ return ARC_ISA_ARCV2;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("unknown machine id %lu"), mach);
+ }
+}
- const struct target_desc *tdesc_loc = info.target_desc;
+/* See arc-tdep.h. */
- /* Depending on whether this is ARCompact or ARCv2 we will assign
- different default registers sets (which will differ in exactly two core
- registers). GDB will also refuse to accept register feature from invalid
- ISA - v2 features can be used only with v2 ARChitecture. We read
- bfd_arch_info, which looks like to be a safe bet here, as it looks like it
- is always initialized even when we don't pass any elf file to GDB at all
- (it uses default arch in this case). Also GDB will call this function
- multiple times, and if XML target description file contains architecture
- specifications, then GDB will set this architecture to info.bfd_arch_info,
- overriding value from ELF file if they are different. That means that,
- where matters, this value is always our best guess on what CPU we are
- debugging. It has been noted that architecture specified in tdesc file
- has higher precedence over ELF and even "set architecture" - that is,
- using "set architecture" command will have no effect when tdesc has "arch"
- tag. */
- /* Cannot use arc_mach_is_arcv2 (), because gdbarch is not created yet. */
- const int is_arcv2 = (info.bfd_arch_info->mach == bfd_mach_arc_arcv2);
- int is_reduced_rf;
- const char *const *core_regs;
- const char *core_feature_name;
-
- /* If target doesn't provide a description - use default one. */
- if (!tdesc_has_registers (tdesc_loc))
+arc_arch_features
+arc_arch_features_create (const bfd *abfd, const unsigned long mach)
+{
+ /* Use 4 as a fallback value. */
+ int reg_size = 4;
+
+ /* Try to guess the features parameters by looking at the binary to be
+ executed. If the user is providing a binary that does not match the
+ target, then tough luck. This is the last effort to makes sense of
+ what's going on. */
+ if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
{
- if (is_arcv2)
- {
- tdesc_loc = tdesc_arc_v2;
- if (arc_debug)
- debug_printf ("arc: Using default register set for ARC v2.\n");
- }
+ unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
+
+ if (eclass == ELFCLASS32)
+ reg_size = 4;
+ else if (eclass == ELFCLASS64)
+ reg_size = 8;
else
- {
- tdesc_loc = tdesc_arc_arcompact;
- if (arc_debug)
- debug_printf ("arc: Using default register set for ARCompact.\n");
- }
+ internal_error (__FILE__, __LINE__,
+ _("unknown ELF header class %d"), eclass);
}
- else
+
+ /* MACH from a bfd_arch_info struct is used here. It should be a safe
+ bet, as it looks like the struct is always initialized even when we
+ don't pass any elf file to GDB at all (it uses default arch in that
+ case). */
+ arc_isa isa = mach_type_to_arc_isa (mach);
+
+ return arc_arch_features (reg_size, isa);
+}
+
+/* Look for obsolete core feature names in TDESC. */
+
+static const struct tdesc_feature *
+find_obsolete_core_names (const struct target_desc *tdesc)
+{
+ const struct tdesc_feature *feat = nullptr;
+
+ feat = tdesc_find_feature (tdesc, ARC_CORE_V1_OBSOLETE_FEATURE_NAME);
+
+ if (feat == nullptr)
+ feat = tdesc_find_feature (tdesc, ARC_CORE_V2_OBSOLETE_FEATURE_NAME);
+
+ if (feat == nullptr)
+ feat = tdesc_find_feature
+ (tdesc, ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME);
+
+ return feat;
+}
+
+/* Look for obsolete aux feature names in TDESC. */
+
+static const struct tdesc_feature *
+find_obsolete_aux_names (const struct target_desc *tdesc)
+{
+ return tdesc_find_feature (tdesc, ARC_AUX_OBSOLETE_FEATURE_NAME);
+}
+
+/* Based on the MACH value, determines which core register features set
+ must be used. */
+
+static arc_register_feature *
+determine_core_reg_feature_set (const unsigned long mach)
+{
+ switch (mach_type_to_arc_isa (mach))
{
- if (arc_debug)
- debug_printf ("arc: Using provided register set.\n");
+ case ARC_ISA_ARCV1:
+ return &arc_v1_core_reg_feature;
+ case ARC_ISA_ARCV2:
+ return &arc_v2_core_reg_feature;
+ default:
+ gdb_assert_not_reached
+ ("Unknown machine type to determine the core feature set.");
}
- gdb_assert (tdesc_loc != NULL);
-
- /* Now we can search for base registers. Core registers can be either full
- or reduced. Summary:
-
- - core.v2 + aux-minimal
- - core-reduced.v2 + aux-minimal
- - core.arcompact + aux-minimal
-
- NB: It is entirely feasible to have ARCompact with reduced core regs, but
- we ignore that because GCC doesn't support that and at the same time
- ARCompact is considered obsolete, so there is not much reason to support
- that. */
- const struct tdesc_feature *feature
- = tdesc_find_feature (tdesc_loc, core_v2_feature_name);
- if (feature != NULL)
- {
- /* Confirm that register and architecture match, to prevent accidents in
- some situations. This code will trigger an error if:
+}
- 1. XML tdesc doesn't specify arch explicitly, registers are for arch
- X, but ELF specifies arch Y.
+/* At the moment, there is only 1 auxiliary register features set.
+ This is a place holder for future extendability. */
- 2. XML tdesc specifies arch X, but contains registers for arch Y.
+static const arc_register_feature *
+determine_aux_reg_feature_set ()
+{
+ return &arc_common_aux_reg_feature;
+}
- It will not protect from case where XML or ELF specify arch X,
- registers are for the same arch X, but the real target is arch Y. To
- detect this case we need to check IDENTITY register. */
- if (!is_arcv2)
- {
- arc_print (_("Error: ARC v2 target description supplied for "
- "non-ARCv2 target.\n"));
- return FALSE;
- }
+/* Update accumulator register names (ACCH/ACCL) for r58 and r59 in the
+ register sets. The endianness determines the assignment:
- is_reduced_rf = FALSE;
- core_feature_name = core_v2_feature_name;
- core_regs = core_v2_register_names;
- }
- else
+ ,------.------.
+ | acch | accl |
+ ,----|------+------|
+ | LE | r59 | r58 |
+ | BE | r58 | r59 |
+ `----^------^------' */
+
+static void
+arc_update_acc_reg_names (const int byte_order)
+{
+ const char *r58_alias
+ = byte_order == BFD_ENDIAN_LITTLE ? "accl" : "acch";
+ const char *r59_alias
+ = byte_order == BFD_ENDIAN_LITTLE ? "acch" : "accl";
+
+ /* Subscript 1 must be OK because those registers have 2 names. */
+ arc_v1_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
+ arc_v1_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
+ arc_v2_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
+ arc_v2_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
+}
+
+/* Go through all the registers in REG_SET and check if they exist
+ in FEATURE. The TDESC_DATA is updated with the register number
+ in REG_SET if it is found in the feature. If a required register
+ is not found, this function returns false. */
+
+static bool
+arc_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
+ const struct tdesc_feature *feature,
+ const struct arc_register_feature *reg_set)
+{
+ for (const auto ® : reg_set->registers)
{
- feature = tdesc_find_feature (tdesc_loc, core_reduced_v2_feature_name);
- if (feature != NULL)
+ bool found = false;
+
+ for (const char *name : reg.names)
{
- if (!is_arcv2)
- {
- arc_print (_("Error: ARC v2 target description supplied for "
- "non-ARCv2 target.\n"));
- return FALSE;
- }
+ found
+ = tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
- is_reduced_rf = TRUE;
- core_feature_name = core_reduced_v2_feature_name;
- core_regs = core_v2_register_names;
+ if (found)
+ break;
}
- else
+
+ if (!found && reg.required_p)
{
- feature = tdesc_find_feature (tdesc_loc,
- core_arcompact_feature_name);
- if (feature != NULL)
+ std::ostringstream reg_names;
+ for (std::size_t i = 0; i < reg.names.size(); ++i)
{
- if (is_arcv2)
- {
- arc_print (_("Error: ARCompact target description supplied "
- "for non-ARCompact target.\n"));
- return FALSE;
- }
-
- is_reduced_rf = FALSE;
- core_feature_name = core_arcompact_feature_name;
- core_regs = core_arcompact_register_names;
- }
- else
- {
- arc_print (_("Error: Couldn't find core register feature in "
- "supplied target description."));
- return FALSE;
+ if (i == 0)
+ reg_names << "'" << reg.names[0] << "'";
+ else
+ reg_names << " or '" << reg.names[0] << "'";
}
+ arc_print (_("Error: Cannot find required register(s) %s "
+ "in feature '%s'.\n"), reg_names.str ().c_str (),
+ feature->name.c_str ());
+ return false;
}
}
- struct tdesc_arch_data *tdesc_data_loc = tdesc_data_alloc ();
+ return true;
+}
- gdb_assert (feature != NULL);
- int valid_p = 1;
+/* Check for the existance of "lp_start" and "lp_end" in target description.
+ If both are present, assume there is hardware loop support in the target.
+ This can be improved by looking into "lpc_size" field of "isa_config"
+ auxiliary register. */
- for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
+static bool
+arc_check_for_hw_loops (const struct target_desc *tdesc,
+ struct tdesc_arch_data *data)
+{
+ const auto feature_aux = tdesc_find_feature (tdesc, ARC_AUX_FEATURE_NAME);
+ const auto aux_regset = determine_aux_reg_feature_set ();
+
+ if (feature_aux == nullptr)
+ return false;
+
+ bool hw_loop_p = false;
+ const auto lp_start_name =
+ aux_regset->registers[ARC_LP_START_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
+ const auto lp_end_name =
+ aux_regset->registers[ARC_LP_END_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
+
+ hw_loop_p = tdesc_numbered_register (feature_aux, data,
+ ARC_LP_START_REGNUM, lp_start_name);
+ hw_loop_p &= tdesc_numbered_register (feature_aux, data,
+ ARC_LP_END_REGNUM, lp_end_name);
+
+ return hw_loop_p;
+}
+
+/* Initialize target description for the ARC.
+
+ Returns true if input TDESC was valid and in this case it will assign TDESC
+ and TDESC_DATA output parameters. */
+
+static bool
+arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
+ tdesc_arch_data_up *tdesc_data)
+{
+ const struct target_desc *tdesc_loc = info.target_desc;
+ arc_debug_printf ("Target description initialization.");
+
+ /* If target doesn't provide a description, use the default ones. */
+ if (!tdesc_has_registers (tdesc_loc))
{
- /* If rf16, then skip extra registers. */
- if (is_reduced_rf && ((i >= ARC_R4_REGNUM && i <= ARC_R9_REGNUM)
- || (i >= ARC_R16_REGNUM && i <= ARC_R25_REGNUM)))
- continue;
-
- valid_p = tdesc_numbered_register (feature, tdesc_data_loc, i,
- core_regs[i]);
-
- /* - Ignore errors in extension registers - they are optional.
- - Ignore missing ILINK because it doesn't make sense for Linux.
- - Ignore missing ILINK2 when architecture is ARCompact, because it
- doesn't make sense for Linux targets.
-
- In theory those optional registers should be in separate features, but
- that would create numerous but tiny features, which looks like an
- overengineering of a rather simple task. */
- if (!valid_p && (i <= ARC_SP_REGNUM || i == ARC_BLINK_REGNUM
- || i == ARC_LP_COUNT_REGNUM || i == ARC_PCL_REGNUM
- || (i == ARC_R30_REGNUM && is_arcv2)))
- {
- arc_print (_("Error: Cannot find required register `%s' in "
- "feature `%s'.\n"), core_regs[i], core_feature_name);
- tdesc_data_cleanup (tdesc_data_loc);
- return FALSE;
- }
+ arc_arch_features features
+ = arc_arch_features_create (info.abfd,
+ info.bfd_arch_info->mach);
+ tdesc_loc = arc_lookup_target_description (features);
}
+ gdb_assert (tdesc_loc != nullptr);
+
+ arc_debug_printf ("Have got a target description");
+
+ const struct tdesc_feature *feature_core
+ = tdesc_find_feature (tdesc_loc, ARC_CORE_FEATURE_NAME);
+ const struct tdesc_feature *feature_aux
+ = tdesc_find_feature (tdesc_loc, ARC_AUX_FEATURE_NAME);
- /* Mandatory AUX registeres are intentionally few and are common between
- ARCompact and ARC v2, so same code can be used for both. */
- feature = tdesc_find_feature (tdesc_loc, aux_minimal_feature_name);
- if (feature == NULL)
+ /* Maybe there still is a chance to salvage the input. */
+ if (feature_core == nullptr)
+ feature_core = find_obsolete_core_names (tdesc_loc);
+ if (feature_aux == nullptr)
+ feature_aux = find_obsolete_aux_names (tdesc_loc);
+
+ if (feature_core == nullptr)
{
- arc_print (_("Error: Cannot find required feature `%s' in supplied "
- "target description.\n"), aux_minimal_feature_name);
- tdesc_data_cleanup (tdesc_data_loc);
- return FALSE;
+ arc_print (_("Error: Cannot find required feature '%s' in supplied "
+ "target description.\n"), ARC_CORE_FEATURE_NAME);
+ return false;
}
- for (int i = ARC_FIRST_AUX_REGNUM; i <= ARC_LAST_AUX_REGNUM; i++)
+ if (feature_aux == nullptr)
{
- const char *name = aux_minimal_register_names[i - ARC_FIRST_AUX_REGNUM];
- valid_p = tdesc_numbered_register (feature, tdesc_data_loc, i, name);
- if (!valid_p)
- {
- arc_print (_("Error: Cannot find required register `%s' "
- "in feature `%s'.\n"),
- name, tdesc_feature_name (feature));
- tdesc_data_cleanup (tdesc_data_loc);
- return FALSE;
- }
+ arc_print (_("Error: Cannot find required feature '%s' in supplied "
+ "target description.\n"), ARC_AUX_FEATURE_NAME);
+ return false;
+ }
+
+ const arc_register_feature *arc_core_reg_feature
+ = determine_core_reg_feature_set (info.bfd_arch_info->mach);
+ const arc_register_feature *arc_aux_reg_feature
+ = determine_aux_reg_feature_set ();
+
+ tdesc_arch_data_up tdesc_data_loc = tdesc_data_alloc ();
+
+ arc_update_acc_reg_names (info.byte_order);
+
+ bool valid_p = arc_check_tdesc_feature (tdesc_data_loc.get (),
+ feature_core,
+ arc_core_reg_feature);
+
+ valid_p &= arc_check_tdesc_feature (tdesc_data_loc.get (),
+ feature_aux,
+ arc_aux_reg_feature);
+
+ if (!valid_p)
+ {
+ arc_debug_printf ("Target description is not valid");
+ return false;
}
*tdesc = tdesc_loc;
- *tdesc_data = tdesc_data_loc;
+ *tdesc_data = std::move (tdesc_data_loc);
- return TRUE;
+ return true;
+}
+
+/* Implement the type_align gdbarch function. */
+
+static ULONGEST
+arc_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+ switch (type->code ())
+ {
+ case TYPE_CODE_PTR:
+ case TYPE_CODE_FUNC:
+ case TYPE_CODE_FLAGS:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_RANGE:
+ case TYPE_CODE_FLT:
+ case TYPE_CODE_ENUM:
+ case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
+ case TYPE_CODE_CHAR:
+ case TYPE_CODE_BOOL:
+ case TYPE_CODE_DECFLOAT:
+ case TYPE_CODE_METHODPTR:
+ case TYPE_CODE_MEMBERPTR:
+ type = check_typedef (type);
+ return std::min<ULONGEST> (4, TYPE_LENGTH (type));
+ default:
+ return 0;
+ }
}
/* Implement the "init" gdbarch method. */
arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
const struct target_desc *tdesc;
- struct tdesc_arch_data *tdesc_data;
+ tdesc_arch_data_up tdesc_data;
- if (arc_debug)
- debug_printf ("arc: Architecture initialization.\n");
+ arc_debug_printf ("Architecture initialization.");
if (!arc_tdesc_init (info, &tdesc, &tdesc_data))
- return NULL;
+ return nullptr;
/* Allocate the ARC-private target-dependent information structure, and the
GDB target-independent information structure. */
- struct gdbarch_tdep *tdep = XCNEW (struct gdbarch_tdep);
+ std::unique_ptr<arc_gdbarch_tdep> tdep_holder (new arc_gdbarch_tdep);
+ arc_gdbarch_tdep *tdep = tdep_holder.get ();
tdep->jb_pc = -1; /* No longjmp support by default. */
- struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->has_hw_loops = arc_check_for_hw_loops (tdesc, tdesc_data.get ());
+ struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep_holder.release ());
/* Data types. */
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_long_bit (gdbarch, 32);
set_gdbarch_long_long_bit (gdbarch, 64);
- set_gdbarch_long_long_align_bit (gdbarch, 32);
+ set_gdbarch_type_align (gdbarch, arc_type_align);
set_gdbarch_float_bit (gdbarch, 32);
set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
set_gdbarch_double_bit (gdbarch, 64);
set_gdbarch_ps_regnum (gdbarch, ARC_STATUS32_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, -1); /* No FPU registers. */
- set_gdbarch_dummy_id (gdbarch, arc_dummy_id);
set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call);
set_gdbarch_push_dummy_code (gdbarch, arc_push_dummy_code);
else
set_gdbarch_decr_pc_after_break (gdbarch, 2);
- set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc);
- set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp);
-
set_gdbarch_frame_align (gdbarch, arc_frame_align);
set_gdbarch_print_insn (gdbarch, arc_delayed_print_insn);
/* Frame unwinders and sniffers. */
dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &arc_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &arc_frame_unwind);
frame_base_set_default (gdbarch, &arc_normal_base);
if (tdep->jb_pc >= 0)
set_gdbarch_get_longjmp_target (gdbarch, arc_get_longjmp_target);
- tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+ /* 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);
+ set_gdbarch_valid_disassembler_options (gdbarch,
+ disassembler_options_arc ());
+
+ tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
return gdbarch;
}
static void
arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
-}
-
-/* Wrapper for "maintenance print arc" list of commands. */
-
-static void
-maintenance_print_arc_command (char *args, int from_tty)
-{
- cmd_show_list (maintenance_print_arc_list, from_tty, "");
+ arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+ gdb_printf (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+ gdb_printf (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+ host_address_to_string (tdep->is_sigtramp));
+ gdb_printf (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+ host_address_to_string (tdep->sigcontext_addr));
+ gdb_printf (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+ host_address_to_string (tdep->sc_reg_offset));
+ gdb_printf (file, "arc_dump_tdep: sc_num_regs = %d\n",
+ tdep->sc_num_regs);
}
/* This command accepts single argument - address of instruction to
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
-_initialize_arc_tdep (void)
+_initialize_arc_tdep ()
{
gdbarch_register (bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);
- initialize_tdesc_arc_v2 ();
- initialize_tdesc_arc_arcompact ();
-
/* Register ARC-specific commands with gdb. */
/* Add root prefix command for "maintenance print arc" commands. */
- add_prefix_cmd ("arc", class_maintenance, maintenance_print_arc_command,
- _("ARC-specific maintenance commands for printing GDB "
- "internal state."),
- &maintenance_print_arc_list, "maintenance print arc ", 0,
- &maintenanceprintlist);
+ add_show_prefix_cmd ("arc", class_maintenance,
+ _("ARC-specific maintenance commands for printing GDB "
+ "internal state."),
+ &maintenance_print_arc_list,
+ 0, &maintenanceprintlist);
add_cmd ("arc-instruction", class_maintenance,
dump_arc_instruction_command,
&maintenance_print_arc_list);
/* Debug internals for ARC GDB. */
- add_setshow_zinteger_cmd ("arc", class_maintenance,
- &arc_debug,
- _("Set ARC specific debugging."),
- _("Show ARC specific debugging."),
- _("Non-zero enables ARC specific debugging."),
- NULL, NULL, &setdebuglist, &showdebuglist);
+ add_setshow_boolean_cmd ("arc", class_maintenance,
+ &arc_debug,
+ _("Set ARC specific debugging."),
+ _("Show ARC specific debugging."),
+ _("When set, ARC specific debugging is enabled."),
+ NULL, NULL, &setdebuglist, &showdebuglist);
}