Change regcache list to be an hash map
[deliverable/binutils-gdb.git] / gdb / arc-tdep.c
index 60a4e0442d4ec12e3f8c70c630eace1a4cf7558e..4817c623df4d66b834e1dffeab03f9a49f57b5ad 100644 (file)
@@ -1,6 +1,6 @@
-/* Target dependent code for ARC arhitecture, for GDB.
+/* Target dependent code for ARC architecture, for GDB.
 
-   Copyright 2005-2016 Free Software Foundation, Inc.
+   Copyright 2005-2019 Free Software Foundation, Inc.
    Contributed by Synopsys Inc.
 
    This file is part of GDB.
 #include "gdbcore.h"
 #include "gdbcmd.h"
 #include "objfiles.h"
+#include "prologue-value.h"
 #include "trad-frame.h"
 
 /* ARC header files.  */
 #include "opcode/arc.h"
+#include "opcodes/arc-dis.h"
 #include "arc-tdep.h"
 
 /* Standard headers.  */
@@ -41,8 +43,7 @@
 #include "features/arc-v2.c"
 #include "features/arc-arcompact.c"
 
-/* The frame unwind cache for the ARC.  Current structure is a stub, because
-   it should be filled in during the prologue analysis.  */
+/* The frame unwind cache for ARC.  */
 
 struct arc_frame_cache
 {
@@ -51,7 +52,35 @@ struct arc_frame_cache
      frame.  */
   CORE_ADDR prev_sp;
 
-  /* Store addresses for registers saved in prologue.  */
+  /* Register that is a base for this frame - FP for normal frame, SP for
+     non-FP frames.  */
+  int frame_base_reg;
+
+  /* Offset from the previous SP to the current frame base.  If GCC uses
+     `SUB SP,SP,offset` to allocate space for local variables, then it will be
+     done after setting up a frame pointer, but it still will be considered
+     part of prologue, therefore SP will be lesser than FP at the end of the
+     prologue analysis.  In this case that would be an offset from old SP to a
+     new FP.  But in case of non-FP frames, frame base is an SP and thus that
+     would be an offset from old SP to new SP.  What is important is that this
+     is an offset from old SP to a known register, so it can be used to find
+     old SP.
+
+     Using FP is preferable, when possible, because SP can change in function
+     body after prologue due to alloca, variadic arguments or other shenanigans.
+     If that is the case in the caller frame, then PREV_SP will point to SP at
+     the moment of function call, but it will be different from SP value at the
+     end of the caller prologue.  As a result it will not be possible to
+     reconstruct caller's frame and go past it in the backtrace.  Those things
+     are unlikely to happen to FP - FP value at the moment of function call (as
+     stored on stack in callee prologue) is also an FP value at the end of the
+     caller's prologue.  */
+
+  LONGEST frame_base_offset;
+
+  /* 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;
 };
 
@@ -59,6 +88,10 @@ struct arc_frame_cache
 
 int 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";
@@ -86,7 +119,7 @@ static const char *const core_v2_register_names[] = {
   "r48", "r49", "r50", "r51",
   "r52", "r53", "r54", "r55",
   "r56", "r57", "accl", "acch",
-  "lp_count", "pcl",
+  "lp_count", "reserved", "limm", "pcl",
 };
 
 static const char *const aux_minimal_register_names[] = {
@@ -109,9 +142,274 @@ static const char *const core_arcompact_register_names[] = {
   "r48", "r49", "r50", "r51",
   "r52", "r53", "r54", "r55",
   "r56", "r57", "r58", "r59",
-  "lp_count", "pcl",
+  "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.  */
+
+/* Returns an unsigned value of OPERAND_NUM in instruction INSN.
+   For relative branch instructions returned value is an offset, not an actual
+   branch target.  */
+
+static ULONGEST
+arc_insn_get_operand_value (const struct arc_instruction &insn,
+                           unsigned int operand_num)
+{
+  switch (insn.operands[operand_num].kind)
+    {
+    case ARC_OPERAND_KIND_LIMM:
+      gdb_assert (insn.limm_p);
+      return insn.limm_value;
+    case ARC_OPERAND_KIND_SHIMM:
+      return insn.operands[operand_num].value;
+    default:
+      /* Value in instruction is a register number.  */
+      struct regcache *regcache = get_current_regcache ();
+      ULONGEST value;
+      regcache_cooked_read_unsigned (regcache,
+                                    insn.operands[operand_num].value,
+                                    &value);
+      return value;
+    }
+}
+
+/* Like arc_insn_get_operand_value, but returns a signed value.  */
+
+static LONGEST
+arc_insn_get_operand_value_signed (const struct arc_instruction &insn,
+                                  unsigned int operand_num)
+{
+  switch (insn.operands[operand_num].kind)
+    {
+    case ARC_OPERAND_KIND_LIMM:
+      gdb_assert (insn.limm_p);
+      /* Convert unsigned raw value to signed one.  This assumes 2's
+        complement arithmetic, but so is the LONG_MIN value from generic
+        defs.h and that assumption is true for ARC.  */
+      gdb_static_assert (sizeof (insn.limm_value) == sizeof (int));
+      return (((LONGEST) insn.limm_value) ^ INT_MIN) - INT_MIN;
+    case ARC_OPERAND_KIND_SHIMM:
+      /* Sign conversion has been done by binutils.  */
+      return insn.operands[operand_num].value;
+    default:
+      /* Value in instruction is a register number.  */
+      struct regcache *regcache = get_current_regcache ();
+      LONGEST value;
+      regcache_cooked_read_signed (regcache,
+                                  insn.operands[operand_num].value,
+                                  &value);
+      return value;
+    }
+}
+
+/* Get register with base address of memory operation.  */
+
+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.  */
+  if (insn.insn_class == PUSH || insn.insn_class == POP)
+    return ARC_SP_REGNUM;
+
+  gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
+
+  /* Other instructions all have at least two operands: operand 0 is data,
+     operand 1 is address.  Operand 2 is offset from address.  However, see
+     comment to arc_instruction.operands - in some cases, third operand may be
+     missing, namely if it is 0.  */
+  gdb_assert (insn.operands_count >= 2);
+  return insn.operands[1].value;
+}
+
+/* Get offset of a memory operation INSN.  */
+
+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
+     disassembler.  */
+  if (insn.insn_class == POP)
+    return 4;
+  else if (insn.insn_class == PUSH)
+    return -4;
+
+  gdb_assert (insn.insn_class == LOAD || insn.insn_class == STORE);
+
+  /* Other instructions all have at least two operands: operand 0 is data,
+     operand 1 is address.  Operand 2 is offset from address.  However, see
+     comment to arc_instruction.operands - in some cases, third operand may be
+     missing, namely if it is 0.  */
+  if (insn.operands_count < 3)
+    return 0;
+
+  CORE_ADDR value = arc_insn_get_operand_value (insn, 2);
+  /* Handle scaling.  */
+  if (insn.writeback_mode == ARC_WRITEBACK_AS)
+    {
+      /* Byte data size is not valid for AS.  Halfword means shift by 1 bit.
+        Word and double word means shift by 2 bits.  */
+      gdb_assert (insn.data_size_mode != ARC_SCALING_B);
+      if (insn.data_size_mode == ARC_SCALING_H)
+       value <<= 1;
+      else
+       value <<= 2;
+    }
+  return value;
+}
+
+CORE_ADDR
+arc_insn_get_branch_target (const struct arc_instruction &insn)
+{
+  gdb_assert (insn.is_control_flow);
+
+  /* BI [c]: PC = nextPC + (c << 2).  */
+  if (insn.insn_class == BI)
+    {
+      ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
+      return arc_insn_get_linear_next_pc (insn) + (reg_value << 2);
+    }
+  /* BIH [c]: PC = nextPC + (c << 1).  */
+  else if (insn.insn_class == BIH)
+    {
+      ULONGEST reg_value = arc_insn_get_operand_value (insn, 0);
+      return arc_insn_get_linear_next_pc (insn) + (reg_value << 1);
+    }
+  /* JLI and EI.  */
+  /* 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.");
+      return 0;
+    }
+  else if (insn.insn_class == EI)
+    {
+      fprintf_unfiltered (gdb_stderr,
+                         "EI_S instruction is not supported by the GDB.");
+      return 0;
+    }
+  /* LEAVE_S: PC = BLINK.  */
+  else if (insn.insn_class == LEAVE)
+    {
+      struct regcache *regcache = get_current_regcache ();
+      ULONGEST value;
+      regcache_cooked_read_unsigned (regcache, ARC_BLINK_REGNUM, &value);
+      return value;
+    }
+  /* BBIT0/1, BRcc: PC = currentPC + operand.  */
+  else if (insn.insn_class == BBIT0 || insn.insn_class == BBIT1
+          || insn.insn_class == BRCC)
+    {
+      /* Most instructions has branch target as their sole argument.  However
+        conditional brcc/bbit has it as a third operand.  */
+      CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 2);
+
+      /* Offset is relative to the 4-byte aligned address of the current
+        instruction, hence last two bits should be truncated.  */
+      return pcrel_addr + align_down (insn.address, 4);
+    }
+  /* B, Bcc, BL, BLcc, LP, LPcc: PC = currentPC + operand.  */
+  else if (insn.insn_class == BRANCH || insn.insn_class == LOOP)
+    {
+      CORE_ADDR pcrel_addr = arc_insn_get_operand_value (insn, 0);
+
+      /* Offset is relative to the 4-byte aligned address of the current
+        instruction, hence last two bits should be truncated.  */
+      return pcrel_addr + align_down (insn.address, 4);
+    }
+  /* J, Jcc, JL, JLcc: PC = operand.  */
+  else if (insn.insn_class == JUMP)
+    {
+      /* All jumps are single-operand.  */
+      return arc_insn_get_operand_value (insn, 0);
+    }
+
+  /* This is some new and unknown instruction.  */
+  gdb_assert_not_reached ("Unknown branch instruction.");
+}
+
+/* Dump INSN into gdb_stdlog.  */
+
+static void
+arc_insn_dump (const struct arc_instruction &insn)
+{
+  struct gdbarch *gdbarch = target_gdbarch ();
+
+  arc_print ("Dumping arc_instruction at %s\n",
+            paddress (gdbarch, insn.address));
+  arc_print ("\tlength = %u\n", insn.length);
+
+  if (!insn.valid)
+    {
+      arc_print ("\tThis is not a valid ARC instruction.\n");
+      return;
+    }
+
+  arc_print ("\tlength_with_limm = %u\n", insn.length + (insn.limm_p ? 4 : 0));
+  arc_print ("\tcc = 0x%x\n", insn.condition_code);
+  arc_print ("\tinsn_class = %u\n", insn.insn_class);
+  arc_print ("\tis_control_flow = %i\n", insn.is_control_flow);
+  arc_print ("\thas_delay_slot = %i\n", insn.has_delay_slot);
+
+  CORE_ADDR next_pc = arc_insn_get_linear_next_pc (insn);
+  arc_print ("\tlinear_next_pc = %s\n", paddress (gdbarch, next_pc));
+
+  if (insn.is_control_flow)
+    {
+      CORE_ADDR t = arc_insn_get_branch_target (insn);
+      arc_print ("\tbranch_target = %s\n", paddress (gdbarch, t));
+    }
+
+  arc_print ("\tlimm_p = %i\n", insn.limm_p);
+  if (insn.limm_p)
+    arc_print ("\tlimm_value = 0x%08x\n", insn.limm_value);
+
+  if (insn.insn_class == STORE || insn.insn_class == LOAD
+      || insn.insn_class == PUSH || insn.insn_class == POP)
+    {
+      arc_print ("\twriteback_mode = %u\n", insn.writeback_mode);
+      arc_print ("\tdata_size_mode = %u\n", insn.data_size_mode);
+      arc_print ("\tmemory_base_register = %s\n",
+                gdbarch_register_name (gdbarch,
+                                       arc_insn_get_memory_base_reg (insn)));
+      /* get_memory_offset returns an unsigned CORE_ADDR, but treat it as a
+        LONGEST for a nicer representation.  */
+      arc_print ("\taddr_offset = %s\n",
+                plongest (arc_insn_get_memory_offset (insn)));
+    }
+
+  arc_print ("\toperands_count = %u\n", insn.operands_count);
+  for (unsigned int i = 0; i < insn.operands_count; ++i)
+    {
+      int is_reg = (insn.operands[i].kind == ARC_OPERAND_KIND_REG);
+
+      arc_print ("\toperand[%u] = {\n", i);
+      arc_print ("\t\tis_reg = %i\n", is_reg);
+      if (is_reg)
+       arc_print ("\t\tregister = %s\n",
+                  gdbarch_register_name (gdbarch, insn.operands[i].value));
+      /* Don't know if this value is signed or not, so print both
+        representations.  This tends to look quite ugly, especially for big
+        numbers.  */
+      arc_print ("\t\tunsigned value = %s\n",
+                pulongest (arc_insn_get_operand_value (insn, i)));
+      arc_print ("\t\tsigned value = %s\n",
+                plongest (arc_insn_get_operand_value_signed (insn, i)));
+      arc_print ("\t}\n");
+    }
+}
+
+CORE_ADDR
+arc_insn_get_linear_next_pc (const struct arc_instruction &insn)
+{
+  /* In ARC long immediate is always 4 bytes.  */
+  return (insn.address + insn.length + (insn.limm_p ? 4 : 0));
+}
+
 /* Implement the "write_pc" gdbarch method.
 
    In ARC PC register is a normal register so in most cases setting PC value
@@ -149,7 +447,7 @@ static const char *const core_arcompact_register_names[] = {
 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",
@@ -211,19 +509,6 @@ arc_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc,
   *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
@@ -294,7 +579,8 @@ arc_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
 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)
@@ -309,7 +595,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
      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);
@@ -366,7 +652,7 @@ arc_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
          /* 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;
@@ -430,8 +716,19 @@ arc_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
 static int
 arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
 {
-  /* Assume that register is readable if it is unknown.  */
-  return FALSE;
+  /* Assume that register is readable if it is unknown.  LIMM and RESERVED are
+     not real registers, but specific register numbers.  They are available as
+     regnums to align architectural register numbers with GDB internal regnums,
+     but they shouldn't appear in target descriptions generated by
+     GDB-servers.  */
+  switch (regnum)
+    {
+    case ARC_RESERVED_REGNUM:
+    case ARC_LIMM_REGNUM:
+      return true;
+    default:
+      return false;
+    }
 }
 
 /* Implement the "cannot_store_register" gdbarch method.  */
