[ARM] Read memory as unsigned integer
[deliverable/binutils-gdb.git] / gdb / arc-tdep.c
index 8bea23400320110c944e1b4b6fa750a04fab9d10..e7a7d53f6f79656464764f658bcaf86e3fbf124a 100644 (file)
-/* ARC target-dependent stuff.
-   Copyright (C) 1995 Free Software Foundation, Inc.
+/* Target dependent code for ARC arhitecture, for GDB.
 
-This file is part of GDB.
+   Copyright 2005-2016 Free Software Foundation, Inc.
+   Contributed by Synopsys Inc.
 
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+   This file is part of GDB.
 
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
 
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* GDB header files.  */
 #include "defs.h"
-#include "frame.h"
-#include "inferior.h"
+#include "arch-utils.h"
+#include "disasm.h"
+#include "dwarf2-frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
 #include "gdbcore.h"
-#include "target.h"
-#include "floatformat.h"
-#include "symtab.h"
-
-static void codestream_read PARAMS ((unsigned int *, int));
-static void codestream_seek PARAMS ((int));
-static unsigned int codestream_fill PARAMS ((int));
-
-#define CODESTREAM_BUFSIZ 16 
-static CORE_ADDR codestream_next_addr;
-static CORE_ADDR codestream_addr;
-static unsigned int codestream_buf[CODESTREAM_BUFSIZ];
-static int codestream_off;
-static int codestream_cnt;
-
-#define codestream_tell() (codestream_addr + codestream_off)
-#define codestream_peek() (codestream_cnt == 0 ? \
-                          codestream_fill(1): codestream_buf[codestream_off])
-#define codestream_get() (codestream_cnt-- == 0 ? \
-                        codestream_fill(0) : codestream_buf[codestream_off++])
-#define OPMASK 0xf8000000
-
-static unsigned int 
-codestream_fill (peek_flag)
-    int peek_flag;
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "trad-frame.h"
+
+/* ARC header files.  */
+#include "opcode/arc.h"
+#include "arc-tdep.h"
+
+/* Standard headers.  */
+#include <algorithm>
+
+/* Default target descriptions.  */
+#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.  */
+
+struct arc_frame_cache
 {
-  codestream_addr = codestream_next_addr;
-  codestream_next_addr += CODESTREAM_BUFSIZ;
-  codestream_off = 0;
-  codestream_cnt = CODESTREAM_BUFSIZ;
-  read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
-  
-  if (peek_flag)
-    return (codestream_peek());
-  else
-    return (codestream_get());
-}
+  /* The stack pointer at the time this frame was created; i.e. the caller's
+     stack pointer when this function was called.  It is used to identify this
+     frame.  */
+  CORE_ADDR prev_sp;
+
+  /* Store addresses for registers saved in prologue.  */
+  struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Global debug flag.  */
+
+int arc_debug;
+
+/* 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", "pcl",
+};
+
+static const char *const aux_minimal_register_names[] = {
+  "pc", "status32",
+};
+
+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", "pcl",
+};
+
+/* Implement the "write_pc" gdbarch method.
+
+   In ARC PC register is a normal register so in most cases setting PC value
+   is a straightforward process: debugger just writes PC value.  However it
+   gets trickier in case when current instruction is an instruction in delay
+   slot.  In this case CPU will execute instruction at current PC value, then
+   will set PC to the current value of BTA register; also current instruction
+   cannot be branch/jump and some of the other instruction types.  Thus if
+   debugger would try to just change PC value in this case, this instruction
+   will get executed, but then core will "jump" to the original branch target.
+
+   Whether current instruction is a delay-slot instruction or not is indicated
+   by DE bit in STATUS32 register indicates if current instruction is a delay
+   slot instruction.  This bit is writable by debug host, which allows debug
+   host to prevent core from jumping after the delay slot instruction.  It
+   also works in another direction: setting this bit will make core to treat
+   any current instructions as a delay slot instruction and to set PC to the
+   current value of BTA register.
+
+   To workaround issues with changing PC register while in delay slot
+   instruction, debugger should check for the STATUS32.DE bit and reset it if
+   it is set.  No other change is required in this function.  Most common
+   case, where this function might be required is calling inferior functions
+   from debugger.  Generic GDB logic handles this pretty well: current values
+   of registers are stored, value of PC is changed (that is the job of this
+   function), and after inferior function is executed, GDB restores all
+   registers, include BTA and STATUS32, which also means that core is returned
+   to its original state of being halted on delay slot instructions.
+
+   This method is useless for ARC 600, because it doesn't have externally
+   exposed BTA register.  In the case of ARC 600 it is impossible to restore
+   core to its state in all occasions thus core should never be halted (from
+   the perspective of debugger host) in the delay slot.  */
 
 static void
