summaryrefslogtreecommitdiff
path: root/gdb/arc-linux-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/arc-linux-tdep.c')
-rw-r--r--gdb/arc-linux-tdep.c1143
1 files changed, 759 insertions, 384 deletions
diff --git a/gdb/arc-linux-tdep.c b/gdb/arc-linux-tdep.c
index 14d34a668fa..479d8503545 100644
--- a/gdb/arc-linux-tdep.c
+++ b/gdb/arc-linux-tdep.c
@@ -1,506 +1,881 @@
-/* Target dependent code for ARC700, for GDB, the GNU debugger.
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
- Copyright 2005 Free Software Foundation, Inc.
+ Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
- Authors:
- Soam Vasani <soam.vasani@codito.com>
- Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
+ Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
+
+ Authors:
+ Soam Vasani <soam.vasani@codito.com>
+ Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
+ Richard Stuckey <richard.stuckey@arc.com>
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 2 of the License, or
+ 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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-
-#include <string.h>
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This module provides support for the ARC processor family's target */
+/* dependencies which are specific to the arc-linux-uclibc configuration */
+/* of the ARC gdb. */
+/* */
+/* Functionality: */
+/* This module provides a number of operations, including: */
+/* */
+/* 1) a function which returns the name of a register, given its number */
+/* */
+/* 2) a function which determines whether a given register belongs to a */
+/* particular group (e.g. the group of registers which should be saved */
+/* and restored across a function call) */
+/* */
+/* 3) a function which prints out registers */
+/* */
+/* */
+/* Usage: */
+/* The module exports a function _initialize_arc_linux_tdep: the call to */
+/* this function is generated by the gdb build mechanism, so this function*/
+/* should not be explicitly called. */
+/* */
+/* Some of the operations provided by this module are registered with gdb */
+/* during initialization; gdb then calls them via function pointers, */
+/* rather than by name (this allows gdb to handle multiple target */
+/* architectures): */
+/* */
+/* set_gdbarch_XXX (gdbarch, <function>); */
+/* */
+/* */
+/* Register Numbering Scheme: */
+/* The N target processor registers are assigned gdb numbers which form a */
+/* contiguous range starting at 0. The scheme used is: */
+/* */
+/* 0 .. 26 : core registers R0 .. R26 */
+/* 27 : BTA (Branch Target Address) auxiliary register */
+/* 28 : LP_START auxiliary register */
+/* 29 : LP_END auxiliary register */
+/* 30 : LP_COUNT core register (R60) */
+/* 31 : STATUS32 auxiliary register */
+/* 32 : BLINK (Branch Link) core register (R31) */
+/* 33 : FP (Frame Pointer) core register (R27) */
+/* 34 : SP (Stack Pointer) core register (R28) */
+/* 35 : EFA (Exception Fault Address) auxiliary register */
+/* 36 : RET (Exception Return Address) auxiliary register */
+/* 37 : ORIG_R8 */
+/* 38 : STOP_PC */
+/* */
+/* N.B. 1) core registers R61 and R62 are not included in the scheme, as */
+/* R61 is reserved, and R62 is not a real register; */
+/* */
+/* 2) core registers R29 (ILINK1), R30 (ILINK2) and R63 (PCL) are */
+/* not included; */
+/* */
+/* 3) extension core registers R32 .. R59 are not included; */
+/* */
+/* 4) most auxiliary registers (including all Build Configuration */
+/* Registers) are not included. */
+/* */
+/******************************************************************************/
+
+/* gdb header files */
#include "defs.h"
#include "osabi.h"
-#include "frame.h"
#include "regcache.h"
-#include "gdb_assert.h"
#include "inferior.h"
#include "reggroups.h"
#include "solib-svr4.h"
-#include "symtab.h"
-#include "objfiles.h"
#include "block.h"
+#include "regset.h"
+#include "dis-asm.h"
+#include "opcode/arc.h"
+#include "gdb_assert.h"
+/* ARC header files */
+#include "config/arc/tm-linux.h"
+#include "arc-linux-tdep.h"
+#include "arc-support.h"
#include "arc-tdep.h"
-#include "regset.h"
+#include "opcodes/arcompact-dis.h"
-//#define ARC_DEBUG 1
-/* Default Breakpoint instructions used for
- ARC700 Linux
-*/
-unsigned int arc700_linux_breakpoint_size = 2;
-unsigned char arc700_linux_breakpoint_insn[2] = { 0x3e,0x78 } ;
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define STATUS32_L 0x00000100
-static const char *
-arc_linux_register_name (int regno)
-{
- static char linux_names[][10] = {"r0", "r1", "r2", "r3", "r4", "r5", "r6",
- "r7", "r8", "r9", "r10", "r11", "r12", "r13",
- "r14", "r15", "r16", "r17", "r18", "r19", "r20",
- "r21", "r22", "r23", "r24", "r25", "r26",
-
- "bta",
- "lp_start", "lp_end", "lp_count",
- "status32", "blink",
- "fp", "sp", "efa",
- /* linux-only registers */
- "ret", "orig_r8", "pc",
-
- /* pseudo-regs */
- "ilink1", "ilink2", "eret",
- "status_l1", "status_l2", "erstatus" };
-
- gdb_assert(ARRAY_SIZE (linux_names) == NUM_REGS + NUM_PSEUDO_REGS);
- gdb_assert(regno >=0 && regno < NUM_REGS + NUM_PSEUDO_REGS);
-
- return linux_names[regno];
-}
-/*
- * The kernel stores only one of (ilink1,ilink2,eret). This is stored in
- * the ret "register". ilink1 is stored when the kernel has been entered
- * because of a level 1 interrupt, etc.
- *
- * Same story for (status_l1, status_l2, erstatus).
- *
- * This disambiguity has been fixed by adding orig_r8 to pt_regs.
- * It will take the following values -
- * 1. if an exception of any kind occurs then orig_r8 >= 0
- * 2. Int level 1 : -1
- * 3. Int level 2 : -2
- *
- * Registers whose value we don't know are given the value zero.
+/* Default breakpoint instruction used for ARC700 Linux. */
+static const unsigned char le_breakpoint_instruction[] = { 0x3e, 0x78 };
+static const unsigned char be_breakpoint_instruction[] = { 0x78, 0x3e };
+
+
+/* This array holds the object code of two instructions:
+ mov r8,nr_sigreturn
+ swi
*/
-static void
-arc_linux_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
- int regno, void *buf)
+static const gdb_byte arc_sigtramp_insns[] = { 0x8a, 0x20, 0xc1, 0x1d,
+ 0x6f, 0x22, 0x3f, 0x00 };
+
+#define SIGTRAMP_INSNS_LENGTH sizeof(arc_sigtramp_insns)
+
+
+/* N.B. the array size is specified in the declaration so that the compiler
+ will warn of "excess elements in array initializer" if there is a
+ mismatch (but not of too few elements, unfortunately!). */
+static const char *register_names[ARC_NR_REGS + ARC_NR_PSEUDO_REGS] =
{
- int status32, ret, orig_r8;
- regcache_cooked_read (current_regcache, ARC_ORIG_R8_REGNUM, &orig_r8);
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6",
+ "r7", "r8", "r9", "r10", "r11", "r12", "r13",
+ "r14", "r15", "r16", "r17", "r18", "r19", "r20",
+ "r21", "r22", "r23", "r24", "r25", "r26",
+
+ "bta",
+ "lp_start",
+ "lp_end",
+ "lp_count",
+ "status32",
+ "blink",
+ "fp",
+ "sp",
+ "efa",
+
+ /* Linux-only registers. */
+ "ret",
+ "orig_r8",
+ "pc", // stop pc
+
+ /* Pseudo-regs. */
+ "ilink1",
+ "ilink2",
+ "eret",
+ "status_l1",
+ "status_l2",
+ "erstatus"
+};
- if(regno == ARC_ILINK1_REGNUM ||
- regno == ARC_ILINK2_REGNUM ||
- regno == ARC_ERET_REGNUM)
- {
- regcache_cooked_read (current_regcache, ARC_RET_REGNUM, &ret);
- if(regno == ARC_ILINK1_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 == -1) ? ret : 0);
- else if(regno == ARC_ILINK2_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 == -2) ? ret : 0);
- else if(regno == ARC_ERET_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 >= 0) ? ret : 0);
+/* Mapping between the general-purpose registers in `struct sigcontext' format
+ and GDB's register cache layout.
+
+ arc_linux_sc_reg_offset[i] is the sigcontext offset of GDB regnum `i'. */
+
+/* From <asm/sigcontext.h>. */
+static const int arc_linux_sc_reg_offset[ARC_NR_REGS] =
+{
+ 23 * BYTES_IN_REGISTER, /* r0 */
+ 22 * BYTES_IN_REGISTER, /* r1 */
+ 21 * BYTES_IN_REGISTER, /* r2 */
+ 20 * BYTES_IN_REGISTER, /* r3 */
+ 19 * BYTES_IN_REGISTER, /* r4 */
+ 18 * BYTES_IN_REGISTER, /* r5 */
+ 17 * BYTES_IN_REGISTER, /* r6 */
+ 16 * BYTES_IN_REGISTER, /* r7 */
+ 15 * BYTES_IN_REGISTER, /* r8 */
+ 14 * BYTES_IN_REGISTER, /* r9 */
+ 13 * BYTES_IN_REGISTER, /* r10 */
+ 12 * BYTES_IN_REGISTER, /* r11 */
+ 11 * BYTES_IN_REGISTER, /* r12 */
+ REGISTER_NOT_PRESENT, /* r13 */
+ REGISTER_NOT_PRESENT, /* r14 */
+ REGISTER_NOT_PRESENT, /* r15 */
+ REGISTER_NOT_PRESENT, /* r16 */
+ REGISTER_NOT_PRESENT, /* r17 */
+ REGISTER_NOT_PRESENT, /* r18 */
+ REGISTER_NOT_PRESENT, /* r19 */
+ REGISTER_NOT_PRESENT, /* r20 */
+ REGISTER_NOT_PRESENT, /* r21 */
+ REGISTER_NOT_PRESENT, /* r22 */
+ REGISTER_NOT_PRESENT, /* r23 */
+ REGISTER_NOT_PRESENT, /* r24 */
+ REGISTER_NOT_PRESENT, /* r25 */
+ 10 * BYTES_IN_REGISTER, /* r26 */
+ 2 * BYTES_IN_REGISTER, /* bta */
+ 3 * BYTES_IN_REGISTER, /* lp_start */
+ 4 * BYTES_IN_REGISTER, /* lp_end */
+ 5 * BYTES_IN_REGISTER, /* lp_count */
+ 6 * BYTES_IN_REGISTER, /* status32 */
+ 8 * BYTES_IN_REGISTER, /* blink */
+ 9 * BYTES_IN_REGISTER, /* fp */
+ 1 * BYTES_IN_REGISTER, /* sp */
+ REGISTER_NOT_PRESENT, /* efa */
+ 7 * BYTES_IN_REGISTER, /* ret */
+ REGISTER_NOT_PRESENT, /* orig_r8 */
+ REGISTER_NOT_PRESENT /* stop_pc */
+};
+
+
+/* arcompact_linux_core_reg_offsets[i] is the offset in the .reg section of GDB regnum i.
+ From include/asm-arc/user.h in the ARC Linux sources. */
+
+static const int arcompact_linux_core_reg_offsets[ARC_NR_REGS] =
+{
+ 22 * BYTES_IN_REGISTER, /* r0 */
+ 21 * BYTES_IN_REGISTER, /* r1 */
+ 20 * BYTES_IN_REGISTER, /* r2 */
+ 19 * BYTES_IN_REGISTER, /* r3 */
+ 18 * BYTES_IN_REGISTER, /* r4 */
+ 17 * BYTES_IN_REGISTER, /* r5 */
+ 16 * BYTES_IN_REGISTER, /* r6 */
+ 15 * BYTES_IN_REGISTER, /* r7 */
+ 14 * BYTES_IN_REGISTER, /* r8 */
+ 13 * BYTES_IN_REGISTER, /* r9 */
+ 12 * BYTES_IN_REGISTER, /* r10 */
+ 11 * BYTES_IN_REGISTER, /* r11 */
+ 10 * BYTES_IN_REGISTER, /* r12 */
+ 39 * BYTES_IN_REGISTER, /* r13 */
+ 38 * BYTES_IN_REGISTER, /* r14 */
+ 37 * BYTES_IN_REGISTER, /* r15 */
+ 36 * BYTES_IN_REGISTER, /* r16 */
+ 35 * BYTES_IN_REGISTER, /* r17 */
+ 34 * BYTES_IN_REGISTER, /* r18 */
+ 33 * BYTES_IN_REGISTER, /* r19 */
+ 32 * BYTES_IN_REGISTER, /* r20 */
+ 31 * BYTES_IN_REGISTER, /* r21 */
+ 30 * BYTES_IN_REGISTER, /* r22 */
+ 29 * BYTES_IN_REGISTER, /* r23 */
+ 28 * BYTES_IN_REGISTER, /* r24 */
+ 27 * BYTES_IN_REGISTER, /* r25 */
+ 9 * BYTES_IN_REGISTER, /* r26 */
+ 1 * BYTES_IN_REGISTER, /* bta */
+ 2 * BYTES_IN_REGISTER, /* lp_start */
+ 3 * BYTES_IN_REGISTER, /* lp_end */
+ 4 * BYTES_IN_REGISTER, /* lp_count */
+ 5 * BYTES_IN_REGISTER, /* status32 */
+ 7 * BYTES_IN_REGISTER, /* blink */
+ 8 * BYTES_IN_REGISTER, /* fp */
+ 25 * BYTES_IN_REGISTER, /* sp */
+ REGISTER_NOT_PRESENT, /* efa */
+ 6 * BYTES_IN_REGISTER, /* ret */
+ 24 * BYTES_IN_REGISTER, /* orig_r8 */
+ 40 * BYTES_IN_REGISTER, /* stop_pc */
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* forward declarations */
+/* -------------------------------------------------------------------------- */
+
+static int arc_linux_binutils_reg_to_regnum (struct gdbarch *gdbarch, int reg);
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define PRINT(regnum) \
+ default_print_registers_info (gdbarch, file, frame, regnum, all)
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Returns TRUE if the instruction at PC is a branch (of any kind).
+ *fall_thru is set to the address of the next insn.
+ *target is set to the branch target. */
+
+static Boolean
+next_pc (CORE_ADDR pc, CORE_ADDR *fall_thru, CORE_ADDR *target)
+{
+ struct regcache *regcache = get_current_regcache();
+ struct disassemble_info di;
+ struct arcDisState instr;
+ Boolean two_targets = FALSE;
+
+ arc_initialize_disassembler(&di);
+
+ /* So what is the instruction at the given PC? */
+ instr = arcAnalyzeInstr(pc, &di);
+
+ /* By default, the next instruction is the one immediately after the one at PC. */
+ *fall_thru = pc + instr.instructionLen;
+ DEBUG("--- next_pc(%x) = %x, isBranch = %d, tcnt = %d [%x], flow = %s (%d), "
+ "reg for indirect jump = %d, nullifyMode = %s\n",
+ (unsigned int) pc, (unsigned int) *fall_thru, instr.isBranch, instr.tcnt, instr.targets[0],
+ (instr.flow == direct_jump || instr.flow == direct_call) ? "direct" : "indirect",
+ instr.flow,
+ instr.register_for_indirect_jump,
+ ((instr.nullifyMode == (char) BR_exec_always) ? "delay slot" : "no delay"));
+
+ /* OK, it's a branch. */
+ if ((Boolean) instr.isBranch)
+ {
+ two_targets = TRUE;
+
+ /* If it's a direct jump or call, the destination address is encoded in
+ the instruction, so we got it by disassembling the instruction;
+ otherwise, it's an indirect jump to the address held in the register
+ named in the instruction, so we must read that register. */
+ if (instr.flow == direct_jump || instr.flow == direct_call)
+ *target = (CORE_ADDR) instr.targets[0];
+ else
+ regcache_cooked_read(regcache,
+ arc_linux_binutils_reg_to_regnum(current_gdbarch,
+ instr.register_for_indirect_jump),
+ (gdb_byte*) target);
+
+ /* For instructions with delay slots, the fall thru is not the instruction
+ immediately after the branch instruction, but the one after that. */
+ if (instr.nullifyMode == (char) BR_exec_always)
+ {
+ struct arcDisState instr_d = arcAnalyzeInstr(*fall_thru, &di);
+
+ *fall_thru += instr_d.instructionLen;
+ }
}
- else if(regno == ARC_STATUS32_L1_REGNUM ||
- regno == ARC_STATUS32_L2_REGNUM ||
- regno == ARC_ERSTATUS_REGNUM)
+
+
+ /* Check for a zero-overhead loop. */
{
- regcache_cooked_read (current_regcache, ARC_STATUS32_REGNUM, &status32);
-
- if(regno == ARC_STATUS32_L1_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 == -1) ? status32 : 0);
- else if(regno == ARC_STATUS32_L2_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 == -2) ? status32 : 0);
- else if(regno == ARC_ERSTATUS_REGNUM)
- *((unsigned int *)buf) = ((orig_r8 >= 0) ? status32 : 0);
+ unsigned int lp_end, lp_start, lp_count, status32;
+
+ regcache_cooked_read(regcache, ARC_LP_START_REGNUM, (gdb_byte*) &lp_start);
+ regcache_cooked_read(regcache, ARC_LP_END_REGNUM, (gdb_byte*) &lp_end);
+ regcache_cooked_read(regcache, ARC_LP_COUNT_REGNUM, (gdb_byte*) &lp_count);
+ regcache_cooked_read(regcache, ARC_STATUS32_REGNUM, (gdb_byte*) &status32);
+
+ if (!(status32 & STATUS32_L) && *fall_thru == lp_end && lp_count > 1)
+ {
+ /* The instruction is in effect a jump back to the start of the loop. */
+ two_targets = TRUE;
+ *target = lp_start;
+ }
}
- else
- internal_error(__FILE__, __LINE__, "arc_pseudo_register_read: bad register number (%d)", regno);
+
+ return two_targets;
}
+
+/* Extract the register values found in the ABI GREGSET, storing their values in
+ regcache. */
+
static void
-arc_linux_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regno, const void *buf)
+arcompact_linux_supply_gregset (struct regcache *regcache,
+ int regnum,
+ const void *gregs,
+ size_t size)
{
- /* none of our pseudo-regs are writable */
- internal_error(__FILE__, __LINE__, "arc_pseudo_register_write: bad register number");
+ const bfd_byte *buf = gregs;
+ unsigned int reg;
+
+ for (reg = 0; reg < ELEMENTS_IN_ARRAY(arcompact_linux_core_reg_offsets); reg++)
+ {
+ if (arcompact_linux_core_reg_offsets[reg] != REGISTER_NOT_PRESENT)
+ regcache_raw_supply (regcache,
+ (int) reg,
+ buf + arcompact_linux_core_reg_offsets[reg]);
+ }
}
-/*
- * print registers in the correct order.
- *
- * Why not have the regnums in the right order in the first place ?
- * Because some of the registers have to be pseudo-registers because of
- * the way the kernel is written, and because gdb assumes that
- * pseudo-registers have regnums greater than real register regnums.
- */
-static void
-arc_linux_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
- struct frame_info *frame, int regnum, int all)
+
+/* Return whether the frame preceding next_frame corresponds to a GNU/Linux
+ sigtramp routine. */
+
+static Boolean
+is_linux_sigtramp (struct frame_info *next_frame)
+{
+ /* Find the PC for that previous frame. */
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ gdb_byte buf[SIGTRAMP_INSNS_LENGTH];
+
+ /* Read the memory at that PC (this gives us the code without any s/w
+ breakpoints that may have been set in it). */
+ if (!safe_frame_unwind_memory (next_frame, pc, buf, (int) SIGTRAMP_INSNS_LENGTH))
+ /* Failed to unwind frame. */
+ return FALSE;
+
+ /* Is that code the sigtramp instruction sequence? */
+ if (memcmp(buf, arc_sigtramp_insns, SIGTRAMP_INSNS_LENGTH) == 0)
+ return TRUE;
+
+ /* No - look one instruction earlier in the code. */
+ if (!safe_frame_unwind_memory (next_frame, pc - 4, buf, (int) SIGTRAMP_INSNS_LENGTH))
+ /* Failed to unwind frame. */
+ return FALSE;
+
+ if (memcmp(buf, arc_sigtramp_insns, SIGTRAMP_INSNS_LENGTH) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/* Assuming next_frame is a frame following a GNU/Linux sigtramp
+ routine, return the address of the associated sigcontext structure. */
+
+static CORE_ADDR
+linux_sigcontext_addr (struct frame_info *next_frame)
{
- int i;
+ gdb_byte buf[4];
+
+ frame_unwind_register (next_frame, ARC_SP_REGNUM, buf);
+
+ return (CORE_ADDR) extract_unsigned_integer (buf, 4);
+}
+
+
+/* Determine whether the given register is a member of the given group.
- if (regnum >= 0)
+ Returns 0, 1, or -1:
+ 0 means the register is not in the group.
+ 1 means the register is in the group.
+ -1 means the tdep has nothing to say about this register and group. */
+
+static int
+register_reggroup_p (int regnum, struct reggroup *group)
+{
+ if (system_reggroup)
{
- default_print_registers_info (gdbarch, file, frame, regnum, all);
- return;
+ if (regnum == ARC_ORIG_R8_REGNUM ||
+ regnum == ARC_EFA_REGNUM ||
+ regnum == ARC_ERET_REGNUM ||
+ regnum == ARC_ERSTATUS_REGNUM)
+ return 1;
+ }
+ else if (group == general_reggroup)
+ {
+ if (regnum == ARC_RET_REGNUM)
+ return 0;
+
+ return (regnum == ARC_STATUS32_REGNUM) ? 0 : 1;
}
- /* print all registers */
-
- /* r0..r26 */
- for (i=0; i <= 26; ++i)
- default_print_registers_info (gdbarch, file, frame, i, all);
-
- default_print_registers_info (gdbarch, file, frame, ARC_FP_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_SP_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_ILINK1_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_ILINK2_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_BLINK_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_LP_COUNT_REGNUM, all);
-
- /* now the aux registers */
-
- default_print_registers_info (gdbarch, file, frame, ARC_BTA_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_LP_START_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_LP_END_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_EFA_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_ERET_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_STATUS32_L1_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_STATUS32_L2_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame, ARC_ERSTATUS_REGNUM, all);
-
- /* show the pc */
- default_print_registers_info (gdbarch, file, frame, ARC_STOP_PC_REGNUM, all);
+ /* Let the caller sort it out! */
+ return -1;
}
-/*
- * mov r8,nr_sigreturn
- * swi
- */
-static char arc_sigtramp_insn[] = { 0x8a, 0x20, 0xc1, 0x1d, 0x6f, 0x22, 0x3f, 0x00 };
+/* -------------------------------------------------------------------------- */
+/* local functions called from gdb */
+/* -------------------------------------------------------------------------- */
-/* Return whether the frame preceding NEXT_FRAME corresponds to a
- GNU/Linux sigtramp routine. */
-static int
-arc_linux_sigtramp_p (struct frame_info *next_frame)
+/* The Linux kernel stores only one of (ilink1, ilink2, eret). This is stored
+ in the ret "register". ilink1 is stored when the kernel has been entered
+ because of a level 1 interrupt, etc.
+
+ Same story for (status_l1, status_l2, erstatus).
+
+ This disambiguity has been fixed by adding orig_r8 to pt_regs.
+
+ FIXME: what is pt_regs????
+
+ It will take the following values -
+ 1. if an exception of any kind occurs then orig_r8 >= 0
+ 2. Interrupt level 1 : orig == -1
+ 3. Interrupt level 2 : orig == -2
+
+ Registers whose value we don't know are given the value zero.
+
+ The only pseudo-registers are:
+
+ ARC_ILINK1_REGNUM
+ ARC_ILINK2_REGNUM
+ ARC_ERET_REGNUM
+ ARC_STATUS32_L1_REGNUM
+ ARC_STATUS32_L2_REGNUM
+ ARC_ERSTATUS_REGNUM
+*/
+
+static void
+arc_linux_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int gdb_regno,
+ gdb_byte *buf)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
- unsigned char buf[8];
+ unsigned int* contents = (unsigned int *) buf;
+ unsigned int status32, ret;
+ int orig_r8;
- if (!safe_frame_unwind_memory (next_frame, pc, buf, 8))
- return 0;
+ regcache_cooked_read (regcache, ARC_ORIG_R8_REGNUM, (gdb_byte*) &orig_r8);
- if (memcmp(buf, arc_sigtramp_insn, 8) == 0)
- return 1;
- else
+ if (gdb_regno == ARC_ILINK1_REGNUM ||
+ gdb_regno == ARC_ILINK2_REGNUM ||
+ gdb_regno == ARC_ERET_REGNUM)
{
- pc -= 4;
-
- if (!safe_frame_unwind_memory (next_frame, pc, buf, 8))
- return 0;
+ regcache_cooked_read (regcache, ARC_RET_REGNUM, (gdb_byte*) &ret);
- if (memcmp(buf, arc_sigtramp_insn, 8) == 0)
- return 1;
+ if (gdb_regno == ARC_ILINK1_REGNUM)
+ *contents = ((orig_r8 == -1) ? ret : 0);
+ else if (gdb_regno == ARC_ILINK2_REGNUM)
+ *contents = ((orig_r8 == -2) ? ret : 0);
+ else // (gdb_regno == ARC_ERET_REGNUM)
+ *contents = ((orig_r8 >= 0) ? ret : 0);
+
+ }
+ else if (gdb_regno == ARC_STATUS32_L1_REGNUM ||
+ gdb_regno == ARC_STATUS32_L2_REGNUM ||
+ gdb_regno == ARC_ERSTATUS_REGNUM)
+ {
+ regcache_cooked_read (regcache, ARC_STATUS32_REGNUM, (gdb_byte*) &status32);
+
+ if (gdb_regno == ARC_STATUS32_L1_REGNUM)
+ *contents = ((orig_r8 == -1) ? status32 : 0);
+ else if (gdb_regno == ARC_STATUS32_L2_REGNUM)
+ *contents = ((orig_r8 == -2) ? status32 : 0);
+ else // (gdb_regno == ARC_ERSTATUS_REGNUM)
+ *contents = ((orig_r8 >= 0) ? status32 : 0);
}
+ else
+ internal_error(__FILE__, __LINE__, _("%s: bad pseudo register number (%d)"), __FUNCTION__, gdb_regno);
+}
+
- return 0;
+static void
+arc_linux_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int gdb_regno,
+ const gdb_byte *buf)
+{
+ /* None of our pseudo-regs are writable. */
+ internal_error(__FILE__, __LINE__, _("%s: pseudo-registers are unwritable"), __FUNCTION__);
}
-/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
- routine, return the address of the associated sigcontext structure. */
-static CORE_ADDR
-arc_linux_sigcontext_addr (struct frame_info *next_frame)
+
+/* Mapping from binutils/gcc register number to GDB register number ("regnum").
+ N.B. registers such as ARC_FP_REGNUM, ARC_SP_REGNUM, etc., actually have
+ different GDB register numbers in the arc-elf32 and arc-linux-uclibc
+ configurations of the ARC gdb. */
+
+static int
+arc_linux_binutils_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
- char buf[4];
- CORE_ADDR sp;
-
- frame_unwind_register (next_frame, ARC_SP_REGNUM, buf);
- sp = extract_unsigned_integer (buf, 4);
+ /* From gcc/config/arc/arc.h header file. */
+
+ if (reg >= 0 && reg <= 26)
+ return reg;
+ else if (reg == ARC_ABI_FRAME_POINTER) /* fp */
+ return ARC_FP_REGNUM;
+ else if (reg == ARC_ABI_STACK_POINTER) /* sp */
+ return ARC_SP_REGNUM;
+ else if (reg == 29) /* ilink1 */
+ return ARC_ILINK1_REGNUM;
+ else if (reg == 30) /* ilink2 */
+ return ARC_ILINK2_REGNUM;
+ else if (reg == 31) /* blink */
+ return ARC_BLINK_REGNUM;
+ else if (IS_EXTENSION_CORE_REGISTER(reg)) /* reserved */
+ ;
+ else if (reg == 60) /* lp_count */
+ return ARC_LP_COUNT_REGNUM;
+#if 0
+ else if (reg == 61) /* reserved */
+ ;
+ else if (reg == 62) /* no such register */
+ ;
+ else if (reg == 63) /* PCL */
+ ;
+#endif
+
+ warning(_("unmapped register #%d encountered"), reg);
+ return -1;
+}
+
+
+/* Print the contents of one, some or all registers.
- return sp;
+ Print registers in the correct order.
+ Why not have the regnums in the right order in the first place?
+ Because some of the registers have to be pseudo-registers because of
+ the way the kernel is written, and because gdb assumes that
+ pseudo-registers have regnums greater than real register regnums. */
+
+static void
+arc_linux_print_registers_info (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ struct frame_info *frame,
+ int regnum,
+ int all)
+{
+ if (regnum >= 0)
+ PRINT (regnum);
+ else /* If regnum < 0, print all registers. */
+ {
+ int i;
+
+ /* R0 .. R26 */
+ for (i = 0; i <= 26; i++) PRINT (i);
+
+ PRINT (ARC_FP_REGNUM );
+ PRINT (ARC_SP_REGNUM );
+ PRINT (ARC_ILINK1_REGNUM );
+ PRINT (ARC_ILINK2_REGNUM );
+ PRINT (ARC_BLINK_REGNUM );
+ PRINT (ARC_LP_COUNT_REGNUM );
+
+ /* Now the auxiliary registers. */
+
+ PRINT (ARC_BTA_REGNUM );
+ PRINT (ARC_LP_START_REGNUM );
+ PRINT (ARC_LP_END_REGNUM );
+ PRINT (ARC_EFA_REGNUM );
+ PRINT (ARC_ERET_REGNUM );
+ PRINT (ARC_STATUS32_L1_REGNUM);
+ PRINT (ARC_STATUS32_L2_REGNUM);
+ PRINT (ARC_ERSTATUS_REGNUM );
+
+ /* Show the PC. */
+ PRINT (ARC_STOP_PC_REGNUM );
+ }
}
-int
-arc_linux_register_reggroup_p (int regnum, struct reggroup *group)
+
+/* Return the name of the given register. */
+
+static const char*
+arc_linux_register_name (struct gdbarch *gdbarch, int gdb_regno)
{
- if(regnum == ARC_ORIG_R8_REGNUM && group == system_reggroup)
- return 1;
+ gdb_assert(ELEMENTS_IN_ARRAY(register_names) == (unsigned int) (ARC_NR_REGS + ARC_NR_PSEUDO_REGS));
- if(regnum == ARC_RET_REGNUM && group == general_reggroup)
- return 0;
+ /* Oh, for a proper language with array bounds checking, like Ada... */
+ gdb_assert(0 <= gdb_regno && gdb_regno < (int) ELEMENTS_IN_ARRAY(register_names));
- return -1;
+ return register_names[gdb_regno];
}
-/* Mapping between the general-purpose registers in `struct
- sigcontext' format and GDB's register cache layout.
- arc_linux_sc_reg_offset[i] is the sigcontext offset of GDB regnum `i'. */
-/* From <asm/sigcontext.h>. */
-static int arc_linux_sc_reg_offset[] =
+/* Determine whether the given register is read-only. */
+
+static int
+arc_linux_cannot_store_register (struct gdbarch *gdbarch, int gdb_regno)
{
- 23 * 4, /* r0 */
- 22 * 4, /* r1 */
- 21 * 4, /* r2 */
- 20 * 4, /* r3 */
- 19 * 4, /* r4 */
- 18 * 4, /* r5 */
- 17 * 4, /* r6 */
- 16 * 4, /* r7 */
- 15 * 4, /* r8 */
- 14 * 4, /* r9 */
- 13 * 4, /* r10 */
- 12 * 4, /* r11 */
- 11 * 4, /* r12 */
- -1, /* r13 */
- -1, /* r14 */
- -1, /* r15 */
- -1, /* r16 */
- -1, /* r17 */
- -1, /* r18 */
- -1, /* r19 */
- -1, /* r20 */
- -1, /* r21 */
- -1, /* r22 */
- -1, /* r23 */
- -1, /* r24 */
- -1, /* r25 */
- 10 * 4, /* r26 */
- 2 * 4, /* bta */
- 3 * 4, /* lp_start */
- 4 * 4, /* lp_end */
- 5 * 4, /* lp_count */
- 6 * 4, /* status32 */
- 8 * 4, /* blink */
- 9 * 4, /* fp */
- 1 * 4, /* sp */
- -1, /* efa */
- 7 * 4, /* ret */
- -1, /* orig_r8 */
- -1, /* stop_pc */
-};
+ if (gdb_regno == ARC_EFA_REGNUM ||
+ gdb_regno == ARC_ERET_REGNUM ||
+ gdb_regno == ARC_STATUS32_L1_REGNUM ||
+ gdb_regno == ARC_STATUS32_L2_REGNUM ||
+ gdb_regno == ARC_ERSTATUS_REGNUM ||
+ gdb_regno == ARC_ILINK1_REGNUM ||
+ gdb_regno == ARC_ILINK2_REGNUM)
+ {
+ /* No warning should be printed. arc_cannot_store_register being
+ called does not imply that someone is actually writing to regnum. */
+
+ /* warning(_("writing to read-only register: %s"), gdbarch_register_name(gdbarch, gdb_regno)); */
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* This function is called just before we resume executing the inferior, if we
+ want to single-step it. We find the target(s) of the instruction about to
+ be executed and and place breakpoints there. */
+
+static int
+arc_linux_software_single_step (struct frame_info *frame)
+{
+ CORE_ADDR fall_thru, branch_target;
+ CORE_ADDR pc = get_frame_pc(frame);
+ Boolean two_breakpoints = next_pc(pc, &fall_thru, &branch_target);
+
+ insert_single_step_breakpoint (fall_thru);
+
+ if (two_breakpoints)
+ {
+ if (pc != branch_target)
+ insert_single_step_breakpoint (branch_target);
+ }
+
+ /* Always returns true for now. */
+ return 1;
+}
/* Set the program counter for process PTID to PC. */
static void
-arc700_linux_write_pc (CORE_ADDR pc, ptid_t ptid)
+arc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
- ULONGEST val;
- write_register_pid (PC_REGNUM, pc, ptid);
-
- /* We must be careful with modifying the program counter. If we
- just interrupted a system call, the kernel might try to restart
- it when we resume the inferior. On restarting the system call,
- the kernel will try backing up the program counter even though it
- no longer points at the system call. This typically results in a
- SIGSEGV or SIGILL. We can prevent this by writing `-1' in the
- "orig_r8" pseudo-register.
-
- Note that "orig_r8" is saved when setting up a dummy call frame.
- This means that it is properly restored when that frame is
- popped, and that the interrupted system call will be restarted
- when we resume the inferior on return from a function call from
- within GDB. In all other cases the system call will not be
- restarted. */
- write_register_pid (ARC_ORIG_R8_REGNUM, -3, ptid);
+ regcache_cooked_write_unsigned (regcache, ARC_PC_REGNUM, pc);
+
+ /* We must be careful with modifying the program counter. If we
+ just interrupted a system call, the kernel might try to restart
+ it when we resume the inferior. On restarting the system call,
+ the kernel will try backing up the program counter even though it
+ no longer points at the system call. This typically results in a
+ SIGSEGV or SIGILL. We can prevent this by writing `-1' in the
+ "orig_r8" pseudo-register.
+
+ Note that "orig_r8" is saved when setting up a dummy call frame.
+ This means that it is properly restored when that frame is
+ popped, and that the interrupted system call will be restarted
+ when we resume the inferior on return from a function call from
+ within GDB. In all other cases the system call will not be
+ restarted. */
+
+ // FIXME: why -3 and not -1? -3 does not appear to be a defined valued for
+ // orig_r8 (i.e. -2, -1 or >= 0) - perhaps it means "none of these"?
+ regcache_cooked_write_signed (regcache, ARC_ORIG_R8_REGNUM, -3);
}
/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
- This is called on every single step thru the PLT and runtime resolver.
+ This is called on every single step through the PLT and runtime resolver.
This function:
- 1) decides whether a PLT has sent us into the linker to resolve
- a function reference, and
- 2) if so, tells us where to set a temporary breakpoint that will
- trigger when the dynamic linker is done. */
+ 1) decides whether a PLT has sent us into the linker to resolve
+ a function reference, and
+ 2) if so, tells us where to set a temporary breakpoint that will
+ trigger when the dynamic linker is done. */
-CORE_ADDR
+static CORE_ADDR
arc_linux_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
{
- /* For uClibc 0.9.26.
-
- An unresolved PLT entry points to "__dl_linux_resolve", which calls
- "__dl_linux_resolver" to do the resolving and then eventually jumps to
- the function.
-
- So we look for the symbol `_dl_linux_resolver', and if we are there,
- we set a breakpoint at the return address, and continue. */
-
- /* lookup_minimal_symbol didn't work, for some reason. */
- struct symbol *resolver
- = lookup_symbol_global ("_dl_linux_resolver", 0, VAR_DOMAIN, 0);
-
-#ifdef ARC_DEBUG
- printf("--- arc_linux_skip_solib_resolver: pc = %x, resolver at %x\n", pc,
- resolver ? BLOCK_START (SYMBOL_BLOCK_VALUE (resolver)) : 0);
-#endif
-
- if (resolver && (BLOCK_START (SYMBOL_BLOCK_VALUE (resolver))) == pc)
- {
- return frame_pc_unwind (get_current_frame ());
- }
+ /* For uClibc 0.9.26.
- return 0;
-}
+ An unresolved PLT entry points to "__dl_linux_resolve", which calls
+ "__dl_linux_resolver" to do the resolving and then eventually jumps to
+ the function.
+ So we look for the symbol `_dl_linux_resolver', and if we are there,
+ gdb sets a breakpoint at the return address, and continues. */
-/* arcompact_linux_core_reg_offsets[i] is the offset in the .reg section of GDB
- regnum i .
-
- From include/asm-arc/user.h in the ARC Linux sources. */
-static int arcompact_linux_core_reg_offsets[] = {
- 22 * 4, /* r0 */
- 21 * 4, /* r1 */
- 20 * 4, /* r2 */
- 19 * 4, /* r3 */
- 18 * 4, /* r4 */
- 17 * 4, /* r5 */
- 16 * 4, /* r6 */
- 15 * 4, /* r7 */
- 14 * 4, /* r8 */
- 13 * 4, /* r9 */
- 12 * 4, /* r10 */
- 11 * 4, /* r11 */
- 10 * 4, /* r12 */
- 39 * 4, /* r13 */
- 38 * 4, /* r14 */
- 37 * 4, /* r15 */
- 36 * 4, /* r16 */
- 35 * 4, /* r17 */
- 34 * 4, /* r18 */
- 33 * 4, /* r19 */
- 32 * 4, /* r20 */
- 31 * 4, /* r21 */
- 30 * 4, /* r22 */
- 29 * 4, /* r23 */
- 28 * 4, /* r24 */
- 27 * 4, /* r25 */
- 9 * 4, /* r26 */
- 1 * 4, /* bta */
- 2 * 4, /* lp_start */
- 3 * 4, /* lp_end */
- 4 * 4, /* lp_count */
- 5 * 4, /* status32 */
- 7 * 4, /* blink */
- 8 * 4, /* fp */
- 25 * 4, /* sp */
- -1, /* efa */
- 6 * 4, /* ret */
- 24 * 4, /* orig_r8 */
- 40 * 4, /* stop_pc */
-};
+ /* Lookup_minimal_symbol didn't work, for some reason. */
+ struct symbol *resolver =
+ lookup_symbol_global ("_dl_linux_resolver", 0, 0, VAR_DOMAIN, 0);
-/* Extract the register values found in the ABI GREGSET, storing their
- values in REGCACHE. */
-static void
-arcompact_linux_supply_gregset (struct regcache *regcache,
- int regnum, const void *gregs, size_t size)
-{
- int regi;
- int arc_num_gprs = ARRAY_SIZE (arcompact_linux_core_reg_offsets);
- const bfd_byte *buf = gregs;
+ DEBUG((resolver == NULL) ? "--- %s : pc = %x, no resolver found"
+ : "--- %s : pc = %x, resolver at %x\n",
+ __FUNCTION__,
+ (unsigned int) pc,
+ (unsigned int) ((resolver == NULL) ? 0 : BLOCK_START (SYMBOL_BLOCK_VALUE (resolver))));
- for (regi = 0; regi < arc_num_gprs; regi++)
- {
- if (arcompact_linux_core_reg_offsets[regi] > 0)
- regcache_raw_supply (regcache, regi,
- buf + arcompact_linux_core_reg_offsets[regi]);
- }
+ if ((resolver != NULL) && (BLOCK_START (SYMBOL_BLOCK_VALUE (resolver))) == pc)
+ /* Find the return address. */
+ return frame_pc_unwind (get_current_frame ());
+
+ /* No breakpoint is required. */
+ return 0;
}
-/* Call the right architecture variant's supply_gregset function. For now,
- we only have ARCompact. */
+
+/* Call the right architecture variant's supply_gregset function. For now, we
+ have only ARCompact. */
+
static void
arc_linux_supply_gregset (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t size)
+ struct regcache *regcache,
+ int regnum,
+ const void *gregs,
+ size_t size)
{
- arcompact_linux_supply_gregset (regcache, regnum, gregs, size);
+ arcompact_linux_supply_gregset (regcache, regnum, gregs, size);
}
+
/* Functions for handling core files.
The first element is a parameter to pass the rest of the functions. We
don't need it.
supply_gregset is for reading the core file.
collect_regset, which we haven't defined, would be for writing the core
file. */
-static struct regset arc_linux_gregset = {
- NULL, arc_linux_supply_gregset
-};
-/* This is called through gdbarch. */
static const struct regset *
arc_linux_regset_from_core_section (struct gdbarch *core_arch,
- const char *sect_name, size_t sect_size)
+ const char *sect_name,
+ size_t sect_size)
{
- if (strcmp (sect_name, ".reg") == 0)
- return &arc_linux_gregset;
+ static const struct regset arc_linux_gregset =
+ {
+ NULL, // descr
+ arc_linux_supply_gregset, // supply_regset
+ NULL, // collect_regset
+ NULL // arch
+ };
+
+ if (strcmp (sect_name, ".reg") == 0)
+ return &arc_linux_gregset;
- return NULL;
+ return NULL;
}
-/* Add the signal stuff to gdbarch->tdep. */
+
+/* Initialize for this ABI. */
+
static void
arc_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- tdep->sigtramp_p = arc_linux_sigtramp_p;
- tdep->sigcontext_addr = arc_linux_sigcontext_addr;
- tdep->sc_reg_offset = arc_linux_sc_reg_offset;
- tdep->sc_num_regs = ARRAY_SIZE (arc_linux_sc_reg_offset);
-
- tdep->arc_breakpoint_size = arc700_linux_breakpoint_size;
- tdep->arc_breakpoint_insn = arc700_linux_breakpoint_insn;
-
- set_gdbarch_num_regs (gdbarch, ARC_NR_REGS);
- set_gdbarch_num_pseudo_regs (gdbarch, ARC_NR_PSEUDO_REGS);
-
- set_gdbarch_pc_regnum (gdbarch, ARC_STOP_PC_REGNUM);
- set_gdbarch_register_name (gdbarch, arc_linux_register_name);
-
- set_gdbarch_software_single_step (gdbarch, arc_software_single_step);
-
- set_gdbarch_write_pc (gdbarch, arc700_linux_write_pc);
-
- tdep->pc_regnum_in_sigcontext = ARC_RET_REGNUM;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Fill in target-dependent info in ARC-private structure. */
+
+ tdep->is_sigtramp = is_linux_sigtramp;
+ tdep->sigcontext_addr = linux_sigcontext_addr;
+ tdep->sc_reg_offset = arc_linux_sc_reg_offset;
+ tdep->sc_num_regs = ELEMENTS_IN_ARRAY(arc_linux_sc_reg_offset);
+ tdep->pc_regnum_in_sigcontext = ARC_RET_REGNUM;
+
+ tdep->le_breakpoint_instruction = le_breakpoint_instruction;
+ tdep->be_breakpoint_instruction = be_breakpoint_instruction;
+ tdep->breakpoint_size = (unsigned int) sizeof(le_breakpoint_instruction);
+
+ tdep->register_reggroup_p = register_reggroup_p;
+
+ tdep->lowest_pc = 0x74; // FIXME: why this?
+ tdep->processor_variant_info = NULL;
+
+ /* Pass target-dependent info to gdb. */
+
+ /* ARC_NR_REGS and ARC_NR_PSEUDO_REGS are defined in the tm.h configuration file. */
+ set_gdbarch_pc_regnum (gdbarch, ARC_STOP_PC_REGNUM);
+ set_gdbarch_num_regs (gdbarch, ARC_NR_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, ARC_NR_PSEUDO_REGS);
+ set_gdbarch_print_registers_info (gdbarch, arc_linux_print_registers_info);
+ set_gdbarch_register_name (gdbarch, arc_linux_register_name);
+ set_gdbarch_cannot_store_register (gdbarch, arc_linux_cannot_store_register);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arc_linux_binutils_reg_to_regnum);
+
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+ set_gdbarch_software_single_step (gdbarch, arc_linux_software_single_step);
+ set_gdbarch_write_pc (gdbarch, arc_linux_write_pc);
+ set_gdbarch_pseudo_register_read (gdbarch, arc_linux_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, arc_linux_pseudo_register_write);
+ set_gdbarch_regset_from_core_section (gdbarch, arc_linux_regset_from_core_section);
+ set_gdbarch_skip_solib_resolver (gdbarch, arc_linux_skip_solib_resolver);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets);
+}
- set_gdbarch_pseudo_register_read (gdbarch, arc_linux_pseudo_register_read);
- set_gdbarch_pseudo_register_write (gdbarch, arc_linux_pseudo_register_write);
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
- set_gdbarch_print_registers_info (gdbarch, arc_linux_print_registers_info);
+/* Initialize the module. This function is called from the gdb core on start-up. */
- tdep->register_reggroup_p = arc_linux_register_reggroup_p;
-
- tdep->lowest_pc = 0x74;
+void
+_initialize_arc_linux_tdep (void)
+{
+ /* Register a handler with gdb for the Linux O/S ABI variant for the ARC
+ processor architecture, providing an initialization function;
+ 'bfd_arch_arc' is an enumeration value specifically denoting the ARC
+ architecture. */
+ gdbarch_register_osabi (bfd_arch_arc,
+ 0, // machine (irrelevant)
+ GDB_OSABI_LINUX,
+ arc_linux_init_abi);
+}
- tdep->arc_processor_variant_info = NULL;
- set_gdbarch_regset_from_core_section (gdbarch,
- arc_linux_regset_from_core_section);
- /* GNU/Linux uses SVR4-style shared libraries. */
- set_solib_svr4_fetch_link_map_offsets
- (gdbarch, svr4_ilp32_fetch_link_map_offsets);
- set_gdbarch_skip_solib_resolver (gdbarch, arc_linux_skip_solib_resolver);
-}
+/* This function is required simply to avoid an undefined symbol at linkage. */
void
-_initialize_arc_linux_tdep (void)
+arc_check_pc_defined (struct gdbarch *gdbarch)
{
- gdbarch_register_osabi (bfd_arch_arc, 0, GDB_OSABI_LINUX,
- arc_linux_init_abi);
}
+
+/******************************************************************************/