@@ -439,13 +736,16 @@ arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
 static int
 arc_cannot_store_register (struct gdbarch *gdbarch, int regnum)
 {
-  /* Assume that register is writable if it is unknown.  */
+  /* Assume that register is writable if it is unknown.  See comment in
+     arc_cannot_fetch_register about LIMM and RESERVED.  */
   switch (regnum)
     {
+    case ARC_RESERVED_REGNUM:
+    case ARC_LIMM_REGNUM:
     case ARC_PCL_REGNUM:
-      return TRUE;
+      return true;
     default:
-      return FALSE;
+      return false;
     }
 }
 
@@ -557,6 +857,28 @@ arc_store_return_value (struct gdbarch *gdbarch, struct type *type,
     error (_("arc_store_return_value: type length too large."));
 }
 
+/* Implement the "get_longjmp_target" gdbarch method.  */
+
+static int
+arc_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  if (arc_debug)
+    debug_printf ("arc: get_longjmp_target\n");
+
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *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);
+
+  if (target_read_memory (jb_addr + pc_offset, buf, ARC_REGISTER_SIZE))
+    return 0; /* Failed to read from memory.  */
+
+  *pc = extract_unsigned_integer (buf, ARC_REGISTER_SIZE,
+                                 gdbarch_byte_order (gdbarch));
+  return 1;
+}
+
 /* Implement the "return_value" gdbarch method.  */
 
 static enum return_value_convention