-codestream_seek (place)
-    int place;
+arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
 {
-  codestream_next_addr = place / CODESTREAM_BUFSIZ;
-  codestream_next_addr *= CODESTREAM_BUFSIZ;
-  codestream_cnt = 0;
-  codestream_fill (1);
-  while (codestream_tell() != place)
-    codestream_get ();
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+  if (arc_debug)
+    debug_printf ("arc: Writing PC, new value=%s\n",
+                 paddress (gdbarch, new_pc));
+
+  regcache_cooked_write_unsigned (regcache, gdbarch_pc_regnum (gdbarch),
+                                 new_pc);
+
+  ULONGEST status32;
+  regcache_cooked_read_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
+                                &status32);
+
+  /* Mask for DE bit is 0x40.  */
+  if (status32 & 0x40)
+    {
+      if (arc_debug)
+       {
+         debug_printf ("arc: Changing PC while in delay slot.  Will "
+                       "reset STATUS32.DE bit to zero.  Value of STATUS32 "
+                       "register is 0x%s\n",
+                       phex (status32, ARC_REGISTER_SIZE));
+       }
+
+      /* Reset bit and write to the cache.  */
+      status32 &= ~0x40;
+      regcache_cooked_write_unsigned (regcache, gdbarch_ps_regnum (gdbarch),
+                                     status32);
+    }
 }
 
+/* Implement the "virtual_frame_pointer" gdbarch method.
+
+   According to ABI the FP (r27) is used to point to the middle of the current
+   stack frame, just below the saved FP and before local variables, register
+   spill area and outgoing args.  However for optimization levels above O2 and
+   in any case in leaf functions, the frame pointer is usually not set at all.
+   The exception being when handling nested functions.
+
+   We use this function to return a "virtual" frame pointer, marking the start
+   of the current stack frame as a register-offset pair.  If the FP is not
+   being used, then it should return SP, with an offset of the frame size.
+
+   The current implementation doesn't actually know the frame size, nor
+   whether the FP is actually being used, so for now we just return SP and an
+   offset of zero.  This is no worse than other architectures, but is needed
+   to avoid assertion failures.
+
+   TODO: Can we determine the frame size to get a correct offset?
+
+   PC is a program counter where we need the virtual FP.  REG_PTR is the base
+   register used for the virtual FP.  OFFSET_PTR is the offset used for the
+   virtual FP.  */
+
 static void
-codestream_read (buf, count)
-     unsigned int *buf;
-     int count;
+arc_virtual_frame_pointer (struct gdbarch *gdbarch, CORE_ADDR pc,
+                          int *reg_ptr, LONGEST *offset_ptr)
+{
+  *reg_ptr = gdbarch_sp_regnum (gdbarch);
+  *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)
 {
-  unsigned int *p;
-  int i;
-  p = buf;
-  for (i = 0; i < count; i++)
-    *p++ = codestream_get ();
+  return frame_id_build (get_frame_sp (this_frame),
+                        get_frame_pc (this_frame));
 }
 
-/*
- * find & return amound a local space allocated, and advance codestream to
- * first register push (if any)
- * if entry sequence doesn't make sense, return -1, and leave 
- * codestream pointer random
- */
+/* Implement the "push_dummy_call" gdbarch method.
+
+   Stack Frame Layout
+
+   This shows the layout of the stack frame for the general case of a
+   function call; a given function might not have a variable number of
+   arguments or local variables, or might not save any registers, so it would
+   not have the corresponding frame areas.  Additionally, a leaf function
+   (i.e. one which calls no other functions) does not need to save the
+   contents of the BLINK register (which holds its return address), and a
+   function might not have a frame pointer.
+
+   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
+
+   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
+   memory with each parameter occupying an integral number of words).  Words
+   1..8 are passed in registers 0..7; if the function has more than 8 words of
+   arguments then words 9..@em N are passed on the stack in the caller's frame.
 
-static long
-arc_get_frame_setup (pc)
-     int pc;
+   If the function has a variable number of arguments, e.g. it has a form such
+   as `function (p1, p2, ...);' and _P_ words are required to hold the values
+   of the named parameters (which are passed in registers 0..@em P -1), then
+   the remaining 8 - _P_ words passed in registers _P_..7 are spilled into the
+   top of the frame so that the anonymous parameter words occupy a continuous
+   region.
+
+   Any arguments are already in target byte order.  We just need to store
+   them!
+
+   BP_ADDR is the return address where breakpoint must be placed.  NARGS is
+   the number of arguments to the function.  ARGS is the arguments values (in
+   target byte order).  SP is the Current value of SP register.  STRUCT_RETURN
+   is TRUE if structures are returned by the function.  STRUCT_ADDR is the
+   hidden address for returning a struct.  Returns SP of a new 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,
+                    CORE_ADDR struct_addr)
 {
-  unsigned int insn, n;
+  if (arc_debug)
+    debug_printf ("arc: push_dummy_call (nargs = %d)\n", nargs);
 
-  codestream_seek (pc);
-  insn = codestream_get ();
+  int arg_reg = ARC_FIRST_ARG_REGNUM;
 
-  if (insn & OPMASK == 0x10000000)             /* st fp,[sp] */
-    {  
-      insn = codestream_get ();
-      if (insn & OPMASK != 0x10000000)         /* st blink,[sp,4] */
+  /* Push the return address.  */
+  regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr);
+
+  /* Are we returning a value using a structure return instead of a normal
+     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)
+    {
+      /* 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);
+
+      arg_reg++;
+    }
+
+  if (nargs > 0)
+    {
+      unsigned int total_space = 0;
+
+      /* How much space do the arguments occupy in total?  Must round each
+        argument's size up to an integral number of words.  */
+      for (int i = 0; i < nargs; i++)
        {
-         if (insn & OPMASK != 0x60000000)      /* for leaf, no st blink */
-           return -1;
+         unsigned int len = TYPE_LENGTH (value_type (args[i]));
+         unsigned int space = align_up (len, 4);
+
+         total_space += space;
+
+         if (arc_debug)
+           debug_printf ("arc: arg %d: %u bytes -> %u\n", i, len, space);
        }
