summaryrefslogtreecommitdiff
path: root/gdb/arc-elf32-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/arc-elf32-tdep.c')
-rwxr-xr-xgdb/arc-elf32-tdep.c2064
1 files changed, 2064 insertions, 0 deletions
diff --git a/gdb/arc-elf32-tdep.c b/gdb/arc-elf32-tdep.c
new file mode 100755
index 00000000000..2c7de60639f
--- /dev/null
+++ b/gdb/arc-elf32-tdep.c
@@ -0,0 +1,2064 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
+
+ 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 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/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This module provides support for the ARC processor family's target */
+/* dependencies which are specific to the arc-elf32 configuration of the */
+/* ARC gdb. */
+/* */
+/* */
+/* Functionality: */
+/* This module provides a number of operations: */
+/* */
+/* 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 */
+/* */
+/* 4) functions which implement the gdb extended commands */
+/* */
+/* arc-watch-range <start> [<kind>] for setting a watchpoint range */
+/* arc-break-range <start> <length> for setting a breakpoint range */
+/* arc-fill-memory <start> <length> [<pattern>] for filling memory */
+/* */
+/* 5) functions for various operations (such as program loading) which */
+/* are common to the different arc-elf32 targets supported */
+/* */
+/* */
+/* Usage: */
+/* The module exports a function _initialize_arc_elf32_tdep: the call to */
+/* this function is generated by the gdb build mechanism, so this function*/
+/* should not be explicitly called. */
+/* */
+/* This module exports a function arc_elf32_initialize which creates the */
+/* user commands which use those command-implementing functions; it also */
+/* stores pointers to the other functions in a data structure so that */
+/* they may be called from outside this module. */
+/* */
+/* 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 .. n1 : core registers R0 .. R31 */
+/* n1+1 .. n2 : extension core registers R32 .. R59 (if any) */
+/* n2+1 : r60 (LP_COUNT) */
+/* n2+2 : r63 (PCL) */
+/* n2+3 : IDENTITY auxiliary register */
+/* n2+4 .. n3 : non-BCR auxiliary registers in address order */
+/* n3+1 .. N-1 : Build Configuration Registers in address order */
+/* */
+/* 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) the set of non-BCR auxiliary registers, and the set of BCRs, */
+/* are each ordered by increasing register address in the ARC */
+/* auxiliary register space; */
+/* */
+/* 3) the IDENTITY auxiliary register comes before all the other */
+/* auxiliary registers, even though it does not come first in the */
+/* address space: this is so that the debugger can always get the */
+/* contents of the register, and so determine the architectural */
+/* version of the target processor, regardless of what that */
+/* version may be (and hence what the processor's auxiliary */
+/* register set is) - this is vital when the debug target is a */
+/* remote target, as the position of the register contents in the */
+/* 'g' RSP response packet (or the number to be specified in the */
+/* 'p' query packet) depends upon the target processor version; */
+/* otherwise, we would have the problem that the debugger could */
+/* not determine the target processor version without already */
+/* knowing it! */
+/* */
+/* The numbers are assigned to the registers by the arc-registers module, */
+/* after the XML definitions of the auxiliary registers and any extension */
+/* core registers defined for the target processor have been read and */
+/* processed. */
+/* */
+/* */
+/* Auxiliary Registers Definition: */
+/* The ARC processor is configurable, and the set of auxiliary registers */
+/* that a target processor may possess depends upon the configuration. It */
+/* is therefore not possible to hard-code descriptions of this register */
+/* set into the debugger. Instead, the descriptions of the registers are */
+/* read from an XML file (or files). */
+/* */
+/* The arc-elf32-gdb debugger provides commands which allow the user to */
+/* instruct it to read an XML file and use the register definitions in */
+/* that file; these definitions either completely replace, or are added */
+/* to (depending upon which command is used), any existing set of */
+/* definitions the debugger has; this allows processor architecture */
+/* variants to be described by groups of files (e.g. a common main file */
+/* describing the base configuration, plus additional files describing */
+/* cache-related registers, or MMU-related registers, which are specific */
+/* to different variants). */
+/* */
+/* Note that this scheme may also be used to define the set of extension */
+/* core registers (if any) possessed by the target processor. */
+/* */
+/* If no register set is defined by use of the commands, the debugger */
+/* attempts to read the register definitions from a default file; it will */
+/* look for this file first in the user's current working directory, then */
+/* in the user's home directory. In order to provide maximum flexibility, */
+/* the debugger delays the attempt to read the default file until it is */
+/* necessary, e.g. when connection to a target is being attempted, or a */
+/* check is made that the executable file to be debugged has been built */
+/* for the same architectural version (e.g. ARC600, ARC700, etc.) as the */
+/* version of the target processor. */
+/* */
+/* The arc-elf32 specific code makes as few assumptions as possible about */
+/* the auxiliary register set: it will always try to get the number (i.e. */
+/* the hardware number, the offset in the auxiliary register space) of an */
+/* auxiliary register from the definition of that register, even in the */
+/* case that the register is defined in the base ARC architecture, and */
+/* hence should be present in all processor variants. */
+/* */
+/* In particular, no assumption is made about the PC; so, to guarantee */
+/* that the debugger has read a definition of the PC by the time that it */
+/* is needed (as the complete set of auxiliary register definitions may */
+/* be read from a number of files, there is no requirement for the PC's */
+/* definition to be in any given file), a "guard" is set upon the PC such */
+/* that any attempt to read/write the PC by gdb will result in a check */
+/* that the PC is defined: if the PC is defined, the guard is removed, */
+/* and the read/write operation performed - otherwise, an error message */
+/* is reported, and the operation aborted. */
+/* */
+/* Register Byte Order: */
+/* The target register contents are held in gdb's register cache (i.e. in */
+/* a regcache struct) in target byte order; however, when values are */
+/* read/written to/from the xISS target (i.e. the dynamically loaded xISS */
+/* simulator) or the ARCangel4 target those values must be in host byte */
+/* order. */
+/* */
+/* The ARC debugger is currently built only to run on an X86 Linux host, */
+/* so the assumption is made that the host is little-endian. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <string.h>
+#include <signal.h>
+#include <byteswap.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcore.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "exceptions.h"
+#include "reggroups.h"
+#include "observer.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "gdb-events.h"
+#include "gdb_assert.h"
+
+/* ARC header files */
+#include "config/arc/tm-embed.h"
+#include "arc-tdep.h"
+#include "arc-memory.h"
+#include "arc-arguments.h"
+#include "arc-elf32-tdep.h"
+#include "arc-registers.h"
+#include "arc-remote-fileio.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ struct gdbarch *gdbarch;
+ struct ui_file *file;
+ struct frame_info *frame;
+} PrintData;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define INVALID_REGISTER_NUMBER (ARC_RegisterNumber) 0xFFFFFFFFU
+
+#define WATCH_MEMORY_COMMAND "arc-watch-range"
+#define BREAK_MEMORY_COMMAND "arc-break-range"
+#define FILL_MEMORY_COMMAND "arc-fill-memory"
+
+#define WATCH_MEMORY_COMMAND_USAGE "Usage: " WATCH_MEMORY_COMMAND " <START> <LENGTH> [ read | write | access ]\n"
+#define BREAK_MEMORY_COMMAND_USAGE "Usage: " BREAK_MEMORY_COMMAND " <START> <LENGTH>\n"
+#define FILL_MEMORY_COMMAND_USAGE "Usage: " FILL_MEMORY_COMMAND " <START> <LENGTH> [ <PATTERN> ]\n"
+
+
+
+/* ARC 700 brk_s instruction. */
+static const unsigned char le_breakpoint_instruction[] = { 0xff, 0x7f };
+static const unsigned char be_breakpoint_instruction[] = { 0x7f, 0xff };
+
+
+/* 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_MAX_CORE_REGS] =
+{
+ "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",
+
+ "fp", // r27
+ "sp", // r28
+ "ilink1", // r29
+ "ilink2", // r30
+ "blink", // r31
+
+ /* Extension core registers are 32 .. 59 inclusive. */
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47", "r48", "r49",
+ "r50", "r51", "r52", "r53", "r54", "r55", "r56", "r57", "r58", "r59",
+
+ "lp_count",
+
+ /* 61 is reserved, 62 is not a real register. */
+ "r61",
+ "r62",
+
+ "pcl"
+};
+
+
+/* For the Ctrl-C signal handler. */
+static void (*old_signal_handler) (int);
+
+/* This flag is used by the Ctrl-C interrupt mechanism: it is set by an
+ interrupt handler and tested by non-interrupt code, so must be declared
+ as volatile to avoid possible optimisation problems. */
+static volatile Boolean interrupt_processor;
+
+/* A pointer to the remote target's register store function. */
+static void (*remote_register_store)(struct regcache *regcache, int regno);
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* These are the h/w register numbers of the DEBUG, PC and STATUS32 registers. */
+ARC_RegisterNumber arc_debug_regnum;
+ARC_RegisterNumber arc_pc_regnum;
+ARC_RegisterNumber arc_status32_regnum;
+
+/* Whether a program has been loaded to the target. */
+Boolean arc_program_is_loaded;
+
+/* Whether a target is connected. */
+Boolean arc_target_is_connected;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define PRINT(regnum) \
+ default_print_registers_info (gdbarch, file, frame, regnum, all)
+
+#define PRINT_HW(hw_regnum) PRINT(arc_core_register_gdb_number(hw_regnum))
+
+#define PRINT_BY_NAME(regname) \
+{ \
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_name(regname); \
+ \
+ if (def) \
+ PRINT(arc_aux_gdb_register_number(def)); \
+} while (0)
+
+
+#define EXTRACT(argument, type, result) \
+{ \
+ struct expression *expr = parse_expression(argument); \
+ struct value *val = evaluate_expression(expr); \
+ struct cleanup *chain = make_cleanup(free_current_contents, &expr); \
+ \
+ result = *(type*) (value_contents (val)); \
+ do_cleanups (chain); \
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* This function creates the processor-specific information for the arc-elf32-gdb
+ variant of the the ARC gdb deubbger. */
+
+static void
+create_variant_info (struct gdbarch_tdep *tdep)
+{
+ tdep->processor_variant_info = xmalloc(sizeof(ARC_VariantsInfo));
+ tdep->processor_variant_info->processor_version = NO_ARCHITECTURE;
+
+ arc_initialize_aux_reg_info(&tdep->processor_variant_info->registers);
+}
+
+
+/* This function is used to read an auxiliary register on the target. */
+
+static Boolean
+read_target_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure)
+{
+ struct regcache *regcache = get_current_regcache();
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+ int gdb_regno = arc_aux_gdb_register_number(def);
+
+ /* Read the register contents from the target to the register cache,
+ then collect the register value from the cache. */
+ target_fetch_registers(regcache, gdb_regno);
+ regcache_raw_collect (regcache, gdb_regno, contents);
+
+ /* The register cache holds the contents in target byte order, so convert to
+ host byte order if the target and host orders are different. */
+ if (HOST_AND_TARGET_ENDIANNESS_DIFFER(current_gdbarch))
+ *contents = __bswap_32(*contents);
+
+ /* Unfortunately, we can not tell whether the read succeeded or failed. */
+ return TRUE;
+}
+
+
+/* This function returns a pointer to a function which may be used to read an
+ auxiliary register on the target. The register contents returned by that
+ function are in host byte order. */
+
+static ReadRegisterFunction
+read_aux_register (struct target_ops *target)
+{
+ /* If we have a function which can read an aux register on the target,
+ and return a success/failure result, use it instead. */
+ if ((strcmp(target->to_shortname, "arcxiss") == 0) ||
+ (strcmp(target->to_shortname, "arcjtag") == 0))
+ {
+ TargetOperations *operations = (TargetOperations*) target->to_data;
+ return operations->read_auxiliary_register;
+ }
+
+ return read_target_aux_register;
+}
+
+
+/* Convert the contents of the given register in the given cache so that it can
+ be written to the target (i.e. if there are any fields in the register which
+ are required by the ARC processor architectural definition to have particular
+ values on write, set those fields to those values). */
+
+static void convert_register(int gdb_regno,
+ struct regcache *regcache)
+{
+ ARC_RegisterContents contents;
+
+ regcache_raw_collect (regcache, gdb_regno, &contents);
+ arc_convert_aux_contents_for_write (gdb_regno, &contents);
+ regcache_raw_supply (regcache, gdb_regno, &contents);
+}
+
+
+/* This function is called when a remote target calls its 'to_store_registers'
+ operation: we intercept that call, and convert the register contents as
+ required, before calling the real operation. */
+
+static void
+intercept_remote_register_store (struct regcache *regcache, int gdb_regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch(regcache);
+ struct regcache *savedcache = regcache_xmalloc(gdbarch);
+
+ ENTERARGS("gdb_regno: %d", gdb_regno);
+
+ /* Save the register cache. */
+ regcache_cpy(savedcache, regcache);
+
+ /* Convert the value of the register(s) for writing. */
+ if (gdb_regno >= 0)
+ convert_register(gdb_regno, regcache);
+ else
+ {
+ int num_regs = gdbarch_num_regs (gdbarch);
+
+ for (gdb_regno = 0; gdb_regno < num_regs; gdb_regno++)
+ convert_register(gdb_regno, regcache);
+ }
+
+ /* Now use the real remote target 'store registers' operation to store the
+ converted cache. */
+ remote_register_store(regcache, gdb_regno);
+
+ /* Restore the register cache. */
+ regcache_cpy(regcache, savedcache);
+ regcache_xfree(savedcache);
+}
+
+
+/* This is a callback function which gets called by gdb whenever the current
+ object file changes. */
+
+static void
+new_object_file (struct objfile *objfile)
+{
+ if (objfile)
+ ARCHITECTURE_CHECK(current_gdbarch, objfile->obfd);
+}
+
+
+/* This is a callback function which gets called by gdb just before connection
+ * to a target is attempted. */
+
+static void
+pre_target_connection (struct target_ops *target)
+{
+ DEBUG("pre_target_connect : %s\n", target->to_shortname);
+
+ /* We do not yet know the version of the target processor. */
+ arc_architecture_is_unknown();
+
+ /* If we have not read yet any aux register definitions for this architecture,
+ * try to read the default file now. */
+ if (!arc_aux_regs_defined(current_gdbarch))
+ arc_read_default_aux_registers(current_gdbarch);
+}
+
+
+/* This is a callback function which gets called by gdb just after connection
+ to a target is completed. */
+
+static void
+post_target_connection (struct target_ops *target)
+{
+ DEBUG("post_target_connect : %s\n", target->to_shortname);
+
+ arc_target_is_connected = TRUE;
+
+ arc_update_architecture(read_aux_register(target));
+
+ ARCHITECTURE_CHECK(current_gdbarch,
+ (current_objfile) ? current_objfile->obfd : NULL);
+}
+
+
+/* This is a callback function which gets called by gdb just after disconnection
+ from a target has been completed. */
+
+static void
+post_target_disconnection (struct target_ops *target)
+{
+ DEBUG("post_target_disconnect : %s\n", target->to_shortname);
+
+ arc_target_is_connected = FALSE;
+}
+
+
+/* This is a callback function which gets called by gdb after a target has been updated. */
+
+static void
+target_updated (struct target_ops *target)
+{
+ DEBUG("target_updated : %s\n", target->to_shortname);
+
+ if (strcmp(target->to_shortname, "remote") == 0)
+ {
+ DEBUG("remote target register store interception is in force\n");
+
+ /* We must intercept the remote target's register store operation: we
+ need to convert register contents before they are written to the
+ target (we can not do that in remote.c as that is generic gdb code). */
+ if (target->to_store_registers != intercept_remote_register_store)
+ {
+ remote_register_store = target->to_store_registers;
+ target->to_store_registers = intercept_remote_register_store;
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 1) local functions for handling Ctrl-C */
+/* -------------------------------------------------------------------------- */
+
+/* The command line interface's stop routines. The interrupted_by_user function
+ is installed as a signal handler for SIGINT (it gets called when the user
+ types Ctrl-C).
+
+ The first time a user requests a stop, we set the interrupt_processor flag.
+ If this does not work, and the user tries a second time, we ask the user if
+ he'd like to detach from the target. */
+
+
+static void
+interrupted_twice (int signo);
+
+
+/* This function is called when the user types Ctrl-C. */
+
+static void
+interrupted_by_user (int signo)
+{
+ /* Change the signal handler for Ctrl-C to the second level handler so that
+ if we get the signal again whilst waiting for the program to halt, we do
+ something more drastic. */
+ (void) signal (SIGINT, interrupted_twice);
+
+ /* This flag is checked in each iteration of the loop that polls the target
+ processor to see whether it has halted (e.g. at a breakpoint); if the
+ flag is set, an attempt will be made to force the processor to halt.
+
+ N.B. once the polling loop is running, this flag is set only by this
+ handler, and is read only by the polling loop - so there is no
+ mutual exclusion problem to be worried about here; this is a MUCH
+ cleaner and more reliable method than trying to have this handler
+ force the halt itself, e.g. by calling target_stop. */
+ interrupt_processor = TRUE;
+
+ DEBUG("Attempting to interrupt...\n");
+}
+
+
+/* This function is called when the user types Ctrl-C twice. */
+
+static void
+interrupted_twice (int signo)
+{
+ if (query(_("Interrupted while waiting for the program to halt.\n"
+ "Give up (and stop debugging it)?")))
+ {
+ struct gdb_exception exception = {RETURN_QUIT,
+ GDB_NO_ERROR,
+ _("Interrupted by user")};
+
+ /* Put the old signal handler back. */
+ (void) signal (signo, old_signal_handler);
+
+ target_mourn_inferior();
+ DEBUG("interrupted_twice: throwing exception\n");
+ throw_exception (exception);
+
+ /* Control does not return here! */
+ }
+
+ /* Change the signal handler for Ctrl-C back to the first level handler. */
+ (void) signal (SIGINT, interrupted_by_user);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 2) functions for reading/writing registers */
+/* -------------------------------------------------------------------------- */
+
+/* This function maps a gdb internal register number to the hardware number
+ (i.e. core register number or number in the auxiliary register space). */
+
+static ARC_RegisterNumber
+get_hw_regnum_mapping (int gdb_regno)
+{
+ ARC_AuxRegisterDefinition *def;
+
+ if (arc_is_core_register(gdb_regno))
+ return arc_core_register_number(gdb_regno);
+
+ def = arc_find_aux_register_by_gdb_number(gdb_regno);
+
+ if (def)
+ return arc_aux_hw_register_number(def);
+
+ /* Not found. */
+ return INVALID_REGISTER_NUMBER;
+}
+
+
+/* This function fetches one register from the target and saves its contents in
+ the given register cache. The register is identified both by its gdb number
+ and its ARC hardware number. */
+
+static void
+debug_fetch_one_register (struct regcache * regcache,
+ ARC_RegisterNumber hw_regno,
+ int gdb_regno)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ ARC_RegisterContents contents;
+ Boolean register_read = FALSE;
+
+ ENTERARGS("gdb = %d, h/w = %d", gdb_regno, hw_regno);
+
+ gdb_assert(gdb_regno >= 0);
+
+ /* N.B. do not give a warning message if the register is write-only, as gdb
+ may be reading all registers, and it is best to quietly ignore the
+ ones that can not be read! */
+ if (arc_is_core_register(gdb_regno))
+ {
+ if (arc_core_register_access(hw_regno) != WRITE_ONLY)
+ register_read = operations->read_core_register(hw_regno, &contents, TRUE);
+ }
+ else
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+
+ if (arc_aux_register_access(def) != WRITE_ONLY)
+ register_read = operations->read_auxiliary_register (hw_regno, &contents, TRUE);
+ }
+
+ if (register_read)
+ {
+ DEBUG("read 0x%08X from target\n", contents);
+
+ /* The read_<type>_register functions return the register contents in
+ host order, but the register cache holds them in target byte order,
+ so swap the bytes if necessary before supplying the contents to the
+ cache. */
+ if (HOST_AND_TARGET_ENDIANNESS_DIFFER(get_regcache_arch(regcache)))
+ {
+ contents = __bswap_32(contents);
+ DEBUG("byte-swapped to 0x%08X\n", contents);
+ }
+
+ regcache_raw_supply (regcache, (int) gdb_regno, &contents);
+ }
+
+ LEAVEMSG;
+}
+
+
+/* This function is passed to the arc_all_aux_registers iterator.
+ It fetches one auxiliary register from the target. */
+
+static void
+debug_fetch_reg (ARC_AuxRegisterDefinition *def, void *data)
+{
+ debug_fetch_one_register((struct regcache*) data,
+ arc_aux_hw_register_number (def),
+ arc_aux_gdb_register_number(def));
+}
+
+
+/* This function gets a register from the given register cache and stores it
+ to the target. The register is identified both by its gdb number and its
+ ARC hardware number. */
+
+static void
+debug_store_one_register (struct regcache *regcache,
+ ARC_RegisterNumber hw_regno,
+ int gdb_regno)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ ARC_RegisterContents contents;
+
+ ENTERARGS("gdb = %d, h/w = %d", gdb_regno, hw_regno);
+
+ gdb_assert(gdb_regno >= 0);
+
+ regcache_raw_collect(regcache, gdb_regno, &contents);
+
+ DEBUG("collected 0x%08X from cache\n", contents);
+
+ /* The write_<type>_register functions take the register contents in
+ host order, but the register cache holds them in target byte order,
+ so swap the bytes if necessary after collecting the contents from the
+ functions. */
+ if (HOST_AND_TARGET_ENDIANNESS_DIFFER(get_regcache_arch(regcache)))
+ {
+ contents = __bswap_32(contents);
+ DEBUG("byte-swapped to 0x%08X\n", contents);
+ }
+
+ if (arc_is_core_register(gdb_regno))
+ {
+ if (arc_core_register_access(hw_regno) == READ_ONLY)
+ arc_elf32_core_warning(REGISTER_IS_READ_ONLY, hw_regno);
+ else
+ (void) operations->write_core_register(hw_regno, contents, TRUE);
+ }
+ else
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+
+ if (arc_aux_register_access(def) == READ_ONLY)
+ arc_elf32_aux_warning(REGISTER_IS_READ_ONLY, hw_regno);
+ else
+ (void) operations->write_auxiliary_register (hw_regno, contents, TRUE);
+ }
+
+ LEAVEMSG;
+}
+
+
+/* This function is passed to the arc_all_aux_registers iterator.
+ It stores one auxiliary register to the target. */
+
+static void
+debug_store_reg (ARC_AuxRegisterDefinition *def, void *data)
+{
+ debug_store_one_register ((struct regcache*) data,
+ arc_aux_hw_register_number (def),
+ arc_aux_gdb_register_number(def));
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 3) functions for reading/writing mmeory */
+/* -------------------------------------------------------------------------- */
+
+static unsigned int
+read_bytes (ARC_Address address,
+ ARC_Byte *data, /* May be not word-aligned. */
+ unsigned int bytes)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ return arc_read_memory(operations, address, data, bytes);
+}
+
+
+static unsigned int
+write_bytes (ARC_Address address,
+ ARC_Byte *data, /* May be not word-aligned. */
+ unsigned int bytes)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ return arc_write_memory(operations, address, data, bytes);
+}
+
+
+static unsigned int
+write_pattern (ARC_Address address,
+ ARC_Word pattern,
+ unsigned int bytes)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ return arc_write_pattern(operations, address, 0, bytes);
+}
+
+
+static unsigned int
+write_zeros (ARC_Address address,
+ unsigned int bytes)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ return arc_write_pattern(operations, address, 0, bytes);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 4) local functions for processor control */
+/* -------------------------------------------------------------------------- */
+
+/* This function is called when execution on the target has halted for some
+ reason (such as a breakpoint trigger). It determines whether the halt should
+ be reported to gdb, or execution resumed.
+
+ Parameters:
+ status : a pointer to the target status information
+ debug : the contents of the target processor DEBUG register
+ read_core_register : a function which can read a target core register
+
+ Result: TRUE if the halt is to be reported, FALSE if execution is to resume. */
+
+static Boolean
+report_processor_halt (struct target_waitstatus *status,
+ ARC_RegisterContents debug,
+ ReadRegisterFunction read_core_register)
+{
+ /* Test BH bit of DEBUG register. */
+ if (debug & DEBUG_BH)
+ {
+ DEBUG("s/w breakpoint instruction was executed\n");
+
+ /* If the breakpoint is on an intercepted function entrypoint. */
+ switch (arc_check_interception_breakpoint(&status->value.integer))
+ {
+ case INTERCEPTION_RESUME:
+ /* If the user has typed a Ctrl-C since target execution was
+ last started. */
+ if (interrupt_processor)
+ {
+ /* The interception is complete, so honour the interrupt
+ request by making it appear that the target was stopped
+ by a SIGINT signal; the PC has been set to the return
+ address of the intercepted function, so it will look to
+ the user as though the program was interrupted at that
+ point. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_INT;
+ }
+ else
+ {
+ /* This is the only case in which we return FALSE. */
+ return FALSE;
+ }
+ break;
+
+ case INTERCEPTION_HALT:
+ /* Some other breakpoint has triggered. */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+
+ case INTERCEPTION_EXIT:
+ /* The program called the 'exit' routine (its exit status has
+ been read by the interception mechanism and returned to us in
+ status->value.integer). */
+ status->kind = TARGET_WAITKIND_EXITED;
+ break;
+
+ case INTERCEPTION_INTERRUPT:
+ DEBUG("*** interception was interrupted!\n");
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_INT;
+ break;
+ }
+ }
+ /* Test SH bit of DEBUG register. */
+ else if (debug & DEBUG_SH)
+ {
+ ARC_RegisterContents exit_code = 0;
+
+ /* If the DEBUG.SH ("self halt") bit is set, we stopped because of the
+ flag instruction, which is used by programs to exit. */
+ status->kind = TARGET_WAITKIND_EXITED;
+
+ /* Get the exit code of the program (held in R0). */
+ if (read_core_register(0, &exit_code, TRUE))
+ {
+ DEBUG("exit code = %d\n", exit_code);
+ }
+ else
+ warning(_("assuming exit code = 0"));
+
+ status->value.integer = (int) exit_code;
+ }
+ else
+ {
+ /* We stopped for some other reason: if the user had tried to interrupt
+ with a Ctrl-C, return the event as a SIGINT, otherwise as a SIGTRAP
+ (and let gdb work out what happened). */
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = (interrupt_processor) ? TARGET_SIGNAL_INT
+ : TARGET_SIGNAL_TRAP;
+ }
+
+ return TRUE;
+}
+
+
+/* Determine whether the given register is a member of the given group.
+
+ 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)
+{
+ gdb_assert(regnum >= 0);
+
+ /* Save/restore:
+ 1. all standard core regs, except PCL (PCL is not writable)
+ 2. those extension core regs which are read/write
+ 3. aux regs LP_START .. LP_END (IDENTITY is not writable)
+ 4. aux regs PC_REGNUM .. STATUS32_L2
+ 5. aux regs ERET .. EFA */
+
+ if (arc_is_core_register(regnum))
+ {
+ ARC_RegisterNumber hw_num = arc_core_register_number(regnum);
+
+ /* R61 and R62 are reserved; they are not in any reggroup. */
+ if (hw_num == 61 || hw_num == 62)
+ return 0;
+
+ if ((group == save_reggroup || group == restore_reggroup))
+ {
+ if (IS_EXTENSION_CORE_REGISTER(hw_num))
+ return (arc_core_register_access(hw_num) == READ_WRITE) ? 1 : 0;
+
+ return (hw_num == ARC_PCL_REGNUM) ? 0 : 1;
+ }
+
+ if (group == general_reggroup)
+ return 1;
+ }
+ else
+ {
+#define REGISTER_NAME_IS(ident) (strcasecmp(name, ident) == 0)
+
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(regnum);
+
+ if (def)
+ {
+ const char *name = arc_aux_register_name(def);
+
+ if (arc_aux_is_unused(def))
+ return 0;
+
+ if ((group == save_reggroup || group == restore_reggroup))
+ {
+ if (arc_aux_register_access(def) != READ_WRITE)
+ return 0;
+ }
+
+ /* Which regs to save/restore? */
+ if ((group == save_reggroup || group == restore_reggroup))
+ {
+ return (REGISTER_NAME_IS("LP_START") ||
+ REGISTER_NAME_IS("LP_END") ||
+ REGISTER_NAME_IS("PC") ||
+ REGISTER_NAME_IS("STATUS32") ||
+ REGISTER_NAME_IS("STATUS32_L1") ||
+ REGISTER_NAME_IS("STATUS32_L2") ||
+ REGISTER_NAME_IS("ERET") ||
+ REGISTER_NAME_IS("ERBTA") ||
+ REGISTER_NAME_IS("ERSTATUS") ||
+ REGISTER_NAME_IS("ECR") ||
+ REGISTER_NAME_IS("EFA")) ? 1 : 0;
+ }
+
+ if (group == general_reggroup)
+ return (REGISTER_NAME_IS("STATUS32")) ? 0 : 1;
+
+ if (group == system_reggroup)
+ {
+ return (REGISTER_NAME_IS("SEMAPHORE") ||
+ REGISTER_NAME_IS("STATUS32_L1") ||
+ REGISTER_NAME_IS("STATUS32_L2") ||
+ REGISTER_NAME_IS("AUX_IRQ_LV12") ||
+ REGISTER_NAME_IS("AUX_IRQ_LEV") ||
+ REGISTER_NAME_IS("AUX_IRQ_HINT") ||
+ REGISTER_NAME_IS("ERET") ||
+ REGISTER_NAME_IS("ERBTA") ||
+ REGISTER_NAME_IS("ERSTATUS") ||
+ REGISTER_NAME_IS("ECR") ||
+ REGISTER_NAME_IS("EFA") ||
+ REGISTER_NAME_IS("ICAUSE1") ||
+ REGISTER_NAME_IS("ICAUSE2") ||
+ REGISTER_NAME_IS("AUX_IENABLE") ||
+ REGISTER_NAME_IS("AUX_ITRIGGER") ||
+ REGISTER_NAME_IS("BTA_L1") ||
+ REGISTER_NAME_IS("BTA_L2") ||
+ REGISTER_NAME_IS("AUX_IRQ_PULSE_CANCEL") ||
+ REGISTER_NAME_IS("AUX_IRQ_PENDING")) ? 1 : 0;
+ }
+ }
+ }
+
+ /* Let the caller sort it out! */
+ return -1;
+}
+
+
+/* This function is passed to the arc_all_aux_registers iterator.
+ It prints the value of one auxiliary register. */
+
+static void
+print_one_aux_register (ARC_AuxRegisterDefinition *def, void *data)
+{
+ if (!arc_aux_is_unused(def))
+ {
+ PrintData *p = (PrintData*) data;
+ int regnum = arc_aux_gdb_register_number(def);
+
+ default_print_registers_info (p->gdbarch, p->file, p->frame, regnum, TRUE);
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 5) local functions called from gdb */
+/* -------------------------------------------------------------------------- */
+
+/* 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_elf32_binutils_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+ return arc_core_register_gdb_number((ARC_RegisterNumber) reg);
+}
+
+
+/* Print the contents of one, some or all registers. */
+
+static void
+arc_elf32_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 registers. */
+ {
+ /* R32 .. R59 are the extension core registers, R61 and R62 are reserved. */
+
+ /* R0 .. R26 */
+ for (regnum = 0; regnum <= 26; regnum++)
+ PRINT_HW ((ARC_RegisterNumber) regnum);
+
+ PRINT_HW (ARC_FP_REGNUM ); // r27
+ PRINT_HW (ARC_SP_REGNUM ); // r28
+ PRINT_HW (ARC_ILINK1_REGNUM ); // r29
+ PRINT_HW (ARC_ILINK2_REGNUM ); // r30
+ PRINT_HW (ARC_BLINK_REGNUM ); // r31
+ PRINT_HW (ARC_LP_COUNT_REGNUM); // r60
+ PRINT_HW (ARC_PCL_REGNUM ); // r63
+
+ if (all)
+ {
+ PrintData data = {gdbarch, file, frame};
+
+ /* Print all of the aux registers. */
+ arc_all_aux_registers(print_one_aux_register, &data);
+ }
+ else
+ {
+ /* Print just a selection of the aux registers. */
+ PRINT_BY_NAME ("LP_START" );
+ PRINT_BY_NAME ("LP_END" );
+ PRINT_BY_NAME ("STATUS32" );
+ PRINT_BY_NAME ("BTA" );
+ PRINT_BY_NAME ("EFA" );
+ PRINT_BY_NAME ("ERET" );
+ PRINT_BY_NAME ("STATUS32_L1");
+ PRINT_BY_NAME ("STATUS32_L2");
+ PRINT_BY_NAME ("ERSTATUS" );
+ PRINT_BY_NAME ("PC" );
+ }
+ }
+}
+
+
+/* Return the name of the given register. */
+
+static const char*
+arc_elf32_register_name (struct gdbarch *gdbarch, int gdb_regno)
+{
+ if (gdb_regno >= 0)
+ {
+ if (arc_is_core_register(gdb_regno))
+ {
+ ARC_RegisterNumber hw_num = arc_core_register_number(gdb_regno);
+
+ if (hw_num < ELEMENTS_IN_ARRAY(register_names))
+ return register_names[hw_num];
+ }
+ else
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno);
+
+ /* If it is an auxiliary register. */
+ if (def)
+ return arc_aux_register_name(def);
+ }
+ }
+
+ internal_error(__FILE__, __LINE__, _("invalid register number: %d"), gdb_regno);
+}
+
+
+/* Determine whether the given register is read-only. */
+
+static int
+arc_elf32_cannot_store_register (struct gdbarch *gdbarch, int gdb_regno)
+{
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno);
+
+ /* No warning should be printed. arc_cannot_store_register being
+ called does not imply that someone is actually writing to regnum. */
+
+ /* If it is an auxiliary register. */
+ if (def)
+ return (arc_aux_register_access(def) == READ_ONLY) ? 1 : 0;
+
+ /* It is writable. */
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 6) local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+
+/* This function handles seeting a hardware breakpoint or watchpoint across a
+ range of memory address (rather than at a single location).
+
+ Parameters:
+ args : the user arguments to the command
+ from_tty : non-zero if the command was issued at the command-line
+ is_watchpoint : TRUE if a watchpoint to to be set, FALSE if a breakpoint
+ command : the name of the command
+ usage : the usage message for the command
+*/
+
+static void
+memory_range_command (char *args,
+ int from_tty,
+ Boolean is_watchpoint,
+ const char *command,
+ const char *usage)
+{
+ char *length_arg;
+ unsigned int start;
+ int length;
+ enum target_hw_bp_type type;
+
+ if (!args)
+ {
+ printf_filtered (_("%s"), usage);
+ return;
+ }
+
+ length_arg = strchr(args, ' ');
+
+ if (!length_arg)
+ {
+ printf_filtered (_("%s : no second argument\n%s"), command, usage);
+ return;
+ }
+
+ /* Split up the input string. */
+ length_arg[0] = (char) 0;
+ length_arg++;
+ while (*length_arg == ' ') length_arg++;
+
+ if (is_watchpoint)
+ {
+ char *access_arg = strchr(length_arg, ' ');
+
+ if (access_arg)
+ {
+ /* Split up the input string. */
+ access_arg[0] = (char) 0;
+ access_arg++;
+ while (*access_arg == ' ') access_arg++;
+
+ if (strcmp(access_arg, "read") == 0)
+ type = hw_read;
+ else if (strcmp(access_arg, "write") == 0)
+ type = hw_write;
+ else if (strcmp(access_arg, "access") == 0)
+ type = hw_access;
+ else
+ {
+ printf_filtered (_("%s: invalid type '%s'\n%s"), command, access_arg, usage);
+ return;
+ }
+ }
+ else
+ /* Access is write by default. */
+ type = hw_write;
+ }
+ else
+ type = hw_execute;
+
+ /* The address expression. */
+ EXTRACT(args, unsigned int, start)
+
+ /* The length expression. */
+ EXTRACT(length_arg, int, length)
+
+ if (length <= 0)
+ {
+ warning(_("%s: %s <= 0"), command, length_arg);
+ return;
+ }
+
+ DEBUG("try to set %u breakpoint at 0x%08X length %d bytes\n",
+ type, start, length);
+
+ watch_range_command(start, (unsigned int) length, type, from_tty);
+
+ /* Although the call to insert_breakpoints would result in an error message
+ if the range breakpoint could not be set, the breakpoint would still be
+ entered into gdb's breakpoint table, and displayed by the 'info break'
+ command - that would be even more confusing to the user! */
+#if 0
+ /* gdb manages breakpoints by deleting them from the target as soon as it
+ has halted, then re-inserting them again immediately before execution is
+ resumed (no, I don't know why either, unless it is to make generating a
+ disassembly display easier by removing all the s/w b/ps from the code) -
+ so in order to display what actionpoints are currently in use, we must
+ temporarily re-insert the breakpoints! */
+ insert_breakpoints();
+ arc_display_actionpoints();
+ (void) remove_breakpoints();
+#endif
+}
+
+
+/* arc-break-range <start> <length>
+ Set hardware breakpoint at address START covering LENGTH bytes. */
+
+static void
+arc_elf32_break_memory_command (char *arg, int from_tty)
+{
+ memory_range_command(arg, from_tty, FALSE, BREAK_MEMORY_COMMAND, BREAK_MEMORY_COMMAND_USAGE);
+}
+
+
+/* arc-watch-range <start> <length> [read|write|access]
+ Set hardware watchpoint at address START covering LENGTH bytes. */
+
+static void
+arc_elf32_watch_memory_command (char *arg, int from_tty)
+{
+ memory_range_command(arg, from_tty, TRUE, WATCH_MEMORY_COMMAND, WATCH_MEMORY_COMMAND_USAGE);
+}
+
+
+/* arc-fill-memory <start> <length> [<pattern>]
+ Write repeated copies of PATTERN at address START covering LENGTH bytes. */
+
+static void
+arc_elf32_fill_memory_command (char *arg, int from_tty)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ char *length_arg;
+ char *pattern_arg;
+ ARC_Address start;
+ ARC_Word pattern;
+ int length;
+
+ gdb_assert(operations != NULL);
+
+ if (!arg)
+ {
+ printf_filtered ("%s", _(FILL_MEMORY_COMMAND_USAGE));
+ return;
+ }
+
+ length_arg = strchr(arg, ' ');
+
+ if (!length_arg)
+ {
+ printf_filtered (_(FILL_MEMORY_COMMAND " : no second argument\n" FILL_MEMORY_COMMAND_USAGE));
+ return;
+ }
+
+ /* Split up the input string. */
+ length_arg[0] = (char) 0;
+ length_arg++;
+ while (*length_arg == ' ') length_arg++;
+
+ pattern_arg = strchr(length_arg, ' ');
+ if (pattern_arg)
+ {
+ /* Split up the input string. */
+ pattern_arg[0] = (char) 0;
+ pattern_arg++;
+ }
+
+ /* The address expression. */
+ EXTRACT(arg, ARC_Address, start)
+
+ /* The length expression. */
+ EXTRACT(length_arg, int, length)
+
+ if (length <= 0)
+ {
+ warning(_(FILL_MEMORY_COMMAND ": %s <= 0"), length_arg);
+ return;
+ }
+
+ if (pattern_arg)
+ {
+ /* The pattern expression. */
+ EXTRACT(pattern_arg, ARC_Word, pattern)
+ }
+ else
+ pattern = 0;
+
+ if (operations)
+ {
+ unsigned int written = write_pattern(start, pattern, (unsigned int) length);
+
+ if (written != (unsigned int) length)
+ warning (_(FILL_MEMORY_COMMAND ": only %u bytes written to target memory"), written);
+ }
+ else
+ error(_(FILL_MEMORY_COMMAND " is not available for this target"));
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Perform arc-elf32-gdb specific initialization. */
+
+struct gdbarch*
+arc_elf32_initialize (struct gdbarch *gdbarch,
+ struct gdbarch_list *arches)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Set up a guard on the PC: if any attempt is made by gdb to read or write
+ the PC before an XML definition of the PC aux register has been read this
+ will cause an error message to be output. */
+ arc_aux_pc_guard(gdbarch, TRUE);
+
+ /* N.B. this function may be called twice: once when gdb is started, then again
+ when the 'target' command is issued; do not try to read the aux
+ registers definitions the first time (when 'arches' is NULL) as that
+ results in an error message (if the XML file is not found) which is
+ output too early in the start-up process (before gdb has identified
+ itself). */
+ if (arches == NULL)
+ create_variant_info(tdep);
+ else
+ {
+ /* This is the arch that was created earlier. */
+ struct gdbarch *gdbarch0 = arches[0].gdbarch;
+ struct gdbarch_tdep *tdep0 = gdbarch_tdep(gdbarch0);
+
+ /* Have auxiliary registers been defined for that arch? */
+ if (arc_aux_regs_defined(gdbarch0))
+ {
+ /* Share the variant info. */
+ tdep->processor_variant_info = tdep0->processor_variant_info;
+ }
+ else
+ create_variant_info(tdep);
+ }
+
+ /* Fill in target-dependent info in ARC-private structure. */
+
+ tdep->is_sigtramp = NULL;
+ tdep->sigcontext_addr = NULL;
+ tdep->sc_reg_offset = NULL;
+ tdep->sc_num_regs = 0;
+ tdep->pc_regnum_in_sigcontext = 0;
+
+ 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 = 0;
+
+ /* Pass target-dependent info to gdb. */
+
+ DEBUG("setting PC %d\n", arc_aux_pc_number(gdbarch));
+ DEBUG("setting #regs %d\n", ARC_NR_REGS);
+ DEBUG("setting #pseudo %d\n", ARC_NR_PSEUDO_REGS);
+
+ /* ARC_NR_REGS and ARC_NR_PSEUDO_REGS are defined in the tm-embed.h configuration file. */
+ set_gdbarch_pc_regnum (gdbarch, arc_aux_pc_number(gdbarch));
+ 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_elf32_print_registers_info);
+ set_gdbarch_register_name (gdbarch, arc_elf32_register_name);
+ set_gdbarch_cannot_store_register (gdbarch, arc_elf32_cannot_store_register);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arc_elf32_binutils_reg_to_regnum);
+
+ /* See ARC Bug #96650: disable the use of the 'P' and 'p' RSP packets, so
+ forcing gdb to use the 'G' and 'g' packets instead, in case the arc-elf32
+ debug target is the xISS being used as a remote target. */
+ {
+ static Boolean packets_disabled = FALSE;
+
+ /* N.B. this is something of a kluge: if execution of the target program
+ is restarted (e.g. a 'start' command is followed by a 'run'
+ command) this function is called again - but if execute_command
+ is called again, an assertion fails way down in the regcache code
+ because the target appears to have a stack, but current_gdbarch
+ is set to NULL! So do this only once. */
+ if (!packets_disabled)
+ {
+ execute_command("set remote set-register-packet off", 0);
+ execute_command("set remote fetch-register-packet off", 0);
+
+ packets_disabled = TRUE;
+ }
+ }
+
+ return gdbarch;
+}
+
+
+/* This is the module initialization function that is called from gdb. */
+
+void
+_initialize_arc_elf32_tdep (void)
+{
+ (void) add_cmd (BREAK_MEMORY_COMMAND,
+ class_breakpoint,
+ arc_elf32_break_memory_command,
+ _("Set a breakpoint on a memory address range.\n"
+ BREAK_MEMORY_COMMAND_USAGE
+ "<START> and <LENGTH> can be any expressions that evaluate to integers.\n"),
+ &cmdlist);
+
+ (void) add_cmd (WATCH_MEMORY_COMMAND,
+ class_breakpoint,
+ arc_elf32_watch_memory_command,
+ _("Set a watchpoint on a memory address range.\n"
+ WATCH_MEMORY_COMMAND_USAGE
+ "<START> and <LENGTH> can be any expressions that evaluate to integers.\n"
+ "If the watchpoint mode is omitted, it defaults to 'access'.\n"),
+ &cmdlist);
+
+ (void) add_cmd (FILL_MEMORY_COMMAND,
+ class_obscure,
+ arc_elf32_fill_memory_command,
+ _("Fill a memory address range with a repeated pattern.\n"
+ FILL_MEMORY_COMMAND_USAGE
+ "<START>, <LENGTH> and <PATTERN> can be any expressions that evaluate to integers.\n"
+ "If <PATTERN> is omitted, it defaults to 0.\n"),
+ &cmdlist);
+
+ (void) observer_attach_new_objfile (new_object_file);
+ (void) observer_attach_target_pre_connect (pre_target_connection);
+ (void) observer_attach_target_post_connect (post_target_connection);
+ (void) observer_attach_target_post_disconnect(post_target_disconnection);
+ (void) observer_attach_target_updated (target_updated);
+}
+
+
+/* Find the ARC hardware numbers of the DEBUG, POC and STATUS32 aux registers: this
+ is the minimal set of registers required for controlling program execution on a
+ h/w target. */
+
+void arc_elf32_find_register_numbers (void)
+{
+ arc_debug_regnum = arc_aux_find_register_number("DEBUG", ARC_HW_DEBUG_REGNUM);
+ arc_pc_regnum = arc_aux_find_register_number("PC", ARC_HW_PC_REGNUM);
+ arc_status32_regnum = arc_aux_find_register_number("STATUS32", ARC_HW_STATUS32_REGNUM);
+}
+
+
+/* Check that an XML definition of the PC aux register has been read: 'error'
+ is called if that is not the case.
+
+ This function is simply a wrapper for a call to arc_aux_check_pc_defined;
+ there is a function of the same name in the arc-linux-tdep module (which does
+ nothing) so that it may be called from the arc-tdep module in either of the
+ builds of the ARC debugger (as the arc-registers module is present only in
+ the arc-elf32-gdb build). */
+
+void
+arc_check_pc_defined (struct gdbarch *gdbarch)
+{
+ arc_aux_check_pc_defined(gdbarch);
+}
+
+
+/* Load the program to be debugged to the tarrget.
+
+ Parameters:
+ filename : the executable file
+ from_tty : non-zero if the command was issued at the command-line
+*/
+
+void
+arc_elf32_load_program (char *filename, int from_tty)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ asection *bss_section;
+
+ ENTERARGS("%s", filename);
+
+ if (exec_bfd == NULL)
+ error(_("Must use 'file' command before 'load' command"));
+
+ arc_aux_check_pc_defined(NULL);
+
+ /* Now that we know the program file as well as the target (since we can be
+ loading only if the target is connected), check that the program has been
+ built for the processor version that is in the target. */
+ ARCHITECTURE_CHECK(current_gdbarch, exec_bfd);
+
+ if (filename == NULL || *filename == '\0')
+ filename = bfd_get_filename(exec_bfd);
+
+ /* Check that the file has been compiled for the endianness of the target. */
+ {
+ ARC_RegisterNumber memsubsys = arc_aux_find_register_number("MEMSUBSYS", ARC_HW_MEMSUBSYS_REGNUM);
+ ARC_RegisterContents contents;
+
+ if (read_aux_register(&current_target)(memsubsys, &contents, TRUE))
+ {
+ Boolean big_endian_target = ((contents & 4) != 0);
+
+ DEBUG("MEMSUBSYS BCR: 0x%08X\n", contents);
+
+ if (big_endian_target && bfd_little_endian(exec_bfd))
+ warning(_("target is big-endian but file %s is little-endian"), filename);
+
+ if (!big_endian_target && bfd_big_endian(exec_bfd))
+ warning(_("target is little-endian but file %s is big-endian"), filename);
+ }
+ }
+
+ /* In case anything was previously loaded. */
+ arc_set_IO_interception(operations, INTERCEPTION_RESET);
+
+ /* Let gdb do all the real work of loading. */
+ generic_load(filename, from_tty);
+
+ /* Zero the BSS section in memory, if it exists. */
+ bss_section = bfd_get_section_by_name (exec_bfd, ".bss");
+
+ if (bss_section)
+ {
+ CORE_ADDR bss_addr = bfd_section_lma (exec_bfd, bss_section);
+ bfd_size_type bss_size = bfd_get_section_size (bss_section);
+ unsigned int bytes;
+
+ printf_filtered(_("Zeroing section .bss, size 0x%0x lma 0x%0x\n"),
+ (unsigned int) bss_size, (unsigned int) bss_addr);
+
+ bytes = write_zeros((ARC_Address) bss_addr, (unsigned int) bss_size);
+
+ if (bytes != (unsigned int) bss_size)
+ warning(_("load: error zeroing BSS section - only %u bytes zeroed"), bytes);
+ }
+ else
+ {
+ DEBUG("%s: no BSS section\n", __FUNCTION__);
+ }
+
+
+ /* We now have a program ready for execution on the target; inform the
+ program arguments module that we have a newly-loaded program (so any
+ information that it had about any program loaded before is now invalid). */
+ arc_program_is_loaded = TRUE;
+ arc_program_loaded();
+
+ /* But the program has not yet been executed. */
+ current_target.to_has_execution = 0;
+}
+
+
+/* Create the inferior, ready for execution on the target to start.
+
+ Parameters:
+ exec_file : the executable file from which the loaded program was read
+ args : the arguments to be passed to the program in argc/argv
+ env : the environment (name/value pairs) for program execution
+ target_ops : the target operations structure for the target
+*/
+
+void
+arc_elf32_create_inferior (char *exec_file,
+ char *args,
+ char **env,
+ struct target_ops *target_ops)
+{
+ TargetOperations *operations = (TargetOperations*) target_ops->to_data;
+ Boolean set_no_args = TRUE;
+ char *all_args = NULL;
+ CORE_ADDR start_address;
+
+ ENTERARGS("exec_file = \"%s\", args = \"%s\"", exec_file, args);
+
+ /* If no exec file handed to us, get it from the exec-file command -
+ with a good, common error message if none is specified. */
+ if (exec_file == NULL)
+ exec_file = get_exec_file (1);
+
+ /* Include the exec file name as arg[0]. */
+ if (exec_file != NULL || args != NULL)
+ {
+ size_t length = 10; /* Safety margin. */
+
+ if (exec_file != NULL)
+ length += strlen(exec_file) + 1;
+
+ if (args != NULL)
+ length += strlen(args) + 1;
+
+ all_args = xmalloc(length);
+
+ all_args[0] = '\0';
+
+ if (exec_file != NULL)
+ (void) strcat(all_args, exec_file);
+
+ if (args != NULL)
+ {
+ (void) strcat(all_args, " ");
+ (void) strcat(all_args, args);
+ }
+ }
+
+ /* Check that we do know which register is the PC. */
+ arc_aux_check_pc_defined(NULL);
+
+ if (!arc_program_is_loaded)
+ error(_("No program loaded"));
+
+ /* We don't really have a PID or anything, but GDB uses this value to check
+ if the program is running. */
+ inferior_ptid.pid = 42;
+
+ /* Must set the PC to the program start address. */
+ start_address = bfd_get_start_address (exec_bfd);
+
+ DEBUG("setting PC to 0x%x\n", (unsigned int) start_address);
+
+ write_pc (start_address);
+
+ /* This sets the target's to_has_execution flag to 1. */
+ target_mark_running(target_ops);
+
+ /* Do we have arguments to pass to the program? */
+ if (all_args != NULL)
+ {
+ if (arc_setup_arguments(all_args))
+ set_no_args = FALSE;
+ else
+ warning(_("can not set up arguments to program"));
+
+ xfree(all_args);
+ }
+
+ /* If there are no arguments to be passed to the program, or we failed to
+ set them up, at least try to set R0 and R1 to indicate that are no
+ arguments! */
+ if (set_no_args)
+ {
+ /* N.B. we do not use the target_store_registers operation here, as that
+ does not give us an indication of success or failure. */
+ if (!operations->write_core_register(0, 0, TRUE))
+ warning(_("can not set parameter register R0 to 0 - main parameter 'argc' will be undefined"));
+
+ if (!operations->write_core_register(1, 0, TRUE))
+ warning(_("can not set parameter register R1 to 0 - main parameter 'argv' will be undefined"));
+ }
+
+ /* Set I/O interception on, so that any I/O operations performed by the program
+ when it is executed will be trapped and handled by the debugger. */
+ arc_set_IO_interception(operations, INTERCEPTION_ON);
+}
+
+
+/* There are two ways in which the target processor may be executed:
+
+ 1) once started, the processor will run asynchronously until an explicit
+ attempt to stop it is made (e.g. real h/w);
+
+ 2) the processor may be run synchronously until it has executed a certain
+ 'chunk' of instructions (e.g. the xISS).
+
+ So, this function gets either 1) a 'run' operation, or 2) 'start' and 'stop'
+ operations - but not all three of them!
+
+ If an attempt is made (by the user typing Ctrl-C) to interrupt the processor
+ whilst it is running, in case 1) we must wait until the 'run' operation has
+ completed before checking the 'interrupt_processor' flag; whereas in case 2),
+ we can attempt to force the processor to stop. */
+
+void
+arc_elf32_execute (struct target_waitstatus *status,
+ ProcessorControlFunction run_processor,
+ ProcessorControlFunction start_processor,
+ ProcessorControlFunction stop_processor)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ /* This flag will be set if the user types Ctrl-C. */
+ interrupt_processor = FALSE;
+
+ /* Set up a signal handler for Ctrl-C. */
+ old_signal_handler = signal (SIGINT, interrupted_by_user);
+
+ /* Wait until the processor has *really* halted. */
+ while (TRUE)
+ {
+ /* Set to 0 in case we leave inner loop without reading DEBUG register. */
+ ARC_RegisterContents debug = 0;
+
+ /* Wait until the processor has *apparently* halted. */
+ while (TRUE)
+ {
+ ARC_RegisterContents status32;
+
+ /* Are we running the processor synchronously? */
+ if (run_processor)
+ {
+ /* If the user has typed a Ctrl-C since the last chunk of
+ instructions were executed, exit from this inner loop. */
+ if (interrupt_processor)
+ break;
+
+ DEBUG("running processor...\n");
+
+ /* Otherwise, run the processor to execute another chunk. */
+ run_processor();
+ }
+ else
+ {
+ /* If the user has typed a Ctrl-C since target execution was
+ last started, try to force the processor to halt; it does not
+ matter if we do not succeed, as we will simply try again on
+ the next iteration of the loop. */
+ if (interrupt_processor)
+ stop_processor();
+ }
+
+ /* Now try to read the STATUS32 register, and check whether its H
+ bit is set, indicating that the processor has really halted (as
+ opposed to having simply finished executing a chunk); again, it
+ does not matter if we do not succeed, as we will simply try again
+ on the next iteration of the loop. */
+ if (operations->read_auxiliary_register(arc_status32_regnum, &status32, TRUE))
+ {
+#if 0
+ ARC_RegisterContents PC;
+
+ printf_filtered(_("STATUS32: %08X\n"), status32);
+
+ if (operations->read_auxiliary_register(arc_pc_regnum, &PC, TRUE))
+ printf_filtered(_("PC: %08X\n"), PC);
+#endif
+
+ if (status32 & STATUS32_HALT)
+ {
+ DEBUG("halted: STATUS32 = %08X\n", status32);
+
+ /* Perform a polling wait for any delayed load to complete.
+
+ N.B. this is necessary for real hardware, though the xISS
+ currently does not simulate pending loads, although
+ it will do so at some future date - however, it is
+ not an error to check the flag! */
+ while (TRUE)
+ {
+ if (operations->read_auxiliary_register(arc_debug_regnum, &debug, TRUE))
+ {
+ if (!(debug & DEBUG_LOAD_PENDING))
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* The processor is now halted in a reliable state, but it might need to
+ be re-started... */
+ if (report_processor_halt(status, debug, operations->read_core_register))
+ break;
+
+ DEBUG("*** resuming execution\n");
+
+ /* If we are running the processor asynchronously, we must explicitly
+ start it again - otherwise, we simply execute another chunk in the
+ next iteration of this loop. */
+ if (start_processor)
+ start_processor();
+ }
+
+ /* Put the old signal handler back. */
+ (void) signal (SIGINT, old_signal_handler);
+
+ DEBUG("processor has halted\n");
+}
+
+
+/* Close the connection to the target. */
+
+void
+arc_elf32_close (Boolean resume)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+
+ /* Do this while the target is halted. */
+ arc_restore_stack_top_address();
+
+ /* We will no longer intercept any I/O operations. */
+ arc_set_IO_interception(operations, INTERCEPTION_OFF);
+
+ /* Let the target continue. */
+ if (resume)
+ target_resume (inferior_ptid, 0, 0);
+
+ current_target.to_has_execution = 0;
+
+ arc_architecture_is_unknown();
+}
+
+
+/* Fetch one or all registers from the target.
+
+ Parameters:
+ regcache : cache to write register to
+ gdb_regno: register number (-1 means 'all registers')
+*/
+
+void
+arc_elf32_fetch_registers (struct regcache *regcache, int gdb_regno)
+{
+ ENTERARGS("%d", gdb_regno);
+
+ /* All registers. */
+ if (gdb_regno == -1)
+ {
+ int num_core_registers = (int) arc_core_register_count(get_regcache_arch(regcache));
+
+ /* Core registers. */
+ for (gdb_regno = 0; gdb_regno < num_core_registers; gdb_regno++)
+ debug_fetch_one_register(regcache, (ARC_RegisterNumber) gdb_regno, gdb_regno);
+
+ /* Auxiliary registers (incl. build configuration registers). */
+ arc_all_aux_registers(debug_fetch_reg, regcache);
+ }
+ else
+ {
+ ARC_RegisterNumber hw_regno = get_hw_regnum_mapping (gdb_regno);
+
+ if (hw_regno == INVALID_REGISTER_NUMBER)
+ error(_("Invalid register number: %d"), gdb_regno);
+ else
+ debug_fetch_one_register(regcache, hw_regno, gdb_regno);
+ }
+
+ LEAVEMSG;
+}
+
+
+/* Store one or all registers to the target.
+
+ Parameters :
+ regcache : cache to read register from
+ gdb_regno: register number (-1 means 'all registers')
+*/
+
+void
+arc_elf32_store_registers (struct regcache *regcache, int gdb_regno)
+{
+ ENTERARGS("%d", gdb_regno);
+
+ /* All registers. */
+ if (gdb_regno == -1)
+ {
+ int num_core_registers = (int) arc_core_register_count(get_regcache_arch(regcache));
+
+ /* Core registers. */
+ for (gdb_regno = 0; gdb_regno < num_core_registers; gdb_regno++)
+ debug_store_one_register(regcache, (ARC_RegisterNumber) gdb_regno, gdb_regno);
+
+ /* Auxiliary registers (excl. build configuration registers, which are not writable). */
+ arc_all_aux_registers(debug_store_reg, regcache);
+ }
+ else
+ {
+ ARC_RegisterNumber hw_regno = get_hw_regnum_mapping (gdb_regno);
+
+ if (hw_regno == INVALID_REGISTER_NUMBER)
+ error(_("Invalid register number: %d"), gdb_regno);
+ else
+ debug_store_one_register(regcache, hw_regno, gdb_regno);
+ }
+
+ LEAVEMSG;
+}
+
+
+/* Read or write data to/from target memory.
+
+ if 'object' is TARGET_OBJECT_MEMORY then
+ if 'writebuf' is NULL
+ read 'len' bytes of data from target memory starting at address 'offset' to 'readbuf'
+ else
+ write 'len' bytes of data from 'writebuf' to target memory starting at address 'offset'
+
+ Returns number of bytes of memory read/written.
+
+ Returns -1 for all other operations (i.e. object != TARGET_OBJECT_MEMORY). */
+
+LONGEST
+arc_elf32_xfer_partial (struct target_ops *ops, // unused
+ enum target_object object,
+ const char *annex, // unused
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ LONGEST len)
+{
+ ENTERARGS("object %d offset 0x%x len %lld", (unsigned int) object, (unsigned int) offset, len);
+
+ /* Handle memory access. */
+ if (object == TARGET_OBJECT_MEMORY)
+ {
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ unsigned int xfered;
+
+ /* No need to worry about the alignment of the address 'offset', or the number
+ of bytes to be transffered - the memory read/write operations handle that. */
+ if (writebuf != NULL)
+ xfered = write_bytes((ARC_Address) offset,
+ (ARC_Byte*) writebuf,
+ (unsigned int) len);
+ else
+ xfered = read_bytes((ARC_Address) offset,
+ (ARC_Byte*) readbuf,
+ (unsigned int) len);
+
+ DEBUG("...leaving %s(memory %s) with return value %d\n",
+ __FUNCTION__, (writebuf == NULL) ? "read" : "write", xfered);
+
+ return (LONGEST) xfered;
+ }
+
+ if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
+ {
+ /* We should create and return an XML string here. */
+ return -1;
+ }
+
+ printf_filtered(_("\nRequested target_object %d not yet supported with target %s\n"),
+ (int) object, current_target.to_shortname);
+ return -1;
+}
+
+
+/* Insert a software breakpoint in the program code on the target.
+
+ Parameters:
+ bpt: information defining the breakpoint.
+
+ Returns: 0 for success, 1 for failure. */
+
+int
+arc_elf32_insert_breakpoint (struct bp_target_info *bpt)
+{
+ TargetOperations *operations = (TargetOperations*) current_target.to_data;
+ const unsigned char *breakpt_instruction;
+ unsigned int bytes;
+
+ ENTERARGS("0x%08X", (unsigned int) bpt->placed_address);
+
+ /* Get the breakpoint instruction code, and its size in bytes. */
+ breakpt_instruction = gdbarch_breakpoint_from_pc (current_gdbarch,
+ &bpt->placed_address,
+ &bpt->placed_size);
+
+ /* FIXME: alignment of breakpt_instruction data! */
+ DEBUG("breakpoint size = %d and breakpoint instruction = 0x%x\n",
+ bpt->placed_size, *(unsigned int *) breakpt_instruction);
+
+ /* Save the existing instruction at the given address as the shadow contents. */
+ bytes = read_bytes((ARC_Address) bpt->placed_address,
+ (ARC_Byte*) bpt->shadow_contents,
+ (unsigned int) bpt->placed_size);
+
+ if (bytes == (unsigned int) bpt->placed_size)
+ /* Overwrite the instruction with the breakpoint instruction. */
+ bytes = write_bytes((ARC_Address) bpt->placed_address,
+ (ARC_Byte*) breakpt_instruction,
+ (unsigned int) bpt->placed_size);
+
+ return (bytes == (unsigned int) bpt->placed_size) ? 0 : 1;
+}
+
+
+/* Remove a software breakpoint from the program code on the target.
+
+ Parameters:
+ bpt: information defining breakpoint.
+
+ Returns: 0 for success, 1 for failure. */
+
+int
+arc_elf32_remove_breakpoint (struct bp_target_info *bpt)
+{
+ unsigned int bytes;
+
+ /* FIXME: alignment of shadow_contents data! */
+ ENTERARGS("0x%08X, 0x%lx", (unsigned int) bpt->placed_address,
+ *(unsigned long *) bpt->shadow_contents);
+
+ /* Write the old code back. */
+ bytes = write_bytes((ARC_Address) bpt->placed_address,
+ (ARC_Byte*) bpt->shadow_contents,
+ (unsigned int) bpt->placed_size);
+
+ return (bytes == (unsigned int) bpt->placed_size) ? 0 : 1;
+}
+
+
+/* Output a warning message related to a core register. */
+
+void
+arc_elf32_core_warning (RegisterError error,
+ ARC_RegisterNumber hw_regno)
+{
+ int gdb_regno = arc_core_register_gdb_number(hw_regno);
+
+ /* N.B. the supplied format string contains a %s specifier which
+ allows the string "extension " to be inserted into the message. */
+ warning((error == REGISTER_IS_READ_ONLY) ? _("%score register %s is read-only") :
+ (error == ERROR_ON_READING_REGISTER) ? _("failure reading %score register %s") :
+ _("failure writing %score register %s"),
+ IS_EXTENSION_CORE_REGISTER(hw_regno) ? _("extension ") : _(""),
+ gdbarch_register_name(current_gdbarch, gdb_regno));
+}
+
+
+/* Output a warning message related to an auxiliary register. */
+
+void
+arc_elf32_aux_warning (RegisterError error,
+ ARC_RegisterNumber hw_regno)
+{
+ warning((error == REGISTER_IS_READ_ONLY) ? _("auxiliary register %s (0x%x) is read-only") :
+ (error == ERROR_ON_READING_REGISTER) ? _("failure reading auxiliary register %s (0x%x)") :
+ _("failure writing auxiliary register %s (0x%x)"),
+ arc_aux_register_name_of(hw_regno), hw_regno);
+}
+
+/******************************************************************************/