@@ -609,6 +931,407 @@ arc_frame_base_address (struct frame_info *this_frame, void **prologue_cache)
   return (CORE_ADDR) get_frame_register_unsigned (this_frame, ARC_FP_REGNUM);
 }
 
+/* Helper function that returns valid pv_t for an instruction operand:
+   either a register or a constant.  */
+
+static pv_t
+arc_pv_get_operand (pv_t *regs, const struct arc_instruction &insn, int operand)
+{
+  if (insn.operands[operand].kind == ARC_OPERAND_KIND_REG)
+    return regs[insn.operands[operand].value];
+  else
+    return pv_constant (arc_insn_get_operand_value (insn, operand));
+}
+
+/* Determine whether the given disassembled instruction may be part of a
+   function prologue.  If it is, the information in the frame unwind cache will
+   be updated.  */
+
+static bool
+arc_is_in_prologue (struct gdbarch *gdbarch, const struct arc_instruction &insn,
+                   pv_t *regs, struct pv_area *stack)
+{
+  /* It might be that currently analyzed address doesn't contain an
+     instruction, hence INSN is not valid.  It likely means that address points
+     to a data, non-initialized memory, or middle of a 32-bit instruction.  In
+     practice this may happen if GDB connects to a remote target that has
+     non-zeroed memory.  GDB would read PC value and would try to analyze
+     prologue, but there is no guarantee that memory contents at the address
+     specified in PC is address is a valid instruction.  There is not much that
+     that can be done about that.  */
+  if (!insn.valid)
+    return false;
+
+  /* Branch/jump or a predicated instruction.  */
+  if (insn.is_control_flow || insn.condition_code != ARC_CC_AL)
+    return false;
+
+  /* Store of some register.  May or may not update base address register.  */
+  if (insn.insn_class == STORE || insn.insn_class == PUSH)
+    {
+      /* There is definitely at least one operand - register/value being
+        stored.  */
+      gdb_assert (insn.operands_count > 0);
+
+      /* Store at some constant address.  */
+      if (insn.operands_count > 1
+         && insn.operands[1].kind != ARC_OPERAND_KIND_REG)
+       return false;
+
+      /* Writeback modes:
+        Mode   Address used                Writeback value
+        --------------------------------------------------
+        No     reg + offset                no
+        A/AW   reg + offset                reg + offset
+        AB     reg                         reg + offset
+        AS     reg + (offset << scaling)   no
+
+        "PUSH reg" is an alias to "ST.AW reg, [SP, -4]" encoding.  However
+        16-bit PUSH_S is a distinct instruction encoding, where offset and
+        base register are implied through opcode.  */
+
+      /* Register with base memory address.  */
+      int base_reg = arc_insn_get_memory_base_reg (insn);
+
+      /* Address where to write.  arc_insn_get_memory_offset returns scaled
+        value for ARC_WRITEBACK_AS.  */
+      pv_t addr;
+      if (insn.writeback_mode == ARC_WRITEBACK_AB)
+       addr = regs[base_reg];
+      else
+       addr = pv_add_constant (regs[base_reg],
+                               arc_insn_get_memory_offset (insn));
+
+      if (stack->store_would_trash (addr))
+       return false;
+
+      if (insn.data_size_mode != ARC_SCALING_D)
+       {
+         /* Find the value being stored.  */
+         pv_t store_value = arc_pv_get_operand (regs, insn, 0);
+
+         /* What is the size of a the stored value?  */
+         CORE_ADDR size;
+         if (insn.data_size_mode == ARC_SCALING_B)
+           size = 1;
+         else if (insn.data_size_mode == ARC_SCALING_H)
+           size = 2;
+         else
+           size = ARC_REGISTER_SIZE;
+
+         stack->store (addr, size, store_value);
+       }
+      else
+       {
+         if (insn.operands[0].kind == ARC_OPERAND_KIND_REG)
+           {
+             /* 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];
+             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));
+             stack->store (addr, ARC_REGISTER_SIZE * 2, store_value);
+           }
+       }
+
+      /* Is base register updated?  */
+      if (insn.writeback_mode == ARC_WRITEBACK_A
+         || insn.writeback_mode == ARC_WRITEBACK_AB)
+       regs[base_reg] = pv_add_constant (regs[base_reg],
+                                         arc_insn_get_memory_offset (insn));
+
+      return true;
+    }
+  else if (insn.insn_class == MOVE)
+    {
+      gdb_assert (insn.operands_count == 2);
+
+      /* Destination argument can be "0", so nothing will happen.  */
+      if (insn.operands[0].kind == ARC_OPERAND_KIND_REG)
+       {
+         int dst_regnum = insn.operands[0].value;
+         regs[dst_regnum] = arc_pv_get_operand (regs, insn, 1);
+       }
+      return true;
+    }
+  else if (insn.insn_class == SUB)
+    {
+      gdb_assert (insn.operands_count == 3);
+
+      /* SUB 0,b,c.  */
+      if (insn.operands[0].kind != ARC_OPERAND_KIND_REG)
+       return true;
+
+      int dst_regnum = insn.operands[0].value;
+      regs[dst_regnum] = pv_subtract (arc_pv_get_operand (regs, insn, 1),
+                                     arc_pv_get_operand (regs, insn, 2));
+      return true;
+    }
+  else if (insn.insn_class == ENTER)
+    {
+      /* ENTER_S is a prologue-in-instruction - it saves all callee-saved
+        registers according to given arguments thus greatly reducing code
+        size.  Which registers will be actually saved depends on arguments.
+
+        ENTER_S {R13-...,FP,BLINK} stores registers in following order:
+
+        new SP ->
+                  BLINK
+                  R13
+                  R14
+                  R15
+                  ...
+                  FP
+        old SP ->
+
+        There are up to three arguments for this opcode, as presented by ARC
+        disassembler:
+        1) amount of general-purpose registers to be saved - this argument is
+           always present even when it is 0;
+        2) FP register number (27) if FP has to be stored, otherwise argument
+           is not present;
+        3) BLINK register number (31) if BLINK has to be stored, otherwise
+           argument is not present.  If both FP and BLINK are stored, then FP
+           is present before BLINK in argument list.  */
+      gdb_assert (insn.operands_count > 0);
+
+      int regs_saved = arc_insn_get_operand_value (insn, 0);
+
+      bool is_fp_saved;
+      if (insn.operands_count > 1)
+       is_fp_saved = (insn.operands[1].value  == ARC_FP_REGNUM);
+      else
+       is_fp_saved = false;
+
+      bool is_blink_saved;
+      if (insn.operands_count > 1)
+       is_blink_saved = (insn.operands[insn.operands_count - 1].value
+                         == ARC_BLINK_REGNUM);
+      else
+       is_blink_saved = false;
+
+      /* Amount of bytes to be allocated to store specified registers.  */
+      CORE_ADDR st_size = ((regs_saved + is_fp_saved + is_blink_saved)
+                          * ARC_REGISTER_SIZE);
+      pv_t new_sp = pv_add_constant (regs[ARC_SP_REGNUM], -st_size);
+
+      /* Assume that if the last register (closest to new SP) can be written,
+        then it is possible to write all of them.  */
+      if (stack->store_would_trash (new_sp))
+       return false;
+
+      /* Current store address.  */
+      pv_t addr = regs[ARC_SP_REGNUM];
+
+      if (is_fp_saved)
+       {
+         addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
+         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);
+         stack->store (addr, ARC_REGISTER_SIZE, regs[i]);
+       }
+
+      if (is_blink_saved)
+       {
+         addr = pv_add_constant (addr, -ARC_REGISTER_SIZE);
+         stack->store (addr, ARC_REGISTER_SIZE,
+                       regs[ARC_BLINK_REGNUM]);
+       }
+
+      gdb_assert (pv_is_identical (addr, new_sp));
+
+      regs[ARC_SP_REGNUM] = new_sp;
+
+      if (is_fp_saved)
+       regs[ARC_FP_REGNUM] = regs[ARC_SP_REGNUM];
+
+      return true;
+    }
+
+  /* Some other architectures, like nds32 or arm, try to continue as far as
+     possible when building a prologue cache (as opposed to when skipping
+     prologue), so that cache will be as full as possible.  However current
+     code for ARC doesn't recognize some instructions that may modify SP, like
+     ADD, AND, OR, etc, hence there is no way to guarantee that SP wasn't
+     clobbered by the skipped instruction.  Potential existence of extension
+     instruction, which may do anything they want makes this even more complex,
+     so it is just better to halt on a first unrecognized instruction.  */
+
+  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;
+}
+
+struct disassemble_info
+arc_disassemble_info (struct gdbarch *gdbarch)
+{
+  struct disassemble_info di;
+  init_disassemble_info (&di, &null_stream, arc_fprintf_disasm);
+  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  di.endian = gdbarch_byte_order (gdbarch);
+  di.read_memory_func = [](bfd_vma memaddr, gdb_byte *myaddr,
+                          unsigned int len, struct disassemble_info *info)
+    {
+      return target_read_code (memaddr, myaddr, len);
+    };
+  return di;
+}
+
+/* Analyze the prologue and update the corresponding frame cache for the frame
+   unwinder for unwinding frames that doesn't have debug info.  In such
+   situation GDB attempts to parse instructions in the prologue to understand
+   where each register is saved.
+
+   If CACHE is not NULL, then it will be filled with information about saved
+   registers.
+
+   There are several variations of prologue which GDB may encounter.  "Full"
+   prologue looks like this:
+
+       sub     sp,sp,<imm>   ; Space for variadic arguments.
+       push    blink         ; Store return address.
+       push    r13           ; Store callee saved registers (up to R26/GP).
+       push    r14
+       push    fp            ; Store frame pointer.
+       mov     fp,sp         ; Update frame pointer.
+       sub     sp,sp,<imm>   ; Create space for local vars on the stack.
+
+   Depending on compiler options lots of things may change:
+
+    1) BLINK is not saved in leaf functions.
+    2) Frame pointer is not saved and updated if -fomit-frame-pointer is used.
+    3) 16-bit versions of those instructions may be used.
+    4) Instead of a sequence of several push'es, compiler may instead prefer to
+    do one subtract on stack pointer and then store registers using normal
+    store, that doesn't update SP.  Like this:
+
+
+       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]
+
+    5) ENTER_S instruction can encode most of prologue sequence in one
+    instruction (except for those subtracts for variadic arguments and local
+    variables).
+    6) GCC may use "millicode" functions from libgcc to store callee-saved
+    registers with minimal code-size requirements.  This function currently
+    doesn't support this.
+
+   ENTRYPOINT is a function entry point where prologue starts.
+
+   LIMIT_PC is a maximum possible end address of prologue (meaning address
+   of first instruction after the prologue).  It might also point to the middle
+   of prologue if execution has been stopped by the breakpoint at this address
+   - in this case debugger should analyze prologue only up to this address,
+   because further instructions haven't been executed yet.
+
+   Returns address of the first instruction after the prologue.  */
+
+static CORE_ADDR
+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));
+
+  /* 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);
+  pv_area stack (ARC_SP_REGNUM, gdbarch_addr_bit (gdbarch));
+
+  CORE_ADDR current_prologue_end = entrypoint;
+
+  /* Look at each instruction in the prologue.  */
+  while (current_prologue_end < limit_pc)
+    {
+      struct arc_instruction insn;
+      struct disassemble_info di = arc_disassemble_info (gdbarch);
+      arc_insn_decode (current_prologue_end, &di, arc_delayed_print_insn,
+                      &insn);
+
+      if (arc_debug >= 2)
+       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))
+       {
+         /* 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));
+         break;
+       }
+
+      current_prologue_end = arc_insn_get_linear_next_pc (insn);
+    }
+
+  if (cache != NULL)
+    {
+      /* Figure out if it is a frame pointer or just a stack pointer.  */
+      if (pv_is_register (regs[ARC_FP_REGNUM], ARC_SP_REGNUM))
+       {
+         cache->frame_base_reg = ARC_FP_REGNUM;
+         cache->frame_base_offset = -regs[ARC_FP_REGNUM].k;
+       }
+      else
+       {
+         cache->frame_base_reg = ARC_SP_REGNUM;
+         cache->frame_base_offset = -regs[ARC_SP_REGNUM].k;
+       }
+
+      /* Assign offset from old SP to all saved registers.  */
+      for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
+       {
+         CORE_ADDR offset;
+         if (stack.find_reg (gdbarch, i, &offset))
+           cache->saved_regs[i].addr = offset;
+       }
+    }
+
+  return current_prologue_end;
+}
+
+/* Estimated maximum prologue length in bytes.  This should include:
+   1) Store instruction for each callee-saved register (R25 - R13 + 1)
+   2) Two instructions for FP
+   3) One for BLINK
+   4) Three substract instructions for SP (for variadic args, for
+   callee saved regs and for local vars) and assuming that those SUB use
+   long-immediate (hence double length).
+   5) Stores of arguments registers are considered part of prologue too
+      (R7 - R1 + 1).
+   This is quite an extreme case, because even with -O0 GCC will collapse first
+   two SUBs into one and long immediate values are quite unlikely to appear in
+   this case, but still better to overshoot a bit - prologue analysis will
+   anyway stop at the first instruction that doesn't fit prologue, so this
+   limit will be rarely reached.  */
+
+const static int MAX_PROLOGUE_LENGTH
+  = 4 * (ARC_R25_REGNUM - ARC_R13_REGNUM + 1 + 2 + 1 + 6
+        + ARC_LAST_ARG_REGNUM - ARC_FIRST_ARG_REGNUM + 1);
+
 /* Implement the "skip_prologue" gdbarch method.
 
    Skip the prologue for the function at PC.  This is done by checking from
@@ -638,15 +1361,19 @@ arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
   /* No prologue info in symbol table, have to analyze prologue.  */
 
   /* Find an upper limit on the function prologue using the debug
-     information.  If the debug information could not be used to provide that
-     bound, then pass 0 and arc_scan_prologue will estimate value itself.  */
+     information.  If there is no debug information about prologue end, then
+     skip_prologue_using_sal will return 0.  */
   CORE_ADDR limit_pc = skip_prologue_using_sal (gdbarch, pc);