-      else if (codestream_get () & OPMASK != 0x60000000)    /* mov fp,sp */
-       return (-1);
 
-      /* check for stack adjustment sub sp,nnn,sp */
-      insn = codestream_peek ();
-      if (insn & OPMASK == 0x50000000)
+      /* Allocate a buffer to hold a memory image of the arguments.  */
+      gdb_byte *memory_image = XCNEWVEC (gdb_byte, total_space);
+
+      /* Now copy all of the arguments into the buffer, correctly aligned.  */
+      gdb_byte *data = memory_image;
+      for (int i = 0; i < nargs; i++)
        {
-         n = (insn & 0x000001ff ); 
-          codestream_get ();
+         unsigned int len = TYPE_LENGTH (value_type (args[i]));
+         unsigned int space = align_up (len, 4);
 
-         /* this sequence is used to get the address of the return
-          * buffer for a function that returns a structure
-          */
-         insn = codestream_peek ();
-         if (insn & OPMASK == 0x60000000)
-           codestream_get ();
+         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);
 
-         return n;
+         data += space;
        }
-      else
+
+      /* Now load as much as possible of the memory image into registers.  */
+      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);
+
+         /* 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);
+
+         data += ARC_REGISTER_SIZE;
+         total_space -= ARC_REGISTER_SIZE;
+
+         /* All the data is now in registers.  */
+         if (total_space == 0)
+           break;
+
+         arg_reg++;
+       }
+
+      /* If there is any data left, push it onto the stack (in a single write
+        operation).  */
+      if (total_space > 0)
        {
-         return (0);
+         if (arc_debug)
+           debug_printf ("arc: passing %d bytes on stack\n", total_space);
+
+         sp -= total_space;
+         write_memory (sp, data, (int) total_space);
        }
