gdb/debuginfod: Whitespace-only URL should disable debuginfod
[binutils-gdb.git] / gdb / arc-tdep.c
index 5c44915237ee72e4d71aeef6540a128e8f7bf44c..98bd1c4bc0a6ea775bc7767bfe671233a5f9c3c8 100644 (file)
-// OBSOLETE /* ARC target-dependent stuff.
-// OBSOLETE    Copyright 1995, 1996, 1999, 2000, 2001 Free Software Foundation, Inc.
-// OBSOLETE 
-// OBSOLETE    This file is part of GDB.
-// OBSOLETE 
-// OBSOLETE    This program is free software; you can redistribute it and/or modify
-// OBSOLETE    it under the terms of the GNU General Public License as published by
-// OBSOLETE    the Free Software Foundation; either version 2 of the License, or
-// OBSOLETE    (at your option) any later version.
-// OBSOLETE 
-// OBSOLETE    This program is distributed in the hope that it will be useful,
-// OBSOLETE    but WITHOUT ANY WARRANTY; without even the implied warranty of
-// OBSOLETE    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// OBSOLETE    GNU General Public License for more details.
-// OBSOLETE 
-// OBSOLETE    You should have received a copy of the GNU General Public License
-// OBSOLETE    along with this program; if not, write to the Free Software
-// OBSOLETE    Foundation, Inc., 59 Temple Place - Suite 330,
-// OBSOLETE    Boston, MA 02111-1307, USA.  */
-// OBSOLETE 
-// OBSOLETE #include "defs.h"
-// OBSOLETE #include "frame.h"
-// OBSOLETE #include "inferior.h"
-// OBSOLETE #include "gdbcore.h"
-// OBSOLETE #include "target.h"
-// OBSOLETE #include "floatformat.h"
-// OBSOLETE #include "symtab.h"
-// OBSOLETE #include "gdbcmd.h"
-// OBSOLETE #include "regcache.h"
-// OBSOLETE #include "gdb_string.h"
-// OBSOLETE 
-// OBSOLETE /* Local functions */
-// OBSOLETE 
-// OBSOLETE static int arc_set_cpu_type (char *str);
-// OBSOLETE 
-// OBSOLETE /* Current CPU, set with the "set cpu" command.  */
-// OBSOLETE static int arc_bfd_mach_type;
-// OBSOLETE char *arc_cpu_type;
-// OBSOLETE char *tmp_arc_cpu_type;
-// OBSOLETE 
-// OBSOLETE /* Table of cpu names.  */
-// OBSOLETE struct
-// OBSOLETE   {
-// OBSOLETE     char *name;
-// OBSOLETE     int value;
-// OBSOLETE   }
-// OBSOLETE arc_cpu_type_table[] =
-// OBSOLETE {
-// OBSOLETE   { "arc5", bfd_mach_arc_5 },
-// OBSOLETE   { "arc6", bfd_mach_arc_6 },
-// OBSOLETE   { "arc7", bfd_mach_arc_7 },
-// OBSOLETE   { "arc8", bfd_mach_arc_8 },
-// OBSOLETE   {  NULL,  0 }
-// OBSOLETE };
-// OBSOLETE 
-// OBSOLETE /* Used by simulator.  */
-// OBSOLETE int display_pipeline_p;
-// OBSOLETE int cpu_timer;
-// OBSOLETE /* This one must have the same type as used in the emulator.
-// OBSOLETE    It's currently an enum so this should be ok for now.  */
-// OBSOLETE int debug_pipeline_p;
-// OBSOLETE 
-// OBSOLETE #define ARC_CALL_SAVED_REG(r) ((r) >= 16 && (r) < 24)
-// OBSOLETE 
-// OBSOLETE #define OPMASK     0xf8000000
-// OBSOLETE 
-// OBSOLETE /* Instruction field accessor macros.
-// OBSOLETE    See the Programmer's Reference Manual.  */
-// OBSOLETE #define X_OP(i) (((i) >> 27) & 0x1f)
-// OBSOLETE #define X_A(i) (((i) >> 21) & 0x3f)
-// OBSOLETE #define X_B(i) (((i) >> 15) & 0x3f)
-// OBSOLETE #define X_C(i) (((i) >> 9) & 0x3f)
-// OBSOLETE #define X_D(i) ((((i) & 0x1ff) ^ 0x100) - 0x100)
-// OBSOLETE #define X_L(i) (((((i) >> 5) & 0x3ffffc) ^ 0x200000) - 0x200000)
-// OBSOLETE #define X_N(i) (((i) >> 5) & 3)
-// OBSOLETE #define X_Q(i) ((i) & 0x1f)
-// OBSOLETE 
-// OBSOLETE /* Return non-zero if X is a short immediate data indicator.  */
-// OBSOLETE #define SHIMM_P(x) ((x) == 61 || (x) == 63)
-// OBSOLETE 
-// OBSOLETE /* Return non-zero if X is a "long" (32 bit) immediate data indicator.  */
-// OBSOLETE #define LIMM_P(x) ((x) == 62)
-// OBSOLETE 
-// OBSOLETE /* Build a simple instruction.  */
-// OBSOLETE #define BUILD_INSN(op, a, b, c, d) \
-// OBSOLETE   ((((op) & 31) << 27) \
-// OBSOLETE    | (((a) & 63) << 21) \
-// OBSOLETE    | (((b) & 63) << 15) \
-// OBSOLETE    | (((c) & 63) << 9) \
-// OBSOLETE    | ((d) & 511))
-// OBSOLETE \f
-// OBSOLETE /* Codestream stuff.  */
-// OBSOLETE static void codestream_read (unsigned int *, int);
-// OBSOLETE static void codestream_seek (CORE_ADDR);
-// OBSOLETE static unsigned int codestream_fill (int);
-// OBSOLETE 
-// OBSOLETE #define CODESTREAM_BUFSIZ 16
-// OBSOLETE static CORE_ADDR codestream_next_addr;
-// OBSOLETE static CORE_ADDR codestream_addr;
-// OBSOLETE /* FIXME assumes sizeof (int) == 32? */
-// OBSOLETE static unsigned int codestream_buf[CODESTREAM_BUFSIZ];
-// OBSOLETE static int codestream_off;
-// OBSOLETE static int codestream_cnt;
-// OBSOLETE 
-// OBSOLETE #define codestream_tell() \
-// OBSOLETE   (codestream_addr + codestream_off * sizeof (codestream_buf[0]))
-// OBSOLETE #define codestream_peek() \
-// OBSOLETE   (codestream_cnt == 0 \
-// OBSOLETE    ? codestream_fill (1) \
-// OBSOLETE    : codestream_buf[codestream_off])
-// OBSOLETE #define codestream_get() \
-// OBSOLETE   (codestream_cnt-- == 0 \
-// OBSOLETE    ? codestream_fill (0) \
-// OBSOLETE    : codestream_buf[codestream_off++])
-// OBSOLETE 
-// OBSOLETE static unsigned int
-// OBSOLETE codestream_fill (int peek_flag)
-// OBSOLETE {
-// OBSOLETE   codestream_addr = codestream_next_addr;
-// OBSOLETE   codestream_next_addr += CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]);
-// OBSOLETE   codestream_off = 0;
-// OBSOLETE   codestream_cnt = CODESTREAM_BUFSIZ;
-// OBSOLETE   read_memory (codestream_addr, (char *) codestream_buf,
-// OBSOLETE           CODESTREAM_BUFSIZ * sizeof (codestream_buf[0]));
-// OBSOLETE   /* FIXME: check return code?  */
-// OBSOLETE 
-// OBSOLETE 
-// OBSOLETE   /* Handle byte order differences -> convert to host byte ordering.  */
-// OBSOLETE   {
-// OBSOLETE     int i;
-// OBSOLETE     for (i = 0; i < CODESTREAM_BUFSIZ; i++)
-// OBSOLETE       codestream_buf[i] =
-// OBSOLETE    extract_unsigned_integer (&codestream_buf[i],
-// OBSOLETE                              sizeof (codestream_buf[i]));
-// OBSOLETE   }
-// OBSOLETE 
-// OBSOLETE   if (peek_flag)
-// OBSOLETE     return codestream_peek ();
-// OBSOLETE   else
-// OBSOLETE     return codestream_get ();
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE static void
-// OBSOLETE codestream_seek (CORE_ADDR place)
-// OBSOLETE {
-// OBSOLETE   codestream_next_addr = place / CODESTREAM_BUFSIZ;
-// OBSOLETE   codestream_next_addr *= CODESTREAM_BUFSIZ;
-// OBSOLETE   codestream_cnt = 0;
-// OBSOLETE   codestream_fill (1);
-// OBSOLETE   while (codestream_tell () != place)
-// OBSOLETE     codestream_get ();
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* This function is currently unused but leave in for now.  */
-// OBSOLETE 
-// OBSOLETE static void
-// OBSOLETE codestream_read (unsigned int *buf, int count)
-// OBSOLETE {
-// OBSOLETE   unsigned int *p;
-// OBSOLETE   int i;
-// OBSOLETE   p = buf;
-// OBSOLETE   for (i = 0; i < count; i++)
-// OBSOLETE     *p++ = codestream_get ();
-// OBSOLETE }
-// OBSOLETE \f
-// OBSOLETE /* Set up prologue scanning and return the first insn.  */
-// OBSOLETE 
-// OBSOLETE static unsigned int
-// OBSOLETE setup_prologue_scan (CORE_ADDR pc)
-// OBSOLETE {
-// OBSOLETE   unsigned int insn;
-// OBSOLETE 
-// OBSOLETE   codestream_seek (pc);
-// OBSOLETE   insn = codestream_get ();
-// OBSOLETE 
-// OBSOLETE   return insn;
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /*
-// OBSOLETE  * Find & return amount a local space allocated, and advance codestream to
-// OBSOLETE  * first register push (if any).
-// OBSOLETE  * If entry sequence doesn't make sense, return -1, and leave 
-// OBSOLETE  * codestream pointer random.
-// OBSOLETE  */
-// OBSOLETE 
-// OBSOLETE static long
-// OBSOLETE arc_get_frame_setup (CORE_ADDR pc)
-// OBSOLETE {
-// OBSOLETE   unsigned int insn;
-// OBSOLETE   /* Size of frame or -1 if unrecognizable prologue.  */
-// OBSOLETE   int frame_size = -1;
-// OBSOLETE   /* An initial "sub sp,sp,N" may or may not be for a stdarg fn.  */
-// OBSOLETE   int maybe_stdarg_decr = -1;
-// OBSOLETE 
-// OBSOLETE   insn = setup_prologue_scan (pc);
-// OBSOLETE 
-// OBSOLETE   /* The authority for what appears here is the home-grown ABI.
-// OBSOLETE      The most recent version is 1.2.  */
-// OBSOLETE 
-// OBSOLETE   /* First insn may be "sub sp,sp,N" if stdarg fn.  */
-// OBSOLETE   if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
-// OBSOLETE       == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 0))
-// OBSOLETE     {
-// OBSOLETE       maybe_stdarg_decr = X_D (insn);
-// OBSOLETE       insn = codestream_get ();
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))      /* st blink,[sp,4] */
-// OBSOLETE       == BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
-// OBSOLETE     {
-// OBSOLETE       insn = codestream_get ();
-// OBSOLETE       /* Frame may not be necessary, even though blink is saved.
-// OBSOLETE          At least this is something we recognize.  */
-// OBSOLETE       frame_size = 0;
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))      /* st fp,[sp] */
-// OBSOLETE       == BUILD_INSN (2, 0, SP_REGNUM, FP_REGNUM, 0))
-// OBSOLETE     {
-// OBSOLETE       insn = codestream_get ();
-// OBSOLETE       if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
-// OBSOLETE      != BUILD_INSN (12, FP_REGNUM, SP_REGNUM, SP_REGNUM, 0))
-// OBSOLETE    return -1;
-// OBSOLETE 
-// OBSOLETE       /* Check for stack adjustment sub sp,sp,N.  */
-// OBSOLETE       insn = codestream_peek ();
-// OBSOLETE       if ((insn & BUILD_INSN (-1, -1, -1, 0, 0))
-// OBSOLETE      == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, 0, 0))
-// OBSOLETE    {
-// OBSOLETE      if (LIMM_P (X_C (insn)))
-// OBSOLETE        frame_size = codestream_get ();
-// OBSOLETE      else if (SHIMM_P (X_C (insn)))
-// OBSOLETE        frame_size = X_D (insn);
-// OBSOLETE      else
-// OBSOLETE        return -1;
-// OBSOLETE      if (frame_size < 0)
-// OBSOLETE        return -1;
-// OBSOLETE 
-// OBSOLETE      codestream_get ();
-// OBSOLETE 
-// OBSOLETE      /* This sequence is used to get the address of the return
-// OBSOLETE         buffer for a function that returns a structure.  */
-// OBSOLETE      insn = codestream_peek ();
-// OBSOLETE      if ((insn & OPMASK) == 0x60000000)
-// OBSOLETE        codestream_get ();
-// OBSOLETE    }
-// OBSOLETE       /* Frameless fn.  */
-// OBSOLETE       else
-// OBSOLETE    {
-// OBSOLETE      frame_size = 0;
-// OBSOLETE    }
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   /* If we found a "sub sp,sp,N" and nothing else, it may or may not be a
-// OBSOLETE      stdarg fn.  The stdarg decrement is not treated as part of the frame size,
-// OBSOLETE      so we have a dilemma: what do we return?  For now, if we get a
-// OBSOLETE      "sub sp,sp,N" and nothing else assume this isn't a stdarg fn.  One way
-// OBSOLETE      to fix this completely would be to add a bit to the function descriptor
-// OBSOLETE      that says the function is a stdarg function.  */
-// OBSOLETE 
-// OBSOLETE   if (frame_size < 0 && maybe_stdarg_decr > 0)
-// OBSOLETE     return maybe_stdarg_decr;
-// OBSOLETE   return frame_size;
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* Given a pc value, skip it forward past the function prologue by
-// OBSOLETE    disassembling instructions that appear to be a prologue.
-// OBSOLETE 
-// OBSOLETE    If FRAMELESS_P is set, we are only testing to see if the function
-// OBSOLETE    is frameless.  If it is a frameless function, return PC unchanged.
-// OBSOLETE    This allows a quicker answer.  */
-// OBSOLETE 
-// OBSOLETE CORE_ADDR
-// OBSOLETE arc_skip_prologue (CORE_ADDR pc, int frameless_p)
-// OBSOLETE {
-// OBSOLETE   unsigned int insn;
-// OBSOLETE   int i, frame_size;
-// OBSOLETE 
-// OBSOLETE   if ((frame_size = arc_get_frame_setup (pc)) < 0)
-// OBSOLETE     return (pc);
-// OBSOLETE 
-// OBSOLETE   if (frameless_p)
-// OBSOLETE     return frame_size == 0 ? pc : codestream_tell ();
-// OBSOLETE 
-// OBSOLETE   /* Skip over register saves.  */
-// OBSOLETE   for (i = 0; i < 8; i++)
-// OBSOLETE     {
-// OBSOLETE       insn = codestream_peek ();
-// OBSOLETE       if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
-// OBSOLETE      != BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
-// OBSOLETE    break;                  /* not st insn */
-// OBSOLETE       if (!ARC_CALL_SAVED_REG (X_C (insn)))
-// OBSOLETE    break;
-// OBSOLETE       codestream_get ();
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   return codestream_tell ();
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* Is the prologue at PC frameless?  */
-// OBSOLETE 
-// OBSOLETE int
-// OBSOLETE arc_prologue_frameless_p (CORE_ADDR pc)
-// OBSOLETE {
-// OBSOLETE   return (pc == arc_skip_prologue (pc, 1));
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* Return the return address for a frame.
-// OBSOLETE    This is used to implement FRAME_SAVED_PC.
-// OBSOLETE    This is taken from frameless_look_for_prologue.  */
-// OBSOLETE 
-// OBSOLETE CORE_ADDR
-// OBSOLETE arc_frame_saved_pc (struct frame_info *frame)
-// OBSOLETE {
-// OBSOLETE   CORE_ADDR func_start;
-// OBSOLETE   unsigned int insn;
-// OBSOLETE 
-// OBSOLETE   func_start = get_pc_function_start (frame->pc) + FUNCTION_START_OFFSET;
-// OBSOLETE   if (func_start == 0)
-// OBSOLETE     {
-// OBSOLETE       /* Best guess.  */
-// OBSOLETE       return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   /* The authority for what appears here is the home-grown ABI.
-// OBSOLETE      The most recent version is 1.2.  */
-// OBSOLETE 
-// OBSOLETE   insn = setup_prologue_scan (func_start);
-// OBSOLETE 
-// OBSOLETE   /* First insn may be "sub sp,sp,N" if stdarg fn.  */
-// OBSOLETE   if ((insn & BUILD_INSN (-1, -1, -1, -1, 0))
-// OBSOLETE       == BUILD_INSN (10, SP_REGNUM, SP_REGNUM, SHIMM_REGNUM, 0))
-// OBSOLETE     insn = codestream_get ();
-// OBSOLETE 
-// OBSOLETE   /* If the next insn is "st blink,[sp,4]" we can get blink from there.
-// OBSOLETE      Otherwise this is a leaf function and we can use blink.  Note that
-// OBSOLETE      this still allows for the case where a leaf function saves/clobbers/
-// OBSOLETE      restores blink.  */
-// OBSOLETE 
-// OBSOLETE   if ((insn & BUILD_INSN (-1, 0, -1, -1, -1))      /* st blink,[sp,4] */
-// OBSOLETE       != BUILD_INSN (2, 0, SP_REGNUM, BLINK_REGNUM, 4))
-// OBSOLETE     return ARC_PC_TO_REAL_ADDRESS (read_register (BLINK_REGNUM));
-// OBSOLETE   else
-// OBSOLETE     return ARC_PC_TO_REAL_ADDRESS (read_memory_integer (FRAME_FP (frame) + 4, 4));
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /*
-// OBSOLETE  * Parse the first few instructions of the function to see
-// OBSOLETE  * what registers were stored.
-// OBSOLETE  *
-// OBSOLETE  * The startup sequence can be at the start of the function.
-// OBSOLETE  * 'st blink,[sp+4], st fp,[sp], mov fp,sp' 
-// OBSOLETE  *
-// OBSOLETE  * Local space is allocated just below by sub sp,sp,nnn.
-// OBSOLETE  * Next, the registers used by this function are stored (as offsets from sp).
-// OBSOLETE  */
-// OBSOLETE 
-// OBSOLETE void
-// OBSOLETE frame_find_saved_regs (struct frame_info *fip, struct frame_saved_regs *fsrp)
-// OBSOLETE {
-// OBSOLETE   long locals;
-// OBSOLETE   unsigned int insn;
-// OBSOLETE   CORE_ADDR dummy_bottom;
-// OBSOLETE   CORE_ADDR adr;
-// OBSOLETE   int i, regnum, offset;
-// OBSOLETE 
-// OBSOLETE   memset (fsrp, 0, sizeof *fsrp);
-// OBSOLETE 
-// OBSOLETE   /* If frame is the end of a dummy, compute where the beginning would be.  */
-// OBSOLETE   dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
-// OBSOLETE 
-// OBSOLETE   /* Check if the PC is in the stack, in a dummy frame.  */
-// OBSOLETE   if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
-// OBSOLETE     {
-// OBSOLETE       /* all regs were saved by push_call_dummy () */
-// OBSOLETE       adr = fip->frame;
-// OBSOLETE       for (i = 0; i < NUM_REGS; i++)
-// OBSOLETE    {
-// OBSOLETE      adr -= REGISTER_RAW_SIZE (i);
-// OBSOLETE      fsrp->regs[i] = adr;
-// OBSOLETE    }
-// OBSOLETE       return;
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   locals = arc_get_frame_setup (get_pc_function_start (fip->pc));
-// OBSOLETE 
-// OBSOLETE   if (locals >= 0)
-// OBSOLETE     {
-// OBSOLETE       /* Set `adr' to the value of `sp'.  */
-// OBSOLETE       adr = fip->frame - locals;
-// OBSOLETE       for (i = 0; i < 8; i++)
-// OBSOLETE    {
-// OBSOLETE      insn = codestream_get ();
-// OBSOLETE      if ((insn & BUILD_INSN (-1, 0, -1, 0, 0))
-// OBSOLETE          != BUILD_INSN (2, 0, SP_REGNUM, 0, 0))
-// OBSOLETE        break;
-// OBSOLETE      regnum = X_C (insn);
-// OBSOLETE      offset = X_D (insn);
-// OBSOLETE      fsrp->regs[regnum] = adr + offset;
-// OBSOLETE    }
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   fsrp->regs[PC_REGNUM] = fip->frame + 4;
-// OBSOLETE   fsrp->regs[FP_REGNUM] = fip->frame;
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE void
-// OBSOLETE arc_push_dummy_frame (void)
-// OBSOLETE {
-// OBSOLETE   CORE_ADDR sp = read_register (SP_REGNUM);
-// OBSOLETE   int regnum;
-// OBSOLETE   char regbuf[MAX_REGISTER_RAW_SIZE];
-// OBSOLETE 
-// OBSOLETE   read_register_gen (PC_REGNUM, regbuf);
-// OBSOLETE   write_memory (sp + 4, regbuf, REGISTER_SIZE);
-// OBSOLETE   read_register_gen (FP_REGNUM, regbuf);
-// OBSOLETE   write_memory (sp, regbuf, REGISTER_SIZE);
-// OBSOLETE   write_register (FP_REGNUM, sp);
-// OBSOLETE   for (regnum = 0; regnum < NUM_REGS; regnum++)
-// OBSOLETE     {
-// OBSOLETE       read_register_gen (regnum, regbuf);
-// OBSOLETE       sp = push_bytes (sp, regbuf, REGISTER_RAW_SIZE (regnum));
-// OBSOLETE     }
-// OBSOLETE   sp += (2 * REGISTER_SIZE);
-// OBSOLETE   write_register (SP_REGNUM, sp);
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE void
-// OBSOLETE arc_pop_frame (void)
-// OBSOLETE {
-// OBSOLETE   struct frame_info *frame = get_current_frame ();
-// OBSOLETE   CORE_ADDR fp;
-// OBSOLETE   int regnum;
-// OBSOLETE   struct frame_saved_regs fsr;
-// OBSOLETE   char regbuf[MAX_REGISTER_RAW_SIZE];
-// OBSOLETE 
-// OBSOLETE   fp = FRAME_FP (frame);
-// OBSOLETE   get_frame_saved_regs (frame, &fsr);
-// OBSOLETE   for (regnum = 0; regnum < NUM_REGS; regnum++)
-// OBSOLETE     {
-// OBSOLETE       CORE_ADDR adr;
-// OBSOLETE       adr = fsr.regs[regnum];
-// OBSOLETE       if (adr)
-// OBSOLETE    {
-// OBSOLETE      read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
-// OBSOLETE      write_register_bytes (REGISTER_BYTE (regnum), regbuf,
-// OBSOLETE                            REGISTER_RAW_SIZE (regnum));
-// OBSOLETE    }
-// OBSOLETE     }
-// OBSOLETE   write_register (FP_REGNUM, read_memory_integer (fp, 4));
-// OBSOLETE   write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
-// OBSOLETE   write_register (SP_REGNUM, fp + 8);
-// OBSOLETE   flush_cached_frames ();
-// OBSOLETE }
-// OBSOLETE \f
-// OBSOLETE /* Simulate single-step.  */
-// OBSOLETE 
-// OBSOLETE typedef enum
-// OBSOLETE {
-// OBSOLETE   NORMAL4,                 /* a normal 4 byte insn */
-// OBSOLETE   NORMAL8,                 /* a normal 8 byte insn */
-// OBSOLETE   BRANCH4,                 /* a 4 byte branch insn, including ones without delay slots */
-// OBSOLETE   BRANCH8,                 /* an 8 byte branch insn, including ones with delay slots */
-// OBSOLETE }
-// OBSOLETE insn_type;
-// OBSOLETE 
-// OBSOLETE /* Return the type of INSN and store in TARGET the destination address of a
-// OBSOLETE    branch if this is one.  */
-// OBSOLETE /* ??? Need to verify all cases are properly handled.  */
-// OBSOLETE 
-// OBSOLETE static insn_type
-// OBSOLETE get_insn_type (unsigned long insn, CORE_ADDR pc, CORE_ADDR *target)
-// OBSOLETE {
-// OBSOLETE   unsigned long limm;
-// OBSOLETE 
-// OBSOLETE   switch (insn >> 27)
-// OBSOLETE     {
-// OBSOLETE     case 0:
-// OBSOLETE     case 1:
-// OBSOLETE     case 2:                        /* load/store insns */
-// OBSOLETE       if (LIMM_P (X_A (insn))
-// OBSOLETE      || LIMM_P (X_B (insn))
-// OBSOLETE      || LIMM_P (X_C (insn)))
-// OBSOLETE    return NORMAL8;
-// OBSOLETE       return NORMAL4;
-// OBSOLETE     case 4:
-// OBSOLETE     case 5:
-// OBSOLETE     case 6:                        /* branch insns */
-// OBSOLETE       *target = pc + 4 + X_L (insn);
-// OBSOLETE       /* ??? It isn't clear that this is always the right answer.
-// OBSOLETE          The problem occurs when the next insn is an 8 byte insn.  If the
-// OBSOLETE          branch is conditional there's no worry as there shouldn't be an 8
-// OBSOLETE          byte insn following.  The programmer may be cheating if s/he knows
-// OBSOLETE          the branch will never be taken, but we don't deal with that.
-// OBSOLETE          Note that the programmer is also allowed to play games by putting
-// OBSOLETE          an insn with long immediate data in the delay slot and then duplicate
-// OBSOLETE          the long immediate data at the branch target.  Ugh!  */
-// OBSOLETE       if (X_N (insn) == 0)
-// OBSOLETE    return BRANCH4;
-// OBSOLETE       return BRANCH8;
-// OBSOLETE     case 7:                        /* jump insns */
-// OBSOLETE       if (LIMM_P (X_B (insn)))
-// OBSOLETE    {
-// OBSOLETE      limm = read_memory_integer (pc + 4, 4);
-// OBSOLETE      *target = ARC_PC_TO_REAL_ADDRESS (limm);
-// OBSOLETE      return BRANCH8;
-// OBSOLETE    }
-// OBSOLETE       if (SHIMM_P (X_B (insn)))
-// OBSOLETE    *target = ARC_PC_TO_REAL_ADDRESS (X_D (insn));
-// OBSOLETE       else
-// OBSOLETE    *target = ARC_PC_TO_REAL_ADDRESS (read_register (X_B (insn)));
-// OBSOLETE       if (X_Q (insn) == 0 && X_N (insn) == 0)
-// OBSOLETE    return BRANCH4;
-// OBSOLETE       return BRANCH8;
-// OBSOLETE     default:                       /* arithmetic insns, etc. */
-// OBSOLETE       if (LIMM_P (X_A (insn))
-// OBSOLETE      || LIMM_P (X_B (insn))
-// OBSOLETE      || LIMM_P (X_C (insn)))
-// OBSOLETE    return NORMAL8;
-// OBSOLETE       return NORMAL4;
-// OBSOLETE     }
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* single_step() is called just before we want to resume the inferior, if we
-// OBSOLETE    want to single-step it but there is no hardware or kernel single-step
-// OBSOLETE    support.  We find all the possible targets of the coming instruction and
-// OBSOLETE    breakpoint them.
-// OBSOLETE 
-// OBSOLETE    single_step is also called just after the inferior stops.  If we had
-// OBSOLETE    set up a simulated single-step, we undo our damage.  */
-// OBSOLETE 
-// OBSOLETE void
-// OBSOLETE arc_software_single_step (enum target_signal ignore,       /* sig but we don't need it */
-// OBSOLETE                      int insert_breakpoints_p)
-// OBSOLETE {
-// OBSOLETE   static CORE_ADDR next_pc, target;
-// OBSOLETE   static int brktrg_p;
-// OBSOLETE   typedef char binsn_quantum[BREAKPOINT_MAX];
-// OBSOLETE   static binsn_quantum break_mem[2];
-// OBSOLETE 
-// OBSOLETE   if (insert_breakpoints_p)
-// OBSOLETE     {
-// OBSOLETE       insn_type type;
-// OBSOLETE       CORE_ADDR pc;
-// OBSOLETE       unsigned long insn;
-// OBSOLETE 
-// OBSOLETE       pc = read_register (PC_REGNUM);
-// OBSOLETE       insn = read_memory_integer (pc, 4);
-// OBSOLETE       type = get_insn_type (insn, pc, &target);
-// OBSOLETE 
-// OBSOLETE       /* Always set a breakpoint for the insn after the branch.  */
-// OBSOLETE       next_pc = pc + ((type == NORMAL8 || type == BRANCH8) ? 8 : 4);
-// OBSOLETE       target_insert_breakpoint (next_pc, break_mem[0]);
-// OBSOLETE 
-// OBSOLETE       brktrg_p = 0;
-// OBSOLETE 
-// OBSOLETE       if ((type == BRANCH4 || type == BRANCH8)
-// OBSOLETE       /* Watch out for branches to the following location.
-// OBSOLETE          We just stored a breakpoint there and another call to
-// OBSOLETE          target_insert_breakpoint will think the real insn is the
-// OBSOLETE          breakpoint we just stored there.  */
-// OBSOLETE      && target != next_pc)
-// OBSOLETE    {
-// OBSOLETE      brktrg_p = 1;
-// OBSOLETE      target_insert_breakpoint (target, break_mem[1]);
-// OBSOLETE    }
-// OBSOLETE 
-// OBSOLETE     }
-// OBSOLETE   else
-// OBSOLETE     {
-// OBSOLETE       /* Remove breakpoints.  */
-// OBSOLETE       target_remove_breakpoint (next_pc, break_mem[0]);
-// OBSOLETE 
-// OBSOLETE       if (brktrg_p)
-// OBSOLETE    target_remove_breakpoint (target, break_mem[1]);
-// OBSOLETE 
-// OBSOLETE       /* Fix the pc.  */
-// OBSOLETE       stop_pc -= DECR_PC_AFTER_BREAK;
-// OBSOLETE       write_pc (stop_pc);
-// OBSOLETE     }
-// OBSOLETE }
-// OBSOLETE \f
-// OBSOLETE /* Because of Multi-arch, GET_LONGJMP_TARGET is always defined.  So test
-// OBSOLETE    for a definition of JB_PC.  */
-// OBSOLETE #ifdef JB_PC
-// OBSOLETE /* Figure out where the longjmp will land.  Slurp the args out of the stack.
-// OBSOLETE    We expect the first arg to be a pointer to the jmp_buf structure from which
-// OBSOLETE    we extract the pc (JB_PC) that we will land at.  The pc is copied into PC.
-// OBSOLETE    This routine returns true on success. */
-// OBSOLETE 
-// OBSOLETE int
-// OBSOLETE get_longjmp_target (CORE_ADDR *pc)
-// OBSOLETE {
-// OBSOLETE   char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
-// OBSOLETE   CORE_ADDR sp, jb_addr;
-// OBSOLETE 
-// OBSOLETE   sp = read_register (SP_REGNUM);
-// OBSOLETE 
-// OBSOLETE   if (target_read_memory (sp + SP_ARG0,            /* Offset of first arg on stack */
-// OBSOLETE                      buf,
-// OBSOLETE                      TARGET_PTR_BIT / TARGET_CHAR_BIT))
-// OBSOLETE     return 0;
-// OBSOLETE 
-// OBSOLETE   jb_addr = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
-// OBSOLETE 
-// OBSOLETE   if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
-// OBSOLETE                      TARGET_PTR_BIT / TARGET_CHAR_BIT))
-// OBSOLETE     return 0;
-// OBSOLETE 
-// OBSOLETE   *pc = extract_address (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
-// OBSOLETE 
-// OBSOLETE   return 1;
-// OBSOLETE }
-// OBSOLETE #endif /* GET_LONGJMP_TARGET */
-// OBSOLETE \f
-// OBSOLETE /* Disassemble one instruction.  */
-// OBSOLETE 
-// OBSOLETE static int
-// OBSOLETE arc_print_insn (bfd_vma vma, disassemble_info *info)
-// OBSOLETE {
-// OBSOLETE   static int current_mach;
-// OBSOLETE   static int current_endian;
-// OBSOLETE   static disassembler_ftype current_disasm;
-// OBSOLETE 
-// OBSOLETE   if (current_disasm == NULL
-// OBSOLETE       || arc_bfd_mach_type != current_mach
-// OBSOLETE       || TARGET_BYTE_ORDER != current_endian)
-// OBSOLETE     {
-// OBSOLETE       current_mach = arc_bfd_mach_type;
-// OBSOLETE       current_endian = TARGET_BYTE_ORDER;
-// OBSOLETE       current_disasm = arc_get_disassembler (NULL);
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   return (*current_disasm) (vma, info);
-// OBSOLETE }
-// OBSOLETE \f
-// OBSOLETE /* Command to set cpu type.  */
-// OBSOLETE 
-// OBSOLETE void
-// OBSOLETE arc_set_cpu_type_command (char *args, int from_tty)
-// OBSOLETE {
-// OBSOLETE   int i;
-// OBSOLETE 
-// OBSOLETE   if (tmp_arc_cpu_type == NULL || *tmp_arc_cpu_type == '\0')
-// OBSOLETE     {
-// OBSOLETE       printf_unfiltered ("The known ARC cpu types are as follows:\n");
-// OBSOLETE       for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
-// OBSOLETE    printf_unfiltered ("%s\n", arc_cpu_type_table[i].name);
-// OBSOLETE 
-// OBSOLETE       /* Restore the value.  */
-// OBSOLETE       tmp_arc_cpu_type = xstrdup (arc_cpu_type);
-// OBSOLETE 
-// OBSOLETE       return;
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   if (!arc_set_cpu_type (tmp_arc_cpu_type))
-// OBSOLETE     {
-// OBSOLETE       error ("Unknown cpu type `%s'.", tmp_arc_cpu_type);
-// OBSOLETE       /* Restore its value.  */
-// OBSOLETE       tmp_arc_cpu_type = xstrdup (arc_cpu_type);
-// OBSOLETE     }
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE static void
-// OBSOLETE arc_show_cpu_type_command (char *args, int from_tty)
-// OBSOLETE {
-// OBSOLETE }
-// OBSOLETE 
-// OBSOLETE /* Modify the actual cpu type.
-// OBSOLETE    Result is a boolean indicating success.  */
-// OBSOLETE 
-// OBSOLETE static int
-// OBSOLETE arc_set_cpu_type (char *str)
-// OBSOLETE {
-// OBSOLETE   int i, j;
-// OBSOLETE 
-// OBSOLETE   if (str == NULL)
-// OBSOLETE     return 0;
-// OBSOLETE 
-// OBSOLETE   for (i = 0; arc_cpu_type_table[i].name != NULL; ++i)
-// OBSOLETE     {
-// OBSOLETE       if (strcasecmp (str, arc_cpu_type_table[i].name) == 0)
-// OBSOLETE    {
-// OBSOLETE      arc_cpu_type = str;
-// OBSOLETE      arc_bfd_mach_type = arc_cpu_type_table[i].value;
-// OBSOLETE      return 1;
-// OBSOLETE    }
-// OBSOLETE     }
-// OBSOLETE 
-// OBSOLETE   return 0;
-// OBSOLETE }
-// OBSOLETE \f
-// OBSOLETE void
-// OBSOLETE _initialize_arc_tdep (void)
-// OBSOLETE {
-// OBSOLETE   struct cmd_list_element *c;
-// OBSOLETE 
-// OBSOLETE   c = add_set_cmd ("cpu", class_support, var_string_noescape,
-// OBSOLETE               (char *) &tmp_arc_cpu_type,
-// OBSOLETE               "Set the type of ARC cpu in use.\n\
-// OBSOLETE This command has two purposes.  In a multi-cpu system it lets one\n\
-// OBSOLETE change the cpu being debugged.  It also gives one access to\n\
-// OBSOLETE cpu-type-specific registers and recognize cpu-type-specific instructions.\
-// OBSOLETE ",
-// OBSOLETE               &setlist);
-// OBSOLETE   set_cmd_cfunc (c, arc_set_cpu_type_command);
-// OBSOLETE   c = add_show_from_set (c, &showlist);
-// OBSOLETE   set_cmd_cfunc (c, arc_show_cpu_type_command);
-// OBSOLETE 
-// OBSOLETE   /* We have to use xstrdup() here because the `set' command frees it
-// OBSOLETE      before setting a new value.  */
-// OBSOLETE   tmp_arc_cpu_type = xstrdup (DEFAULT_ARC_CPU_TYPE);
-// OBSOLETE   arc_set_cpu_type (tmp_arc_cpu_type);
-// OBSOLETE 
-// OBSOLETE   c = add_set_cmd ("displaypipeline", class_support, var_zinteger,
-// OBSOLETE               (char *) &display_pipeline_p,
-// OBSOLETE               "Set pipeline display (simulator only).\n\
-// OBSOLETE When enabled, the state of the pipeline after each cycle is displayed.",
-// OBSOLETE               &setlist);
-// OBSOLETE   c = add_show_from_set (c, &showlist);
-// OBSOLETE 
-// OBSOLETE   c = add_set_cmd ("debugpipeline", class_support, var_zinteger,
-// OBSOLETE               (char *) &debug_pipeline_p,
-// OBSOLETE               "Set pipeline debug display (simulator only).\n\
-// OBSOLETE When enabled, debugging information about the pipeline is displayed.",
-// OBSOLETE               &setlist);
-// OBSOLETE   c = add_show_from_set (c, &showlist);
-// OBSOLETE 
-// OBSOLETE   c = add_set_cmd ("cputimer", class_support, var_zinteger,
-// OBSOLETE               (char *) &cpu_timer,
-// OBSOLETE               "Set maximum cycle count (simulator only).\n\
-// OBSOLETE Control will return to gdb if the timer expires.\n\
-// OBSOLETE A negative value disables the timer.",
-// OBSOLETE               &setlist);
-// OBSOLETE   c = add_show_from_set (c, &showlist);
-// OBSOLETE 
-// OBSOLETE   tm_print_insn = arc_print_insn;
-// OBSOLETE }
+/* Target dependent code for ARC architecture, for GDB.
+
+   Copyright 2005-2022 Free Software Foundation, Inc.
+   Contributed by Synopsys Inc.
+
+   This file is part of GDB.
+
+   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.
+
+   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 "arch-utils.h"
+#include "elf-bfd.h"
+#include "disasm.h"
+#include "dwarf2/frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "gdbcore.h"
+#include "reggroups.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "osabi.h"
+#include "prologue-value.h"
+#include "target-descriptions.h"
+#include "trad-frame.h"
+
+/* ARC header files.  */
+#include "opcode/arc.h"
+#include "opcodes/arc-dis.h"
+#include "arc-tdep.h"
+#include "arch/arc.h"
+
+/* Standard headers.  */
+#include <algorithm>
+#include <sstream>
+
+/* The frame unwind cache for ARC.  */
+
+struct arc_frame_cache
+{
+  /* 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;
+
+  /* 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.  */
+  trad_frame_saved_reg *saved_regs;
+};
+
+/* Global debug flag.  */
+
+bool arc_debug;
+
+/* List of "maintenance print arc" commands.  */
+
+static struct cmd_list_element *maintenance_print_arc_list = NULL;
+
+/* A set of registers that we expect to find in a tdesc_feature.  These
+   are used in ARC_TDESC_INIT when processing the target description.  */
+
+struct arc_register_feature
+{
+  /* Information for a single register.  */
+  struct register_info
+  {
+    /* The GDB register number for this register.  */
+    int regnum;
+
+    /* List of names for this register.  The first name in this list is the
+       preferred name, the name GDB will use when describing this register.  */
+    std::vector<const char *> names;
+
+    /* When true, this register must be present in this feature set.  */
+    bool required_p;
+  };
+
+  /* The name for this feature.  This is the name used to find this feature
+     within the target description.  */
+  const char *name;
+
+  /* List of all the registers that we expect to encounter in this register
+     set.  */
+  std::vector<struct register_info> registers;
+};
+
+/* Obsolete feature names for backward compatibility.  */
+static const char *ARC_CORE_V1_OBSOLETE_FEATURE_NAME
+  = "org.gnu.gdb.arc.core.arcompact";
+static const char *ARC_CORE_V2_OBSOLETE_FEATURE_NAME
+  = "org.gnu.gdb.arc.core.v2";
+static const char *ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME
+  = "org.gnu.gdb.arc.core-reduced.v2";
+static const char *ARC_AUX_OBSOLETE_FEATURE_NAME
+  = "org.gnu.gdb.arc.aux-minimal";
+/* Modern feature names.  */
+static const char *ARC_CORE_FEATURE_NAME = "org.gnu.gdb.arc.core";
+static const char *ARC_AUX_FEATURE_NAME = "org.gnu.gdb.arc.aux";
+
+/* ARCv1 (ARC600, ARC601, ARC700) general core registers feature set.
+   See also arc_update_acc_reg_names() for "accl/acch" names.  */
+
+static struct arc_register_feature arc_v1_core_reg_feature =
+{
+  ARC_CORE_FEATURE_NAME,
+  {
+    { ARC_R0_REGNUM + 0, { "r0" }, true },
+    { ARC_R0_REGNUM + 1, { "r1" }, true },
+    { ARC_R0_REGNUM + 2, { "r2" }, true },
+    { ARC_R0_REGNUM + 3, { "r3" }, true },
+    { ARC_R0_REGNUM + 4, { "r4" }, false },
+    { ARC_R0_REGNUM + 5, { "r5" }, false },
+    { ARC_R0_REGNUM + 6, { "r6" }, false },
+    { ARC_R0_REGNUM + 7, { "r7" }, false },
+    { ARC_R0_REGNUM + 8, { "r8" }, false },
+    { ARC_R0_REGNUM + 9, { "r9" }, false },
+    { ARC_R0_REGNUM + 10, { "r10" }, true },
+    { ARC_R0_REGNUM + 11, { "r11" }, true },
+    { ARC_R0_REGNUM + 12, { "r12" }, true },
+    { ARC_R0_REGNUM + 13, { "r13" }, true },
+    { ARC_R0_REGNUM + 14, { "r14" }, true },
+    { ARC_R0_REGNUM + 15, { "r15" }, true },
+    { ARC_R0_REGNUM + 16, { "r16" }, false },
+    { ARC_R0_REGNUM + 17, { "r17" }, false },
+    { ARC_R0_REGNUM + 18, { "r18" }, false },
+    { ARC_R0_REGNUM + 19, { "r19" }, false },
+    { ARC_R0_REGNUM + 20, { "r20" }, false },
+    { ARC_R0_REGNUM + 21, { "r21" }, false },
+    { ARC_R0_REGNUM + 22, { "r22" }, false },
+    { ARC_R0_REGNUM + 23, { "r23" }, false },
+    { ARC_R0_REGNUM + 24, { "r24" }, false },
+    { ARC_R0_REGNUM + 25, { "r25" }, false },
+    { ARC_R0_REGNUM + 26, { "gp" }, true },
+    { ARC_R0_REGNUM + 27, { "fp" }, true },
+    { ARC_R0_REGNUM + 28, { "sp" }, true },
+    { ARC_R0_REGNUM + 29, { "ilink1" }, false },
+    { ARC_R0_REGNUM + 30, { "ilink2" }, false },
+    { ARC_R0_REGNUM + 31, { "blink" }, true },
+    { ARC_R0_REGNUM + 32, { "r32" }, false },
+    { ARC_R0_REGNUM + 33, { "r33" }, false },
+    { ARC_R0_REGNUM + 34, { "r34" }, false },
+    { ARC_R0_REGNUM + 35, { "r35" }, false },
+    { ARC_R0_REGNUM + 36, { "r36" }, false },
+    { ARC_R0_REGNUM + 37, { "r37" }, false },
+    { ARC_R0_REGNUM + 38, { "r38" }, false },
+    { ARC_R0_REGNUM + 39, { "r39" }, false },
+    { ARC_R0_REGNUM + 40, { "r40" }, false },
+    { ARC_R0_REGNUM + 41, { "r41" }, false },
+    { ARC_R0_REGNUM + 42, { "r42" }, false },
+    { ARC_R0_REGNUM + 43, { "r43" }, false },
+    { ARC_R0_REGNUM + 44, { "r44" }, false },
+    { ARC_R0_REGNUM + 45, { "r45" }, false },
+    { ARC_R0_REGNUM + 46, { "r46" }, false },
+    { ARC_R0_REGNUM + 47, { "r47" }, false },
+    { ARC_R0_REGNUM + 48, { "r48" }, false },
+    { ARC_R0_REGNUM + 49, { "r49" }, false },
+    { ARC_R0_REGNUM + 50, { "r50" }, false },
+    { ARC_R0_REGNUM + 51, { "r51" }, false },
+    { ARC_R0_REGNUM + 52, { "r52" }, false },
+    { ARC_R0_REGNUM + 53, { "r53" }, false },
+    { ARC_R0_REGNUM + 54, { "r54" }, false },
+    { ARC_R0_REGNUM + 55, { "r55" }, false },
+    { ARC_R0_REGNUM + 56, { "r56" }, false },
+    { ARC_R0_REGNUM + 57, { "r57" }, false },
+    { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
+    { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
+    { ARC_R0_REGNUM + 60, { "lp_count" }, false },
+    { ARC_R0_REGNUM + 61, { "reserved" }, false },
+    { ARC_R0_REGNUM + 62, { "limm" }, false },
+    { ARC_R0_REGNUM + 63, { "pcl" }, true }
+  }
+};
+
+/* ARCv2 (ARCHS) general core registers feature set.  See also
+   arc_update_acc_reg_names() for "accl/acch" names.  */
+
+static struct arc_register_feature arc_v2_core_reg_feature =
+{
+  ARC_CORE_FEATURE_NAME,
+  {
+    { ARC_R0_REGNUM + 0, { "r0" }, true },
+    { ARC_R0_REGNUM + 1, { "r1" }, true },
+    { ARC_R0_REGNUM + 2, { "r2" }, true },
+    { ARC_R0_REGNUM + 3, { "r3" }, true },
+    { ARC_R0_REGNUM + 4, { "r4" }, false },
+    { ARC_R0_REGNUM + 5, { "r5" }, false },
+    { ARC_R0_REGNUM + 6, { "r6" }, false },
+    { ARC_R0_REGNUM + 7, { "r7" }, false },
+    { ARC_R0_REGNUM + 8, { "r8" }, false },
+    { ARC_R0_REGNUM + 9, { "r9" }, false },
+    { ARC_R0_REGNUM + 10, { "r10" }, true },
+    { ARC_R0_REGNUM + 11, { "r11" }, true },
+    { ARC_R0_REGNUM + 12, { "r12" }, true },
+    { ARC_R0_REGNUM + 13, { "r13" }, true },
+    { ARC_R0_REGNUM + 14, { "r14" }, true },
+    { ARC_R0_REGNUM + 15, { "r15" }, true },
+    { ARC_R0_REGNUM + 16, { "r16" }, false },
+    { ARC_R0_REGNUM + 17, { "r17" }, false },
+    { ARC_R0_REGNUM + 18, { "r18" }, false },
+    { ARC_R0_REGNUM + 19, { "r19" }, false },
+    { ARC_R0_REGNUM + 20, { "r20" }, false },
+    { ARC_R0_REGNUM + 21, { "r21" }, false },
+    { ARC_R0_REGNUM + 22, { "r22" }, false },
+    { ARC_R0_REGNUM + 23, { "r23" }, false },
+    { ARC_R0_REGNUM + 24, { "r24" }, false },
+    { ARC_R0_REGNUM + 25, { "r25" }, false },
+    { ARC_R0_REGNUM + 26, { "gp" }, true },
+    { ARC_R0_REGNUM + 27, { "fp" }, true },
+    { ARC_R0_REGNUM + 28, { "sp" }, true },
+    { ARC_R0_REGNUM + 29, { "ilink" }, false },
+    { ARC_R0_REGNUM + 30, { "r30" }, true },
+    { ARC_R0_REGNUM + 31, { "blink" }, true },
+    { ARC_R0_REGNUM + 32, { "r32" }, false },
+    { ARC_R0_REGNUM + 33, { "r33" }, false },
+    { ARC_R0_REGNUM + 34, { "r34" }, false },
+    { ARC_R0_REGNUM + 35, { "r35" }, false },
+    { ARC_R0_REGNUM + 36, { "r36" }, false },
+    { ARC_R0_REGNUM + 37, { "r37" }, false },
+    { ARC_R0_REGNUM + 38, { "r38" }, false },
+    { ARC_R0_REGNUM + 39, { "r39" }, false },
+    { ARC_R0_REGNUM + 40, { "r40" }, false },
+    { ARC_R0_REGNUM + 41, { "r41" }, false },
+    { ARC_R0_REGNUM + 42, { "r42" }, false },
+    { ARC_R0_REGNUM + 43, { "r43" }, false },
+    { ARC_R0_REGNUM + 44, { "r44" }, false },
+    { ARC_R0_REGNUM + 45, { "r45" }, false },
+    { ARC_R0_REGNUM + 46, { "r46" }, false },
+    { ARC_R0_REGNUM + 47, { "r47" }, false },
+    { ARC_R0_REGNUM + 48, { "r48" }, false },
+    { ARC_R0_REGNUM + 49, { "r49" }, false },
+    { ARC_R0_REGNUM + 50, { "r50" }, false },
+    { ARC_R0_REGNUM + 51, { "r51" }, false },
+    { ARC_R0_REGNUM + 52, { "r52" }, false },
+    { ARC_R0_REGNUM + 53, { "r53" }, false },
+    { ARC_R0_REGNUM + 54, { "r54" }, false },
+    { ARC_R0_REGNUM + 55, { "r55" }, false },
+    { ARC_R0_REGNUM + 56, { "r56" }, false },
+    { ARC_R0_REGNUM + 57, { "r57" }, false },
+    { ARC_R0_REGNUM + 58, { "r58", "accl" }, false },
+    { ARC_R0_REGNUM + 59, { "r59", "acch" }, false },
+    { ARC_R0_REGNUM + 60, { "lp_count" }, false },
+    { ARC_R0_REGNUM + 61, { "reserved" }, false },
+    { ARC_R0_REGNUM + 62, { "limm" }, false },
+    { ARC_R0_REGNUM + 63, { "pcl" }, true }
+  }
+};
+
+/* The common auxiliary registers feature set.  The REGNUM field
+   must match the ARC_REGNUM enum in arc-tdep.h.  */
+
+static const struct arc_register_feature arc_common_aux_reg_feature =
+{
+  ARC_AUX_FEATURE_NAME,
+  {
+    { ARC_FIRST_AUX_REGNUM + 0, { "pc" }, true },
+    { ARC_FIRST_AUX_REGNUM + 1, { "status32" }, true },
+    { ARC_FIRST_AUX_REGNUM + 2, { "lp_start" }, false },
+    { ARC_FIRST_AUX_REGNUM + 3, { "lp_end" }, false },
+    { ARC_FIRST_AUX_REGNUM + 4, { "bta" }, false }
+  }
+};
+
+static char *arc_disassembler_options = NULL;
+
+/* Functions are sorted in the order as they are used in the
+   _initialize_arc_tdep (), which uses the same order as gdbarch.h.  Static
+   functions are defined before the first invocation.  */
+
+/* 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)
+    {
+      gdb_printf (gdb_stderr,
+                 "JLI_S instruction is not supported by the GDB.");
+      return 0;
+    }
+  else if (insn.insn_class == EI)
+    {
+      gdb_printf (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
+   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
+arc_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+
+  arc_debug_printf ("Writing PC, new value=%s",
+                   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);
+
+  if ((status32 & ARC_STATUS32_DE_MASK) != 0)
+    {
+      arc_debug_printf ("Changing PC while in delay slot.  Will "
+                       "reset STATUS32.DE bit to zero.  Value of STATUS32 "
+                       "register is 0x%s",
+                       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
+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 "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.
+
+   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,
+                    function_call_return_method return_method,
+                    CORE_ADDR struct_addr)
+{
+  arc_debug_printf ("nargs = %d", nargs);
+
+  int arg_reg = ARC_FIRST_ARG_REGNUM;
+
+  /* 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 (return_method == return_method_struct)
+    {
+      /* Pass the return address in the first argument register.  */
+      regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
+
+      arc_debug_printf ("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++)
+       {
+         unsigned int len = TYPE_LENGTH (value_type (args[i]));
+         unsigned int space = align_up (len, 4);
+
+         total_space += space;
+
+         arc_debug_printf ("arg %d: %u bytes -> %u", i, len, space);
+       }
+
+      /* 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++)
+       {
+         unsigned int len = TYPE_LENGTH (value_type (args[i]));
+         unsigned int space = align_up (len, 4);
+
+         memcpy (data, value_contents (args[i]).data (), (size_t) len);
+         arc_debug_printf ("copying arg %d, val 0x%08x, len %d to mem",
+                           i, *((int *) value_contents (args[i]).data ()),
+                           len);
+
+         data += space;
+       }
+
+      /* Now load as much as possible of the memory image into registers.  */
+      data = memory_image;
+      while (arg_reg <= ARC_LAST_ARG_REGNUM)
+       {
+         arc_debug_printf ("passing 0x%02x%02x%02x%02x in register R%d",
+                           data[0], data[1], data[2], data[3], arg_reg);
+
+         /* Note we don't use write_unsigned here, since that would convert
+            the byte order, but we are already in the correct byte order.  */
+         regcache->cooked_write (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)
+       {
+         arc_debug_printf ("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.  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.  */
+
+static int
+arc_cannot_store_register (struct gdbarch *gdbarch, int regnum)
+{
+  /* 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;
+    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);
+
+  arc_debug_printf ("called");
+
+  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);
+
+      arc_debug_printf ("returning 0x%s", 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);
+
+      arc_debug_printf ("returning 0x%s%s",
+                       phex (high, ARC_REGISTER_SIZE),
+                       phex (low, ARC_REGISTER_SIZE));
+    }
+  else
+    error (_("arc: extract_return_value: type length %u too large"), len);
+}
+
+
+/* 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);
+
+  arc_debug_printf ("called");
+
+  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);
+
+      arc_debug_printf ("storing 0x%s", 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);
+
+      arc_debug_printf ("storing 0x%s%s",
+                       phex (high, ARC_REGISTER_SIZE),
+                       phex (low, ARC_REGISTER_SIZE));
+    }
+  else
+    error (_("arc_store_return_value: type length too large."));
+}
+
+/* Implement the "get_longjmp_target" gdbarch method.  */
+
+static int
+arc_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+  arc_debug_printf ("called");
+
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  int pc_offset = tdep->jb_pc * ARC_REGISTER_SIZE;
+  gdb_byte buf[ARC_REGISTER_SIZE];
+  CORE_ADDR jb_addr = get_frame_register_unsigned (frame, ARC_FIRST_ARG_REGNUM);
+
+  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 = (valtype->code () == TYPE_CODE_STRUCT
+                         || valtype->code () == TYPE_CODE_UNION
+                         || TYPE_LENGTH (valtype) > 2 * ARC_REGISTER_SIZE);
+
+  arc_debug_printf ("readbuf = %s, writebuf = %s",
+                   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);
+}
+
+/* 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;
+}
+
+/* See arc-tdep.h.  */
+
+struct disassemble_info
+arc_disassemble_info (struct gdbarch *gdbarch)
+{
+  struct disassemble_info di;
+  init_disassemble_info_for_no_printing (&di);
+  di.arch = gdbarch_bfd_arch_info (gdbarch)->arch;
+  di.mach = gdbarch_bfd_arch_info (gdbarch)->mach;
+  di.endian = gdbarch_byte_order (gdbarch);
+  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)
+{
+  arc_debug_printf ("entrypoint=%s, limit_pc=%s",
+                   paddress (gdbarch, entrypoint),
+                   paddress (gdbarch, limit_pc));
+
+  /* Prologue values.  Only core registers can be stored.  */
+  pv_t regs[ARC_LAST_CORE_REGNUM + 1];
+  for (int i = 0; i <= ARC_LAST_CORE_REGNUM; i++)
+    regs[i] = pv_register (i, 0);
+  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)
+       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.  */
+         arc_debug_printf ("End of prologue reached at address %s",
+                           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].set_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
+   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)
+{
+  arc_debug_printf ("pc = %s", paddress (gdbarch, pc));
+
+  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);
+    }
+
+  /* No prologue info in symbol table, have to analyze prologue.  */
+
+  /* Find an upper limit on the function prologue using the debug
+     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);
+
+  /* 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.
+
+   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.  */
+
+int
+arc_delayed_print_insn (bfd_vma addr, struct disassemble_info *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.
+
+   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)
+{
+  gdb_assert (kind == 2 || kind == 4);
+  *size = kind;
+
+  if (kind == sizeof (arc_brk_le))
+    {
+      return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+             ? arc_brk_be
+             : arc_brk_le);
+    }
+  else
+    {
+      return ((gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+             ? arc_brk_s_be
+             : arc_brk_s_le);
+    }
+}
+
+/* Implement the "frame_align" gdbarch method.  */
+
+static CORE_ADDR
+arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  return align_down (sp, 4);
+}
+
+/* Dump the frame info.  Used for internal debugging only.  */
+
+static void
+arc_print_frame_cache (struct gdbarch *gdbarch, const char *message,
+                      struct arc_frame_cache *cache, int addresses_known)
+{
+  arc_debug_printf ("frame_info %s", message);
+  arc_debug_printf ("prev_sp = %s", paddress (gdbarch, cache->prev_sp));
+  arc_debug_printf ("frame_base_reg = %i", cache->frame_base_reg);
+  arc_debug_printf ("frame_base_offset = %s",
+                   plongest (cache->frame_base_offset));
+
+  for (int i = 0; i <= ARC_BLINK_REGNUM; i++)
+    {
+      if (cache->saved_regs[i].is_addr ())
+       arc_debug_printf ("saved register %s at %s %s",
+                         gdbarch_register_name (gdbarch, i),
+                         (addresses_known) ? "address" : "offset",
+                             paddress (gdbarch, cache->saved_regs[i].addr ()));
+    }
+}
+
+/* Frame unwinder for normal frames.  */
+
+static struct arc_frame_cache *
+arc_make_frame_cache (struct frame_info *this_frame)
+{
+  arc_debug_printf ("called");
+
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
+  CORE_ADDR block_addr = get_frame_address_in_block (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;
+      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
+    {
+      /* 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 = entrypoint + MAX_PROLOGUE_LENGTH;
+    }
+
+  /* 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);
+
+  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 (cache->saved_regs[i].is_addr ())
+       cache->saved_regs[i].set_addr (cache->saved_regs[i].addr ()
+                                      + cache->prev_sp);
+    }
+
+  if (arc_debug)
+    arc_print_frame_cache (gdbarch, "after previous SP found", cache, true);
+
+  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)
+{
+  arc_debug_printf ("called");
+
+  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;
+}
+
+/*  Signal trampoline frame unwinder.  Allows frame unwinding to happen
+    from within signal handlers.  */
+
+static struct arc_frame_cache *
+arc_make_sigtramp_frame_cache (struct frame_info *this_frame)
+{
+  arc_debug_printf ("called");
+
+  gdbarch *arch = get_frame_arch (this_frame);
+  arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
+
+  /* Allocate new frame cache instance and space for saved register info.  */
+  struct arc_frame_cache *cache = FRAME_OBSTACK_ZALLOC (struct arc_frame_cache);
+  cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+
+  /* Get the stack pointer and use it as the frame base.  */
+  cache->prev_sp = arc_frame_base_address (this_frame, NULL);
+
+  /* If the ARC-private target-dependent info doesn't have a table of
+     offsets of saved register contents within an OS signal context
+     structure, then there is nothing to analyze.  */
+  if (tdep->sc_reg_offset == NULL)
+    return cache;
+
+  /* Find the address of the sigcontext structure.  */
+  CORE_ADDR addr = tdep->sigcontext_addr (this_frame);
+
+  /* For each register, if its contents have been saved within the
+     sigcontext structure, determine the address of those contents.  */
+  gdb_assert (tdep->sc_num_regs <= (ARC_LAST_REGNUM + 1));
+  for (int i = 0; i < tdep->sc_num_regs; i++)
+    {
+      if (tdep->sc_reg_offset[i] != ARC_OFFSET_NO_REGISTER)
+       cache->saved_regs[i].set_addr (addr + tdep->sc_reg_offset[i]);
+    }
+
+  return cache;
+}
+
+/* Implement the "this_id" frame_unwind method for signal trampoline
+   frames.  */
+
+static void
+arc_sigtramp_frame_this_id (struct frame_info *this_frame,
+                           void **this_cache, struct frame_id *this_id)
+{
+  arc_debug_printf ("called");
+
+  if (*this_cache == NULL)
+    *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+  CORE_ADDR stack_addr = cache->prev_sp;
+  CORE_ADDR code_addr
+    = get_frame_register_unsigned (this_frame, gdbarch_pc_regnum (gdbarch));
+  *this_id = frame_id_build (stack_addr, code_addr);
+}
+
+/* Get a register from a signal handler frame.  */
+
+static struct value *
+arc_sigtramp_frame_prev_register (struct frame_info *this_frame,
+                                 void **this_cache, int regnum)
+{
+  arc_debug_printf ("regnum = %d", regnum);
+
+  /* Make sure we've initialized the cache.  */
+  if (*this_cache == NULL)
+    *this_cache = arc_make_sigtramp_frame_cache (this_frame);
+
+  struct arc_frame_cache *cache = (struct arc_frame_cache *) *this_cache;
+  return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
+}
+
+/* Frame sniffer for signal handler frame.  Only recognize a frame if we
+   have a sigcontext_addr handler in the target dependency.  */
+
+static int
+arc_sigtramp_frame_sniffer (const struct frame_unwind *self,
+                           struct frame_info *this_frame,
+                           void **this_cache)
+{
+  arc_debug_printf ("called");
+
+  gdbarch *arch = get_frame_arch (this_frame);
+  arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (arch);
+
+  /* If we have a sigcontext_addr handler, then just return 1 (same as the
+     "default_frame_sniffer ()").  */
+  return (tdep->sigcontext_addr != NULL && tdep->is_sigtramp != NULL
+         && tdep->is_sigtramp (this_frame));
+}
+
+/* Structure defining the ARC ordinary frame unwind functions.  Since we are
+   the fallback unwinder, we use the default frame sniffer, which always
+   accepts the frame.  */
+
+static const struct frame_unwind arc_frame_unwind = {
+  "arc prologue",
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  arc_frame_this_id,
+  arc_frame_prev_register,
+  NULL,
+  default_frame_sniffer,
+  NULL,
+  NULL
+};
+
+/* Structure defining the ARC signal frame unwind functions.  Custom
+   sniffer is used, because this frame must be accepted only in the right
+   context.  */
+
+static const struct frame_unwind arc_sigtramp_frame_unwind = {
+  "arc sigtramp",
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  arc_sigtramp_frame_this_id,
+  arc_sigtramp_frame_prev_register,
+  NULL,
+  arc_sigtramp_frame_sniffer,
+  NULL,
+  NULL
+};
+
+
+static const struct frame_base arc_normal_base = {
+  &arc_frame_unwind,
+  arc_frame_base_address,
+  arc_frame_base_address,
+  arc_frame_base_address
+};
+
+static enum arc_isa
+mach_type_to_arc_isa (const unsigned long mach)
+{
+  switch (mach)
+    {
+    case bfd_mach_arc_arc600:
+    case bfd_mach_arc_arc601:
+    case bfd_mach_arc_arc700:
+      return ARC_ISA_ARCV1;
+    case bfd_mach_arc_arcv2:
+      return ARC_ISA_ARCV2;
+    default:
+       internal_error (__FILE__, __LINE__,
+                       _("unknown machine id %lu"), mach);
+    }
+}
+
+/* See arc-tdep.h.  */
+
+arc_arch_features
+arc_arch_features_create (const bfd *abfd, const unsigned long mach)
+{
+  /* Use 4 as a fallback value.  */
+  int reg_size = 4;
+
+  /* Try to guess the features parameters by looking at the binary to be
+     executed.  If the user is providing a binary that does not match the
+     target, then tough luck.  This is the last effort to makes sense of
+     what's going on.  */
+  if (abfd != nullptr && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    {
+      unsigned char eclass = elf_elfheader (abfd)->e_ident[EI_CLASS];
+
+      if (eclass == ELFCLASS32)
+       reg_size = 4;
+      else if (eclass == ELFCLASS64)
+       reg_size = 8;
+      else
+       internal_error (__FILE__, __LINE__,
+                       _("unknown ELF header class %d"), eclass);
+    }
+
+  /* MACH from a bfd_arch_info struct is used here.  It should be a safe
+     bet, as it looks like the struct is always initialized even when we
+     don't pass any elf file to GDB at all (it uses default arch in that
+     case).  */
+  arc_isa isa = mach_type_to_arc_isa (mach);
+
+  return arc_arch_features (reg_size, isa);
+}
+
+/* Look for obsolete core feature names in TDESC.  */
+
+static const struct tdesc_feature *
+find_obsolete_core_names (const struct target_desc *tdesc)
+{
+  const struct tdesc_feature *feat = nullptr;
+
+  feat = tdesc_find_feature (tdesc, ARC_CORE_V1_OBSOLETE_FEATURE_NAME);
+
+  if (feat == nullptr)
+    feat = tdesc_find_feature (tdesc, ARC_CORE_V2_OBSOLETE_FEATURE_NAME);
+
+  if (feat == nullptr)
+    feat = tdesc_find_feature
+      (tdesc, ARC_CORE_V2_REDUCED_OBSOLETE_FEATURE_NAME);
+
+  return feat;
+}
+
+/* Look for obsolete aux feature names in TDESC.  */
+
+static const struct tdesc_feature *
+find_obsolete_aux_names (const struct target_desc *tdesc)
+{
+  return tdesc_find_feature (tdesc, ARC_AUX_OBSOLETE_FEATURE_NAME);
+}
+
+/* Based on the MACH value, determines which core register features set
+   must be used.  */
+
+static arc_register_feature *
+determine_core_reg_feature_set (const unsigned long mach)
+{
+  switch (mach_type_to_arc_isa (mach))
+    {
+    case ARC_ISA_ARCV1:
+      return &arc_v1_core_reg_feature;
+    case ARC_ISA_ARCV2:
+      return &arc_v2_core_reg_feature;
+    default:
+      gdb_assert_not_reached
+       ("Unknown machine type to determine the core feature set.");
+    }
+}
+
+/* At the moment, there is only 1 auxiliary register features set.
+   This is a place holder for future extendability.  */
+
+static const arc_register_feature *
+determine_aux_reg_feature_set ()
+{
+  return &arc_common_aux_reg_feature;
+}
+
+/* Update accumulator register names (ACCH/ACCL) for r58 and r59 in the
+   register sets.  The endianness determines the assignment:
+
+       ,------.------.
+       | acch | accl |
+   ,----|------+------|
+   | LE | r59  | r58  |
+   | BE | r58  | r59  |
+   `----^------^------'  */
+
+static void
+arc_update_acc_reg_names (const int byte_order)
+{
+  const char *r58_alias
+    = byte_order == BFD_ENDIAN_LITTLE ? "accl" : "acch";
+  const char *r59_alias
+    = byte_order == BFD_ENDIAN_LITTLE ? "acch" : "accl";
+
+  /* Subscript 1 must be OK because those registers have 2 names.  */
+  arc_v1_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
+  arc_v1_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
+  arc_v2_core_reg_feature.registers[ARC_R58_REGNUM].names[1] = r58_alias;
+  arc_v2_core_reg_feature.registers[ARC_R59_REGNUM].names[1] = r59_alias;
+}
+
+/* Go through all the registers in REG_SET and check if they exist
+   in FEATURE.  The TDESC_DATA is updated with the register number
+   in REG_SET if it is found in the feature.  If a required register
+   is not found, this function returns false.  */
+
+static bool
+arc_check_tdesc_feature (struct tdesc_arch_data *tdesc_data,
+                        const struct tdesc_feature *feature,
+                        const struct arc_register_feature *reg_set)
+{
+  for (const auto &reg : reg_set->registers)
+    {
+      bool found = false;
+
+      for (const char *name : reg.names)
+       {
+         found
+           = tdesc_numbered_register (feature, tdesc_data, reg.regnum, name);
+
+         if (found)
+           break;
+       }
+
+      if (!found && reg.required_p)
+       {
+         std::ostringstream reg_names;
+         for (std::size_t i = 0; i < reg.names.size(); ++i)
+           {
+             if (i == 0)
+               reg_names << "'" << reg.names[0] << "'";
+             else
+               reg_names << " or '" << reg.names[0] << "'";
+           }
+         arc_print (_("Error: Cannot find required register(s) %s "
+                      "in feature '%s'.\n"), reg_names.str ().c_str (),
+                      feature->name.c_str ());
+         return false;
+       }
+    }
+
+  return true;
+}
+
+/* Check for the existance of "lp_start" and "lp_end" in target description.
+   If both are present, assume there is hardware loop support in the target.
+   This can be improved by looking into "lpc_size" field of "isa_config"
+   auxiliary register.  */
+
+static bool
+arc_check_for_hw_loops (const struct target_desc *tdesc,
+                       struct tdesc_arch_data *data)
+{
+  const auto feature_aux = tdesc_find_feature (tdesc, ARC_AUX_FEATURE_NAME);
+  const auto aux_regset = determine_aux_reg_feature_set ();
+
+  if (feature_aux == nullptr)
+    return false;
+
+  bool hw_loop_p = false;
+  const auto lp_start_name =
+    aux_regset->registers[ARC_LP_START_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
+  const auto lp_end_name =
+    aux_regset->registers[ARC_LP_END_REGNUM - ARC_FIRST_AUX_REGNUM].names[0];
+
+  hw_loop_p = tdesc_numbered_register (feature_aux, data,
+                                      ARC_LP_START_REGNUM, lp_start_name);
+  hw_loop_p &= tdesc_numbered_register (feature_aux, data,
+                                      ARC_LP_END_REGNUM, lp_end_name);
+
+  return hw_loop_p;
+}
+
+/* Initialize target description for the ARC.
+
+   Returns true if input TDESC was valid and in this case it will assign TDESC
+   and TDESC_DATA output parameters.  */
+
+static bool
+arc_tdesc_init (struct gdbarch_info info, const struct target_desc **tdesc,
+               tdesc_arch_data_up *tdesc_data)
+{
+  const struct target_desc *tdesc_loc = info.target_desc;
+  arc_debug_printf ("Target description initialization.");
+
+  /* If target doesn't provide a description, use the default ones.  */
+  if (!tdesc_has_registers (tdesc_loc))
+    {
+      arc_arch_features features
+       = arc_arch_features_create (info.abfd,
+                                   info.bfd_arch_info->mach);
+      tdesc_loc = arc_lookup_target_description (features);
+    }
+  gdb_assert (tdesc_loc != nullptr);
+
+  arc_debug_printf ("Have got a target description");
+
+  const struct tdesc_feature *feature_core
+    = tdesc_find_feature (tdesc_loc, ARC_CORE_FEATURE_NAME);
+  const struct tdesc_feature *feature_aux
+    = tdesc_find_feature (tdesc_loc, ARC_AUX_FEATURE_NAME);
+
+  /* Maybe there still is a chance to salvage the input.  */
+  if (feature_core == nullptr)
+    feature_core = find_obsolete_core_names (tdesc_loc);
+  if (feature_aux == nullptr)
+    feature_aux = find_obsolete_aux_names (tdesc_loc);
+
+  if (feature_core == nullptr)
+    {
+      arc_print (_("Error: Cannot find required feature '%s' in supplied "
+                  "target description.\n"), ARC_CORE_FEATURE_NAME);
+      return false;
+    }
+
+  if (feature_aux == nullptr)
+    {
+      arc_print (_("Error: Cannot find required feature '%s' in supplied "
+                  "target description.\n"), ARC_AUX_FEATURE_NAME);
+      return false;
+    }
+
+  const arc_register_feature *arc_core_reg_feature
+    = determine_core_reg_feature_set (info.bfd_arch_info->mach);
+  const arc_register_feature *arc_aux_reg_feature
+    = determine_aux_reg_feature_set ();
+
+  tdesc_arch_data_up tdesc_data_loc = tdesc_data_alloc ();
+
+  arc_update_acc_reg_names (info.byte_order);
+
+  bool valid_p = arc_check_tdesc_feature (tdesc_data_loc.get (),
+                                         feature_core,
+                                         arc_core_reg_feature);
+
+  valid_p &= arc_check_tdesc_feature (tdesc_data_loc.get (),
+                                     feature_aux,
+                                     arc_aux_reg_feature);
+
+  if (!valid_p)
+    {
+      arc_debug_printf ("Target description is not valid");
+      return false;
+    }
+
+  *tdesc = tdesc_loc;
+  *tdesc_data = std::move (tdesc_data_loc);
+
+  return true;
+}
+
+/* Implement the type_align gdbarch function.  */
+
+static ULONGEST
+arc_type_align (struct gdbarch *gdbarch, struct type *type)
+{
+  switch (type->code ())
+    {
+    case TYPE_CODE_PTR:
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_FLAGS:
+    case TYPE_CODE_INT:
+    case TYPE_CODE_RANGE:
+    case TYPE_CODE_FLT:
+    case TYPE_CODE_ENUM:
+    case TYPE_CODE_REF:
+    case TYPE_CODE_RVALUE_REF:
+    case TYPE_CODE_CHAR:
+    case TYPE_CODE_BOOL:
+    case TYPE_CODE_DECFLOAT:
+    case TYPE_CODE_METHODPTR:
+    case TYPE_CODE_MEMBERPTR:
+      type = check_typedef (type);
+      return std::min<ULONGEST> (4, TYPE_LENGTH (type));
+    default:
+      return 0;
+    }
+}
+
+/* Implement the "init" gdbarch method.  */
+
+static struct gdbarch *
+arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  const struct target_desc *tdesc;
+  tdesc_arch_data_up tdesc_data;
+
+  arc_debug_printf ("Architecture initialization.");
+
+  if (!arc_tdesc_init (info, &tdesc, &tdesc_data))
+    return nullptr;
+
+  /* Allocate the ARC-private target-dependent information structure, and the
+     GDB target-independent information structure.  */
+  std::unique_ptr<arc_gdbarch_tdep> tdep_holder (new arc_gdbarch_tdep);
+  arc_gdbarch_tdep *tdep = tdep_holder.get ();
+  tdep->jb_pc = -1; /* No longjmp support by default.  */
+  tdep->has_hw_loops = arc_check_for_hw_loops (tdesc, tdesc_data.get ());
+  struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep_holder.release ());
+
+  /* Data types.  */
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 32);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_type_align (gdbarch, arc_type_align);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_char_signed (gdbarch, 0);
+
+  set_gdbarch_write_pc (gdbarch, arc_write_pc);
+
+  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_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_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_sigtramp_frame_unwind);
+  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);
+
+  /* Disassembler options.  Enforce CPU if it was specified in XML target
+     description, otherwise use default method of determining CPU (ELF private
+     header).  */
+  if (info.target_desc != NULL)
+    {
+      const struct bfd_arch_info *tdesc_arch
+       = tdesc_architecture (info.target_desc);
+      if (tdesc_arch != NULL)
+       {
+         xfree (arc_disassembler_options);
+         /* FIXME: It is not really good to change disassembler options
+            behind the scene, because that might override options
+            specified by the user.  However as of now ARC doesn't support
+            `set disassembler-options' hence this code is the only place
+            where options are changed.  It also changes options for all
+            existing gdbarches, which also can be problematic, if
+            arc_gdbarch_init will start reusing existing gdbarch
+            instances.  */
+         /* Target description specifies a BFD architecture, which is
+            different from ARC cpu, as accepted by disassembler (and most
+            other ARC tools), because cpu values are much more fine grained -
+            there can be multiple cpu values per single BFD architecture.  As
+            a result this code should translate architecture to some cpu
+            value.  Since there is no info on exact cpu configuration, it is
+            best to use the most feature-rich CPU, so that disassembler will
+            recognize all instructions available to the specified
+            architecture.  */
+         switch (tdesc_arch->mach)
+           {
+           case bfd_mach_arc_arc601:
+             arc_disassembler_options = xstrdup ("cpu=arc601");
+             break;
+           case bfd_mach_arc_arc600:
+             arc_disassembler_options = xstrdup ("cpu=arc600");
+             break;
+           case bfd_mach_arc_arc700:
+             arc_disassembler_options = xstrdup ("cpu=arc700");
+             break;
+           case bfd_mach_arc_arcv2:
+             /* Machine arcv2 has three arches: ARCv2, EM and HS; where ARCv2
+                is treated as EM.  */
+             if (arc_arch_is_hs (tdesc_arch))
+               arc_disassembler_options = xstrdup ("cpu=hs38_linux");
+             else
+               arc_disassembler_options = xstrdup ("cpu=em4_fpuda");
+             break;
+           default:
+             arc_disassembler_options = NULL;
+             break;
+           }
+       }
+    }
+
+  set_gdbarch_disassembler_options (gdbarch, &arc_disassembler_options);
+  set_gdbarch_valid_disassembler_options (gdbarch,
+                                         disassembler_options_arc ());
+
+  tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data));
+
+  return gdbarch;
+}
+
+/* Implement the "dump_tdep" gdbarch method.  */
+
+static void
+arc_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
+{
+  arc_gdbarch_tdep *tdep = (arc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+
+  gdb_printf (file, "arc_dump_tdep: jb_pc = %i\n", tdep->jb_pc);
+
+  gdb_printf (file, "arc_dump_tdep: is_sigtramp = <%s>\n",
+             host_address_to_string (tdep->is_sigtramp));
+  gdb_printf (file, "arc_dump_tdep: sigcontext_addr = <%s>\n",
+             host_address_to_string (tdep->sigcontext_addr));
+  gdb_printf (file, "arc_dump_tdep: sc_reg_offset = <%s>\n",
+             host_address_to_string (tdep->sc_reg_offset));
+  gdb_printf (file, "arc_dump_tdep: sc_num_regs = %d\n",
+             tdep->sc_num_regs);
+}
+
+/* This command accepts single argument - address of instruction to
+   disassemble.  */
+
+static void
+dump_arc_instruction_command (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
+_initialize_arc_tdep ()
+{
+  gdbarch_register (bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);
+
+  /* Register ARC-specific commands with gdb.  */
+
+  /* Add root prefix command for "maintenance print arc" commands.  */
+  add_show_prefix_cmd ("arc", class_maintenance,
+                      _("ARC-specific maintenance commands for printing GDB "
+                        "internal state."),
+                      &maintenance_print_arc_list,
+                      0, &maintenanceprintlist);
+
+  add_cmd ("arc-instruction", class_maintenance,
+          dump_arc_instruction_command,
+          _("Dump arc_instruction structure for specified address."),
+          &maintenance_print_arc_list);
+
+  /* Debug internals for ARC GDB.  */
+  add_setshow_boolean_cmd ("arc", class_maintenance,
+                          &arc_debug,
+                          _("Set ARC specific debugging."),
+                          _("Show ARC specific debugging."),
+                          _("When set, ARC specific debugging is enabled."),
+                          NULL, NULL, &setdebuglist, &showdebuglist);
+}