-  /* We don't have a proper analyze_prologue function yet, but its result
-     should be returned here.  Currently GDB will just stop at the first
-     instruction of function if debug information doesn't have prologue info;
-     and if there is a debug info about prologue - this code path will not be
-     taken at all.  */
-  return (limit_pc == 0 ? pc : limit_pc);
+
+  /* If there is no debug information at all, it is required to give some
+     semi-arbitrary hard limit on amount of bytes to scan during prologue
+     analysis.  */
+  if (limit_pc == 0)
+    limit_pc = pc + MAX_PROLOGUE_LENGTH;
+
+  /* Find the address of the first instruction after the prologue by scanning
+     through it - no other information is needed, so pass NULL as a cache.  */
+  return arc_analyze_prologue (gdbarch, pc, limit_pc, NULL);
 }
 
 /* Implement the "print_insn" gdbarch method.
@@ -661,15 +1388,37 @@ arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
    that will not print, or `stream` should be different from standard
    gdb_stdlog.  */
 
-static int
+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.
@@ -693,9 +1442,7 @@ static const gdb_byte arc_brk_s_le[] = { 0xff, 0x7f };
 static const gdb_byte arc_brk_be[] = { 0x25, 0x6f, 0x00, 0x3f };
 static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 };
 
-/* Implement the "breakpoint_from_pc" gdbarch method.
-
-   For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff
+/* For ARC ELF, breakpoint uses the 16-bit BRK_S instruction, which is 0x7fff
    (little endian) or 0xff7f (big endian).  We used to insert BRK_S even
    instead of 32-bit instructions, which works mostly ok, unless breakpoint is
    inserted into delay slot instruction.  In this case if branch is taken
@@ -712,15 +1459,12 @@ static const gdb_byte arc_brk_le[] = { 0x6f, 0x25, 0x3f, 0x00 };
    NB: Baremetal GDB uses BRK[_S], while user-space GDB uses TRAP_S.  BRK[_S]
    is much better because it doesn't commit unlike TRAP_S, so it can be set in
    delay slots; however it cannot be used in user-mode, hence usage of TRAP_S
-   in GDB for user-space.
+   in GDB for user-space.  */
 