+
+      xfree (memory_image);
+    }
+
+  /* Finally, update the SP register.  */
+  regcache_cooked_write_unsigned (regcache, gdbarch_sp_regnum (gdbarch), sp);
+
+  return sp;
+}
+
+/* Implement the "push_dummy_code" gdbarch method.
+
+   We don't actually push any code.  We just identify where a breakpoint can
+   be inserted to which we are can return and the resume address where we
+   should be called.
+
+   ARC does not necessarily have an executable stack, so we can't put the
+   return breakpoint there.  Instead we put it at the entry point of the
+   function.  This means the SP is unchanged.
+
+   SP is a current stack pointer FUNADDR is an address of the function to be
+   called.  ARGS is arguments to pass.  NARGS is a number of args to pass.
+   VALUE_TYPE is a type of value returned.  REAL_PC is a resume address when
+   the function is called.  BP_ADDR is an address where breakpoint should be
+   set.  Returns the updated stack pointer.  */
+
+static CORE_ADDR
+arc_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr,
+                    struct value **args, int nargs, struct type *value_type,
+                    CORE_ADDR *real_pc, CORE_ADDR *bp_addr,
+                    struct regcache *regcache)
+{
+  *real_pc = funaddr;
+  *bp_addr = entry_point_address ();
+  return sp;
+}
+
+/* Implement the "cannot_fetch_register" gdbarch method.  */
+
+static int
+arc_cannot_fetch_register (struct gdbarch *gdbarch, int regnum)
+{
+  /* Assume that register is readable if it is unknown.  */
+  return FALSE;
+}
+
+/* Implement the "cannot_store_register" gdbarch method.  */
+
+static int
+arc_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+  /* Assume that register is writable if it is unknown.  */
+  switch (regnum)
+    {
+    case ARC_PCL_REGNUM:
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
+
+/* Get the return value of a function from the registers/memory used to
+   return it, according to the convention used by the ABI - 4-bytes values are
+   in the R0, while 8-byte values are in the R0-R1.
+
+   TODO: This implementation ignores the case of "complex double", where
+   according to ABI, value is returned in the R0-R3 registers.
+
+   TYPE is a returned value's type.  VALBUF is a buffer for the returned
+   value.  */
+
+static void
+arc_extract_return_value (struct gdbarch *gdbarch, struct type *type,
+                         struct regcache *regcache, gdb_byte *valbuf)
+{
+  unsigned int len = TYPE_LENGTH (type);
+
+  if (arc_debug)
+    debug_printf ("arc: extract_return_value\n");
+
+  if (len <= ARC_REGISTER_SIZE)
+    {
+      ULONGEST val;
+
+      /* Get the return value from one register.  */
+      regcache_cooked_read_unsigned (regcache, ARC_R0_REGNUM, &val);
+      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));
+    }
+  else if (len <= ARC_REGISTER_SIZE * 2)
+    {
+      ULONGEST low, high;
+
+      /* Get the return value from two registers.  */
+      regcache_cooked_read_unsigned (regcache, ARC_R0_REGNUM, &low);
+      regcache_cooked_read_unsigned (regcache, ARC_R1_REGNUM, &high);
+
+      store_unsigned_integer (valbuf, ARC_REGISTER_SIZE,
+                             gdbarch_byte_order (gdbarch), low);
+      store_unsigned_integer (valbuf + ARC_REGISTER_SIZE,
+                             (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));
+    }
+  else
+    error (_("arc: extract_return_value: type length %u too large"), len);
+}
+
+
+/* Store the return value of a function into the registers/memory used to
+   return it, according to the convention used by the ABI.
+
+   TODO: This implementation ignores the case of "complex double", where
+   according to ABI, value is returned in the R0-R3 registers.
+
+   TYPE is a returned value's type.  VALBUF is a buffer with the value to
+   return.  */
+
+static void
+arc_store_return_value (struct gdbarch *gdbarch, struct type *type,
+                       struct regcache *regcache, const gdb_byte *valbuf)
+{
+  unsigned int len = TYPE_LENGTH (type);
+
+  if (arc_debug)
+    debug_printf ("arc: store_return_value\n");
+
+  if (len <= ARC_REGISTER_SIZE)
+    {
+      ULONGEST val;
+
+      /* Put the return value into one register.  */
+      val = extract_unsigned_integer (valbuf, (int) len,
+                                     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));
+    }
+  else if (len <= ARC_REGISTER_SIZE * 2)
+    {
+      ULONGEST low, high;
+
+      /* Put the return value into  two registers.  */
+      low = extract_unsigned_integer (valbuf, ARC_REGISTER_SIZE,
+                                     gdbarch_byte_order (gdbarch));
+      high = extract_unsigned_integer (valbuf + ARC_REGISTER_SIZE,
+                                      (int) len - ARC_REGISTER_SIZE,
+                                      gdbarch_byte_order (gdbarch));
+
+      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));
+    }
+  else
+    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
+arc_return_value (struct gdbarch *gdbarch, struct value *function,
+                 struct type *valtype, struct regcache *regcache,
+                 gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  /* If the return type is a struct, or a union, or would occupy more than two
+     registers, the ABI uses the "struct return convention": the calling
+     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
+                         || 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));
+
+  if (writebuf != NULL)
+    {
+      /* Case 1.  GDB should not ask us to set a struct return value: it
+        should know the struct return location and write the value there
+        itself.  */
+      gdb_assert (!is_struct_return);
+      arc_store_return_value (gdbarch, valtype, regcache, writebuf);
+    }
+  else if (readbuf != NULL)
+    {
+      /* Case 2.  GDB should not ask us to get a struct return value: it
+        should know the struct return location and read the value from there
+        itself.  */
+      gdb_assert (!is_struct_return);
+      arc_extract_return_value (gdbarch, valtype, regcache, readbuf);
+    }
+
+  return (is_struct_return
+         ? RETURN_VALUE_STRUCT_CONVENTION
+         : RETURN_VALUE_REGISTER_CONVENTION);
+}
+
+/* Return the base address of the frame.  For ARC, the base address is the
+   frame pointer.  */
+
+static CORE_ADDR
+arc_frame_base_address (struct frame_info *this_frame, void **prologue_cache)
+{
+  return (CORE_ADDR) get_frame_register_unsigned (this_frame, ARC_FP_REGNUM);
+}
+
+/* Implement the "skip_prologue" gdbarch method.
+
+   Skip the prologue for the function at PC.  This is done by checking from
+   the line information read from the DWARF, if possible; otherwise, we scan
+   the function prologue to find its end.  */
+
+static CORE_ADDR
+arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  if (arc_debug)
+    debug_printf ("arc: skip_prologue\n");
+
+  CORE_ADDR func_addr;
+  const char *func_name;
+
+  /* See what the symbol table says.  */
+  if (find_pc_partial_function (pc, &func_name, &func_addr, NULL))
+    {
+      /* Found a function.  */
+      CORE_ADDR postprologue_pc
+       = skip_prologue_using_sal (gdbarch, func_addr);
+
+      if (postprologue_pc != 0)
+       return std::max (pc, postprologue_pc);
     }