-   PCPTR is a pointer to the PC where we want to place a breakpoint.  LENPTR
-   is a number of bytes used by the breakpoint.  Returns the byte sequence of
-   a breakpoint instruction.  */
+/* Implement the "breakpoint_kind_from_pc" gdbarch method.  */
 
-static const gdb_byte *
-arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
-                       int *lenptr)
+static int
+arc_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
 {
   size_t length_with_limm = gdb_insn_length (gdbarch, *pcptr);
 
@@ -729,55 +1473,60 @@ arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
      bytes for 32-bit instructions.  */
   if ((length_with_limm == 4 || length_with_limm == 8)
       && !arc_mach_is_arc600 (gdbarch))
+    return sizeof (arc_brk_le);
+  else
+    return sizeof (arc_brk_s_le);
+}
+
+/* Implement the "sw_breakpoint_from_kind" gdbarch method.  */
+
+static const gdb_byte *
+arc_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+  *size = kind;
+
+  if (kind == sizeof (arc_brk_le))
     {
-      *lenptr = sizeof (arc_brk_le);
       return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
              ? arc_brk_be
              : arc_brk_le);
     }
   else
     {
-      *lenptr = sizeof (arc_brk_s_le);
       return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
              ? arc_brk_s_be
              : arc_brk_s_le);
     }
 }
 