-  return (-1);
+
+  /* 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.  */
+  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);
 }
 
-/* return pc of first real instruction */
-CORE_ADDR
-skip_prologue (pc)
-     int pc;
+/* Implement the "print_insn" gdbarch method.
+
+   arc_get_disassembler () may return different functions depending on bfd
+   type, so it is not possible to pass print_insn directly to
+   set_gdbarch_print_insn ().  Instead this wrapper function is used.  It also
+   may be used by other functions to get disassemble_info for address.  It is
+   important to note, that those print_insn from opcodes always print
+   instruction to the stream specified in the INFO.  If this is not desired,
+   then either `print_insn` function in INFO should be set to some function
+   that will not print, or `stream` should be different from standard
+   gdb_stdlog.  */
+
+static int
+arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *info)
 {
-  unsigned int insn;
-  int i;
-  CORE_ADDR pos;
-  
-  if (arc_get_frame_setup (pc) < 0)
-    return (pc);
-  
-  /* skip over register saves */
-  for (i = 0; i < 10; i++)
+  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);
+}
+
+/* Baremetal breakpoint instructions.
+
+   ARC supports both big- and little-endian.  However, instructions for
+   little-endian processors are encoded in the middle-endian: half-words are
+   in big-endian, while bytes inside the half-words are in little-endian; data
+   is represented in the "normal" little-endian.  Big-endian processors treat
+   data and code identically.
+
+   Assuming the number 0x01020304, it will be presented this way:
+
+   Address            :  N   N+1  N+2  N+3
+   little-endian      : 0x04 0x03 0x02 0x01
+   big-endian         : 0x01 0x02 0x03 0x04
+   ARC middle-endian  : 0x02 0x01 0x04 0x03
+  */
+
+static const gdb_byte arc_brk_s_be[] = { 0x7f, 0xff };
+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 };
+
+/* 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
+   BLINK value will be set to address of instruction after delay slot, however
+   if we replaced 32-bit instruction in delay slot with 16-bit long BRK_S,
+   then BLINK value will have an invalid value - it will point to the address
+   after the BRK_S (which was there at the moment of branch execution) while
+   it should point to the address after the 32-bit long instruction.  To avoid
+   such issues this function disassembles instruction at target location and
+   evaluates it value.
+
+   ARC 600 supports only 16-bit BRK_S.
+
+   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.  */
+
+/* Implement the "breakpoint_kind_from_pc" gdbarch method.  */
+
+static int
+arc_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+  size_t length_with_limm = gdb_insn_length (gdbarch, *pcptr);
+
+  /* Replace 16-bit instruction with BRK_S, replace 32-bit instructions with
+     BRK.  LIMM is part of instruction length, so it can be either 4 or 8
+     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))
+    {
+      return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+             ? arc_brk_be
+             : arc_brk_le);
+    }
+  else
     {
-      insn = codestream_peek ();
-      if (insn & OPMASK != 0x10000000)       /* break if not st inst */
-       break;
-      codestream_get ();
+      return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+             ? arc_brk_s_be
+             : arc_brk_s_le);
     }
-     
-  codestream_seek (pos);
-  return (codestream_tell ());
 }
 