-/* Implement the "unwind_pc" gdbarch method.  */
+/* Implement the "frame_align" gdbarch method.  */
 
 static CORE_ADDR
-arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 {
-  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;
+  return align_down (sp, 4);
 }
 
-/* Implement the "unwind_sp" gdbarch method.  */
+/* Dump the frame info.  Used for internal debugging only.  */
 
-static CORE_ADDR
-arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+static void
+arc_print_frame_cache (struct gdbarch *gdbarch, const char *message,
+                      struct arc_frame_cache *cache, int addresses_known)
 {
-  int sp_regnum = gdbarch_sp_regnum (gdbarch);
-  CORE_ADDR sp = frame_unwind_register_unsigned (next_frame, sp_regnum);
+  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));
 
-  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_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
-{
-  return align_down (sp, 4);
+  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));
+    }
 }
 
 /* Frame unwinder for normal frames.  */
@@ -791,12 +1540,11 @@ arc_make_frame_cache (struct frame_info *this_frame)
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
 
   CORE_ADDR block_addr = get_frame_address_in_block (this_frame);
-  CORE_ADDR prev_pc = get_frame_pc (this_frame);
-
   CORE_ADDR entrypoint, prologue_end;
   if (find_pc_partial_function (block_addr, NULL, &entrypoint, &prologue_end))
     {
       struct symtab_and_line sal = find_pc_line (entrypoint, 0);
+      CORE_ADDR prev_pc = get_frame_pc (this_frame);
       if (sal.line == 0)
        /* No line info so use current PC.  */
        prologue_end = prev_pc;
@@ -808,18 +1556,42 @@ arc_make_frame_cache (struct frame_info *this_frame)
     }
   else
     {
+      /* If find_pc_partial_function returned nothing then there is no symbol
+        information at all for this PC.  Currently it is assumed in this case
+        that current PC is entrypoint to function and try to construct the
+        frame from that.  This is, probably, suboptimal, for example ARM
+        assumes in this case that program is inside the normal frame (with
+        frame pointer).  ARC, perhaps, should try to do the same.  */
       entrypoint = get_frame_register_unsigned (this_frame,
                                                gdbarch_pc_regnum (gdbarch));
-      prologue_end = 0;
+      prologue_end = entrypoint + MAX_PROLOGUE_LENGTH;
     }
 
   /* Allocate new frame cache instance and space for saved register info.
-   * FRAME_OBSTACK_ZALLOC will initialize fields to zeroes.  */
+     FRAME_OBSTACK_ZALLOC will initialize fields to zeroes.  */
   struct arc_frame_cache *cache
     = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
   cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
 