-/* Return number of args passed to a frame.
-   Can return -1, meaning no way to tell.  */
-int
-frame_num_args (fi)
-     struct frame_info *fi;
+/* 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_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  return align_down (sp, 4);
+}
+
+/* Frame unwinder for normal frames.  */
+
+static struct arc_frame_cache *
+arc_make_frame_cache (struct frame_info *this_frame)
 {
-#if 1
-  return -1;
-#else
-  /* This loses because not only might the compiler not be popping the
-     args right after the function call, it might be popping args from both
-     this call and a previous one, and we would say there are more args
-     than there really are.  Is it true for ARC */
-
-  int retpc;                                           
-  unsigned char op;                                    
-  struct frame_info *pfi;
-
-  int frameless;
-
-  FRAMELESS_FUNCTION_INVOCATION (fi, frameless);
-  if (frameless)
-    /* In the absence of a frame pointer, GDB doesn't get correct values
-       for nameless arguments.  Return -1, so it doesn't print any
-       nameless arguments.  */
-    return -1;
-
-  pfi = get_prev_frame_info (fi);                      
-  if (pfi == 0)
+  if (arc_debug)
+    debug_printf ("arc: frame_cache\n");
+
+  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))
     {
-      /* Note:  this can happen if we are looking at the frame for
-        main, because FRAME_CHAIN_VALID won't let us go into
-        start.  If we have debugging symbols, that's not really
-        a big deal; it just means it will only show as many arguments
-        to main as are declared.  */
-      return -1;
+      struct symtab_and_line sal = find_pc_line (entrypoint, 0);
+      if (sal.line == 0)
+       /* No line info so use current PC.  */
+       prologue_end = prev_pc;
+      else if (sal.end < prologue_end)
+       /* The next line begins after the function end.  */
+       prologue_end = sal.end;
+
+      prologue_end = std::min (prologue_end, prev_pc);
     }
   else
     {
-      retpc = pfi->pc;                                 
-      op = read_memory_integer (retpc, 1);                     
-      if (op == 0x59)                                  
-       /* pop %ecx */                         
-       return 1;                               
+      entrypoint = get_frame_register_unsigned (this_frame,
+                                               gdbarch_pc_regnum (gdbarch));
+      prologue_end = 0;
+    }
+
+  /* Allocate new frame cache instance and space for saved register info.
+   * 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.  */
+
+  return cache;
+}
+
+/* Implement the "this_id" frame_unwind method.  */
+
+static void
+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");
+
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  if (*this_cache == NULL)
+    *this_cache = arc_make_frame_cache (this_frame);
+  struct arc_frame_cache *cache = (struct arc_frame_cache *) (*this_cache);
+
+  CORE_ADDR stack_addr = cache->prev_sp;
+
+  /* There are 4 possible situation which decide how frame_id->code_addr is
+     evaluated:
+
+     1) Function is compiled with option -g.  Then frame_id will be created
+     in dwarf_* function and not in this function.  NB: even if target
+     binary is compiled with -g, some std functions like __start and _init
+     are not, so they still will follow one of the following choices.
+
+     2) Function is compiled without -g and binary hasn't been stripped in
+     any way.  In this case GDB still has enough information to evaluate
+     frame code_addr properly.  This case is covered by call to
+     get_frame_func ().
+
+     3) Binary has been striped with option -g (strip debug symbols).  In
+     this case there is still enough symbols for get_frame_func () to work
+     properly, so this case is also covered by it.
+
+     4) Binary has been striped with option -s (strip all symbols).  In this
+     case GDB cannot get function start address properly, so we return current
+     PC value instead.
+   */
+  CORE_ADDR code_addr = get_frame_func (this_frame);
+  if (code_addr == 0)
+    code_addr = get_frame_register_unsigned (this_frame,
+                                            gdbarch_pc_regnum (gdbarch));
+
+  *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Implement the "prev_register" frame_unwind method.  */
+
+static struct value *
+arc_frame_prev_register (struct frame_info *this_frame,
+                        void **this_cache, int regnum)
+{
+  if (*this_cache == NULL)
+    *this_cache = arc_make_frame_cache (this_frame);
+  struct arc_frame_cache *cache = (struct arc_frame_cache *) (*this_cache);
+
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  /* If we are asked to unwind the PC, then we need to return BLINK instead:
+     the saved value of PC points into this frame's function's prologue, not
+     the next frame's function's resume location.  */
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    regnum = ARC_BLINK_REGNUM;
+
+  /* SP is a special case - we should return prev_sp, because
+     trad_frame_get_prev_register will return _current_ SP value.
+     Alternatively we could have stored cache->prev_sp in the cache->saved
+     regs, but here we follow the lead of AArch64, ARM and Xtensa and will
+     leave that logic in this function, instead of prologue analyzers.  That I
+     think is a bit more clear as `saved_regs` should contain saved regs, not
+     computable.
+
+     Because value has been computed, "got_constant" should be used, so that
+     returned value will be a "not_lval" - immutable.  */
+
+  if (regnum == gdbarch_sp_regnum (gdbarch))
+    return frame_unwind_got_constant (this_frame, regnum, cache->prev_sp);
+
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Implement the "init_reg" dwarf2_frame method.  */
+
+static void
+arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+                          struct dwarf2_frame_state_reg *reg,
+                          struct frame_info *info)
+{
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    /* The return address column.  */
+    reg->how = DWARF2_FRAME_REG_RA;
+  else if (regnum == gdbarch_sp_regnum (gdbarch))
+    /* The call frame address.  */
+    reg->how = DWARF2_FRAME_REG_CFA;
+}
+
+/* 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 = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  arc_frame_this_id,
+  arc_frame_prev_register,
+  NULL,
+  default_frame_sniffer,
+  NULL,
+  NULL
+};
+
+
+static const struct frame_base arc_normal_base = {
+  &arc_frame_unwind,
+  arc_frame_base_address,
+  arc_frame_base_address,
+  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)
+{
+  if (arc_debug)
+    debug_printf ("arc: Target description initialization.\n");
+
+  const struct target_desc *tdesc_loc = info.target_desc;
+
+  /* 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))
+    {
+      if (is_arcv2)
+       {
+         tdesc_loc = tdesc_arc_v2;
+         if (arc_debug)
+           debug_printf ("arc: Using default register set for ARC v2.\n");
        }
       else
        {
-         return 0;
+         tdesc_loc = tdesc_arc_arcompact;
+         if (arc_debug)
+           debug_printf ("arc: Using default register set for ARCompact.\n");
        }
     }
-#endif
-}
+  else
+    {
+      if (arc_debug)
+       debug_printf ("arc: Using provided register set.\n");
+    }
+  gdb_assert (tdesc_loc != NULL);
 
-/*
- * parse the first few instructions of the function to see
- * what registers were stored.
- *
- * The startup sequence can be at the start of the function.
- * 'st fp,[sp], st blink,[sp+4], mov fp,sp' 
- *
- * Local space is allocated just below by sub sp,nnn,sp
- * Next, the registers used by this function are stored.
- */
+  /* Now we can search for base registers.  Core registers can be either full
+     or reduced.  Summary:
 
-void
-frame_find_saved_regs (fip, fsrp)
-     struct frame_info *fip;
-     struct frame_saved_regs *fsrp;
-{
-  long locals;
-  unsigned int insn;
-  CORE_ADDR dummy_bottom;
-  CORE_ADDR adr;
-  int i, regnum, offset;
-  
-  memset (fsrp, 0, sizeof *fsrp);
-  
-  /* if frame is the end of a dummy, compute where the
-   * beginning would be
-   */
-  dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
-  
-  /* check if the PC is in the stack, in a dummy frame */
-  if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) 
+     - 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)
     {
-      /* all regs were saved by push_call_dummy () */
-      adr = fip->frame;
-      for (i = 0; i < NUM_REGS; i++) 
+      /* 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.
+
+        2. XML tdesc specifies arch X, but contains registers for arch Y.
+
+        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)
        {
-         adr -= REGISTER_RAW_SIZE (i);
-         fsrp->regs[i] = adr;
+         arc_print (_("Error: ARC v2 target description supplied for "
+                      "non-ARCv2 target.\n"));
+         return FALSE;
        }
-      return;
+
+      is_reduced_rf = FALSE;
+      core_feature_name = core_v2_feature_name;
+      core_regs = core_v2_register_names;
     }
-  
-  locals = arc_get_frame_setup (get_pc_function_start (fip->pc));
-  
-  if (locals >= 0) 
+  else
     {
-      adr = fip->frame - locals;
-      for (i = 0; i < 10; i++) 
+      feature = tdesc_find_feature (tdesc_loc, core_reduced_v2_feature_name);
+      if (feature != NULL)
        {
-         insn = codestream_get ();
-         if (insn & 0xffff8000 != 0x100d8000)
-           break;
-          regnum = (insn & 0x00007c00) >> 9;
-         offset = (insn << 23) >> 23;
-         fsrp->regs[regnum] = adr + offset;
+         if (!is_arcv2)
+           {
+             arc_print (_("Error: ARC v2 target description supplied for "
+                          "non-ARCv2 target.\n"));
+             return FALSE;
+           }
+
+         is_reduced_rf = TRUE;
+         core_feature_name = core_reduced_v2_feature_name;
+         core_regs = core_v2_register_names;
+       }
+      else
+       {
+         feature = tdesc_find_feature (tdesc_loc,
+                                       core_arcompact_feature_name);
+         if (feature != NULL)
+           {
+             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;
+           }
        }
     }
-  
-  fsrp->regs[PC_REGNUM] = fip->frame + 4;
-  fsrp->regs[FP_REGNUM] = fip->frame;
-}
 
-void
-push_dummy_frame ()
-{
-  CORE_ADDR sp = read_register (SP_REGNUM);
-  int regnum;
-  char regbuf[MAX_REGISTER_RAW_SIZE];
-
-  read_register_gen (PC_REGNUM, regbuf);
-  write_memory (sp+4, regbuf, REGISTER_SIZE);
-  read_register_gen (FP_REGNUM, regbuf);
-  write_memory (sp, regbuf, REGISTER_SIZE);
-  write_register (FP_REGNUM, sp);
-  for (regnum = 0; regnum < NUM_REGS; regnum++)
+  struct tdesc_arch_data *tdesc_data_loc = tdesc_data_alloc ();
+
+  gdb_assert (feature != NULL);
+  int valid_p = 1;
+
+  for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
+    {
+      /* 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;
+       }
+    }
+
+  /* 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)
     {
-      read_register_gen (regnum, regbuf);
-      sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
+      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;
     }
-  sp += (2*REGISTER_SIZE);
-  write_register (SP_REGNUM, sp);
-}
 
-void
-pop_frame ()
-{
-  struct frame_info *frame = get_current_frame ();
-  CORE_ADDR fp;
-  int regnum;
-  struct frame_saved_regs fsr;
-  char regbuf[MAX_REGISTER_RAW_SIZE];
-  
-  fp = FRAME_FP (frame);
-  get_frame_saved_regs (frame, &fsr);
-  for (regnum = 0; regnum < NUM_REGS; regnum++) 
+  for (int i = ARC_FIRST_AUX_REGNUM; i <= ARC_LAST_AUX_REGNUM; i++)
     {
-      CORE_ADDR adr;
-      adr = fsr.regs[regnum];
-      if (adr)
+      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)
        {
-         read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
-         write_register_bytes (REGISTER_BYTE (regnum), regbuf,
-                               REGISTER_RAW_SIZE (regnum));
+         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;
        }
     }
-  write_register (FP_REGNUM, read_memory_integer (fp, 4));
-  write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
-  write_register (SP_REGNUM, fp + 8);
-  flush_cached_frames ();
+
+  *tdesc = tdesc_loc;
+  *tdesc_data = tdesc_data_loc;
+
+  return TRUE;
 }
 
-#ifdef GET_LONGJMP_TARGET
-/* Figure out where the longjmp will land.  Slurp the args out of the stack.
-   We expect the first arg to be a pointer to the jmp_buf structure from which
-   we extract the pc (JB_PC) that we will land at.  The pc is copied into PC.
-   This routine returns true on success. */
+/* Implement the "init" gdbarch method.  */
 
-int
-get_longjmp_target(pc)
-     CORE_ADDR *pc;
+static struct gdbarch *
+arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
-  char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
-  CORE_ADDR sp, jb_addr;
+  const struct target_desc *tdesc;
+  struct tdesc_arch_data *tdesc_data;
 
-  sp = read_register (SP_REGNUM);
+  if (arc_debug)
+    debug_printf ("arc: Architecture initialization.\n");
 
-  if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
-                         buf,
-                         TARGET_PTR_BIT / TARGET_CHAR_BIT))
-    return 0;
+  if (!arc_tdesc_init (info, &tdesc, &tdesc_data))
+    return NULL;
 