-  /* Should call analyze_prologue here, when it will be implemented.  */
+  arc_analyze_prologue (gdbarch, entrypoint, prologue_end, cache);
+
+  if (arc_debug)
+    arc_print_frame_cache (gdbarch, "after prologue", cache, false);
+
+  CORE_ADDR unwound_fb = get_frame_register_unsigned (this_frame,
+                                                     cache->frame_base_reg);
+  if (unwound_fb == 0)
+    return cache;
+  cache->prev_sp = unwound_fb + cache->frame_base_offset;
+
+  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 (arc_debug)
+    arc_print_frame_cache (gdbarch, "after previous SP found", cache, true);
 
   return cache;
 }
@@ -948,7 +1720,7 @@ static const struct frame_base arc_normal_base = {
    Returns TRUE if input tdesc was valid and in this case it will assign TDESC
    and TDESC_DATA output parameters.  */
 
-static int
+static bool
 arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
                struct tdesc_arch_data **tdesc_data)
 {
@@ -974,7 +1746,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
      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;
+  bool is_reduced_rf;
   const char *const *core_regs;
   const char *core_feature_name;
 
@@ -1031,10 +1803,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
        {
          arc_print (_("Error: ARC v2 target description supplied for "
                       "non-ARCv2 target.\n"));
-         return FALSE;
+         return false;
        }
 
-      is_reduced_rf = FALSE;
+      is_reduced_rf = false;
       core_feature_name = core_v2_feature_name;
       core_regs = core_v2_register_names;
     }
@@ -1047,10 +1819,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
            {
              arc_print (_("Error: ARC v2 target description supplied for "
                           "non-ARCv2 target.\n"));
-             return FALSE;
+             return false;
            }
 
-         is_reduced_rf = TRUE;
+         is_reduced_rf = true;
          core_feature_name = core_reduced_v2_feature_name;
          core_regs = core_v2_register_names;
        }
@@ -1064,10 +1836,10 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
                {
                  arc_print (_("Error: ARCompact target description supplied "
                               "for non-ARCompact target.\n"));
-                 return FALSE;
+                 return false;
                }
 
-             is_reduced_rf = FALSE;
+             is_reduced_rf = false;
              core_feature_name = core_arcompact_feature_name;
              core_regs = core_arcompact_register_names;
            }
@@ -1075,7 +1847,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
            {
              arc_print (_("Error: Couldn't find core register feature in "
                           "supplied target description."));
-             return FALSE;
+             return false;
            }
        }
     }
@@ -1110,11 +1882,11 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
          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;
+         return false;
        }
     }
 
-  /* Mandatory AUX registeres are intentionally few and are common between
+  /* Mandatory AUX registers 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)
@@ -1122,7 +1894,7 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
       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;
+      return false;
     }
 
   for (int i = ARC_FIRST_AUX_REGNUM; i <= ARC_LAST_AUX_REGNUM; i++)
@@ -1135,14 +1907,42 @@ arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
                       "in feature `%s'.\n"),
                     name, tdesc_feature_name (feature));
          tdesc_data_cleanup (tdesc_data_loc);
-         return FALSE;
+         return false;
        }
     }
 
   *tdesc = tdesc_loc;
   *tdesc_data = 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 (type))
+    {
+    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.  */
@@ -1159,14 +1959,18 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (!arc_tdesc_init (info, &tdesc, &tdesc_data))
     return NULL;
 
-  struct gdbarch *gdbarch = gdbarch_alloc (&info, NULL);
+  /* Allocate the ARC-private target-dependent information structure, and the
+     GDB target-independent information structure.  */
+  struct gdbarch_tdep *tdep = XCNEW (struct gdbarch_tdep);
+  tdep->jb_pc = -1; /* No longjmp support by default.  */
+  struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
 
   /* 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);
@@ -1189,7 +1993,6 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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);
 
@@ -1203,7 +2006,8 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
 
-  set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc);
+  set_gdbarch_breakpoint_kind_from_pc (gdbarch, arc_breakpoint_kind_from_pc);
+  set_gdbarch_sw_breakpoint_from_kind (gdbarch, arc_sw_breakpoint_from_kind);
 
   /* On ARC 600 BRK_S instruction advances PC, unlike other ARC cores.  */
   if (!arc_mach_is_arc600 (gdbarch))
@@ -1211,9 +2015,6 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   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);
@@ -1243,6 +2044,64 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      It can override functions set earlier.  */
   gdbarch_init_osabi (info, gdbarch);
 
+  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;
@@ -1253,11 +2112,38 @@ arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 static void
 arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 {
-  /* Empty for now.  */
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  fprintf_unfiltered (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
 }
 
-/* Suppress warning from -Wmissing-prototypes.  */
-extern initialize_file_ftype _initialize_arc_tdep;
+/* Wrapper for "maintenance print arc" list of commands.  */
+
+static void
+maintenance_print_arc_command (const char *args, int from_tty)
+{
+  cmd_show_list (maintenance_print_arc_list, from_tty, "");
+}
+
+/* This command accepts single argument - address of instruction to
+   disassemble.  */
+
+static void
+dump_arc_instruction_command (const char *args, int from_tty)
+{
+  struct value *val;
+  if (args != NULL && strlen (args) > 0)
+    val = evaluate_expression (parse_expression (args).get ());
+  else
+    val = access_value_history (0);
+  record_latest_value (val);
+
+  CORE_ADDR address = value_as_address (val);
+  struct arc_instruction insn;
+  struct disassemble_info di = arc_disassemble_info (target_gdbarch ());
+  arc_insn_decode (address, &di, arc_delayed_print_insn, &insn);
+  arc_insn_dump (insn);
+}
 
 void
 _initialize_arc_tdep (void)
@@ -1269,6 +2155,18 @@ _initialize_arc_tdep (void)
 
   /* 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_cmd ("arc-instruction", class_maintenance,
+          dump_arc_instruction_command,
+          _("Dump arc_instruction structure for specified address."),
+          &maintenance_print_arc_list);
+
   /* Debug internals for ARC GDB.  */
   add_setshow_zinteger_cmd ("arc", class_maintenance,
                            &arc_debug,
This page took 0.038635 seconds and 4 git commands to generate.