-  jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  /* 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);
 
-  if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
-                         TARGET_PTR_BIT / TARGET_CHAR_BIT))
-    return 0;
+  /* 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_float_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_char_signed (gdbarch, 0);
 
-  *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  set_gdbarch_write_pc (gdbarch, arc_write_pc);
 
-  return 1;
+  set_gdbarch_virtual_frame_pointer (gdbarch, arc_virtual_frame_pointer);
+
+  /* tdesc_use_registers expects gdbarch_num_regs to return number of registers
+     parsed by gdbarch_init, and then it will add all of the remaining
+     registers and will increase number of registers.  */
+  set_gdbarch_num_regs (gdbarch, ARC_LAST_REGNUM + 1);
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM);
+  set_gdbarch_pc_regnum (gdbarch, ARC_PC_REGNUM);
+  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);
+
+  set_gdbarch_cannot_fetch_register (gdbarch, arc_cannot_fetch_register);
+  set_gdbarch_cannot_store_register (gdbarch, arc_cannot_store_register);
+
+  set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+
+  set_gdbarch_return_value (gdbarch, arc_return_value);
+
+  set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+  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))
+    set_gdbarch_decr_pc_after_break (gdbarch, 0);
+  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);
+
+  set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
+
+  /* "nonsteppable" watchpoint means that watchpoint triggers before
+     instruction is committed, therefore it is required to remove watchpoint
+     to step though instruction that triggers it.  ARC watchpoints trigger
+     only after instruction is committed, thus there is no need to remove
+     them.  In fact on ARC watchpoint for memory writes may trigger with more
+     significant delay, like one or two instructions, depending on type of
+     memory where write is performed (CCM or external) and next instruction
+     after the memory write.  */
+  set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 0);
+
+  /* This doesn't include possible long-immediate value.  */
+  set_gdbarch_max_insn_length (gdbarch, 4);
+
+  /* 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_frame_unwind);
+  frame_base_set_default (gdbarch, &arc_normal_base);
+
+  /* Setup stuff specific to a particular environment (baremetal or Linux).
+     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);
+
+  tdesc_use_registers (gdbarch, tdesc, tdesc_data);
+
+  return gdbarch;
+}
+
+/* Implement the "dump_tdep" gdbarch method.  */
+
+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);
 }
-#endif /* GET_LONGJMP_TARGET */
 
-void _initialize_arc_tdep ()
+/* Suppress warning from -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_arc_tdep;
+
+void
+_initialize_arc_tdep (void)
 {
-  tm_print_insn = print_insn_arc;
+  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.  */
+
+  /* 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);
 }
This page took 0.03909 seconds and 4 git commands to generate.