summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/JTAG_aps_driver.c560
-rwxr-xr-xgdb/JTAG_download.c208
-rw-r--r--gdb/JTAG_ops_driver.c904
-rw-r--r--gdb/Makefile.in138
-rwxr-xr-xgdb/arc-architecture.c502
-rw-r--r--gdb/arc-architecture.h74
-rw-r--r--gdb/arc-arguments.c427
-rw-r--r--gdb/arc-arguments.h48
-rw-r--r--gdb/arc-board.c1996
-rw-r--r--gdb/arc-board.h65
-rw-r--r--gdb/arc-dummy-gpio.c94
-rw-r--r--gdb/arc-dummy-jtag-ops.c274
-rwxr-xr-xgdb/arc-elf32-tdep.c2064
-rw-r--r--gdb/arc-elf32-tdep.h118
-rw-r--r--gdb/arc-gpio.c251
-rwxr-xr-xgdb/arc-gpio.h72
-rw-r--r--gdb/arc-inst-tracing.c356
-rw-r--r--gdb/arc-inst-tracing.h89
-rw-r--r--gdb/arc-jtag-actionpoints.c1337
-rw-r--r--gdb/arc-jtag-actionpoints.h68
-rw-r--r--gdb/arc-jtag-ops.c2215
-rw-r--r--gdb/arc-jtag-ops.h154
-rw-r--r--gdb/arc-jtag-tdep.c638
-rw-r--r--gdb/arc-jtag.c2008
-rw-r--r--gdb/arc-jtag.h112
-rw-r--r--gdb/arc-linux-tdep.c1143
-rw-r--r--gdb/arc-linux-tdep.h51
-rw-r--r--gdb/arc-memory.c445
-rw-r--r--gdb/arc-memory.h64
-rw-r--r--gdb/arc-registers.c2566
-rw-r--r--gdb/arc-registers.h226
-rw-r--r--gdb/arc-regnums-defs.h195
-rw-r--r--gdb/arc-remote-fileio.c741
-rw-r--r--gdb/arc-remote-fileio.h64
-rw-r--r--gdb/arc-support.h136
-rw-r--r--gdb/arc-tdep.c3840
-rw-r--r--gdb/arc-tdep.h213
-rwxr-xr-xgdb/arc-xiss.c1787
-rwxr-xr-xgdb/arc-xiss.h41
-rw-r--r--gdb/breakpoint.c563
-rw-r--r--gdb/breakpoint.h13
-rw-r--r--gdb/cli/cli-script.c7
-rw-r--r--gdb/config.in15
-rw-r--r--gdb/config/arc/a4-jtag.mt3
-rw-r--r--gdb/config/arc/arc.mt4
-rw-r--r--gdb/config/arc/embed.mt3
-rw-r--r--gdb/config/arc/linux.mt3
-rw-r--r--gdb/config/arc/tm-a4-jtag.h103
-rw-r--r--gdb/config/arc/tm-embed.h164
-rw-r--r--gdb/config/arc/tm-linux.h112
-rwxr-xr-xgdb/configure236
-rw-r--r--gdb/configure.ac33
-rw-r--r--gdb/configure.tgt14
-rw-r--r--gdb/doc/observer.texi17
-rw-r--r--gdb/dwarf2-frame.c6
-rw-r--r--gdb/dwarf2loc.c153
-rw-r--r--gdb/exec.c2
-rw-r--r--gdb/features/arc-a5-cpu.xml258
-rw-r--r--gdb/features/arc-registers.dtd71
-rw-r--r--gdb/features/arc600-cpu.xml266
-rw-r--r--gdb/features/arc700-cpu.xml416
-rw-r--r--gdb/gdb-events.c33
-rw-r--r--gdb/gdb-events.h9
-rw-r--r--gdb/gdbserver/Makefile.in2
-rwxr-xr-xgdb/gdbserver/build_gdbserver.sh6
-rw-r--r--gdb/gdbserver/configure.srv15
-rw-r--r--gdb/gdbserver/linux-arc-low.c4
-rw-r--r--gdb/gdbserver/proc-service.c6
-rw-r--r--gdb/gdbserver/remote-utils.c7
-rw-r--r--gdb/gpio.h38
-rw-r--r--gdb/infcmd.c28
-rw-r--r--gdb/remote-fileio.c1314
-rw-r--r--gdb/remote-sim.c14
-rw-r--r--gdb/stack.c26
-rw-r--r--gdb/symtab.h20
-rw-r--r--gdb/target-fileio.c1344
-rw-r--r--gdb/target-fileio.h53
-rw-r--r--gdb/target.c57
-rw-r--r--gdb/testsuite/config/arc-jtag.exp112
-rw-r--r--gdb/testsuite/config/remote-gdbserver.exp570
-rw-r--r--gdb/testsuite/gdb.arch/arc-step-jtag.exp88
-rw-r--r--gdb/testsuite/gdb.arch/arc-step-jtag.s46
-rw-r--r--gdb/testsuite/gdb.arch/arc-step.exp83
-rw-r--r--gdb/testsuite/gdb.arch/arc-step.s43
-rw-r--r--gdb/testsuite/gdb.asm/arc.inc55
-rw-r--r--gdb/testsuite/gdb.asm/asm-source.exp6
-rw-r--r--gdb/testsuite/gdb.base/callfuncs.exp9
-rw-r--r--gdb/testsuite/gdb.base/float.exp2
-rw-r--r--gdb/testsuite/gdb.base/relocate.exp8
-rw-r--r--gdb/testsuite/lib/arc-gdbserver.exp98
-rw-r--r--gdb/testsuite/lib/arc-jtag.exp32
-rw-r--r--gdb/testsuite/lib/gdb.exp16
-rw-r--r--gdb/testsuite/lib/gdbserver-support.exp4
-rw-r--r--gdb/testsuite/lib/mi-support.exp13
-rw-r--r--gdb/testsuite/lib/telnet-exec.exp29
-rw-r--r--gdb/version.in2
96 files changed, 24980 insertions, 7958 deletions
diff --git a/gdb/JTAG_aps_driver.c b/gdb/JTAG_aps_driver.c
new file mode 100644
index 00000000000..1118948c62b
--- /dev/null
+++ b/gdb/JTAG_aps_driver.c
@@ -0,0 +1,560 @@
+/* Target dependent code for ARC700, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Richard Stuckey <richard.stuckey@arc.com>
+
+ 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 contains a test driver for the JTAG actionpoints module of */
+/* the ARC port of gdb. */
+/* */
+/* Usage: */
+/* <driver> [ -c ] [ -d ] [ -s ] [ -r <count> ] [ -a N ] */
+/* */
+/* where -c specifies target connection & disconnection only */
+/* -d switches on JTAG operation debuggging */
+/* -s simulates the JTAG target */
+/* -r specifies the JTAG operation retry count */
+/* -a 2 | 4 | 8 specifies the number of simulated actionpoints */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "breakpoint.h"
+
+/* ARC header files */
+#include "arc-jtag.h"
+#include "arc-jtag-ops.h"
+#include "arc-jtag-actionpoints.h"
+#include "arc-registers.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+// complete the type here
+struct aux_register_definition
+{
+ const char* name;
+ ARC_RegisterNumber number;
+};
+
+
+typedef enum
+{
+ CLEAR_USER_BIT,
+ RESTORE_USER_BIT
+} Status32Action;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* global debug flag */
+Boolean arc_debug_target;
+
+ARC_RegisterNumber arc_debug_regnum = ARC_HW_DEBUG_REGNUM;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define SUCCESS 0
+#define FAILURE (-1)
+
+// what should this be?
+#define DATA_AREA 0x00001000
+#define DATA_AREA_LENGTH 1024
+
+#define BP_ADDRESS (DATA_AREA + 0x0400)
+
+#define MAX_ACTION_POINTS 8
+
+#define WRITE_WATCHPOINT 0
+#define READ_WATCHPOINT 1
+#define ACCESS_WATCHPOINT 2
+
+#define AP_BUILD 0x76
+
+
+static Boolean test = TRUE;
+static Boolean simulate = FALSE;
+static unsigned int num_actionpoints = 2;
+static struct target_ops operations;
+
+static const ARC_AuxRegisterDefinition registers[] =
+{
+ { "DEBUG", ARC_HW_DEBUG_REGNUM },
+ { "IDENTITY", ARC_HW_IDENTITY_REGNUM },
+ { "PC", ARC_HW_PC_REGNUM },
+ { "STATUS32", ARC_HW_STATUS32_REGNUM },
+ { "AP_BUILD", ARC_HW_AP_BUILD_REGNUM },
+ { "AMV0", ARC_HW_AMV0_REGNUM },
+ { "AMM0", ARC_HW_AMM0_REGNUM },
+ { "AC0", ARC_HW_AC0_REGNUM }
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define CHECK(status, expected) \
+{ \
+ if ((status) != (expected)) \
+ { \
+ failed("%d line: status %d != %d", __LINE__, status, expected); \
+ } \
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+static void failed(const char* fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "*** FAILED: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+// exit(EXIT_FAILURE);
+}
+
+
+static void run_tests(Boolean before_reset)
+{
+static struct bp_target_info bpt[MAX_ACTION_POINTS + 1];
+
+ int status;
+ int result;
+ CORE_ADDR addr;
+ unsigned int i;
+ unsigned int max_actionpoints;
+
+ if (before_reset)
+ {
+ memset(&bpt, sizeof(bpt), 0);
+
+ for (i = 0; i <= MAX_ACTION_POINTS; i++)
+ bpt[i].placed_address = BP_ADDRESS + 4 * i;
+ }
+ else
+ {
+ arc_dump_actionpoints("after reset");
+
+ /* remove the actionpoints that were set before the reset */
+ status = operations.to_remove_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+ }
+
+
+ if (operations.to_can_use_hw_breakpoint(bp_hardware_breakpoint, 8, 0) == 1)
+ max_actionpoints = 8;
+ else if (operations.to_can_use_hw_breakpoint(bp_hardware_breakpoint, 4, 0) == 1)
+ max_actionpoints = 4;
+ else if (operations.to_can_use_hw_breakpoint(bp_hardware_breakpoint, 2, 0) == 1)
+ max_actionpoints = 2;
+ else
+ {
+ printf("can not use h/w breakpoints\n");
+ return;
+ }
+
+ printf("target supports %d actionpoints\n", max_actionpoints);
+
+
+ /* N breakpoints that each require 1 actionpoint can be set */
+ for (i = 0; i < max_actionpoints + 1; i++)
+ {
+ status = operations.to_insert_hw_breakpoint(&bpt[i]);
+ CHECK(status, (i < max_actionpoints) ? SUCCESS : FAILURE);
+ }
+ for (i = 0; i < max_actionpoints + 1; i++)
+ {
+ status = operations.to_remove_hw_breakpoint(&bpt[i]);
+ CHECK(status, (i < max_actionpoints) ? SUCCESS : FAILURE);
+ }
+
+
+ if (operations.to_region_ok_for_hw_watchpoint(DATA_AREA, DATA_AREA_LENGTH))
+ {
+ /* N watchpoints that each require 1 actionpoint can be set */
+ for (i = 0; i < max_actionpoints + 1; i++)
+ {
+ status = operations.to_insert_watchpoint(DATA_AREA, 4, WRITE_WATCHPOINT);
+ CHECK(status, (i < max_actionpoints) ? SUCCESS : FAILURE);
+ }
+ for (i = 0; i < max_actionpoints + 1; i++)
+ {
+ status = operations.to_remove_watchpoint(DATA_AREA, 4, WRITE_WATCHPOINT);
+ CHECK(status, (i < max_actionpoints) ? SUCCESS : FAILURE);
+ }
+
+ if (max_actionpoints == 8)
+ {
+ /* this requires 2 actionpoints (a pair) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ arc_display_actionpoints();
+ status = operations.to_remove_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this requires 3 actionpoints (a quad) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 5, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ arc_display_actionpoints();
+ status = operations.to_remove_watchpoint(DATA_AREA, 5, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this requires 4 actionpoints (a quad) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this requires another 4 actionpoints (another quad) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 25, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ status = operations.to_remove_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 25, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this would require 5 actionpoints! */
+ status = operations.to_insert_watchpoint(DATA_AREA, 17, ACCESS_WATCHPOINT); CHECK(status, FAILURE);
+
+ /* this will tie up actionpoints 0, 2 and 6 */
+ status = operations.to_insert_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[2]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[3]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[4]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[5]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[6]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[3]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[4]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[5]); CHECK(status, SUCCESS);
+
+ arc_display_actionpoints();
+
+ arc_dump_actionpoints("before quad shuffle");
+
+ /* this requires 4 actionpoints (a quad) - this should cause the
+ * actionpoints to be shuffled so that a quad is available
+ */
+ status = operations.to_insert_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ arc_dump_actionpoints("after quad shuffle");
+
+ arc_display_actionpoints();
+
+ /* release the tied-up actionpoints */
+ status = operations.to_remove_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[2]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[6]); CHECK(status, SUCCESS);
+
+ arc_dump_actionpoints("before quad shuffle");
+
+ /* this requires another 4 actionpoints (a quad) - this should
+ * cause the actionpoints to be shuffled so that the other quad is
+ * available
+ */
+ status = operations.to_insert_watchpoint(DATA_AREA, 36, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ arc_dump_actionpoints("after quad shuffle");
+
+ /* release the two quads */
+ status = operations.to_remove_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 36, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ }
+ else if (max_actionpoints == 4)
+ {
+ /* this requires 2 actionpoints (a pair) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this requires 3 actionpoints (a quad) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 5, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 5, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this requires 4 actionpoints (a quad) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 9, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this would require 5 actionpoints! */
+ status = operations.to_insert_watchpoint(DATA_AREA, 17, ACCESS_WATCHPOINT); CHECK(status, FAILURE);
+
+ /* this will tie up actionpoints 0 and 2 */
+ status = operations.to_insert_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[2]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+
+ arc_dump_actionpoints("before quad shuffle");
+
+ /* this requires 2 actionpoints (a pair) - this should cause the
+ * actionpoints to be shuffled so that a pair is available
+ */
+ status = operations.to_insert_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ arc_dump_actionpoints("after quad shuffle");
+
+ status = operations.to_remove_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_remove_hw_breakpoint(&bpt[2]); CHECK(status, SUCCESS);
+ }
+ else if (max_actionpoints == 2)
+ {
+ /* this requires 2 actionpoints (a pair) */
+ status = operations.to_insert_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+ status = operations.to_remove_watchpoint(DATA_AREA, 6, ACCESS_WATCHPOINT); CHECK(status, SUCCESS);
+
+ /* this would require 3 actionpoints! */
+ status = operations.to_insert_watchpoint(DATA_AREA, 5, ACCESS_WATCHPOINT); CHECK(status, FAILURE);
+ }
+
+ result = operations.to_stopped_by_watchpoint();
+ printf("%sstopped by watchpoint\n", (result) ? "" : "not ");
+
+ result = operations.to_stopped_data_address(&operations, &addr);
+ if (result)
+ printf("stopped by data access at address 0x%08X\n", (unsigned int) addr);
+ }
+ else
+ printf("area %0x08X .. %0x08X does not allow watchpoints\n", DATA_AREA, DATA_AREA + DATA_AREA_LENGTH - 1);
+
+ arc_dump_actionpoints("before reset");
+
+ /* leave some actionpoints set to ensure that there are some to re-establish
+ * after target board reset
+ */
+ if (before_reset)
+ {
+ status = operations.to_insert_hw_breakpoint(&bpt[0]); CHECK(status, SUCCESS);
+ status = operations.to_insert_hw_breakpoint(&bpt[1]); CHECK(status, SUCCESS);
+ }
+}
+
+
+static void process_options(int argc, char** argv)
+{
+ int c;
+
+ while ((c = getopt (argc, argv, "sdcr:a:")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ arc_jtag_ops.state_machine_debug = TRUE;
+ break;
+ case 'r':
+ arc_jtag_ops.retry_count = atoi(optarg);
+ break;
+ case 'a':
+ num_actionpoints = atoi(optarg);
+ if (!(num_actionpoints == 2 || num_actionpoints == 4 || num_actionpoints == 8))
+ {
+ fprintf(stderr, "Usage: %s [ -d ]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'c':
+ test = FALSE;
+ break;
+ case 's':
+ simulate = TRUE;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [ -dcs ] [ -r <count> ] [ -a <actionpoints> ]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+extern void _initialize_arc_jtag_ops(void);
+
+
+int main(int argc, char** argv)
+{
+ Boolean opened;
+
+ printf("Starting test of ARC JTAG actionpoints...\n");
+
+ _initialize_arc_jtag_ops();
+
+ process_options(argc, argv);
+
+ opened = ((simulate) ? TRUE : arc_jtag_ops.open());
+
+ if (opened)
+ {
+ printf("ARC processor is connected\n");
+
+ /* this can be done only after connection */
+ if (arc_initialize_actionpoint_ops(&operations))
+ {
+ if (test)
+ {
+ run_tests(TRUE);
+ printf("resetting board...\n");
+ if (!simulate)
+ arc_jtag_ops.reset_board();
+ printf("board reset\n");
+ if (!arc_restore_actionpoints_after_reset())
+ failed("could not restore actionpoints after reset");
+ run_tests(FALSE);
+ }
+ }
+ else
+ printf("processor does not support actionpoints\n");
+
+ if (!simulate)
+ arc_jtag_ops.close();
+ }
+
+ printf("Finished test of ARC JTAG actionpoints\n");
+
+ return 0;
+}
+
+
+/* N.B. these functions are found in arc-jtag.c and arc-registers.c, but are
+ * included here in order to avoid including that module in the built test
+ * driver, as that would also pull in a lot of the gdb modules!
+ *
+ * Also, this allows the AUX register read/write operations to be simulated,
+ * thus making it possible to test much of the logic of the arc-jtag-actionpoints
+ * module without a real JTAG target.
+ */
+
+void arc_change_status32(Status32Action action)
+{
+ static ARC_RegisterContents status32;
+
+ if (action == CLEAR_USER_BIT)
+ {
+ /* Get processor out of user mode. */
+
+ if (arc_read_jtag_aux_register(ARC_HW_STATUS32_REGNUM, &status32, FALSE))
+ {
+ /* if the User bit is actually set */
+ if (status32 & STATUS32_USER)
+ if (!arc_write_jtag_aux_register(ARC_HW_STATUS32_REGNUM,
+ status32 & ~STATUS32_USER, FALSE))
+ warning(_("Can not clear User bit in STATUS32 register"));
+ }
+ else
+ warning(_("Can not read STATUS32 register"));
+ }
+ else
+ {
+ /* if the User bit was actually cleared */
+ if (status32 & STATUS32_USER)
+ if (!arc_write_jtag_aux_register(ARC_HW_STATUS32_REGNUM, status32, FALSE))
+ warning(_("Can not restore User bit in STATUS32 register"));
+ }
+}
+
+
+Boolean arc_read_jtag_aux_register (ARC_RegisterNumber hwregno,
+ ARC_RegisterContents* contents,
+ Boolean warn_on_failure)
+{
+ if (simulate)
+ {
+ if (hwregno == AP_BUILD)
+ {
+ if (num_actionpoints == 2)
+ *contents = 0x00000004;
+ else if (num_actionpoints == 4)
+ *contents = 0x00000104;
+ else
+ *contents = 0x00000204;
+ }
+ else
+ *contents = 0;
+ return TRUE;
+ }
+
+ return (arc_jtag_ops.read_aux_reg(hwregno, contents) == JTAG_SUCCESS);
+}
+
+
+Boolean arc_write_jtag_aux_register (ARC_RegisterNumber hwregno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure)
+{
+ if (simulate)
+ {
+// printf("AUX: hwregno = %d, contents = 0x%08X\n", hwregno, contents);
+ return TRUE;
+ }
+
+ return (arc_jtag_ops.write_aux_reg(hwregno, contents) == JTAG_SUCCESS);
+}
+
+
+ARC_AuxRegisterDefinition*
+arc_find_aux_register_by_name(const char* name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(registers); i++)
+ {
+ const ARC_AuxRegisterDefinition* def = &registers[i];
+
+ if (strcmp(name, def->name) == 0)
+ return (ARC_AuxRegisterDefinition*) def;
+ }
+
+ return NULL;
+}
+
+
+ARC_RegisterNumber arc_aux_hw_register_number(ARC_AuxRegisterDefinition* def)
+{
+ return def->number;
+}
+
+
+ARC_RegisterNumber arc_aux_find_register_number(const char* name,
+ ARC_RegisterNumber defaultNumber)
+{
+ ARC_AuxRegisterDefinition* def = arc_find_aux_register_by_name(name);
+
+ return (def) ? def->number : defaultNumber;
+}
+
+/******************************************************************************/
diff --git a/gdb/JTAG_download.c b/gdb/JTAG_download.c
new file mode 100755
index 00000000000..d3f0626906a
--- /dev/null
+++ b/gdb/JTAG_download.c
@@ -0,0 +1,208 @@
+/* Target dependent code for ARC700, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Richard Stuckey <richard.stuckey@arc.com>
+
+ 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 contains a test driver for the JTAG operations module of */
+/* the ARC port of gdb. It measures the speed at which data can be */
+/* downloaded to the target. */
+/* */
+/* Usage: */
+/* <driver> [ -c ] [ -d ] [ -r <count> ] */
+/* */
+/* where -c specifies target connection & disconnection only */
+/* -d switches on JTAG operation debuggging */
+/* -r specifies the JTAG operation retry count */
+/* */
+/******************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "arc-jtag-ops.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define MB 1024 * 1024
+#define DATA_AREA 0x00001000
+#define DATA_AREA_SIZE 1 * MB
+
+
+static ARC_Byte data[DATA_AREA_SIZE];
+
+
+static Boolean test = TRUE;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* global debug flag */
+Boolean arc_debug_target;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+static void failed(const char* fmt, ...)
+{
+ va_list ap;
+
+ printf("*** FAILED: ");
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf("\n");
+
+// exit(EXIT_FAILURE);
+}
+
+
+static void run_test(void)
+{
+ unsigned int i;
+ unsigned int bytes;
+ struct timeval start_time, end_time;
+ long long int time_count;
+
+ for (i = 0; i < DATA_AREA_SIZE; i++)
+ data[i] = (ARC_Byte) i;
+
+ gettimeofday (&start_time, NULL);
+
+ bytes = arc_jtag_ops.memory_write_chunk(DATA_AREA, data, DATA_AREA_SIZE);
+
+ gettimeofday (&end_time, NULL);
+
+ if (bytes != DATA_AREA_SIZE)
+ failed("memory write: %d", bytes);
+
+ /* Compute the elapsed time in milliseconds, as a tradeoff between
+ accuracy and overflow. */
+ time_count = (end_time.tv_sec - start_time.tv_sec) * 1000;
+ time_count += (end_time.tv_usec - start_time.tv_usec) / 1000;
+
+ if (time_count > 0)
+ {
+ unsigned long rate = (bytes * 1000) / time_count;
+
+ printf("0x%x bytes downloaded in %lld milliseconds\n", bytes, time_count);
+ printf("transfer rate: %lu bytes/sec\n", rate);
+ }
+
+
+ gettimeofday (&start_time, NULL);
+
+ bytes = arc_jtag_ops.memory_write_pattern(DATA_AREA, 0, DATA_AREA_SIZE);
+
+ gettimeofday (&end_time, NULL);
+
+ if (bytes != DATA_AREA_SIZE)
+ failed("memory fill zero: %d", bytes);
+
+ /* Compute the elapsed time in milliseconds, as a tradeoff between
+ accuracy and overflow. */
+ time_count = (end_time.tv_sec - start_time.tv_sec) * 1000;
+ time_count += (end_time.tv_usec - start_time.tv_usec) / 1000;
+
+ if (time_count > 0)
+ {
+ unsigned long rate = (bytes * 1000) / time_count;
+
+ printf("0x%x bytes zeroed in %lld milliseconds\n", bytes, time_count);
+ printf("zero rate: %lu bytes/sec\n", rate);
+ }
+
+}
+
+
+static void process_options(int argc, char** argv)
+{
+ int c;
+
+ while ((c = getopt (argc, argv, "dcr:")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ arc_jtag_ops.state_machine_debug = TRUE;
+ break;
+ case 'r':
+ arc_jtag_ops.retry_count = atoi(optarg);
+ break;
+ case 'c':
+ test = FALSE;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [ -d ]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+extern void _initialize_arc_jtag_ops(void);
+
+
+int main(int argc, char** argv)
+{
+ Boolean opened;
+
+ printf("Starting test of ARC JTAG download...\n");
+
+ _initialize_arc_jtag_ops();
+
+ process_options(argc, argv);
+
+ opened = arc_jtag_ops.open();
+
+ if (opened)
+ {
+ printf("ARC processor is connected\n");
+
+ if (test)
+ run_test();
+
+ arc_jtag_ops.close();
+ }
+
+ printf("Finished test of ARC JTAG download\n");
+
+ return 0;
+}
+
+/******************************************************************************/
diff --git a/gdb/JTAG_ops_driver.c b/gdb/JTAG_ops_driver.c
new file mode 100644
index 00000000000..8ae877627c6
--- /dev/null
+++ b/gdb/JTAG_ops_driver.c
@@ -0,0 +1,904 @@
+/* Target dependent code for ARC700, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Richard Stuckey <richard.stuckey@arc.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This 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 contains a test driver for the JTAG operations module of */
+/* the ARC port of gdb. */
+/* */
+/* Usage: */
+/* <driver> [ -c ] [ -d ] [ -r <count> ] [ -m ] */
+/* */
+/* where -c specifies target connection & disconnection only */
+/* -d switches on JTAG operation debuggging */
+/* -r specifies the JTAG operation retry count */
+/* -m specifies testing memory operations only */
+/* */
+/******************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "arc-jtag-ops.h"
+#include "arc-memory.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef enum
+{
+ RO, // read-only
+ RW, // read/write
+ WO, // write-only
+ UU
+} RegisterMode;
+
+
+typedef struct
+{
+ const char* name;
+ ARC_RegisterNumber regno;
+ ARC_RegisterContents mask;
+ RegisterMode mode;
+} RegisterInfo;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+// what should this be?
+#define DATA_AREA 0x00001000
+#define BUFFER_LENGTH 128
+
+#define ARC_NR_CORE_REGS 32
+
+
+#undef RBCR
+#define RAUX(name, hwregno, desc, gdbregno, mask, mode, version) { #name, hwregno, mask, mode },
+static const RegisterInfo aux[] =
+{
+ #include "arc-regnums-defs.h"
+};
+
+#undef RAUX
+#define RBCR(name, hwregno, desc, gdbregno, mask, mode, version) { #name, hwregno, mask, mode },
+static const RegisterInfo bcr[] =
+{
+ #include "arc-regnums-defs.h"
+};
+
+
+static Boolean test = TRUE;
+static Boolean memory_only = FALSE;
+static TargetOperations operations;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* global debug flag */
+Boolean arc_debug_target;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+static void failed(const char* fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "*** FAILED: ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+// exit(EXIT_FAILURE);
+}
+
+
+static void read_core_registers(void)
+{
+ ARC_RegisterNumber r;
+
+ for (r = 0; r < ARC_NR_CORE_REGS; r++)
+ {
+ ARC_RegisterContents contents;
+ JTAG_OperationStatus status = arc_jtag_ops.read_core_reg(r, &contents);
+
+ if (status == JTAG_SUCCESS)
+ printf("core register %02d: 0x%08X\n", r, contents);
+ else
+ failed("could not read core register %02d: %d", r, (int) status);
+ }
+}
+
+
+static void write_core_registers(void)
+{
+ ARC_RegisterNumber r;
+
+ for (r = 0; r < ARC_NR_CORE_REGS; r++)
+ {
+ ARC_RegisterContents contents = 0xDEADBEEF + r;
+ JTAG_OperationStatus status = arc_jtag_ops.write_core_reg(r, contents);
+
+ if (status == JTAG_SUCCESS)
+ {
+ ARC_RegisterContents new_contents;
+
+ status = arc_jtag_ops.read_core_reg(r, &new_contents);
+
+ if (status == JTAG_SUCCESS)
+ {
+ if (new_contents != contents)
+ failed("discrepancy in core register %02d contents: 0x%08X != 0x%08X", r, contents, new_contents);
+ }
+ else
+ failed("could not read back core register %02d: %d", r, (int) status);
+ }
+ else
+ failed("could not write core register %02d: %d", r, (int) status);
+ }
+}
+
+
+static void read_auxiliary_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(aux); i++)
+ {
+ const RegisterInfo* info = &aux[i];
+
+ if (info->mode != WO)
+ {
+ ARC_RegisterContents contents;
+ JTAG_OperationStatus status = arc_jtag_ops.read_aux_reg(info->regno, &contents);
+
+ if (status == JTAG_SUCCESS)
+ printf("aux register 0x%03x (%-15s): 0x%08X\n", info->regno, info->name, contents);
+ else
+ failed("could not read aux register 0x%03x (%s): %d", info->regno, info->name, (int) status);
+ }
+ }
+}
+
+
+static void write_auxiliary_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(aux); i++)
+ {
+ const RegisterInfo* info = &aux[i];
+
+ if (info->mode != RO)
+ {
+ ARC_RegisterContents contents = 0xFFFFFFFF;
+ JTAG_OperationStatus status = arc_jtag_ops.write_aux_reg(info->regno, contents);
+
+ if (status == JTAG_SUCCESS)
+ {
+ if (info->mode != WO)
+ {
+ ARC_RegisterContents new_contents;
+
+ status = arc_jtag_ops.read_aux_reg(info->regno, &new_contents);
+
+ if (status == JTAG_SUCCESS)
+ {
+ ARC_RegisterContents masked_contents = contents & info->mask;
+ ARC_RegisterContents masked_new_contents = new_contents & info->mask;
+
+ if (masked_new_contents != masked_contents)
+ failed("discrepancy in aux register %03x (%s) contents: 0x%08X != 0x%08X",
+ info->regno, info->name, masked_contents, masked_new_contents);
+ }
+ else
+ failed("could not read back aux register 0x%03x (%s): %d", info->regno, info->name, (int) status);
+ }
+ }
+ else
+ failed("could not write aux register 0x%03x (%s): %d", info->regno, info->name, (int) status);
+ }
+ }
+}
+
+
+static void read_build_configuration_registers(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(bcr); i++)
+ {
+ const RegisterInfo* info = &bcr[i];
+
+ /* if the register is not unused */
+ if (info->mode != UU)
+ {
+ ARC_RegisterContents contents;
+ JTAG_OperationStatus status = arc_jtag_ops.read_aux_reg(info->regno, &contents);
+
+ if (status == JTAG_SUCCESS)
+ printf("BCR 0x%02x (%-16s): 0x%08X\n", info->regno, info->name, contents);
+ else
+ failed("could not read BCR 0x%02x (%s): %d", info->regno, info->name, (int) status);
+ }
+ }
+}
+
+
+/* these functions should NOT be used within this module: they are intended
+ * purely for use by the arc-memory module for reading/writing multiple words
+ * of data at word-aligned addresses
+ */
+
+static unsigned int read_jtag_words(ARC_Address address,
+ ARC_Byte* data,
+ unsigned int words)
+{
+ DEBUG("reading %u words from 0x%08X in xISS\n", words, address);
+
+ assert(IS_WORD_ALIGNED(address));
+
+ return arc_jtag_ops.memory_read_chunk(address, data, words);
+}
+
+
+static unsigned int write_jtag_words(ARC_Address address,
+ ARC_Byte* data,
+ unsigned int words)
+{
+ assert(IS_WORD_ALIGNED(address));
+
+ DEBUG("writing %u words to 0x%08X in xISS\n", words, address);
+
+ return arc_jtag_ops.memory_write_chunk(address, data, words);
+}
+
+
+static unsigned int write_jtag_pattern(ARC_Address address,
+ ARC_Word pattern,
+ unsigned int words)
+{
+ assert(IS_WORD_ALIGNED(address));
+
+ DEBUG("writing pattern 0x%08X repeated %u times to 0x%08X in xISS\n", pattern, words, address);
+
+ return arc_jtag_ops.memory_write_pattern(address, pattern, words);
+}
+
+
+/* these functions should be used within this module for all memory accesses */
+static unsigned int read_chunk(ARC_Address addr, ARC_Byte* data, unsigned int bytes)
+{
+ unsigned int total_read;
+
+ ENTERARGS("addr 0x%08X, bytes %u", addr, bytes);
+
+ total_read = arc_read_memory(&operations, addr, data, bytes);
+
+ DEBUG("read %u bytes\n", total_read);
+
+ return total_read;
+}
+
+
+static unsigned int write_chunk(ARC_Address addr, ARC_Byte* data, unsigned int bytes)
+{
+ unsigned int total_written;
+
+ ENTERARGS("addr 0x%08X, bytes %u", addr, bytes);
+
+ total_written = arc_write_memory(&operations, addr, data, bytes);
+
+ DEBUG("written %u bytes\n", total_written);
+
+ return total_written;
+}
+
+
+/* write a repeated pattern of data to memory;
+ * the start of each pattern is always word-aligned, so if the given address is
+ * not word-aligned, the first partial word written will contain trailing bytes
+ * of the pattern
+ */
+static unsigned int write_pattern(ARC_Address addr, ARC_Word pattern, unsigned int bytes)
+{
+ unsigned int total_written;
+
+ ENTERARGS("addr 0x%08X, pattern 0x%08X, bytes %u", addr, pattern, bytes);
+
+ total_written = arc_write_pattern(&operations, addr, pattern, bytes);
+
+ DEBUG("written %u bytes\n", total_written);
+
+ return total_written;
+}
+
+
+/* test word read/write operations - write several words to different
+ * addresses to ensure that JTAG Data Register does not still hold first
+ * word; use both contiguous and non-contiguous words to check that
+ * JTAG Address Register is loaded correctly
+ */
+static void read_write_memory_words(void)
+{
+ const ARC_Word write1 = 0xCAFEBABE;
+ const ARC_Word write2 = 0xDEADBEEF;
+ const ARC_Word write3 = 0xBABEFACE;
+ const ARC_Word write4 = 0x12345678;
+ ARC_Word read1 = 0;
+ ARC_Word read2 = 0;
+ ARC_Word read3 = 0;
+ ARC_Word read4 = 0;
+ unsigned int bytes;
+
+ bytes = arc_jtag_ops.memory_write_word(DATA_AREA, write1);
+ if (bytes != 4)
+ failed("memory word 1 write: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_write_word(DATA_AREA + 4, write2);
+ if (bytes != 4)
+ failed("memory word 2 write: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_write_word(DATA_AREA + 8, write3);
+ if (bytes != 4)
+ failed("memory word 3 write: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_write_word(DATA_AREA + 20, write4);
+ if (bytes != 4)
+ failed("memory word 4 write: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_read_word(DATA_AREA, &read1);
+ if (bytes != 4)
+ failed("memory word 1 read: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_read_word(DATA_AREA + 4, &read2);
+ if (bytes != 4)
+ failed("memory word 2 read: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_read_word(DATA_AREA + 8, &read3);
+ if (bytes != 4)
+ failed("memory word 3 read: %d", bytes);
+
+ bytes = arc_jtag_ops.memory_read_word(DATA_AREA + 20, &read4);
+ if (bytes != 4)
+ failed("memory word 4 read: %d", bytes);
+
+ if (read1 != write1)
+ failed("word 1: %08X != %08X", read1, write1);
+
+ if (read2 != write2)
+ failed("word 2: %08X != %08X", read2, write2);
+
+ if (read3 != write3)
+ failed("word 3: %08X != %08X", read3, write3);
+
+ if (read3 != write3)
+ failed("word 3: %08X != %08X", read3, write3);
+
+ if (read4 != write4)
+ failed("word 4: %08X != %08X", read4, write4);
+}
+
+
+/* test chunk read/write operations */
+static void read_write_memory_chunks(void)
+{
+ ARC_Byte in [BUFFER_LENGTH];
+ ARC_Byte out[BUFFER_LENGTH];
+ unsigned int bytes;
+ unsigned int i;
+ unsigned int offset;
+
+ /* initialize output buffer to 7 bit values */
+ for (i = 0; i < BUFFER_LENGTH; i++)
+ out[i] = (ARC_Byte) i;
+
+ /* ----------------------------------------------------------- */
+ /* initialize data area */
+ /* ----------------------------------------------------------- */
+
+ /* write series of complete words */
+
+ bytes = write_chunk(DATA_AREA, out, BUFFER_LENGTH);
+ if (bytes != BUFFER_LENGTH)
+ failed("memory chunk write: %d", bytes);
+
+ /* and read them back */
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (bytes != BUFFER_LENGTH)
+ failed("memory chunk read: %d", bytes);
+
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk read/write:");
+
+
+ /* ----------------------------------------------------------- */
+ /* read operations */
+ /* ----------------------------------------------------------- */
+
+ /* 0) read single word */
+
+ bytes = read_chunk(DATA_AREA, in, 4);
+ if (bytes != 4)
+ failed("memory chunk read word: %d", bytes);
+
+ if (memcmp(in, out, 4) != 0)
+ failed("memory chunk read word");
+
+ /* 1) read leading bytes */
+
+ for (i = 1; i <= 3; i++)
+ {
+ bytes = read_chunk(DATA_AREA + 4 - i, in, i);
+ if (bytes != i)
+ failed("memory chunk read leading bytes: %d", bytes);
+
+ if (memcmp(in, out + 4 - i, i) != 0)
+ failed("memory chunk read leading bytes");
+ }
+
+ /* 2) read trailing bytes */
+
+ for (i = 1; i <= 3; i++)
+ {
+ bytes = read_chunk(DATA_AREA, in, i);
+ if (bytes != i)
+ failed("memory chunk read trailing bytes: %d", bytes);
+
+ if (memcmp(in, out, i) != 0)
+ failed("memory chunk read trailing bytes");
+ }
+
+ /* 3) read leading bytes and series of complete words */
+
+ bytes = read_chunk(DATA_AREA + 1, in, 11);
+ if (bytes != 11)
+ failed("memory chunk read leading bytes and words: %d", bytes);
+
+ if (memcmp(in, out + 1, 11) != 0)
+ failed("memory chunk read leading bytes and words");
+
+ /* 4) read series of complete words and trailing bytes */
+
+ bytes = read_chunk(DATA_AREA, in, 11);
+ if (bytes != 11)
+ failed("memory chunk read words and trailing bytes: %d", bytes);
+
+ if (memcmp(in, out, 11) != 0)
+ failed("memory chunk read words and trailing bytes");
+
+ /* 5) read leading bytes and trailing bytes */
+
+ bytes = read_chunk(DATA_AREA + 1, in, 5);
+ if (bytes != 5)
+ failed("memory chunk read leading and trailing bytes: %d", bytes);
+
+ if (memcmp(in, out + 1, 5) != 0)
+ failed("memory chunk read leading and trailing bytes");
+
+ /* 6) read leading bytes, series of complete words and trailing bytes */
+
+ bytes = read_chunk(DATA_AREA + 2, in, 23);
+ if (bytes != 23)
+ failed("memory chunk read leading bytes, words and trailing bytes: %d", bytes);
+
+ if (memcmp(in, out + 2, 23) != 0)
+ failed("memory chunk read leading bytes, words and trailing bytes");
+
+ /* 7) pathological cases: bytes in middle of word */
+
+ bytes = read_chunk(DATA_AREA + 1, in, 1);
+ if (bytes != 1)
+ failed("memory chunk read bytes in middle (1) : %d", bytes);
+
+ if (memcmp(in, out + 1, 1) != 0)
+ failed("memory chunk read middle bytes (1)");
+
+ bytes = read_chunk(DATA_AREA + 2, in, 2);
+ if (bytes != 2)
+ failed("memory chunk read bytes in middle (2) : %d", bytes);
+
+ if (memcmp(in, out + 2, 2) != 0)
+ failed("memory chunk read middle bytes (2)");
+
+ bytes = read_chunk(DATA_AREA + 3, in, 1);
+ if (bytes != 1)
+ failed("memory chunk read bytes in middle (3) : %d", bytes);
+
+ if (memcmp(in, out + 3, 1) != 0)
+ failed("memory chunk read middle bytes (3)");
+
+
+ /* ----------------------------------------------------------- */
+ /* write operations */
+ /* ----------------------------------------------------------- */
+
+ /* on each test, read back the whole area: we must check that no other data
+ * in the area has been changed, hence the use of 8-bit values on the write
+ * to distinguish them from the 7-bit values used to initialise the area;
+ * also, a different section of the area is used for each test
+ */
+
+ /* 0) write single word */
+
+ out[0] = 45;
+ out[1] = 89;
+ out[2] = 66;
+ out[3] = 53;
+
+ bytes = write_chunk(DATA_AREA, out, 4);
+ if (bytes != 4)
+ failed("memory chunk write word: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, 4);
+ if (memcmp(in, out, 4) != 0)
+ failed("memory chunk write word");
+
+ /* 1) write leading bytes */
+
+ for (i = 1; i <= 3; i++)
+ {
+ offset = 8 - i;
+
+ /* change data in output buffer to 8-bit values */
+ *(out + offset) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, i);
+ if (bytes != i)
+ failed("memory chunk write leading bytes: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write leading bytes");
+ }
+
+ /* 2) write trailing bytes */
+
+ offset = 8;
+
+ for (i = 1; i <= 3; i++)
+ {
+ /* change data in output buffer to 8-bit values */
+ *(out + offset + i - 1) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, i);
+ if (bytes != i)
+ failed("memory chunk write trailing bytes: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write trailing bytes");
+ }
+
+ /* 3) write leading bytes and series of complete words */
+
+ offset = 13;
+
+ for (i = 0; i < 11; i++)
+ *(out + offset + i) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 11);
+ if (bytes != 11)
+ failed("memory chunk write leading bytes and words: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write leading bytes and words");
+
+ /* 4) write series of complete words and trailing bytes */
+
+ offset = 28;
+
+ for (i = 0; i < 11; i++)
+ *(out + offset + i) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 11);
+ if (bytes != 11)
+ failed("memory chunk write words and trailing bytes: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write words and trailing bytes");
+
+ /* 5) write leading bytes and trailing bytes */
+
+ offset = 40;
+
+ for (i = 0; i < 5; i++)
+ *(out + offset + i) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 5);
+ if (bytes != 5)
+ failed("memory chunk write leading and trailing bytes: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write leading and trailing bytes");
+
+ /* 6) write leading bytes, series of complete words and trailing bytes */
+
+ offset = 48;
+
+ for (i = 0; i < 23; i++)
+ *(out + offset + i) = 128 + i;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 23);
+ if (bytes != 23)
+ failed("memory chunk write leading bytes, words and trailing bytes: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write leading bytes, words and trailing bytes");
+
+ /* 7) pathological cases: bytes in middle of word */
+
+ offset = 85;
+ *(out + offset) = 128;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 1);
+ if (bytes != 1)
+ failed("memory chunk write bytes in middle (1) : %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write middle bytes (1)");
+
+ offset = 95;
+ *(out + offset) = 129;
+ *(out + offset + 1) = 130;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 2);
+ if (bytes != 2)
+ failed("memory chunk write bytes in middle (2) : %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write middle bytes (2)");
+
+ offset = 106;
+ *(out + offset) = 131;
+
+ bytes = write_chunk(DATA_AREA + offset, out + offset, 1);
+ if (bytes != 1)
+ failed("memory chunk write bytes in middle (3) : %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write middle bytes (3)");
+
+
+ /* ----------------------------------------------------------- */
+ /* write zeroes operation */
+ /* ----------------------------------------------------------- */
+
+ offset = 110;
+
+ for (i = 0; i < 15; i++)
+ *(out + offset + i) = 0;
+
+ bytes = write_pattern(DATA_AREA + offset, 0, 15);
+ if (bytes != 15)
+ failed("memory zero: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory zero");
+
+
+ /* ----------------------------------------------------------- */
+ /* write pattern operation */
+ /* ----------------------------------------------------------- */
+
+ offset = 38;
+
+ /* the pattern will be word-aligned */
+
+#ifdef TARGET_IS_BIG_ENDIAN
+ *(out + offset + 0) = 0xBE; // leading bytes
+ *(out + offset + 1) = 0xEF;
+
+ *(out + offset + 2) = 0xDE; // word 0
+ *(out + offset + 3) = 0xAD;
+ *(out + offset + 4) = 0xBE;
+ *(out + offset + 5) = 0xEF;
+
+ *(out + offset + 6) = 0xDE; // word 1
+ *(out + offset + 7) = 0xAD;
+ *(out + offset + 8) = 0xBE;
+ *(out + offset + 9) = 0xEF;
+
+ *(out + offset + 10) = 0xDE; // word 2
+ *(out + offset + 11) = 0xAD;
+ *(out + offset + 12) = 0xBE;
+ *(out + offset + 13) = 0xEF;
+
+ *(out + offset + 14) = 0xDE; // word 3
+ *(out + offset + 15) = 0xAD;
+ *(out + offset + 16) = 0xBE;
+ *(out + offset + 17) = 0xEF;
+
+ *(out + offset + 18) = 0xDE; // trailing bytes
+ *(out + offset + 19) = 0xAD;
+#else
+ *(out + offset + 0) = 0xAD; // leading bytes
+ *(out + offset + 1) = 0xDE;
+
+ *(out + offset + 5) = 0xDE; // word 0
+ *(out + offset + 4) = 0xAD;
+ *(out + offset + 3) = 0xBE;
+ *(out + offset + 2) = 0xEF;
+
+ *(out + offset + 9) = 0xDE; // word 1
+ *(out + offset + 8) = 0xAD;
+ *(out + offset + 7) = 0xBE;
+ *(out + offset + 6) = 0xEF;
+
+ *(out + offset + 13) = 0xDE; // word 2
+ *(out + offset + 12) = 0xAD;
+ *(out + offset + 11) = 0xBE;
+ *(out + offset + 10) = 0xEF;
+
+ *(out + offset + 17) = 0xDE; // word 3
+ *(out + offset + 16) = 0xAD;
+ *(out + offset + 15) = 0xBE;
+ *(out + offset + 14) = 0xEF;
+
+ *(out + offset + 18) = 0xEF; // trailing bytes
+ *(out + offset + 19) = 0xBE;
+#endif
+
+ bytes = write_pattern(DATA_AREA + offset, 0xDEADBEEF, 20);
+ if (bytes != 20)
+ failed("memory pattern: %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory pattern");
+
+ /* ----------------------------------------------------------- */
+ /* write repeated values operation */
+ /* ----------------------------------------------------------- */
+
+ /* initialize output buffer to the same value */
+ for (i = 0; i < BUFFER_LENGTH; i++)
+ out[i] = 0xA;
+
+ bytes = write_chunk(DATA_AREA, out, BUFFER_LENGTH);
+ if (bytes != BUFFER_LENGTH)
+ failed("memory chunk write repeated values : %d", bytes);
+
+ bytes = read_chunk(DATA_AREA, in, BUFFER_LENGTH);
+ if (memcmp(in, out, BUFFER_LENGTH) != 0)
+ failed("memory chunk write repeated values");
+}
+
+
+static void run_tests(void)
+{
+ if (!memory_only)
+ {
+ read_core_registers();
+ read_auxiliary_registers();
+ read_build_configuration_registers();
+
+ write_core_registers();
+ write_auxiliary_registers();
+ }
+
+ read_write_memory_words();
+ read_write_memory_chunks();
+}
+
+
+static void process_options(int argc, char** argv)
+{
+ int c;
+
+ while ((c = getopt (argc, argv, "mdcr:")) != -1)
+ {
+ switch (c)
+ {
+ case 'd':
+ arc_jtag_ops.state_machine_debug = TRUE;
+ break;
+ case 'r':
+ arc_jtag_ops.retry_count = atoi(optarg);
+ break;
+ case 'c':
+ test = FALSE;
+ break;
+ case 'm':
+ memory_only = TRUE;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [ -d ]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+extern void _initialize_arc_jtag_ops(void);
+
+
+int main(int argc, char** argv)
+{
+ Boolean opened;
+
+ printf("Starting test of ARC JTAG interface...\n");
+
+ _initialize_arc_jtag_ops();
+
+ process_options(argc, argv);
+
+ opened = arc_jtag_ops.open();
+
+ if (opened)
+ {
+ printf("ARC processor is connected\n");
+
+ if (test)
+ {
+ operations.read_core_register = NULL;
+ operations.write_core_register = NULL;
+ operations.read_auxiliary_register = NULL;
+ operations.write_auxiliary_register = NULL;
+ operations.read_memory = read_jtag_words;
+ operations.write_memory = write_jtag_words;
+ operations.fill_memory = write_jtag_pattern;
+
+ run_tests();
+ printf("resetting board...\n");
+ arc_jtag_ops.reset_board();
+ printf("board reset\n");
+ run_tests();
+ }
+
+ arc_jtag_ops.close();
+ }
+
+ printf("Finished test of ARC JTAG interface\n");
+
+ return 0;
+}
+
+/******************************************************************************/
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index f52607342f6..20cce290f7b 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1,5 +1,5 @@
# Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+# 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
# Free Software Foundation, Inc.
# This file is part of GDB.
@@ -141,6 +141,9 @@ READLINE_CFLAGS = @READLINE_CFLAGS@
# Where is expat? This will be empty if expat was not available.
LIBEXPAT = @LIBEXPAT@
+# Where are the ARC xISS header files?
+XISS_INCLUDES = @XISS_INCLUDES@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -364,7 +367,8 @@ INTERNAL_CFLAGS_BASE = \
$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
- $(INTL_CFLAGS) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+ $(INTL_CFLAGS) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS) \
+ $(XISS_INCLUDES)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
@@ -392,7 +396,7 @@ INSTALLED_LIBS=-lbfd -lreadline -lopcodes -liberty -ldecnumber \
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(TM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ \
$(LIBICONV) $(LIBEXPAT) \
- $(LIBIBERTY) $(WIN32LIBS)
+ $(LIBIBERTY) $(WIN32LIBS) -lz
CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS)
@@ -411,7 +415,8 @@ RUNTESTFLAGS=
# XML files to build in to GDB.
XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \
- $(srcdir)/features/library-list.dtd
+ $(srcdir)/features/library-list.dtd \
+ $(srcdir)/features/arc-registers.dtd
# This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX
# interface to the serial port. Hopefully if get ported to OS/2, VMS,
@@ -423,7 +428,7 @@ SER_HARDWIRE = @SER_HARDWIRE@
# The `remote' debugging target is supported for most architectures,
# but not all (e.g. 960)
-REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o
+REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o target-fileio.o
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
@@ -624,7 +629,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
solib.c solib-null.c source.c \
stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
symtab.c \
- target.c target-descriptions.c target-memory.c \
+ target.c target-descriptions.c target-fileio.c target-memory.c \
thread.c top.c tracepoint.c \
trad-frame.c \
tramp-frame.c \
@@ -647,6 +652,7 @@ aout_stabs_gnu_h = $(INCLUDE_DIR)/aout/stabs_gnu.h
getopt_h = $(INCLUDE_DIR)/getopt.h
floatformat_h = $(INCLUDE_DIR)/floatformat.h
bfd_h = $(BFD_DIR)/bfd.h
+bfd_in2_h = $(BFD_DIR)/bfd-in2.h
coff_sym_h = $(INCLUDE_DIR)/coff/sym.h
coff_symconst_h = $(INCLUDE_DIR)/coff/symconst.h
coff_ecoff_h = $(INCLUDE_DIR)/coff/ecoff.h
@@ -731,10 +737,25 @@ annotate_h = annotate.h $(symtab_h) $(gdbtypes_h)
arch_utils_h = arch-utils.h
arm_linux_tdep_h = arm-linux-tdep.h
arm_tdep_h = arm-tdep.h
+arc_board_h = arc-board.h
+arc_gpio_h = arc-gpio.h
arc_tdep_h = arc-tdep.h
arc_jtag_h = arc-jtag.h
+arc_xiss_h = arc-xiss.h
+arc_inst_tracing_h = arc-inst-tracing.h
+arc_memory_h = arc-memory.h
+arc_arguments_h = arc-arguments.h
+arc_elf32_tdep_h = arc-elf32-tdep.h
+arc_linux_tdep_h = arc-linux-tdep.h
arc_jtag_ops_h = arc-jtag-ops.h
-arc_regnums_defs_h = arc-regnums-defs.h
+arc_tm_linux_h = config/arc/tm-linux.h
+arc_tm_embed_h = config/arc/tm-embed.h
+arc_sim_registers_h = ../sim/arc/arc-sim-registers.h
+arc_jtag_actionpoints_h = arc-jtag-actionpoints.h
+arc_registers_h = arc-registers.h
+arc_remote_fileio_h = arc-remote-fileio.h
+arc_architecture_h = arc-architecture.h
+arc_support_h = arc-support.h
auxv_h = auxv.h
ax_gdb_h = ax-gdb.h
ax_h = ax.h $(doublest_h)
@@ -849,6 +870,8 @@ nto_tdep_h = nto-tdep.h $(solist_h) $(osabi_h) $(regset_h)
objc_lang_h = objc-lang.h
objfiles_h = objfiles.h $(gdb_obstack_h) $(symfile_h)
obsd_tdep_h = obsd-tdep.h
+opcodes_arc_dis_h = $(OPCODES_DIR)/arc-dis.h
+opcodes_arcompact_dis_h = $(OPCODES_DIR)/arcompact-dis.h
osabi_h = osabi.h
parser_defs_h = parser-defs.h $(doublest_h)
p_lang_h = p-lang.h
@@ -895,6 +918,7 @@ symfile_h = symfile.h $(symtab_h)
symtab_h = symtab.h
target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) $(vec_h)
target_descriptions_h = target-descriptions.h
+target_fileio_h = target-fileio.h
terminal_h = terminal.h
top_h = top.h
tracepoint_h = tracepoint.h
@@ -1535,8 +1559,11 @@ ALLDEPFILES = \
amd64obsd-nat.c amd64obsd-tdep.c \
amd64-linux-nat.c amd64-linux-tdep.c \
amd64-sol2-tdep.c \
- arc-tdep.c arc-linux-tdep.c arc-jtag.c \
- arc-jtag-ops.c arc-jtag.c \
+ arc-jtag-actionpoints.c arc-remote-fileio.c \
+ arc-tdep.c arc-linux-tdep.c arc-jtag.c arc-architecture.c \
+ arc-jtag-ops.c arc-jtag.c arc-registers.c arc-board.c \
+ arc-xiss.c arc-gpio.c arc-memory.c arc-arguments.c \
+ arc-inst-tracing.c \
arm-linux-nat.c arm-linux-tdep.c arm-tdep.c \
armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c \
avr-tdep.c \
@@ -1901,20 +1928,78 @@ arch-utils.o: arch-utils.c $(defs_h) $(arch_utils_h) $(buildsym_h) \
$(gdbcmd_h) $(inferior_h) $(gdb_string_h) $(regcache_h) \
$(gdb_assert_h) $(sim_regno_h) $(gdbcore_h) $(osabi_h) $(version_h) \
$(floatformat_h) $(target_descriptions_h)
-arc-jtag.o:arc-jtag.c $(arc_jtag_h) $(defs_h) $(gdbcore_h) \
- $(arc_regnums_defs_h) $(gdbcmd_h)
-arc-jtag-ops.o: arc-jtag-ops.c $(arc_jtag_ops_h) $(arc_tdep_h)
-arc-jtag-tdep.o:arc-jtag-tdep.c $(arc_tdep_h) $(arc_jtag_h) $(defs_h) \
- $(osabi_h) $(frame_h) $(regcache_h) $(gdb_assert_h) $(inferior_h) \
- $(arc_tdep_h) $(arc_jtag_h)
-arc-linux-tdep.o: arc-linux-tdep.c $(defs_h) $(osabi_h) $(frame_h) \
- $(regcache_h) $(gdb_assert_h) $(inferior_h) $(reggroups_h) \
- $(solib_svr4_h) $(symtab_h) $(objfiles_h) $(block_h) $(arc_tdep_h)
-arc-tdep.o: arc-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) $(inferior_h) \
- $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) $(dis_asm_h) $(regcache_h) \
- $(doublest_h) $(value_h) $(frame_unwind_h) $(frame_base_h) \
- $(trad_frame_h) $(arc_tdep_h) $(elf_bfd_h) $(elf_arc_h) \
- $(opcode_arc_h) $(gdb_assert_h) $(bfd_in2_h) $(observer_h)
+arc-architecture.o: arc-architecture.c \
+ $(arc_architecture_h) $(arc_registers_h) $(arch_utils_h) \
+ $(arc_elf32_tdep_h) $(arc_support_h) $(arc_tdep_h) $(bfd_in2_h) \
+ $(defs_h) $(gdbarch_h) $(gdb_events_h) $(objfiles_h) $(breakpoint_h) \
+ $(target_h) $(gdb_assert_h)
+ $(CC) -c $(INTERNAL_CFLAGS) -Wno-format-nonliteral $<
+arc-registers.o: arc-registers.c \
+ $(arc_architecture_h) $(arc_registers_h) $(arc_elf32_tdep_h) \
+ $(arc_sim_registers_h) $(arc_support_h) $(arc_tdep_h) \
+ $(arc_tm_embed_h) $(bfd_in2_h) $(defs_h) $(gdbarch_h) $(gdbcmd_h) \
+ $(inferior_h) $(objfiles_h) $(regcache_h) \
+ $(target_h) $(xml_support_h) $(breakpoint_h) $(gdb_assert_h)
+ $(CC) -c $(INTERNAL_CFLAGS) -Wno-format-nonliteral $<
+arc-board.o: arc-board.c $(arc_architecture_h) $(arc_registers_h) \
+ $(arc_board_h) $(arc_gpio_h) $(arc_jtag_h) $(arc_jtag_ops_h) \
+ $(arc_support_h) $(arc_tdep_h) $(bfd_in2_h) \
+ $(completer_h) $(defs_h) $(gdbarch_h) $(gdbcmd_h) $(objfiles_h)
+ $(CC) -c $(INTERNAL_CFLAGS) -Wno-format-nonliteral $<
+arc-gpio.o: arc-gpio.c \
+ $(arc_gpio_h) $(arc_support_h) $(defs_h)
+arc-jtag.o: arc-jtag.c \
+ $(arc_architecture_h) $(arc_registers_h) $(arc_board_h) \
+ $(arc_gpio_h) $(arc_jtag_actionpoints_h) $(arc_jtag_h) \
+ $(arc_jtag_ops_h) $(arc_elf32_tdep_h) $(arc_support_h) $(arc_tdep_h) \
+ $(arc_tm_embed_h) $(bfd_in2_h) $(breakpoint_h) $(defs_h) $(gdbarch_h) \
+ $(gdbcmd_h) $(inferior_h) $(libiberty_h) $(objfiles_h) $(target_h) \
+ $(gdb_assert_h)
+arc-arguments.o: arc-arguments.c $(arc_arguments_h) $(arc_support_h) \
+ $(arc_tdep_h) $(defs_h) $(objfiles_h) \
+ $(regcache_h) $(symtab_h) $(target_h)
+arc-memory.o: arc-memory.c \
+ $(arc_memory_h) $(arc_tdep_h) $(arc_support_h) $(defs_h)
+arc-inst-tracing.o: arc-inst-tracing.c \
+ $(arc_inst_tracing_h) $(arc_tdep_h) $(arc_support_h)
+arc-xiss.o: arc-xiss.c \
+ $(arc_architecture_h) $(arc_elf32_tdep_h) $(arc_registers_h) \
+ $(arc_support_h) $(arc_tdep_h) $(arc_tm_embed_h) $(arc_xiss_h) \
+ $(arc_inst_tracing_h) $(bfd_in2_h) $(breakpoint_h) $(defs_h) \
+ $(disasm_h) $(gdbarch_h) $(gdbcmd_h) $(inferior_h) $(libiberty_h) \
+ $(objfiles_h) $(completer_h) $(target_h) $(gdb_assert_h)
+arc-jtag-ops.o: arc-jtag-ops.c $(arc_gpio_h) $(arc_jtag_h) $(arc_jtag_ops_h) \
+ $(arc_support_h) $(defs_h) $(gdb_assert_h)
+arc-elf32-tdep.o:arc-elf32-tdep.c $(arc_architecture_h) $(arc_registers_h) \
+ $(arch_utils_h) $(arc_remote_fileio_h) $(arc_memory_h) \
+ $(arc_elf32_tdep_h) $(arc_support_h) $(arc_tdep_h) $(arc_tm_embed_h) \
+ $(arc_arguments_h) $(bfd_in2_h) $(defs_h) $(gdbarch_h) $(gdbcmd_h) \
+ $(gdb_events_h) $(inferior_h) $(objfiles_h) \
+ $(observer_h) $(exceptions_h) $(regcache_h) $(reggroups_h) \
+ $(gdbcore_h) $(breakpoint_h) $(target_h) $(gdb_assert_h)
+ $(CC) -c $(INTERNAL_CFLAGS) -Wno-format-nonliteral $<
+arc-linux-tdep.o: arc-linux-tdep.c $(arc_linux_tdep_h) $(arc_support_h) \
+ $(arc_tdep_h) $(arc_tm_linux_h) $(block_h) $(defs_h) $(dis_asm_h) \
+ $(gdbarch_h) $(inferior_h) $(opcode_arc_h) $(osabi_h) $(regcache_h) \
+ $(reggroups_h) $(regset_h) $(solib_svr4_h) $(gdb_assert_h)
+arc-tdep.o: arc-tdep.c $(arch_utils_h) $(arc_support_h) $(arc_tdep_h) \
+ $(arc_tm_linux_h) $(arc_tm_embed_h) \
+ $(block_h) $(defs_h) $(demangle_h) $(dictionary_h) $(dis_asm_h) \
+ $(dwarf2_frame_h) $(frame_h) $(frame_unwind_h) $(gdbcmd_h) \
+ $(gdbcore_h) $(inferior_h) $(language_h) \
+ $(objfiles_h) $(observer_h) $(opcode_arc_h) $(opcodes_arc_dis_h) \
+ $(opcodes_arcompact_dis_h) $(osabi_h) $(regcache_h) $(reggroups_h) \
+ $(trad_frame_h) $(gdb_assert_h)
+arc-jtag-actionpoints.o: arc-jtag-actionpoints.c $(arc_architecture_h) \
+ $(arc_registers_h) $(arc_jtag_actionpoints_h) $(arc_jtag_h) \
+ $(arc_jtag_ops_h) $(arc_support_h) $(arc_tdep_h) $(arc_elf32_tdep_h) \
+ $(bfd_in2_h) $(defs_h) $(gdbarch_h) $(gdb_assert_h) $(inferior_h) \
+ $(target_h) $(breakpoint_h)
+arc-remote-fileio.o: arc-remote-fileio.c \
+ $(arc_remote_fileio_h) $(arc_support_h) $(arc_tm_embed_h) \
+ $(block_h) $(defs_h) $(frame_h) $(target_h) \
+ $(gdb_fileio_h) $(symtab_h) $(target_fileio_h) $(exceptions_h)
+ $(CC) -c $(INTERNAL_CFLAGS) -Wno-format-nonliteral $<
arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
$(gdb_string_h) $(regcache_h) $(arm_tdep_h) $(gregset_h) \
$(target_h) $(linux_nat_h) $(gdb_proc_service_h) $(arm_linux_tdep_h) \
@@ -2645,8 +2730,8 @@ remote.o: remote.c $(defs_h) $(gdb_string_h) $(inferior_h) $(bfd_h) \
$(cli_decode_h) $(cli_setshow_h) $(memory_map_h) \
$(target_descriptions_h) $(gdb_fileio_h)
remote-fileio.o: remote-fileio.c $(defs_h) $(gdb_string_h) $(gdbcmd_h) \
- $(remote_h) $(gdb_fileio_h) $(gdb_wait_h) $(gdb_stat_h) \
- $(exceptions_h) $(remote_fileio_h)
+ $(remote_h) $(gdb_fileio_h) \
+ $(exceptions_h) $(remote_fileio_h) $(target_fileio_h)
remote-m32r-sdi.o: remote-m32r-sdi.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \
$(inferior_h) $(target_h) $(regcache_h) $(gdb_string_h) $(serial_h)
remote-mips.o: remote-mips.c $(defs_h) $(inferior_h) $(bfd_h) $(symfile_h) \
@@ -2898,6 +2983,9 @@ target-descriptions.o: target-descriptions.c $(defs_h) $(arch_utils_h) \
$(target_h) $(target_descriptions_h) $(vec_h) $(xml_tdesc_h) \
$(gdbcmd_h) $(gdb_assert_h) $(gdbtypes_h) $(reggroups_h) \
$(xml_support_h) $(gdb_obstack_h) $(hashtab_h)
+target-fileio.o: target-fileio.c $(defs_h) $(exceptions_h) $(gdbcmd_h) \
+ $(gdb_fileio_h) $(gdb_stat_h) $(gdb_string_h) $(gdb_wait_h) \
+ $(target_fileio_h)
target-memory.o: target-memory.c $(defs_h) $(vec_h) $(target_h) \
$(memory_map_h) $(gdb_assert_h)
thread.o: thread.c $(defs_h) $(symtab_h) $(frame_h) $(inferior_h) \
diff --git a/gdb/arc-architecture.c b/gdb/arc-architecture.c
new file mode 100755
index 00000000000..f520d6141f1
--- /dev/null
+++ b/gdb/arc-architecture.c
@@ -0,0 +1,502 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 handling the architectural version of */
+/* of the ARC target processor. */
+/* */
+/* Architectural Checks: */
+/* Checks upon architectural consistency are (currently) performed at */
+/* these points: */
+/* */
+/* 1) after connection to target */
+/* 2) after reading (non-default) XML file */
+/* 3) after blasting JTAG target FPGA */
+/* 4) after attaching to JTAG target */
+/* 5) after selecting executable file */
+/* 6) before downloading program to target */
+/* */
+/******************************************************************************/
+
+/* gdb header files. */
+#include "defs.h"
+#include "objfiles.h"
+#include "arch-utils.h"
+#include "gdb-events.h"
+#include "gdb_assert.h"
+
+/* ARC header files. */
+#include "arc-architecture.h"
+#include "arc-elf32-tdep.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef enum
+{
+ DEFAULT_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS,
+ DEFAULT_SIMULATOR_WITH_AUXILIARY_REGISTERS,
+ SELECTED_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS,
+ SELECTED_SIMULATOR_WITH_AUXILIARY_REGISTERS,
+ TARGET_WITH_NO_AUXILIARY_REGISTERS,
+ TARGET_WITH_AUXILIARY_REGISTERS,
+ EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS,
+ EXECUTABLE_WITH_AUXILIARY_REGISTERS,
+ DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS,
+ DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS,
+ SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS,
+ SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS,
+ TARGET_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS,
+ TARGET_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS,
+ NO_ERROR
+} Diagnostic;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+/* N.B. the messages MUST correspond to the values in the Diagnostic enumeration
+ type above, as a value of that type is used to index the array. */
+
+static const char *messages[] =
+{
+ "default simulator architecture is %s but auxiliary registers are not defined",
+ "default simulator architecture is %s but auxiliary registers are defined for %s",
+ "selected simulator architecture is %s but auxiliary registers are not defined",
+ "selected simulator architecture is %s but auxiliary registers are defined for %s",
+ "target architecture is %s but auxiliary registers are not defined",
+ "target architecture is %s but auxiliary registers are defined for %s",
+ "executable file %s is built for %s but auxiliary registers are not defined",
+ "executable file %s is built for %s but auxiliary registers are defined for %s",
+ "default simulator architecture is %s, executable file %s is built for %s but auxiliary registers are not defined",
+ "default simulator architecture is %s, executable file %s is built for %s and auxiliary registers are defined for %s",
+ "selected simulator is %s, executable file %s is built for %s but auxiliary registers are not defined",
+ "selected simulator is %s, executable file %s is built for %s and auxiliary registers are defined for %s",
+ "target architecture is %s, executable file %s is built for %s but auxiliary registers are not defined",
+ "target architecture is %s, executable file %s is built for %s and auxiliary registers are defined for %s"
+};
+
+
+/* This is the architecture of the current target. */
+static ARC_ProcessorVersion ARC_processor = NO_ARCHITECTURE;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Map the BFD architerctural type onto the ARC processor type. */
+
+static ARC_ProcessorVersion
+architecture (const bfd_arch_info_type *arch)
+{
+ switch (arch->mach)
+ {
+ case bfd_mach_arc_a5 : return A5;
+ case bfd_mach_arc_arc600: return ARC600;
+ case bfd_mach_arc_arc700: return ARC700;
+ default : return UNSUPPORTED_ARCHITECTURE;
+ }
+}
+
+
+/* This function performs the architectural consistency check.
+
+ Parameters:
+ target : the architectural version of the target
+ auxregs : the architectural version of the auxiliary registers
+ program : the architectural version of the executable program
+ is_builtin_simulator: TRUE if the target is the built-in simulator
+ is_default : TRUE if built-in simulator's version is the default
+ objfile_bfd : a pointer to the BFD for the object file
+
+ If the check fails, an appropriate warning message is output. */
+
+static void
+perform_check (ARC_ProcessorVersion target,
+ ARC_ProcessorVersion auxregs,
+ ARC_ProcessorVersion program,
+ Boolean is_builtin_simulator,
+ bfd_boolean is_default,
+ bfd *objfile_bfd)
+{
+ Diagnostic diagnostic = NO_ERROR;
+
+ /* If we do not yet have an object file (and hence we do not know the
+ program's architecture). */
+ if (program == NO_ARCHITECTURE)
+ {
+ if (target != auxregs)
+ {
+ if (is_builtin_simulator)
+ {
+ if (is_default)
+ {
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = DEFAULT_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = DEFAULT_SIMULATOR_WITH_AUXILIARY_REGISTERS;
+ }
+ else
+ {
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = SELECTED_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = SELECTED_SIMULATOR_WITH_AUXILIARY_REGISTERS;
+ }
+ }
+ else
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = TARGET_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = TARGET_WITH_AUXILIARY_REGISTERS;
+ }
+ }
+ else
+ {
+ if (program != target || program != auxregs)
+ {
+ if (is_builtin_simulator)
+ {
+ if (target == program)
+ {
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = EXECUTABLE_WITH_AUXILIARY_REGISTERS;
+ }
+ else
+ {
+ if (is_default)
+ {
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS;
+ }
+ else
+ {
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS;
+ }
+ }
+ }
+ else
+ if (auxregs == NO_ARCHITECTURE)
+ diagnostic = TARGET_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS;
+ else
+ diagnostic = TARGET_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS;
+ }
+ }
+
+ if (diagnostic != NO_ERROR)
+ {
+ const char *message = messages[diagnostic];
+
+ switch (diagnostic)
+ {
+ case DEFAULT_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS:
+ case SELECTED_SIMULATOR_WITH_NO_AUXILIARY_REGISTERS:
+ case TARGET_WITH_NO_AUXILIARY_REGISTERS:
+ warning(message, arc_version_image(target));
+ break;
+
+ case DEFAULT_SIMULATOR_WITH_AUXILIARY_REGISTERS:
+ case SELECTED_SIMULATOR_WITH_AUXILIARY_REGISTERS:
+ case TARGET_WITH_AUXILIARY_REGISTERS:
+ warning(message, arc_version_image(target), arc_version_image(auxregs));
+ break;
+
+ case EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS:
+ warning(message, objfile_bfd->filename, arc_version_image(program));
+ break;
+
+ case EXECUTABLE_WITH_AUXILIARY_REGISTERS:
+ warning(message, objfile_bfd->filename, arc_version_image(program), arc_version_image(auxregs));
+ break;
+
+ case DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS:
+ case SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS:
+ case TARGET_AND_EXECUTABLE_WITH_NO_AUXILIARY_REGISTERS:
+ warning(message, arc_version_image(target), objfile_bfd->filename, arc_version_image(program));
+ break;
+
+ case DEFAULT_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS:
+ case SELECTED_SIMULATOR_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS:
+ case TARGET_AND_EXECUTABLE_WITH_AUXILIARY_REGISTERS:
+ warning(message, arc_version_image(target), objfile_bfd->filename, arc_version_image(program), arc_version_image(auxregs));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Set the architectural version of the target processor as being unknown. */
+
+void
+arc_architecture_is_unknown (void)
+{
+ ARC_processor = NO_ARCHITECTURE;
+}
+
+
+/* Return the processor variant that is connected. */
+
+ARC_ProcessorVersion
+arc_get_architecture (ReadRegisterFunction read_aux_register)
+{
+ ENTERMSG;
+
+ if (ARC_processor == NO_ARCHITECTURE)
+ {
+ ARC_RegisterNumber identity_regnum = arc_aux_find_register_number("IDENTITY", ARC_HW_IDENTITY_REGNUM);
+ ARC_RegisterContents value;
+
+ if (read_aux_register(identity_regnum, &value, TRUE))
+ {
+ DEBUG("IDENTITY = 0x%X\n", value);
+
+ /* Get the processor version number. */
+ value &= IDENTITY_ARCVER;
+
+ if ((value >= 0x30) && (value <= 0x3f))
+ ARC_processor = ARC700;
+ else if ((value >= 0x20) && (value <= 0x2f))
+ ARC_processor = ARC600;
+ else if ((value >= 0x10) && (value <= 0x1f))
+ ARC_processor = A5;
+ else if (value <= 0x0f)
+ ARC_processor = A4;
+ else
+ warning(_("unsupported processor version 0x%x"), value);
+
+ DEBUG("target (from IDENTITY) is %s\n", arc_version_image(ARC_processor));
+ }
+ }
+
+ return ARC_processor;
+}
+
+
+/* Get the target processor architecture, check that is it supported, and
+ * update any architecture-related information that gdb requires. */
+
+void
+arc_update_architecture (ReadRegisterFunction read_register)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ ARC_ProcessorVersion version = arc_get_architecture(read_register);
+
+ /* Record the target processor architecture in the targt-dependent
+ * variant information. */
+ tdep->processor_variant_info->processor_version = version;
+
+ switch (version)
+ {
+ case NO_ARCHITECTURE:
+ break;
+ case ARC700:
+ set_gdbarch_decr_pc_after_break (current_gdbarch, 0);
+ break;
+ case ARC600:
+ set_gdbarch_decr_pc_after_break (current_gdbarch, 2);
+ break;
+ case A5:
+ warning(_("A5 debugging is unsupported and may be unreliable."));
+ break;
+ case A4:
+ /* N.B. this will not return. */
+ error(_("A4 debugging is unsupported."));
+ break;
+ case UNSUPPORTED_ARCHITECTURE:
+ break;
+ }
+}
+
+
+/* This function checks for architectural consistency; there are three possible
+ architectures to be considered:
+
+ 1) the architecture for which the program to be debugged has been built
+ 2) the architecture of the target upon which the program is to be debugged
+ 3) the architecture for which we have a description of the auxiliary registers
+
+ The 'gdbarch' parameter to this function corresponds to 2).
+
+ A hardware target (such as an ARCangel) has a fixed architecture (e.g. that
+ defined by the XBF file used to configure it; and the xISS simulator's
+ architecture is defined by the simulator definition (.xis) file; however,
+ if the target is the built-in simulator, the architecture depends upon how
+ the simulator instance is created: if the instance is created by use of the
+ commands
+
+ file <program_file>
+ target sim
+
+ then the simulator architecture is taken from the program file; if it is
+ created by the commands
+
+ set endian big | little
+ set architecture <name>
+ target sim
+
+ then the architecture is the named one; if it is created by the commands
+
+ set endian big | little
+ target sim
+
+ the architecture is the default ARC architecture as defined in bfd/cpu-arc.c,
+ and this is indicated by the 'the_default' flag in the 'bfd_arch_info' struct
+ being TRUE. */
+
+void
+arc_check_architecture (struct gdbarch *gdbarch, bfd *objfile_bfd,
+ const char* file, const char* function)
+{
+ ARC_ProcessorVersion target = gdbarch_tdep (gdbarch)->processor_variant_info->processor_version;
+ ARC_ProcessorVersion auxregs = arc_aux_architecture(gdbarch);
+ ARC_ProcessorVersion program = NO_ARCHITECTURE;
+ bfd_boolean is_default = FALSE;
+ Boolean is_builtin_simulator = FALSE;
+
+ ENTERARGS("current target = %s (%sconnected), objfile = %s",
+ current_target.to_shortname,
+ (arc_target_is_connected) ? "" : "not ",
+ (objfile_bfd) ? bfd_get_filename(objfile_bfd) : "<none>");
+
+ DEBUG("architectural check in function '%s' in file '%s'\n", function, file);
+
+ /* If the target is the built-in simulator. */
+ if (strcmp(current_target.to_shortname, "sim") == 0)
+ {
+ const char *name = selected_architecture_name();
+ const bfd_arch_info_type *arch;
+
+ if (name)
+ arch = bfd_scan_arch(name);
+ else
+ arch = gdbarch_bfd_arch_info(gdbarch);
+
+ is_default = arch->the_default;
+ is_builtin_simulator = TRUE;
+ }
+
+ if (objfile_bfd)
+ program = architecture(objfile_bfd->arch_info);
+ else
+ program = NO_ARCHITECTURE;
+
+ DEBUG("target = %s\n", arc_version_image(target));
+ DEBUG("auxregs = %s\n", arc_version_image(auxregs));
+ DEBUG("program = %s\n", arc_version_image(program));
+
+ /* If we are connected to a target, we should know its architecture; if we
+ are not connected, if we don't know both the program and aux registers
+ architectures then there is no point in checking anything (this situation
+ could occur if a 'file <program>' or 'arc-reg-read-file <xmlfile>'
+ command has been issued before the connection is made). */
+ if (arc_target_is_connected)
+ gdb_assert(target != NO_ARCHITECTURE);
+ else
+ if (program == NO_ARCHITECTURE || auxregs == NO_ARCHITECTURE)
+ return;
+
+ /* Check that the architectures are the same. */
+ perform_check(target,
+ auxregs,
+ program,
+ is_builtin_simulator,
+ is_default,
+ objfile_bfd);
+
+ /* Unfortunately, this event can not be sent at the point that it is known
+ that the register architecture has changed, as at that point the global
+ variable current_gdbarch may have the value NULL, and that could cause
+ an error elsewhere where gdbarch_num_regs or gdbarch_num_pseudo_regs is
+ used (e.g. in setup_architecture_data in gdbtk/generic/gdbtk-register.c). */
+ if (arc_pending_register_architecture_change_event)
+ {
+ DEBUG("sending register architecture changed event\n");
+ arc_pending_register_architecture_change_event = FALSE;
+ reg_architecture_changed_event();
+ }
+}
+
+
+/* Get the ARC architectural version from a string. */
+
+ARC_ProcessorVersion
+arc_version (const char *arch)
+{
+ ARC_ProcessorVersion version;
+
+#define ARCH_IS(ident) (strcmp(arch, ident) == 0)
+
+ if (ARCH_IS("ARC700"))
+ version = ARC700;
+ else if (ARCH_IS("ARC600"))
+ version = ARC600;
+ else if (ARCH_IS("A5"))
+ version = A5;
+ else if (ARCH_IS("A4"))
+ version = A4;
+ else
+ version = UNSUPPORTED_ARCHITECTURE;
+
+ return version;
+}
+
+
+/* Return a string representation of the ARC architectural version. */
+
+const char*
+arc_version_image (ARC_ProcessorVersion version)
+{
+ switch (version)
+ {
+ case NO_ARCHITECTURE : return _("NONE");
+ case ARC700 : return _("ARC700");
+ case ARC600 : return _("ARC600");
+ case A5 : return _("A5");
+ case A4 : return _("A4");
+ case UNSUPPORTED_ARCHITECTURE: return _("UNSUPPORTED");
+ default : return _("???");
+ }
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-architecture.h b/gdb/arc-architecture.h
new file mode 100644
index 00000000000..f7a2751ecec
--- /dev/null
+++ b/gdb/arc-architecture.h
@@ -0,0 +1,74 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines an enumeration type for representing the */
+/* architectural version of an ARC processor, and associated functions. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_ARCHITECTURE_H
+#define ARC_ARCHITECTURE_H
+
+/* gdb header files */
+#include "defs.h"
+#include "gdbarch.h"
+#include "bfd/bfd-in2.h"
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+typedef enum arc_processor_version
+{
+ NO_ARCHITECTURE,
+ ARC700,
+ ARC600,
+ A5,
+ A4,
+ UNSUPPORTED_ARCHITECTURE
+} ARC_ProcessorVersion;
+
+
+#define ARCHITECTURE_CHECK(arch, bfd) arc_check_architecture (arch, bfd, __FILE__, __FUNCTION__)
+
+
+void arc_architecture_is_unknown (void);
+
+ARC_ProcessorVersion arc_get_architecture (ReadRegisterFunction read_aux_register);
+
+void arc_update_architecture (ReadRegisterFunction read_register);
+
+void arc_check_architecture (struct gdbarch *gdbarch, bfd *objfile_bfd,
+ const char* file, const char* function);
+
+ARC_ProcessorVersion arc_version (const char *arch);
+
+const char* arc_version_image (ARC_ProcessorVersion version);
+
+
+#endif /* ARC_ARCHITECTURE_H */
+/******************************************************************************/
diff --git a/gdb/arc-arguments.c b/gdb/arc-arguments.c
new file mode 100644
index 00000000000..bd3404a6986
--- /dev/null
+++ b/gdb/arc-arguments.c
@@ -0,0 +1,427 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 implements operations for setting up the command line */
+/* arguments to the program which is being debugged. */
+/* */
+/* E.g. if we are passing 4 arguments to the program's 'main' function, */
+/* we must place them on the stack in the layout: */
+/* */
+/* . */
+/* . */
+/* stack[top + A3] <== <arg_3> */
+/* . */
+/* . */
+/* stack[top + A2] <== <arg_2> */
+/* . */
+/* . */
+/* stack[top + A1] <== <arg_1> */
+/* . */
+/* . */
+/* stack[top + A0] <== <arg_0> */
+/* stack[top + 24] <== 0x0 # ? NULL terminator */
+/* stack[top + 20] <== 0x0 # envp NULL terminator */
+/* stack[top + 16] <== 0x0 # argv NULL terminator */
+/* stack[top + 12] <== TOP + A3 # argv[3] */
+/* stack[top + 8] <== TOP + A2 # argv[2] */
+/* stack[top + 4] <== TOP + A1 # argv[1] */
+/* stack[top + 0] <== TOP + A0 # argv[0] */
+/* */
+/* where TOP = &stack[top] */
+/* and A0 .. A3 are the offsets of the stored arguments from the stack */
+/* top. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <byteswap.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "target.h"
+#include "symtab.h"
+#include "regcache.h"
+#include "objfiles.h"
+
+/* ARC header files */
+#include "arc-arguments.h"
+#include "arc-support.h"
+#include "arc-tdep.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define MINIMUM_INSTRUCTION_SIZE 2
+#define MOV_SP_INSTRUCTION_LE 0x3F80240A
+#define MOV_SP_INSTRUCTION_BE 0x803F0A24
+
+
+/* The address of the top of the target program's stack before the program
+ arguments were pushed onto the stack. */
+static CORE_ADDR old_stack_top;
+
+/* The address in the target program code of the instructions which set up the
+ stack pointer (SP) at program start-up. */
+static CORE_ADDR stack_pointer_setup_code_operand_address;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define TARGET_IS_BIG_ENDIAN (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+
+#define TARGET_ENDIAN(word) ((TARGET_IS_BIG_ENDIAN) ? __bswap_32(word) : (word))
+
+#define MK_OPERAND_LE(x) (ARC_Word) ((((x) & 0xffff0000) >> 16) | \
+ (((x) & 0x0000ffff) << 16))
+
+#define MK_OPERAND_BE(x) (ARC_Word) (__bswap_32(x))
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Find the address in the target program code of the given label.
+ Return 0 if the label is not found. */
+
+static CORE_ADDR
+find_label (const char *label)
+{
+ struct minimal_symbol *msymbol = lookup_minimal_symbol(label, NULL, symfile_objfile);
+ CORE_ADDR address = 0;
+
+ if (msymbol != NULL)
+ address = SYMBOL_VALUE_ADDRESS (msymbol);
+
+ DEBUG("%s = %x\n", label, (unsigned int) address);
+
+ return address;
+}
+
+
+/* Write a word of data to target memory.
+
+ Parameters:
+ address : the address in memory to write the data
+ word : the data to be written
+
+ Returns TRUE if the data is written. FALSE otherwise.
+
+ If the data is written, the given address is incremented to reference the
+ next word in target memory. */
+
+static Boolean
+write_word (CORE_ADDR *address, ARC_Word word)
+{
+ word = TARGET_ENDIAN(word);
+
+ if (target_write_memory(*address, (gdb_byte*) &word, BYTES_IN_WORD) == 0)
+ {
+ *address += BYTES_IN_WORD;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Try to find the address in the target program code of the instructions which
+ set up the program stack pointer (SP).
+
+ Parameter:
+ stack_top: the address which is loaded into SP by the setup code
+
+ Return TRUE if the code is found.
+
+ If the setup code is found, the variable stack_pointer_setup_code_operand_address
+ is set to the code's address. */
+
+static Boolean
+find_stack_top_setup_code (CORE_ADDR stack_top)
+{
+ /* Try to find the start address in the target program. */
+ CORE_ADDR code_start = find_label("__start");
+
+ if (code_start != 0)
+ {
+ CORE_ADDR code = (ARC_Address) code_start;
+ ARC_Word set_sp_insn[2];
+ ARC_Byte buffer[16 * BYTES_IN_WORD];
+
+ DEBUG("setting up arguments: stack_top = %x, code_start = %x\n",
+ (unsigned int) stack_top, (unsigned int) code_start);
+
+ if (TARGET_IS_BIG_ENDIAN)
+ {
+ set_sp_insn[0] = MOV_SP_INSTRUCTION_BE;
+ set_sp_insn[1] = MK_OPERAND_BE(stack_top);
+ }
+ else
+ {
+ set_sp_insn[0] = MOV_SP_INSTRUCTION_LE;
+ set_sp_insn[1] = MK_OPERAND_LE(stack_top);
+ }
+
+ /* Scan through the start code of the program, looking for the code that
+ sets up the program's stack pointer; we recognize this as a 32-bit
+ 'mov sp' instruction followed by a 32-bit operand which is the
+ address of the stack top (which we obtained from the executable file). */
+ while (TRUE)
+ {
+ int result = target_read_memory(code, (gdb_byte*) buffer, (int) sizeof(buffer));
+
+ if (result == 0)
+ {
+ size_t offset = 0;
+
+ while (offset <= sizeof(buffer) - sizeof(set_sp_insn))
+ {
+ if (memcmp(buffer + offset, set_sp_insn, sizeof(set_sp_insn)) == 0)
+ {
+ stack_pointer_setup_code_operand_address = code + (CORE_ADDR) offset + BYTES_IN_WORD;
+
+ DEBUG("found 'mov sp, <stacktop>' instruction operand at address 0x%x\n",
+ (unsigned int) stack_pointer_setup_code_operand_address);
+ return TRUE;
+ }
+
+ offset += MINIMUM_INSTRUCTION_SIZE;
+ }
+ }
+ else
+ {
+ warning(_("can not find read target program start code"));
+ break;
+ }
+
+ code += (CORE_ADDR) (sizeof(buffer) - sizeof(set_sp_insn));
+
+ /* If we haven't found it in the first 100 bytes. */
+ if (code - code_start > 100)
+ {
+ warning(_("can not find 'mov sp, <stacktop>' instruction in start code"));
+ break;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+/* Try to change the setup code in the program so that SP is loaded with a
+ given address.
+
+ Parameters:
+ old_stack_top: the address which is currently loaded into SP by the code
+ new_stack_top: the address which we wish to be loaded into SP by the code
+
+ Return TRUE if the setup code is changed. */
+
+static Boolean
+set_stack_top (CORE_ADDR old_stack_top, CORE_ADDR new_stack_top)
+{
+ ARC_Word operand = (TARGET_IS_BIG_ENDIAN) ? MK_OPERAND_BE(new_stack_top)
+ : MK_OPERAND_LE(new_stack_top);
+
+ /* If we do not yet know the address in the program code at which the
+ program's stack pointer is set up. */
+ if (stack_pointer_setup_code_operand_address == 0)
+ {
+ /* Try to find it. */
+ if (!find_stack_top_setup_code(old_stack_top))
+ return FALSE;
+ }
+
+ DEBUG("set stack top @ 0x%08X to 0x%08X (0x%08X)\n",
+ (unsigned int) stack_pointer_setup_code_operand_address,
+ (unsigned int) new_stack_top,
+ operand);
+
+ return (target_write_memory(stack_pointer_setup_code_operand_address,
+ (gdb_byte*) &operand,
+ BYTES_IN_WORD) == 0);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* This is called when a program is downloaded to the debug target. */
+
+void
+arc_program_loaded (void)
+{
+ /* The program has just been loaded, so we do not yet know the address in
+ the program code at which the program's stack pointer is set up. */
+ stack_pointer_setup_code_operand_address = 0;
+}
+
+
+/* Store the program's arguments on the stack.
+ Return TRUE if they are stored successfully. */
+
+Boolean
+arc_setup_arguments (char *args)
+{
+ Boolean done = FALSE;
+
+ /* Try to find the top of stack in the target program. */
+ old_stack_top = find_label("__stack_top");
+
+ if (old_stack_top != 0)
+ {
+ char **argv = buildargv (args);
+ char **argp;
+ size_t string_length = 0;
+ unsigned int argc = 0;
+ unsigned int num_pointers;
+ unsigned int total_size;
+ CORE_ADDR new_stack_top;
+
+ if (argv == NULL)
+ nomem (0);
+
+ /* Calculate the space required to hold the args. */
+
+ for (argp = argv; *argp != NULL; argp++)
+ {
+ string_length += strlen (*argp) + 1;
+ argc++;
+ }
+
+ DEBUG("%d arguments\n", argc);
+
+ num_pointers = argc + 3;
+
+ total_size = (unsigned int) string_length + num_pointers * BYTES_IN_WORD;
+
+ /* Round up to a multiple of 32: strlen expects memory to come in chunks
+ * that are at least cache-line (32 bytes) sized. */
+ total_size += 31;
+ total_size &= -32;
+
+ DEBUG("total size: %d\n", total_size);
+
+ new_stack_top = old_stack_top - total_size;
+
+ DEBUG("new stack top: 0x%08x\n", (unsigned int) new_stack_top);
+
+ /* Adjust the setting of the top of the stack in the object code. */
+ if (set_stack_top(old_stack_top, new_stack_top))
+ {
+ struct regcache *regcache = get_current_regcache();
+ CORE_ADDR data_space = new_stack_top + num_pointers * BYTES_IN_WORD;
+ CORE_ADDR stack_top = new_stack_top;
+ unsigned int i;
+
+ DEBUG("data space: 0x%08x\n", (unsigned int) data_space);
+
+ done = TRUE;
+
+ /* Write the args onto the top of the stack. */
+
+ for (i = 0; i < argc; i++)
+ {
+ char *parameter = argv[i];
+ size_t length = strlen(parameter) + 1;
+ int result = target_write_memory(data_space, (gdb_byte*) parameter, (int) length);
+
+ if (result == 0)
+ {
+ DEBUG("written argv[%d] to 0x%08x: \"%s\"\n",
+ i, (unsigned int) data_space, parameter);
+ }
+ else
+ done = FALSE;
+
+ /* Write a pointer to the argument onto the stack. */
+ if (!write_word(&stack_top, (ARC_Word) data_space))
+ done = FALSE;
+
+ data_space += length;
+ }
+
+ /* Try to write the NULLs. */
+ if (!write_word(&stack_top, 0) ||
+ !write_word(&stack_top, 0) ||
+ !write_word(&stack_top, 0))
+ done = FALSE;
+
+ /* Set up the R0 and R1 parameter registers. */
+
+ /* Convert to target byte order if necessary. */
+ if (HOST_AND_TARGET_ENDIANNESS_DIFFER(current_gdbarch))
+ {
+ argc = __bswap_32(argc);
+ new_stack_top = __bswap_32(new_stack_top);
+ }
+
+ regcache_raw_supply (regcache, 0, &argc);
+ regcache_raw_supply (regcache, 1, &new_stack_top);
+ target_store_registers(regcache, 0);
+ target_store_registers(regcache, 1);
+ }
+
+ freeargv(argv);
+ }
+
+ return done;
+}
+
+
+/* This function is called just before disconnection from the debug target. */
+
+void
+arc_restore_stack_top_address (void)
+{
+ /* If we know the address in the program start-up code at which the stack
+ pointer is set up, it must be because we changed the stack top address
+ in the code - so change it back to the original address as read from the
+ excutable file.
+
+ This is done so that if the user disconnects from the target, then
+ reconnects to it in a subsequent debugging session but does NOT download
+ the program to the target again (as it is still in target memory), the
+ mechanism for altering the stack top will still work.
+
+ Note that this has no effect if the target is allowed to resume execution
+ (i.e. a 'detach' is being performed) as we are changing code that has
+ already been executed.
+
+ 0 is passed as the "old" stack top as it is not used in this situation. */
+
+ if (stack_pointer_setup_code_operand_address != 0)
+ (void) set_stack_top(0, old_stack_top);
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-arguments.h b/gdb/arc-arguments.h
new file mode 100644
index 00000000000..d0d79ed5214
--- /dev/null
+++ b/gdb/arc-arguments.h
@@ -0,0 +1,48 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines operations for setting up the command line */
+/* arguments to the program which is being debugged. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_ARGUMENTS
+#define ARC_ARGUMENTS
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+void arc_program_loaded (void);
+
+Boolean arc_setup_arguments (char *args);
+
+void arc_restore_stack_top_address (void);
+
+
+#endif /* ARC_ARGUMENTS */
+/******************************************************************************/
diff --git a/gdb/arc-board.c b/gdb/arc-board.c
new file mode 100644
index 00000000000..664222014b1
--- /dev/null
+++ b/gdb/arc-board.c
@@ -0,0 +1,1996 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Tim Gore
+ Tom Pennello <tom.pennello@arc.com>
+ Justin Wilde <justin.wilde@arc.com>
+ Phil Barnard <phil.barnard@arc.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 implements operations for controlling an ARC target board. */
+/* */
+/* These operations are: */
+/* 1) configuring ("blasting") an FPGA target with the contents of an */
+/* XBF file; */
+/* 2) checking whether a target has been so configured; */
+/* 3) setting the clock frequency of the target; */
+/* 4) setting the clock sources of the target. */
+/* */
+/* Notes: */
+/* The blast_board function implements an ARC-specific command; hence its */
+/* 'args' parameter contains data entered by the debugger user, which */
+/* must be checked for validity. */
+/* */
+/* Target Board: */
+/* It is assumed that the target board is actually an ARCangel 4 (AA4). */
+/* */
+/* See */
+/* ARCangel 4 Development System */
+/* User's Guide */
+/* 5801-001 */
+/* */
+/* for a full description of the target. */
+/* */
+/* The AA4 contains a Configurable Programmable Logic Device (CPLD) which */
+/* is used to control the system services on the board; this includes the */
+/* configuration of the board's PLL (Phase Lock Loop) clock chip, and */
+/* clock routing. */
+/* */
+/* The AA4 also has a 48 MHz crystal oscillator module, and has a number */
+/* of DIP switches which may be set manually: these may be used to select */
+/* a divisor (1, 2, 4 or 8) which may be applied to the crystal frequency */
+/* to obtain a lower frequency. */
+/* */
+/* The target FPGA has 4 global clock pins (GCLK0-3); a different clock */
+/* source may be routed to each of these by the CPLD. The available */
+/* sources are: */
+/* */
+/* crystal : the physical crystal */
+/* dips : the physical crystal divided by the DIP switch divisors */
+/* highimp : high impedance */
+/* host : use the STR (strobe) input of the host interface */
+/* mclk : use a clock provided by the PLL */
+/* vclk : use a clock provided by the PLL */
+/* */
+/* Note that "high impedance" (also referred to as "Tri-state") means, in */
+/* effect, that the clock is switched off. */
+/* */
+/* It is also possible to specify that the PLL clock should be a Harvard */
+/* clock generator. */
+/* */
+/* The main clock for the target's ARC processor is provided by GLCK3. */
+/* */
+/* The PLL is assumed to be a Cypress Semiconductor Corporation ICD2061A */
+/* Dual Programmable Graphics Clock Generator; the Data Sheet describing */
+/* this device may be readily found on the Web, and should be consulted */
+/* for an understanding of how the clock is programmed. */
+/* */
+/* The ICD2061A actually provides two independent clocks: MCLK (Memory or */
+/* I/O Timing Clock) and VCLK (Video Clock). It is recommended that the */
+/* frequency of one clock should not be an integer multiple of that of */
+/* other, in order to avoid clock signal degradation through jitter. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "completer.h"
+#include "objfiles.h"
+#include "gdbcmd.h"
+
+/* ARC header files */
+#include "arc-board.h"
+#include "arc-architecture.h"
+#include "arc-registers.h"
+#include "arc-gpio.h"
+#include "arc-jtag.h"
+#include "arc-jtag-ops.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef enum
+{
+ CLOCK_SOURCE_HIGH_IMPEDANCE,
+ CLOCK_SOURCE_PLL_MCLK,
+ CLOCK_SOURCE_PLL_VCLK,
+ CLOCK_SOURCE_CRYSTAL,
+ CLOCK_SOURCE_PLL_MCLK_HARVARD,
+ CLOCK_SOURCE_PLL_VCLK_HARVARD,
+ CLOCK_SOURCE_HOST_STROBE,
+ CLOCK_SOURCE_CRYSTAL_DIVIDED
+} ClockSource;
+
+typedef enum
+{
+ PLL_MCLK = 0,
+ PLL_VCLK = 1,
+ NO_PLL_CLK = 2
+} PLL_ClockId;
+
+typedef unsigned int GlobalClockId; // 0 .. 3
+
+typedef double MegaHertz;
+
+typedef struct global_clock
+{
+ ClockSource source;
+ Boolean set;
+ PLL_ClockId PLL_clock;
+} GlobalClock;
+
+typedef struct pll_clock
+{
+ MegaHertz requested_frequency;
+ MegaHertz actual_frequency;
+ Boolean in_use;
+} PLL_Clock;
+
+typedef struct pll_clock_info
+{
+ const char *name;
+ unsigned int PLL_register;
+ MegaHertz MIN_VCO_FREQ;
+ MegaHertz MAX_VCO_FREQ;
+} PLL_ClockInfo;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define ARC_SET_CLOCK_FREQUENCY_COMMAND "arc-set-clock-frequency"
+#define ARC_SET_CLOCK_SOURCE_COMMAND "arc-set-clock-source"
+#define ARC_CLOCK_SETTINGS_COMMAND "arc-clock-settings"
+#define ARC_BLAST_BOARD_COMMAND "arc-blast-board"
+#define ARC_FPGA_COMMAND "arc-fpga"
+
+#define ARC_SET_CLOCK_FREQUENCY_COMMAND_USAGE "Usage: " ARC_SET_CLOCK_FREQUENCY_COMMAND " [ <CLOCK> = ] <FREQUENCY> |\n" \
+ " " \
+ " <FREQUENCY> , <FREQUENCY>\n"
+
+#define ARC_SET_CLOCK_SOURCE_COMMAND_USAGE "Usage: " ARC_SET_CLOCK_SOURCE_COMMAND " gclk[N] = <SOURCE> |\n" \
+ " " \
+ " gclks = <SOURCE> { , <SOURCE> } |\n" \
+ " " \
+ " harvard\n"
+#define ARC_CLOCK_SETTINGS_COMMAND_USAGE "Usage: info " ARC_CLOCK_SETTINGS_COMMAND "\n"
+#define ARC_BLAST_BOARD_COMMAND_USAGE "Usage: " ARC_BLAST_BOARD_COMMAND " <FILE>\n"
+#define ARC_FPGA_COMMAND_USAGE "Usage: info " ARC_FPGA_COMMAND "\n"
+
+
+#define MAX_MAX_BURST 256
+
+#define S_XOR (Byte) 0x80 /* XOR value with this to get all bits positive. */
+#define C_XOR (Byte) 0x0b /* with respect to the signal values. */
+
+/* Control bits in the masks for the Control port. */
+#define STR (Byte) 0x01 // strobe
+#define CNT (Byte) 0x02
+#define SS0 (Byte) 0x04
+#define SS1 (Byte) 0x08
+#define BI (Byte) 0x20 // bi-directional?
+
+/* Control bits in the masks for the Status port. */
+#define OP (Byte) 0x20
+#define ACK (Byte) 0x40
+#define BUSY (Byte) 0x80
+
+/* Special meanings of some of those bits. */
+#define FPA_CFG_DONE OP
+#define CFG_FROM_ROM BUSY
+#define PAR_CFG_MODE ACK
+
+
+/* Constants for the PLL. */
+#define MREG_ADDRESS 3
+#define VCLK_SETUP_REG_NO 0 /* which of Reg0 .. Reg2 is used to set the VClock freq. */
+#define MCLK_RESET_FREQUENCY (MegaHertz) 25.0
+#define VCLK_RESET_FREQUENCY (MegaHertz) 25.0
+
+#define NUM_GLOBAL_CLOCKS 4
+#define NUM_PLL_CLOCKS 2
+
+#define UNDEFINED_FREQUENCY (MegaHertz) (-1.0)
+
+
+static const char *CLOCK_SOURCE_STRINGS[] =
+{
+ "High Impedance",
+ "PLL MCLK",
+ "PLL VCLK",
+ "Crystal",
+ "High Impedance",
+ "High Impedance",
+ "Host Strobe",
+ "Crystal With Division"
+};
+
+static const char *GCLOCK3_SOURCE_STRINGS[] =
+{
+ "High Impedance",
+ "PLL MCLK",
+ "PLL VCLK",
+ "Crystal",
+ "PLL MCLK (+Harvard)",
+ "PLL VCLK (+Harvard)",
+ "Host Strobe",
+ "Crystal With Division (+Harvard)"
+};
+
+
+static const ClockSource default_GCLK_sources[] =
+{
+ CLOCK_SOURCE_HIGH_IMPEDANCE, // GCLK0
+ CLOCK_SOURCE_CRYSTAL, // GCLK1
+ CLOCK_SOURCE_HOST_STROBE, // GCLK2
+ CLOCK_SOURCE_CRYSTAL_DIVIDED // GCLK3
+};
+
+
+static const MegaHertz VCO_PRESET_BOUNDARIES[] = {50.0, 51.0, 53.2, 58.5, 60.7, 64.4, 66.8,
+ 73.5, 75.6, 80.9, 83.2, 91.5, 100.0, 120.0};
+
+
+/* Unchanging information for the two PLL clocks. */
+static const PLL_ClockInfo PLL_clock_fixed_info[NUM_PLL_CLOCKS] =
+{
+ { "MCLK", MREG_ADDRESS, 52.0, 120.0 },
+ { "VCLK", VCLK_SETUP_REG_NO, 65.0, 165.0 }
+};
+
+
+/* Data describing the 2 PLL clocks and the 4 global clock sources. */
+static PLL_Clock PLL_clocks [NUM_PLL_CLOCKS];
+static GlobalClock global_clocks[NUM_GLOBAL_CLOCKS];
+static Boolean harvard;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define IS_SET(bit, byte) (((bit) & (byte)) == (bit))
+#define __MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define __MAX(X, Y) ((X) < (Y) ? (Y) : (X))
+
+#define FREQUENCY(clock) ((PLL_clocks[clock].in_use) ? PLL_clocks[clock].requested_frequency \
+ : UNDEFINED_FREQUENCY)
+
+#define PLL_CLOCK_NAME(clock) PLL_clock_fixed_info[clock].name
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Sleep for the given number of milliseconds. */
+
+static void
+Sleep (unsigned int milliseconds)
+{
+ usleep((unsigned long) (1000 * milliseconds));
+}
+
+
+/* Read a byte of data from the Status port. */
+
+static Byte
+read_status_port (void)
+{
+ return gpio_read(STATUS_PORT) ^ S_XOR;
+}
+
+
+/* Write a byte of data to the Control port, then sleep for the given delay. */
+
+static void
+write_control_port (Byte data, unsigned int delay)
+{
+ Byte value = data ^ C_XOR;
+
+ gpio_write(CONTROL_PORT, value);
+ Sleep(delay);
+}
+
+
+/* Write a byte of data to the Data port. */
+
+static void
+write_data_port (Byte value)
+{
+ gpio_write(DATA_PORT, value);
+}
+
+
+/* Extract the value from a string containing a name/value pair of the form
+
+ [ <name> = ] <value>
+
+ Return 0 if the string is not of the given form
+ 1 if the string is of the form <value>
+ 2 if the string is of the form <name> = <value>
+*/
+
+static int
+name_value_pair (char *args, char **value)
+{
+ char *equals = strchr(args, '=');
+
+ if (equals)
+ {
+ char *val = equals + 1;
+
+ /* If the key is missing from the argument string. */
+ if (equals == args)
+ return 0;
+
+ equals--;
+ while (*equals == ' ') equals--;
+ equals[1] = '\0';
+
+ while (*val == ' ') val++;
+ if (*val == '\0')
+ return 0;
+
+ *value = val;
+ return 2;
+ }
+
+ return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for FPGA blasting */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the FPGA ready for blasting.
+ Return TRUE if the initialization is successful. */
+
+static Boolean
+initialize_FPGA (void)
+{
+ Byte status;
+ Byte iOriginalState;
+ Byte iControlState;
+ unsigned int cpld_rev;
+
+ ENTERMSG;
+
+ /* snapshot the control port. */
+ iOriginalState = gpio_read(CONTROL_PORT);
+
+ /* Initialize FPGA by taking SS0 and SS1 low (all other ctrl's low as well). */
+ iControlState = iOriginalState & (0xFFFFFFFF ^ (SS0 | SS1 | CNT | STR | BI));
+ write_control_port(iControlState, 51);
+
+ /* Tri-state port outputs so we can read CPLD revision number. */
+ iControlState = iControlState | BI;
+ write_control_port(iControlState, 1);
+
+ // Read the CPLD revision number LSB. */
+ cpld_rev = (unsigned int) gpio_read(DATA_PORT);
+
+ /* Set CNT high and read CPLD revision number MSB. */
+ iControlState = iControlState | CNT;
+ write_control_port(iControlState, 1);
+
+ cpld_rev += (unsigned int) gpio_read(DATA_PORT) << 8;
+
+ /* Test the CPLD rev no; if it is 0xffff then this CPLD may not support
+ parallel blasting. */
+ if ((cpld_rev & 0xffff) == 0xffff)
+ {
+ warning(_("old board type (AA2), not supported"));
+ gpio_close();
+ return FALSE;
+ }
+ else
+ {
+ char rev_string[32];
+ unsigned int temp = cpld_rev;
+ unsigned int char_pos = 0;
+ unsigned int i;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (temp & 0x8000)
+ rev_string[char_pos++] = '1';
+ else
+ rev_string[char_pos++] = '0';
+
+ temp <<= 1;
+ if ((i % 4) == 3)
+ rev_string[char_pos++] = ' ';
+ }
+
+ rev_string[char_pos] = '\0';
+
+ printf_filtered(_("\nCPLD Revision = %20s\n"), rev_string);
+ }
+
+ /* Take CNT low. */
+ iControlState = iControlState & (0xFFFFFFFF ^ (SS0 | SS1 | CNT | STR | BI));
+
+ /* Now take STR high, CNT low and SS0 high to enter FPGA download mode. */
+ iControlState = iControlState | STR;
+ write_control_port(iControlState, 1);
+
+ iControlState = iControlState | SS0;
+ write_control_port(iControlState, 3);
+
+ /* Check that FPA_CFG_DONE=0. */
+ status = read_status_port();
+
+ if (IS_SET(FPA_CFG_DONE, status))
+ {
+ warning(_("FPGA is not responding - status = 0x%08x"), status);
+ gpio_close();
+ return FALSE;
+ }
+
+ LEAVEMSG;
+
+ return TRUE;
+}
+
+
+/* Try to send data to the target in a parallel stream.
+ Return TRUE if it is sent. */
+
+static Boolean
+parallel_send_data (Byte *buffer, unsigned int count)
+{
+ GPIO_Pair arr[MAX_MAX_BURST * 3 + 1];
+
+ /* Work out how many bytes we can send in one PIO program. */
+ unsigned const int bytes_per_burst = 127;
+
+ /* Initialize offsets into config data buffer. */
+ unsigned int burst_start = 0;
+ unsigned int burst_end = bytes_per_burst - 1;
+
+ /* Snapshot the control port. */
+ Byte iOriginalState = gpio_read(CONTROL_PORT);
+ Byte iControlState = (iOriginalState | SS0) & (0xFFFFFFFF ^ (SS1 | CNT | STR | BI));
+
+ while (TRUE)
+ {
+ GPIO_Pair *gpio = arr;
+ unsigned int i;
+
+ /* Do not try to write more data than is in the buffer. */
+ if (burst_end > (count - 1))
+ burst_end = count - 1;
+
+ /* Initialize the gpio driver instruction stream. */
+ for (i = burst_start; i <= burst_end; i++)
+ {
+ gpio->port = DATA_PORT;
+ gpio->data = buffer[i];
+ gpio++;
+ gpio->port = CONTROL_PORT;
+ gpio->data = iControlState ^ C_XOR;
+ gpio++;
+ gpio->port = CONTROL_PORT;
+ gpio->data = (iControlState | STR) ^ C_XOR;
+ gpio++;
+ }
+
+ gpio_write_array(arr, gpio - arr);
+
+ /* Last block of data written. */
+ if (burst_end == count - 1)
+ break;
+
+ burst_start = burst_end + 1;
+ burst_end = burst_start + bytes_per_burst - 1;
+ }
+
+ return TRUE;
+}
+
+
+/* Try to send data to the target in a serial stream.
+ Return TRUE if it is sent. */
+
+static Boolean
+serial_send_data (Byte *buff, unsigned int count)
+{
+ /* There is code which implements serial blasting in the SeeCode debugger
+ file os/arc/connect/par/arc/aa3blast.cpp, which is intended to work with
+ either Win95 or WinNT. If serial blasting is required for Linux, this
+ code would have to be re-written to use Linux O/S operations. However,
+ there is currently no requirement for that. */
+ warning(_("sorry, serial download is not supported"));
+ return FALSE;
+}
+
+
+
+/* Try to blast the target board FPGA with the contents of an XBF file.
+ Return TRUE if the blast is succcessful. */
+
+static Boolean
+blast_FPGA (FILE *xbf)
+{
+ Boolean parallel_cfg;
+ unsigned long file_size;
+ unsigned long five_percent;
+ unsigned long bytes_sent = 0;
+ unsigned long twentieths_complete = 0;
+ Byte status;
+
+ ENTERMSG;
+
+ /* Get parallel port status, and see whether the board is expecting parallel
+ or serial blast. */
+ status = read_status_port();
+
+ if ((status & CFG_FROM_ROM) == CFG_FROM_ROM)
+ {
+ /* Oops - FPGA is configured from ROM! */
+ if (IS_SET(FPA_CFG_DONE, status))
+ printf_filtered(_("FPGA is configured from ROM"));
+ else
+ warning(_("FPGA should be configured from ROM - BUT IT IS NOT!"));
+ return FALSE;
+ }
+
+ parallel_cfg = ((status & PAR_CFG_MODE) == PAR_CFG_MODE);
+
+ /* Find the length of the file (could use fstat instead here). */
+ (void) fseek(xbf, 0, SEEK_END);
+ file_size = (unsigned long) ftell(xbf);
+ (void) fseek(xbf, 0, SEEK_SET);
+
+ five_percent = file_size / 20;
+
+ /* Read file and blast. */
+
+ while (TRUE)
+ {
+ Byte data_buffer[1024];
+ size_t n_bytes = fread(data_buffer, 1, sizeof(data_buffer), xbf);
+
+ if (gpio_port_error)
+ error(_("Error in accessing JTAG port (device " GPIO_DEVICE ")"));
+
+ /* End of file reached? (fread returns 0 for both EOF and error!). */
+ if (n_bytes == 0)
+ {
+ if (!feof(xbf))
+ {
+ warning(_("error in reading XBF file"));
+ return FALSE;
+ }
+ break;
+ }
+
+ if (!(((parallel_cfg) ? parallel_send_data
+ : serial_send_data) (data_buffer, (unsigned int) n_bytes)))
+ break;
+
+ bytes_sent += n_bytes;
+ if (bytes_sent == file_size)
+ break;
+
+ if ((bytes_sent / five_percent) > twentieths_complete)
+ {
+ twentieths_complete++;
+ printf_filtered(_("*"));
+ gdb_flush (gdb_stdout);
+ }
+ }
+
+ printf_filtered(_("\n"));
+
+ /* Check for the ConfigDone signal. */
+ status = read_status_port();
+
+ if (!IS_SET(FPA_CFG_DONE, status))
+ {
+ warning(_("FPGA configuration failed"));
+ return FALSE;
+ }
+
+ printf_filtered(_("FPGA configured\n"));
+
+ /* Set SS0 and SS1 high to take board out of reset. */
+ {
+ Byte iControlState = (gpio_read(CONTROL_PORT) | SS0 | SS1 | STR) & (0xFFFFFFFF ^ (CNT | BI));
+
+ write_control_port(iControlState, 1);
+ }
+
+ LEAVEMSG;
+
+ return TRUE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for setting clocks */
+/* -------------------------------------------------------------------------- */
+
+/* Reset the clock configuration information to its default values (i.e. the
+ values that the h/w has after a hard reset of the target. */
+
+static void
+reset_clock_configuration (void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(PLL_clocks); i++)
+ {
+ PLL_clocks[i].requested_frequency = MCLK_RESET_FREQUENCY;
+ PLL_clocks[i].actual_frequency = VCLK_RESET_FREQUENCY;
+ PLL_clocks[i].in_use = FALSE;
+ }
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ {
+ global_clocks[i].source = default_GCLK_sources[i];
+ global_clocks[i].set = FALSE;
+ global_clocks[i].PLL_clock = NO_PLL_CLK;
+ }
+
+ harvard = FALSE;
+}
+
+
+/* Calculate the control word required to set a PLL clock to a particular frequency.
+
+ Parameters:
+ requested_frequency : the frequency we want
+ min_vco_frequency : the minimum VCO frequency for this clock
+ max_vco_frequency : the maximum VCO frequency for this clock
+ actual_frequency : the frequency we actually get
+
+ Result: the control word; 0 if no frequency can be set
+
+ The PLL consists of a VCO and 3 counters that divide by p, q and 2^d. The
+ VCO runs at 2*RefClk*p/q. This is divided by 2^d to give the PLL output.
+
+ There are several contraints on the various values:
+ 4 <= p <= 130
+ 3 <= q <= 129
+ 0 <= d <= 7
+ 0.2 <= ref_clk / q <= 1.0 (200kHz .. 1MHz)
+
+ This method is a bit of a palaver - very procedural. Basically it uses
+ trial and error to find the best values for d, p and q, within the given
+ contraints. */
+
+static unsigned int
+calculate_ctrl_word (const MegaHertz requested_frequency,
+ const MegaHertz min_vco_frequency,
+ const MegaHertz max_vco_frequency,
+ MegaHertz *actual_frequency)
+{
+ const unsigned int MIN_P = 4;
+ const unsigned int MAX_P = 130;
+ const unsigned int MIN_Q = 3;
+ const unsigned int MAX_Q = 129;
+ const unsigned int MIN_D = 0;
+ const unsigned int MAX_D = 7;
+ const MegaHertz MIN_REF_CLK_OVER_Q = 0.2;
+ const MegaHertz MAX_REF_CLK_OVER_Q = 1.0;
+ const MegaHertz REF_CLK = 14.31818; // input to PLL
+
+#define NUM_PRESETS ELEMENTS_IN_ARRAY(VCO_PRESET_BOUNDARIES)
+
+ unsigned int index, p = 0, q = 0, d = MIN_D; /* PLL parameters (see ICD2061A Data Sheet). */
+ unsigned int trial_p, trial_q; /* Temp vars for p & q values that we are trying out. */
+ unsigned int first_q, last_q;
+ unsigned int ctrl_word;
+ double min_delta = 1.0; /* Smallest error so far. */
+ MegaHertz vco_frequency = requested_frequency; /* Freq at which the VCO will run. */
+ double p_over_q;
+
+ /* Find a value of d which gives a VCO frequency that is within limits (VCO
+ output is divided by 2^d). */
+ while ((vco_frequency < min_vco_frequency) && (d < MAX_D))
+ {
+ vco_frequency *= 2;
+ d++;
+ }
+
+ DEBUG("request = %g, vco = %g, min = %g, max = %g, d = %d\n",
+ requested_frequency, vco_frequency, min_vco_frequency, max_vco_frequency, d);
+
+ /* Check that we have found a suitable value for d. */
+ if ((vco_frequency < min_vco_frequency) || (vco_frequency > max_vco_frequency))
+ {
+ DEBUG("frequency is out of range\n");
+ return 0;
+ }
+
+ /* Calculate the ratio needed for p/q, to get vco_frequency from ref_clk. */
+ p_over_q = vco_frequency / (2.0 * REF_CLK);
+
+ /* Now use some brute force and ignorance to find the best values for p & q:
+ we look for p & q such that p / q is the best approximation to p_over_q. */
+
+ /* Calculate range of values allowed for q. */
+ first_q = __MAX((unsigned int) (REF_CLK / MAX_REF_CLK_OVER_Q + 0.999999), MIN_Q);
+ last_q = __MIN((unsigned int) (REF_CLK / MIN_REF_CLK_OVER_Q), MAX_Q);
+
+ /* Look at each possible value of q. */
+ for (trial_q = first_q; trial_q <= last_q; trial_q++)
+ {
+ /* Calculate the value of p needed with this q value. */
+ double raw_p = p_over_q * (double) trial_q;
+ double delta;
+
+ /* Round the raw value for p to the nearest integer. */
+ trial_p = (unsigned int) (raw_p + 0.5);
+
+ /* Range check the required p value: note that because trial_q is
+ increasing, trial_p is also increasing, so if it is less than MIN_P
+ we may find a suitable value in a later iteration, whereas if it is
+ greater than MAX_P we will never find a suitable value in a later
+ iteration. */
+ if (trial_p < MIN_P)
+ continue;
+ if (trial_p > MAX_P)
+ break;
+
+ /* See how much error is caused by p being an integer. */
+ delta = fabs (1.0 - ((double) trial_p / raw_p));
+
+ /* If this is the most accurate so far, then keep track of it. */
+ if (delta < min_delta)
+ {
+ p = trial_p;
+ q = trial_q;
+
+ /* If it is exact then quit (we won't be able to find a better approximation!). */
+ if (min_delta == 0.0)
+ break;
+
+ min_delta = delta;
+ }
+ }
+
+ /* Just in case. */
+ if (p == 0)
+ {
+ DEBUG("loop failed to find p & q!");
+ return 0;
+ }
+
+ /* Have sorted out values for p, q & d - now form them into a control word. */
+
+ /* First, look up the value for Index (VCO preset). */
+ for (index = 0; index < NUM_PRESETS; index++)
+ {
+ if (VCO_PRESET_BOUNDARIES[index] > vco_frequency)
+ break;
+ }
+
+ // make sure we have found a suitable value for I
+ if ((index == 0) || (index == NUM_PRESETS))
+ {
+ DEBUG("can not find preset for %g\n", vco_frequency);
+ return 0;
+ }
+
+ /* The index must now be in the range 1 .. 13; so subtract 1, to change the
+ range to 0 .. 12 as required by the encoding. */
+ index--;
+
+ /* Return the frequency calculated as best approximation to the one requested. */
+ *actual_frequency = (2.0 * REF_CLK * p / q) / (1 << d);
+
+ DEBUG("p = %d, q = %d, d = %d, I = %d\n", p, q, d, index);
+
+ /* The ranges for p, q & d are:
+
+ I : 0 .. 12
+ p : 4 .. 130
+ d : 0 .. 7
+ q : 3 .. 129
+
+ Subtracting a bias of 3 from p and 2 from q converts these to:
+
+ I : 0 .. 12 which can be held in 4 bits
+ p : 1 .. 127 which can be held in 7 bits
+ d : 0 .. 7 which can be held in 3 bits
+ q : 1 .. 126 which can be held in 7 bits
+
+ which gives a control word with bitfields:
+
+ 00000000000IIIIPPPPPPPDDDQQQQQQQ
+
+ Note that 0 is not a valid value for the control word, which is why
+ it is safe to return 0 from this function in the error cases. */
+
+ ctrl_word = (index & 0xf);
+ ctrl_word = (ctrl_word << 7) | ((p - 3) & 0x7f);
+ ctrl_word = (ctrl_word << 3) | (d & 0x7);
+ ctrl_word = (ctrl_word << 7) | ((q - 2) & 0x7f);
+
+ return ctrl_word;
+}
+
+
+/* Write a control word to the PLL clock control register whose address is given.
+ Return TRUE if the write is successful. */
+
+static Boolean
+write_PLL_register (unsigned int address, unsigned int ctrl_word)
+{
+ const Byte S0S1_FINAL_STATE[] = {(Byte) 0x0, (Byte) 0x1, (Byte) 0x2};
+ const Byte PLL_CLK_BIT = (Byte) 0x08;
+ const Byte PLL_DATA_BIT = (Byte) 0x10;
+ unsigned int i;
+ Byte data;
+ Byte iControlState;
+ Byte iOriginalState;
+ int manchester_bitstream[64];
+
+ DEBUG("writing 0x%08X to PLL register %d\n", ctrl_word, address);
+
+ /* Add the address in the MSBs of the ctrl_word: this gives us a 24-bit value
+ with the fields AAAIIIIPPPPPPPDDDQQQQQQQ */
+
+ ctrl_word = ((address & 0x7) << 21) | (ctrl_word & 0x1fffff);
+
+ /* Create a bit stream at twice the data rate that incorporates the pseudo
+ Manchester encoding for the data and also the unlock sequence. */
+ for (i = 0; i < 11; i++)
+ manchester_bitstream[i] = 1;
+
+ /* The start bit. */
+ manchester_bitstream[11] = 0;
+ manchester_bitstream[12] = 0;
+ manchester_bitstream[13] = 0;
+
+ i = 14;
+ while (i < 62)
+ {
+ if ((ctrl_word & 0x1) == 0)
+ {
+ manchester_bitstream[i++] = 1;
+ manchester_bitstream[i++] = 0;
+ }
+ else
+ {
+ manchester_bitstream[i++] = 0;
+ manchester_bitstream[i++] = 1;
+ }
+
+ ctrl_word >>= 1;
+ }
+
+ /* The stop bit. */
+ manchester_bitstream[62] = 1;
+ manchester_bitstream[63] = 1;
+
+ /* Snapshot the control port state. */
+ iOriginalState = gpio_read(CONTROL_PORT);
+
+ /* Set the parallel port data to 0, in preparation for sending config data. */
+ write_data_port((Byte) 0);
+ Sleep(2);
+
+ /* Set CPLD into config mode. */
+
+ /* Set SS0=1, SS1=1, CNT=1, BIDir=0. */
+ iControlState = (iOriginalState | SS0 | SS1 | CNT | BI) ^ BI;
+ write_control_port(iControlState, 2);
+
+ /* Ensure STROBE is high. */
+ iControlState = iControlState | STR;
+ write_control_port(iControlState, 2);
+
+ /* Set CPLD into config mode by setting SS0=1, SS1=0, CNT=1. */
+ iControlState = iControlState ^ SS1;
+ write_control_port(iControlState, 2);
+
+ /* Now send the double rate data stream. */
+
+ // Set the clock high and data low. */
+ data = PLL_CLK_BIT & ~PLL_DATA_BIT;
+ write_data_port(data);
+ //Sleep(1);
+
+ for (i = 0; i < 64; i++)
+ {
+ /* Put the next Manchester code bit out. */
+ if (manchester_bitstream[i] == 1)
+ data = data | PLL_DATA_BIT;
+ else
+ data = data & ~PLL_DATA_BIT;
+
+ write_data_port(data);
+ //Sleep(1);
+
+ /* Toggle the clock bit. */
+ data = data ^ PLL_CLK_BIT;
+ write_data_port(data);
+ //Sleep(1);
+ }
+
+ /* Set data/clock (alias s1/s0) to select the programmed divisor register
+ for the video clock. */
+ write_data_port(S0S1_FINAL_STATE[VCLK_SETUP_REG_NO]);
+ //Sleep(1);
+
+ /* Set CPLD into ARC-Run Host-Read mode. */
+ iControlState = iControlState | SS1 | BI;
+ write_control_port(iControlState, 2);
+
+ return TRUE;
+}
+
+
+/* Configure the target board's CPLD. */
+
+static void
+configure_CPLD (void)
+{
+ const Byte CPLD_CLK_BIT = (Byte) 0x01;
+ const Byte CPLD_DATA_BIT = (Byte) 0x02;
+ const Byte CPLD_SET_BIT = (Byte) 0x04;
+ const unsigned int NUM_OF_CPLD_CFG_BITS = 16;
+ unsigned int cpldConfigData = 0;
+ Byte iControlState;
+ unsigned int i;
+
+ /* Snapshot the control port. */
+ Byte iOriginalState = gpio_read(CONTROL_PORT);
+
+ /* Set the parallel port data to 0, in preparation for sending config data. */
+ write_data_port((Byte) 0);
+ Sleep(1);
+
+ /* Set CPLD into configuration mode. */
+
+ /* Set SS0=1, SS1=1, CNT=1, BIDir=0. */
+ iControlState = (iOriginalState | SS0 | SS1 | CNT | BI) ^ BI;
+ write_control_port(iControlState, 2);
+
+ /* Ensure STROBE is high. */
+ iControlState = iControlState | STR;
+ write_control_port(iControlState, 2);
+
+ /* Set CPLD into config mode by setting SS0=1, SS1=0, CNT=1. */
+ iControlState = iControlState ^ SS1;
+ write_control_port(iControlState, 2);
+
+ /* Now send the config data stream with set low. */
+
+ /* Set clock high and data low. */
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ cpldConfigData += (unsigned int) global_clocks[i].source << (3 * i);
+
+ for (i = 0; i < NUM_OF_CPLD_CFG_BITS; i++)
+ {
+ Byte value;
+
+ /* See if the next cfg bit is 0 or 1. */
+ if ((cpldConfigData & 0x1) == 0x1)
+ value = CPLD_DATA_BIT;
+ else
+ value = (Byte) 0;
+
+ /* Put data bit out to parallel port. */
+ write_data_port(value);
+
+ /* And toggle the clock line. */
+ value |= CPLD_CLK_BIT;
+ write_data_port(value);
+
+ value &= ~CPLD_CLK_BIT;
+ write_data_port(value);
+
+ cpldConfigData >>= 1;
+ }
+
+ /* Now take the clock and set bits high. */
+ write_data_port(CPLD_CLK_BIT | CPLD_SET_BIT);
+
+ /* Finally, take the clock low. */
+ write_data_port(CPLD_SET_BIT);
+
+ /* And put the CPLD into ARC run mode, SS0=1, SS1= 1, CNT=x. */
+ iControlState = iControlState | SS1 | BI;
+ write_control_port(iControlState, 2);
+}
+
+
+/* Try to set the frequency of a PLL clock.
+
+ Parameters:
+ clock : the identity of the clock (MCLK or VCLK)
+ requested_frequency: the desired frequency fro the clock
+ inform : TRUE if a message should be output if the clock is set
+ emit_warning : TRUE if a warning should be output if the clock is not set
+
+ Returns TRUE if the clock is set.
+*/
+
+static Boolean
+set_PLL_clock_frequency (PLL_ClockId clock,
+ MegaHertz requested_frequency,
+ Boolean inform,
+ Boolean emit_warning)
+{
+ /* First need to work out the control words for the frequencies set. */
+ MegaHertz actual_frequency = UNDEFINED_FREQUENCY;
+ unsigned int ctrl_word = calculate_ctrl_word (requested_frequency,
+ PLL_clock_fixed_info[clock].MIN_VCO_FREQ,
+ PLL_clock_fixed_info[clock].MAX_VCO_FREQ,
+ &actual_frequency);
+ Boolean set;
+
+ DEBUG("set_PLL_clock_frequency: %s ctrl_word = %08X, freq = %.2lf MHz\n",
+ PLL_CLOCK_NAME(clock), ctrl_word, requested_frequency);
+
+ if (ctrl_word == 0)
+ {
+ if (emit_warning)
+ warning(_("it is not possible to set %s to %.2lf"),
+ PLL_CLOCK_NAME(clock), requested_frequency);
+ return FALSE;
+ }
+
+ DEBUG("set_PLL_clock_frequency: %s %.2lf, %.2lf, %.2lf\n",
+ PLL_CLOCK_NAME(clock),
+ requested_frequency,
+ actual_frequency,
+ PLL_clocks[clock].actual_frequency);
+
+ if (actual_frequency != PLL_clocks[clock].actual_frequency)
+ {
+ /* Set up the PLL chip. We program the MREG, the REG0/1/2 - whichever
+ is selected to control VCLK. */
+ set = write_PLL_register (PLL_clock_fixed_info[clock].PLL_register, ctrl_word);
+
+ if (set)
+ {
+ PLL_clocks[clock].requested_frequency = requested_frequency;
+ PLL_clocks[clock].actual_frequency = actual_frequency;
+ }
+ else
+ if (emit_warning)
+ warning(_("PLL programming failed"));
+ }
+ else
+ set = TRUE;
+
+ if (set && inform)
+ printf_filtered(_("PLL clock %s set to %.2lf MHz.\n"), PLL_CLOCK_NAME(clock), actual_frequency);
+
+ return set;
+}
+
+
+/* Check the frequencies of the two PLL clocks, and emit a warning if necessary.
+
+ The ICD2061A Data Sheet recommends that the two clocks should not be set to
+ frequencies such that one is an integer multiple of the other, in order to
+ avoid jitter. */
+
+static void
+check_PLL_clock_frequencies (void)
+{
+ DEBUG("check_PLL_clock_frequencies\n");
+
+ /* If both clocks are in use. */
+ if (PLL_clocks[PLL_MCLK].in_use && PLL_clocks[PLL_VCLK].in_use)
+ {
+ /* Check whether the two chosen clocks are divisible by one another, in
+ which case print a warning. */
+ double multiplier = PLL_clocks[PLL_VCLK].actual_frequency /
+ PLL_clocks[PLL_MCLK].actual_frequency;
+ double modulus;
+
+ if (multiplier < 1.00)
+ multiplier = 1 / multiplier;
+
+ modulus = multiplier - ((int) multiplier);
+
+ /* Check also for near multiples. */
+ if ((modulus < 0.02) || (modulus > 0.98))
+ warning(_("PLL MCLK and PLL VCLK frequencies are (near) multiples of each other.\n"
+ "This may lead to clock degradation."));
+ }
+ else if (PLL_clocks[PLL_MCLK].in_use || PLL_clocks[PLL_VCLK].in_use)
+ {
+ MegaHertz requested_frequency;
+ MegaHertz actual_frequency;
+ PLL_ClockId clock;
+
+ /* If we now are only using one PLL clock then ensure that the second
+ clock's frequency is not a multiple of the first's (M == V is OK). */
+ if (PLL_clocks[PLL_MCLK].in_use)
+ {
+ clock = PLL_VCLK;
+ actual_frequency = PLL_clocks[PLL_MCLK].actual_frequency;
+ }
+ else
+ {
+ clock = PLL_MCLK;
+ actual_frequency = PLL_clocks[PLL_VCLK].actual_frequency;
+ }
+
+ if (actual_frequency < VCO_PRESET_BOUNDARIES[0])
+ requested_frequency = actual_frequency * 1.43;
+ else
+ requested_frequency = actual_frequency;
+
+ if (!set_PLL_clock_frequency(clock, requested_frequency, TRUE, FALSE))
+ (void) set_PLL_clock_frequency(clock, actual_frequency, TRUE, TRUE);
+ }
+}
+
+
+/* Try to set the source of the given global clock to be a PLL clock set to the
+ given frequency.
+
+ If one of the PLL clocks is already set to the given frequency, we use that
+ as the source; otherwise, if the global clock's source is a PLL clock, and
+ no other global clock is using that PLL clock as its source, we change its
+ frequency to the required frequency; otherwise, if the other PLL clock is not
+ already in use, we set that other clock to the required frequency and use it
+ as the source; otherwise (both PLL clocks are in use), we find the clock
+ whose frequency is closest to the required frequency and use that clock as
+ the source. */
+
+static void
+use_PLL_clock (GlobalClockId clockId, MegaHertz clockValue)
+{
+ PLL_ClockId PLL_clock_id = NO_PLL_CLK;
+ PLL_ClockId free_PLL_clock_id = NO_PLL_CLK;
+ unsigned int i;
+
+ /* Is this global clock not already using a PLL clock? */
+ if (global_clocks[clockId].PLL_clock == NO_PLL_CLK)
+ {
+ /* Has this frequency already been assigned to a PLL clock? */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(PLL_clocks); i++)
+ {
+ PLL_Clock* clock = &PLL_clocks[i];
+
+ if (clock->in_use)
+ {
+ /* The actual frequency to which the clock is set may differ
+ slightly from the frequency that was requested - so check
+ both. */
+ if (clockValue == clock->requested_frequency ||
+ clockValue == clock->actual_frequency)
+ {
+ PLL_clock_id = (PLL_ClockId) i;
+ break;
+ }
+ }
+ else
+ {
+ /* Use MCLK (first in array) in preference to VCLK. */
+ if (free_PLL_clock_id == NO_PLL_CLK)
+ free_PLL_clock_id = (PLL_ClockId) i;
+ }
+ }
+ }
+ else
+ {
+ PLL_ClockId this_clock = global_clocks[clockId].PLL_clock;
+ int users = 0;
+
+ /* How many global clocks are using this PLL clock? */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ {
+ if (global_clocks[i].PLL_clock == this_clock)
+ users++;
+ }
+
+ if (users == 1)
+ {
+ /* Just this one - so we can change its frequency without affecting
+ any other global clocks. */
+ free_PLL_clock_id = this_clock;
+ }
+ else
+ {
+ /* Look at the other clock - if it is not already in use, we can use it. */
+ PLL_ClockId other_clock = (this_clock == PLL_MCLK) ? PLL_VCLK : PLL_MCLK;
+
+ if (!PLL_clocks[other_clock].in_use)
+ free_PLL_clock_id = other_clock;
+ }
+ }
+
+ /* Do we need another PLL clock? */
+ if (PLL_clock_id == NO_PLL_CLK)
+ {
+ /* If so, and there aren't any which are not in use. */
+ if (free_PLL_clock_id == NO_PLL_CLK)
+ {
+ MegaHertz M_delta = fabs(PLL_clocks[PLL_MCLK].actual_frequency - clockValue);
+ MegaHertz V_delta = fabs(PLL_clocks[PLL_VCLK].actual_frequency - clockValue);
+
+ /* Which clock has the closet frequency to what we want? */
+ PLL_clock_id = (M_delta <= V_delta) ? PLL_MCLK : PLL_VCLK;
+
+ warning(_("can not set GCLK%d to %.2lf MHz - "
+ "there are no more PLL clocks available.\n"
+ "Using closest match instead (%s @ %.2lf MHz)."),
+ clockId, clockValue,
+ PLL_CLOCK_NAME(PLL_clock_id),
+ PLL_clocks[PLL_clock_id].actual_frequency);
+ }
+ else
+ {
+ /* Otherwise, use a free PLL clock. */
+ PLL_clock_id = free_PLL_clock_id;
+
+ if (set_PLL_clock_frequency(PLL_clock_id, clockValue, TRUE, TRUE))
+ {
+ PLL_clocks[PLL_clock_id].in_use = TRUE;
+ check_PLL_clock_frequencies();
+ }
+ }
+ }
+
+ global_clocks[clockId].PLL_clock = PLL_clock_id;
+ global_clocks[clockId].source = (PLL_clock_id == PLL_MCLK) ? CLOCK_SOURCE_PLL_MCLK : CLOCK_SOURCE_PLL_VCLK;
+ global_clocks[clockId].set = TRUE;
+}
+
+
+/* Set the source of the given global clock as specified.
+ This may be one of: crystal, dips, highimp, host, mclk, vclk or <frequency>.
+ Specifying an explicit frequency means that the source should be a PLL clock
+ set to that frequency. */
+
+static void
+set_global_clock (GlobalClockId clockId, const char *clockData)
+{
+ static const struct table_entry
+ {
+ ClockSource source;
+ PLL_ClockId clock;
+ const char *name;
+ Boolean harvard;
+ } table[] =
+ { { CLOCK_SOURCE_CRYSTAL, NO_PLL_CLK, "crystal", FALSE },
+ { CLOCK_SOURCE_CRYSTAL_DIVIDED, NO_PLL_CLK, "dips", FALSE },
+ { CLOCK_SOURCE_HIGH_IMPEDANCE, NO_PLL_CLK, "highimp", FALSE },
+ { CLOCK_SOURCE_HOST_STROBE, NO_PLL_CLK, "host", FALSE },
+ { CLOCK_SOURCE_PLL_MCLK_HARVARD, PLL_MCLK, "mclk", TRUE },
+ { CLOCK_SOURCE_PLL_VCLK_HARVARD, PLL_MCLK, "vclk", TRUE },
+ { CLOCK_SOURCE_PLL_MCLK, PLL_MCLK, "mclk", FALSE },
+ { CLOCK_SOURCE_PLL_VCLK, PLL_VCLK, "vclk", FALSE } };
+
+ MegaHertz clockValue;
+ unsigned int i;
+
+ /* Look at each possible clock source in the table. */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(table); i++)
+ {
+ const struct table_entry *entry = &table[i];
+
+ if (strcasecmp(clockData, entry->name) == 0)
+ {
+ /* N.B. the order of the entries in the table is important! */
+ if (entry->harvard && !harvard)
+ continue;
+
+ global_clocks[clockId].source = entry->source;
+ global_clocks[clockId].PLL_clock = entry->clock;
+ global_clocks[clockId].set = TRUE;
+
+ /* N.B. "high impedance" effectively means "off". */
+ if ((clockId == 3) && (entry->source == CLOCK_SOURCE_HIGH_IMPEDANCE))
+ {
+ warning(_("GCLK3 must be valid in order for the ARC processor's debug interface to interact with the processor."));
+ }
+ else if ((clockId == 2) && (entry->source != CLOCK_SOURCE_HOST_STROBE))
+ {
+ warning(_("GCLK2 must be %s for the JTAG clock to be connected to the ARC processor's debug interface."),
+ CLOCK_SOURCE_STRINGS[CLOCK_SOURCE_HOST_STROBE]);
+ }
+
+ return;
+ }
+ }
+
+ /* We did not find a match in the table - so the given source may be a frequency. */
+ if (sscanf(clockData, "%lf", &clockValue) == 1)
+ {
+ if (clockId == 2)
+ {
+ warning(_("GCLK2 must be %s for the JTAG clock to be connected to the ARC processor's debug interface."),
+ CLOCK_SOURCE_STRINGS[CLOCK_SOURCE_HOST_STROBE]);
+ }
+
+ use_PLL_clock(clockId, clockValue);
+ }
+ else
+ warning(_("'%s' is not a valid source for clock %d\n"), clockData, clockId);
+}
+
+
+/* Enable Harvard clock to drive global clock GLK3. */
+
+static void
+enable_Harvard_clock (void)
+{
+ /* Does GCLK3 come from the PLL? */
+ if (global_clocks[3].PLL_clock != NO_PLL_CLK)
+ {
+ /* Save existing settings. */
+ const PLL_ClockId saved_clock[] = {global_clocks[0].PLL_clock,
+ global_clocks[1].PLL_clock,
+ global_clocks[2].PLL_clock,
+ global_clocks[3].PLL_clock};
+ const MegaHertz saved_value[] = {PLL_clocks[PLL_MCLK].actual_frequency,
+ PLL_clocks[PLL_VCLK].actual_frequency};
+ GlobalClockId clockId;
+
+ printf_filtered(_("Configuring clocks to drive Harvard Ctl_Clk.\n"));
+
+ reset_clock_configuration();
+ harvard = TRUE;
+
+ /* Now re-assign the Harvard inputs and double the requested frequency. */
+ use_PLL_clock(3, 2 * saved_value[saved_clock[3]]);
+
+ /* Now ensure GCLK3 is configured as a Harvard generator. */
+ if (saved_clock[3] == PLL_MCLK)
+ global_clocks[3].source = CLOCK_SOURCE_PLL_MCLK_HARVARD;
+ else
+ global_clocks[3].source = CLOCK_SOURCE_PLL_VCLK_HARVARD;
+
+ /* Re-assign any existing PLL clocks. */
+ for (clockId = 0; clockId < 3; clockId++)
+ {
+ if (saved_clock[clockId] != NO_PLL_CLK)
+ use_PLL_clock(saved_clock[clockId], saved_value[saved_clock[clockId]]);
+ }
+ }
+}
+
+
+/* Print out the settings of the PLL clocks and the global clock sources.
+
+ Parameters:
+ with_PLL_clocks : if TRUE, print the settings of the PLL clocks
+ with_global_only_if_using_PLL: if TRUE, print the sources of the global
+ clocks only if at least one of those sources
+ is a PLL clock
+ */
+
+static void
+print_clock_settings (Boolean with_PLL_clocks, Boolean with_global_only_if_using_PLL)
+{
+ Boolean with_global_clocks = TRUE;
+ unsigned int i;
+
+ if (with_global_only_if_using_PLL)
+ {
+ with_global_clocks = FALSE;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ {
+ if (global_clocks[i].PLL_clock != NO_PLL_CLK)
+ {
+ with_global_clocks = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (with_PLL_clocks)
+ {
+ printf_filtered(_("PLL clock %s : %.2lf MHz.\n"), PLL_CLOCK_NAME(PLL_MCLK), PLL_clocks[PLL_MCLK].actual_frequency);
+ printf_filtered(_("PLL clock %s : %.2lf MHz.\n"), PLL_CLOCK_NAME(PLL_VCLK), PLL_clocks[PLL_VCLK].actual_frequency);
+ }
+
+ if (with_global_clocks)
+ {
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ {
+ GlobalClock clock = global_clocks[i];
+ const char *format = "GCLK%d << %s @ %.2lf MHz\n";
+ const char *source;
+ MegaHertz value;
+
+ switch (clock.source)
+ {
+ case CLOCK_SOURCE_PLL_MCLK:
+ source = CLOCK_SOURCE_STRINGS[clock.source];
+ value = PLL_clocks[PLL_MCLK].actual_frequency;
+ break;
+
+ case CLOCK_SOURCE_PLL_VCLK:
+ source = CLOCK_SOURCE_STRINGS[clock.source];
+ value = PLL_clocks[PLL_VCLK].actual_frequency;
+ break;
+
+ case CLOCK_SOURCE_PLL_MCLK_HARVARD:
+ source = GCLOCK3_SOURCE_STRINGS[clock.source];
+ value = PLL_clocks[PLL_MCLK].actual_frequency / 2.0;
+ break;
+
+ case CLOCK_SOURCE_PLL_VCLK_HARVARD:
+ source = GCLOCK3_SOURCE_STRINGS[clock.source];
+ value = PLL_clocks[PLL_VCLK].actual_frequency / 2.0;
+ break;
+
+ default:
+ format = "GCLK%d << %s\n";
+ source = ((i == 3) ? GCLOCK3_SOURCE_STRINGS : CLOCK_SOURCE_STRINGS)[clock.source];
+ value = 0.0;
+ break;
+ }
+
+ printf_filtered(format, i, source, value);
+ }
+ }
+}
+
+
+/* Set the two PLL clocks to the given frequencies. */
+
+static void
+set_PLL_clocks (MegaHertz requested_MCLK_frequency,
+ MegaHertz requested_VCLK_frequency)
+{
+ DEBUG("set_PLL_clocks: MCLK = %.2lf MHz, VCLK = %.2lf MHz\n",
+ requested_MCLK_frequency, requested_VCLK_frequency);
+
+ /* Configure PLL clocks. */
+
+ if (requested_MCLK_frequency != UNDEFINED_FREQUENCY)
+ {
+ if (set_PLL_clock_frequency(PLL_MCLK, requested_MCLK_frequency, TRUE, TRUE))
+ PLL_clocks[PLL_MCLK].in_use = TRUE;
+ }
+
+ if (requested_VCLK_frequency != UNDEFINED_FREQUENCY)
+ {
+ if (set_PLL_clock_frequency(PLL_VCLK, requested_VCLK_frequency, TRUE, TRUE))
+ PLL_clocks[PLL_VCLK].in_use = TRUE;
+ }
+}
+
+
+/* Set the clock settings.
+
+ The PLL clocks are set only if this is being done after the target board
+ FPGA has been blasted.
+ If any of the global clock sources needs to be set, the target CPLD is
+ configured, and the given message is printed out. */
+
+static void
+program_clock_settings (const char *message, Boolean after_blast)
+{
+ unsigned int i;
+
+ /* If the FPGA has been blasted, configure the PLL clocks. */
+ if (after_blast)
+ set_PLL_clocks(FREQUENCY(PLL_MCLK), FREQUENCY(PLL_VCLK));
+
+ /* Do any of the global clocks need to be set? */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(global_clocks); i++)
+ {
+ if (global_clocks[i].set)
+ {
+ /* Print status message only if there is something to be done. */
+ printf_filtered("%s\n", message);
+
+ if (harvard)
+ enable_Harvard_clock();
+
+ configure_CPLD();
+
+ print_clock_settings(after_blast, FALSE);
+ break;
+ }
+ }
+
+ /* Reset the JTAG Test Access Port Controller. */
+ arc_jtag_ops.reset();
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for blasting the FPGA */
+/* -------------------------------------------------------------------------- */
+
+/* Try to blast the target board FPGA.
+ Return TRUE if blasting is done. */
+
+static Boolean
+blast_board (char *args, int from_tty)
+{
+ /* Check that a file name has been given. */
+ if (args == NULL)
+ printf_filtered (_(ARC_BLAST_BOARD_COMMAND_USAGE));
+ else
+ {
+ char *suffix = strrchr(args, '.');
+
+ /* Check the file is an .xbf file. */
+ if ((suffix != NULL) && (strcasecmp(suffix, ".xbf") == 0))
+ {
+ FILE *fp;
+
+ /* Check that the JTAG interface (which opens the GPIO driver) is open
+ (do this before opening the file, as this function does not return
+ here if the interface is not open). */
+ arc_jtag_ops.check_open();
+
+ fp = fopen(args, "rb");
+
+ if (fp)
+ {
+ char *message = NULL;
+
+ if (initialize_FPGA())
+ {
+ if (blast_FPGA(fp))
+ {
+ /* Reset the JTAG Test Access Port Controller. */
+ arc_jtag_ops.reset();
+
+ program_clock_settings(_("Reconfiguring clock settings after FPGA blast."), TRUE);
+
+ return TRUE;
+ }
+ else
+ message = _("Can not blast FPGA");
+ }
+ else
+ message = _("Can not initialize FPGA for blasting");
+
+ (void) fclose(fp);
+
+ if (message)
+ error("%s", message);
+ }
+ else
+ error(_("Can not open file '%s': %s"), args, strerror(errno));
+ }
+ else
+ error(_("Filename does not have suffix .xbf, so is presumably not an XBF file"));
+ }
+
+ return FALSE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+
+/* Command: <command> <XBF_file>
+
+ Blast the target board's FPGA with an XBF file. */
+
+static void
+arc_blast_board_FPGA (char *args, int from_tty)
+{
+ if (blast_board(args, from_tty))
+ {
+ /* We no longer know what the target processor is. */
+ arc_architecture_is_unknown();
+
+ /* So find it out again. */
+ arc_update_architecture(arc_read_jtag_aux_register);
+
+ /* And check that it matches the aux registers and the executable file. */
+ ARCHITECTURE_CHECK(current_gdbarch,
+ (current_objfile) ? current_objfile->obfd : NULL);
+ }
+}
+
+
+/* Command: <command> [ <clock> = ] <frequency> [ , <frequency> ]
+
+ Set the frequency of one or both PLL clocks. */
+
+static void
+arc_set_clock_frequency (char *args, int from_tty)
+{
+ MegaHertz MCLK_frequency = UNDEFINED_FREQUENCY;
+ MegaHertz VCLK_frequency = UNDEFINED_FREQUENCY;
+ int result;
+ char *value;
+
+ if (args == NULL)
+ {
+ printf_filtered (_(ARC_SET_CLOCK_FREQUENCY_COMMAND_USAGE));
+ return;
+ }
+
+ result = name_value_pair(args, &value);
+
+ if (result == 0)
+ {
+ printf_filtered (_(ARC_SET_CLOCK_FREQUENCY_COMMAND_USAGE));
+ return;
+ }
+
+ if (result == 1)
+ {
+ char *comma = strchr(args, ',');
+
+ if (comma)
+ {
+ *comma = '\0';
+ MCLK_frequency = strtod(args, NULL);
+ VCLK_frequency = strtod(comma + 1, NULL);
+ }
+ else
+ MCLK_frequency = strtod(args, NULL);
+
+ }
+ else if (result == 2)
+ {
+ char *comma = strchr(value, ',');
+
+ if (comma)
+ {
+ printf_filtered (_(ARC_SET_CLOCK_FREQUENCY_COMMAND_USAGE));
+ return;
+ }
+
+ if (strcasecmp(args, "mclk") == 0)
+ MCLK_frequency = strtod(value, NULL);
+ else if (strcasecmp(args, "vclk") == 0)
+ VCLK_frequency = strtod(value, NULL);
+ else
+ {
+ warning(_("invalid PLL clock '%s'"), args);
+ return;
+ }
+ }
+
+ /* strtod returns 0 for an invalid argument - and 0 is not a valid clock
+ frequency anyway! */
+ if (MCLK_frequency == 0.0 || VCLK_frequency == 0.0)
+ {
+ warning(_("invalid clock frequency"));
+ }
+ else
+ {
+ DEBUG(_("MCLK : %.2lf MHz.\n"), MCLK_frequency);
+ DEBUG(_("VCLK : %.2lf MHz.\n"), VCLK_frequency);
+
+ /* Check that the JTAG interface (which opens the GPIO driver) is open. */
+ arc_jtag_ops.check_open();
+
+ set_PLL_clocks(MCLK_frequency, VCLK_frequency);
+ check_PLL_clock_frequencies();
+ print_clock_settings(FALSE, TRUE);
+
+ /* Reset the JTAG Test Access Port Controller. */
+ arc_jtag_ops.reset();
+ }
+}
+
+
+/* Command: <command> gclk<N> = <source>
+ gclk = <source>
+ gclks = <source> , { <source> }
+ harvard
+
+ Set the source of one or more global clocks. */
+
+static void
+arc_set_clock_source (char *args, int from_tty)
+{
+ Boolean invalid = FALSE;
+
+ if (args)
+ {
+ int result;
+ char *value;
+
+ /* Check that the JTAG interface (which opens the GPIO driver) is open. */
+ arc_jtag_ops.check_open();
+
+ result = name_value_pair(args, &value);
+
+ if (result == 1)
+ {
+ if (strcasecmp(args, "harvard") == 0)
+ harvard = TRUE;
+ else
+ invalid = TRUE;
+ }
+ else if (result == 2)
+ {
+ char *key = args;
+
+ DEBUG("key = %s, value = %s\n", key, value);
+
+ if (strncasecmp(key, "gclk", 4) == 0)
+ {
+ size_t keylength = strlen(key);
+
+ if (keylength == 4)
+ set_global_clock(3, value);
+ else if (keylength == 5)
+ {
+ if (key[4] == 's' || key[4] == 'S')
+ {
+ GlobalClockId clockId = 0;
+ char *clockData = strtok(value, " ,");
+
+ do
+ {
+ if (clockId == NUM_GLOBAL_CLOCKS)
+ {
+ warning(_("too many clock sources specified"));
+ return;
+ }
+
+ set_global_clock(clockId++, clockData);
+ clockData = strtok(NULL, " ,");
+ } while (clockData != NULL);
+ }
+ else if ('0' <= key[4] && key[4] < '0' + (char) NUM_GLOBAL_CLOCKS)
+ {
+ DEBUG("gclkN found\n");
+ set_global_clock((GlobalClockId) (key[4] - (char) '0'), value);
+ }
+ else
+ {
+ warning(_("'%c' is not a valid clock number"), key[4]);
+ return;
+ }
+ }
+ else
+ invalid = TRUE;
+ }
+ else
+ invalid = TRUE;
+ }
+ else
+ invalid = TRUE;
+ }
+ else
+ invalid = TRUE;
+
+ if (invalid)
+ printf_filtered (_(ARC_SET_CLOCK_SOURCE_COMMAND_USAGE));
+ else
+ program_clock_settings(_("Attempting to set clocks."), FALSE);
+}
+
+
+/* Command: <command>
+
+ Show the current clock settings. */
+
+static void
+arc_print_clock_settings (char *args, int from_tty)
+{
+ if (args)
+ {
+ printf_filtered (_(ARC_CLOCK_SETTINGS_COMMAND_USAGE));
+ return;
+ }
+
+ /* Check that the JTAG interface (which opens the GPIO driver) is open. */
+ arc_jtag_ops.check_open();
+
+ print_clock_settings(TRUE, FALSE);
+}
+
+
+/* Command: <command>
+
+ Show the current target board FPGA status. */
+
+static void
+arc_check_FPGA_configuration (char *args, int from_tty)
+{
+ if (args)
+ {
+ printf_filtered (_(ARC_FPGA_COMMAND_USAGE));
+ return;
+ }
+
+ switch (arc_is_FPGA_configured())
+ {
+ case INACCESSIBLE:
+ break;
+ case CONFIGURED:
+ printf_filtered(_("FPGA is configured.\n"));
+ break;
+ case UNCONFIGURED:
+ printf_filtered(_("FPGA is not configured.\n"));
+ break;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Blast the target board FPGA. */
+
+void
+arc_blast_board (char *args, int from_tty)
+{
+ (void) blast_board(args, from_tty);
+}
+
+
+/* Reset the target board. */
+
+void
+arc_reset_board (void)
+{
+ /* Toggle the SS1 line - this should do a soft reset. */
+
+ write_control_port(SS1 | SS0 | CNT, 0);
+ write_control_port( SS0 | CNT, 200); /* TBH 18 JUN 2003 delay needed by slower simulations. */
+ write_control_port(SS1 | SS0 | CNT, 0);
+
+ /* Reset the PLL clocks and the global clock sources - this should be done
+ by the soft reset, but that does not appear to happen! */
+ reset_clock_configuration();
+
+ (void) set_PLL_clock_frequency(PLL_MCLK, MCLK_RESET_FREQUENCY, FALSE, FALSE);
+ (void) set_PLL_clock_frequency(PLL_VCLK, VCLK_RESET_FREQUENCY, FALSE, FALSE);
+
+ configure_CPLD();
+}
+
+
+/* Check whether the FPGA has been configured (i.e. blasted with an XBF). */
+
+FPGA_Status
+arc_is_FPGA_configured (void)
+{
+ FPGA_Status result;
+
+ ENTERMSG;
+
+ /* Try to open the JTAG interface (which opens the GPIO driver). */
+ if (arc_jtag_ops.open(arc_aux_find_register_number("MEMSUBSYS", ARC_HW_MEMSUBSYS_REGNUM)))
+ {
+ /* Get the current state of the control register. */
+ Byte origCTRL = gpio_read(CONTROL_PORT) ^ C_XOR;
+ Byte newCTRL;
+ Byte status;
+
+ /* If SS0 is low, bring this high first (to protect against reset). */
+ if (SS0 != (origCTRL & SS0))
+ {
+ /* Output new control state. */
+ newCTRL = (origCTRL | SS0);
+ write_control_port(newCTRL, 1);
+ }
+
+ /* Ensure that SS0 is high, and SS1 and CNT are low. */
+ newCTRL = (origCTRL | SS0) & 0xF5; // 11110101
+ newCTRL = newCTRL | BI;
+ write_control_port(newCTRL, 1);
+
+ /* Read the OP input. */
+ status = read_status_port();
+
+ /* If SS1 was originally high then bring high now (to protect against reset). */
+ if (SS1 == (origCTRL & SS1))
+ {
+ /* Output new control state (Gray code transition). */
+ newCTRL = (origCTRL | SS1);
+ write_control_port(newCTRL, 1);
+ }
+
+ /* Restore the control register. */
+ write_control_port(origCTRL, 1);
+
+ /* Reset the JTAG Test Access Port Controller. */
+ arc_jtag_ops.reset();
+
+ result = IS_SET(FPA_CFG_DONE, status) ? CONFIGURED : UNCONFIGURED;
+ }
+ else
+ result = INACCESSIBLE;
+
+ LEAVEMSG;
+ return result;
+}
+
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+void
+_initialize_arc_board (void)
+{
+ struct cmd_list_element* c;
+
+ /* Reset the configuration info to its default state. */
+ reset_clock_configuration();
+
+ /* Add support for blasting an FPGA board (ARCangel). */
+ c = add_cmd (ARC_BLAST_BOARD_COMMAND,
+ class_obscure,
+ arc_blast_board_FPGA,
+ _("Blast the ARC board FPGA.\n"
+ ARC_BLAST_BOARD_COMMAND_USAGE
+ "<FILE> is the filepath of an XBF (eXtended Binary Format) file.\n"),
+ &cmdlist);
+ set_cmd_completer (c, filename_completer);
+
+ /* Add support for setting the CPU clock frequency. */
+ (void) add_cmd (ARC_SET_CLOCK_FREQUENCY_COMMAND,
+ class_obscure,
+ arc_set_clock_frequency,
+ _("Set the PLL frequency on the ARC board.\n"
+ ARC_SET_CLOCK_FREQUENCY_COMMAND_USAGE
+ "<CLOCK> is 'mclk' or 'vclk'; if omitted, and only one frequency is given, it defaults to 'mclk'.\n"
+ "<FREQUENCY> is a number (interpreted as MegaHertz).\n"),
+ &cmdlist);
+
+ /* Add support for setting the CPU clock sources. */
+ (void) add_cmd (ARC_SET_CLOCK_SOURCE_COMMAND,
+ class_obscure,
+ arc_set_clock_source,
+ _("Set the clock sources on the ARC board.\n"
+ ARC_SET_CLOCK_SOURCE_COMMAND_USAGE
+ "N is in the range 0 .. 3; if omitted, it defaults to 3.\n"
+ "<SOURCE> is 'crystal', 'dips', 'highimp', 'host', 'mclk', 'vclk' or a number (interpreted as MegaHertz). \n"),
+ &cmdlist);
+
+ /* Add support for showing the clock settings. */
+ (void) add_cmd (ARC_CLOCK_SETTINGS_COMMAND,
+ class_info,
+ arc_print_clock_settings,
+ _("Show the clock settings on the ARC board.\n"
+ ARC_CLOCK_SETTINGS_COMMAND_USAGE),
+ &infolist);
+
+ /* Add support for checking whether the FPGA board has been configured. */
+ (void) add_cmd (ARC_FPGA_COMMAND,
+ class_info,
+ arc_check_FPGA_configuration,
+ _("Check ARC board FPGA configuration.\n"
+ ARC_FPGA_COMMAND_USAGE),
+ &infolist);
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-board.h b/gdb/arc-board.h
new file mode 100644
index 00000000000..3683b5baee4
--- /dev/null
+++ b/gdb/arc-board.h
@@ -0,0 +1,65 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Phil Barnard <phil.barnard@arc.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 header file defines operations for controlling an ARC target */
+/* board. */
+/* */
+/* These operations are: */
+/* 1) configuring ("blasting") an FPGA target with the contents of an */
+/* XBF file; */
+/* 2) checking whether a target has been so configured; and */
+/* 3) setting the clock frequency of the target. */
+/* */
+/* Notes: */
+/* The arc_blast_board function implements an ARC-specific command; hence */
+/* its 'args' parameter contains data entered by the debugger user, which */
+/* must be checked for validity. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_BOARD_H
+#define ARC_BOARD_H
+
+
+typedef enum
+{
+ INACCESSIBLE,
+ CONFIGURED,
+ UNCONFIGURED
+} FPGA_Status;
+
+
+void arc_blast_board (char *args, int from_tty);
+
+void arc_reset_board (void);
+
+FPGA_Status arc_is_FPGA_configured (void);
+
+
+#endif /* ARC_BOARD_H */
+/******************************************************************************/
diff --git a/gdb/arc-dummy-gpio.c b/gdb/arc-dummy-gpio.c
new file mode 100644
index 00000000000..8297408215d
--- /dev/null
+++ b/gdb/arc-dummy-gpio.c
@@ -0,0 +1,94 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 implements a dummy set of operations for reading data from */
+/* / writing data to a parallel port using a GPIO (General Purpose Input/ */
+/* Output) driver. */
+/* */
+/* It is useful for testing when no hardware target is available. */
+/* */
+/******************************************************************************/
+
+#include "arc-gpio.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* This is set to TRUE if an I/O error occurs in accessing the port.
+ (This never happens in this dummy module). */
+Boolean gpio_port_error;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialization of the GPIO interface. */
+
+Boolean
+gpio_open (void)
+{
+ gpio_port_error = FALSE;
+ return TRUE;
+}
+
+
+/* Close the GPIO interface. */
+
+void
+gpio_close (void)
+{
+}
+
+
+/* Write a byte of data to the given port. */
+
+void
+gpio_write (ParallelPort port, Byte data)
+{
+}
+
+
+/* Read a byte of data from the given port. */
+
+Byte
+gpio_read (ParallelPort port)
+{
+ return 0;
+}
+
+
+/* Write a series of bytes of data to the ports. */
+
+void
+gpio_write_array (GPIO_Pair array[], unsigned int num_elements)
+{
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-dummy-jtag-ops.c b/gdb/arc-dummy-jtag-ops.c
new file mode 100644
index 00000000000..257330b79f4
--- /dev/null
+++ b/gdb/arc-dummy-jtag-ops.c
@@ -0,0 +1,274 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 implements a dummy set of operations for debug access to */
+/* an ARC processor via its JTAG interface. */
+/* */
+/* It is useful for testing when no hardware target is available. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <stdio.h>
+
+/* ARC header files */
+#include "arc-jtag-ops.h"
+#include "arc-registers.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define AMV1_REG (ARC_HW_AMV0_REGNUM + 3)
+
+
+/* The number of actionpoints supported by the target. Set this to different
+ values (2, 4 or 8) when testing. */
+static unsigned int num_actionpoints = 8;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+JTAG_Operations arc_jtag_ops;
+
+
+/* -------------------------------------------------------------------------- */
+/* main operations */
+/* -------------------------------------------------------------------------- */
+
+/* These are the functions that are called from outside this module via the
+ pointers in the arc_jtag_ops global object.
+
+ N.B. none of these functions are called from within this module. */
+
+
+/* Read a processor core register. */
+
+static JTAG_OperationStatus
+jtag_read_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents)
+{
+ return JTAG_SUCCESS;
+}
+
+
+/* Write a processor core register. */
+
+static JTAG_OperationStatus
+jtag_write_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents)
+{
+ return JTAG_SUCCESS;
+}
+
+
+/* Read a processor auxiliary register. */
+
+static JTAG_OperationStatus
+jtag_read_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents)
+{
+ /* Return a "useful" value for some specific registers. */
+
+ if (regnum == ARC_HW_PC_REGNUM)
+ *contents = 0x00001008;
+ else if (regnum == ARC_HW_AP_BUILD_REGNUM)
+ {
+ if (num_actionpoints == 2)
+ *contents = 0x00000004;
+ else if (num_actionpoints == 4)
+ *contents = 0x00000104;
+ else
+ *contents = 0x00000204;
+ }
+ else if (regnum == ARC_HW_DEBUG_REGNUM)
+ {
+ /* Fake trigger of AP 1. */
+ *contents = DEBUG_ACTIONPOINT_HALT |
+ (1 << (DEBUG_ACTIONPOINT_STATUS_SHIFT + 1));
+ }
+ else if (regnum == AMV1_REG)
+ {
+ *contents = 0x4008;
+ }
+ else if (regnum == ARC_HW_IDENTITY_REGNUM)
+ {
+ *contents = 0x31;
+ }
+ else if (regnum == ARC_HW_STATUS32_REGNUM)
+ {
+ *contents = STATUS32_HALT;
+ }
+ else
+ *contents = 0;
+
+// DEBUG("regnum = %x, contents = 0x%08X", regnum, *contents);
+
+ return JTAG_SUCCESS;
+}
+
+
+/* Write a processor auxiliary register. */
+
+static JTAG_OperationStatus
+jtag_write_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents)
+{
+// printf(_("AUX: regnum = %d, contents = 0x%08X\n"), regnum, contents);
+ return JTAG_SUCCESS;
+}
+
+
+/* Read a word of data from memory; the given address must be word-aligned.
+ Returns number of bytes read. */
+
+static unsigned int
+jtag_read_word (ARC_Address addr, ARC_Word *data)
+{
+ *data = 0;
+ return BYTES_IN_WORD;
+}
+
+
+/* Write a word of data to memory; the given address must be word-aligned.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_word (ARC_Address addr, ARC_Word data)
+{
+ return BYTES_IN_WORD;
+}
+
+
+/* Read a number of words of data from target memory starting at the given address.
+ Returns number of bytes read. */
+
+static unsigned int
+jtag_read_chunk (ARC_Address addr, ARC_Byte *data, unsigned int words)
+{
+ return words * BYTES_IN_WORD;
+}
+
+
+/* Write a number of words of data to target memory starting at the given address.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_chunk (ARC_Address addr, ARC_Byte *data, unsigned int words)
+{
+ return words * BYTES_IN_WORD;
+}
+
+
+/* Write a number of copies of a word-sized pattern of data to memory starting
+ at the given address.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_pattern (ARC_Address addr, ARC_Word pattern, unsigned int words)
+{
+ return words * BYTES_IN_WORD;
+}
+
+
+/* Open the JTAG interface.
+ Returns TRUE for success. */
+
+static Boolean
+jtag_open (void)
+{
+ arc_jtag_ops.status = JTAG_OPENED;
+ return TRUE;
+}
+
+
+/* Close the JTAG interface. */
+
+static void
+jtag_close (void)
+{
+ arc_jtag_ops.status = JTAG_CLOSED;
+}
+
+
+/* Reset the target JTAG controller. */
+
+static void
+jtag_reset (void)
+{
+}
+
+
+/* Reset the target board. */
+
+static void
+jtag_reset_board (void)
+{
+}
+
+
+/* Check that the JTAG interface is open.
+ If it is closed, 'error' is called. */
+
+static void
+jtag_check_open (void)
+{
+ if (arc_jtag_ops.status == JTAG_CLOSED)
+ error(_("JTAG connection is closed. "
+ "Use command 'target " ARC_TARGET_NAME "' first."));
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+void
+_initialize_arc_jtag_ops (void)
+{
+ arc_jtag_ops.status = JTAG_CLOSED;
+ arc_jtag_ops.state_machine_debug = FALSE;
+ arc_jtag_ops.retry_count = 50;
+
+ arc_jtag_ops.open = jtag_open;
+ arc_jtag_ops.close = jtag_close;
+ arc_jtag_ops.check_open = jtag_check_open;
+ arc_jtag_ops.reset_board = jtag_reset_board;
+ arc_jtag_ops.reset = jtag_reset;
+ arc_jtag_ops.memory_read_word = jtag_read_word;
+ arc_jtag_ops.memory_write_word = jtag_write_word;
+ arc_jtag_ops.memory_read_chunk = jtag_read_chunk;
+ arc_jtag_ops.memory_write_chunk = jtag_write_chunk;
+ arc_jtag_ops.memory_write_pattern = jtag_write_pattern;
+ arc_jtag_ops.read_aux_reg = jtag_read_aux_reg;
+ arc_jtag_ops.write_aux_reg = jtag_write_aux_reg;
+ arc_jtag_ops.read_core_reg = jtag_read_core_reg;
+ arc_jtag_ops.write_core_reg = jtag_write_core_reg;
+}
+
+/******************************************************************************/
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);
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-elf32-tdep.h b/gdb/arc-elf32-tdep.h
new file mode 100644
index 00000000000..eb7d3e9497b
--- /dev/null
+++ b/gdb/arc-elf32-tdep.h
@@ -0,0 +1,118 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines an initialization function for the arc_elf32 */
+/* architecture, and various operations which are useful for the various */
+/* arc-elf32 targets supported. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_ELF32_TDEP_H
+#define ARC_ELF32_TDEP_H
+
+/* gdb header files */
+#include "defs.h"
+#include "gdbarch.h"
+#include "target.h"
+#include "breakpoint.h"
+
+/* ARC header files */
+#include "arc-registers.h"
+#include "arc-architecture.h"
+
+
+/* Complete the structure definition here. */
+struct arc_variant_info
+{
+ ARC_ProcessorVersion processor_version;
+ ARC_RegisterInfo registers;
+};
+
+
+typedef enum
+{
+ REGISTER_IS_READ_ONLY,
+ ERROR_ON_READING_REGISTER,
+ ERROR_ON_WRITING_REGISTER
+} RegisterError;
+
+
+typedef void (*ProcessorControlFunction)(void);
+
+
+struct gdbarch* arc_elf32_initialize (struct gdbarch *gdbarch,
+ struct gdbarch_list *arches);
+
+void arc_check_pc_defined (struct gdbarch *gdbarch);
+
+void arc_elf32_find_register_numbers (void);
+
+void arc_elf32_load_program (char *filename, int from_tty);
+
+void arc_elf32_create_inferior (char *exec_file,
+ char *args,
+ char **env,
+ struct target_ops *target_ops);
+
+void arc_elf32_execute (struct target_waitstatus *status,
+ ProcessorControlFunction run_processor,
+ ProcessorControlFunction start_processor,
+ ProcessorControlFunction stop_processor);
+
+void arc_elf32_close (Boolean resume);
+
+void arc_elf32_fetch_registers (struct regcache *regcache, int gdb_regno);
+void arc_elf32_store_registers (struct regcache *regcache, int gdb_regno);
+
+int arc_elf32_insert_breakpoint (struct bp_target_info *bpt);
+int arc_elf32_remove_breakpoint (struct bp_target_info *bpt);
+
+LONGEST arc_elf32_xfer_partial (struct target_ops *ops,
+ enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset,
+ LONGEST len);
+
+void arc_elf32_core_warning (RegisterError error,
+ ARC_RegisterNumber hw_regno);
+
+void arc_elf32_aux_warning (RegisterError error,
+ ARC_RegisterNumber hw_regno);
+
+
+extern ARC_RegisterNumber arc_debug_regnum;
+extern ARC_RegisterNumber arc_pc_regnum;
+extern ARC_RegisterNumber arc_status32_regnum;
+
+extern Boolean arc_program_is_loaded;
+extern Boolean arc_target_is_connected;
+
+
+#endif /* ARC_ELF32_TDEP_H */
+/******************************************************************************/
diff --git a/gdb/arc-gpio.c b/gdb/arc-gpio.c
new file mode 100644
index 00000000000..cc9f7753d31
--- /dev/null
+++ b/gdb/arc-gpio.c
@@ -0,0 +1,251 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Richard Stuckey <richard.stuckey@arc.com>
+ A.N. Other <unknown>
+
+ 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 implements operations for reading data from / writing data */
+/* to a parallel port using a GPIO (General Purpose Input/Output) driver. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <string.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* gdb header files */
+#include "defs.h"
+
+/* ARC header files */
+#include "arc-gpio.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+// I/O control numbers.
+
+// Linux kernel uses 0x54XX for special purposes. Avoid such.
+// We'll pick large numbers.
+// We don't use the linux convention of dividing the IOC into a bunch
+// of bit fields. We can always switch to this later, as the
+// IOC 0 returns the driver version (which IOC value will never change).
+
+#define GPIO_IOC_VERSION 0 // returns version
+#define GPIO_IOC_BASE 0xaa3a0000UL // Intended for use on ARCangel 3!
+
+
+// Switch base address of parallel port. 0x3f8 is assumed.
+// WARNING! You can write on any port whatsoever with this driver.
+// BE CAREFUL!
+#define GPIO_IOC_SET_PORT_BASE (GPIO_IOC_BASE + 1) // cmd, arg=port base
+
+// General input/output ioctl. See GPIO_ioctl struct.
+#define GPIO_IOC_DO_IO (GPIO_IOC_BASE + 2) // cmd, arg=GPIO_ioctl *
+
+// For emergency purposes in case the driver is goofed up.
+#define GPIO_IOC_HARD_RESET (GPIO_IOC_BASE + 3) // cmd, no arg
+
+// Do you have an antiquated parallel port? You might need to ask
+// the driver to use outb_p and inb_p (_p = pause). Default is not to.
+#define GPIO_IOC_SET_PAUSE (GPIO_IOC_BASE + 4) // arg = 1 => use pause; otherwise not.
+
+
+/* parallel port I/O addresses (LPT1) */
+#define PORT_BASE_ADDRESS 0x378
+#define DATA_PORT_ADDRESS (PORT_BASE_ADDRESS + DATA_PORT)
+#define STATUS_PORT_ADDRESS (PORT_BASE_ADDRESS + STATUS_PORT)
+#define CONTROL_PORT_ADDRESS (PORT_BASE_ADDRESS + CONTROL_PORT)
+
+#define NULL_FILE_DESCRIPTOR (-1)
+
+
+typedef struct
+{
+ // This is used for general input and output in the same ioctl.
+ // N.B. "input" is input TO the port, and "output" is output FROM the port.
+ //
+ // inlen is always even and represents a number of pairs:
+ //
+ // [0|1|2, value] : write value to port_base+0|1|2.
+ // [0x80|0x81|0x82, <ignored>] : read value from port_base+0|1|2
+ // and append result to outbuf.
+ //
+ // Thus one can intermix read and write in the same ioctl.
+
+ // inlen is replaced by the number of input bytes consumed.
+ unsigned inlen;
+ char *inbuf;
+
+ // outlen is replaced by the number of output bytes written.
+ unsigned outlen;
+ char *outbuf;
+} GPIO_ioctl;
+
+
+/* Buffers to hold data read from / written to ports; we generally read/write
+ only 1 byte of data at a time, so the buffers need hold only 1 byte pair each. */
+static char input_buffer [2];
+static char output_buffer[2];
+static GPIO_ioctl ioctl_data = { 0, input_buffer, 0, output_buffer };
+
+/* A file descriptor for the GPIO driver. */
+static int gpio_driver = NULL_FILE_DESCRIPTOR;
+
+/* Debug data. */
+// static const char name[] = {'D', 'S', 'C'};
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* This is set to TRUE if an I/O error occurs in accessing the port. */
+Boolean gpio_port_error;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialization of the GPIO interface. */
+
+Boolean
+gpio_open (void)
+{
+ /* Open the driver, if not already open. */
+ if (gpio_driver == NULL_FILE_DESCRIPTOR)
+ {
+ gpio_driver = open(GPIO_DEVICE, O_RDWR);
+
+ if ((gpio_driver == NULL_FILE_DESCRIPTOR) ||
+ ioctl(gpio_driver, GPIO_IOC_HARD_RESET) ||
+ ioctl(gpio_driver, GPIO_IOC_SET_PORT_BASE, PORT_BASE_ADDRESS))
+ {
+ warning(_("unable to open JTAG port (device " GPIO_DEVICE "): %s"),
+ strerror(errno));
+ return FALSE;
+ }
+
+ gpio_port_error = FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* Close the GPIO interface. */
+
+void
+gpio_close (void)
+{
+ /* Close the driver, if not already closed. */
+ if (gpio_driver != NULL_FILE_DESCRIPTOR)
+ {
+ /* Close file descriptor opened for communication with gpio driver. */
+ if (close(gpio_driver) == -1)
+ warning(_("unable to close JTAG port (device " GPIO_DEVICE "): %s"),
+ strerror(errno));
+
+ gpio_driver = NULL_FILE_DESCRIPTOR;
+ }
+}
+
+
+/* Write a byte of data to the given port. */
+
+void
+gpio_write (ParallelPort port, Byte data)
+{
+ ioctl_data.inlen = 2;
+ ioctl_data.inbuf[0] = (char) port;
+ ioctl_data.inbuf[1] = (char) data;
+
+ if (ioctl(gpio_driver, GPIO_IOC_DO_IO, &ioctl_data))
+ error(_("Failure writing to port %d: %s"), port, strerror(errno));
+
+ /* If no data has been consumed by the port. */
+ if (ioctl_data.inlen == 0)
+ gpio_port_error = TRUE;
+
+// DEBUG("ioctl_data.inlen: %d\n", ioctl_data.inlen);
+// DEBUG("GPIO write: %02x -> %c\n", data, name[port]);
+}
+
+
+/* Read a byte of data from the given port. */
+
+Byte
+gpio_read (ParallelPort port)
+{
+ ioctl_data.inlen = 2;
+ ioctl_data.inbuf[0] = (char) (port + 0x80);
+// ioctl_data.inbuf[1] is ignored
+
+ /* N.B. outlen must be set! */
+ ioctl_data.outlen = 1;
+ ioctl_data.outbuf[0] = (char) 0; // in case the read fails
+
+ if (ioctl(gpio_driver, GPIO_IOC_DO_IO, &ioctl_data))
+ error(_("Failure reading from port %d: %s"), port, strerror(errno));
+
+ /* If no data has been provided by the port */
+ if (ioctl_data.outlen == 0)
+ gpio_port_error = TRUE;
+
+// DEBUG("ioctl_data.outlen: %d\n", ioctl_data.outlen);
+// DEBUG("GPIO read : %02x <- %c\n", (Byte) ioctl_data.outbuf[0], name[port]);
+
+ return (Byte) ioctl_data.outbuf[0];
+}
+
+
+/* Write a series of bytes of data to the ports. */
+
+void
+gpio_write_array (GPIO_Pair array[], unsigned int num_elements)
+{
+ char buffer[num_elements * 2];
+ GPIO_ioctl data = { 0, buffer, 0, NULL };
+ unsigned int i;
+
+ for (i = 0; i < num_elements; i++)
+ {
+ buffer[data.inlen++] = (char) array[i].port;
+ buffer[data.inlen++] = (char) array[i].data;
+ }
+
+ if (ioctl(gpio_driver, GPIO_IOC_DO_IO, &data))
+ error(_("Failure writing to port: %s"), strerror(errno));
+
+ /* If no data has been consumed by the port. */
+ if (ioctl_data.inlen == 0)
+ gpio_port_error = TRUE;
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-gpio.h b/gdb/arc-gpio.h
new file mode 100755
index 00000000000..914138c75f2
--- /dev/null
+++ b/gdb/arc-gpio.h
@@ -0,0 +1,72 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines operations for reading data from / writing */
+/* data to a parallel port using a GPIO (General Purpose Input/Output) */
+/* driver. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_GPIO_H
+#define ARC_GPIO_H
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+#define GPIO_DEVICE "/dev/gpio"
+
+
+typedef enum
+{
+ DATA_PORT = 0,
+ STATUS_PORT = 1,
+ CONTROL_PORT = 2
+} ParallelPort;
+
+typedef unsigned char Byte;
+
+typedef struct
+{
+ ParallelPort port;
+ Byte data;
+} GPIO_Pair;
+
+
+Boolean gpio_open (void);
+void gpio_close (void);
+
+void gpio_write (ParallelPort port, Byte data);
+Byte gpio_read (ParallelPort port);
+
+void gpio_write_array (GPIO_Pair array[], unsigned int num_elements);
+
+
+extern Boolean gpio_port_error;
+
+#endif /* ARC_GPIO_H */
+/******************************************************************************/
diff --git a/gdb/arc-inst-tracing.c b/gdb/arc-inst-tracing.c
new file mode 100644
index 00000000000..c22ddb732ec
--- /dev/null
+++ b/gdb/arc-inst-tracing.c
@@ -0,0 +1,356 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 implements operations for recording an instruction trace */
+/* of successive PC values in a compressed binary format in a file. */
+/* */
+/* The file is regarded as a linear sequence of bits, of the form: */
+/* */
+/* <64-bit first instruction count> */
+/* <64-bit last instruction count> */
+/* { <3-bit-code> [ <16-bit-data> | <31-bit-data> ] } */
+/* [ <zero-pad-bits> ] */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+/* gdb header files */
+#include "defs.h"
+
+/* ARC header files */
+#include "arc-inst-tracing.h"
+#include "arc-tdep.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_ORDINAL 0xFFFFFFFFFFFFFFFFULL
+
+/* The file that is currently open for read or write. */
+static FILE *file;
+
+/* The byte of data that has been read from, or is about to be written to, the
+ currently open file; and the number of bits in that byte that have been used
+ (i.e. been consumed on input, or produced on output). */
+static unsigned char byte;
+static unsigned int bits_used;
+
+/* Set to TRUE if EOF occurs whilst trying to read from the file. */
+static Boolean EOF_detected;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Write the N least-significant bits of the given value to the file. */
+
+static void
+output_bits (unsigned int N, unsigned int value)
+{
+ unsigned int i;
+
+ for (i = 0; i < N; i++)
+ {
+ if (bits_used == BITS_IN_BYTE)
+ {
+ (void) putc((int) byte, file);
+ byte = 0;
+ bits_used = 0;
+// printf("byte = %02X\n", byte);
+ }
+
+ byte <<= 1;
+ byte |= (value >> (N - i - 1)) & 0x1;
+ bits_used++;
+ }
+}
+
+
+/* Read N bits from the file and return them as the least-significant bits of a value. */
+
+static unsigned int
+input_bits (unsigned int N)
+{
+ unsigned int value = 0;
+ unsigned int i;
+
+ for (i = 0; i < N; i++)
+ {
+ unsigned int bit;
+
+ /* If all the bits in the current input byte have been used. */
+ if (bits_used == BITS_IN_BYTE)
+ {
+ /* Read the next byte from the file. */
+ int input = getc(file);
+
+ if (input == EOF)
+ {
+ EOF_detected = TRUE;
+ return 0;
+ }
+
+ byte = (unsigned char) input;
+ bits_used = 0;
+// printf("byte = %02X\n", byte);
+ }
+
+ bit = (unsigned int) ((byte & 0x80) >> 7);
+ value <<= 1;
+ value |= bit;
+ byte <<= 1;
+ bits_used++;
+ }
+
+ return value;
+}
+
+
+/* Write a 64-bit value to the file. */
+
+static void
+output_ordinal (Ordinal value)
+{
+ output_bits(32, (unsigned int) (value >> 32));
+ output_bits(32, (unsigned int) (value & 0xFFFFFFFF));
+}
+
+
+/* Read a 64-bit value from the file. */
+
+static Ordinal
+input_ordinal (void)
+{
+ unsigned int high = input_bits(32);
+ unsigned int low = input_bits(32);
+
+ return ((Ordinal) high) << 32 | (Ordinal) low;
+}
+
+
+/* Open the named file with the given access mode. */
+
+static Boolean
+open_file (const char *filename, const char *mode)
+{
+ file = fopen(filename, mode);
+
+ if (file == NULL)
+ {
+ fprintf(stderr, "Can not open file %s: %s\n", filename, strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Start encoding trace data into the named file. */
+
+Boolean
+arc_start_encoding (const char *filename,
+ Ordinal first_instr_count)
+{
+ ENTERARGS("filename = %s, first = %llu", filename, first_instr_count);
+
+ byte = 0;
+ bits_used = 0;
+
+ if (open_file(filename, "wb"))
+ {
+ /* The second value will be fixed up later. */
+ output_ordinal(first_instr_count);
+ output_ordinal(MAX_ORDINAL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Stop encoding trace data into the file. */
+
+void
+arc_stop_encoding (Ordinal last_instr_count)
+{
+ ENTERARGS("last = %llu", last_instr_count);
+
+ if (file)
+ {
+ /* Make sure the last partial byte output is flushed to the file,
+ padded with 0 bits as necessary. */
+ if (bits_used > 0)
+ output_bits(BITS_IN_BYTE, 0);
+
+ /* N.B. this is necessary! */
+ (void) fflush(file);
+
+ /* Now fix up the second 8-byte value in tjhe file. */
+
+ if (lseek(fileno(file), (off_t) sizeof(Ordinal), SEEK_SET) == -1)
+ warning(_("can not seek in file: %s"), strerror(errno));
+ else
+ {
+ bits_used = 0;
+ byte = 0;
+ output_ordinal(last_instr_count);
+
+ /* Make sure the last byte is flushed. */
+ output_bits(1, 0);
+ }
+
+ (void) fclose(file);
+ file = NULL;
+ }
+}
+
+
+/* Start decoding trace data from the named file.
+ Retrieve the first and last instruction ordinal positions. */
+
+Boolean
+arc_start_decoding (const char *filename,
+ Ordinal *first_instr_count,
+ Ordinal *last_instr_count)
+{
+ ENTERARGS("filename = %s", filename);
+
+ /* The first attempt to input a bit will result in a read from the file. */
+ bits_used = BITS_IN_BYTE;
+ EOF_detected = FALSE;
+
+ if (open_file(filename, "r"))
+ {
+ *first_instr_count = input_ordinal();
+ *last_instr_count = input_ordinal();
+
+ DEBUG("first = %llu, last = %llu\n", *first_instr_count, *last_instr_count);
+
+ return !EOF_detected;
+ }
+
+ return FALSE;
+}
+
+
+/* Stop decoding trace data from the file. */
+
+void
+arc_stop_decoding (void)
+{
+ if (file)
+ {
+ if (bits_used < BITS_IN_BYTE)
+ fprintf(stderr, "all data not processed!\n");
+
+ (void) fclose(file);
+ file = NULL;
+ }
+}
+
+
+/* Write a PC value into the file with the specified encoding. */
+
+void
+arc_encode_PC (ARC_ProgramCounterEncoding encoding, unsigned int value)
+{
+// printf("%d:%x\n", encoding, value);
+
+ output_bits(3, (unsigned int) encoding);
+
+ switch (encoding)
+ {
+ case NO_CHANGE:
+ case PLUS_16_BITS:
+ case PLUS_32_BITS:
+ case PLUS_48_BITS:
+ case PLUS_64_BITS:
+ break;
+ case DELTA_16_BIT_POSITIVE:
+ case DELTA_16_BIT_NEGATIVE:
+ output_bits(16, value);
+ break;
+ case ABSOLUTE_31_BITS:
+ output_bits(31, value);
+ break;
+ }
+}
+
+
+/* Read a PC value and its encoding from the file.
+ Return TRUE if a value could be read, FALSE otherwise. */
+
+Boolean
+arc_decode_PC (ARC_ProgramCounterEncoding *encoding, unsigned int *value)
+{
+ unsigned int code = input_bits(3);
+
+ if (EOF_detected)
+ return FALSE;
+
+ *encoding = (ARC_ProgramCounterEncoding) code;
+
+ switch (*encoding)
+ {
+ case NO_CHANGE:
+ case PLUS_16_BITS:
+ case PLUS_32_BITS:
+ case PLUS_48_BITS:
+ case PLUS_64_BITS:
+ *value = 0;
+ break;
+ case DELTA_16_BIT_POSITIVE:
+ case DELTA_16_BIT_NEGATIVE:
+ *value = input_bits(16);
+ break;
+ case ABSOLUTE_31_BITS:
+ *value = input_bits(31);
+ break;
+ }
+
+ if (EOF_detected)
+ return FALSE;
+
+// printf("%d:%x\n", *encoding, *value);
+
+ return TRUE;
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-inst-tracing.h b/gdb/arc-inst-tracing.h
new file mode 100644
index 00000000000..4dacad9f985
--- /dev/null
+++ b/gdb/arc-inst-tracing.h
@@ -0,0 +1,89 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines operations for recording an instruction trace */
+/* of successive PC values in a compressed binary format in a file. */
+/* */
+/* We use the fact that instructions are always 16-bit aligned to encode */
+/* 17-bit deltas as 16-bit quantities. We apply a 2-byte bias to the */
+/* delta (as the minimum delta could be -2, for a shortest distance */
+/* backward branch), so giving us */
+/* */
+/* delta range: 2 .. 2^17 */
+/* encoding range: 0 .. 2^16 - 1 */
+/* */
+/* We could encode positive and negative deltas differently (since the */
+/* minimum positive delta is 10, given that 2, 4, 6 and 8 byte positive */
+/* deltas are handled diferently), but this hardly seems worthwhile. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_INSTRUCTION_TRACING_H
+#define ARC_INSTRUCTION_TRACING_H
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+typedef enum
+{
+ NO_CHANGE,
+ PLUS_16_BITS,
+ PLUS_32_BITS,
+ PLUS_48_BITS,
+ PLUS_64_BITS,
+ DELTA_16_BIT_POSITIVE,
+ DELTA_16_BIT_NEGATIVE,
+ ABSOLUTE_31_BITS
+} ARC_ProgramCounterEncoding;
+
+
+typedef unsigned long long Ordinal;
+
+
+#define MAX_DELTA (1 << 17)
+
+#define ENCODE_DELTA(delta) (unsigned int) (((delta) - 2) / 2)
+#define DECODE_DELTA(value) (((value) * 2) + 2)
+
+
+Boolean arc_start_encoding (const char *filename,
+ Ordinal first_instr_count);
+
+void arc_stop_encoding (Ordinal last_instr_count);
+
+Boolean arc_start_decoding (const char *filename,
+ Ordinal *first_instr_count,
+ Ordinal *last_instr_count);
+
+void arc_stop_decoding (void);
+
+void arc_encode_PC (ARC_ProgramCounterEncoding encoding, unsigned int value);
+Boolean arc_decode_PC (ARC_ProgramCounterEncoding *encoding, unsigned int *value);
+
+#endif /* ARC_INSTRUCTION_TRACING_H */
+/******************************************************************************/
diff --git a/gdb/arc-jtag-actionpoints.c b/gdb/arc-jtag-actionpoints.c
new file mode 100644
index 00000000000..4c5d81826db
--- /dev/null
+++ b/gdb/arc-jtag-actionpoints.c
@@ -0,0 +1,1337 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 implements hardware breakpoints and watchpoints on the ARC */
+/* processor using actionpoints. */
+/* */
+/* See */
+/* ARC 700 System Components Reference */
+/* 5126-016 */
+/* */
+/* for a full description of the processor actionpoints mechanism. */
+/* */
+/******************************************************************************/
+
+/* gdb header files */
+#include "defs.h"
+#include "inferior.h"
+#include "gdb_assert.h"
+
+/* ARC header files */
+#include "arc-jtag-actionpoints.h"
+#include "arc-registers.h"
+#include "arc-elf32-tdep.h"
+#include "arc-jtag.h"
+#include "arc-jtag-ops.h"
+#include "arc-support.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef enum
+{
+ NOT_IN_USE,
+ SINGLE,
+ PAIR_0,
+ PAIR_1,
+ QUAD_0,
+ QUAD_1,
+ QUAD_2,
+ QUAD_3
+} Actionpoint_Usage;
+
+
+/* This information describes an individual actionpoint. */
+typedef struct arc_actionpoint
+{
+ Actionpoint_Usage usage;
+ Boolean triggered;
+ Boolean is_exclude;
+ unsigned int length;
+ ARC_RegisterContents match_value;
+ ARC_RegisterContents match_mask;
+ ARC_RegisterContents control;
+ ARC_RegisterContents point;
+} ARC_ActionPoint;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define SUCCESS 0
+#define FAILURE (-1)
+
+#define MAX_ACTION_POINTS 8
+#define MAX_ACTION_POINTS_IN_GROUP 4
+#define HW_BP_SIZE 1
+
+
+/* Bit masks for the Actionpoint Control Registers AP_ACx (10 low-order bits only). */
+#define AP_TARGET_INSTRUCTION_ADDRESS 0x000
+#define AP_TARGET_INSTRUCTION_DATA 0x001
+#define AP_TARGET_LOAD_STORE_ADDRESS 0x002
+#define AP_TARGET_LOAD_STORE_DATA 0x003
+#define AP_TARGET_AUX_REGISTER_ADDRESS 0x004
+#define AP_TARGET_AUX_REGISTER_DATA 0x005
+#define AP_TARGET_EXTERNAL_PARAMETER_0 0x006
+#define AP_TARGET_EXTERNAL_PARAMETER_1 0x007
+#define AP_TARGET_MASK 0x007
+#define AP_TARGET_SHIFT 0
+
+#define AP_TRANSACTION_TYPE_DISABLED 0x000
+#define AP_TRANSACTION_TYPE_WRITE 0x010
+#define AP_TRANSACTION_TYPE_READ 0x020
+#define AP_TRANSACTION_TYPE_ACCESS 0x030
+#define AP_TRANSACTION_TYPE_MASK 0x030
+#define AP_TRANSACTION_TYPE_SHIFT 4
+
+#define AP_MODE_TRIGGER_IN_RANGE 0x000
+#define AP_MODE_TRIGGER_OUTSIDE_RANGE 0x040
+#define AP_MODE_MASK 0x040
+
+#define AP_ACTION_BREAK 0x000
+#define AP_ACTION_EXCEPTION 0x100
+#define AP_ACTION_MASK 0x100
+
+#define AP_PAIR 0x080
+#define AP_QUAD 0x200
+
+
+/* Data defining the actionpoints. */
+static unsigned int num_actionpoints;
+static Boolean full_target_actionpoints;
+static ARC_ActionPoint actionpoints[MAX_ACTION_POINTS];
+
+/* The h/w numbers of the AMV0, AMM0 and AC0 auxiliary registers. */
+static ARC_RegisterNumber amv0_regnum;
+static ARC_RegisterNumber amm0_regnum;
+static ARC_RegisterNumber ac0_regnum;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+/* The N actionpoint auxiliary registers (where N is 0 .. MAX_ACTION_POINTS - 1)
+ (fortunately, the numbers of the registers are one contiguous block, so
+ a simple addition is sufficient here). */
+#define ARC_HW_AMV_REGNUM(n) (ARC_RegisterNumber) (amv0_regnum + 3 * (n))
+#define ARC_HW_AMM_REGNUM(n) (ARC_RegisterNumber) (amm0_regnum + 3 * (n))
+#define ARC_HW_AC_REGNUM(n) (ARC_RegisterNumber) (ac0_regnum + 3 * (n))
+
+/* This will give a value in range 0 .. MAX_ACTION_POINTS - 1. */
+#define AP_INSTANCE(ap) ((ap) - actionpoints)
+#define IN_USE(ap) ((ap)->usage != NOT_IN_USE)
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+#if 0
+/* This function checks that a given number is a power of two, and, if so,
+ returns a bitmask corresponding to (2 ** number - 1). */
+
+static Boolean
+is_power_of_two (int number, ARC_Word *mask)
+{
+ unsigned int power = 1;
+ unsigned int i;
+
+ *mask = 0;
+
+ for (i = 0; (i < BITS_IN_WORD) && (power <= (unsigned int) number); i++)
+ {
+ if (power == (unsigned int) number)
+ return TRUE;
+
+ power <<= 1;
+ *mask = (*mask << 1) + 1;
+ }
+
+ /* not a power */
+ return FALSE;
+}
+#endif
+
+
+/* This function determines whether the ARC processor in the connected target
+ provides support for actionpoints (that is a configuratiopn option). */
+
+static Boolean
+target_has_actionpoints (void)
+{
+ ARC_RegisterNumber ap_build_regnum;
+ ARC_RegisterContents ap_build;
+
+ ap_build_regnum = arc_aux_find_register_number("AP_BUILD", ARC_HW_AP_BUILD_REGNUM);
+ amv0_regnum = arc_aux_find_register_number("AMV0", ARC_HW_AMV0_REGNUM);
+ amm0_regnum = arc_aux_find_register_number("AMM0", ARC_HW_AMM0_REGNUM);
+ ac0_regnum = arc_aux_find_register_number("AC0", ARC_HW_AC0_REGNUM);
+
+ num_actionpoints = 0;
+
+ if (arc_read_jtag_aux_register(ap_build_regnum, &ap_build, TRUE))
+ {
+ DEBUG("AP_BUILD BCR: 0x%08X\n", ap_build);
+
+ /* AP_BUILD returns 0 if actionpoints are not selected in the
+ processor configuration. */
+ if (ap_build != 0)
+ {
+ /* If the processor's implementation of the actionpoint mechanism is
+ the one we know about. */
+ if ((ap_build & AP_BUILD_VERSION) == 0x4)
+ {
+ unsigned int type = (ap_build & AP_BUILD_TYPE) >> AP_BUILD_TYPE_SHIFT;
+ unsigned int i;
+
+ /* The low-order two bits of the type field encode the number
+ of actionpoints supported by the processor. */
+ switch (type % 4)
+ {
+ case 0 : num_actionpoints = 2; break;
+ case 1 : num_actionpoints = 4; break;
+ case 2 : num_actionpoints = 8; break;
+ default: internal_error (__FILE__, __LINE__, _("invalid AP_BUILD.TYPE: 0x%X"), type);
+ }
+
+ /* The next bit specifies whether the processor supports full
+ or minimum targets for the actionpoints. */
+ full_target_actionpoints = ((type & 4) == 0);
+
+ for (i = 0; i < MAX_ACTION_POINTS; i++)
+ {
+ actionpoints[i].usage = NOT_IN_USE;
+ actionpoints[i].triggered = FALSE;
+ actionpoints[i].is_exclude = FALSE;
+ }
+
+ DEBUG("ARC processor supports %u %s actionpoints\n",
+ num_actionpoints, (full_target_actionpoints) ? "full" : "minimum");
+
+ return TRUE;
+ }
+ else
+ warning(_("ARC processor actionpoint mechanism version (0x%x) is not supported."),
+ ap_build & AP_BUILD_VERSION);
+ }
+ }
+
+ DEBUG("ARC processor supports no actionpoints\n");
+
+ return FALSE;
+}
+
+
+/* This function determines the set of actionpoints that would be required to
+ cover exactly the memory region specified by (addr,length), by using one
+ actionpoint with an inclusive range, and zero or more actionpoints with
+ exclusive ranges.
+
+ The set of values and masks for the actionpoint AMV and AMM registers are
+ returned in the actionpoint_value and actionpoint_mask arrays - these must
+ be able to hold 4 entries. The value and mask for the inclusive actionpoint
+ are returned as the first elements in the arrays. */
+
+static unsigned int
+map_actionpoints (ARC_Address addr,
+ unsigned int length,
+ ARC_Address actionpoint_value[],
+ ARC_Word actionpoint_mask[])
+{
+ ARC_Address first_data = addr;
+ ARC_Address last_data = first_data + length - 1;
+ ARC_Address include_start;
+ ARC_Address include_end;
+ ARC_Word mask;
+ unsigned int power_of_two;
+ unsigned int points;
+
+ ENTERARGS("addr 0x%08X, length %d", addr, length);
+// DEBUG("range: %08X .. %08X\n", first_data, last_data);
+
+ /* If the range extends across the midpoint of the address space. */
+ if (((first_data & 0x80000000) == 0) && ((last_data & 0x80000000) != 0))
+ {
+// DEBUG("pathological case!\n");
+
+ /* Must cover entire address space. */
+ include_start = 0x00000000;
+ include_end = 0xFFFFFFFF;
+ mask = 0xFFFFFFFF; // Ignore all bits!
+ }
+ else
+ {
+ unsigned int i;
+
+ mask = 0;
+ power_of_two = 1;
+
+ /* Determine what actionpoint would be required to include all of the given
+ memory region (this include range may have leading and trailing parts
+ that extend beyond the given region). */
+ for (i = 0; i < 32; i++)
+ {
+ unsigned int include_size = power_of_two;
+
+ include_start = (first_data / include_size) * include_size;
+ include_end = include_start + include_size - 1;
+
+ if (include_start <= first_data && include_end >= last_data)
+ {
+// DEBUG("include: 0x%08X .. 0x%08X (mask 0x%08x)\n",
+// include_start, include_end, mask);
+ break;
+ }
+
+ mask = (mask << 1) + 1;
+ power_of_two <<= 1;
+ }
+ }
+
+ /* This is the first actionpoint in the list. */
+ actionpoint_value[0] = include_start;
+ actionpoint_mask [0] = mask;
+ points = 1;
+
+
+ /* Determine what actionpoints would be required to mask out the leading part
+ of the include range. */
+ {
+ unsigned int to_be_excluded = first_data - include_start;
+ ARC_Address boundary = include_start;
+
+ while (to_be_excluded > 0)
+ {
+ unsigned int j;
+
+ mask = 0;
+ power_of_two = 1;
+
+ for (j = 0; j < 32; j++)
+ {
+ unsigned int exclude_size = power_of_two;
+ ARC_Address exclude_start = (first_data / exclude_size - 1) * exclude_size;
+ ARC_Address exclude_end = exclude_start + exclude_size - 1;
+
+ if (exclude_end < first_data && exclude_start <= boundary)
+ {
+// DEBUG("leading exclude: 0x%08X .. 0x%08X (mask 0x%08x)\n",
+// exclude_start, exclude_end, mask);
+
+ to_be_excluded = first_data - exclude_end - 1;
+ boundary = exclude_end + 1;
+
+ /* There is no point in returning the details of
+ more than the maximum number of actionpoints that
+ can be linked together (in a quad). */
+ if (points < MAX_ACTION_POINTS_IN_GROUP)
+ {
+ actionpoint_value[points] = exclude_start;
+ actionpoint_mask [points] = mask;
+ }
+ points++;
+
+ break;
+ }
+
+ mask = (mask << 1) + 1;
+ power_of_two <<= 1;
+ }
+ }
+ }
+
+ /* Determine what actionpoints would be required to mask out the trailing
+ part of the include range. */
+ {
+ unsigned int to_be_excluded = include_end - last_data;
+ ARC_Address boundary = include_end;
+
+ while (to_be_excluded > 0)
+ {
+ unsigned int j;
+
+ mask = 0;
+ power_of_two = 1;
+
+ for (j = 0; j < 32; j++)
+ {
+ unsigned int exclude_size = power_of_two;
+ ARC_Address exclude_start = (last_data / exclude_size + 1) * exclude_size;
+ ARC_Address exclude_end = exclude_start + exclude_size - 1;
+
+ if (exclude_start > last_data && exclude_end >= boundary)
+ {
+// DEBUG("trailing exclude: 0x%08X .. 0x%08X (mask 0x%08x)\n",
+// exclude_start, exclude_end, mask);
+
+ to_be_excluded = exclude_start - last_data - 1;
+ boundary = exclude_start - 1;
+
+ /* There is no point in returning the details of
+ more than the maximum number of actionpoints that
+ can be linked together (in a quad). */
+ if (points < MAX_ACTION_POINTS_IN_GROUP)
+ {
+ actionpoint_value[points] = exclude_start;
+ actionpoint_mask [points] = mask;
+ }
+ points++;
+
+ break;
+ }
+
+ mask = (mask << 1) + 1;
+ power_of_two <<= 1;
+ }
+ }
+ }
+
+ return points;
+}
+
+
+/* Set the given actionpoint on the target by writing to the corresponding set
+ of AMV, AMM and AC auxiliary registers.
+ Return TRUE if it is set successfully. */
+
+static Boolean
+set_actionpoint_on_target (ARC_ActionPoint *actionpoint)
+{
+ unsigned int instance = AP_INSTANCE(actionpoint);
+
+ return arc_write_jtag_aux_register(ARC_HW_AMV_REGNUM(instance), actionpoint->match_value, TRUE) &&
+ arc_write_jtag_aux_register(ARC_HW_AMM_REGNUM(instance), actionpoint->match_mask, TRUE) &&
+ arc_write_jtag_aux_register(ARC_HW_AC_REGNUM (instance), actionpoint->control, TRUE);
+}
+
+
+/* Clear the given actionpoint on the target by writing 'DISABLED' to the
+ corresponding AC auxiliary register.
+ Return TRUE if it is cleared successfully. */
+
+static Boolean
+clear_actionpoint_from_target (ARC_ActionPoint *actionpoint)
+{
+ return arc_write_jtag_aux_register(ARC_HW_AC_REGNUM (AP_INSTANCE(actionpoint)),
+ AP_TRANSACTION_TYPE_DISABLED,
+ TRUE);
+}
+
+
+/* Set the given actionpoint on the target, and update its data structure.
+ Return TRUE if it is set successfully. */
+
+static Boolean
+set_actionpoint (ARC_ActionPoint *actionpoint)
+{
+ Boolean set = set_actionpoint_on_target(actionpoint);
+
+ if (set)
+ {
+ actionpoint->triggered = FALSE;
+ actionpoint->point = 0;
+ }
+ else
+ actionpoint->usage = NOT_IN_USE;
+
+ return set;
+}
+
+
+/* Insert an actionpoint to cover a range of target memory.
+
+ Parameters:
+ bpt : the information describing a breakpoint (NULL for a watchpoint)
+ length : the length in bytes of the range
+ match_value: the value for the actionpoint value (AMV) aux register
+ match_mask : the value for the actionpoint mask (AMM) aux register
+ control : the value for the actionpoint control (AC) aux register
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+insert_actionpoint (struct bp_target_info *bpt,
+ unsigned int length,
+ ARC_RegisterContents match_value,
+ ARC_RegisterContents match_mask,
+ ARC_RegisterContents control)
+{
+ unsigned int i;
+
+ /* Look for an unused actionpoint. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ /* Got one! */
+ if (!IN_USE(actionpoint))
+ {
+ /* Record its data. */
+ actionpoint->match_value = match_value;
+ actionpoint->match_mask = match_mask;
+ actionpoint->control = control;
+ actionpoint->is_exclude = FALSE;
+ actionpoint->length = length;
+
+ /* Try to set it on the target. */
+ if (set_actionpoint(actionpoint))
+ {
+ /* Now it is in use. */
+ actionpoint->usage = SINGLE;
+
+ /* Is it a breakpoint? */
+ if (bpt)
+ {
+ /* We have not actually saved code from the target program. */
+ bpt->shadow_len = 0;
+ bpt->placed_size = (int) actionpoint->length;
+ }
+
+ return SUCCESS;
+ }
+ }
+ }
+
+ /* Failed: no free actionpoints. */
+// warning(_("no actionpoints available"));
+ return FAILURE;
+}
+
+
+/* Restore the actionpoints on the target according to their current settings.
+ If 'clear_unused' is TRUE, any actionpoints which are unused are explicitly
+ cleared on the target.
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+restore_actionpoints (Boolean clear_unused)
+{
+ unsigned int i;
+
+ /* Look at each of the actionpoints. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (IN_USE(actionpoint))
+ {
+ if (!set_actionpoint_on_target(actionpoint))
+ {
+ actionpoint->usage = NOT_IN_USE;
+ return FAILURE;
+ }
+ }
+ else if (clear_unused)
+ {
+ if (!clear_actionpoint_from_target (actionpoint))
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
+
+/* Find a number of unused actionpoints whose numbers (0..7) lie in a contiguous
+ range (allowing for wraparound of the numbers, i.e. % 8).
+
+ Parameters:
+ required : the number of unused actionpoints required
+ from : set to the number (0..7) of the first actionpoint
+ compacted: set to TRUE if the currently used set of actionpoints
+ had to be compacted to give a contiguous range of unused
+ actionpoints
+
+ Returns TRUE if the required number was found, FALSE otherwise. */
+
+static Boolean
+find_unused_actionpoints (unsigned int required,
+ unsigned int *from,
+ Boolean *compacted)
+{
+ unsigned int unused = 0;
+ unsigned int first_unused = 0;
+ unsigned int i;
+
+ /* How many slots are not currently used? */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (!IN_USE(actionpoint))
+ unused++;
+ }
+
+ DEBUG("%u actionpoints unused, %u required\n", unused, required);
+
+ if (required > unused)
+ return FALSE;
+
+ /* When used in pairs or quads, the action points wrap around, e.g. a pair
+ might be actionpoints (3, 0), if the target has 4 actionpoints; and a
+ quad might be (6, 7, 0, 1), if the target has 8 actionpoints. */
+
+ /* First try to find 'required' contiguous unused slots. */
+ for (i = 0; i < num_actionpoints + required - 2; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i % num_actionpoints];
+
+ if (IN_USE(actionpoint))
+ {
+ /* The first unused one MAY be the next one after this one. */
+ first_unused = i + 1;
+ }
+ else
+ {
+ DEBUG("%u: AP%u is unused\n", i, i % num_actionpoints);
+
+ if (i - first_unused + 1 >= required)
+ {
+ /* A sufficiently large sequence of unused actionpoints has been
+ found. */
+ *from = first_unused % num_actionpoints;
+ *compacted = FALSE;
+ return TRUE;
+ }
+ }
+ }
+
+ DEBUG("compacting array\n");
+
+ /* There are sufficient unused slots, but they are not contiguous - so move
+ all the used ones towards the start of the array so that all the unused
+ ones are contiguous at the end of the array. */
+ first_unused = MAX_ACTION_POINTS;
+
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (IN_USE(actionpoint))
+ {
+ if (first_unused != MAX_ACTION_POINTS)
+ {
+ DEBUG("moving %u to %u\n", i, first_unused);
+
+ /* Move the used one into the unused slot. */
+ actionpoints[first_unused] = *actionpoint;
+
+ actionpoint->usage = NOT_IN_USE;
+
+ /* The first unused entry in the array is now the next one after
+ it - this is true whether that next one was the used one that
+ has just been moved, or was the next in a sequence of unused
+ entries. */
+ first_unused++;
+ }
+ }
+ else if (first_unused == MAX_ACTION_POINTS)
+ {
+ /* This one really is the first unused one we have found. */
+ first_unused = i;
+ }
+ }
+
+ *from = num_actionpoints - unused;
+
+ DEBUG("from = %u\n", *from);
+
+ *compacted = TRUE;
+ return TRUE;
+}
+
+
+/* Insert an actionpoint group to cover a range of target memory.
+
+ Parameters:
+ length : the length in bytes of the range
+ number : the number of actionpoints required
+ match_value: the values for the actionpoint value (AMV) aux registers
+ match_mask : the values for the actionpoint mask (AMM) aux registers
+ control : the value for the actionpoint control (AC) aux registers
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+insert_actionpoint_group (unsigned int length,
+ unsigned int number,
+ ARC_RegisterContents match_value[],
+ ARC_RegisterContents match_mask[],
+ ARC_RegisterContents control)
+{
+ /* For 2 actionpoints, we can use a pair; for 3 or 4, we must use a quad. */
+ unsigned int required = (number == 2) ? 2 : 4;
+ unsigned int first_free;
+ Boolean is_pair = (required == 2);
+ Boolean compacted;
+
+ gdb_assert(2 <= number && number <= 4);
+
+ /* Try to find the required number of unused actionpoints. */
+ if (find_unused_actionpoints(required, &first_free, &compacted))
+ {
+ ARC_ActionPoint *actionpoint[MAX_ACTION_POINTS_IN_GROUP];
+ unsigned int i;
+
+ /* Get an array of pointers to the data for those actionpoints. */
+ for (i = 0; i < required; i++)
+ actionpoint[i] = &actionpoints[(first_free + i) % num_actionpoints];
+
+ actionpoint[0]->length = length;
+ actionpoint[0]->is_exclude = FALSE;
+
+ /* The Control register for the first actionpoint in the group must be
+ set to indicate whether the group is a pair or a quad. */
+ actionpoint[0]->usage = (is_pair) ? PAIR_0 : QUAD_0;
+ actionpoint[0]->match_value = match_value[0];
+ actionpoint[0]->match_mask = match_mask[0];
+ actionpoint[0]->control = control | ((is_pair) ? AP_PAIR : AP_QUAD);
+
+ /* All subsequent actionpoints in the group have exclusive rather than
+ inclusive address ranges. */
+ control &= ~AP_MODE_TRIGGER_IN_RANGE;
+ control |= AP_MODE_TRIGGER_OUTSIDE_RANGE;
+
+ for (i = 1; i < number; i++)
+ {
+ actionpoint[i]->usage = actionpoint[0]->usage + i;
+ actionpoint[i]->match_value = match_value[i];
+ actionpoint[i]->match_mask = match_mask[i];
+ actionpoint[i]->control = control;
+ actionpoint[i]->length = 0;
+ actionpoint[i]->is_exclude = TRUE;
+ }
+
+ /* If we are using only 3 of the 4 actionpoints in a quad, the 4th one
+ must be disabled (or we could just make it the same as one of the
+ other exclusive ones). */
+ if (number == 3)
+ {
+ ARC_ActionPoint *disabled = actionpoint[3];
+
+ disabled->usage = QUAD_3;
+ disabled->match_value = 0;
+ disabled->match_mask = 0;
+ disabled->control = AP_TRANSACTION_TYPE_DISABLED;
+ disabled->length = 0;
+ }
+
+ /* If we had to compact the array of actionpoints in order to get a
+ long enough contiguous sequence of unused entries, then set ALL of
+ the actionpoints that are now in use, and explicitly clear all that
+ are not in use (this is simplest!). */
+ if (compacted)
+ return restore_actionpoints(TRUE);
+
+ /* Otherwise, just set the ones for the group, which were previously
+ unused. */
+ for (i = 0; i < required; i++)
+ if (!set_actionpoint(actionpoint[i]))
+ return FAILURE;
+
+ return SUCCESS;
+ }
+
+// warning(_("insufficient actionpoints available"));
+ return FAILURE;
+}
+
+
+/* Insert a h/w breakpoint or watchpoint to cover a range of target memory.
+
+ Parameters:
+ address : the start address of the range
+ control : the value for the actionpoint control (AC) aux register
+ length : the length in bytes of the range
+ bpt : the information describing the breakpoint (NULL for a watchpoint)
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+insert_range (ARC_RegisterContents address,
+ ARC_RegisterContents control,
+ unsigned int length,
+ struct bp_target_info *bpt)
+{
+ /* At most 4 actionpoints can be connected (as a quad). */
+ ARC_Address actionpoint_value[MAX_ACTION_POINTS_IN_GROUP];
+ ARC_Word actionpoint_mask [MAX_ACTION_POINTS_IN_GROUP];
+ unsigned int actionpoints_needed;
+
+ /* Work out how many actionpoints would be required to exactly cover the
+ given memory range. */
+ actionpoints_needed = map_actionpoints(address,
+ length,
+ actionpoint_value,
+ actionpoint_mask);
+
+ if (actionpoints_needed == 1)
+ return insert_actionpoint(bpt,
+ length,
+ actionpoint_value[0],
+ actionpoint_mask[0],
+ control);
+
+ if (actionpoints_needed <= MAX_ACTION_POINTS_IN_GROUP)
+ return insert_actionpoint_group(length,
+ actionpoints_needed,
+ actionpoint_value,
+ actionpoint_mask,
+ control);
+
+ warning (_("break/watchpoint would require %u linked actionpoints, "
+ "but at most %u actionpoints may be linked together"),
+ actionpoints_needed, MAX_ACTION_POINTS_IN_GROUP);
+
+ return FAILURE;
+}
+
+
+/* Remove an actionpoint from a range of target memory.
+
+ Parameters:
+ address : the start address of the range
+ length : the length in bytes of the range
+
+ Returns -1 for failure, 0 for success. */
+
+static int
+remove_actionpoint (CORE_ADDR address, unsigned int length)
+{
+ unsigned int i;
+
+ /* Look at all the actionpoints. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (IN_USE(actionpoint) && !actionpoint->is_exclude)
+ {
+ if (actionpoint->match_value == (ARC_RegisterContents) address &&
+ actionpoint->length == length)
+ {
+ unsigned int points;
+ unsigned int p;
+
+ /* Is this the first of a pair or quad? */
+ if ((actionpoint->control & AP_PAIR) != 0)
+ points = 2;
+ else if ((actionpoint->control & AP_QUAD) != 0)
+ points = 4;
+ else
+ points = 1;
+
+// DEBUG("points = %u\n", points);
+
+ for (p = 1; p < points; p++)
+ {
+ ARC_ActionPoint *next = &actionpoints[(i + p) % num_actionpoints];
+
+ if (clear_actionpoint_from_target (next))
+ next->usage = NOT_IN_USE;
+ else
+ return FAILURE;
+ }
+
+ if (clear_actionpoint_from_target (actionpoint))
+ {
+ actionpoint->usage = NOT_IN_USE;
+ return SUCCESS;
+ }
+
+ break;
+ }
+ }
+ }
+
+ /* Failed: could not find actionpoint, or could not clear it. */
+ return FAILURE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions called from outside this module */
+/* -------------------------------------------------------------------------- */
+
+/* Check if we can set a hardware watchpoint of type TYPE. TYPE is
+ one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint, or
+ bp_hardware_breakpoint. COUNT is the number of such watchpoints used so far
+ (including this one). OTHERTYPE is the total number of hardware breakpoints
+ and watchpoints of other types that are "already" set (0 if type == bp_hardware_breakpoint).
+
+ Result: 0 if hardware watchpoints are not supported
+ -1 if there are not enough hardware watchpoints
+ 1 if there are enough hardware watchpoints
+
+ N.B. this is not what is stated in target.h, but it does conform to the use
+ made of this function's result in breakpoint.c! */
+
+static int
+arc_debug_can_use_hw_breakpoint (int type, int count, int othertype)
+{
+ ENTERARGS("type %d, count %d", type, count);
+
+ if (num_actionpoints == 0)
+ return 0;
+
+ /* N.B. this will sometimes give a "false positive" result, i.e. that there
+ sufficient actionpoints available when in fact there are not: the
+ ARC processor actionpoints can be used for all of the types, but gdb
+ assumes that there are separate sets of resources for breakpoints
+ and watchpoints, and when asking for a breakpoint does not give the
+ number of watchpoints "already" set.
+
+ It is not possible simply to check how many actionpoints are currently
+ set, as gdb does not actually set the breakpoints and watchpoints
+ until program execution is started or resumed - so when this function
+ is called, none are actually set.
+
+ Also, the breakpoints and watchpoints may require pairs or quads of
+ actionpoints, rather than single actionpoints, and this will not be
+ known until they are set, and their addresses and ranges are known! */
+ return ((int) num_actionpoints >= count + othertype) ? 1 : -1;
+}
+
+
+/* Insert a hardware breakpoint on the target.
+ Returns 0 for success, -1 for failure. */
+
+static int
+arc_debug_insert_hw_breakpoint (struct bp_target_info *bpt)
+{
+ ARC_RegisterContents control = AP_TARGET_INSTRUCTION_ADDRESS |
+ AP_TRANSACTION_TYPE_READ |
+ AP_MODE_TRIGGER_IN_RANGE |
+ AP_ACTION_BREAK;
+
+ ENTERARGS("0x%x : %u", (unsigned int) bpt->placed_address, bpt->range);
+
+ /* Is it a range breakpoint? */
+ if (bpt->range)
+ return insert_range((ARC_RegisterContents) bpt->placed_address,
+ control,
+ bpt->range,
+ bpt);
+
+ /* No, just a single-instruction breakpoint? */
+ return insert_actionpoint(bpt,
+ HW_BP_SIZE,
+ (ARC_RegisterContents) bpt->placed_address,
+ 0, /* All bits of address. */
+ control);
+}
+
+
+/* Remove a hardware breakpoint from the target.
+ Returns 0 for success, non-zero for failure. */
+
+static int
+arc_debug_remove_hw_breakpoint (struct bp_target_info *bpt)
+{
+ unsigned int range = (bpt->range) ? bpt->range : HW_BP_SIZE;
+
+ ENTERARGS("0x%x : %u", (unsigned int) bpt->placed_address, range);
+
+ return remove_actionpoint(bpt->placed_address, range);
+}
+
+
+/* Insert a hardware watchpoint on the target.
+
+ Parameters:
+ addr : the start address of the region of memory to be watched
+ length: the length in bytes of the region of memory
+ type : 0 => write, 1 => read, 2 => read/write
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+arc_debug_insert_watchpoint (CORE_ADDR addr, int length, int type)
+{
+ ARC_RegisterContents control = AP_TARGET_LOAD_STORE_ADDRESS |
+ AP_MODE_TRIGGER_IN_RANGE |
+ AP_ACTION_BREAK;
+
+ ENTERARGS("0x%08X:%d %d", (unsigned int) addr, length, type);
+
+ gdb_assert(length > 0);
+
+ switch (type)
+ {
+ case 0:
+ control |= AP_TRANSACTION_TYPE_WRITE; break;
+ case 1:
+ control |= AP_TRANSACTION_TYPE_READ; break;
+ case 2:
+ control |= AP_TRANSACTION_TYPE_ACCESS; break;
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid watchpoint type: %d"), type);
+ }
+
+ return insert_range((ARC_RegisterContents) addr,
+ control,
+ (unsigned int) length,
+ NULL);
+}
+
+
+/* Remove a hardware watchpoint from the target.
+
+ Parameters:
+ addr : the start address of the region of memory being watched
+ length: the length in bytes of the region of memory
+ type : 0 => write, 1 => read, 2 => read/write
+
+ Returns 0 for success, non-zero for failure. */
+
+static int
+arc_debug_remove_watchpoint (CORE_ADDR addr, int length, int type)
+{
+ ENTERARGS("0x%x:%d %d", (unsigned int) addr, length, type);
+
+ return remove_actionpoint(addr, (unsigned int) length);
+}
+
+
+/* Returns non-zero if the execution of the target program has been stopped by
+ the trigger of a hardware watchpoint (i.e. on memory read or write), zero
+ otherwise. */
+
+static int
+arc_debug_stopped_by_watchpoint (void)
+{
+ unsigned int i;
+
+ ENTERMSG;
+
+ /* Look at all of the actionpoints. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (IN_USE(actionpoint) && actionpoint->triggered)
+ {
+ /* Is it a memory read or write actionpoint? */
+ if ((actionpoint->control & AP_TARGET_LOAD_STORE_ADDRESS) != 0)
+ {
+ DEBUG("actionpoint %d (load/store) triggered\n", i);
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Get the address of the data that was read/written causing a h/w watchpoint to
+ trigger; the address is returned in the '*addr' parameter.
+ Returns 0 for failure, non-zero for success. */
+
+static int
+arc_debug_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr)
+{
+ unsigned int i;
+
+ ENTERMSG;
+
+ /* Look at each of the actionpoints. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ DEBUG("AP%u: in use = %d, triggered = %d\n", i, IN_USE(actionpoint), actionpoint->triggered);
+
+ /* If this actionpoint has been triggered. */
+ if (IN_USE(actionpoint) && actionpoint->triggered)
+ {
+ /* Is it a memory read or write actionpoint? */
+ if ((actionpoint->control & AP_TARGET_LOAD_STORE_ADDRESS) != 0)
+ {
+ DEBUG("actionpoint %d (load/store) triggered by access at 0x%08X\n", i, actionpoint->point);
+
+ /* OK, got the data address! */
+ *addr = (CORE_ADDR) actionpoint->point;
+ return 1;
+ }
+ }
+ }
+
+ DEBUG("no watchpoint triggered\n");
+
+ return 0;
+}
+
+
+/* Can a h/w watchpoint 'length' bytes long be set at address 'addr' in target memory? */
+
+static int
+arc_debug_region_ok_for_hw_watchpoint (CORE_ADDR addr, int length)
+{
+ /* As far as we know, we can set a h/w watchpoint anywhere! */
+ return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* This function is called after a reset of the target has been performed (which
+ clears all the aux registers associated with actionpoints). It attempts to
+ restore all actionpoints to their pre-reset settings.
+
+ Returns TRUE if the actionpoints are restored, FALSE otherwise. */
+
+Boolean
+arc_restore_actionpoints_after_reset (void)
+{
+ return (restore_actionpoints(FALSE) == SUCCESS);
+}
+
+
+/* If the debug target supports actionpoints, set up the function pointers in
+ the given target operations structure to point to the functions which
+ implement the associated operations.
+
+ Returns TRUE if actionpoints are supported, FALSE otherwise. */
+
+Boolean
+arc_initialize_actionpoint_ops (struct target_ops *debug_ops)
+{
+ if (target_has_actionpoints())
+ {
+ debug_ops->to_can_use_hw_breakpoint = arc_debug_can_use_hw_breakpoint;
+ debug_ops->to_insert_hw_breakpoint = arc_debug_insert_hw_breakpoint;
+ debug_ops->to_remove_hw_breakpoint = arc_debug_remove_hw_breakpoint;
+ debug_ops->to_insert_watchpoint = arc_debug_insert_watchpoint;
+ debug_ops->to_remove_watchpoint = arc_debug_remove_watchpoint;
+ debug_ops->to_stopped_by_watchpoint = arc_debug_stopped_by_watchpoint;
+ debug_ops->to_stopped_data_address = arc_debug_stopped_data_address;
+ debug_ops->to_region_ok_for_hw_watchpoint = arc_debug_region_ok_for_hw_watchpoint;
+
+ /* This is the default, but just to make it clear that watchpoints must
+ be cleared before execution can resume. */
+ debug_ops->to_have_continuable_watchpoint = 0;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Display all the target actionpoints. */
+
+void
+arc_display_actionpoints (void)
+{
+ unsigned int i;
+
+ char *targets[8] =
+ {
+ _("Instruction Address"),
+ _("Instruction Data"),
+ _("Load/Store Address"),
+ _("Load/Store Data"),
+ _("Aux Register Address"),
+ _("Aux Register Data"),
+ _("Ext Parameter 0"),
+ _("Ext Parameter 1")
+ };
+
+ char *transactions[4] =
+ {
+ _("disabled"),
+ _("write"),
+ _("read"),
+ _("read/write")
+ };
+
+ char *explanations[8] =
+ {
+ _("execution of instruction at address"),
+ _("execution of instruction"),
+ _("load or store of data at address"),
+ _("load or store of data"),
+ _("read or write of auxiliary register"),
+ _("read or write of auxiliary register contents"),
+ _("value"),
+ _("value")
+ };
+
+
+ /* Look at each of the actionpoints in turn. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ if (IN_USE(actionpoint))
+ {
+ ARC_RegisterContents control = actionpoint->control;
+ const unsigned int targ = (control & AP_TARGET_MASK ) >> AP_TARGET_SHIFT;
+ const unsigned int trans = (control & AP_TRANSACTION_TYPE_MASK) >> AP_TRANSACTION_TYPE_SHIFT;
+ const char *target = targets [targ];
+ const char *type = transactions[trans];
+ const char *mode = ((control & AP_MODE_MASK) ==
+ AP_MODE_TRIGGER_OUTSIDE_RANGE) ? _("outside range") : _("in range");
+ const char *action = ((control & AP_ACTION_MASK) ==
+ AP_ACTION_BREAK) ? _("break") : _("raise exception");
+ const char *usage;
+
+ switch (actionpoint->usage)
+ {
+ case SINGLE: usage = _(" "); break;
+ case PAIR_0: usage = _(" (Pair 0)"); break;
+ case PAIR_1: usage = _(" (Pair 1)"); break;
+ case QUAD_0: usage = _(" (Quad 0)"); break;
+ case QUAD_1: usage = _(" (Quad 1)"); break;
+ case QUAD_2: usage = _(" (Quad 2)"); break;
+ case QUAD_3: usage = _(" (Quad 3)"); break;
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid AP usage: %u"), actionpoint->usage);
+ return;
+ }
+
+ printf_filtered(_("AP %u%s :: "), i, usage);
+
+ printf_filtered( _("value : %08X\n"), actionpoint->match_value);
+ printf_filtered( _(" mask : %08X\n"), actionpoint->match_mask);
+ if ((control & AP_TRANSACTION_TYPE_MASK) == AP_TRANSACTION_TYPE_DISABLED)
+ printf_filtered(_(" control : %08X disabled\n"), actionpoint->control);
+ else
+ printf_filtered(_(" control : %08X %s, %s on %s %s\n"), actionpoint->control, target, action, type, mode);
+ if (actionpoint->triggered)
+ {
+ const char *explain = explanations[targ];
+
+ printf_filtered(_(" triggered by %s %08x\n"), explain, actionpoint->point);
+ }
+ }
+ else
+ {
+ printf_filtered(_("AP %u :: not in use\n"), i);
+ }
+ }
+}
+
+
+/* This function is called as soon as execution of the target program has halted.
+ It checks whether the halt is due to an actionpoint trigger, and, if so,
+ identifies the actionpoint that has been triggered and finds the address (code
+ or data) at which memory access (read, write or execute) has caused the trigger. */
+
+void
+arc_target_halted (void)
+{
+ ARC_RegisterContents debug;
+
+ ENTERMSG;
+
+ if (arc_read_jtag_aux_register(arc_debug_regnum, &debug, TRUE))
+ {
+ /* If the bit indicating that an actionpoint has halted the processor is
+ set. */
+ if ((debug & DEBUG_ACTIONPOINT_HALT) != 0)
+ {
+ /* Get the Actionpoints Status Register from the DEBUG register:
+ this contains one bit for each actionpoint in the processor
+ configuration. */
+ unsigned int ASR = (debug & DEBUG_ACTIONPOINT_STATUS) >>
+ DEBUG_ACTIONPOINT_STATUS_SHIFT;
+ unsigned int i;
+
+ /* Now look at each of the actionpoints. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ actionpoint->triggered = FALSE;
+
+ /* Is the ASR bit for this actionpoint set? */
+ if ((ASR & 1) != 0)
+ {
+ if (IN_USE(actionpoint))
+ {
+ actionpoint->triggered = TRUE;
+
+ /* The AMV register for this action point has been
+ updated with the address to which access has caused
+ the actionpoint to trigger. */
+ (void) arc_read_jtag_aux_register(ARC_HW_AMV_REGNUM(AP_INSTANCE(actionpoint)),
+ &actionpoint->point,
+ TRUE);
+ }
+ else
+ internal_error (__FILE__, __LINE__, _("actionpoint %u triggered but not set"), i);
+ }
+
+ ASR >>= 1;
+ }
+ }
+ }
+}
+
+
+/* For debugging - just give the values. */
+
+void
+arc_dump_actionpoints (const char *message)
+{
+ unsigned int i;
+
+ DEBUG("%s\n", message);
+
+ /* Look at each of the actionpoints in turn. */
+ for (i = 0; i < num_actionpoints; i++)
+ {
+ ARC_ActionPoint *actionpoint = &actionpoints[i];
+
+ DEBUG("slot %u:: ", i);
+
+ if (IN_USE(actionpoint))
+ {
+ DEBUG( "value : %08X\n", actionpoint->match_value);
+ DEBUG(" mask : %08X\n", actionpoint->match_mask);
+ DEBUG(" control : %08X\n", actionpoint->control);
+ DEBUG(" triggered: %u\n", actionpoint->triggered);
+ DEBUG(" point : %08x\n", actionpoint->point);
+ }
+ else
+ {
+ DEBUG("not in use\n");
+ }
+ }
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-jtag-actionpoints.h b/gdb/arc-jtag-actionpoints.h
new file mode 100644
index 00000000000..741d8696120
--- /dev/null
+++ b/gdb/arc-jtag-actionpoints.h
@@ -0,0 +1,68 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines the interface to hardware actionpoints in the */
+/* ARC processor. */
+/* */
+/* Usage: */
+/* Once the connection to the target has been established, the function */
+/* arc_initialize_actionpoint_ops should be called: this will update the */
+/* debug_ops structure according to the support provided by the ARC */
+/* processor in the target for hardware breakpoints and watchpoints. */
+/* */
+/* The function arc_restore_actionpoints_after_reset should be called */
+/* after the target board has been reset, in order to re-establish any */
+/* actionpoints that have been set, as they will have been cleared by */
+/* the reset; it returns TRUE if successful. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_JTAG_ACTIONPOINTS_H
+#define ARC_JTAG_ACTIONPOINTS_H
+
+/* gdb header files */
+#include "defs.h"
+#include "target.h"
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+Boolean arc_initialize_actionpoint_ops (struct target_ops *debug_ops);
+
+Boolean arc_restore_actionpoints_after_reset (void);
+
+void arc_target_halted (void);
+
+void arc_display_actionpoints (void);
+
+
+/* For debugging. */
+void arc_dump_actionpoints (const char *message);
+
+#endif /* ARC_JTAG_ACTIONPOINTS_H */
+/******************************************************************************/
diff --git a/gdb/arc-jtag-ops.c b/gdb/arc-jtag-ops.c
index 0a237f69d30..54631b92efd 100644
--- a/gdb/arc-jtag-ops.c
+++ b/gdb/arc-jtag-ops.c
@@ -1,1229 +1,1496 @@
-/* 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.
- Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
+ Contributed by ARC International (www.arc.com)
- Authors:
- Sameer Dhavale <sameer.dhavale@codito.com>
- Soam Vasani <soam.vasani@codito.com>
+ Author:
+ Sameer Dhavale <sameer.dhavale@codito.com>
+ Soam Vasani <soam.vasani@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.
-*/
+ 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 implements debug access to an ARC processor via its JTAG */
+/* interface. */
+/* */
+/* See */
+/* ARCompact Instruction Set Architecture */
+/* Programmer's Reference (5115-018) */
+/* */
+/* for a description of ARC processor architecture (in particular */
+/* the auxiliary registers and the halting procedure); */
+/* */
+/* ARC 700 External Interfaces */
+/* Reference (5117-013) */
+/* */
+/* for a description of the JTAG interface (in particular the Test */
+/* Access Port Controller (TAPC) state machine). */
+/* */
+/* The JTAG interface is accessed by three parallel ports: control, data */
+/* and status. Data is read from or written to these ports one byte at a */
+/* at a time, using a GPIO (General Purpose Input/Output) driver. */
+/* */
+/* The TDI and TMS signals are written to the data port. */
+/* The TCK signal is written to the control port. */
+/* The TDO signal is read from the status port. */
+/* */
+/* Host/Target Byte Order: */
+/* The core and auxiliary register contents read from or written to the */
+/* JTAG interface are ALWAYS in little-endian format, regardless of the */
+/* endianness of the target processor. */
+/* */
+/******************************************************************************/
+
+/* system header files */
#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
+#include <string.h>
#include <errno.h>
-#include <sys/io.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <assert.h>
+#include <unistd.h>
+#include <byteswap.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "gdb_assert.h"
+
+/* ARC header files */
+#include "arc-gpio.h"
+#include "arc-jtag.h"
#include "arc-jtag-ops.h"
-#include "gpio.h"
-#include <signal.h>
-#include <defs.h>
-#include <sys/ioctl.h>
-#include "arc-tdep.h"
-#define printf printf_filtered
+#include "arc-support.h"
-unsigned int arcjtag_retry_count = 50;
+/* -------------------------------------------------------------------------- */
+/* conditional compilation flags */
+/* -------------------------------------------------------------------------- */
+/* We would really like to optimise the use of the JTAG Data Register by
+ loading a word into it only if that word differs from the last word loaded;
+ but there seems to be undocumented behaviour of the JTAG mechanism in that
+ the Data Register is altered after a write operation! See ARC Bug #93814. */
+#define JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
-/* ------------------------------------ */
-/* For ARC jtag Cable */
-/* */
-/* Pin no. Signal Word , Bit */
-/* */
-/* - TRST */
-/* 8 TMS Data 6 */
-/* 1 TCK Control 0 */
-/* 9 TDI Data 7 */
-/* 13 TDO Status 4 */
+/* Define this if you wish to check the whether the contents of the JTAG Data
+ Register are corrupted by write operations. */
+//#define CHECK_JTAG_DATA_REGISTER
+/* Define this if you wish to perform low-level debugging of the JTAG state
+ machine emulated in this module (this should not be necessary). */
+//#define STATE_MACHINE_DEBUG
-#define JTAG_TRST 0x00 /* not there */
-#define JTAG_TMS 0x40 /* data port */
-#define JTAG_TCK 0x01 /* control port. Driven Low. */
-#define JTAG_TDI 0x80 /* data port */
-#define JTAG_TDO 0x10 /* status port */
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
-/* ------------------------------------ */
+/* Sizes of quantities. */
+#define BITS_IN_COMMAND_CODE 4
+#define BITS_IN_REGISTER_CODE 4
-/* */
-#define A4_HALT_VALUE 0x02000000
-#define ARC700_HALT_VALUE 0x1
+typedef unsigned int Bit; /* Only LSB of word is used. */
+typedef unsigned int JTAG_RegisterContents;
-/* Parallel port i/o addr. (LPT1) */
-#define DATA_PORT 0x378
-#define STATUS_PORT 0x379
-#define CONTROL_PORT 0x37A
+typedef enum
+{
+ MSB_FIRST,
+ MSB_LAST
+} Order;
-unsigned char tapc_dataport=0, tapc_statusport=0, tapc_controlport=0x1;
-int fd;
-struct GPIO_ioctl jtag_ioctl;
-sigset_t block_mask;
-enum AA3SSPinState
- {
- READ_FROM_AA3 = 0,
- WRITE_TO_AA3 = 1
- };
-enum AA3SSPinState rw_flag;
+typedef enum
+{
+ Memory,
+ Register
+} JTAG_TransactionType;
+typedef enum
+{
+ STALLED,
+ FAILURE,
+ READY,
+ NOT_READY
+} JTAG_TransactionStatus;
-struct jtag_ops arc_jtag_ops;
-static enum ARCProcessorVersion ARCProcessor = UNSUPPORTED;
+/* Only these JTAG registers are currently used. */
+typedef enum
+{
+ JTAG_STATUS_REGISTER = 0x8,
+ JTAG_TRANSACTION_COMMAND_REGISTER = 0x9,
+ JTAG_ADDRESS_REGISTER = 0xA,
+ JTAG_DATA_REGISTER = 0xB,
+} JTAG_Register;
-/* Sanity check to give error if jtag is not opened at all. */
-static void
-check_and_raise_error_if_jtag_closed (void)
+#ifdef STATE_MACHINE_DEBUG
+typedef enum
+{
+ UNDEFINED,
+ TEST_LOGIC_RESET,
+ RUN_TEST_IDLE,
+ SELECT_DR_SCAN,
+ CAPTURE_DR,
+ SHIFT_DR,
+ EXIT1_DR,
+ PAUSE_DR,
+ EXIT2_DR,
+ UPDATE_DR,
+ SELECT_IR_SCAN,
+ CAPTURE_IR,
+ SHIFT_IR,
+ EXIT1_IR,
+ PAUSE_IR,
+ EXIT2_IR,
+ UPDATE_IR,
+ NUMBER_OF_STATES /* An end-marker, not a state. */
+} JTAG_ControllerState;
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------- */
+/* For ARC JTAG Cable */
+/* */
+/* Pin no. Signal Port Bit */
+/* */
+/* - TRST */
+/* 8 TMS Data 6 */
+/* 1 TCK Control 0 */
+/* 9 TDI Data 7 */
+/* 13 TDO Status 4 */
+/* -------------------------------------- */
+
+/* Bit masks for signals written to parallel ports. */
+
+#define JTAG_TRST 0 /* not there */
+#define JTAG_TMS (1 << 6) /* on Data port */
+#define JTAG_TCK (1 << 0) /* on Control port (driven low) */
+#define JTAG_TDI (1 << 7) /* on Data port */
+#define JTAG_TDO (1 << 4) /* on Status port */
+
+
+/* Commands which can be written to the JTAG Transaction Command Register. */
+#define WRITE_MEMORY_LOCATION 0x0
+#define WRITE_CORE_REGISTER 0x1
+#define WRITE_AUX_REGISTER 0x2
+#define NOP 0x3
+#define READ_MEMORY_LOCATION 0x4
+#define READ_CORE_REGISTER 0x5
+#define READ_AUX_REGISTER 0x6
+
+
+/* Gives the endianness of the target processor. */
+static Boolean target_is_big_endian;
+
+/* These accumulate the bit masks to be written to the data and control ports. */
+static Byte data_port_value, control_port_value;
+
+/* Variables for tracking the contents of the JTAG Address and Transaction
+ Command registers. */
+static JTAG_RegisterContents address_register_contents;
+static JTAG_RegisterContents command_register_contents;
+static Boolean address_register_contents_known;
+static Boolean command_register_contents_known;
+
+
+#ifdef STATE_MACHINE_DEBUG
+/* This table encodes all possible transitions of the JTAG Test Access Port
+ (TAP) Controller State Machine: for each state, the transition to one of two
+ possible next states is determined by whether a 0 bit or a 1 bit is written
+ as the JTAG TMS interface signal. */
+static const JTAG_ControllerState transitions[NUMBER_OF_STATES][2] =
{
- if( arc_jtag_ops.jtag_status == JTAG_CLOSED )
- error ("JTAG connection is closed. Use target arcjtag first\n");
+/* 0 1 */
+/* UNDEFINED */ { UNDEFINED, UNDEFINED },
+/* TEST_LOGIC_RESET */ { RUN_TEST_IDLE, TEST_LOGIC_RESET },
+/* RUN_TEST_IDLE */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
+/* SELECT_DR_SCAN */ { CAPTURE_DR, SELECT_IR_SCAN },
+/* CAPTURE_DR */ { SHIFT_DR, EXIT1_DR },
+/* SHIFT_DR */ { SHIFT_DR, EXIT1_DR },
+/* EXIT1_DR */ { PAUSE_DR, UPDATE_DR },
+/* PAUSE_DR */ { PAUSE_DR, EXIT2_DR },
+/* EXIT2_DR */ { SHIFT_DR, UPDATE_DR },
+/* UPDATE_DR */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
+/* SELECT_IR_SCAN */ { CAPTURE_IR, TEST_LOGIC_RESET },
+/* CAPTURE_IR */ { SHIFT_IR, EXIT1_IR },
+/* SHIFT_IR */ { SHIFT_IR, EXIT1_IR },
+/* EXIT1_IR */ { PAUSE_IR, UPDATE_IR },
+/* PAUSE_IR */ { PAUSE_IR, EXIT2_IR },
+/* EXIT2_IR */ { SHIFT_IR, UPDATE_IR },
+/* UPDATE_IR */ { RUN_TEST_IDLE, SELECT_DR_SCAN },
+};
+
+/* The current state of the TAP Controller State Machine. */
+static JTAG_ControllerState current_state = UNDEFINED;
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* This structure holds the operations and data exported by this module. */
+JTAG_Operations arc_jtag_ops;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+#undef DEBUG
+#endif
+
+#define DEBUG(...) \
+ if (arc_jtag_ops.state_machine_debug) fprintf_unfiltered(gdb_stdlog, __VA_ARGS__)
+
+
+#ifdef STATE_MACHINE_DEBUG
+#define SET_STATE(s) set_state(s)
+#define NEXT_STATE(b) next_state(b)
+#define CHANGE_STATE(x, s) change_state(x, s)
+#define STATE_IS(s) gdb_assert(current_state == s)
+#define STATE_IS_EITHER(s1, s2) gdb_assert(current_state == s1 || \
+ current_state == s2)
+#define STATE_IS_ONE_OF(s1, s2, s3) gdb_assert(current_state == s1 || \
+ current_state == s2 || \
+ current_state == s3)
+#else
+#define SET_STATE(s)
+#define NEXT_STATE(b)
+#define CHANGE_STATE(x, s) tapc_TMS(x)
+#define STATE_IS(s)
+#define STATE_IS_EITHER(s1, s2)
+#define STATE_IS_ONE_OF(s1, s2, s3)
+#endif
+
+
+#define IS_WORD_ALIGNED(addr) ((addr) % BYTES_IN_WORD == 0)
+#define BYTE(val) (Byte) ((val) & 0xFF)
+
+/* This is more efficient than memcpy(to, from, BYTES_IN_WORD). */
+#define COPY_WORD(to, from) { ((Byte*) to)[0] = ((Byte*) from)[0]; \
+ ((Byte*) to)[1] = ((Byte*) from)[1]; \
+ ((Byte*) to)[2] = ((Byte*) from)[2]; \
+ ((Byte*) to)[3] = ((Byte*) from)[3]; }
+
+
+/* -------------------------------------------------------------------------- */
+/* forward declarations */
+/* -------------------------------------------------------------------------- */
+
+static void tapc_TMS (Bit x);
+static void set_interface (JTAG_Status status);
+static void interface_is_closed (void);
+static JTAG_RegisterContents read_jtag_reg (JTAG_Register regnum,
+ unsigned int num_data_bits);
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* 1) debug functions */
+/* -------------------------------------------------------------------------- */
+
+/* Debug function. */
+
+static const char*
+JTAG_register_name (JTAG_Register r)
+{
+ switch (r)
+ {
+ case JTAG_STATUS_REGISTER : return "Status";
+ case JTAG_TRANSACTION_COMMAND_REGISTER : return "Transaction Command";
+ case JTAG_ADDRESS_REGISTER : return "Address";
+ case JTAG_DATA_REGISTER : return "Data";
+ default: internal_error(__FILE__, __LINE__, _("invalid JTAG register %d"), r);
+ }
}
-/* Initializations for GPIO interface */
-static int
-gpio_setup (void)
+/* Debug function. */
+
+static const char*
+JTAG_TransactionStatus_Image (JTAG_TransactionStatus value)
{
- fd=open("//dev//gpio",O_RDWR);
- ioctl(fd,GPIO_IOC_HARDRESET);
- ioctl(fd,GPIO_IOC_SET_PORT_BASE,0x378);
- jtag_ioctl.inlen=0;
- jtag_ioctl.outlen=0;
- jtag_ioctl.inbuf=(unsigned char *)xmalloc(2*sizeof(unsigned char));
- jtag_ioctl.outbuf=(unsigned char *)xmalloc(2*sizeof(unsigned char));
- return 0;
+ switch (value)
+ {
+ case STALLED : return "STALLED";
+ case FAILURE : return "FAILURE";
+ case READY : return "READY";
+ case NOT_READY: return "NOT READY";
+ default: internal_error(__FILE__, __LINE__, _("invalid JTAG transaction status %d"), value);
+ }
}
-void gpio_write(unsigned int port, unsigned char *data)
+
+#ifdef STATE_MACHINE_DEBUG
+/* Debug function. */
+
+static const char*
+JTAG_ControllerState_Image (JTAG_ControllerState state)
{
- jtag_ioctl.inlen=2;
- jtag_ioctl.inbuf[1]=*data;
- switch(port)
+ switch (state)
{
- case DATA_PORT:
- jtag_ioctl.inbuf[0]=0;
- break;
-
- case STATUS_PORT:
- jtag_ioctl.inbuf[0]=1;
- break;
-
- case CONTROL_PORT:
- jtag_ioctl.inbuf[0]=2;
- break;
-
- default:
- error("Invalid port\n");
+ case UNDEFINED : return "<undefined> ";
+ case TEST_LOGIC_RESET: return "Test-Logic-Reset";
+ case RUN_TEST_IDLE : return "Run-Test/Idle ";
+ case SELECT_DR_SCAN : return "Select-DR-Scan ";
+ case CAPTURE_DR : return "Capture-DR ";
+ case SHIFT_DR : return "Shift-DR ";
+ case EXIT1_DR : return "Exit1-DR ";
+ case PAUSE_DR : return "Pause-DR ";
+ case EXIT2_DR : return "Exit2-DR ";
+ case UPDATE_DR : return "Update-DR ";
+ case SELECT_IR_SCAN : return "Select-IR-Scan ";
+ case CAPTURE_IR : return "Capture-IR ";
+ case SHIFT_IR : return "Shift-IR ";
+ case EXIT1_IR : return "Exit1-IR ";
+ case PAUSE_IR : return "Pause-IR ";
+ case EXIT2_IR : return "Exit2-IR ";
+ case UPDATE_IR : return "Update-IR ";
+ default : return "<invalid> ";
}
+}
+#endif
-
- if(ioctl(fd,GPIO_IOC_DO_IO,&jtag_ioctl))
- error("Failure writing to port 0x%x\n",port);
+#ifdef CHECK_JTAG_DATA_REGISTER
+/* Read back the contents of the JTAG Data Register, and check that the value
+ is what is expected, i.e. the last value that was written to that register. */
+
+static void
+check_Data_Register (ARC_Word expected)
+{
+ /* Read the data from the JTAG Data Register. */
+ ARC_Word actual = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD);
+
+ /* Is the data still in the register? */
+ if (actual != expected)
+ warning(_("JTAG Data Register: expected = %08X, actual = %08X\n"), expected, actual);
+ else
+ printf_unfiltered(_("word %08X is still in JTAG Data Register\n"), expected);
}
+#endif
-unsigned char gpio_read(unsigned int port)
-{
- //jtag_ioctl.inbuf[1]=tapc_statusport;
- jtag_ioctl.inlen=2;
- jtag_ioctl.outlen=1;
+/* -------------------------------------------------------------------------- */
+/* 2) helper functions for setting TMS / TCK / TDI */
+/* -------------------------------------------------------------------------- */
- switch(port)
- {
- case DATA_PORT:
- jtag_ioctl.inbuf[0]=0x80;
- break;
-
- case STATUS_PORT:
- jtag_ioctl.inbuf[0]=0x81;
- break;
-
- case CONTROL_PORT:
- jtag_ioctl.inbuf[0]=0x82;
- break;
-
- default:
- error("Invalid port\n");
- }
-
- if(ioctl(fd,GPIO_IOC_DO_IO,&jtag_ioctl))
- error("Failure reading from port 0x%x\n",port);
-
- return jtag_ioctl.outbuf[0];
+/* These functions set the accumulated values to be written out to the ports.
+ The final values are written only by doing the pulse, e.g. if TDI and TMS
+ are set/unset by subsequent calls, the last GPIO write operation performed
+ by those calls before the pulse writes the accumulated bit mask value to
+ the port (overwriting the values written by the preceding calls), and it
+ is this bit mask that is significant when the JTAG is clocked. */
+static void
+tapc_set_TMS (Bit x)
+{
+ Byte current_value = data_port_value;
+
+ if (x)
+ data_port_value |= JTAG_TMS;
+ else
+ data_port_value &= ~JTAG_TMS;
+ if (data_port_value != current_value)
+ gpio_write(DATA_PORT, data_port_value);
}
-/* Helper functions for setting
- TMS / TCK / TDI. Valid inputs
- are 1 and 0. The tapc_<tms/tck/tdi>
- functions set the internal values
- to be written out to the port. The
- final values are written only by doing
- the pulse.
- */
static void
-tapc_set_tms (char x)
+tapc_set_TDI (Bit x)
{
- if(x)
- tapc_dataport |= JTAG_TMS;
+ Byte current_value = data_port_value;
+
+ if (x)
+ data_port_value |= JTAG_TDI;
else
- tapc_dataport &= ~JTAG_TMS;
+ data_port_value &= ~JTAG_TDI;
- /* outb(tapc_dataport, DATA_PORT); */
- gpio_write(DATA_PORT,&tapc_dataport);
+ if (data_port_value != current_value)
+ gpio_write(DATA_PORT, data_port_value);
}
-/* Set TCK. */
static void
-tapc_set_tck (char x)
+tapc_set_TCK (Bit x)
{
- /* active low. The clock is active low. */
- if(!x)
- tapc_controlport |= JTAG_TCK;
+ /* The clock is active low. */
+ if (x)
+ control_port_value &= ~JTAG_TCK;
else
- tapc_controlport &= ~JTAG_TCK;
-
- if(rw_flag == READ_FROM_AA3)
- tapc_controlport |= 0x4;
- else
- tapc_controlport &= ~(0x4);
-
- /* outb(tapc_controlport, CONTROL_PORT); */
- gpio_write(CONTROL_PORT,&tapc_controlport);
+ control_port_value |= JTAG_TCK;
+
+ gpio_write(CONTROL_PORT, control_port_value);
}
+/* -------------------------------------------------------------------------- */
+/* 3) JTAG state machine handlers */
+/* -------------------------------------------------------------------------- */
+
+#ifdef STATE_MACHINE_DEBUG
+/* Debug function. Perform a state change to the given state. */
+
static void
-tapc_set_tdi (char x)
+set_state (JTAG_ControllerState new_state)
{
- if(x)
- tapc_dataport |= JTAG_TDI;
- else
- tapc_dataport &= ~JTAG_TDI;
-
- /* outb(tapc_dataport, DATA_PORT); */
- gpio_write(DATA_PORT,&tapc_dataport);
+ DEBUG("TAPC state: %s ====> %s\n",
+ JTAG_ControllerState_Image(current_state),
+ JTAG_ControllerState_Image(new_state));
+
+ current_state = new_state;
+
+ gdb_assert(current_state != UNDEFINED);
+}
+
+
+/* Debug function. Perform a state change from the current state according to
+ the transition specified by the given bit. */
+
+static void
+next_state (Bit x)
+{
+ current_state = (transitions[current_state][x]);
}
-/* Unused function clockdelay. Why not add a command
- that allows the user to set the clock delay ? */
+
+/* Debug function. Perform a state change from the current state according to
+ the transition specified by the given bit, and check that the new state is
+ as expected. */
static void
-clockdelay (void)
+change_state (Bit x, JTAG_ControllerState new_state)
{
- int i;
- //for (i=0; i<10; ++i)
-
- // usleep(0);
+ tapc_TMS(x);
+
+ gdb_assert(current_state == new_state);
}
+#endif /* STATE_MACHINE_DEBUG */
+
+
+/* Clock the JTAG on the ARC platform. */
-/* Clock the JTAG on the ARC platform. */
static void
tapc_pulse (void)
{
- /* Control 0 bit is active low */
- unsigned char temp;
- assert( (tapc_controlport & JTAG_TCK) ); // clock should be zero on entry
-
- /* outb(tapc_controlport & ~JTAG_TCK, CONTROL_PORT); */
- temp = tapc_controlport & ~JTAG_TCK;
- gpio_write(CONTROL_PORT,&temp);
- /* outb(tapc_controlport, CONTROL_PORT); */
- gpio_write(CONTROL_PORT,&tapc_controlport);
-
+ /* TCK control bit is active low. */
+ gdb_assert((control_port_value & JTAG_TCK) != (Byte) 0); /* Clock should be zero on entry. */
+
+ gpio_write(CONTROL_PORT, control_port_value & ~JTAG_TCK);
+ gpio_write(CONTROL_PORT, control_port_value);
}
-/* All the JTAG state machine handlers. */
-/* Reset the TAPC controller on the JTAG.
- */
+/* Reset the TAP Controller on the JTAG. */
+
static void
tapc_reset (void)
{
- /* from any state, these many ones should get us into "test-logic reset"
- */
- tapc_set_tms(1);
- tapc_set_tck(0); /* want rising edge */
+ ENTERMSG;
+
+ /* The Test Clock signal is active low (i.e. the signal is active when the
+ corresponding bit written to the control bit is 0; so initialize the bit
+ in the control port value to 1 so that the signal is initially not active. */
+ control_port_value = (Byte) JTAG_TCK;
+ data_port_value = (Byte) 0;
+
+ /* From any state, this many TCK pulses should get the controller into state
+ Test-Logic-Reset. */
+ tapc_set_TMS(1);
+ tapc_set_TCK(0); /* We want the rising edge. */
tapc_pulse();
tapc_pulse();
tapc_pulse();
tapc_pulse();
tapc_pulse();
tapc_pulse();
+
+ SET_STATE(TEST_LOGIC_RESET);
+
+ DEBUG("TAPC has been reset\n");
+
+ /* The reset has re-initialized all the JTAG registers. */
+ address_register_contents_known = FALSE;
+ command_register_contents_known = FALSE;
+
+ CHANGE_STATE(0, RUN_TEST_IDLE);
+
+ LEAVEMSG;
}
-/* Set the tms to the value of the bit and
- clock the jtag. */
+
+/* Set the TMS to the value of the bit and clock the JTAG.
+ This will cause the TAP Controller State Machine to move to another state. */
static void
-tapc_tms (char x)
+tapc_TMS (Bit x)
{
- tapc_set_tms(x);
+ tapc_set_TMS(x);
tapc_pulse();
+ NEXT_STATE(x);
}
-/* Read bit from the TDO of the JTAG. */
-static char
-tapc_readbit (void)
+
+/* Read a bit from the TDO of the JTAG. */
+
+static Bit
+tapc_readTDO (void)
{
- if(gpio_read(STATUS_PORT) & JTAG_TDO)
- return 1;
- else
- return 0;
+ Byte byte = gpio_read(STATUS_PORT);
+
+ /* Read from the status port. */
+ return ((byte & JTAG_TDO) != (Byte) 0) ? (Bit) 1 : (Bit) 0;
}
-/* Interface functions that use the below mentioned
- JTAG state machine handler functions.
-*/
+/* -------------------------------------------------------------------------- */
+/* 4) interface functions that use the JTAG state machine handler functions */
+/* -------------------------------------------------------------------------- */
-/* Shift one bit out on the JTAG TDI. */
-static char
-tapc_shiftbit (char x)
-{
- char read;
+/* Shift one bit out on the JTAG TDO and one bit in on the JTAG TDI. */
- //printf("tapc_shiftbit: Shifted %d\n", x);
+static Bit
+tapc_shift_bit (Bit out)
+{
+ Bit in = tapc_readTDO();
- read = tapc_readbit();
- tapc_set_tdi(x);
+ tapc_set_TDI(out);
tapc_pulse();
- return read;
+// DEBUG("%u (out) >>> %u (in)\n", out, in);
+
+ return in;
}
-/*
- * Shift N bits from to_write into TDI, and out from TDO into read.
- *
- * If msb_first=0, shift LSB first, starting from to_write[0], to_write[1],
- * etc.
-
- * If msb_first=1, shift to_write[-1] MSB first, then to_write[-2] etc.
- *
- * Must be called in Shift DR/IR state.
- * Leaves in Exit1 DR/IR state.
- */
+/* Shift N bits from to_write into TDI, and out from TDO into to_read.
+
+ If order == MSB_LAST, shift LSB first, starting from to_write[0], to_write[1],
+ etc.
+
+ If order == MSB_FIRST, shift to_write[N-1] MSB first, then to_write[N-2] etc.
+
+ Must be called in Shift DR/IR state.
+ Leaves in Exit1-DR/IR state. */
+
static void
-tapc_shiftnbits (int n,
- unsigned char *to_write,
- unsigned char *read,
- char msb_first)
+tapc_shift_N_bits (unsigned int n,
+ Byte *to_write,
+ Byte *to_read,
+ Order order)
{
- unsigned char outbyte, inbyte;
- int nbytes = (n-1)/8 + 1,limit=8;
- int i, j;
+ unsigned int nbytes = (n - 1) / BITS_IN_BYTE + 1;
+ unsigned int nbits = BITS_IN_BYTE;
+ unsigned int i, j;
+
+ ENTERARGS("shift %u bits", n);
- for(i=0; i < nbytes; ++i)
+ STATE_IS_EITHER(SHIFT_DR, SHIFT_IR);
+
+ for (i = 0; i < nbytes; i++)
{
- if(msb_first)
- outbyte = to_write[-1-i];
- else
- outbyte = to_write[i];
-
- inbyte = 0;
- /* should write a maximum of 8 bits */
- if(i == nbytes-1)
- limit = ((n-1) % 8) + 1;
-
- for(j = 0; j < limit; ++j)
- {
- unsigned char outbit, inbit;
-
- if(msb_first)
- outbit = !!(outbyte & 0x80);
- else
- outbit = outbyte & 1;
- /* the last bit of the last byte */
- /* transition to EXIT-1 state before last bit */
- if((i == nbytes-1)&&(j == limit-1))
- tapc_set_tms(1);
-
- inbit = tapc_shiftbit(outbit);
-
- if(msb_first)
- {
- inbyte |= (inbit << (7-j));
- outbyte <<= 1;
- }
- else
- {
- inbyte |= inbit << j;
- outbyte >>= 1;
- }
- }
-
- //tapc_tms(1);
- if(msb_first)
- read[-1-i] = inbyte;
- else
- read[i] = inbyte;
+ Boolean is_last_byte = (i == nbytes - 1);
+ Byte inbyte = (Byte) 0;
+ Byte outbyte;
+
+ if (order == MSB_FIRST)
+ outbyte = to_write[nbytes - 1 - i];
+ else
+ outbyte = to_write[i];
+
+ if (is_last_byte)
+ {
+ /* How many significant bits are in this byte? */
+ nbits = ((n - 1) % BITS_IN_BYTE) + 1;
+ }
+
+ /* gdb_assert (nbits <= BITS_IN_BYTE); */
+
+ for (j = 0; j < nbits; j++)
+ {
+ Bit outbit, inbit;
+
+// DEBUG("byte %u, bit %u\n", i, j);
+
+ /* Get the next bit to be output from the current byte. */
+ if (order == MSB_FIRST)
+ {
+ /* Get MSB from byte. */
+ outbit = (Bit) ((outbyte >> BITS_IN_BYTE) & 1);
+ outbyte <<= 1;
+ }
+ else
+ {
+ /* Get LSB from byte. */
+ outbit = (Bit) (outbyte & 1);
+ outbyte >>= 1;
+ }
+
+ /* The last bit of the last byte. */
+ if (is_last_byte && (j == nbits - 1))
+ {
+ /* Change to Exit1-DR/IR state before the last bit is shifted:
+ this is necessary because the TAP Controller performs the
+ last sample of TDI when exiting the Shift-DR/IR state. */
+ tapc_set_TMS(1);
+ NEXT_STATE(1);
+ }
+
+ /* Shift one bit in from the JTAG TDO and one bit out to the JTAG TDI. */
+ inbit = tapc_shift_bit(outbit);
+
+ /* Add the bit read into the input byte.
+ N.B. the shift amount will always be positive, as 0 <= j < BITS_IN_BYTE */
+ if (order == MSB_FIRST)
+ inbyte |= (Byte) (inbit << (BITS_IN_BYTE - 1 - j));
+ else
+ inbyte |= (Byte) (inbit << j);
+ }
+
+ if (order == MSB_FIRST)
+ to_read[nbytes - 1 - i] = inbyte;
+ else
+ to_read[i] = inbyte;
}
-}
+ STATE_IS_EITHER(EXIT1_DR, EXIT1_IR);
-/* Read the JTAG status register. This indicates
- the status of the JTAG for the user.
-*/
-static unsigned int
-read_jtag_status_reg (void)
-{
- unsigned int wr, rd;
- int x;
- //rw_flag=0;
- //tapc_tms(0); // runtest/idle
- tapc_tms(1); // select dr
- tapc_tms(1); // select ir
- tapc_tms(0); // capture ir
- tapc_tms(0); // shift ir
-
- wr = 0x8; // IR = status register
-
- tapc_shiftnbits(4, (unsigned char *)&wr, (unsigned char*)&rd, 0);
-
-
-
- // goto shift DR
- tapc_tms(1); // update ir
- //tapc_tms(0); // runtest/idle
- tapc_tms(1); // select dr
- tapc_tms(0); // capture dr
- tapc_tms(0); // shift dr
-
- rd = 0;
-
- // read 1 bit, if it is zero then keep reading
- rd = tapc_shiftbit(0);
- if (rd)
- return rd;
-
- rd |= tapc_shiftbit(0) << 1;
- if (rd)
- return rd;
-
- rd |= tapc_shiftbit(0) << 2;
-
- /* the last bit is optional */
- /*rd |= tapc_shiftbit(0) << 3;*/
-
- return rd;
+ LEAVEMSG;
}
-/* Interpret the status message. */
-static void
-print_jtag_status_reg_val (unsigned int status)
+/* Read the JTAG Status Register.
+ This indicates the status of the JTAG transaction that has been attempted. */
+
+static JTAG_TransactionStatus
+read_jtag_status_register( void)
{
- int i ;
- char * messages [] = { "Stalled" , "Failure", "Ready", "PC Selected" };
- for(i=0;i<=3;i++)
- {
- printf_filtered("%s %s \t",(status & 1)?"":"Not",messages[i]);
- status = status >> 1;
- }
- printf_filtered("\n");
+ JTAG_RegisterContents rd, wr;
+ Bit bit;
+
+ ENTERMSG;
+
+ STATE_IS_EITHER(RUN_TEST_IDLE, UPDATE_DR);
+
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(1, SELECT_IR_SCAN);
+ CHANGE_STATE(0, CAPTURE_IR);
+ CHANGE_STATE(0, SHIFT_IR);
+
+ wr = JTAG_STATUS_REGISTER;
+
+ tapc_shift_N_bits(BITS_IN_REGISTER_CODE, (Byte*) &wr, (Byte*) &rd, MSB_LAST);
+
+ CHANGE_STATE(1, UPDATE_IR);
+// CHANGE_STATE(0, RUN_TEST_IDLE);
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(0, CAPTURE_DR);
+ CHANGE_STATE(0, SHIFT_DR);
+
+ /* The JTAG Status Register is read-only, and any bits shifted in are
+ ignored - hence the parameter to tapc_shift_bit is irrelevant here. */
+
+ /* Read Stalled bit; if it is zero then keep reading. */
+ bit = tapc_shift_bit(0);
+ if (bit)
+ return STALLED;
+
+ /* Read Failed bit; if it is zero then keep reading. */
+ bit = tapc_shift_bit(0);
+ if (bit)
+ return FAILURE;
+
+ /* Read Ready bit. */
+ bit = tapc_shift_bit(0);
+ if (bit)
+ return READY;
+
+ /* The last bit (PC_SEL) is optional. */
+
+ return NOT_READY;
}
+/* Write a value to a JTAG register.
+ enter in Update-DR/IR state or Run-Test/Idle.
+ exit in Update-DR */
-/* Write a JTAG Command to a JTAG register.
- enter in update dr/ir state
- or Test-Logic-Reset.
- exit in update dr
-*/
static void
-write_jtag_reg (char regnum, unsigned int data, int ndatabits)
+write_jtag_reg (JTAG_Register regnum,
+ JTAG_RegisterContents data,
+ unsigned int num_data_bits)
{
- unsigned int wr=0,rd=0;
- rw_flag = WRITE_TO_AA3 ;
- // tapc_tms(0); // runtest/idle
- tapc_tms(1); // select dr
- tapc_tms(1); // select ir
- tapc_tms(0); // capture ir
- tapc_tms(0); // shift ir
-
-
- tapc_shiftnbits(4, (unsigned char *)&regnum, (unsigned char *)&rd, 0);
-
-
- tapc_tms(1); // update ir
-
- tapc_tms(1); // select dr
- tapc_tms(0); // capture dr
- tapc_tms(0); // shift dr
-
- tapc_shiftnbits(ndatabits, (unsigned char *)&data,
- (unsigned char *)&rd, 0);
- tapc_tms(1); // update dr
+ Byte num = (Byte) regnum;
+ JTAG_RegisterContents rd = 0;
+
+ ENTERARGS("regnum %d <== 0x%08X (:%d)", regnum, data, num_data_bits);
+
+ STATE_IS_ONE_OF(UPDATE_DR, UPDATE_IR, RUN_TEST_IDLE);
+
+// CHANGE_STATE(0, RUN_TEST_IDLE);
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(1, SELECT_IR_SCAN);
+ CHANGE_STATE(0, CAPTURE_IR);
+ CHANGE_STATE(0, SHIFT_IR);
+
+ tapc_shift_N_bits(BITS_IN_REGISTER_CODE, &num, (Byte*) &rd, MSB_LAST);
+
+ CHANGE_STATE(1, UPDATE_IR);
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(0, CAPTURE_DR);
+ CHANGE_STATE(0, SHIFT_DR);
+
+ tapc_shift_N_bits(num_data_bits, (Byte*) &data, (Byte*) &rd, MSB_LAST);
+
+ CHANGE_STATE(1, UPDATE_DR);
+
+ DEBUG("written 0x%08X to JTAG %s register\n", data, JTAG_register_name(regnum));
+
+ LEAVEMSG;
}
-
-// enter in update dr/ir state
-// exit in update dr
-static unsigned int
-read_jtag_reg (char regnum, int ndatabits)
+
+/* Read a value from a JTAG register.
+ enter in Update-DR/IR state
+ exit in Update-DR */
+
+static JTAG_RegisterContents
+read_jtag_reg (JTAG_Register regnum, unsigned int num_data_bits)
{
- unsigned int wr=0x0,rd=0;
- rw_flag = READ_FROM_AA3;
- // tapc_tms(0); // runtest/idle
- tapc_tms(1); // select dr
- tapc_tms(1); // select ir
- tapc_tms(0); // capture ir
- tapc_tms(0); // shift ir
-
- tapc_shiftnbits(4, (unsigned char *)&regnum, (unsigned char *)&rd, 0);
- tapc_tms(1); // update ir
-
- /* JTAG registers can be read without going to run-test/idle state.
-
- Doing tapc_tms(0) will take us to run-test/idle state.
- This will make JTAG perform the transaction as per TCR.
- We dont want this.
- */
- // tapc_tms(0); // runtest/idle
- tapc_tms(1); // select dr
- tapc_tms(0); // capture dr
- tapc_tms(0); // shift dr
-
- tapc_shiftnbits(ndatabits, (unsigned char *)&wr, (unsigned char *)&rd, 0);
- tapc_tms(1); // update dr
+ Byte num = (Byte) regnum;
+ JTAG_RegisterContents wr = 0, rd = 0;
+
+ ENTERARGS("regnum %u, %u bits", regnum, num_data_bits);
+
+ STATE_IS_EITHER(UPDATE_DR, UPDATE_IR);
+
+// CHANGE_STATE(0, RUN_TEST_IDLE);
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(1, SELECT_IR_SCAN);
+ CHANGE_STATE(0, CAPTURE_IR);
+ CHANGE_STATE(0, SHIFT_IR);
+
+ tapc_shift_N_bits(BITS_IN_REGISTER_CODE, &num, (Byte*) &rd, MSB_LAST);
+
+ CHANGE_STATE(1, UPDATE_IR);
+
+ /* JTAG registers can be read without going to Run-Test/Idle state.
+
+ Doing CHANGE_STATE(0) would take us to Run-Test/Idle state. This would
+ make JTAG perform the transaction in the Transaction Command Register.
+ We don't want that! */
+// CHANGE_STATE(0, RUN_TEST_IDLE);
+ CHANGE_STATE(1, SELECT_DR_SCAN);
+ CHANGE_STATE(0, CAPTURE_DR);
+ CHANGE_STATE(0, SHIFT_DR);
+
+ tapc_shift_N_bits(num_data_bits, (Byte*) &wr, (Byte*) &rd, MSB_LAST);
+ CHANGE_STATE(1, UPDATE_DR);
+
+ DEBUG("read 0x%08X from JTAG %s register\n", rd, JTAG_register_name(regnum));
return rd;
}
+/* -------------------------------------------------------------------------- */
+/* 5) JTAG transaction functions */
+/* -------------------------------------------------------------------------- */
-
-
-
+/* Start a JTAG transaction.
+ Parameters:
+ command: the JTAG command to be performed
+ address: the address (memory address or register number) for the command
+*/
-static int
-arc_jtag_read_core_reg (unsigned int regnum, unsigned int *readbuf)
+static void
+start_jtag_transaction (JTAG_RegisterContents command,
+ JTAG_RegisterContents address)
{
- unsigned int rd, wr, data, i;
- check_and_raise_error_if_jtag_closed();
- tapc_reset();
- tapc_tms(0);//run-test idle
- write_jtag_reg(0xA, regnum, 32);//update dr
+ ENTERARGS("command = %d, address = 0x%x", command, address);
-
+ STATE_IS_ONE_OF(UPDATE_DR, UPDATE_IR, RUN_TEST_IDLE);
- // Setup instruction register to 0x9 indicating
- // a JTAG instruction is being downloaded.
- // jtag transaction command reg = 0x5 (read core reg)
- write_jtag_reg(0x9, 0x5, 4);//update dr
+ /* N.B. do NOT reset the TAP Controller at the start of each transaction, as
+ that would re-initialize the JTAG registers to their default values
+ (whatever those might be), so invalidating the optimisation of the
+ use of the Address and Transaction Command registers performed by
+ this module. */
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
-
- // poll the status
+ if (command == READ_MEMORY_LOCATION || command == WRITE_MEMORY_LOCATION)
+ {
+ gdb_assert(IS_WORD_ALIGNED(address));
+ }
- for (i=0;i<arcjtag_retry_count;i++)
+ /* Load the command that is required into the JTAG Transaction Command
+ Register, and the address into the JTAG Address Register; by keeping
+ track of the values that these registers contain, we can avoid re-loading
+ them unnecessarily, which can save time when transferring a stream of data. */
+
+ if (!command_register_contents_known ||
+ (command_register_contents != command))
{
- unsigned int status = read_jtag_status_reg();
- //if( !(status & 1) && (status & 4) )
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_READ_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-test-idle
+ write_jtag_reg(JTAG_TRANSACTION_COMMAND_REGISTER, command, BITS_IN_COMMAND_CODE);
+
+ command_register_contents_known = TRUE;
+ command_register_contents = command;
}
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
- /* JTAG status register leaves us in Shift DR */
- tapc_tms(1); /* Move to Exit-1 DR */
- tapc_tms(1); /* Move to Update DR */
-
- // data = jtag data reg
- data = read_jtag_reg(0xB, 32);
-
- *readbuf = data;
-
- return sizeof(data);
+
+ if (!address_register_contents_known ||
+ (address_register_contents != address))
+ {
+ write_jtag_reg(JTAG_ADDRESS_REGISTER, address, BITS_IN_WORD);
+
+ address_register_contents_known = TRUE;
+ address_register_contents = address;
+ }
+
+ LEAVEMSG;
}
-static int
-arc_jtag_write_core_reg (unsigned int regnum, unsigned int data)
-{
- unsigned int rd, wr, i;
- check_and_raise_error_if_jtag_closed();
- tapc_reset();
- tapc_tms(0);//run-test idle
+/* Perform the given JTAG transaction (a mmeory or register operation).
+ If the transaction fails, this function returns the given error. */
- // data = jtag data reg
- write_jtag_reg(0xB, data, 32);//update dr
+static JTAG_OperationStatus
+perform_jtag_transaction (JTAG_TransactionType transaction,
+ JTAG_OperationStatus error)
+{
+ JTAG_OperationStatus result = error;
+ unsigned int tries = 0;
- // jtag addr register = regnum:
- write_jtag_reg(0xA, regnum, 32);//update dr
-
-
+ ENTERARGS("transaction: %u", transaction);
- // jtag transaction command reg = 0x1(write core reg)
- write_jtag_reg(0x9, 0x1, 4);//update dr
+ /* This causes the TAP Controller to perform the transaction, according to
+ the contents of the JTAG Transaction Command, Address and Data registers. */
+ CHANGE_STATE(0, RUN_TEST_IDLE);
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
-
- for (i=0;i<arcjtag_retry_count;i++)
+ /* Poll the JTAG Status Register. */
+ do
{
- unsigned int status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_WRITE_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-test-idle
+ JTAG_TransactionStatus status = read_jtag_status_register();
+
+ DEBUG("status: %s\n", JTAG_TransactionStatus_Image(status));
+
+ /* The read has left the TAP Controller FSM in state Shift-DR. */
+ STATE_IS(SHIFT_DR);
+
+ CHANGE_STATE(1, EXIT1_DR);
+ CHANGE_STATE(1, UPDATE_DR);
+
+ /* If the transaction is complete. */
+ if (status == READY)
+ {
+ /* The value in the JTAG Address Register is incremented by four
+ (a memory access) or one (a register access) when a read/write
+ transaction has completed. */
+ address_register_contents += (transaction == Memory) ? BYTES_IN_WORD : 1;
+
+ result = JTAG_SUCCESS;
+ break;
+ }
+
+ if (status == FAILURE)
+ break;
+
+ /* Pause and re-try. */
+ usleep(1);
}
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* This should have been done earlier i.e. before
- reading the JTAG status register.
- */
- //tapc_tms(0);//rn-test-idle
- return sizeof(data);
+ while (++tries <= arc_jtag_ops.retry_count);
+
+ LEAVEMSG;
+ return result;
}
-static int
-arc_jtag_read_aux_reg (unsigned int regnum, unsigned int *readbuf)
-{
- unsigned int rd, wr, data, i;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nEntered arc_jtag_read_aux_reg()\
- \n Regnum:%d \n",regnum);
- check_and_raise_error_if_jtag_closed();
- check_and_raise_error_if_jtag_closed();
- tapc_reset();
- tapc_tms(0);//run-test idle
- write_jtag_reg(0xA, regnum, 32);//update dr
+/* -------------------------------------------------------------------------- */
+/* 6) read/write helper functions */
+/* -------------------------------------------------------------------------- */
+/* These functions aid in reading/writing registers/memory. */
- // Setup instruction register to 0x9 indicating
- // a JTAG instruction is being downloaded.
- // jtag transaction command reg = 0x6 (read aux reg)
- write_jtag_reg(0x9, 0x6, 4);//update dr
+/* Read a processor register (core or auxiliary). */
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
+static JTAG_OperationStatus
+read_processor_register (ARC_RegisterNumber regnum,
+ JTAG_RegisterContents command,
+ ARC_RegisterContents *contents)
+{
+ JTAG_OperationStatus status;
- // poll the status
+ /* Load the number of the register that is to be read into the JTAG Address
+ Register. */
+ start_jtag_transaction(command, regnum);
- for (i=0;i<arcjtag_retry_count;i++)
- {
- unsigned int status = read_jtag_status_reg();
-
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_READ_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-test-idle
+ status = perform_jtag_transaction(Register, JTAG_READ_FAILURE);
+ if (status == JTAG_SUCCESS)
+ {
+ /* Read the register contents from the JTAG Data Register. */
+ *contents = (ARC_RegisterContents) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_REGISTER);
}
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
-
-/* JTAG status register leaves us in Shift DR */
- tapc_tms(1); /* Move to Exit-1 IR */
- tapc_tms(1); /* Move to Update IR */
-
- // data = jtag data reg
- data = read_jtag_reg(0xB, 32);
- *readbuf = data;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf(" Data: %d\n",data);
- return sizeof(data);
+
+ return status;
}
-static int
-arc_jtag_write_aux_reg (unsigned int regnum, unsigned int data)
+
+/* Write a processor register (core or auxiliary). */
+
+static JTAG_OperationStatus
+write_processor_register (ARC_RegisterNumber regnum,
+ JTAG_RegisterContents command,
+ ARC_RegisterContents contents)
{
- unsigned int rd, wr, i;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nEntered arc_jtag_write_aux_reg()\n Regnum:%d\nData:%d\n",regnum,data);
- check_and_raise_error_if_jtag_closed();
- tapc_reset();
- tapc_tms(0);//run-test idle
-
- // data = jtag data reg
- write_jtag_reg(0xB, data, 32);//update dr
+ /* Load the number of the register that is to be written into the JTAG
+ Address Register. */
+ start_jtag_transaction(command, regnum);
+
+ /* Load the new register contents into the JTAG Data Register. */
+ write_jtag_reg(JTAG_DATA_REGISTER, contents, BITS_IN_REGISTER);
- // jtag addr register = regnum:
- write_jtag_reg(0xA, regnum, 32);//update dr
-
-
+ return perform_jtag_transaction(Register, JTAG_WRITE_FAILURE);
+}
- // jtag transaction command reg = 0x2 (write aux reg)
- write_jtag_reg(0x9, 0x2, 4);//update dr
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
+/* Write a processor core register. */
- for (i=0;i<arcjtag_retry_count;i++)
- {
- unsigned int status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_WRITE_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-test-idle
- }
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* This should have been done earlier i.e. before
- reading the JTAG status register.
- */
- //tapc_tms(0);//run-test-idle
- return sizeof(data);
+static JTAG_OperationStatus
+jtag_write_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents)
+{
+ ENTERARGS("regnum %d", regnum);
+
+ return write_processor_register(regnum, WRITE_CORE_REGISTER, contents);
}
-static int
-read_mem (unsigned int addr, unsigned int *readbuf)
+/* Read a processor auxiliary register. */
+
+static JTAG_OperationStatus
+jtag_read_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents)
{
- unsigned int rd, wr, data, i;
+ ENTERARGS("regnum %d", regnum);
+
+ return read_processor_register(regnum, READ_AUX_REGISTER, contents);
+}
- rw_flag = READ_FROM_AA3;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nEntered read_mem() 0x%x\n",addr);
- // jtag addr register = regnum:
- tapc_reset();
- tapc_tms(0);//run-test idle
- write_jtag_reg(0xA, addr, 32);//update dr
-
+/* Write a processor auxiliary register. */
- // Setup instruction register to 0x9 indicating
- // a JTAG instruction is being downloaded.
- // jtag transaction command reg = 0x5 (read core reg)
- write_jtag_reg(0x9, 0x4, 4);//update dr
+static JTAG_OperationStatus
+jtag_write_aux_reg (ARC_RegisterNumber regnum, ARC_RegisterContents contents)
+{
+ ENTERARGS("regnum %d", regnum);
+
+ return write_processor_register(regnum, WRITE_AUX_REGISTER, contents);
+}
+
+
+/* Read a word of data from memory; the given address must be word-aligned.
+ Returns number of bytes read. */
+
+static unsigned int
+jtag_read_word (ARC_Address addr, ARC_Word *data)
+{
+ JTAG_OperationStatus status;
+
+ ENTERARGS("addr 0x%08X", addr);
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
+ gdb_assert(IS_WORD_ALIGNED(addr));
- // poll the status
+ /* Load the address of the memory word that is to be read into the JTAG
+ Address Register. */
+ start_jtag_transaction(READ_MEMORY_LOCATION, addr);
- for (i=0;i<arcjtag_retry_count;i++)
+ status = perform_jtag_transaction(Memory, JTAG_READ_FAILURE);
+
+ if (status == JTAG_SUCCESS)
{
- unsigned int status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_READ_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0); // run-test-idle
+ /* Read the data from the JTAG Data Register. */
+ ARC_Word word = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD);
+
+ /* N.B. this assumes that the host is little-endian! */
+ if (target_is_big_endian)
+ word = __bswap_32(word);
+
+ DEBUG("read 0x%08X\n", word);
+
+ *data = word;
+
+ return BYTES_IN_WORD;
}
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
- /* JTAG status register leaves us in Shift DR */
- tapc_tms(1); /* Move to Exit-1 DR */
- tapc_tms(1); /* Move to Update DR */
-
- // data = jtag data reg
- data = read_jtag_reg(0xB, 32);
- *readbuf = data;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\n Read rd =0x%x in read_mem",data);
-
- return sizeof(data);
+
+ /* Failed: no data read. */
+ return 0;
}
-static int
-write_mem (unsigned int addr, unsigned int data)
+/* Write a word of data to memory; the given address must be word-aligned.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_word (ARC_Address addr, ARC_Word data)
{
- unsigned int rd, wr, i;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nEntered write_mem() to write 0x%x at 0x%x\n",data,addr);
- tapc_reset();
- tapc_tms(0);//run-test idle
-
- // data = jtag data reg
- write_jtag_reg(0xB, data, 32);//update dr
+ ENTERARGS("addr 0x%08X, data 0x%08X", addr, data);
- // jtag addr register = regnum:
- write_jtag_reg(0xA, addr, 32);//update dr
-
-
+ gdb_assert(IS_WORD_ALIGNED(addr));
- // jtag transaction command reg = 0x0(write mem)
- write_jtag_reg(0x9, 0x0, 4);//update dr
+ /* Load the address of the memory word that is to be written into the JTAG
+ Address Register. */
+ start_jtag_transaction(WRITE_MEMORY_LOCATION, addr);
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
+ /* N.B. this assumes that the host is little-endian! */
+ if (target_is_big_endian)
+ data = __bswap_32(data);
- for (i=0;i<arcjtag_retry_count;i++)
- {
- unsigned int status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return JTAG_WRITE_FAILURE;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-tes-idle
- }
- if (i==arcjtag_retry_count)
- return JTAG_READ_FAILURE;
-
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* This should have been done earlier i.e. before
- reading the JTAG status register.
- */
- //tapc_tms(0);//run-test-idle
- return sizeof(data);
+ /* Load the data to be written into the JTAG Data Register. */
+ write_jtag_reg(JTAG_DATA_REGISTER, data, BITS_IN_WORD);
+
+ if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) == JTAG_SUCCESS)
+ return BYTES_IN_WORD;
+
+ /* Failed: no data written. */
+ return 0;
}
-static int
-arc_jtag_write_chunk (unsigned int addr, unsigned int *write_buf, int len)
+/* Read a number of words of data from target memory starting at the given address.
+ Returns number of bytes read. */
+
+static unsigned int
+jtag_read_chunk (ARC_Address address, ARC_Byte *data, unsigned int words)
{
- unsigned int rd, wr;
- unsigned int status;
- check_and_raise_error_if_jtag_closed();
-
- rw_flag = WRITE_TO_AA3 ;
- int i = 0;
- int len_mod = len % 4;
- len = len - len_mod;
-
- tapc_reset();
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("Entered arc_jtag_write_chunk()......0x%x\n",*write_buf);
- tapc_tms(0);//run-test idle
-
- // jtag addr register = regnum:
- write_jtag_reg(0xA, addr, 32);//update dr
-
-
-
- // jtag transaction command reg = 0x0(write mem)
- write_jtag_reg(0x9, 0x0, 4);//update dr
-
- while(len)
- {
-
- // data = jtag data reg
- write_jtag_reg(0xB, write_buf[i++], 32);//update dr
-
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
-
-
- while(1)
- {
- status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return (i-1) * 4;
-
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-tes-idle
- }
-
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* This should have been done earlier i.e. before
- reading the JTAG status register.
- */
- //tapc_tms(0);//run-test idle
- len = len - 4;
- }
+ unsigned int total_read = 0;
+
+ ENTERARGS("address 0x%08X, words %u", address, words);
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("leaving arc_jtag_write_chunk() with return value %d",i*4);
-
- // added support for writing no of bytes those are not exact mutiple of four
-
- if(!len_mod)
- return i*4;
- else
+ /* Load the start address of the memory chunk that is to be read
+ into the JTAG Address Register. */
+ start_jtag_transaction(READ_MEMORY_LOCATION, address);
+
+ /* Read all the words of data. */
+ while (words--)
{
-
- addr=addr+(i*4);
- if(read_mem(addr,&rd)==JTAG_READ_FAILURE)
- return i*4;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nrd=0x%x and wr=0x%x\n",rd,write_buf[i]);
-
- switch(len_mod)
- {
-
- case 1:
- wr = (rd & 0xffffff00)|(write_buf[i] & 0xff);
- break;
-
- case 2:
- wr = (rd & 0xffff0000)|(write_buf[i] & 0xffff);
- break;
-
- case 3:
- wr = (rd & 0xff000000)|(write_buf[i] & 0xffffff);
- break;
-
- }
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nwrite_mem writing 0x%x at 0x%x",wr,addr);
- arc_jtag_write_chunk(addr,&wr,4);
- return (i*4 + len_mod);
- }
-
-
+ ARC_Word word;
+
+ /* Read the next word of data - this increments the address in
+ the JTAG Address Register by the word size, so the register
+ does not have to be re-loaded with the next address. */
+ if (perform_jtag_transaction(Memory, JTAG_READ_FAILURE) != JTAG_SUCCESS)
+ {
+ DEBUG("FAIL: read %u bytes\n", total_read);
+
+ /* Failed - just return amount of data read so far. */
+ return total_read;
+ }
+
+ /* Read the word of data from the JTAG Data Register. */
+ word = (ARC_Word) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_WORD);
+
+ /* N.B. this assumes that the host is little-endian! */
+ if (target_is_big_endian)
+ word = __bswap_32(word);
+
+ /* Copy it into the buffer (byte-by-byte copy means that alignment does not matter). */
+ COPY_WORD(data, &word);
+
+ total_read += BYTES_IN_WORD;
+ data += BYTES_IN_WORD;
+ }
+
+ return total_read;
}
-static int
-arc_jtag_read_chunk (unsigned int addr, unsigned int *read_buf, int len)
+
+/* Write a number of words of data to target memory starting at the given address.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_chunk (ARC_Address address, ARC_Byte *data, unsigned int words)
{
- unsigned int rd, wr, data;
- int i=0;
- rw_flag = READ_FROM_AA3 ;
- int len_mod=len%4;
- len=len-len_mod;
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("\nEntered arc_jtag_read_chunk() 0x%x\n",addr);
- check_and_raise_error_if_jtag_closed();
-
- // jtag addr register = regnum:
- tapc_reset();
- tapc_tms(0);//run-test idle
-
- write_jtag_reg(0xA, addr, 32);//update dr
+ unsigned int total_written = 0;
-
- while(len)
- {
- // Setup instruction register to 0x9 indicating
- // a JTAG instruction is being downloaded.
- // jtag transaction command reg = 0x5 (read core reg)
- write_jtag_reg(0x9, 0x4, 4);//update dr
+#ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
+ ARC_Word last_word;
- /* Perform the transaction.
- */
- tapc_tms(0); // run-test idle
+ /* Initialise last_word with a value that is different from the
+ first word to be written. */
+ COPY_WORD(&last_word, data);
+ last_word++;
+#endif
- // poll the status
+ ENTERARGS("address 0x%08X, words %u", address, words);
- while(1)
+ /* Load the start address of the memory chunk that is to be written
+ into the JTAG Address Register. */
+ start_jtag_transaction(WRITE_MEMORY_LOCATION, address);
+
+ /* write all the words of data */
+ while (words--)
{
- unsigned int status = read_jtag_status_reg();
- if(status == 4)
- break;
- if(status == 2)
- return (i-1)*4;
- tapc_tms(1);//exit1-dr
- tapc_tms(1);//update-dr
- /* Do not redo the transaction. Pause and re-try.
- */
- //tapc_tms(0);//run-test-idle
+ ARC_Word word;
- }
+ /* Copy the next word of data from the buffer
+ (byte-by-byte copy means that alignment does not matter). */
+ COPY_WORD(&word, data);
+
+ /* N.B. this assumes that the host is little-endian! */
+ if (target_is_big_endian)
+ word = __bswap_32(word);
+
+#ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
+ if (word != last_word)
+ {
+#endif
+ write_jtag_reg(JTAG_DATA_REGISTER, word, BITS_IN_WORD);
- /* JTAG status register leaves us in Shift DR */
- tapc_tms(1); /* Move to Exit-1 DR */
- tapc_tms(1); /* Move to Update DR */
-
- // data = jtag data reg
- read_buf[i++] = read_jtag_reg(0xB, 32);// exits in Update DR
- len= len-4;
- //tapc_tms(0);/* Move to run-test-idle */
+#ifdef CHECK_JTAG_DATA_REGISTER
+ check_Data_Register(word);
+#endif
+#ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
+ last_word = word;
+ }
+#endif
+
+ data += BYTES_IN_WORD;
+
+ /* Write the word - this increments the address in the JTAG
+ Address Register by the word size, so the register does not
+ have to be re-loaded with the next address. */
+ if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) != JTAG_SUCCESS)
+ {
+ DEBUG("FAIL: written %u bytes\n", total_written);
+
+ /* Failed - just return amount of data written so far. */
+ return total_written;
+ }
+
+ total_written += BYTES_IN_WORD;
}
- // added support for reading no of bytes those are not exact mutiple of four
+ return total_written;
+}
- if(!len_mod)
- return i*4;
- else
+
+/* Write a number of copies of a word-sized pattern of data to memory starting
+ at the given address.
+ Returns number of bytes written. */
+
+static unsigned int
+jtag_write_pattern (ARC_Address address, ARC_Word pattern, unsigned int words)
+{
+ unsigned int total_written = 0;
+
+ ENTERARGS("address 0x%08X, pattern 0x%08X, words %u", address, pattern, words);
+
+ /* Load the start address of the memory chunk that is to be written
+ into the JTAG Address Register. */
+ start_jtag_transaction(WRITE_MEMORY_LOCATION, address);
+
+ /* N.B. this assumes that the host is little-endian! */
+ if (target_is_big_endian)
+ pattern = __bswap_32(pattern);
+
+#ifndef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
+ /* Load the pattern into the JTAG Data Register. */
+ write_jtag_reg(JTAG_DATA_REGISTER, pattern, BITS_IN_WORD);
+#endif
+
+ /* Write all the complete words of data. */
+ while (words--)
{
- char *ptr = (char *)read_buf + i*4;
- addr=addr+(i*4);
- if(read_mem(addr,&rd)==JTAG_READ_FAILURE)
- return i*4;
-
- switch(len_mod)
- {
- case 1:
- ptr[0] = rd & 0xff;
- break;
-
- case 2:
- ptr[0] = rd & 0xff;
- ptr[1] = (rd>>8) & 0xff;
- break;
-
- case 3:
- ptr[0] = rd & 0xff;
- ptr[1] = (rd>>8) & 0xff;
- ptr[2] = (rd>>16) & 0xff;
- break;
- }
-
- return ((i*4)+len_mod);
-
+#ifdef JTAG_DATA_REGISTER_IS_CORRUPTED_BY_WRITE
+ /* Load the pattern into the JTAG Data Register. */
+ write_jtag_reg(JTAG_DATA_REGISTER, pattern, BITS_IN_WORD);
+#endif
+
+#ifdef CHECK_JTAG_DATA_REGISTER
+ check_Data_Register(pattern);
+#endif
+
+ /* Write the word - this increments the address in the JTAG
+ Address Register by the word size, so the register does not
+ have to be re-loaded with the next address. */
+ if (perform_jtag_transaction(Memory, JTAG_WRITE_FAILURE) != JTAG_SUCCESS)
+ {
+ DEBUG("FAIL: written %u bytes\n", total_written);
+
+ /* Failed - just return amount of data written so far. */
+ return total_written;
+ }
+
+ total_written += BYTES_IN_WORD;
}
-
+ return total_written;
}
+/* -------------------------------------------------------------------------- */
+/* 7) main operations */
+/* -------------------------------------------------------------------------- */
+
+/* These are the functions that are called from outside this module via the
+ pointers in the arc_jtag_ops global object.
+ N.B. none of these functions are called from within this module. */
-/*
- * Return the Processor Variant that is connected.
- */
-int
-arc_get_architecture()
+
+/* Read a processor core register. */
+
+static JTAG_OperationStatus
+jtag_read_core_reg (ARC_RegisterNumber regnum, ARC_RegisterContents *contents)
{
- if (ARCProcessor == UNSUPPORTED) {
- unsigned int value;
-
- /* Read the Identity Register. */
- if (arc_jtag_read_aux_reg(4, &value) == JTAG_READ_FAILURE)
- error("Failure reading from auxillary IDENTITY register");
-
- /* Get Identity Mask. */
- value &= 0xff ;
-
- if((value >= 0x30) && (value <= 0x3f))
- ARCProcessor = ARC700;
- else if((value >= 0x20) && (value <= 0x2f))
- ARCProcessor = ARC600;
- else if((value >= 0x10) && (value <= 0x1f))
- ARCProcessor = A5;
- else if ((value >= 0x00) && (value <= 0x0f))
- ARCProcessor = A4;
- else
- error("Unsupported Processor Version 0x%x\n", value);
- }
-
- return ARCProcessor;
+ ENTERARGS("regnum %d", regnum);
+
+ return read_processor_register(regnum, READ_CORE_REGISTER, contents);
}
+/* Try to open the JTAG interface.
+ Returns TRUE for success. */
-static void
-arc_jtag_open (void)
+static Boolean
+jtag_open (ARC_RegisterNumber mem_subsys)
{
- int retval;
- unsigned int read_status = 0;
- sigaddset(&block_mask,SIGINT);
- retval = gpio_setup();
- if(retval != 0)
+ ENTERMSG;
+
+ if (arc_jtag_ops.status == JTAG_CLOSED)
{
- error("Unable to open JTAG Port .%s \n",(retval == EINVAL)?
- "Invalid Params":"Permission Denied" );
- arc_jtag_ops.jtag_status = JTAG_CLOSED;
- return ;
+ JTAG_OperationStatus status;
+
+ /* Make sure that the GPIO driver is open. */
+ if (!gpio_open())
+ return FALSE;
+
+ set_interface(JTAG_OPENED);
+
+ tapc_reset();
+
+ /* Load the number of the MEMSUBSYS BCR that is to be read into the JTAG
+ Address Register. */
+ start_jtag_transaction(READ_AUX_REGISTER, mem_subsys);
+
+ status = perform_jtag_transaction(Register, JTAG_READ_FAILURE);
+
+ if (status == JTAG_SUCCESS)
+ {
+ /* Read the register contents from the JTAG Data Register. */
+ ARC_RegisterContents contents =
+ (ARC_RegisterContents) read_jtag_reg(JTAG_DATA_REGISTER, BITS_IN_REGISTER);
+
+ DEBUG("MEMSUBSYS BCR: 0x%08X\n", contents);
+
+ target_is_big_endian = ((contents & 4) != 0);
+ }
+ else
+ {
+ warning(_("can not discover endianness of target\n"));
+ return FALSE;
+ }
+
+ DEBUG("arcjtag opened\n");
}
- arc_jtag_ops.jtag_status = JTAG_OPENED;
- tapc_reset();
- //Writing debug bit of debug register
-
- do
- {
- /* Note: Reading the status/status32 register here to
- check if halt bit is set*/
- if (IS_A4) {
- if(arc_jtag_read_aux_reg( 0x0, &read_status) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0xA\n");
- if(read_status & A4_HALT_VALUE)
- break;
- }
- else {
- if(arc_jtag_read_aux_reg( 0xA, &read_status) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0xA\n");
- if(read_status & ARC700_HALT_VALUE)
- break;
- }
- printf_filtered("Processor running. Trying to halt.....\n");
- if(arc_jtag_write_aux_reg(0x5,0x2)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x2 to auxillary register 0x5:debug register\n");
- }while(1);
- if (arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("Processor halted.....\n");
+ LEAVEMSG;
+ return TRUE;
}
-static void
-arc_jtag_close (void)
+
+/* Close the JTAG interface. */
+
+static void
+jtag_close (void)
{
- ARCProcessor = UNSUPPORTED;
+ ENTERMSG;
- if(arc_jtag_ops.jtag_status != JTAG_CLOSED)
+ if (arc_jtag_ops.status == JTAG_OPENED)
{
- tapc_reset();
- /* closing file descriptor opened for communication with gpio driver */
- close(fd);
- if(arc_jtag_ops.arc_jtag_state_machine_debug)
- printf_filtered("arc-jtag closed\n");
- arc_jtag_ops.jtag_status = JTAG_CLOSED;
+ tapc_reset();
+
+ /* Close the file descriptor opened for communication with gpio driver. */
+ gpio_close();
+
+ set_interface(JTAG_CLOSED);
+
+#ifdef STATE_MACHINE_DEBUG
+ current_state = UNDEFINED;
+#endif
+
+ DEBUG("arcjtag closed\n");
}
+ LEAVEMSG;
}
-static void
-arc_jtag_wait(void)
+
+/* Reset the target JTAG controller. */
+
+static void
+jtag_reset (void)
{
- unsigned int read_status;
- check_and_raise_error_if_jtag_closed();
- do
- {
- sigprocmask(SIG_BLOCK,&block_mask, NULL);
-
- if (IS_A4) {
- if(arc_jtag_read_aux_reg( 0x0, &read_status) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x0\n");
- //FIXMEA: if(debug_arc_jtag_target_message)
- // printf_filtered ("\n Read Status: 0x%x,%d\n", read_status, read_status);
-
- if(read_status & A4_HALT_VALUE)
- {
- sigprocmask(SIG_BLOCK,&block_mask, NULL);
- break;
- }
- }
- else {
- if(arc_jtag_read_aux_reg( 0xA, &read_status) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0xA\n");
- if(read_status & ARC700_HALT_VALUE)
- {
- sigprocmask(SIG_BLOCK,&block_mask, NULL);
- break;
-
- }
- }
- sigprocmask(SIG_UNBLOCK,&block_mask, NULL);
- }while(1);
-
- while (1)
+ ENTERMSG;
+ tapc_reset();
+ LEAVEMSG;
+}
+
+
+/* Reset the target board. */
+
+static void
+jtag_reset_board (void)
+{
+ ENTERMSG;
+
+ /* Make sure that the GPIO driver is open. */
+ if (gpio_open())
{
- if (arc_jtag_read_aux_reg (0x5,&read_status) == JTAG_READ_FAILURE)
- error ("Failure reading Debug register \n");
- if (!(read_status & 0x80000000))
- break;
+ /* Writing 9 did not work. But that's what the manual says. Hmmm. */
+// gpio_write (CONTROL_PORT, 9);
+
+ /* What is this for? */
+ gpio_write(CONTROL_PORT, (Byte) JTAG_TCK);
+ gpio_write(CONTROL_PORT, (Byte) 0xD);
+ gpio_write(CONTROL_PORT, (Byte) JTAG_TCK);
+ gpio_write(DATA_PORT, (Byte) 0);
+ gpio_write(DATA_PORT, (Byte) JTAG_TMS);
+ gpio_write(DATA_PORT, (Byte) 0);
+
+ tapc_reset();
}
+
+ LEAVEMSG;
+}
+
+
+/* Check that the JTAG interface is open.
+ If it is closed, 'error' is called. */
+
+static void jtag_check_open (void)
+{
+ if (arc_jtag_ops.status == JTAG_CLOSED)
+ interface_is_closed();
}
+
+/* -------------------------------------------------------------------------- */
+/* 8) interface management */
+/* -------------------------------------------------------------------------- */
+
+/* Report that the JTAG interface is closed. */
+
static void
-arc_jtag_reset_board (void)
+interface_is_closed (void)
{
- char c = 5;
- int auxval = 2 ;
- check_and_raise_error_if_jtag_closed ();
-
- /*
- Writing 9 did not work. But thats
- what the manual says. Hmmm.
- gpio_write (CONTROL_PORT, &c);
- */
-
- gpio_write ( CONTROL_PORT, &c);
- c = 0xd;
- gpio_write ( CONTROL_PORT, &c);
- c = 5;
- gpio_write ( CONTROL_PORT, &c);
-
- if (arc_jtag_write_aux_reg(0x5 , 2) == JTAG_WRITE_FAILURE)
- error ("Failure writing to auxiliary register Debug\n");
-
- c = 0;
- gpio_write ( 0x378, &c);
- c = 0x40;
- gpio_write ( 0x378, &c);
- c = 0;
- gpio_write ( 0x378, &c);
-
- tapc_reset();
+ error(_("JTAG connection is closed. "
+ "Use command 'target " ARC_TARGET_NAME "' first."));
}
+/* Set up the function pointers in the arc_jtag_ops structure according to
+ whether the JTAG interface is open or closed. Note that if the interface is
+ closed, all the pointers point to the 'interface_is_closed' function - so any
+ attempt to invoke one of those operations results in an error; but if the
+ interface is open, they point to the appropriate operations (which may be
+ called without incurring the overhead of a check on the interface status). */
+
+static void
+set_interface (JTAG_Status status)
+{
+ arc_jtag_ops.status = status;
+
+ if (status == JTAG_OPENED)
+ {
+ arc_jtag_ops.memory_read_word = jtag_read_word;
+ arc_jtag_ops.memory_write_word = jtag_write_word;
+ arc_jtag_ops.memory_read_chunk = jtag_read_chunk;
+ arc_jtag_ops.memory_write_chunk = jtag_write_chunk;
+ arc_jtag_ops.memory_write_pattern = jtag_write_pattern;
+ arc_jtag_ops.read_aux_reg = jtag_read_aux_reg;
+ arc_jtag_ops.write_aux_reg = jtag_write_aux_reg;
+ arc_jtag_ops.read_core_reg = jtag_read_core_reg;
+ arc_jtag_ops.write_core_reg = jtag_write_core_reg;
+ arc_jtag_ops.reset = jtag_reset;
+ }
+ else
+ {
+ typedef unsigned int (*Read_Word) (ARC_Address, ARC_Word*);
+ typedef unsigned int (*Write_Word) (ARC_Address, ARC_Word);
+ typedef unsigned int (*Transfer_Chunk) (ARC_Address, ARC_Byte*, unsigned int);
+ typedef unsigned int (*Write_Pattern) (ARC_Address, ARC_Word, unsigned int);
+ typedef JTAG_OperationStatus (*Read_Register) (ARC_RegisterNumber, ARC_RegisterContents*);
+ typedef JTAG_OperationStatus (*Write_Register) (ARC_RegisterNumber, ARC_RegisterContents);
+
+ /* The type casts avoid "assignment from incompatible pointer type" warnings
+ at compile-time. */
+ arc_jtag_ops.memory_read_word = (Read_Word) interface_is_closed;
+ arc_jtag_ops.memory_write_word = (Write_Word) interface_is_closed;
+ arc_jtag_ops.memory_read_chunk = (Transfer_Chunk) interface_is_closed;
+ arc_jtag_ops.memory_write_chunk = (Transfer_Chunk) interface_is_closed;
+ arc_jtag_ops.memory_write_pattern = (Write_Pattern) interface_is_closed;
+ arc_jtag_ops.read_aux_reg = (Read_Register) interface_is_closed;
+ arc_jtag_ops.write_aux_reg = (Write_Register) interface_is_closed;
+ arc_jtag_ops.read_core_reg = (Read_Register) interface_is_closed;
+ arc_jtag_ops.write_core_reg = (Write_Register) interface_is_closed;
+ arc_jtag_ops.reset = interface_is_closed;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
void
_initialize_arc_jtag_ops (void)
{
- arc_jtag_ops.name=NULL;
- arc_jtag_ops.jtag_open = arc_jtag_open;
- arc_jtag_ops.jtag_close = arc_jtag_close;
- arc_jtag_ops.jtag_memory_write = arc_jtag_write_chunk;
- arc_jtag_ops.jtag_memory_read = arc_jtag_read_chunk;
- arc_jtag_ops.jtag_memory_chunk_write = arc_jtag_write_chunk;
- arc_jtag_ops.jtag_memory_chunk_read = arc_jtag_read_chunk;
- arc_jtag_ops.jtag_write_aux_reg = arc_jtag_write_aux_reg;
- arc_jtag_ops.jtag_read_aux_reg = arc_jtag_read_aux_reg;
- arc_jtag_ops.jtag_read_core_reg = arc_jtag_read_core_reg;
- arc_jtag_ops.jtag_write_core_reg = arc_jtag_write_core_reg;
- arc_jtag_ops.jtag_wait = arc_jtag_wait;
- arc_jtag_ops.jtag_reset_board = arc_jtag_reset_board;
- arc_jtag_ops.jtag_status = JTAG_CLOSED ;
+ ENTERMSG;
+
+ /* Initialize the arc_jtag_ops global variable. */
+
+ arc_jtag_ops.state_machine_debug = FALSE;
+ arc_jtag_ops.retry_count = 50;
+
+ /* We want to be able to reset the board, and check whether it is connected,
+ regardless of the connection state. */
+ arc_jtag_ops.open = jtag_open;
+ arc_jtag_ops.close = jtag_close;
+ arc_jtag_ops.check_open = jtag_check_open;
+ arc_jtag_ops.reset_board = jtag_reset_board;
+
+ /* The JTAG interface is initially closed. */
+ set_interface(JTAG_CLOSED);
}
+
+/******************************************************************************/
diff --git a/gdb/arc-jtag-ops.h b/gdb/arc-jtag-ops.h
index dbf49e605b8..d278acd303a 100644
--- a/gdb/arc-jtag-ops.h
+++ b/gdb/arc-jtag-ops.h
@@ -1,62 +1,126 @@
-/* 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.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Sameer Dhavale <sameer.dhavale@codito.com>
- Soam Vasani <soam.vasani@codito.com>
+ Authors:
+ Sameer Dhavale <sameer.dhavale@codito.com>
+ Soam Vasani <soam.vasani@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.
-*/
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This header file defines the JTAG interface to an ARC processor. */
+/* */
+/* Operations are provided for: */
+/* 1) controlling the interface */
+/* 2) reading/writing the core registers of the processor */
+/* 3) reading/writing the auxiliary registers of the processor */
+/* 4) reading/writing single words in the target memory */
+/* 5) reading/writing blocks in the target memory */
+/* */
+/* The addresses specified for the memory word read/write operations must */
+/* be word-aligned. Those specified for the memory block read/write */
+/* operations may have any alignment; these operations may transfer an */
+/* arbitrary number of bytes. */
+/* */
+/* Usage: */
+/* The module exports a global variable arc_jtag_ops which holds pointers */
+/* to the functions for the operations, as well as some state information.*/
+/* This variable is initialized by the module's initialization function */
+/* which must be called before any use is made of the module (N.B. the */
+/* call to this function is generated by the gdb build mechanism, so this */
+/* function should not be explicitly called). */
+/* */
+/* The variable arc_jtag_ops.retry_count controls how many repeated */
+/* attempts are made if a read/write operation fail; this variable is */
+/* initially set to 50. */
+/* */
+/* Debugging Facilities: */
+/* If the variable arc_jtag_ops.state_machine_debug is set to TRUE then */
+/* trace information will be output. */
+/* */
+/* Host/Target Byte Order: */
+/* The register contents returned by the read/write aux/core register */
+/* functions, or supplied to them, are in little-endian byte order. */
+/* */
+/* The memory contents returned by the read/write word/chunk/pattern */
+/* functions, or supplied to them, are in host byte order; the functions */
+/* perform whatever byte-swapping is required by the endiannness of the */
+/* target. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_JTAG_OPS
+#define ARC_JTAG_OPS
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+#define ARC_TARGET_NAME "arcjtag"
+
+
+typedef enum
+{
+ JTAG_SUCCESS,
+ JTAG_READ_FAILURE,
+ JTAG_WRITE_FAILURE
+} JTAG_OperationStatus;
-#define ARC_NR_CORE_REGS 64
-#define MAX_ARC700_REG_SIZE 4
-#define JTAG_READ_FAILURE 0
-#define JTAG_WRITE_FAILURE 0
-enum arc_jtag_status
- {
+typedef enum
+{
JTAG_OPENED,
- JTAG_CLOSED,
- JTAG_RUNNING
- };
-
-struct jtag_ops{
- char *name;
- void (*jtag_open) (void);
- void (*jtag_close) (void);
- int (*jtag_memory_write) (unsigned int, unsigned int *, int);
- int (*jtag_memory_chunk_write) (unsigned int, unsigned int *, int);
- int (*jtag_memory_read) (unsigned int, unsigned int *, int);
- int (*jtag_memory_chunk_read) (unsigned int, unsigned int *, int);
- int (*jtag_read_aux_reg) (unsigned int, unsigned int *);
- int (*jtag_write_aux_reg) (unsigned int, unsigned int);
- int (*jtag_read_core_reg) (unsigned int, unsigned int *);
- int (*jtag_write_core_reg) (unsigned int, unsigned int);
- void (*jtag_wait) (void);
- void (*jtag_reset_board) (void);
- enum arc_jtag_status jtag_status;
- int arc_jtag_state_machine_debug;
-};
-
-
-#define IS_ARC700 (arc_get_architecture() == ARC700)
-#define IS_ARC600 (arc_get_architecture() == ARC600)
-#define IS_A5 (arc_get_architecture() == A5)
-#define IS_A4 (arc_get_architecture() == A4)
+ JTAG_CLOSED
+} JTAG_Status;
+
+
+typedef struct
+{
+ JTAG_Status status;
+ unsigned int retry_count;
+ Boolean state_machine_debug;
+
+ Boolean (*open) (ARC_RegisterNumber mem_subsys);
+ void (*close) (void);
+ void (*reset) (void);
+ void (*reset_board) (void);
+ void (*check_open) (void);
+
+ /* These operations return the number of bytes read/written. */
+ unsigned int (*memory_read_word) (ARC_Address address, ARC_Word *data); /* single word. */
+ unsigned int (*memory_write_word) (ARC_Address address, ARC_Word data); /* single word. */
+ unsigned int (*memory_read_chunk) (ARC_Address address, ARC_Byte *data, unsigned int words); /* block. */
+ unsigned int (*memory_write_chunk) (ARC_Address address, ARC_Byte *data, unsigned int words); /* block. */
+ unsigned int (*memory_write_pattern) (ARC_Address address, ARC_Word pattern, unsigned int words); /* block. */
+
+ JTAG_OperationStatus (*read_aux_reg) (ARC_RegisterNumber reg, ARC_RegisterContents *contents);
+ JTAG_OperationStatus (*write_aux_reg) (ARC_RegisterNumber reg, ARC_RegisterContents contents);
+ JTAG_OperationStatus (*read_core_reg) (ARC_RegisterNumber reg, ARC_RegisterContents *contents);
+ JTAG_OperationStatus (*write_core_reg) (ARC_RegisterNumber reg, ARC_RegisterContents contents);
+} JTAG_Operations;
+
+
+extern JTAG_Operations arc_jtag_ops;
+
+
+#endif /* ARC_JTAG_OPS */
+/******************************************************************************/
diff --git a/gdb/arc-jtag-tdep.c b/gdb/arc-jtag-tdep.c
deleted file mode 100644
index 84015387bb6..00000000000
--- a/gdb/arc-jtag-tdep.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/* Target dependent code for ARC700, for GDB, the GNU debugger.
-
- Copyright 2005 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>
-
- 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
- (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>
-
-#include "defs.h"
-#include "osabi.h"
-#include "frame.h"
-#include "regcache.h"
-#include "gdb_assert.h"
-#include "inferior.h"
-#include "gdbcmd.h"
-#include "reggroups.h"
-
-#include "arc-tdep.h"
-#include "arc-jtag.h"
-
-
-#ifdef ARC4_JTAG
-/* brk */
-unsigned int a4_jtag_breakpoint_size = 4;
-unsigned char a4_jtag_breakpoint_insn[4] = { 0x00, 0xfe, 0xff, 0x1f };
-#define A4_HALT_VALUE 0x02000000
-#else
-/* brk_s */
-unsigned int arc700_jtag_breakpoint_size = 2;
-unsigned char arc700_jtag_breakpoint_insn[2] = { 0xff, 0x7f };
-#endif
-
-
-
-struct arc_reg_info
-{
- char *name ;
- int hw_regno;
- char *description;
-#ifdef ARC4_JTAG
- enum arc4_jtag_regnums gdbregno;
-#else
- enum arc700_jtag_regnums gdbregno;
-#endif
- enum ARCProcessorVersion arcVersionSupported;
-};
-
-
-
-static const char *
-arc_jtag_register_name (int regno)
-{
- static char jtag_names[][30] = {
- "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",
- "sp",
- "ilink1",
- "ilink2",
- "blink",
-
- /* Extension core regs 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. */
- /*FIXMEA: The following 3 are supposed to be registers
- that are used only to encode immediate values in A4*/
- "r61",
- "r62",
-
- "pcl",
-
- /* Now the aux registers. */
-
- "status",
- "semaphore",
- "lp_start",
- "lp_end",
- "identity",
- "debug",
-
-#ifndef ARC4_JTAG
- "pc",
- "status32",
- "status32_l1",
- "status32_l2",
-
- "count0",
- "control0",
- "limit0",
- "int_vector_base",
- "aux_macmode",
- "aux_irq_lv12",
-
-
- "count1",
- "control1",
- "limit1",
- "aux_irq_lev",
- "aux_irq_hint",
- "eret",
- "erbta",
- "erstatus",
- "ecr",
- "efa",
- "icause1",
- "icause2",
- "aux_ienable",
- "aux_itrigger",
- "xpu",
- "bta",
- "bta_l1",
- "bta_l2",
- "aux_irq_pulse_cancel",
- "aux_irq_pending",
-
- /* Build configuration registers. */
- "bcr_0",
- "dccm_base_build",
- "crc_base_build",
- "bta_link_build",
- "dvbf_build",
- "tel_instr_build",
- "bcr_6",
- "memsubsys",
- "vecbase_ac_build",
- "p_base_address",
- "bcr_a",
- "bcr_b",
- "bcr_c",
- "bcr_d",
- "bcr_e",
- "mmu_build",
- "arcangel_build",
- "bcr_11",
- "d_cache_build",
- "madi_build",
- "dccm_build",
- "timer_build",
- "ap_build",
- "icache_build",
- "iccm_build",
- "dspram_build",
- "mac_build",
- "multiply_build",
- "swap_build",
- "norm_build",
- "minmax_build",
- "barrel_build",
-#endif
-
- };
-
- gdb_assert(ARRAY_SIZE (jtag_names) == NUM_REGS + NUM_PSEUDO_REGS);
- gdb_assert(regno >=0 && regno < NUM_REGS + NUM_PSEUDO_REGS);
-
- return jtag_names[regno];
-}
-
-int
-arc_jtag_register_reggroup_p (int regnum, struct reggroup *group)
-{
- /* These registers don't exist, so they are not in any reggroup. */
- if ((regnum >= 32 && regnum <= 59) || (regnum == 61) || (regnum == 62))
- return 0;
-
- /* Which regs to save/restore ? */
- if ((group == save_reggroup || group == restore_reggroup))
- {
- /* Save/restore:
- 1. all core regs, except PCL (PCL is not writable)
- 2. aux regs LP_START..LP_END (IDENTITY is not writable)
- 3. aux regs PC_REGNUM..STATUS32_L2
- 3. aux regs ERET..EFA */
- return ( ( regnum >= 0 && regnum < ARC_PCL_REGNUM)
- || ( regnum >= ARC_LP_START_REGNUM && regnum<= ARC_LP_END_REGNUM)
-#ifdef ARC4_JTAG
- || ( regnum == ARC_STATUS_REGNUM)
-#else
- || ( regnum >= ARC_PC_REGNUM && regnum <= ARC_STATUS32_L2_REGNUM)
- || ( regnum >= ARC_ERET_REGNUM && regnum <= ARC_EFA_REGNUM)
-#endif
- );
- }
-
- return -1;
-}
-
-static void
-arc_jtag_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
- struct frame_info *frame, int regnum, int all)
-{
- int i;
-
- if (regnum >= 0 )
- {
- default_print_registers_info (gdbarch, file, frame, regnum, all);
- return;
- }
-
- /* if regnum < 0 , print all registers */
-
- 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 */
- if (!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);
-
-#ifndef ARC4_JTAG
- default_print_registers_info (gdbarch, file,frame,
- ARC_STATUS32_REGNUM, all);
- default_print_registers_info (gdbarch, file, frame,
- ARC_BTA_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);
-
-
- /* PC */
- default_print_registers_info (gdbarch, file, frame,
- ARC_PC_REGNUM, all);
-#endif
- }
- else
- {
- /* This part needs cleaning up. */
- for (i = ARC_STATUS_REGNUM;
-#ifndef ARC4_JTAG
- i <= ARC_AUX_IRQ_PENDING_REGNUM;
-#else /*FIXMEA*/
- i <= ARC_DEBUG_REGNUM;
-#endif
- i ++ )
- default_print_registers_info (gdbarch, file, frame ,
- i, all);
-
-
- for (i = ARC_STATUS_REGNUM ;
-#ifndef ARC4_JTAG
- i <= ARC_AUX_IRQ_PENDING_REGNUM;
-#else /*FIXMEA*/
- i <= ARC_DEBUG_REGNUM;
-#endif
- i ++ )
- default_print_registers_info (gdbarch, file, frame,
- i, all);
-
-#ifndef ARC4_JTAG
- for (i = ARC_BCR_1_REGNUM ;
- i <= ARC_BCR_5_REGNUM ;
- i ++ )
- default_print_registers_info (gdbarch, file , frame,
- i , all);
-
- for (i = ARC_BCR_7_REGNUM ;
- i <= ARC_BCR_9_REGNUM;
- i ++ )
- default_print_registers_info (gdbarch, file, frame,
- i , all);
-
- for (i = ARC_BCR_F_REGNUM;
- i <= ARC_BCR_10_REGNUM;
- i ++ )
- default_print_registers_info (gdbarch, file, frame ,
- i , all);
-
- for (i = ARC_BCR_12_REGNUM;
- i <= ARC_BCR_1F_REGNUM;
- i ++)
- default_print_registers_info (gdbarch, file, frame ,
- i , all);
-#endif //if no ARC4_JTAG
-
-
- }
-}
-
-/* Command: aux-read <from> <to>
-
- Read and display a range of aux registers. Some of the aux registers
- (pc, debug, etc.) are part of the register set, but this is a more
- general interface.
-
- We should eventually change this to use the ui_out stuff rather than
- printf_filtered. */
-static void
-arc_jtag_aux_read_command (char *arg, int from_tty)
-{
- char *arg2 = 0;
- struct expression *expr;
- struct value *val;
- struct cleanup *old_chain = 0;
- int auxregno, auxregno2 = 0, nrregs;
- unsigned int *buf;
- int i, nrtransfered;
-
- if (!arg)
- {
- printf_filtered ("aux-read <REG-FROM> [<REG-TO>]\n");
- return;
- }
-
- /* strip leading spaces */
- while(*arg == ' ')
- arg++;
-
- /* two arguments ? */
- /* This assumes that the first arg cannot have spaces. (The disas command
- also seems to work this way.) */
- arg2 = strchr (arg, ' ');
-
- /* get the second one */
- if (arg2)
- {
- struct expression *expr2;
- struct value *val2;
-
- arg2[0] = 0;
- arg2++;
-
- expr2 = parse_expression (arg2);
- val2 = evaluate_expression (expr2);
- xfree (expr2);
-
- auxregno2 = *(int *)(VALUE_CONTENTS (val2));
- }
-
- /* first arg */
- expr = parse_expression (arg);
- val = evaluate_expression (expr);
- old_chain = make_cleanup (free_current_contents, &expr);
-
- auxregno = *(int *)(VALUE_CONTENTS (val));
-
- /* so, how many regs do we want ? */
- if (arg2)
- {
- if (auxregno2 < auxregno)
- {
- warning ("aux-read: %s < %s, showing one register", arg2, arg);
- nrregs = 1;
- }
- else
- nrregs = auxregno2 - auxregno + 1;
- }
- else
- nrregs = 1;
-
- buf = xcalloc (nrregs, sizeof(int));
- make_cleanup (free_current_contents, &buf);
-
- /* Go get 'em ! */
- nrtransfered = target_read_aux_reg (buf, auxregno, nrregs);
- if (nrtransfered <= 0)
- {
- do_cleanups (old_chain);
- error ("aux-read: couldn't read any registers.");
- }
- else if (nrtransfered < nrregs)
- {
- warning ("aux-read: could only read %d registers", nrtransfered);
- }
-
- gdb_assert (nrtransfered <= nrregs);
-
- /* Show them. */
- for (i = auxregno; i - auxregno < nrtransfered; ++i)
- {
- if ((i - auxregno) % 4 == 0)
- printf_filtered("%s%08x: ", ((i - auxregno) ? "\n" : ""), i);
-
- printf_filtered ("%08x ", buf[i - auxregno]);
- }
- printf_filtered ("\n");
-
- do_cleanups (old_chain);
-}
-
-/* aux-write <regnum> = <value>
- Write VALUE to aux register REGNUM. */
-static void
-arc_jtag_aux_write_command (char *arg, int from_tty)
-{
- char *value_arg = 0;
- struct expression *regnum_expr, *value_expr;
- struct value *regnum_val, *value_val;
- struct cleanup *old_chain = 0;
- unsigned int regnum, value;
- int err;
-
- if (!arg)
- {
- printf_filtered ("aux-write <regnum> = <value>\n");
- return;
- }
-
- value_arg = strchr(arg, '=');
- if (!value_arg)
- {
- error ("aux-write: can't find second argument\n\
-Usage: aux-write <regnum> = <value>");
- return;
- }
- value_arg[0] = 0;
- value_arg++;
-
- /* Regnum expression */
- regnum_expr = parse_expression (arg);
- regnum_val = evaluate_expression (regnum_expr);
- old_chain = make_cleanup (free_current_contents, &regnum_expr);
- regnum = *(unsigned int *)(VALUE_CONTENTS (regnum_val));
-
- /* Value expression */
- value_expr = parse_expression (value_arg);
- value_val = evaluate_expression (value_expr);
- make_cleanup (free_current_contents, &value_expr);
- value = *(unsigned int *)(VALUE_CONTENTS (value_val));
-
- /* Write it. */
- err = target_write_aux_reg (&value, regnum, 1);
- if (err != 1)
- {
- do_cleanups (old_chain);
- error ("aux-write: couldn't write to register 0x%x", regnum);
- }
-
- do_cleanups (old_chain);
-}
-
-#ifdef ARC4_JTAG
-// gdbarch_write_pc_ftype *write_pc;
-/*
- Write PC
- Arguments:
- 1.CORE_ADDR val : Contains the value to be written into PC.
- 2.ptid_t ptid: Process id of the process.
-
- Returns: void
- Description: FIXMEA: Update
- Reads the status register
- Inserts the value (upper 24 bit) into the bits
- 0-23 in the status register
- Write the status register
- */
-void
-a4_jtag_write_pc (CORE_ADDR val, ptid_t ptid)
-{
- CORE_ADDR insert_val = val >> 2;
- unsigned int buffer;
-
-
- if(debug_arc_jtag_target_message)
- printf_filtered ("\n -----***------------ a4_jtag_write_pc Entered ---*%%*#\n");
-
-
- target_read_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
-
- if (!(buffer & A4_HALT_VALUE))
- {
- if(debug_arc_jtag_target_message)
- printf_filtered ("\n***** Halting Processor... *********\n");
-
- buffer = buffer | A4_HALT_VALUE ;
- target_write_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
- /* Now the A4 processor has halted*/
- }
-
- if(debug_arc_jtag_target_message)
- printf_filtered (" \nWriting value %u to PC\n", val);
-
-
- target_read_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
- if(debug_arc_jtag_target_message)
- printf_filtered (" \nValue of Status Register before writing %d\
- \n Value of PC: 0x%x\n", buffer, buffer & 0x00ffffff);
-
- buffer = buffer & 0xff000000;
- insert_val = insert_val & 0x00ffffff;
- buffer = buffer | insert_val ;
-
- if(debug_arc_jtag_target_message)
- printf_filtered (" \nValue of Status Register to be written %d\
- \n Value of PC: 0x%x\n", buffer, buffer & 0x00ffffff);
-
- // jtag_ops.jtag_write_aux_reg (ARC_STATUS_REGNUM, buffer);
- target_write_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
-
- if(debug_arc_jtag_target_message)
- {
- target_read_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
- printf_filtered (" \nValue of Status Register after reading again %d\
- \n Value of PC: 0x%x\n", buffer, buffer & 0x00ffffff);
- }
-
- if(debug_arc_jtag_target_message)
- printf_filtered ("\n -----***------------ a4_jtag_write_pc Leaving ---*%%*#\n");
-
-}
-
-
-/*
- Read PC
- Arguments:
- 1.ptid_t ptid: Process id of the process.
-
- Returns: CORE_ADDR
- Description:
- Reads the status register
- Extracts the PC value from it.
- Right shift twice to get correct value of PC
- return PC
-*/
-CORE_ADDR
-a4_jtag_read_pc (ptid_t ptid)
-{
- unsigned int buffer;
-
- if (debug_arc_jtag_target_message)
- printf_filtered ("\n Entering a4_jtag_read_pc ()");
- buffer = 0;
- target_read_aux_reg (&buffer, ARC_HW_STATUS_REGNUM, 1);
- if (debug_arc_jtag_target_message)
- printf_filtered ("\n Value of Status Reg: 0x%x",buffer);
- buffer = buffer & 0x00ffffff;
- buffer = buffer << 2;
-
- if (debug_arc_jtag_target_message)
- printf_filtered ("\n Leaving a4_jtag_read_pc ()\
- \n Value of Pc: 0x%x\n", buffer);
-
- return buffer;
-}
-
-#endif // ARC4_JTAG
-
-ARCVariantsInfo arc_debug_processor_information;
-
-struct gdbarch *
-arc_jtag_init (struct gdbarch *gdbarch)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
-#ifndef ARC4_JTAG
- tdep->arc_breakpoint_size = arc700_jtag_breakpoint_size;
- tdep->arc_breakpoint_insn = arc700_jtag_breakpoint_insn;
-#else
- tdep->arc_breakpoint_size = a4_jtag_breakpoint_size;
- tdep->arc_breakpoint_insn = a4_jtag_breakpoint_insn;
-#endif
-
- set_gdbarch_num_regs (gdbarch, ARC_NR_REGS);
-#ifndef ARC4_JTAG
- set_gdbarch_pc_regnum (gdbarch, ARC_PC_REGNUM);
-#else
- // set_gdbarch_pc_regnum (gdbarch, ARC_STATUS_REGNUM);
- set_gdbarch_write_pc (gdbarch, a4_jtag_write_pc);
- set_gdbarch_read_pc (gdbarch, a4_jtag_read_pc);
-#endif
- set_gdbarch_register_name (gdbarch, arc_jtag_register_name);
-
- set_gdbarch_print_registers_info (gdbarch, arc_jtag_print_registers_info);
-
- tdep->register_reggroup_p = arc_jtag_register_reggroup_p;
-
- tdep->lowest_pc = 0;
-
- tdep->sigtramp_p = NULL;
-
- tdep->arc_processor_variant_info = &arc_debug_processor_information;
-
- /* Auxillary register commands. */
- add_cmd ("arc-aux-read", class_vars, arc_jtag_aux_read_command,
- "Read and show a range of auxillary registers.\n\
-Usage: arc-aux-read <REG-FROM> [<REG-TO>]\n\
-REG-FROM and REG-TO can be any expressions that evaluate to integers.\n\
-If REG-TO is not specified, one register is displayed.",
- &cmdlist);
-
- add_cmd ("arc-aux-write", class_vars, arc_jtag_aux_write_command,
- "Write to an auxillary register.\n\
-Usage: arc-aux-write <REG> = <VALUE>\n\
-REG and VALUE can be any expressions that evaluate to integers.",
- &cmdlist);
-
- return gdbarch;
-}
-
diff --git a/gdb/arc-jtag.c b/gdb/arc-jtag.c
index 9a86b6d4c8d..02c8b6e7963 100644
--- a/gdb/arc-jtag.c
+++ b/gdb/arc-jtag.c
@@ -1,1297 +1,1173 @@
-/* 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.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Sameer Dhavale <sameer.dhavale@codito.com>
- Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
+ Authors:
+ Sameer Dhavale <sameer.dhavale@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 <stdio.h>
-#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 creates an instance of a gdb 'target_ops' structure which */
+/* contains information and operations for debugging a remote ARC target */
+/* with JTAG. */
+/* */
+/* It also registers a number of ARC-specific commands with gdb. */
+/* */
+/* Usage: */
+/* The module exports a function _initialize_arc_jtag: the call to this */
+/* function is generated by the gdb build mechanism, so this function */
+/* should not be explicitly called. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+
+/* gdb header files */
#include "defs.h"
#include "inferior.h"
-#include "target.h"
-#include "breakpoint.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "libiberty.h"
+#include "gdb_assert.h"
+/* ARC header files */
+#include "config/arc/tm-embed.h"
+#include "arc-jtag.h"
+#include "arc-gpio.h"
#include "arc-tdep.h"
+#include "arc-board.h"
+#include "arc-jtag-ops.h"
+#include "arc-elf32-tdep.h"
+#include "arc-architecture.h"
+#include "arc-registers.h"
+#include "arc-jtag-actionpoints.h"
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/io.h>
-#include <sys/types.h>
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
-#include <assert.h>
+typedef enum
+{
+ CLEAR_USER_BIT,
+ RESTORE_USER_BIT
+} Status32Action;
-#include "arc-jtag.h"
-#include "arc-jtag-ops.h"
-#include "gdbcore.h"
-#include "gdbarch.h"
-#include "regcache.h"
-#include "command.h"
-#include "gdbcmd.h"
-#include <signal.h>
-/* Flag to print debug messages from here. */
-/* FIXMEA:
-static int debug_arc_jtag_target_message;
-*/
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
-#define ENTERMSG \
-do {\
-if(debug_arc_jtag_target_message) \
-printf_filtered ("--- entered %s:%s()\n", __FILE__, __FUNCTION__); \
-} while(0)
-
-#define ENTERARGS(fmt, args...) \
-do { \
-if(debug_arc_jtag_target_message) \
-printf_filtered ("--- entered %s:%s(" fmt ")\n", __FILE__, __FUNCTION__, args);\
-} while(0)
-
-#define LEAVEMSG \
-do { \
-if(debug_arc_jtag_target_message) \
-printf_filtered ("--- exited %s:%s()\n", __FILE__, __FUNCTION__); \
-} while(0)
-
-/* The number of times a memory read/write operation should be attempted
- before returning an error.
-*/
-#define MEMORY_TRANSFER_ATTEMPTS 10
+#define ARC_CONFIGURATION_COMMAND "arc-configuration"
+#define ARC_RESET_BOARD_COMMAND "arc-reset-board"
+#define ARC_LIST_ACTIONPOINTS_COMMAND "arc-list-actionpoints"
+#define ARC_FSM_DEBUG_COMMAND "arcjtag-debug-statemachine"
+#define ARC_JTAG_RETRY_COMMAND "arcjtag-retry-count"
-/* defined in arc-jtag-ops.c */
-extern unsigned int arcjtag_retry_count;
+#define ARC_CONFIGURATION_COMMAND_USAGE "Usage: info " ARC_CONFIGURATION_COMMAND "\n"
+#define ARC_RESET_BOARD_COMMAND_USAGE "Usage: " ARC_RESET_BOARD_COMMAND "\n"
+#define ARC_LIST_ACTIONPOINTS_COMMAND_USAGE "Usage: " ARC_LIST_ACTIONPOINTS_COMMAND "\n"
-struct target_ops arc_debug_ops;
-extern struct jtag_ops arc_jtag_ops;
-static void arc_debug_interrupt (int signo);
-static void arc_debug_interrupt_twice (int signo);
-static void arc_print_processor_variant_info (void);
-static int arc_debug_write_aux_register (int hwregno, int *buf);
-static int arc_debug_read_aux_register (int hwregno, int *buf);
-static int arc_debug_read_core_register (int hwregno, int *buf);
+/* The gdb target operations structure for this target. */
+static struct target_ops jtag_target_ops;
+/* A set of pointers to operations for reading/writing registers/memory in the
+ JTAG target. */
+static TargetOperations operations;
-/* Register Mapping information between GDB regnums
- and actual hardware register numbers.
-*/
+/* The h/w register numbers of various auxiliary registers needed for
+ controlling the target processor. */
+static ARC_RegisterNumber lp_start_regnum;
+static ARC_RegisterNumber lp_end_regnum;
+static ARC_RegisterNumber icache_ivic_regnum;
+static ARC_RegisterNumber icache_control_regnum;
+static ARC_RegisterNumber dcache_ivdc_regnum;
+static ARC_RegisterNumber dcache_control_regnum;
-struct arc_reg_info
-{
- char *name ;
- enum arc_hw_regnums hw_regno;
- char *description;
-#ifdef ARC4_JTAG
- enum arc4_jtag_regnums gdbregno;
-#else
- enum arc700_jtag_regnums gdbregno;
-#endif
- enum ARCProcessorVersion arcVersionSupported;
-};
-#define RBCR(name, hwregno , desc, gdbregno, version) { #name, hwregno , desc , gdbregno , version } ,
+/* -------------------------------------------------------------------------- */
+/* external data */
+/* -------------------------------------------------------------------------- */
-#undef RAUX
-struct arc_reg_info arc_bcr_reg_info [] =
- {
- #include "arc-regnums-defs.h"
- };
+/* This declaration should be in the file breakpoint.h (a gdb core file). */
+extern struct breakpoint *breakpoint_chain;
-#undef RAUX
-#undef RBCR
-#define RAUX(name, hwregno , desc, gdbregno, version) { #name , hwregno , desc , gdbregno , version } ,
-struct arc_reg_info arc_aux_reg_map[] =
- {
- #include "arc-regnums-defs.h"
- };
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+#define IS_ARC700 (arc_get_architecture(arc_read_jtag_aux_register) == ARC700)
+#define IS_ARC600 (arc_get_architecture(arc_read_jtag_aux_register) == ARC600)
-static void
-arc_update_architecture(void)
-{
- unsigned int idinfo;
- unsigned short tmp;
- struct gdbarch_tdep * tdep = gdbarch_tdep (current_gdbarch);
-
- if (IS_ARC700) {
- tdep->arc_processor_variant_info->arcprocessorversion = ARC700;
- set_gdbarch_decr_pc_after_break (current_gdbarch,0);
- }
- else if(IS_ARC600) {
- tdep->arc_processor_variant_info->arcprocessorversion = ARC600;
- set_gdbarch_decr_pc_after_break (current_gdbarch,2);
- }
- else if(IS_A5) {
- warning ("A5 debugging is unsupported and may be buggy.");
- tdep->arc_processor_variant_info->arcprocessorversion = A5;
- }
- else {
- tdep->arc_processor_variant_info->arcprocessorversion = A4;
- set_gdbarch_decr_pc_after_break (current_gdbarch,0);
- }
-}
-/* Get us out of user mode. */
-static unsigned int
-clear_status32_user_bit ()
-{
- int rd;
-#ifndef ARC4_JTAG
- if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS32_REGNUM, &rd) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM);
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
- if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM, rd & ~0x80) == JTAG_READ_FAILURE)
- error("Failure writing to auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM);
-#endif
- return rd;
-}
+/* -------------------------------------------------------------------------- */
+/* 1) functions for reading/writing registers */
+/* -------------------------------------------------------------------------- */
-/* Restore a saved status32; use with clear_status32_user_bit(). */
-static void
-restore_status32_user_bit (unsigned int status32)
+/* Set UB bit in the DEBUG register: this allows brk_s instruction to work in
+ User mode.
+
+ Returns TRUE if the operation is successful. */
+
+static Boolean
+set_debug_user_bit (ARC_RegisterContents extra_bits)
{
-#ifndef ARC4_JTAG
- if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM, status32) == JTAG_READ_FAILURE)
- error("Failure writing to auxillary register 0x%x:status32 register", ARC_HW_STATUS32_REGNUM);
-#endif
+ /* The DEBUG User bit exists only in the ARC700 variant. */
+ if (IS_ARC700)
+ extra_bits |= DEBUG_USER;
+
+ /* If we have extra bits to be set in the DEBUG register. */
+ if (extra_bits != 0)
+ {
+ ARC_RegisterContents debug;
+
+ if (arc_read_jtag_aux_register(arc_debug_regnum, &debug, TRUE))
+ {
+ /* Set UB = 1. */
+ ARC_RegisterContents new_debug = debug | extra_bits;
+
+ /* Do the write only if it will change the register contents. */
+ if (new_debug != debug)
+ return arc_write_jtag_aux_register(arc_debug_regnum, new_debug, TRUE);
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
}
-/* UB bit in the debug register. It allows brk_s to work in user mode. */
+
+/* Clear or restore the User bit in the STATUS32 auxiliary register. */
+
static void
-set_debug_user_bit ()
+change_status32 (Status32Action action)
{
- if(is_arc700 ())
+ static ARC_RegisterContents status32 = 0;
+
+ if (action == CLEAR_USER_BIT)
{
- /* set UB = 1 */
- unsigned int debug;
- if (arc_jtag_ops.jtag_read_aux_reg (ARC_HW_DEBUG_REGNUM, &debug) == JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x:debug register",ARC_HW_DEBUG_REGNUM);
- debug |= 0x10000000;
- arc_jtag_ops.jtag_write_aux_reg (ARC_HW_DEBUG_REGNUM, debug);
+ /* Get processor out of user mode. */
+
+ if (arc_read_jtag_aux_register(arc_status32_regnum, &status32, FALSE))
+ {
+ /* If the User bit is actually set. */
+ if (status32 & STATUS32_USER)
+ if (!arc_write_jtag_aux_register(arc_status32_regnum,
+ status32 & ~STATUS32_USER, FALSE))
+ warning(_("can not clear User bit in STATUS32 auxiliary register"));
+ }
+ else
+ warning(_("can not read STATUS32 auxiliary register"));
+ }
+ else
+ {
+ /* If the User bit was actually cleared. */
+ if (status32 & STATUS32_USER)
+ if (!arc_write_jtag_aux_register(arc_status32_regnum, status32, FALSE))
+ warning(_("can not restore User bit in STATUS32 auxiliary register"));
}
}
+/* -------------------------------------------------------------------------- */
+/* 2) functions for reading/writing mmeory */
+/* -------------------------------------------------------------------------- */
-static void
-invalidateCaches (void)
+/* These functions should NOT be used within this module: they are intended
+ purely for use by the arc-memory module for reading/writing multiple words
+ of data at word-aligned addresses. */
+
+static unsigned int
+read_words (ARC_Address address,
+ ARC_Byte *data,
+ unsigned int words)
{
- if(arc_jtag_ops.jtag_write_aux_reg ( ARC_HW_ICACHE_IVIC , 1)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x1 to auxillary register 0x%x:Icache invalidate\n",ARC_HW_ICACHE_IVIC);
- if(arc_jtag_ops.jtag_write_aux_reg ( ARC_HW_DCACHE_IVIC , 1)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x1 to auxillary register 0x%x:Dcache invalidate\n",ARC_HW_DCACHE_IVIC);
+ DEBUG("reading %u words from 0x%08X on target board\n", words, address);
+
+ gdb_assert(IS_WORD_ALIGNED(address));
+
+ return arc_jtag_ops.memory_read_chunk(address, data, words);
}
-static void
-disableCaches (void)
+
+static unsigned int
+write_words (ARC_Address address,
+ ARC_Byte *data,
+ unsigned int words)
{
- /* Disabling Icache */
- if(arc_jtag_ops.jtag_write_aux_reg( ARC_HW_ICACHE_CONTROL ,0x1)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x1 to auxillary register 0x%x:Icache control register\n",ARC_HW_ICACHE_CONTROL);
- /* Disabling Dcache */
- if(arc_jtag_ops.jtag_write_aux_reg( ARC_HW_DCACHE_CONTROL ,0x1)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x1 to auxillary register 0x%x:Dcache control register\n",ARC_HW_DCACHE_CONTROL);
-}
+ gdb_assert(IS_WORD_ALIGNED(address));
+ DEBUG("writing %u words to 0x%08X on target board\n", words, address);
-/* Function: arc_debug_open
- * Parameters :
- * 1. args :
- * 2. from_tty:
- * Returns : void
- * Description:
- 1. Connect to the jtag target .
- 2. Read the number of action points supported.
- 3. Read the configuration of action points.
- 4. Set up internal data structures for number of hardware
- breakpoints and watchpoints.
- 5. Set the UB bit to 1 for ARC700 and not for ARC600.
- *
- */
+ return arc_jtag_ops.memory_write_chunk(address, data, words);
+}
-void
-arc_debug_open (char *args, int from_tty)
+
+static unsigned int
+write_pattern (ARC_Address address,
+ ARC_Word pattern,
+ unsigned int words)
{
- ENTERARGS("%s", args);
- target_preopen(from_tty);
-
- reopen_exec_file ();
- reread_symbols ();
-
- unpush_target (&arc_debug_ops);
- arc_jtag_ops.jtag_open();
- push_target (&arc_debug_ops);
-
- /* Call arc_update_architecture if opened successfully. */
- arc_update_architecture();
- /* Fixme :: Should these be in create_inferior or
- some place else ?. We would not like these here
- when attach starts working.
- */
- disableCaches();
-#ifdef ARC4_JTAG
- if(arc_jtag_ops.jtag_write_aux_reg (ARC_HW_STATUS_REGNUM, 0x02000000)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x0200 0000 to auxillary register 0x%x:status register\n",ARC_HW_STATUS_REGNUM);
-
- if (from_tty)
- printf_filtered ("Connected to the arcjtag target.\n");
-
-#else
- if(arc_jtag_ops.jtag_write_aux_reg (ARC_HW_STATUS32_REGNUM, 0x1)==JTAG_WRITE_FAILURE)
-
- error("Failure writing 0x1 to auxillary register 0x%x:status32 register\n",ARC_HW_STATUS32_REGNUM);
-
- /* allow breakpoints in user mode. */
- set_debug_user_bit ();
-
-
- if (from_tty)
- printf_filtered ("Connected to the arcjtag target.\n");
-#endif
+ gdb_assert(IS_WORD_ALIGNED(address));
+
+ DEBUG("writing pattern 0x%08X repeated %u times to 0x%08X on target board\n", pattern, words, address);
+
+ return arc_jtag_ops.memory_write_pattern(address, pattern, words);
}
-void arc_debug_close()
+
+/* -------------------------------------------------------------------------- */
+/* 3) functions for processor cache management */
+/* -------------------------------------------------------------------------- */
+
+/* Invalidate the target processor's caches. */
+
+static void
+invalidate_caches (void)
{
- arc_jtag_ops.jtag_close();
+ /* N.B. when invalidating the data caches, we must first set the DC_CTRL.IM
+ bit to 1 to ensure that any "dirty" lines in the cache get flushed
+ to main memory. */
+ (void) arc_write_jtag_aux_register(dcache_control_regnum, DC_CTRL_IM, TRUE);
+ (void) arc_write_jtag_aux_register(icache_ivic_regnum, IC_IVIC_IV, TRUE);
+ (void) arc_write_jtag_aux_register(dcache_ivdc_regnum, DC_IVDC_IV, TRUE);
}
-/* Function: arc_debug_attach
- * Parameters :
- * 1. char *x:
- * 2. int i:
- * Returns : void
- * Description:
- * 1. attach without resetting the board
- * 2. get all Board configuration registers of interest.
- * if ARC700 set the UB bit to 1. (This is invalid in the
- * ARC600).
- */
+/* Disable the target processor's caches. */
-void
-arc_debug_attach (char *x, int i)
+static void
+disable_caches (void)
{
-
- ENTERMSG;
+ (void) arc_write_jtag_aux_register(icache_control_regnum, IC_CTRL_DC, TRUE);
+ (void) arc_write_jtag_aux_register(dcache_control_regnum, DC_CTRL_DC, TRUE);
}
-/* Function: arc_debug_attach
- * Parameters :
- * 1. char *x:
- * 2. int i:
- * Returns : void
- * Description:
- * 1. Detach without resetting the board.
- */
-void
-arc_debug_detach (char *x, int i)
+/* -------------------------------------------------------------------------- */
+/* 4) functions for JTAG interface management */
+/* -------------------------------------------------------------------------- */
+
+/* Open the JTAG interface to the debug target. */
+
+static Boolean
+open_JTAG_interface (int from_tty)
{
-
- ENTERMSG;
+ /* This is somewhat inelegant, but commands read from scripts in the gdb
+ testsuite are regarded as though they were being input interactively
+ (i.e. from_tty is 1), and interactive queries may be made (such as
+ asking the user whether the program currently being debugged should be
+ killed first) - and these queries hang the tests!
+
+ So, if the environment variable is set, assume that the gdb test suite is
+ being run, so that no such queries will be made.
+
+ It is not possible to make this check in the top-level command handler
+ loop, as the output from some other commands (e.g. 'file') depend on the
+ from_tty parameter passed to them, and the gdb test scripts expect to get
+ the interactive version of the output! */
+ target_preopen(from_tty && (getenv("ARC_GDB_TEST") == NULL));
+
+ gdb_assert(arc_jtag_ops.open != NULL);
- /* Let it continue. */
- target_resume (inferior_ptid, 0, 0);
+ return arc_jtag_ops.open(arc_aux_find_register_number("MEMSUBSYS", ARC_HW_MEMSUBSYS_REGNUM));
}
-/* Function: arc_debug_resume
- * Parameters :
- * 1. ptid_t ptid:
- * 2. int step: 1 - single step , 0 run freely.
- * 3. enum target_signal signal;
- * Returns : void
- * Description:
- * 1. What about Pipecleaning?
- * 2. Write 0 to the HALT bit in status32.
- * 3. Send a signal (ignore) in this case.
- * 4. if(step) use hardware single step on the ARC700.
- * done by setting the IS bit in the debug register
- * and clearing the halt bit in status32.
- *
+/* Close the JTAG interface to the debug target.
+
+ Parameter:
+ resume: TRUE if program execution on the target should be allowed to resume
*/
-void
-arc_debug_resume (ptid_t ptid, int step, enum target_signal signal)
+static void
+close_JTAG_interface (Boolean resume)
{
-
- ENTERARGS("%d,%d,%d", ptid.pid, step, signal);
- /* Make the inferior resume execution, sending a signal if necessary */
- unsigned int rd;
-
- /* Because breakpoints may have been set/removed. */
- invalidateCaches ();
-
- /* This bit is required if breakpoints are to be allowed in user mode. We
- set it in target_open, but the operating system might clear it. So we
- set it every time we resume. */
- set_debug_user_bit ();
-
- if(step)
- {
-
- /* reading debug reg */
- if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_DEBUG_REGNUM,&rd)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x:debug register",ARC_HW_DEBUG_REGNUM);
-#ifdef ARC4_JTAG
- rd |= 0x801; /*Setting the IS and the SS bit in the status register
- for the A4 core to allow it to single step. */
-#else
- /* Mask for Single Stepping changes for ARC600 and ARC700. */
- if(is_arc700())
- rd |= 0x800;
- else
- if(is_arc600())
- rd |= 0x801;
-#endif
-
- /* Writing to IS bit in DEBUG register for
- hardware single instruction stepping. */
- if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_DEBUG_REGNUM ,rd)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to auxillary register 0x%x:debug register\n",rd,ARC_HW_DEBUG_REGNUM);
- }
- else
- {
- /* Restarting the processor by clearing the 'H' bit in the status register*/
-#ifdef ARC4_JTAG
- /* reading the status reg */
- if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS_REGNUM,&rd)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x:status register",ARC_HW_STATUS_REGNUM);
-
- rd = rd & ~(0x02000000);
-
- /* starting the halted processor */
- if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS_REGNUM,rd)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to auxillary register 0x%x:status register\n",rd,ARC_HW_STATUS_REGNUM);
-#else
- /* reading the status32 reg */
- if(arc_jtag_ops.jtag_read_aux_reg(ARC_HW_STATUS32_REGNUM,&rd)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x:status32 register",ARC_HW_STATUS32_REGNUM);
-
- rd = rd & ~(0x1);
-
- /* starting the halted processor */
- if(arc_jtag_ops.jtag_write_aux_reg(ARC_HW_STATUS32_REGNUM,rd)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to auxillary register 0x%x:status32 register\n",rd,ARC_HW_STATUS32_REGNUM);
-#endif
- }
+ /* If we have a target connected. */
+ if (arc_jtag_ops.status == JTAG_OPENED)
+ {
+ arc_elf32_close(resume);
+
+ /* And close the connection. */
+ arc_jtag_ops.close();
+ }
}
-/* For the ^C signal handler. */
-static void (*ofunc) (int);
-/* The command line interface's stop routine. This function is installed as
- a signal handler for SIGINT. The first time a user requests a stop, we
- call target_stop to send a break or ^C. If there is no response from the
- target (it didn't stop when the user requested it), we ask the user if
- he'd like to detach from the target. */
+/* -------------------------------------------------------------------------- */
+/* 5) functions for starting/stopping the processor */
+/* -------------------------------------------------------------------------- */
+
+/* Start the processor by clearing the 'H' bit in the STATUS32 register. */
+
static void
-arc_debug_interrupt (int signo)
+start_processor (void)
{
- /* If we get the signal twice, do something more drastic. */
- signal (signo, arc_debug_interrupt_twice);
-
- target_stop ();
+ ARC_RegisterContents status32;
+
+ if (!arc_read_jtag_aux_register (arc_status32_regnum, &status32, FALSE) ||
+ !arc_write_jtag_aux_register(arc_status32_regnum, status32 & ~STATUS32_HALT, FALSE))
+ warning(_("can not clear Halt bit in STATUS32 auxiliary register - can not start processor"));
}
-/* The user typed ^C twice. */
+
+/* Stop the processor by setting the 'FH' bit in the DEBUG register. */
+
static void
-arc_debug_interrupt_twice (int signo)
+stop_processor (void)
{
- signal (signo, ofunc);
+ if (!arc_write_jtag_aux_register(arc_debug_regnum, DEBUG_FORCE_HALT, FALSE))
+ warning(_("can not set Force Halt bit in DEBUG auxiliary register - can not halt processor"));
+}
+
+
+/* Try to halt the processor (if it is running) upon connection to the debug
+ target. Return TRUE if the processor is successfuly halted. */
- if (query ("Interrupted while waiting for the program.\n\
-Give up (and stop debugging it)? "))
+static Boolean
+halt_processor_on_connection (void)
+{
+ Boolean warn_on_read_failure = TRUE;
+ Boolean inform_running = TRUE;
+ Boolean halt_attempted = FALSE;
+ unsigned int tries = 0;
+
+ /* Unfortunately, if the gpio driver module has been installed on the host
+ machine, the gpio read/write operations appear to work even if the host
+ is NOT physically connected to the JTAG target!
+
+ There does not appear to be any way of detecting that situation - all we
+ can do is bale out if we have not succeded in reading the STATUS32 register
+ after the required number of retries! */
+ do
{
- target_mourn_inferior ();
- throw_exception (RETURN_QUIT);
+ ARC_RegisterContents status = 0;
+
+ /* Read the STATUS32 register here to check if the halt bit is set. */
+ if (arc_read_jtag_aux_register(arc_status32_regnum, &status, warn_on_read_failure))
+ {
+ if (status & STATUS32_HALT)
+ {
+ printf_filtered(_("Processor is halted.\n"));
+ return TRUE;
+ }
+
+ if (inform_running)
+ {
+ /* We inform the user that the processor is running only once
+ (to avoid swamping the user with messages!). */
+ printf_filtered(_("Processor is running. Trying to halt it...\n"));
+ inform_running = FALSE;
+ }
+
+ stop_processor();
+ halt_attempted = TRUE;
+ }
+ else
+ {
+ /* We give a warning only on the first read failure (otherwise the
+ user can get swamped with warnings!). */
+ warn_on_read_failure = FALSE;
+ }
+
+ /* Just in case we actually did fail to read/write the port. */
+ if (gpio_port_error)
+ {
+ warning(_("error in accessing parallel port via "
+ GPIO_DEVICE
+ " - check connection to target board."));
+ return FALSE;
+ }
}
+ while (++tries <= arc_jtag_ops.retry_count);
+
+ if (halt_attempted)
+ printf_filtered(_("Can not halt processor!\n"));
+ else
+ printf_filtered(_("Can not connect to processor!\n"));
- signal (signo, arc_debug_interrupt);
+ return FALSE;
}
-/* Function: arc_debug_wait
- * Parameters :
- * 1. ptid_t ptid:
- * 2. struct target_waitstatus *status: Indicates status at end
- of wait for F.E.
- * Returns : void
- * Description:
- * Poll status32 for the value of H bit.
- * After H bit is set in status32.
- * Wait till LD(load pending bit) in the DEBUG register
- * is cleared.
- * SH bit is set if flag instruction was used to halt the processor.
- * BH bit is set if the ARCompact processor stopped due to
- * a brk_s instruction. Set the target_waitstatus (signal) to SIGTRAP
- * only in such a situation.
- *
- */
-ptid_t
-arc_debug_wait (ptid_t ptid, struct target_waitstatus *status)
-{
- unsigned int debug;
- ENTERMSG;
+/* -------------------------------------------------------------------------- */
+/* 6) local functions called from outside this module (from gdb) */
+/* -------------------------------------------------------------------------- */
- /* signal handler for Control-C. */
- ofunc = signal (SIGINT, arc_debug_interrupt);
+/* Connect to the JTAG target.
- arc_jtag_ops.jtag_wait();
- /* put the old function back. */
- signal (SIGINT, ofunc);
+ Parameters:
+ args : user arguments to the 'target' command
+ from_tty: non-zero if the 'target' command was issued at the terminal
- /* If the SH ("self halt") bit is set, we stopped because of the flag
- instruction, which is used by programs to exit. */
- if (arc_jtag_ops.jtag_read_aux_reg (ARC_HW_DEBUG_REGNUM,
- &debug) == JTAG_READ_FAILURE)
- {
- error ("Failure reading from debug register");
- }
+ The arguments may be:
+ noreset | <xbf file>
+
+ If a XBF file is specified, the target board FPGA is blasted as part of the
+ connection process. */
+
+static void
+arc_jtag_open (char *args, int from_tty)
+{
+ /* By default, reset the board, in case it has been left in a funny state by
+ the last connection. */
+ Boolean reset_required = TRUE;
+ char *xbf_file = NULL;
+ FPGA_Status fpga;
- /* SH bit of debug register */
- if (debug & ARC_DEBUG_REG_SH_BIT)
+ ENTERARGS("\"%s\" (%d)", (args) ? args : "", from_tty);
+
+ if (args)
{
- int exitcode;
- status->kind = TARGET_WAITKIND_EXITED;
-
- /* Exit code of the program. */
- if (arc_jtag_ops.jtag_read_core_reg (0, &exitcode) == JTAG_READ_FAILURE)
- {
- warning ("Failure reading from register r0, assuming exit code = 0");
- status->value.integer = 0;
- }
- status->value.integer = exitcode;
+ if (strcmp(args, "noreset") == 0)
+ reset_required = FALSE;
+ else
+ xbf_file = args;
}
- else
+
+ /* Is the target board FPGA already configured? */
+ fpga = arc_is_FPGA_configured();
+
+ switch (fpga)
{
- status->kind = TARGET_WAITKIND_STOPPED;
- status->value.sig = TARGET_SIGNAL_TRAP;
+ case INACCESSIBLE:
+ /* A warning has already been given. */
+ return;
+
+ case UNCONFIGURED:
+ if (xbf_file == NULL)
+ {
+ warning(_("target FPGA is not configured; XBF file must be specified"));
+ return;
+ }
+ break;
+
+ case CONFIGURED:
+ break;
}
-#ifndef ARC4_JTAG
- /* Bug #1311 (ARC600): Setting a breakpoint on the last instruction of a
- ZOL causes GDB to stop at LP_START. Detect this condition and warn the
- user. */
- if (is_arc600 ())
+ /* As far as we know, there is no program loaded on the target. */
+ arc_program_is_loaded = FALSE;
+
+ /* Find the h/w register numbers of various auxiliary registers that we need
+ for debugging.
+
+ N.B. the gdb 'attach' command can attach only to an arcjtag target that
+ has been created (by this function) within the *same* debugging
+ session, i.e. the sequence of commands issued by the user is of the
+ form:
+ target arcjtag ... detach ... attach
+
+ This means that we do not need to worry about finding these numbers
+ again on an 'attach', as they should be the same (they should really
+ be the same for *any* target, anyway - we are simply being paranoid
+ in looking them up, rather than having their numbers hard-coded, in
+ any case!).
+
+ Of course, there are really pathological cases such as the user
+ blasting the (ARCangel) target with an XBF giving a different
+ processor configuration, or even physically disconnecting the target
+ from the host machine and connecting a different target, between
+ issuing the 'detach' and the 'attach' commands (and that could change
+ the target's actionpoint configuration, if nothing else!) - but if
+ the user wants to do that then that is his problem! */
+ arc_elf32_find_register_numbers();
+
+ lp_start_regnum = arc_aux_find_register_number("LP_START", ARC_HW_LP_START_REGNUM);
+ lp_end_regnum = arc_aux_find_register_number("LP_END", ARC_HW_LP_END_REGNUM);
+ icache_ivic_regnum = arc_aux_find_register_number("IC_IVIC", ARC_HW_IC_IVIC_REGNUM);
+ icache_control_regnum = arc_aux_find_register_number("IC_CTRL", ARC_HW_IC_CTRL_REGNUM);
+ dcache_ivdc_regnum = arc_aux_find_register_number("DC_IVDC", ARC_HW_DC_IVDC_REGNUM);
+ dcache_control_regnum = arc_aux_find_register_number("DC_CTRL", ARC_HW_DC_CTRL_REGNUM);
+
+
+ /* Just to be sure that it is not in the target stack... */
+ (void) unpush_target (&jtag_target_ops);
+
+ /* Now try to open the JTAG interface. */
+ if (open_JTAG_interface(from_tty))
{
- unsigned int pc, lp_start, lp_end, lp_count;
- arc_debug_read_core_register (ARC_LP_COUNT_REGNUM, &lp_count);
- if (lp_count != 0)
- {
- arc_debug_read_aux_register (ARC_HW_PC_REGNUM, &pc);
- arc_debug_read_aux_register (ARC_HW_LP_START_REGNUM, &lp_start);
-
- if (pc == lp_start)
- {
- extern struct breakpoint *breakpoint_chain;
- struct breakpoint *b;
- arc_debug_read_aux_register (ARC_HW_LP_END_REGNUM, &lp_end);
-
- for (b = breakpoint_chain; b; b = b->next)
- {
- /* lp_end is the address of the last instruction + the
- size of the last instruction. We could use the
- disassembler and find out the size, or just try both
- possible sizes. */
- if ((b->enable_state == bp_enabled && !b->pending) &&
- b->loc->address == lp_end-4 || b->loc->address == lp_end-2)
- {
- warning ("Did you set a breakpoint on the last instruction of \n\
-a Zero Overhead Loop ? Such breakpoints do not work properly.");
- }
- }
- }
- }
+ /* If a reset is required, do it now, in case it is necessary to reset
+ the target clock sources to their defaults before trying to access
+ the target's auxiliary registers! */
+ if (reset_required)
+ {
+ arc_reset_board();
+ arc_jtag_ops.reset_board();
+ }
+
+ if (fpga == CONFIGURED)
+ {
+ /* If we are going to blast the board, don't bother halting the
+ processor first. */
+ if ((xbf_file == NULL) && !halt_processor_on_connection())
+ {
+ /* We could not halt the processor. */
+ close_JTAG_interface(FALSE);
+ return;
+ }
+ }
+
+ /* If we have been given an XBF file. */
+ if (xbf_file)
+ {
+ /* Try to blast the board.
+ N.B. if the blasting operation fails for any reason,
+ arc_blast_board calls error and does not return! */
+ arc_blast_board(xbf_file, from_tty);
+ }
+
+ /* Get out of user mode so that we can access anything anywhere. */
+ change_status32(CLEAR_USER_BIT);
+
+ /* We do not know whether the target processor supports actionpoints until
+ after we have connected to it, as we have to read the AP_BUILD
+ configuration register to find that out. */
+ (void) arc_initialize_actionpoint_ops(&jtag_target_ops);
+
+ (void) push_target (&jtag_target_ops);
+
+ if (!reset_required)
+ {
+ /* If we have been explicitly told NOT to reset the board, it is
+ most likely because we have connected to a target upon which a
+ program is running and we want to debug that program - so assume
+ we have a program ready for execution on the target. */
+ target_mark_running(&jtag_target_ops);
+ arc_program_is_loaded = TRUE;
+
+ /* Set to_has_execution back to 0; this stops the user getting the
+
+ A program is being debugged already.
+ Are you sure you want to change the file? (y or n) n
+
+ message on issuing the 'file' command after the connection. */
+ current_target.to_has_execution = 0;
+ }
+
+ if (from_tty)
+ printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n"));
}
-#endif
- return inferior_ptid;
+ else
+ error(_("Can not connect to target"));
}
-static unsigned int
-arc_get_hw_regnum_mapping ( int regno )
-{
- int i;
-
- if (regno >= ARC_STATUS_REGNUM
-#ifdef ARC4_JTAG
- && regno <= ARC_DEBUG_REGNUM
-#else
- && regno <= ARC_AUX_IRQ_PENDING_REGNUM
-#endif
- )
- return arc_aux_reg_map[regno - ARC_STATUS_REGNUM].hw_regno;
-
- for ( i = 0 ; i < (sizeof(arc_bcr_reg_info) / sizeof (struct arc_reg_info)) ; i++)
- {
- if (regno == arc_bcr_reg_info[i].gdbregno)
- return arc_bcr_reg_info[i].hw_regno;
- }
- return -1;
+/* Close the connection to the target. */
+
+static void
+arc_jtag_close (int quitting)
+{
+ ENTERMSG;
+ close_JTAG_interface(FALSE);
}
-/* Function: arc_debug_fetch_regs.
- * Parameters :
- * 1. int regnum: Register number. If register number is -1.Fetch
- * all the registers.Read all core registers here.
- * Returns : void
- * Description:
- * Set up regcache_raw_supply(current_regcache,regno)
- *
- */
-void
-arc_debug_fetch_regs (int regno)
+/* Attach to the debug target without resetting the board.
+
+ Parameters:
+ args : user arguments to the 'attach' command (ignored)
+ from_tty: non-zero if the 'attach' command was issued at the terminal
+*/
+
+static void
+arc_jtag_attach (char *args, int from_tty)
{
- /* Read all core registers */
- ENTERARGS("%d",regno);
-
- int dummyvalue = 0xABCDABCD;
- unsigned int hw_regno;
- unsigned int read_buf;
-
- if( regno < ARC_NR_CORE_REGS )
- {
- hw_regno = regno;
- if(arc_jtag_ops.jtag_read_core_reg(regno,&read_buf)==JTAG_READ_FAILURE)
- error("Failure reading from core register 0x%x\n",regno);
- }
- else
- {
-#ifndef ARC4_JTAG
- if( regno > ARC_NR_REGS)
- error("Invalid Register Number\n");
-#endif
-
- hw_regno = arc_get_hw_regnum_mapping (regno);
- if(arc_jtag_ops.jtag_read_aux_reg(hw_regno,&read_buf)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x",hw_regno);
- }
-
- if(debug_arc_jtag_target_message)
+ ENTERARGS("\"%s\" (%d)", args, from_tty);
+
+ /* Try to open the JTAG interface. */
+ if (open_JTAG_interface(from_tty))
{
- printf_filtered("HW_Regno=0x%x",hw_regno);
- printf_filtered("Read Regno 0x%x the value 0x%x\n",hw_regno,read_buf);
+ /* Try to halt the processor (if it is running). */
+ if (halt_processor_on_connection())
+ {
+ /* Check that the processor architecture is correct. */
+ ARCHITECTURE_CHECK(current_gdbarch,
+ (current_objfile) ? current_objfile->obfd : NULL);
+
+ if (from_tty)
+ printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n"));
+ }
}
- regcache_raw_supply(current_regcache,regno,&read_buf);
-
- LEAVEMSG;
+ else
+ error(_("Can not connect to target"));
}
-/* Function: arc_debug_fetch_regs.
- * Parameters :
- * 1. int regnum: Register number. If register number is -1.Fetch
- * all the registers.Read all core registers here.
- * Returns : void
- * Description:
- * Use deprecated register information for this or regcache_read_unsigned .
- * FIXME: would need to change to use regcache_raw_supply instead.
- */
+/* Detach from the debug target without resetting the board.
+ Parameters:
+ args : user arguments to the 'detach' command (ignored)
+ from_tty: non-zero if the 'detach' command was issued at the terminal
+*/
-void
-arc_debug_store_regs (int regno)
+static void
+arc_jtag_detach (char *args, int from_tty)
{
- /* write_all core registers */
- ENTERARGS("%d", regno);
- unsigned int hw_regno;
- unsigned int write_buf;
-
- if(debug_arc_jtag_target_message)
- printf_filtered("\n%d",regno);
-
- regcache_raw_collect(current_regcache,regno,&write_buf);
- if( regno < ARC_NR_CORE_REGS )
- {
- if(arc_jtag_ops.jtag_write_core_reg(regno,write_buf)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to core register 0x%x",write_buf,regno);
- }
- else
- {
-#ifndef ARC4_JTAG
- if (regno > ARC_NR_REGS)
- error ("Invalid register number \n");
-#endif
-
- hw_regno = arc_get_hw_regnum_mapping (regno);
+ ENTERMSG;
+ close_JTAG_interface(TRUE);
+}
- if(debug_arc_jtag_target_message)
- printf_filtered("Writing to regno 0x%x the value 0x%x",
- hw_regno,write_buf);
- if(arc_jtag_ops.jtag_write_aux_reg(hw_regno,write_buf)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to auxillary register 0x%x\n",write_buf,hw_regno);
- }
-}
+/* Cause the inferior on the debug target to resume execution, sending a signal
+ if necessary.
+ Parameters:
+ ptid : the thread id of the thread to be resumed (ignored)
+ step : 1 means single step, 0 run freely.
+ signal: the number of the signal to be sent
-/* Function: arc_debug_prepare_to_store.
- * Parameters :
- * 1. int regnum: Register number. If register number is -1.Fetch
- * all the registers.Read all core registers here.
- * Returns : void
- * Description:
- * Use deprecated register information for this.
- * FIXME: would need to change to use regcache_raw_supply instead.
- */
+ N.B. signals are not supported. */
-/* This gets called just before store_regs */
-void
-arc_debug_prepare_to_store (void)
+static void
+arc_jtag_resume (ptid_t ptid, int step, enum target_signal signal)
{
- /* does nothing . Why is this around ? */
- ENTERMSG;
-}
+ ENTERARGS("%d, %d, %d", ptid.pid, step, signal);
-/* Read or write memory */
+ if (signal != TARGET_SIGNAL_0)
+ error(_("Signals are not supported by the " ARC_TARGET_NAME " target"));
+ /* If we cleared the User bit in the STATUS32 bit the last time that
+ execution halted, restore it now. */
+ change_status32(RESTORE_USER_BIT);
+ /* Software breakpoints may have been set/removed, and data in main memory
+ may have been altered, so invalidate (and flush!) the instruction and
+ data caches before restarting!
-/* Function: arc_debug_xfer_memory.
- * Parameters :
- * 1. int regnum: Register number. If register number is -1.Fetch
- * all the registers.Read all core registers here.
- * Returns : void
- * Description:
- * This has been superceded by target_xfer_memory_partial.
- *
- */
-int
-arc_debug_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
- struct mem_attrib *attrib, struct target_ops *target)
-{
- /* There is no xfer_memory . Its been deprecated in 6.3 .Replace
- * this by target_xfer_memory_partial .
- */
- ENTERARGS("memaddr=%lx, myaddr=%lx, len=%d, write=%d",
- memaddr, (unsigned long)myaddr, len, write);
-
- return len; /* success */
-}
+ N.B. arc_jtag_open disabled the caches, so what is the point of doing this?
+ Also, invalidating a disabled cache when DC_CTRL.IM = 1 seems to have
+ the effect of overwriting valid data!!!!! */
+// invalidate_caches ();
-
+ /* The DEBUG User bit must be set if breakpoints are to be allowed in user
+ mode. We could set it in target_open, but something (the user?) might clear it.
+ So we set it every time we resume (if stepping, we set the extra bit(s) we
+ need in the DEBUG register in the same operation). */
-LONGEST
-arc_debug_xfer_partial (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- void *readbuf,
- const void *writebuf,
- ULONGEST offset,
- LONGEST len)
-{
-
- int i=0, read_num=0, temp_len=0;
- unsigned int small_buf;
- char query_type;
- ULONGEST temp_offset=0;
- if(debug_arc_jtag_target_message)
- printf("..Entered arc_debug_xfer_partial()...with offset 0x%x\n",(unsigned int)offset);
- /* Handle memory */
- if (object == TARGET_OBJECT_MEMORY)
+ if (step)
{
- int saved_status32;
- int xfered=0;
- int attempts;
- errno = 0;
-
- /* Get out of user mode so that we can read/write anything anywhere. */
- saved_status32 = clear_status32_user_bit ();
-
- if (writebuf != NULL)
- {
- char *buffer=(char *)xmalloc(4);
- char *temp_buf = (char *)writebuf;
-
- /* Address alignment to integral multiple of four */
- temp_offset = offset;
- temp_len = temp_offset % 4;
-
- i = 0;
- if(temp_len)
- {
- temp_offset = offset - temp_len;
- if(debug_arc_jtag_target_message)
- {
- printf("---- Aligning-----------\n");
- printf("calling write_chunk at 0x%x where \
-offset = 0x%x\n",
- (unsigned int)temp_offset,(unsigned int)offset);
- }
-
- attempts = 0;
- do{
- if (attempts++ == MEMORY_TRANSFER_ATTEMPTS)
- return 0;
- xfered = arc_jtag_ops.jtag_memory_chunk_read(temp_offset,
- (unsigned int *)buffer,4);
- }while(xfered != 4);
-
- for(i=0;i<len && i<(4-temp_len);i++)
-
- buffer[i+temp_len]=temp_buf[i];
-
- attempts = 0;
- do{
- if (attempts++ == MEMORY_TRANSFER_ATTEMPTS)
- return 0;
- xfered = arc_jtag_ops.jtag_memory_chunk_write(temp_offset,
- (unsigned int *)buffer,4);
- }while(xfered != 4);
-
-
- temp_buf = (char *)writebuf + i;
- temp_offset = offset + i;
- len = len - i;
- }
- if(len>0)
- len =arc_jtag_ops.jtag_memory_chunk_write(temp_offset,
- (unsigned int *)temp_buf,len);
- if(debug_arc_jtag_target_message)
- printf("...leaving arc_debug_xfer_partial() write.. \
-with return value %d",(int)len);
-
- restore_status32_user_bit (saved_status32);
- return (len + i);
- }
- else
- {
- char *buffer=(char *)xmalloc(4);
- char *temp_buf = (char *)readbuf;
- /* Address alignment to integral multiple of four */
- temp_offset= offset;
- temp_len= temp_offset % 4 ;
-
- i = 0;
- if(temp_len)
- {
- temp_offset = offset - temp_len;
- if(debug_arc_jtag_target_message)
- {
- printf("---- Aligning-----------\n");
- printf("calling read_chunk at 0x%x where offset =0x%x \n",
- (unsigned int)temp_offset,(unsigned int)offset);
- }
-
- attempts = 0;
- do{
- if (attempts++ == MEMORY_TRANSFER_ATTEMPTS)
- return 0;
- xfered = arc_jtag_ops.jtag_memory_chunk_read(temp_offset,(unsigned int *)buffer,4);
- }while(xfered != 4);
-
- for(i=0;i<len && i<(4-temp_len);i++)
- temp_buf[i]=buffer[i+temp_len];
-
- temp_buf = (char *)readbuf + i;
- temp_offset = offset + i;
- len = len - i;
- }
- if(len>0)
- len = arc_jtag_ops.jtag_memory_chunk_read(temp_offset,(unsigned int *)temp_buf,len);
- if(debug_arc_jtag_target_message)
- {
- printf("\nlen=%d",(int)len + temp_len);
- printf("...leaving arc_debug_xfer_partial() read.. \
-with return value %d",
- (int)len + temp_len);
- }
-
- restore_status32_user_bit (saved_status32);
- return (len + i);
-
- }
+ ARC_RegisterContents mask = 0;
- }
+ DEBUG("setting DEBUG.IS bit for single-step\n");
- /* ARC auxillary registers: they are 32bits wide and are in a 32 bit
- address space, although only part of the address space is used. */
- else if (object == ARC_TARGET_OBJECT_AUXREGS)
- {
- unsigned int regno;
-
- if (readbuf)
- {
- for (regno = offset; regno < offset+len; ++regno)
- {
- unsigned int rd;
-
- if (arc_jtag_ops.jtag_read_aux_reg (regno, &rd) == JTAG_READ_FAILURE)
- {
- return (regno - offset);
- }
- ((int *)readbuf)[regno - offset] = rd;
- }
- }
- else if (writebuf)
- {
- for (regno = offset; regno < offset+len; ++regno)
- {
- if (arc_jtag_ops.jtag_write_aux_reg (regno, ((int*)writebuf)[regno - offset]) ==
- JTAG_WRITE_FAILURE)
- {
- return (regno - offset);
- }
- }
- }
-
- /* success */
- return (LONGEST)len;
+ /* The mask for single-stepping differs between ARC600 and ARC700. */
+ if (IS_ARC700)
+ mask = DEBUG_INSTRUCTION_STEP;
+ else
+ if (IS_ARC600)
+ mask = DEBUG_INSTRUCTION_STEP | DEBUG_SINGLE_STEP;
+
+ /* Allow breakpoints in User mode, and set the IS bit in the DEBUG
+ register for hardware single instruction stepping. */
+ if (!set_debug_user_bit (mask))
+ error(_("Can not single-step one instruction"));
}
else
{
- printf("\nRequested target_object not yet supported with arc-jtag");
+ /* Allow breakpoints in User mode (no extra bits required). */
+ (void) set_debug_user_bit (0);
+ start_processor();
}
- return -1;
-
+ LEAVEMSG;
}
+/* Wait for execution on the target to halt (for whatever reason).
+ Parameters :
+ ptid : ignored
+ status: set to indicate status at end of the wait
+*/
-void
-arc_debug_files_info (struct target_ops *target)
+static ptid_t
+arc_jtag_wait (ptid_t ptid, struct target_waitstatus *status)
{
- /* Do nothing. Just say its a remote target */
- ENTERMSG;
-}
+ ENTERMSG;
+ /* Execute the program on the target processor. */
+ arc_elf32_execute(status,
+ NULL,
+ start_processor,
+ stop_processor);
-/* Function: arc_debug_insert_breakpoint
- * Parameters :
- * 1. CORE_ADDR addr: Address for breakpoint.
- * 2. char * contents: Contents for the breakpoint.
- * Returns : int
- * Description:
- * See if you can insert a hardware breakpoint using the actionpoints
- * interface. Use brk_s if architecture is ARC700 and you need to use
- * a software breakpoint.The gdbarch breakpoint should be initialized to
- * the right value if used with target_arc_debug.
- *
- */
+ /* The target has now halted. */
+ if (status->kind == TARGET_WAITKIND_EXITED)
+ target_mark_exited (&jtag_target_ops);
-int
-arc_debug_insert_breakpoint (CORE_ADDR addr, char *contents)
-{
-
- ENTERARGS("%x", (unsigned int)addr);
-#ifndef ARC4_JTAG
- unsigned int bp = 0x20207fff; /*FIXMEA: what does 0x2020 stand for ?*/
-#else
- unsigned int bp = 0x1ffffe00;
-#endif
- unsigned int r;
- int instr_size;
- const unsigned char *breakpt_instr;
- breakpt_instr=BREAKPOINT_FROM_PC(&addr,&instr_size);
-
- /* save the existing value */
- /* r==0 means the read succeeded */
- if(debug_arc_jtag_target_message)
- printf_filtered ("instrcution size = %d and instruction 0x%x",
- instr_size, *(unsigned int *)breakpt_instr);
- r = target_read_memory (addr, contents, instr_size);
- /* put the breakpoint */
- if(r==0)
- r = target_write_memory (addr, (char *)&bp, instr_size);
- return r;
+ /* Get out of user mode so that we can access anything anywhere. */
+ change_status32(CLEAR_USER_BIT);
+
+ /* Inform the actionpoints module that the target has halted. */
+ arc_target_halted();
+
+ /* Bug #1311 (ARC600): Setting a breakpoint on the last instruction of a
+ ZOL causes GDB to stop at LP_START. Detect this condition and warn the
+ user. */
+ if (IS_ARC600)
+ {
+ ARC_RegisterContents pc, lp_start, lp_end, lp_count;
+
+ if (arc_read_jtag_core_register(ARC_LP_COUNT_REGNUM, &lp_count, TRUE) && (lp_count != 0) &&
+ arc_read_jtag_aux_register (arc_pc_regnum, &pc, TRUE) &&
+ arc_read_jtag_aux_register (lp_start_regnum, &lp_start, TRUE) && (pc == lp_start) &&
+ arc_read_jtag_aux_register (lp_end_regnum, &lp_end, TRUE))
+ {
+ struct breakpoint *b;
+
+ for (b = breakpoint_chain; b != NULL; b = b->next)
+ {
+ /* lp_end is the address of the last instruction + the size of
+ the last instruction. We could use the disassembler and find
+ out the size, but it's easier just to try both possible sizes. */
+ if ((b->enable_state == bp_enabled) &&
+ (b->loc->address == lp_end - 4 || b->loc->address == lp_end - 2))
+ {
+ warning(_("did you set a breakpoint on the last instruction of a"
+ "Zero Overhead Loop? Such breakpoints do not work properly."));
+ }
+ }
+ }
+ }
+
+ LEAVEMSG;
+
+ return inferior_ptid;
}
-/* Function: arc_debug_remove_breakpoint.
- * Parameters :
- * 1. CORE_ADDR addr: Address.
- * 2. char * contents : contents.
- * Returns : int.
- * Description:
- * Write the old contents back for the breakpoint.
- *
- */
+/* This gets called just before store_regs. */
-int
-arc_debug_remove_breakpoint (CORE_ADDR addr, char *contents)
+static void
+arc_jtag_prepare_to_store (struct regcache *regcache)
{
- ENTERARGS("%x, %lx", (unsigned int)addr, *(unsigned long *)contents);
-
- /* write the old value back */
-#ifdef ARC4_JTAG
- return target_write_memory (addr, contents, 4);
-#else
- return target_write_memory (addr, contents, 2);
-#endif
+ ENTERMSG;
}
+static void
+arc_jtag_files_info (struct target_ops *target)
+{
+ /* Do nothing. */
+ ENTERMSG;
+}
-/* Function: arc_debug_kill
- * Parameters : void.
- * Returns : void.
- * Description: Heavy duty arsenal.Kill the process.
- * Maybe we do a board reset and kill it. Write 1 to Halt
- * in Status32.
- */
+/* Heavy duty arsenal. Kill the process.
+ Maybe we should do a board reset and kill it. */
-void
-arc_debug_kill (void)
+static void
+arc_jtag_kill (void)
{
ENTERMSG;
- /* Do stuff */
-
target_mourn_inferior ();
}
-/* Function: arc_debug_load
- * Parameters :
- * 1. char * args: Arguments.
- * 2. int from_tty: Which terminal.
- * Returns : void.
- * Description: Load the program into jtag.
+
+/* Create the inferior that will be executed upon the target.
+
+ Parameters :
+ exec_file: the executable file containing the program to be executed
+ args : the command line arguments to be passed to the program
+ env : the environment (name/value pairs) for the program
+ from_tty : ignored
*/
-void
-arc_debug_load (char *args, int from_tty)
+static void
+arc_jtag_create_inferior (char *exec_file, char *args, char **env, int from_tty)
{
- /* Write to RAM of the ARC700 board by running through the sections .*/
- asection *bss_section;
- CORE_ADDR bss_addr;
- bfd_size_type bss_size;
- char *zero_buf;
- int target_errno;
+ arc_elf32_create_inferior(exec_file, args, env, &jtag_target_ops);
- ENTERARGS("%s", args);
+ /* Why are the caches disabled anyway? Particularly as arc_jtag_resume
+ invalidates them before each restart? */
+ disable_caches();
+}
- generic_load(args, from_tty);
- /* Zero the bss, if it exists. */
- bss_section = bfd_get_section_by_name (exec_bfd, ".bss");
- if (bss_section)
- {
- bss_addr = bfd_section_lma (exec_bfd, bss_section);
- bss_size = bfd_get_section_size (bss_section);
- zero_buf = (char *)xcalloc (bss_size, 1);
-
- if (debug_arc_jtag_target_message)
- printf_filtered("%s: bss at %x, size = %x\n", __FUNCTION__, (unsigned int)bss_addr,(unsigned int)bss_size);
-
- target_errno = target_write_memory (bss_addr, zero_buf, bss_size);
- free (zero_buf);
- if (target_errno)
- {
- error ("load: error zeroing bss: %s\n", strerror(target_errno));
- }
- }
- else
- {
- if (debug_arc_jtag_target_message)
- printf_filtered("%s: no bss\n", __FUNCTION__);
- }
-
- clear_symtab_users();
+/* Mourn the inferior. */
+
+static void
+arc_jtag_mourn_inferior (void)
+{
+ ENTERMSG;
+
+// (void) unpush_target (&jtag_target_ops);
+ generic_mourn_inferior ();
+ current_target.to_has_execution = 0;
}
-/* Function: arc_debug_create_inferior
- * Parameters :
- * 1. char * exec_file:
- * 2. char * args:
- * 3. char ** env;
- * Returns : void.
- * Description: Set up sanity values for arc_debug_create_inferior. More thought
- * needed for this.
- */
+/* Check whether the given thread is alive. */
-void
-arc_debug_create_inferior (char *exec_file, char *args, char **env,int dummy)
+static int
+arc_jtag_thread_alive (ptid_t ptid)
{
- ENTERARGS("%s,%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 == 0)
- exec_file = get_exec_file (1);
-
- /* We dont really have a PID or anything, but GDB uses this value to check
- if the program is running. */
- inferior_ptid.pid = 42;
-
- clear_proceed_status();
- /* -1 means resume from current place
- TARGET_SIGNAL_0 means dont give it any signal
- Last arg should be true if you want to single step */
- //proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
- proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0);
+ ENTERMSG;
+
+ /* We only have one thread. */
+ return 1;
}
-/* Function: arc_debug_mourn_inferior
- * Parameters :void.
- * Returns : void.
- * Description: Set up sanity values for arc_debug_create_inferior. More thought
- * needed for this.
- */
+/* Check whether our debug target is runnable: return 1 if it is, 0 otherwise. */
-void
-arc_debug_mourn_inferior (void)
+static int
+arc_jtag_can_run (void)
{
- ENTERMSG;
+ /* If we are connected to the JTAG i/f, and a program is loaded. */
+ return (arc_jtag_ops.status == JTAG_OPENED) && arc_program_is_loaded;
+}
+
- unpush_target (&arc_debug_ops);
+/* We do not support asynchronous execution of the target program (i.e. commands
+ like 'run' or 'continue' or 'step' can not be executed in background mode
+ by appending a '&' to them) so we do not need to implement the target stop
+ operation (called by the 'interrupt' command); interrupting a running program
+ is handled by the Ctrl-C mechanism. */
- generic_mourn_inferior ();
+#if 0
+static void
+arc_jtag_stop (void)
+{
+ ENTERMSG;
}
+#endif
-/* Function: arc_debug_mourn_inferior
- * Parameters :ptid_t ptid.
- * Returns : 1 always.
- * Description: Checks for return values .
- */
+/* -------------------------------------------------------------------------- */
+/* 7) local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+/* Print processor-variant information. */
-int
-arc_debug_thread_alive (ptid_t ptid)
+static void
+arc_print_processor_variant_info (char *arg, int from_tty)
{
- ENTERMSG;
- return 1;
+ printf_filtered
+ (_("%s\n"),
+ arc_version_image(arc_get_architecture(arc_read_jtag_aux_register)));
}
-/* Function: arc_debug_stop
- * Parameters: void
- * Returns: void.
- * Description: Stop the Processor. We stop by writing FH bit to Debug Register .
- * write 1 to the FH bit in the Debug register after
- * polling for the DEBUG register to have no loads pending .
- */
-void
-arc_debug_stop (void)
-{
+/* Reset the target board. */
- ENTERMSG;
- int val = 0x2;
- /* Stop using the FH bit in the debug register. */
- arc_debug_write_aux_register (ARC_HW_DEBUG_REGNUM, &val);
-
+static void
+arc_jtag_reset_board (char *arg, int from_tty)
+{
+ /* Make sure the GPIO interface is open. */
+ if (gpio_open())
+ {
+ printf_filtered(_("Attempting to reset target board...\n"));
+
+ if (arc_jtag_ops.status == JTAG_OPENED)
+ {
+ /* Try to force the processor to halt. */
+ stop_processor();
+ }
+
+ /* Try to reset the board. */
+ arc_reset_board();
+ arc_jtag_ops.reset_board();
+
+ if (arc_jtag_ops.status == JTAG_OPENED)
+ {
+ /* The ARC actionpoint registers are cleared upon reset, so it is
+ necessary to restore any actionpoints that were set. */
+ if (!arc_restore_actionpoints_after_reset())
+ warning(_("can not restore hardware actionpoints"));
+ }
+ }
}
-/* Read core register. Return 0 on success. */
-static int
-arc_debug_read_core_register (int hwregno, int *buf)
+
+/* List the ARC target processor actionpoints. */
+
+static void
+arc_list_actionpoints (char *arg, int from_tty)
{
- int rd;
- if(arc_jtag_ops.jtag_read_core_reg(hwregno,&rd)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x",hwregno);
- *buf = rd;
- return 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();
}
-/* Read aux register. Return 0 on success. */
-static int
-arc_debug_read_aux_register (int hwregno, int *buf)
+
+/* -------------------------------------------------------------------------- */
+/* 8) initialization functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the JTAG target operations. */
+
+static void
+initialize_jtag_target_ops (void)
{
- int rd;
- if(arc_jtag_ops.jtag_read_aux_reg(hwregno,&rd)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x",hwregno);
- *buf = rd;
- return 0;
+ ENTERMSG;
+
+ jtag_target_ops.to_data = &operations;
+
+ jtag_target_ops.to_shortname = ARC_TARGET_NAME;
+ jtag_target_ops.to_longname = "Remote JTAG debug target (ARC Processors)";
+ jtag_target_ops.to_doc = "Remote JTAG debug target (ARC Processors)";
+
+ jtag_target_ops.to_open = arc_jtag_open;
+ jtag_target_ops.to_close = arc_jtag_close;
+ jtag_target_ops.to_attach = arc_jtag_attach;
+ jtag_target_ops.to_detach = arc_jtag_detach;
+ jtag_target_ops.to_resume = arc_jtag_resume;
+ jtag_target_ops.to_wait = arc_jtag_wait;
+
+ jtag_target_ops.to_fetch_registers = arc_elf32_fetch_registers;
+ jtag_target_ops.to_store_registers = arc_elf32_store_registers;
+ jtag_target_ops.to_prepare_to_store = arc_jtag_prepare_to_store;
+ jtag_target_ops.to_xfer_partial = arc_elf32_xfer_partial;
+ jtag_target_ops.to_files_info = arc_jtag_files_info;
+
+ jtag_target_ops.to_insert_breakpoint = arc_elf32_insert_breakpoint;
+ jtag_target_ops.to_remove_breakpoint = arc_elf32_remove_breakpoint;
+
+ jtag_target_ops.to_kill = arc_jtag_kill;
+ jtag_target_ops.to_load = arc_elf32_load_program;
+
+ jtag_target_ops.to_create_inferior = arc_jtag_create_inferior;
+ jtag_target_ops.to_mourn_inferior = arc_jtag_mourn_inferior;
+ jtag_target_ops.to_thread_alive = arc_jtag_thread_alive;
+// jtag_target_ops.to_stop = arc_jtag_stop;
+ jtag_target_ops.to_can_run = arc_jtag_can_run;
+ jtag_target_ops.to_terminal_inferior = NULL;
+
+ jtag_target_ops.to_stratum = process_stratum;
+
+ jtag_target_ops.to_has_all_memory = 1;
+ jtag_target_ops.to_has_memory = 1;
+ jtag_target_ops.to_has_stack = 0; /* Defer setting this until the program has been loaded. */
+ jtag_target_ops.to_has_registers = 1;
+ jtag_target_ops.to_has_execution = 0; /* Defer setting this until the program has been started. */
+
+ jtag_target_ops.to_magic = OPS_MAGIC;
}
-/* Write aux register. Return 0 on success. */
-static int
-arc_debug_write_aux_register (int hwregno, int *buf)
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+void
+_initialize_arc_jtag (void)
{
- if(arc_jtag_ops.jtag_write_aux_reg(hwregno, *buf)==JTAG_WRITE_FAILURE)
- error("Failure writing 0x%x to auxillary register 0x%x\n",*buf,hwregno);
- return 0;
+ ENTERMSG;
+
+ operations.read_core_register = arc_read_jtag_core_register;
+ operations.write_core_register = arc_write_jtag_core_register;
+ operations.read_auxiliary_register = arc_read_jtag_aux_register;
+ operations.write_auxiliary_register = arc_write_jtag_aux_register;
+ operations.read_memory = read_words;
+ operations.write_memory = write_words;
+ operations.fill_memory = write_pattern;
+
+ initialize_jtag_target_ops ();
+ add_target (&jtag_target_ops);
+
+ /* Register ARC-specific commands with gdb. */
+
+ add_setshow_boolean_cmd(ARC_FSM_DEBUG_COMMAND,
+ no_class,
+ &arc_jtag_ops.state_machine_debug,
+ _("Set whether to print JTAG state machine debug messages.\n"),
+ _("Show whether to print JTAG state machine debug messages.\n"),
+ _("If set the JTAG state machine messages are printed.\n"),
+ NULL,
+ NULL,
+ &setlist,
+ &showlist);
+
+ add_setshow_uinteger_cmd(ARC_JTAG_RETRY_COMMAND,
+ no_class,
+ &arc_jtag_ops.retry_count,
+ _("Set the number of attempts to be made for a JTAG operation.\n"),
+ _("Show the number of attempts to be made for a JTAG operation.\n"),
+ _("Indicates the number of times a JTAG operation is attempted before returning a failure.\n"),
+ NULL,
+ NULL,
+ &setlist,
+ &showlist);
+
+ (void) add_cmd(ARC_CONFIGURATION_COMMAND,
+ class_info,
+ arc_print_processor_variant_info,
+ _("Show ARC configuration information.\n"
+ ARC_CONFIGURATION_COMMAND_USAGE),
+ &infolist);
+
+ (void) add_cmd(ARC_RESET_BOARD_COMMAND,
+ class_obscure,
+ arc_jtag_reset_board,
+ _("Reset the board.\n"
+ ARC_RESET_BOARD_COMMAND_USAGE),
+ &cmdlist);
+
+ (void) add_cmd(ARC_LIST_ACTIONPOINTS_COMMAND,
+ class_obscure,
+ arc_list_actionpoints,
+ _("List the processor actionpoints.\n"
+ ARC_LIST_ACTIONPOINTS_COMMAND_USAGE),
+ &cmdlist);
}
-/* Helper routine for commands added. */
-/* Print Processor Variant Info. */
-static void
-arc_print_processor_variant_info (void)
+
+/* N.B. the core and auxiliary register contents read from or written to the
+ target via the arc-jtag-ops module are ALWAYS in little-endian format,
+ regardless of the endianness of the target processor. Given that the
+ values passed to/from the functions below are in host byte order, and
+ the host is little-endian (since the ARC gdb is currently built only
+ on an X86 Linux host), this means that no byte-swapping is required
+ here. This will require changing if the debugger is ever built upon a
+ big-endian host (such as a Sun). */
+
+
+/* Read a core register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the read fails
+
+ Result: TRUE if the register contents are read. */
+
+Boolean
+arc_read_jtag_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
-#ifdef ARC4_JTAG
- if (tdep->arc_processor_variant_info &&
- tdep->arc_processor_variant_info->arcprocessorversion == A4)
- {
- printf_filtered ("A4\n");
- }
-#else
- if (tdep->arc_processor_variant_info)
- {
- if(tdep->arc_processor_variant_info->arcprocessorversion == ARC700)
- printf_filtered ("ARC700\n");
- else
- printf_filtered ("ARC600\n");
- }
-#endif
- else
+ if (arc_jtag_ops.read_core_reg(hw_regno, contents) == JTAG_SUCCESS)
{
- printf_filtered ("ARC Processor Information not available \n");
+ DEBUG("Read value 0x%08X from core register %d\n", *contents, hw_regno);
+ return TRUE;
}
+ if (warn_on_failure)
+ arc_elf32_core_warning(ERROR_ON_READING_REGISTER, hw_regno);
+ return FALSE;
}
-static void
-arc_print_bcr_regs (void)
+/* Write a core register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the write fails
+
+ Result: TRUE if the register contents are written. */
+
+Boolean
+arc_write_jtag_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure)
{
- int i = 0;
- unsigned int bcrval = 0;
- for ( i = 0 ; i < (sizeof(arc_bcr_reg_info) / sizeof (struct arc_reg_info)) ; i++)
+ if (arc_jtag_ops.write_core_reg(hw_regno, contents) == JTAG_SUCCESS)
{
- if(arc_jtag_ops.jtag_read_aux_reg (arc_bcr_reg_info[i].hw_regno, &bcrval)==JTAG_READ_FAILURE)
- error("Failure reading auxillary register 0x%x",arc_bcr_reg_info[i].hw_regno);
- printf_filtered ("[%02x] %-15s : 0x%02x\n",arc_bcr_reg_info[i].hw_regno,
- arc_bcr_reg_info[i].name, bcrval );
+ DEBUG("Written value 0x%08X to core register %d\n", contents, hw_regno);
+ return TRUE;
}
+ if (warn_on_failure)
+ arc_elf32_core_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
+ return FALSE;
}
-static void
-arc_debug_jtag_reset_board (void)
-{
- arc_jtag_ops.jtag_reset_board();
-}
+/* Read an auxiliary register on the target.
-/* Function: init_arc_debug_ops
- * Parameters: void
- * Returns: void.
- * Description: Initialize the jtag operations.
- */
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the read fails
-void
-init_arc_debug_ops (void)
-{
- ENTERMSG;
-#ifdef ARC4_JTAG
- arc_debug_ops.to_shortname = "arcjtag";
- arc_debug_ops.to_longname = "Target for debugging an A4 board with JTAG.";
- arc_debug_ops.to_doc = "Debug a remote A4 board via a JTAG"; /* to_doc */
-#else
- arc_debug_ops.to_shortname = "arcjtag";
- arc_debug_ops.to_longname = "Target for debugging an ARC700 board with JTAG.";
- arc_debug_ops.to_doc = "Debug a remote ARC700 board via a JTAG"; /* to_doc */
-#endif
+ Result: TRUE if the register contents are read. */
+Boolean
+arc_read_jtag_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure)
+{
+ if (arc_jtag_ops.read_aux_reg(hw_regno, contents) == JTAG_SUCCESS)
+ {
+ DEBUG("Read value 0x%08X from auxiliary register %d\n", *contents, hw_regno);
+ return TRUE;
+ }
- arc_debug_ops.to_open = arc_debug_open;
- arc_debug_ops.to_close = arc_debug_close;
- arc_debug_ops.to_attach = arc_debug_attach;
- arc_debug_ops.to_detach = arc_debug_detach;
- arc_debug_ops.to_resume = arc_debug_resume;
- arc_debug_ops.to_wait = arc_debug_wait;
-
- arc_debug_ops.to_fetch_registers = arc_debug_fetch_regs;
- arc_debug_ops.to_store_registers = arc_debug_store_regs;
- arc_debug_ops.to_prepare_to_store = arc_debug_prepare_to_store;
- //arc_debug_ops.to_xfer_memory = arc_debug_xfer_memory;
- arc_debug_ops.to_xfer_partial = arc_debug_xfer_partial;
- arc_debug_ops.to_files_info = arc_debug_files_info;
- arc_debug_ops.to_insert_breakpoint = arc_debug_insert_breakpoint;
- arc_debug_ops.to_remove_breakpoint = arc_debug_remove_breakpoint;
- arc_debug_ops.to_kill = arc_debug_kill;
- arc_debug_ops.to_load = arc_debug_load;
-
- arc_debug_ops.to_create_inferior = arc_debug_create_inferior;
-
- arc_debug_ops.to_mourn_inferior = arc_debug_mourn_inferior;
- arc_debug_ops.to_thread_alive = arc_debug_thread_alive;
- arc_debug_ops.to_stop = arc_debug_stop;
-
- arc_debug_ops.to_terminal_inferior = NULL;
-
-
- arc_debug_ops.to_stratum = process_stratum;
-
- arc_debug_ops.to_has_all_memory = 1;
- arc_debug_ops.to_has_memory = 1;
- arc_debug_ops.to_has_stack = 1;
- arc_debug_ops.to_has_registers = 1;
- arc_debug_ops.to_has_execution = 1;
-
- arc_debug_ops.to_magic = OPS_MAGIC;
+ if (warn_on_failure)
+ arc_elf32_aux_warning(ERROR_ON_READING_REGISTER, hw_regno);
+ return FALSE;
}
+/* Write an auxiliary register on the target.
-void
-_initialize_arc_debug (void)
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the write fails
+
+ Result: TRUE if the register contents are written. */
+
+Boolean
+arc_write_jtag_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure)
{
- ENTERMSG;
- init_arc_debug_ops ();
- add_target (&arc_debug_ops);
- add_setshow_boolean_cmd("arcjtag-debug-target",no_class,
- &debug_arc_jtag_target_message,
- "Set whether to print arc jtag debug messages.\n",
- "Show whether to print arc jtag debug messages.\n",
- "If set the jtag debug messages from the target are \
-printed.\n",
- "Whether to print debug jtag messages is %s.\n",
- NULL,NULL,&setlist,&showlist);
-
- add_setshow_boolean_cmd("arcjtag-debug-statemachine",no_class,
- &(arc_jtag_ops.arc_jtag_state_machine_debug),
- "Set whether to print JTAG state machine \
-debug messages \n",
- "Show whether to print JTAG state machine \
-debug messages \n",
- "If set the JTAG state machine messages are \
-printed.\n",
- "Whether to print JTAG state machine debug \
-messages is %s\n",
- NULL,NULL,&setlist,&showlist);
-
- add_setshow_uinteger_cmd("arcjtag-retry-count",no_class, &arcjtag_retry_count,
- "Set the number of attempts to be made for \
-a JTAG operation.\n",
- "Show the number of attempts to be made for \
-a JTAG operation.\n",
- "Indicates the number of times a JTAG operation \
-is attempted before returning a failure.\n",
- "The number of times a JTAG operation is attempted \
-before returning a failure is %s.\n",
- NULL, NULL, &setlist, &showlist);
-
- add_cmd ("arc-configuration", class_info, arc_print_processor_variant_info,
- "Show ARC configuration information." , &infolist);
-
- add_cmd ("arc-bcr-registers", class_info, arc_print_bcr_regs,
- "Show BCR Registers in the ARC Processor Variant", &infolist);
-
- add_cmd ("arc-reset-board", class_obscure, arc_debug_jtag_reset_board,
- "Reset the board.", &cmdlist);
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+
+ if (def)
+ contents = arc_write_value(def, contents);
+ if (arc_jtag_ops.write_aux_reg(hw_regno, contents) == JTAG_SUCCESS)
+ {
+ DEBUG("Written value 0x%08X to auxiliary register %d\n", contents, hw_regno);
+ return TRUE;
+ }
+
+ if (warn_on_failure)
+ arc_elf32_aux_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
+ return FALSE;
}
+
+/******************************************************************************/
diff --git a/gdb/arc-jtag.h b/gdb/arc-jtag.h
index b770a53c6a3..68b747b3fc4 100644
--- a/gdb/arc-jtag.h
+++ b/gdb/arc-jtag.h
@@ -1,76 +1,64 @@
-/* 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.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Soam Vasani <soam.vasani@codito.com>
+ Authors:
+ Soam Vasani <soam.vasani@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.
-*/
-
-#define ARC_DEBUG_REG_SH_BIT 0x40000000
-
-#define RAUX(name, hwregno , desc, gdbregno, version) ARC_HW_##name##_REGNUM = hwregno ,
-#define RBCR(name, hwregno , desc, gdbregno, version) ARC_HW_##name##_REGNUM = hwregno ,
-
-
-enum arc_hw_regnums
- {
- #include "arc-regnums-defs.h"
- /* Specific ARCAngel Registers for Caches. */
- ARC_HW_ICACHE_IVIC = 0x10 , /* Invalidate Cache. */
- ARC_HW_ICACHE_CONTROL = 0x11 , /* Disable ICache. ICache control. */
- ARC_HW_DCACHE_IVIC = 0x47, /* Invalidate Cache. */
- ARC_HW_DCACHE_CONTROL = 0x48 , /* Disable DCache. DCache Control. */
- };
-
-#undef RBCR
-#undef RAUX
-
-#define ARC_TARGET_OBJECT_AUXREGS -1
-
-#define target_read_aux_reg(readbuf, offset, len) \
- (current_target.to_xfer_partial(&current_target, \
- ARC_TARGET_OBJECT_AUXREGS, NULL, readbuf, NULL, offset, len))
-
-#define target_write_aux_reg(writebuf, offset, len) \
- (current_target.to_xfer_partial(&current_target, \
- ARC_TARGET_OBJECT_AUXREGS, NULL, NULL, writebuf, offset, len))
-
-
-static inline int
-is_arc700 (void)
-{
- struct gdbarch_tdep * tdep = gdbarch_tdep (current_gdbarch);
- if(tdep->arc_processor_variant_info->arcprocessorversion == ARC700)
- return 1;
- return 0;
-
-}
-
-static inline int
-is_arc600 (void)
-{
- struct gdbarch_tdep * tdep = gdbarch_tdep (current_gdbarch);
- if(tdep->arc_processor_variant_info->arcprocessorversion == ARC600)
- return 1;
- return 0;
-
-}
- int debug_arc_jtag_target_message;
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This header file defines some operations provided by the ARC JTAG */
+/* module. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_JTAG_H
+#define ARC_JTAG_H
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+/* Operations for reading/writing core/auxiliary registers; these must be used
+ when access to the registers *specifically* via the JTAG i/f is required.
+
+ N.B. the register contents returned by these functions, or supplied to them,
+ are in host byte order. */
+
+Boolean arc_read_jtag_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure);
+
+Boolean arc_write_jtag_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure);
+
+Boolean arc_read_jtag_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure);
+
+Boolean arc_write_jtag_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure);
+
+#endif /* ARC_JTAG_H */
+/******************************************************************************/
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);
}
+
+/******************************************************************************/
diff --git a/gdb/arc-linux-tdep.h b/gdb/arc-linux-tdep.h
new file mode 100644
index 00000000000..af1aa0e6df6
--- /dev/null
+++ b/gdb/arc-linux-tdep.h
@@ -0,0 +1,51 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines the type and operations for the Linux-uclibc */
+/* variant of the ARC debugger. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_LINUX_TDEP_H
+#define ARC_LINUX_TDEP_H
+
+/* gdb header files */
+#include "defs.h"
+#include "gdbarch.h"
+
+
+/* Complete the structure definition here. */
+struct arc_variant_info
+{
+ /* There is currently no variant-specific info. */
+};
+
+
+void arc_check_pc_defined (struct gdbarch *gdbarch);
+
+#endif /* ARC_LINUX_TDEP_H */
+/******************************************************************************/
diff --git a/gdb/arc-memory.c b/gdb/arc-memory.c
new file mode 100644
index 00000000000..806efb0d3c2
--- /dev/null
+++ b/gdb/arc-memory.c
@@ -0,0 +1,445 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 implements operations for reading data from and writing */
+/* data to target memory. */
+/* */
+/* The operations may be required to transfer arbitrary amounts of data */
+/* to/from arbitrary addresses in memory; however, the supplied transfer */
+/* operations must be assumed to be able only to transfer multiple words */
+/* of data to/from word-aligned addresses. */
+/* */
+/* This gives the general case: */
+/* */
+/* word boundaries */
+/* | */
+/* ------------------------------------------------- */
+/* | | | | | | */
+/* ----------------------------------------------------------- */
+/* | g g L L | W W W W | W W W W | W W W W | T T e e | */
+/* ----------------------------------------------------------- */
+/* ^ */
+/* |-------------------------------------| */
+/* | len */
+/* addr */
+/* */
+/* where addr is the base address of the data to be transferred */
+/* len is the number of bytes of data to be transferred */
+/* W denotes a byte that can be transfered in a whole word */
+/* L denotes a leading byte */
+/* T denotes a trailing byte */
+/* g denotes a gap byte */
+/* e denotes a end gap byte */
+/* */
+/* There may be 0 .. BYTES_IN_WORD - 1 leading bytes, 0 or more whole */
+/* words, and 0 .. BYTES_IN_WORD - 1 trailing bytes. If the given address */
+/* is word-aligned, there is no gap and hence no leading bytes. */
+/* */
+/* There is also a pathological case: */
+/* */
+/* word boundaries */
+/* | */
+/* --------- */
+/* | | */
+/* ----------------------------------------------------------- */
+/* | g B B e | */
+/* ----------------------------------------------------------- */
+/* ^ */
+/* |-| */
+/* | len */
+/* addr */
+/* */
+/* where 1 .. BYTES_IN_WORD - 2 bytes of data in the middle of a word */
+/* must be transfered. */
+/* */
+/* In a write operation, it is necessary to preserve the contents of the */
+/* gap and end gap bytes, if any - this is done by first reading the word */
+/* which contains those bytes, constructing a new word which contains */
+/* those bytes and the new bytes, and writing the new value back to that */
+/* location. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+
+/* gdb header files */
+#include "defs.h"
+
+/* ARC header files */
+#include "arc-memory.h"
+#include "arc-tdep.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef struct
+{
+ unsigned int leading_bytes;
+ unsigned int trailing_bytes;
+ unsigned int words;
+} Layout;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Split a memory chunk up into its layout - see diagram in file header. */
+
+static Layout
+split (ARC_Address addr, unsigned int bytes)
+{
+ unsigned int gap = addr % BYTES_IN_WORD;
+ Layout layout;
+
+ layout.leading_bytes = (gap == 0) ? 0 : (BYTES_IN_WORD - gap);
+ layout.trailing_bytes = (addr + bytes) % BYTES_IN_WORD;
+ layout.words = (bytes - layout.leading_bytes
+ - layout.trailing_bytes) / BYTES_IN_WORD;
+
+ DEBUG("%u leading bytes, %u words, %u trailing bytes\n",
+ layout.leading_bytes, layout.words, layout.trailing_bytes);
+
+ return layout;
+}
+
+
+/* Read part of a word of data from memory; the given address must be word-aligned. */
+
+static unsigned int
+read_partial_word (TargetOperations *ops,
+ ARC_Address addr,
+ ARC_Byte *data,
+ unsigned int bytes,
+ unsigned int offset) /* Offset of required bytes within word. */
+{
+ ARC_Byte word[BYTES_IN_WORD];
+
+ /* Read the word: only some bytes of this are required. */
+ if (ops->read_memory(addr, word, 1) > 0)
+ {
+ unsigned int i;
+
+ for (i = 0; i < bytes; i++)
+ data[i] = word[offset + i];
+
+ /* Have read the specified number of bytes. */
+ return bytes;
+ }
+
+ /* Failed: no data read. */
+ return 0;
+}
+
+
+/* Write part of a word of data to memory; the given address must be word-aligned. */
+
+static unsigned int
+write_partial_word (TargetOperations *ops,
+ ARC_Address addr,
+ ARC_Byte *data,
+ unsigned int bytes,
+ unsigned int offset) /* Offset of required bytes within word. */
+{
+ ARC_Byte word[BYTES_IN_WORD];
+
+ /* First read the word of memory that will be overwritten. */
+ if (ops->read_memory(addr, word, 1) > 0)
+ {
+ unsigned int i;
+
+ /* Next replace the bytes in that word that are to be written. */
+ for (i = 0; i < bytes; i++)
+ word[offset + i] = data[i];
+
+ /* Now write it! */
+ if (ops->write_memory(addr, word, 1) > 0)
+ /* Have written the specified number of bytes. */
+ return bytes;
+ }
+
+ /* Failed: no data written. */
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Read a chunk of data from target memory.
+ Returns number of bytes read. */
+
+unsigned int
+arc_read_memory (TargetOperations *ops,
+ ARC_Address address,
+ ARC_Byte *data,
+ unsigned int bytes)
+{
+ unsigned int gap = address % BYTES_IN_WORD;
+ unsigned int total_read = 0;
+
+ ENTERARGS("address 0x%08X, bytes %u", address, bytes);
+
+ /* Special fast case for reading a single word. */
+ if (gap == 0 && bytes == BYTES_IN_WORD)
+ {
+ DEBUG("read single word\n");
+
+ /* N.B. assumes that 'data' is word-aligned, or that host does not care! */
+ total_read = ops->read_memory(address, data, 1);
+ }
+ /* Pathological case: bytes in middle of word. */
+ else if (gap > 0 && gap + bytes < BYTES_IN_WORD)
+ {
+ DEBUG("read pathological\n");
+
+ total_read = read_partial_word(ops,
+ address - gap, /* Word-aligned address. */
+ data,
+ bytes,
+ gap);
+ }
+ else /* The general case. */
+ {
+ Layout chunk = split(address, bytes);
+
+ if (chunk.leading_bytes > 0)
+ {
+ /* Read the first few bytes. */
+ total_read = read_partial_word(ops,
+ address - gap, /* Word-aligned addres. */
+ data,
+ chunk.leading_bytes,
+ gap);
+ data += chunk.leading_bytes;
+ address += chunk.leading_bytes;
+ }
+
+ if (chunk.words > 0)
+ {
+ unsigned int bytes_read = ops->read_memory(address, data, chunk.words);
+
+ total_read += bytes_read;
+ address += bytes_read;
+ data += bytes_read;
+ }
+
+ if (chunk.trailing_bytes > 0)
+ {
+ /* Read the last few bytes of data. */
+ total_read += read_partial_word(ops,
+ address, // Word-aligned address. */
+ data,
+ chunk.trailing_bytes,
+ 0);
+ }
+ }
+
+ DEBUG("read %u bytes\n", total_read);
+
+ return total_read;
+}
+
+
+/* Write a chunk of data to target memory.
+ Returns number of bytes written. */
+
+unsigned int
+arc_write_memory (TargetOperations *ops,
+ ARC_Address address,
+ ARC_Byte *data,
+ unsigned int bytes)
+{
+ unsigned int gap = address % BYTES_IN_WORD;
+ unsigned int total_written = 0;
+
+ ENTERARGS("address 0x%08X, bytes %u", address, bytes);
+
+ /* Useful debugging code: just change 0 to 1. */
+ if (0)
+ {
+ unsigned int i;
+ for (i = 0; i < bytes; i++)
+ {
+ DEBUG("%02X", data[i]);
+ if ((i + 1) % 16 == 0)
+ DEBUG("\n");
+ }
+ DEBUG("\n");
+ }
+
+ /* Special fast case for writing a single word. */
+ if (gap == 0 && bytes == BYTES_IN_WORD)
+ {
+ DEBUG("write single word (%02X %02X %02X %02X)\n", data[0], data[1], data[2], data[3]);
+
+ total_written = ops->write_memory(address, data, 1);
+ }
+ /* Pathological case: bytes in middle of word. */
+ else if (gap > 0 && gap + bytes < BYTES_IN_WORD)
+ {
+ DEBUG("write pathological\n");
+
+ total_written = write_partial_word(ops,
+ address - gap, /* Word-aligned address. */
+ data,
+ bytes,
+ gap);
+ }
+ else /* general case */
+ {
+ Layout chunk = split(address, bytes);
+
+ if (chunk.leading_bytes > 0)
+ {
+ /* Write the first few bytes. */
+ total_written = write_partial_word(ops,
+ address - gap, /* Word-aligned address. */
+ data,
+ chunk.leading_bytes,
+ gap);
+ data += chunk.leading_bytes;
+ address += chunk.leading_bytes;
+ }
+
+ if (chunk.words > 0)
+ {
+ unsigned int bytes_written = ops->write_memory(address, data, chunk.words);
+
+ total_written += bytes_written;
+ address += bytes_written;
+ data += bytes_written;
+ }
+
+ if (chunk.trailing_bytes > 0)
+ {
+ /* Write the last few bytes of data. */
+ total_written += write_partial_word(ops,
+ address, /* Word-aligned address. */
+ data,
+ chunk.trailing_bytes,
+ 0);
+ }
+ }
+
+ DEBUG("written %u bytes\n", total_written);
+
+ return total_written;
+}
+
+
+/* Write a repeated pattern of data to memory;
+ the start of each pattern is always word-aligned, so if the given address is
+ not word-aligned, the first partial word written will contain trailing bytes
+ of the pattern. */
+
+unsigned int
+arc_write_pattern (TargetOperations *ops,
+ ARC_Address address,
+ ARC_Word pattern,
+ unsigned int bytes)
+{
+ unsigned int gap = address % BYTES_IN_WORD;
+ unsigned int total_written = 0;
+
+ ENTERARGS("address 0x%08X, pattern 0x%08X, bytes %u", address, pattern, bytes);
+
+ /* Special fast case for writing a single word. */
+ if (gap == 0 && bytes == BYTES_IN_WORD)
+ {
+ DEBUG("write single word (%08X)\n", pattern);
+
+ total_written = ops->write_memory(address, (ARC_Byte*) &pattern, 1);
+ }
+ /* Pathological case: bytes in middle of word. */
+ else if (gap > 0 && gap + bytes < BYTES_IN_WORD)
+ {
+ DEBUG("write pathological\n");
+
+ total_written = write_partial_word(ops,
+ address - gap, /* Word-aligned address. */
+ ((ARC_Byte*) &pattern) + gap ,
+ bytes,
+ gap);
+ }
+ else /* General case. */
+ {
+ Layout chunk = split(address, bytes);
+
+ if (chunk.leading_bytes > 0)
+ {
+ /* Write the first few bytes. */
+ total_written = write_partial_word(ops,
+ address - gap, /* Word-aligned address. */
+ ((ARC_Byte*) &pattern) + gap ,
+ chunk.leading_bytes,
+ gap);
+
+ address += chunk.leading_bytes;
+ }
+
+ /* If we have been given a fill_memory operation. */
+ if (ops->fill_memory)
+ {
+ /* Write the complete words of data in one go. */
+ unsigned int bytes_written = ops->fill_memory(address, pattern, chunk.words);
+
+ total_written += bytes_written;
+ address += bytes_written;
+ }
+ else
+ {
+ /* Write all the complete words of data, one word at a time. */
+ while (chunk.words--)
+ {
+ unsigned int bytes_written = ops->write_memory(address, (ARC_Byte*) &pattern, 1);
+
+ total_written += bytes_written;
+ address += bytes_written;
+ }
+ }
+
+ if (chunk.trailing_bytes > 0)
+ {
+ /* Write the last few bytes of data. */
+ total_written += write_partial_word(ops,
+ address, /* Word-aligned address. */
+ ((ARC_Byte*) &pattern),
+ chunk.trailing_bytes,
+ 0);
+ }
+ }
+
+ DEBUG("written %u bytes\n", total_written);
+
+ return total_written;
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-memory.h b/gdb/arc-memory.h
new file mode 100644
index 00000000000..110d5cba75b
--- /dev/null
+++ b/gdb/arc-memory.h
@@ -0,0 +1,64 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines operations for reading data from, and writing */
+/* data to, target memory. */
+/* */
+/* The data transferred may be of any length, and its start address may */
+/* have any alignment. */
+/* */
+/* These operations must be supplied with more basic operations which can */
+/* read or write an arbitrary number of complete words of data to or from */
+/* word-aligned addresses. */
+/* */
+/* Optionally, an operation which can write an arbitrary number of copies */
+/* of a word-sized pattern to memory, starting at a word-aligned address, */
+/* may be supplied for use by the arc_write_pattern operation; this is an */
+/* optimisation for improving performance: if it is not supplied, the */
+/* arc_write_pattern operation will use repeated calls of the supplied */
+/* 'write_words' operation. */
+/* */
+/* A pointer to user-defined data may be passed to these operations: it */
+/* will be passed to the basic operations when they are invoked (this */
+/* allows any required context data to be passed to those operations). */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_MEMORY
+#define ARC_MEMORY
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+unsigned int arc_read_memory (TargetOperations *ops, ARC_Address address, ARC_Byte *data, unsigned int bytes);
+unsigned int arc_write_memory (TargetOperations *ops, ARC_Address address, ARC_Byte *data, unsigned int bytes);
+unsigned int arc_write_pattern (TargetOperations *ops, ARC_Address address, ARC_Word pattern, unsigned int bytes);
+
+
+#endif /* ARC_MEMORY */
+/******************************************************************************/
diff --git a/gdb/arc-registers.c b/gdb/arc-registers.c
new file mode 100644
index 00000000000..c0f7710cbb6
--- /dev/null
+++ b/gdb/arc-registers.c
@@ -0,0 +1,2566 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 implements operations for manipulating the ARC processor */
+/* core registers and auxiliary registers. */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "gdbcmd.h"
+#include "regcache.h"
+#include "objfiles.h"
+#include "inferior.h"
+#include "target.h"
+#include "xml-support.h"
+#include "gdb_assert.h"
+
+/* ARC header files */
+#include "arc-registers.h"
+#include "arc-architecture.h"
+#include "arc-tdep.h"
+#include "arc-elf32-tdep.h"
+#include "config/arc/tm-embed.h"
+
+/* ARC simulator header files */
+#include "sim/arc/arc-sim-registers.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef struct field_meaning
+{
+ char *description;
+ ARC_RegisterContents value;
+} ARC_FieldMeaning;
+
+
+typedef struct field_definition
+{
+ char *name;
+ char *description;
+ unsigned int offset;
+ unsigned int size;
+ RegisterAccess access;
+ ARC_RegisterContents value_for_write;
+ Boolean fixed;
+ ARC_FieldMeaning *meanings;
+ unsigned int meaning_count;
+} ARC_FieldDefinition;
+
+
+/* Complete the type (declared in the header file) here. */
+struct aux_register_definition
+{
+ char *name;
+ char *description;
+ ARC_RegisterNumber number; /* The number in the auxiliary register space. */
+ int gdb_regno;
+ Boolean is_BCR;
+ ARC_Word mask;
+ RegisterAccess access;
+ ARC_FieldDefinition *fields;
+ unsigned int field_count;
+ unsigned int longest_field_name;
+ unsigned int max_bits_in_field;
+};
+
+
+/* An instance of this structure is used to pass state data
+ between the parsing routines.
+
+ The information is accumulated into the 'info' * field;
+ as each register or field description is parsed, the
+ information is held in the 'reg' or 'field' field before
+ validation is performed. If the information is valid,
+ it is copied into the 'info' structure. */
+typedef struct parsing_data
+{
+ const char *filename;
+ ARC_RegisterInfo *info;
+ ARC_AuxRegisterDefinition *currentRegister;
+ ARC_FieldDefinition *currentField;
+ ARC_RegisterContents maxFieldContents;
+ ARC_AuxRegisterDefinition reg;
+ ARC_FieldDefinition field;
+} ParsingData;
+
+
+/* -------------------------------------------------------------------------- */
+/* forward declarations */
+/* -------------------------------------------------------------------------- */
+
+static gdb_xml_element_start_handler start_architecture;
+static gdb_xml_element_end_handler end_architecture;
+static gdb_xml_element_start_handler start_feature;
+static gdb_xml_element_start_handler start_target;
+static gdb_xml_element_start_handler start_auxregister;
+static gdb_xml_element_start_handler start_bcr;
+static gdb_xml_element_start_handler start_ecr;
+static gdb_xml_element_start_handler start_field;
+static gdb_xml_element_start_handler start_bcrfield;
+static gdb_xml_element_start_handler start_meaning;
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* This indicates whether a 'register architecture changed' event must be sent,
+ but has not yet been sent. */
+Boolean arc_pending_register_architecture_change_event;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define REG_READ_FILE_COMMAND "arc-reg-read-file"
+#define REG_READ_EXTRA_FILE_COMMAND "arc-reg-read-extra-file"
+#define AUX_REG_READ_COMMAND "arc-aux-read"
+#define AUX_REG_WRITE_COMMAND "arc-aux-write"
+#define AUX_REG_SHOW_COMMAND "arc-aux-show"
+#define AUX_LIST_REGISTER_COMMAND "arc-aux-list"
+#define ARC_BCR_COMMAND "arc-bcr-registers"
+
+#define REG_READ_FILE_COMMAND_USAGE "Usage: " REG_READ_FILE_COMMAND " <FILE>\n"
+#define REG_READ_EXTRA_FILE_COMMAND_USAGE "Usage: " REG_READ_EXTRA_FILE_COMMAND " <FILE>\n"
+#define AUX_REG_READ_COMMAND_USAGE "Usage: " AUX_REG_READ_COMMAND " <REG-FROM> [ <REG-TO> ]\n"
+#define AUX_REG_WRITE_COMMAND_USAGE "Usage: " AUX_REG_WRITE_COMMAND " <REG> = <VALUE>\n"
+#define AUX_REG_SHOW_COMMAND_USAGE "Usage: " AUX_REG_SHOW_COMMAND " [ <REG> ] \n"
+#define AUX_LIST_REGISTER_COMMAND_USAGE "Usage: " AUX_LIST_REGISTER_COMMAND " [ <REG> ]\n"
+#define ARC_BCR_COMMAND_USAGE "Usage: info " ARC_BCR_COMMAND "\n"
+
+
+#define ELEMENT_END_MARKER { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
+#define ATTRIBUTE_END_MARKER { NULL, GDB_XML_AF_NONE, NULL, NULL }
+
+
+/* Special values for the name and description fields. */
+static const char *NO_DESCRIPTION = "";
+static const char *RESERVED = "<reserved>";
+static const char *UNUSED = "<unused>";
+
+
+/* The elements and attributes of an XML target description. */
+
+/* A handler_data for access values. */
+
+static const struct gdb_xml_enum enums_access[] =
+{
+ { "RO", READ_ONLY },
+ { "RW", READ_WRITE },
+ { "WO", WRITE_ONLY },
+ { NULL, 0 }
+};
+
+
+static const struct gdb_xml_attribute aux_register_attributes[] =
+{
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { "description", GDB_XML_AF_NONE, NULL, NULL },
+ { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "mask", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute core_register_attributes[] =
+{
+ { "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "mask", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute field_attributes[] =
+{
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { "description", GDB_XML_AF_OPTIONAL, NULL, NULL },
+ { "onwrite", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+ { "offset", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "access", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_enum, enums_access },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute bcrfield_attributes[] =
+{
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ { "description", GDB_XML_AF_OPTIONAL, NULL, NULL },
+ { "offset", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute meaning_attributes[] =
+{
+ { "description", GDB_XML_AF_NONE, NULL, NULL },
+ { "value", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute feature_attributes[] =
+{
+ { "name", GDB_XML_AF_NONE, NULL, NULL },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_element field_children[] =
+{
+ { "meaning", meaning_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_meaning, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+static const struct gdb_xml_element auxregister_children[] =
+{
+ { "field", field_attributes, field_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_field, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+static const struct gdb_xml_element bcr_children[] =
+{
+ { "bcrfield", bcrfield_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_bcrfield, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+static const struct gdb_xml_element feature_children[] =
+{
+ { "auxregister", aux_register_attributes, auxregister_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_auxregister, NULL },
+ { "bcr", aux_register_attributes, bcr_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_bcr, NULL },
+ { "ecr", core_register_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, start_ecr, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+static const struct gdb_xml_attribute target_attributes[] =
+{
+ { "version", GDB_XML_AF_NONE, NULL, NULL },
+ ATTRIBUTE_END_MARKER
+};
+
+
+static const struct gdb_xml_element target_children[] =
+{
+ { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, start_architecture, end_architecture },
+ { "feature", feature_attributes, feature_children,
+ GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+ start_feature, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+static const struct gdb_xml_element elements[] =
+{
+ { "target", target_attributes, target_children, GDB_XML_EF_NONE, start_target, NULL },
+ ELEMENT_END_MARKER
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define NAME_IS(ident) (strcmp(name, ident) == 0)
+
+#define INFO_OF(gdbarch) &gdbarch_tdep (gdbarch)->processor_variant_info->registers
+
+#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); \
+}
+
+#define FIND_REGISTER_DEFINITION_SUCH_THAT(condition) \
+{ \
+ ARC_RegisterInfo *info = find_info(TRUE); \
+ unsigned int i; \
+ \
+ for (i = 0; i < info->aux_register_count; i++) \
+ { \
+ ARC_AuxRegisterDefinition *def = &info->aux_registers[i]; \
+ \
+ if (condition) \
+ return def; \
+ } \
+ \
+ return NULL; \
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for XML file parsing */
+/* -------------------------------------------------------------------------- */
+
+/* Return a string corresponding to the given access. */
+
+static const char*
+RegisterAccess_Image (RegisterAccess val)
+{
+ switch (val)
+ {
+ case READ_ONLY : return "read-only";
+ case READ_WRITE: return "read/write";
+ case WRITE_ONLY: return "write-only";
+ default : return "???";
+ }
+}
+
+
+static void
+initialize_register (ARC_AuxRegisterDefinition *reg)
+{
+ reg->name = NULL;
+ reg->number = 0;
+ reg->gdb_regno = 0;
+ reg->is_BCR = FALSE;
+ reg->description = (char*) NO_DESCRIPTION;
+ reg->mask = 0xFFFFFFFF;
+ reg->access = READ_WRITE;
+ reg->field_count = 0;
+ reg->fields = NULL;
+ reg->longest_field_name = 0;
+ reg->max_bits_in_field = 0;
+}
+
+
+static void
+initialize_field (ARC_FieldDefinition *field, RegisterAccess access)
+{
+ field->name = NULL;
+ field->description = (char*) NO_DESCRIPTION;
+ field->value_for_write = 0;
+ field->fixed = FALSE;
+ field->size = 1;
+ field->offset = 0;
+ field->access = access;
+ field->meanings = NULL;
+ field->meaning_count = 0;
+}
+
+
+static void
+initialize_meaning (ARC_FieldMeaning *meaning)
+{
+ meaning->description = (char*) NO_DESCRIPTION;
+ meaning->value = 0;
+}
+
+
+/* Return TRUE if the given register fields overlap within the register. */
+
+static Boolean
+overlaps(ARC_FieldDefinition *field1, ARC_FieldDefinition *field2)
+{
+ unsigned int field1_start = field1->offset;
+ unsigned int field1_end = field1_start + field1->size - 1;
+ unsigned int field2_start = field2->offset;
+ unsigned int field2_end = field2_start + field2->size - 1;
+
+ return !(field2_end < field1_start || field1_end < field2_start);
+}
+
+
+/* Release all the storage allocated to hold the given register information,
+ and re-initialize it. */
+
+static void
+free_register_set (ARC_RegisterInfo *info)
+{
+ if (info->aux_registers)
+ {
+ unsigned int i;
+
+ for (i = 0; i < info->aux_register_count; i++)
+ {
+ ARC_AuxRegisterDefinition *r = &info->aux_registers[i];
+
+ if (r->name != UNUSED)
+ xfree (r->name);
+ if (r->description != NO_DESCRIPTION)
+ xfree (r->description);
+
+ if (r->fields)
+ {
+ unsigned int j;
+
+ for (j = 0; j < r->field_count; j++)
+ {
+ ARC_FieldDefinition *f = &r->fields[j];
+
+ if (f->name != RESERVED)
+ xfree (f->name);
+
+ if (f->description != NO_DESCRIPTION)
+ xfree (f->description);
+
+ if (f->meanings)
+ {
+ unsigned int k;
+
+ for (k = 0; k < f->meaning_count; k++)
+ {
+ ARC_FieldMeaning *m = &f->meanings[k];
+
+ if (m->description != NO_DESCRIPTION)
+ xfree (m->description);
+ }
+
+ xfree(f->meanings);
+ }
+ }
+ }
+
+ xfree(r->fields);
+ }
+
+ xfree(info->aux_registers);
+
+ arc_initialize_aux_reg_info(info);
+ }
+}
+
+
+/* This function reads the contents of a file.
+
+ Parameters:
+ filename : the name of the file to be accessed
+ baton : the path to the directory containing the file
+
+ Result:
+ If the file contents were successfully read, a pointer to a buffer
+ containing those contents; otherwise NULL. */
+
+static char*
+read_file_contents (const char *filename, void *baton)
+{
+ char *name = (char*) filename;
+ const char *dirname = baton;
+ char *contents = NULL;
+ int fd;
+
+ if ((dirname != NULL) && (*dirname != '\0'))
+ {
+ name = concat (dirname, "/", filename, NULL);
+
+ if (name == NULL)
+ {
+ /* N.B. this does not return */
+ nomem (0);
+ }
+ }
+
+ if ((fd = open (name, O_RDONLY)) != -1)
+ {
+ struct stat stat;
+ int status;
+
+ if ((status = fstat(fd, &stat)) != -1)
+ {
+ size_t size = (size_t) stat.st_size;
+
+ /* Allocate buffer to hold the file contents; note that this space
+ is deliberately made larger than required, so that it is possible
+ to add extra characters to the end of the data. */
+ if ((contents = xmalloc (size + 10)))
+ {
+ ssize_t bytes;
+
+ if ((bytes = read (fd, contents, size)) == (ssize_t) size)
+ {
+ /* Append an explicit end-of-line to the data, in case there
+ was not one there already; also, explicitly NUL-terminate
+ the data so that it is a valid string. */
+ contents[bytes] = '\n';
+ contents[bytes + 1] = '\0';
+ }
+ else
+ {
+ warning (_("can not read contents of file '%s': %s"),
+ name, strerror (errno));
+
+ /* Cannot trust the contents of the buffer. */
+ xfree (contents);
+ contents = NULL;
+ }
+
+ if ((status = close (fd)) != 0)
+ warning (_("can not close file '%s': %s"), name,
+ strerror (errno));
+ }
+ else
+ warning (_("can not allocate buffer to hold contents of file '%s'"), name);
+ }
+ else
+ warning (_("can not get size of file '%s': %s"), name,
+ strerror (errno));
+ }
+ else
+ warning (_("can not open file '%s': %s"), name, strerror (errno));
+
+ if (name != filename)
+ xfree (name);
+
+ return contents;
+}
+
+
+/* This function is called by the XML parser when the start of a <target> element is seen. */
+
+static void
+start_target (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+// ParsingData* data = user_data;
+ char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+
+ if (strcmp (version, "1.0") != 0)
+ gdb_xml_error (parser,
+ _("Registers description has unsupported version \"%s\""),
+ version);
+
+ DEBUG("target started\n");
+}
+
+
+/* This function is called by the XML parser when the start of an <architecture> element is seen. */
+
+static void
+start_architecture (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ DEBUG("architecture started\n");
+}
+
+
+/* This function is called by the XML parser when the end of an <architecture> element is seen. */
+
+static void
+end_architecture (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ const char *body_text)
+{
+ ParsingData *data = user_data;
+
+ if (body_text[0] != '\0')
+ {
+ data->info->processor = arc_version(body_text);
+
+ if (data->info->processor == UNSUPPORTED_ARCHITECTURE)
+ warning(_("unknown target architecture '%s' in XML file '%s'\n"),
+ body_text, data->filename);
+ }
+}
+
+
+/* This function is called by the XML parser when the start of a <feature> element is seen. */
+
+static void
+start_feature (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ DEBUG("feature started\n");
+}
+
+
+/* This function checks the XML description of an auxiliary register for
+ correctness, and if it is correct, adds a definition of this register to the
+ register information that is currently being constructed.
+
+ Parameters:
+ parser : the XML parser being used
+ element : a pointer to the parse structure
+ user_data : a pointer to the parsing data
+ attributes: a vector containing the attributes of the register from the XML
+ is_BCR : TRUE if the register is a Build Configuration Register
+ */
+
+static void
+add_aux_register (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes,
+ Boolean is_BCR)
+{
+ ParsingData *data = user_data;
+ ARC_RegisterInfo *info = data->info;
+ ARC_AuxRegisterDefinition *reg = &data->reg;
+ struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+ unsigned int length = VEC_length (gdb_xml_value_s, attributes);
+ unsigned int i;
+ Boolean add = TRUE;
+
+ initialize_register(reg);
+
+ /* Look at all the register attributes. */
+ for (i = 0; i < length; i++)
+ {
+ const char *name = attrs[i].name;
+ void *value = attrs[i].value;
+
+ if (NAME_IS("name")) reg->name = value;
+ else if (NAME_IS("description")) reg->description = xstrdup(value);
+ else if (NAME_IS("number")) reg->number = (ARC_RegisterNumber) *(ULONGEST*) value;
+ else if (NAME_IS("mask")) reg->mask = (ARC_Word) *(ULONGEST*) value;
+ else if (NAME_IS("access")) reg->access = (RegisterAccess) *(ULONGEST*) value;
+ }
+
+ if (strcasecmp(reg->name, "unused") == 0)
+ reg->name = (char*) UNUSED;
+ else
+ reg->name = xstrdup (reg->name);
+
+ if (is_BCR)
+ {
+ reg->is_BCR = is_BCR;
+ reg->access = READ_ONLY;
+ }
+
+ /* Sanity checking. */
+ for (i = 0; i < info->aux_register_count; i++)
+ {
+ if (reg->name != UNUSED)
+ if (strcasecmp(reg->name, info->aux_registers[i].name) == 0)
+ {
+ warning(_("auxiliary register with name '%s' already defined in file %s"),
+ reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (reg->number == info->aux_registers[i].number)
+ {
+ warning(_("auxiliary register with number %u already defined in file %s"),
+ reg->number, data->filename);
+ add = FALSE;
+ }
+ }
+
+ if (add)
+ {
+ unsigned int name_length = (unsigned int) strlen(reg->name);
+
+ if (name_length > info->max_name_length)
+ info->max_name_length = name_length;
+
+ info->aux_register_count++;
+ info->aux_registers = xrealloc(info->aux_registers,
+ info->aux_register_count * sizeof(ARC_AuxRegisterDefinition));
+
+ if (info->aux_registers == NULL)
+ {
+ /* N.B. this does not return. */
+ nomem (0);
+ }
+
+ /* Copy the register description into the array, and make it the current
+ register that will be referred to when parsing any fields. */
+ data->currentRegister = &info->aux_registers[info->aux_register_count - 1];
+ *data->currentRegister = *reg;
+ }
+ else
+ /* Do not copy it into the array, but still make it the current register. */
+ data->currentRegister = reg;
+}
+
+
+/* This function is called by the XML parser when the start of a <auxregister> element is seen. */
+
+static void
+start_auxregister (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ add_aux_register(parser, element, user_data, attributes, FALSE);
+}
+
+
+/* This function is called by the XML parser when the start of a <bcr> element is seen. */
+
+static void
+start_bcr (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ add_aux_register(parser, element, user_data, attributes, TRUE);
+}
+
+
+/* This function is called by the XML parser when the start of a <ecr> element
+ is seen. It checks the XML description of an extension core register for
+ correctness, and if it is correct, adds a definition of this register to the
+ register information that is currently being constructed.
+
+ Parameters:
+ parser : the XML parser being used
+ element : a pointer to the parse structure
+ user_data : a pointer to the parsing data
+ attributes: a vector containing the attributes of the register from the XML
+ */
+
+static void
+start_ecr (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ ParsingData *data = user_data;
+ ARC_RegisterInfo *info = data->info;
+ struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+ unsigned int length = VEC_length (gdb_xml_value_s, attributes);
+ ARC_RegisterNumber number = 0;
+ ARC_Word mask = 0xFFFFFFFF;
+ RegisterAccess access = READ_WRITE;
+ unsigned int i;
+
+ /* Look at all the register attributes. */
+ for (i = 0; i < length; i++)
+ {
+ const char *name = attrs[i].name;
+ void *value = attrs[i].value;
+
+ if (NAME_IS("number")) number = (ARC_RegisterNumber) *(ULONGEST*) value;
+ else if (NAME_IS("mask")) mask = (ARC_Word) *(ULONGEST*) value;
+ else if (NAME_IS("access")) access = (RegisterAccess) *(ULONGEST*) value;
+ }
+
+ /* Sanity checking. */
+ if (IS_EXTENSION_CORE_REGISTER(number))
+ {
+ ARC_CoreRegisterDefinition *reg = &info->core_registers[number];
+
+ if (reg->exists)
+ {
+ warning(_("extension core register with number %d already defined in file %s"),
+ number, data->filename);
+ }
+ else
+ {
+ reg->mask = mask;
+ reg->access = access;
+ reg->exists = TRUE;
+ }
+ }
+ else
+ warning(_("extension core register with invalid number %d defined in file %s"),
+ number, data->filename);
+}
+
+
+/* This function checks the XML description of an auxiliary register field for
+ correctness, and if it is correct, adds a definition of this field to the
+ register information that is currently being constructed.
+
+ Parameters:
+ parser : the XML parser being used
+ element : a pointer to the parse structure
+ user_data : a pointer to the parsing data
+ attributes: a vector containing the attributes of the field from the XML
+ is_BCR : TRUE if the field is part of a Build Configuration Register
+ */
+
+static void
+add_field (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes,
+ Boolean is_BCR)
+{
+ ParsingData *data = user_data;
+ ARC_AuxRegisterDefinition *reg = data->currentRegister;
+ ARC_FieldDefinition *field = &data->field;
+ struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+ unsigned int length = VEC_length (gdb_xml_value_s, attributes);
+ unsigned int i;
+ Boolean add = TRUE;
+
+ /* By default, a field has the same access as the register that contains it
+ (though a particular field in a R/W register might be R/O or W/O). */
+ initialize_field(field, reg->access);
+
+ /* Look at all the field attributes. */
+ for (i = 0; i < length; i++)
+ {
+ const char *name = attrs[i].name;
+ void *value = attrs[i].value;
+
+ if (NAME_IS("name")) field->name = value;
+ else if (NAME_IS("description")) field->description = xstrdup(value);
+ else if (NAME_IS("offset")) field->offset = (unsigned int) *(ULONGEST*) value;
+ else if (NAME_IS("size")) field->size = (unsigned int) *(ULONGEST*) value;
+ else if (NAME_IS("access")) field->access = (RegisterAccess) *(ULONGEST*) value;
+ else if (NAME_IS("onwrite")) { field->value_for_write = (ARC_RegisterContents) *(ULONGEST*) value;
+ field->fixed = TRUE; }
+ }
+
+ if (strcasecmp(field->name, "reserved") == 0)
+ field->name = (char*) RESERVED;
+ else
+ field->name = xstrdup (field->name);
+
+ /* Sanity checking. */
+ if (is_BCR)
+ {
+ /* BCRs are, by definition, read-only. */
+ field->access = READ_ONLY;
+ }
+ else
+ {
+ if (field->access != WRITE_ONLY && reg->access == WRITE_ONLY)
+ {
+ warning (_("field '%s' is readable in write-only auxiliary register '%s' in file %s"),
+ field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+ else if (field->access != READ_ONLY && reg->access == READ_ONLY)
+ {
+ warning (_("field '%s' is writable in read-only auxiliary register '%s' in file %s"),
+ field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+ }
+
+ if (field->size == 0)
+ {
+ warning(_("field '%s' contains no bits in auxiliary register '%s' in file %s"),
+ field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (field->offset > BITS_IN_REGISTER - 1)
+ {
+ warning(_("field '%s' offset > %u in auxiliary register '%s' in file %s"),
+ field->name, BITS_IN_REGISTER - 1, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (field->offset + field->size > BITS_IN_REGISTER)
+ {
+ warning(_("field '%s' is too wide in auxiliary register '%s' in file %s"),
+ field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ for (i = 0; i < reg->field_count; i++)
+ {
+ ARC_FieldDefinition *f = &reg->fields[i];
+
+ if (field->name != RESERVED)
+ if (strcasecmp(field->name, f->name) == 0)
+ {
+ warning(_("field '%s' already defined in auxiliary register '%s' in file %s"),
+ field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (overlaps(field, f))
+ {
+ warning(_("field '%s' overlaps field '%s' in auxiliary register '%s' in file %s"),
+ field->name, f->name, reg->name, data->filename);
+ add = FALSE;
+ }
+ }
+
+ data->maxFieldContents = 0;
+
+ for (i = 0; i < field->size; i++)
+ data->maxFieldContents = (data->maxFieldContents << 1) + 1;
+
+ if (field->value_for_write > data->maxFieldContents)
+ {
+ warning(_("value on write %u is too large for %u-bit reserved field in auxiliary register '%s' in file %s"),
+ field->value_for_write, field->size, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (add)
+ {
+ /* Keep track of the longest field name, and the most number of bits in a field. */
+ unsigned int len = (unsigned int) strlen(field->name);
+
+ if (len > reg->longest_field_name)
+ reg->longest_field_name = len;
+
+ if (field->size > reg->max_bits_in_field)
+ reg->max_bits_in_field = field->size;
+
+ reg->field_count++;
+ reg->fields = xrealloc(reg->fields,
+ reg->field_count * sizeof(ARC_FieldDefinition));
+
+ if (reg->fields == NULL)
+ {
+ /* N.B. this does not return. */
+ nomem (0);
+ }
+
+ /* Copy the field description into the array, and make it the current
+ field that will be referred to when parsing any meanings. */
+ data->currentField = &reg->fields[reg->field_count - 1];
+ *data->currentField = *field;
+ }
+ else
+ /* Do not copy it into the array, but still make it the current field. */
+ data->currentField = field;
+}
+
+
+/* This function is called by the XML parser when the start of a <field> element is seen. */
+
+static void
+start_field (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ add_field(parser, element, user_data, attributes, FALSE);
+}
+
+
+/* This function is called by the XML parser when the start of a <bcrfield> element is seen. */
+
+static void
+start_bcrfield (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ add_field(parser, element, user_data, attributes, TRUE);
+}
+
+
+/* This function is called by the XML parser when the start of a <meaning>
+ element is seen. It checks the XML description of the meaning for
+ correctness, and if it is correct, adds a definition of this meaning to the
+ register information that is currently being constructed.
+
+ Parameters:
+ parser : the XML parser being used
+ element : a pointer to the parse structure
+ user_data : a pointer to the parsing data
+ attributes: a vector containing the attributes of the meaning from the XML
+ */
+
+static void
+start_meaning (struct gdb_xml_parser *parser,
+ const struct gdb_xml_element *element,
+ void *user_data,
+ VEC(gdb_xml_value_s) *attributes)
+{
+ ParsingData *data = user_data;
+ ARC_AuxRegisterDefinition *reg = data->currentRegister;
+ ARC_FieldDefinition *field = data->currentField;
+ ARC_FieldMeaning meaning;
+ struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes);
+ unsigned int length = VEC_length (gdb_xml_value_s, attributes);
+ unsigned int i;
+ Boolean add = TRUE;
+
+ initialize_meaning(&meaning);
+
+ /* Look at all the meaning attributes. */
+ for (i = 0; i < length; i++)
+ {
+ const char *name = attrs[i].name;
+ void *value = attrs[i].value;
+
+ if (NAME_IS("description")) meaning.description = xstrdup(value);
+ else if (NAME_IS("value")) meaning.value = (ARC_RegisterContents) *(ULONGEST*) value;
+ }
+
+ if (meaning.value > data->maxFieldContents)
+ {
+ warning(_("value %u is too large for field '%s' in auxiliary register '%s' in file %s"),
+ meaning.value, field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ /* Sanity checking. */
+ for (i = 0; i < field->meaning_count; i++)
+ {
+ ARC_FieldMeaning *m = &field->meanings[i];
+
+ if (strcmp(meaning.description, m->description) == 0)
+ {
+ warning(_("meaning '%s' already defined for field '%s' in auxiliary register '%s' in file %s"),
+ meaning.description, field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+
+ if (meaning.value == m->value)
+ {
+ warning(_("value %u already has meaning for field '%s' in auxiliary register '%s' in file %s"),
+ meaning.value, field->name, reg->name, data->filename);
+ add = FALSE;
+ }
+ }
+
+ if (add)
+ {
+ field->meaning_count++;
+ field->meanings = xrealloc(field->meanings,
+ field->meaning_count * sizeof(ARC_FieldMeaning));
+
+ if (field->meanings == NULL)
+ {
+ /* N.B. this does not return. */
+ nomem (0);
+ }
+
+ field->meanings[field->meaning_count - 1] = meaning;
+ }
+}
+
+
+/* This function is passed to qsort to sort the auxiliary registers into a
+ canonical order such that BCRs come after the non-BCR aux registers, but
+ otherwise, the registers are ordered by increasing number, with the
+ exception that the IDENTITY register must come first. */
+
+static int
+compare_auxiliary_registers(const void *p1, const void *p2)
+{
+ ARC_AuxRegisterDefinition* reg1 = (ARC_AuxRegisterDefinition*) p1;
+ ARC_AuxRegisterDefinition* reg2 = (ARC_AuxRegisterDefinition*) p2;
+
+ if (reg1->is_BCR && !reg2->is_BCR)
+ return 1;
+
+ if (!reg1->is_BCR && reg2->is_BCR)
+ return -1;
+
+ if (!reg1->is_BCR && !reg2->is_BCR)
+ {
+ if (strcmp(reg1->name, "IDENTITY") == 0)
+ return -1;
+ if (strcmp(reg2->name, "IDENTITY") == 0)
+ return 1;
+ }
+
+ return (reg1->number < reg2->number) ? -1 : 1;
+}
+
+
+/* This function assigns the gdb register numbers to the target processor's
+ registers, using the scheme defined in arc-elf32-tdep.c. */
+
+static void
+assign_gdb_register_numbers (struct gdbarch *gdbarch, ARC_RegisterInfo *info)
+{
+ unsigned int i;
+ int pc = -1;
+
+ /* Core registers first. */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(info->core_registers); i++)
+ {
+ ARC_CoreRegisterDefinition *reg = &info->core_registers[i];
+
+ /* If this core register exists in the target, we have one more core
+ register in total; and the gdb number of this register is that number
+ less 1. */
+ if (reg->exists)
+ reg->gdb_regno = (int) info->core_register_count++;
+ }
+
+ info->first_aux_gdb_regno = (int) info->core_register_count;
+
+ /* Then the auxiliary registers. */
+ for (i = 0; i < info->aux_register_count; i++)
+ {
+ ARC_AuxRegisterDefinition *reg = &info->aux_registers[i];
+
+ reg->gdb_regno = info->first_aux_gdb_regno + i;
+
+ /* Is this the PC? */
+ if (strcasecmp(reg->name, "PC") == 0)
+ {
+ pc = reg->gdb_regno;
+ info->PC_number = pc;
+ }
+ }
+
+ /* We must tell gdb that the total number of registers has changed. */
+ set_gdbarch_num_regs (gdbarch, (int) (info->core_register_count +
+ info->aux_register_count));
+
+ /* The file may have contained a description of the PC, so we must tell gdb
+ what its number is.
+ N.B. if the 'replace' parameter to read_XML_file was true and the file
+ did NOT contain a description of the PC, we now no longer know which
+ auxiliary register is the PC, so we must set gdb's PC number back to
+ -1! */
+ set_gdbarch_pc_regnum(gdbarch, pc);
+
+ if (pc >= 0)
+ {
+ DEBUG("PC is reg #%d (arch %p)\n", pc, gdbarch);
+
+ /* So PC is defined - so remove the guard. */
+ arc_aux_pc_guard(gdbarch, FALSE);
+ }
+}
+
+
+/* Parse the XML file containing the register definitions.
+
+ Parameters:
+ document : the XML document to be parsed (i.e. the XML text)
+ fetcher : a function which can be used to read an XML document from a file
+ fetcher_baton : the directory containing the XML file(s)
+ data : a pointer to a structure used to pass state data
+ between the parsing routines. */
+
+static void
+parse_XML (const char *document,
+ xml_fetch_another fetcher,
+ void *fetcher_baton,
+ ParsingData *data)
+
+{
+ struct cleanup *back_to;
+ struct gdb_xml_parser *parser;
+ char *expanded_text;
+
+ /* Expand all XInclude directives. */
+ expanded_text = xml_process_xincludes (_("aux registers description"),
+ document, fetcher, fetcher_baton, 0);
+ if (expanded_text == NULL)
+ {
+ warning (_("can not load XML auxiliary registers description"));
+ return;
+ }
+
+ back_to = make_cleanup (null_cleanup, NULL);
+ parser = gdb_xml_create_parser_and_cleanup (_("aux registers description"),
+ elements, data);
+
+ /* Do the parsing; the DTD file defines the schema to be used by the XML. */
+ gdb_xml_use_dtd (parser, "arc-registers.dtd");
+
+ (void) make_cleanup (xfree, expanded_text);
+
+ if (gdb_xml_parse (parser, expanded_text) != 0)
+ warning (_("can not load XML auxiliary registers description"));
+
+ do_cleanups (back_to);
+}
+
+
+/* Read an XML file containing the register definitions.
+
+ Parameters:
+ filename : the path to the file
+ gdbarch : the architecture for which the register set is are being defined
+ replace : TRUE if any existing set of register defintions should be deleted first
+ inform : TRUE if a message should be output say that the file has been read
+ check : TRUE if an architectural check is to be performed once the file has been read
+
+ Result: TRUE if the file was successfully read and its contents parsed. */
+
+static Boolean
+read_XML_file (const char *filename,
+ struct gdbarch *gdbarch,
+ Boolean replace,
+ Boolean inform,
+ Boolean check)
+{
+ char *xml = read_file_contents(filename, NULL);
+
+ DEBUG("reading XML file: %s\n", filename);
+
+ if (xml)
+ {
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+ struct cleanup *back_to = make_cleanup (xfree, xml);
+ char *dirname = ldirname (filename);
+ ParsingData data;
+
+ memset (&data, 0, sizeof (ParsingData));
+
+ if (replace)
+ free_register_set(info);
+
+ info->processor = NO_ARCHITECTURE;
+
+ data.info = info;
+ data.filename = filename;
+
+ if (dirname != NULL)
+ (void) make_cleanup (xfree, dirname);
+
+ parse_XML (xml, read_file_contents, dirname, &data);
+ do_cleanups (back_to);
+
+ if (inform)
+ printf_filtered(_("Register definitions read from file %s\n"), filename);
+
+ if (check)
+ ARCHITECTURE_CHECK(gdbarch,
+ (current_objfile) ? current_objfile->obfd : NULL);
+
+ /* Sort the auxiliary registers into a canonical order: this allows
+ entries in the XML file to be in any order without affecting the gdb
+ register numbers assigned to them; in particular, it aids in ensuring
+ that when the xISS is being used as a remote debug target gdb and the
+ xISS agree upon the order in which register contents are held in the
+ RSP 'G' (set all registers) packet and the 'g' (get all registers)
+ response packet. */
+ qsort(info->aux_registers,
+ (size_t) info->aux_register_count,
+ sizeof (ARC_AuxRegisterDefinition),
+ compare_auxiliary_registers);
+
+ /* Now that we know all of the core and auxiliary registers in this
+ target, we can assign gdb register numbers to them. */
+ assign_gdb_register_numbers(gdbarch, info);
+
+ /* We can send the event now only if current_gdbarch is not NULL, or
+ it could cause an error elsewhere where gdbarch_num_regs or
+ gdbarch_num_pseudo_regs is used (e.g. in setup_architecture_data in
+ gdbtk/generic/gdbtk-register.c). */
+ if (current_gdbarch == NULL)
+ arc_pending_register_architecture_change_event = TRUE;
+ else
+ reg_architecture_changed_event();
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Try to find a file containing the default AUX register definitions; look in
+ 1) the current working directory
+ 2) the user's home directory
+
+ Parameters:
+ gdbarch : the architecture for which the register set is are being defined
+ inform : TRUE if a message should be output say that the file has been read
+ check : TRUE if an architectural check is to be performed once the file has been read
+*/
+
+static void
+read_default_file (struct gdbarch *gdbarch, Boolean inform, Boolean check)
+{
+ ENTERARGS("inform = %d, check = %d", inform, check);
+
+#define DESCR "auxiliary registers definition file "
+
+ if (access(REGISTER_DEFINITION_FILE, F_OK) == 0)
+ {
+ if (!read_XML_file(REGISTER_DEFINITION_FILE, gdbarch, FALSE, inform, check))
+ error(_("Can not read " DESCR REGISTER_DEFINITION_FILE));
+ }
+ else
+ {
+ const char *home_dir = getenv ("HOME");
+
+ if (home_dir)
+ {
+ char *home_file = xstrprintf (_("%s/%s"), home_dir, REGISTER_DEFINITION_FILE);
+
+ if (access(home_file, F_OK) == 0)
+ {
+ if (!read_XML_file(home_file, gdbarch, FALSE, inform, check))
+ error(_("Can not read " DESCR " %s"), home_file);
+ }
+ else
+ warning(_("can not find " DESCR REGISTER_DEFINITION_FILE " in either current directory or $HOME"));
+
+ xfree (home_file);
+ }
+ else
+ warning(_("HOME environment variable is not set - can not find " DESCR REGISTER_DEFINITION_FILE));
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* miscellaneous local functions */
+/* -------------------------------------------------------------------------- */
+
+/* This is a callback which is called from gdb when it writes the PC.
+ It is used to "guard" the PC. */
+
+static CORE_ADDR
+get_pc (struct regcache *regcache)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ /* This does not return if PC is not defined. */
+ arc_aux_check_pc_defined(gdbarch);
+
+ /* So PC is defined - so remove the guard. */
+ arc_aux_pc_guard(gdbarch, FALSE);
+
+ /* Now read and return the PC. */
+ return read_pc();
+}
+
+
+/* This is a callback which is called from gdb when it reads the PC.
+ It is used to "guard" the PC. */
+
+static void
+set_pc (struct regcache *regcache, CORE_ADDR val)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ /* This does not return if PC is not defined. */
+ arc_aux_check_pc_defined(gdbarch);
+
+ /* So PC is defined - so remove the guard. */
+ arc_aux_pc_guard(gdbarch, FALSE);
+
+ write_pc(val);
+}
+
+
+/* Try to find the register information for the current architecture.
+
+ Parameter:
+ must_be_defined : TRUE if the register information must be known
+
+ Result: a pointer to the info; NULL if there is none as yet. */
+
+static ARC_RegisterInfo*
+find_info (Boolean must_be_defined)
+{
+ gdb_assert (current_gdbarch != NULL);
+
+ {
+ ARC_RegisterInfo *info = INFO_OF(current_gdbarch);
+
+ /* If we have no aux register info. */
+ if (must_be_defined && info->aux_register_count == 0)
+ {
+ /* Try to get it. */
+ read_default_file(current_gdbarch, FALSE, FALSE);
+
+ /* No, could not get it. */
+ if (info->aux_register_count == 0)
+ error(_("No auxiliary registers have yet been defined for this target"));
+ }
+
+ return info;
+ }
+}
+
+
+/* Map a gdb register number to the ARC processor hardware number, and
+ determine the class of the register (as known to the built-in simulator). */
+
+static void
+simulator_mapping (int gdb_regno,
+ int *hw_regno,
+ ARC_RegisterClass *reg_class)
+{
+ /* Just in case gdb_regno is invalid. */
+ *hw_regno = -1;
+ *reg_class = ARC_UNKNOWN_REGISTER;
+
+ if (arc_is_core_register(gdb_regno))
+ {
+ *hw_regno = (int) arc_core_register_number(gdb_regno);
+ *reg_class = ARC_CORE_REGISTER;
+ }
+ else if (gdb_regno == arc_aux_pc_number(current_gdbarch))
+ {
+ /* The hw_regno is irrelevant here. */
+ *reg_class = ARC_PROGRAM_COUNTER;
+ }
+ else
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno);
+
+ if (def)
+ {
+ *hw_regno = (int) arc_aux_hw_register_number(def);
+ *reg_class = ARC_AUX_REGISTER;
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for supporting commands */
+/* -------------------------------------------------------------------------- */
+
+/* This function determines the h/w register number of an auxiliary register
+ from a command argument provided by a user. The argument might be a register
+ name, a number, or an expression to be evaluated. */
+
+static ARC_RegisterNumber
+extractRegisterNumber (char *arg)
+{
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_name(arg);
+ ARC_RegisterNumber num;
+
+ /* Is it a register name? */
+ if (def)
+ num = arc_aux_hw_register_number(def);
+ else
+ {
+ int regnum;
+
+ /* Is it some expression? */
+ EXTRACT(arg, int, regnum)
+
+ if (regnum < 0)
+ error(_("Register number '%s < 0"), arg);
+
+ num = (ARC_RegisterNumber) regnum;
+ }
+
+ return num;
+}
+
+
+/* This function finds the definition of an auxiliary register from a command
+ argument provided by a user. The argument might be a register name, a number,
+ or an expression to be evaluated.
+
+ NULL is returned if the argumenmt does not identify a defined auxiliary
+ register. */
+
+static ARC_AuxRegisterDefinition*
+find_aux_register (char *arg)
+{
+ ARC_AuxRegisterDefinition* def = arc_find_aux_register_by_name(arg);
+
+ /* Is it not a register name? */
+ if (def == NULL)
+ {
+ int regnum;
+
+ /* Is it some expression? */
+ EXTRACT(arg, int, regnum)
+
+ if (regnum < 0)
+ error(_("Register number '%s < 0"), arg);
+
+ def = arc_find_aux_register_by_hw_number((ARC_RegisterNumber) regnum);
+ }
+
+ return def;
+}
+
+
+/* This function list the description (but not the contents) of an auxiliary
+ register.
+
+ Parameters:
+ r : a pointer to the register definition
+ full: TRUE if full information is to be listed.
+*/
+
+static void
+list_register (ARC_AuxRegisterDefinition *r, Boolean full)
+{
+ printf_filtered("%s", r->name);
+ if (r->is_BCR)
+ printf_filtered(_(" (BCR)"));
+ printf_filtered(_("\n"));
+
+ if (r->description != NO_DESCRIPTION)
+ printf_filtered(_(" description: %s\n"), r->description);
+ printf_filtered(_(" number : 0x%x\n"), r->number);
+
+ if (full)
+ {
+ /* The gdb number of the register is internal information which would
+ be meaningless to the user; the mask is probably not useful either. */
+ printf_filtered(_(" gdb number : %d\n"), r->gdb_regno);
+ printf_filtered(_(" mask : %08X\n"), r->mask);
+ }
+
+ if (!r->is_BCR)
+ printf_filtered(_(" access : %s\n"), RegisterAccess_Image(r->access));
+
+ if (r->fields)
+ {
+ unsigned int j;
+
+ printf_filtered(_(" fields\n"));
+
+ for (j = 0; j < r->field_count; j++)
+ {
+ ARC_FieldDefinition *f = &r->fields[j];
+
+ printf_filtered(_(" %s\n"), f->name);
+ if (f->description != NO_DESCRIPTION)
+ printf_filtered(_(" description: %s\n"), f->description);
+ printf_filtered(_(" position : %u:%u\n"), f->offset, f->size);
+ printf_filtered(_(" access : %s\n"), RegisterAccess_Image(f->access));
+
+ if (f->meanings)
+ {
+ unsigned int k;
+
+ printf_filtered(_(" field meanings\n"));
+
+ for (k = 0; k < f->meaning_count; k++)
+ {
+ ARC_FieldMeaning *m = &f->meanings[k];
+
+ printf_filtered(_(" %x ==> %s\n"), m->value, m->description);
+ }
+ }
+ }
+ }
+
+ printf_filtered(_("\n"));
+}
+
+
+/* This function list the descriptions (but not the contents) of all auxiliary
+ registers.
+
+ Parameter:
+ full: TRUE if full information is to be listed.
+*/
+
+static void
+list_registers (Boolean full)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+ unsigned int i;
+
+ for (i = 0; i < info->aux_register_count; i++)
+ {
+ ARC_AuxRegisterDefinition *def = info->aux_registers + i;
+
+ if (def->name != UNUSED)
+ list_register(def, full);
+ }
+}
+
+
+/* This function reads the contents of an auxiliary register on the target.
+
+ Parameters:
+ def : the definition of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the read fails
+
+ Result: TRUE if the register contents are read. */
+
+static Boolean
+read_aux_register (ARC_AuxRegisterDefinition *def,
+ ARC_RegisterContents *value,
+ Boolean warn_on_failure)
+{
+ int gdb_regno = arc_aux_gdb_register_number(def);
+ struct regcache *regcache = get_current_regcache();
+
+ /* 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, value);
+
+ /* Unfortunately, the target_fetch_registers operation does not give us an
+ indication of success or failure. */
+ return TRUE;
+}
+
+
+/* This function writes the contents of an auxiliary register on the target.
+
+ Parameters:
+ def : the definition of the register
+ value : the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the write fails
+
+ Result: TRUE if the register contents are written. */
+
+static Boolean
+write_aux_register (ARC_AuxRegisterDefinition *def,
+ ARC_RegisterContents value,
+ Boolean warn_on_failure)
+{
+ int gdb_regno = arc_aux_gdb_register_number(def);
+ struct regcache *regcache = get_current_regcache();
+ ARC_RegisterContents written = arc_write_value(def, value);
+
+ /* Supply the register value to the register cache, then write it from the
+ cache to the target. */
+ regcache_raw_supply (regcache, gdb_regno, &written);
+ target_store_registers(regcache, gdb_regno);
+
+ /* If the value we actually wrote to the target is not the same as the value
+ we were given (because the register has fields that must have particular
+ values when written). */
+ if (written != value)
+ {
+ DEBUG("%s auxiliary register value %08X written as %08X\n",
+ arc_aux_register_name(def), value, written);
+
+ /* Put the value we were actually given into the register cache, so if
+ the user then displays the register contents he will see the
+ unmodified value. */
+ regcache_raw_supply (regcache, gdb_regno, &value);
+ }
+
+ /* Unfortunately, the target_store_registers operation does not give us an
+ indication of success or failure. */
+ return TRUE;
+}
+
+
+/* This function is passed to the arc_all_aux_registers iterator.
+ It is called for each auxiliary register defined for the current architecture;
+ if the register is a Build Configuration Register, and it is not unused, the
+ register's contents are read from the target and printed. */
+
+static void
+print_bcr (ARC_AuxRegisterDefinition *def, void *data)
+{
+ if (arc_aux_is_BCR(def) && !arc_aux_is_unused(def))
+ {
+ ARC_RegisterNumber bcr = arc_aux_hw_register_number(def);
+ ARC_RegisterContents bcr_value;
+
+ if (read_aux_register (def, &bcr_value, TRUE))
+ printf_filtered(_("[%02x] %-16s : 0x%02x\n"),
+ bcr, arc_aux_register_name(def), bcr_value);
+ }
+}
+
+
+/* This function may be passed to the arc_all_aux_registers iterator.
+ It reads the contents of the register whose definition is given from
+ the target and prints those contents. */
+
+static void
+show_one_aux_register (ARC_AuxRegisterDefinition *def, void *data)
+{
+ ARC_RegisterNumber reg_no = arc_aux_hw_register_number(def);
+ ARC_RegisterContents contents;
+
+ DEBUG("try to read aux reg %u\n", reg_no);
+
+ if (read_aux_register(def, &contents, TRUE))
+ arc_print_aux_register(def, contents);
+}
+
+
+/* Read the register definitions from a file.
+
+ Parameters:
+ filename : the path to the file
+ gdbarch : the architecture for which the register set is are being defined
+ replace : TRUE if any existing set of register defintions should be deleted first
+ inform : TRUE if a message should be output say that the file has been read
+ check : TRUE if an architectural check is to be performed once the file has been read
+*/
+static Boolean
+read_aux_regs_file (const char *filename,
+ struct gdbarch *gdbarch,
+ Boolean replace,
+ Boolean inform,
+ Boolean check)
+{
+ /* Try to read the register descriptions from the file. */
+ if (read_XML_file(filename, gdbarch, replace, inform, check))
+ return TRUE;
+
+ printf_filtered(_("can not read file '%s'\n"), filename);
+ return FALSE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+
+/* Command: <command> <from> [ <to> ]
+
+ Read and display a range of auxiliary registers.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_aux_reg_read_command (char *arg, int from_tty)
+{
+ char *arg2;
+ ARC_RegisterNumber first_regnum, last_regnum, r;
+ char format[40];
+
+ if (!arg)
+ {
+ printf_filtered (_(AUX_REG_READ_COMMAND_USAGE));
+ return;
+ }
+
+ /* Strip leading spaces. */
+ while (*arg == ' ')
+ arg++;
+
+ /* This assumes that the first arg cannot have spaces (the disas command
+ also seems to work this way). */
+ arg2 = strchr (arg, ' ');
+
+ /* Are there two arguments? */
+ if (arg2)
+ {
+ /* Split the input string up. */
+ arg2[0] = (char) 0;
+ arg2++;
+ }
+
+ /* First arg. */
+ first_regnum = extractRegisterNumber(arg);
+
+ /* So, how many regs do we want? */
+ if (arg2)
+ {
+ last_regnum = extractRegisterNumber(arg2);
+
+ if (last_regnum < first_regnum)
+ {
+ warning(_(AUX_REG_READ_COMMAND ": %s < %s, showing one register"), arg2, arg);
+ last_regnum = first_regnum;
+ }
+ }
+ else
+ last_regnum = first_regnum;
+
+ DEBUG("try to read aux regs %d .. %d\n", first_regnum, last_regnum);
+
+ (void) snprintf(format, sizeof(format),
+ _("0x%%08x %%-%us: %%08X\n"),
+ arc_aux_register_max_name_length() + 1);
+
+ for (r = first_regnum; r <= last_regnum; r++)
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(r);
+
+ /* If the aux register exists, and is used. */
+ if ((def != NULL) && !arc_aux_is_unused(def))
+ {
+ ARC_RegisterContents contents;
+
+ DEBUG("try to read aux reg %u\n", r);
+
+ if (read_aux_register(def, &contents, TRUE))
+ printf_filtered (format, r, arc_aux_register_name(def), contents);
+ }
+ }
+}
+
+
+/* Command: <command> <reg> = <value>
+
+ Write VALUE to auxiliary register REG.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+static void
+arc_aux_reg_write_command (char *arg, int from_tty)
+{
+ char *value_arg;
+ char *p;
+ ARC_RegisterNumber regnum;
+ ARC_RegisterContents value;
+ ARC_AuxRegisterDefinition *def;
+
+ if (!arg)
+ {
+ printf_filtered (_(AUX_REG_WRITE_COMMAND_USAGE));
+ return;
+ }
+
+ p = strchr(arg, '=');
+
+ if (p == NULL)
+ {
+ printf_filtered (_(AUX_REG_WRITE_COMMAND ": no second argument\n" AUX_REG_WRITE_COMMAND_USAGE));
+ return;
+ }
+
+ /* Split up the input string. */
+ value_arg = p + 1;
+ p--;
+ while (*p == ' ') p--;
+ p[1] = '\0';
+
+ /* Register expression. */
+ regnum = extractRegisterNumber(arg);
+
+ /* Value expression. */
+ EXTRACT(value_arg, ARC_RegisterContents, value)
+
+ def = arc_find_aux_register_by_hw_number(regnum);
+
+ if (def == NULL)
+ warning(_("no such auxiliary register: %s"), arg);
+ else
+ {
+ DEBUG("try to write aux reg %d = 0x%08X\n", regnum, value);
+
+ /* Write it. */
+ (void) write_aux_register(def, value, TRUE);
+ }
+}
+
+
+/* Command: <command> [ <reg> ]
+
+ Display the values of one or all of the auxiliary registers.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_aux_reg_show_command (char *arg, int from_tty)
+{
+ if (arg)
+ {
+ ARC_AuxRegisterDefinition *def = find_aux_register(arg);
+
+ if (def)
+ show_one_aux_register(def, NULL);
+ else
+ printf_filtered(_("There is no auxiliary register named '%s'\n"), arg);
+ }
+ else
+ /* list them all */
+ arc_all_aux_registers(show_one_aux_register, NULL);
+}
+
+
+/* Command: <command> [ <file> ]
+
+ Read a definition of a set of auxiliary registers from an XML file.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_aux_reg_file_read_command (char *arg, int from_tty)
+{
+ if (!arg)
+ {
+ printf_filtered (REG_READ_FILE_COMMAND_USAGE);
+ return;
+ }
+
+ /* The new set replaces the existing set (if any). */
+ (void) read_aux_regs_file(arg, current_gdbarch, TRUE, TRUE, TRUE);
+}
+
+
+/* Command: <command> <file>
+
+ Read a definition of a set of auxiliary registers from an XML file.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_aux_reg_file_read_extra_command (char *arg, int from_tty)
+{
+ if (!arg)
+ {
+ printf_filtered (REG_READ_EXTRA_FILE_COMMAND_USAGE);
+ return;
+ }
+
+ /* The new set is added to the existing set (if any). */
+ (void) read_aux_regs_file(arg, current_gdbarch, FALSE, TRUE, TRUE);
+}
+
+
+/* Command: <command> [ <reg> ]
+
+ Display a description of one or all auxiliary registers.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_aux_reg_list_command (char *arg, int from_tty)
+{
+ if (arg)
+ {
+ ARC_AuxRegisterDefinition *def = find_aux_register(arg);
+
+ if (def)
+ list_register(def, FALSE);
+ else
+ printf_filtered(_("There is no auxiliary register named '%s'\n"), arg);
+ }
+ else
+ /* List them all. */
+ list_registers(FALSE);
+}
+
+
+/* Command: <command>
+
+ Display the Build Configuration Registers.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_print_bcr_regs (char *arg, int from_tty)
+{
+ arc_all_aux_registers(print_bcr, NULL);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the given register information to the base configuration:
+ 1) core registers exist
+ 2) extension core registers do not exist
+ 3) no aux registers
+ */
+
+void
+arc_initialize_aux_reg_info (ARC_RegisterInfo *info)
+{
+ unsigned int i;
+
+ info->processor = NO_ARCHITECTURE;
+ info->aux_registers = NULL;
+ info->aux_register_count = 0;
+ info->max_name_length = 0;
+ info->PC_number = -1;
+ info->first_aux_gdb_regno = 0;
+ info->core_register_count = 0;
+
+ /* All possible core registers. */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(info->core_registers); i++)
+ {
+ ARC_CoreRegisterDefinition *reg = &info->core_registers[i];
+
+ reg->exists = TRUE;
+ reg->mask = 0xFFFFFFFF;
+ reg->access = READ_WRITE;
+ }
+
+ /* We do not yet know if we have any extension registers. */
+ for (i = ARC_FIRST_EXTENSION_CORE_REGISTER; i <= ARC_LAST_EXTENSION_CORE_REGISTER; i++)
+ info->core_registers[i].exists = FALSE;
+
+ /* R61 is reserved, R62 is not a real register. */
+ info->core_registers[61].exists = FALSE;
+ info->core_registers[62].exists = FALSE;
+
+ /* PCL is read-only */
+ info->core_registers[63].access = READ_ONLY;
+}
+
+
+/* Read the XML registers definition for the given architecture from the default file. */
+
+void
+arc_read_default_aux_registers (struct gdbarch *gdbarch)
+{
+ ENTERMSG;
+ read_default_file(gdbarch, FALSE, FALSE);
+}
+
+
+
+/* This function sets up or remaoves a "guard" on the PC */
+
+void
+arc_aux_pc_guard (struct gdbarch *gdbarch, Boolean on)
+{
+ set_gdbarch_read_pc (gdbarch, (on) ? get_pc : NULL);
+ set_gdbarch_write_pc(gdbarch, (on) ? set_pc : NULL);
+}
+
+
+/* Check whether the PC aux register is defined for the given architecture. */
+
+void
+arc_aux_check_pc_defined (struct gdbarch *gdbarch)
+{
+ ENTERARGS("target %s", current_target.to_shortname);
+
+ if (gdbarch == NULL)
+ gdbarch = current_gdbarch;
+
+ if (arc_aux_pc_number(gdbarch) < 0)
+ error(_("There is no auxiliary register description for the PC (Program Counter)"));
+}
+
+
+/* Return the gdb register number of the PC (Program Counter); -1 if the PC is not defined. */
+
+int
+arc_aux_pc_number (struct gdbarch *gdbarch)
+{
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+
+ return (info) ? info->PC_number : -1;
+}
+
+
+/* Find the register definition of the given aux register (identified by name). */
+
+ARC_AuxRegisterDefinition*
+arc_find_aux_register_by_name (const char *name)
+{
+ FIND_REGISTER_DEFINITION_SUCH_THAT(strcasecmp(name, def->name) == 0)
+}
+
+
+/* Find the register definition of the given aux register (identified by hardware register number). */
+
+ARC_AuxRegisterDefinition*
+arc_find_aux_register_by_hw_number (ARC_RegisterNumber hw_regno)
+{
+ FIND_REGISTER_DEFINITION_SUCH_THAT(hw_regno == def->number)
+}
+
+
+/* Find the register definition of the given aux register (identified by gdb register number). */
+
+ARC_AuxRegisterDefinition*
+arc_find_aux_register_by_gdb_number (int gdb_regno)
+{
+ /* N.B. the elements in the info->aux_registers array have strictly increasing
+ gdb numbers starting at info->first_aux_gdb_regno, so we can index the array
+ instead of searching it. */
+ ARC_RegisterInfo *info = find_info(TRUE);
+ int index = gdb_regno - info->first_aux_gdb_regno;
+
+ if (0 <= index && index < (int) info->aux_register_count)
+ {
+ ARC_AuxRegisterDefinition *def = info->aux_registers + index;
+
+ /* Just to be sure we have found the right element. */
+ gdb_assert(def->gdb_regno == gdb_regno);
+
+ return def;
+ }
+
+ return NULL;
+}
+
+
+/* Return the hardware register number of the given named auxiliary register;
+ if no register set is currently defined, or there is no register of that
+ name in the set, return the given default number. */
+
+ARC_RegisterNumber
+arc_aux_find_register_number (const char *name,
+ ARC_RegisterNumber defaultNumber)
+{
+ if (arc_aux_regs_defined(current_gdbarch))
+ {
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_name(name);
+
+ if (def != NULL)
+ return arc_aux_hw_register_number(def);
+ }
+
+ warning(_("there is no auxiliary register description for the %s register - "
+ "using 0x%x for the register number"), name, defaultNumber);
+ return defaultNumber;
+}
+
+
+/* Return the hardware register number of the given core register. */
+
+ARC_RegisterNumber
+arc_core_register_number (int gdb_regno)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+ unsigned int i;
+
+ /* The lower-numbered set of non-extension core registers (i.e. excluding
+ R60 .. R63) have fixed gdb numbers which are the same as the h/w number. */
+ if (gdb_regno < ARC_FIRST_EXTENSION_CORE_REGISTER)
+ return (ARC_RegisterNumber) gdb_regno;
+
+ /* Scan the rest of the array. */
+ for (i = ARC_FIRST_EXTENSION_CORE_REGISTER; i < ELEMENTS_IN_ARRAY(info->core_registers); i++)
+ {
+ ARC_CoreRegisterDefinition *def = &info->core_registers[i];
+
+ if (def->exists)
+ if (gdb_regno == def->gdb_regno)
+ return (ARC_RegisterNumber) (i);
+ }
+
+ /* Too large to be the number of a core register. */
+ return ARC_MAX_CORE_REGS + 1000;
+}
+
+
+/* Return the gdb register number of the given core register. */
+
+int
+arc_core_register_gdb_number (ARC_RegisterNumber hw_regno)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+ ARC_CoreRegisterDefinition *def = &info->core_registers[hw_regno];
+
+ gdb_assert(def->exists);
+
+ return def->gdb_regno;
+}
+
+
+/* Print the aux register whose definition and contents are given.
+ The field and meaning information in the definition is used to
+ give a detailed display of the register. */
+
+void
+arc_print_aux_register (ARC_AuxRegisterDefinition *def,
+ ARC_RegisterContents contents)
+
+{
+ printf_filtered (_("%s : %08x\n"), def->name, contents);
+
+ if (def->fields)
+ {
+ unsigned int i;
+ char format[128];
+
+ printf_filtered(_(" fields\n"));
+
+ /* Create a format string such as
+
+ " %-10s: %8s"
+
+ so that the field name is left-justified, and the field value is
+ right-justified. */
+ (void) snprintf(format, sizeof(format),
+ _(" %%-%us: %%%us"),
+ def->longest_field_name, def->max_bits_in_field);
+
+ for (i = 0; i < def->field_count; i++)
+ {
+ ARC_FieldDefinition *f = &def->fields[i];
+ ARC_RegisterContents val = contents >> f->offset;
+ ARC_RegisterContents val2 = val;
+ ARC_RegisterContents mask = 0;
+ char bits[BITS_IN_REGISTER];
+ char *p = &bits[BITS_IN_REGISTER - 1];
+ unsigned int b;
+
+ *p = '\0';
+
+ /* Build up a string representing the bits of the field, starting
+ with the least significant bit, which will be the rightmost digit
+ displayed; at the same time, construct a mask of 1-bits of the
+ same size as the field. */
+ for (b = 0; b < f->size; b++)
+ {
+ p--;
+ *p = (val & 1) ? '1' : '0';
+ val >>= 1;
+
+ mask <<= 1;
+ mask++;
+ }
+
+ printf_filtered(format, f->name, p);
+
+ if (f->meanings)
+ {
+ unsigned int j;
+
+ val2 &= mask;
+
+ /* Look for a meaning for this particular value of the field. */
+ for (j = 0; j < f->meaning_count; j++)
+ {
+ ARC_FieldMeaning *m = &f->meanings[j];
+
+ if (val2 == m->value)
+ {
+ printf_filtered(_(" (%s)"), m->description);
+ break;
+ }
+ }
+ }
+
+ printf_filtered(_("\n"));
+ }
+ }
+
+ printf_filtered(_("\n"));
+}
+
+
+/* Return the gdb register number of the given aux register. */
+
+int
+arc_aux_gdb_register_number (ARC_AuxRegisterDefinition *def)
+{
+ return def->gdb_regno;
+}
+
+
+/* Return the hardware register number of the given aux register. */
+
+ARC_RegisterNumber
+arc_aux_hw_register_number (ARC_AuxRegisterDefinition *def)
+{
+ return def->number;
+}
+
+
+/* Return the access mode (R/W, RO 0r WO) of the given aux register. */
+
+RegisterAccess
+arc_aux_register_access (ARC_AuxRegisterDefinition *def)
+{
+ return def->access;
+}
+
+
+/* Return TRUE if the given aux register is not used in the processor architecture,
+ i.e. there is a "place-holder" definition of that register (possibly a BCR) in
+ the XML file, but that register does not actually exist on the target. */
+
+Boolean
+arc_aux_is_unused (ARC_AuxRegisterDefinition *def)
+{
+ return (def->name == UNUSED);
+}
+
+
+/* Return TRUE if the given aux register is a BCR (Build Configuration Register). */
+
+Boolean
+arc_aux_is_BCR (ARC_AuxRegisterDefinition *def)
+{
+ return def->is_BCR;
+}
+
+
+/* Return the name of the given aux register. */
+
+const char*
+arc_aux_register_name (ARC_AuxRegisterDefinition *def)
+{
+ return def->name;
+}
+
+
+/* Return the access mode (R/W, RO 0r WO) of the given core register. */
+
+RegisterAccess
+arc_core_register_access (ARC_RegisterNumber hw_regno)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+ ARC_CoreRegisterDefinition *def = &info->core_registers[hw_regno];
+
+ gdb_assert(def->exists);
+
+ return def->access;
+}
+
+
+/* Return the name of the given auxiliary register. */
+
+const char*
+arc_aux_register_name_of (ARC_RegisterNumber hw_regno)
+{
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+
+ return (def) ? def->name : "<no such register>";
+}
+
+
+/* Return TRUE if the given register is a core register. */
+
+Boolean
+arc_is_core_register (int gdb_regno)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+
+ return (gdb_regno < info->first_aux_gdb_regno);
+}
+
+
+/* Iterate across all the aux registers; for each one, call the supplied
+ function, passing it the defintion of the register and the supplied data. */
+
+void
+arc_all_aux_registers (ARC_AuxRegisterFunction function, void *data)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+ unsigned int i;
+
+ for (i = 0; i < info->aux_register_count; i++)
+ function(info->aux_registers + i, data);
+}
+
+
+/* Return the length of the longest aux register name in the current architecture. */
+unsigned int
+arc_aux_register_max_name_length (void)
+{
+ ARC_RegisterInfo *info = find_info(TRUE);
+
+ return info->max_name_length;
+}
+
+
+/* Return the number of aux registers defined for the given architecture;
+ 0 if no register set has yet been defined. */
+
+unsigned int
+arc_aux_register_count (struct gdbarch *gdbarch)
+{
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+
+ return (info) ? info->aux_register_count : 0;
+}
+
+
+/* Return the number of core registers defined for the given architecture;
+ ARC_NUM_STANDARD_CORE_REGS if no register set has yet been defined. */
+
+unsigned int
+arc_core_register_count (struct gdbarch *gdbarch)
+{
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+
+ return (info) ? info->core_register_count : ARC_NUM_STANDARD_CORE_REGS;
+}
+
+
+/* Return TRUE if the register set has been defined for the given architecture. */
+
+Boolean
+arc_aux_regs_defined (struct gdbarch *gdbarch)
+{
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+
+ return (info->aux_register_count > 0 && info->aux_registers != NULL);
+}
+
+
+/* Return the architectural version of the register set associated with the
+ given architecture. */
+
+ARC_ProcessorVersion
+arc_aux_architecture (struct gdbarch *gdbarch)
+{
+ ARC_RegisterInfo *info = INFO_OF(gdbarch);
+
+ return info->processor;
+}
+
+
+/* Compute the value to be written to an auxiliary register so that any fields it
+ has contain the values that they are required to have by the ARC architectural
+ specification.
+
+ Parameters:
+ def : the definition of the aux register
+ value : the value to be adjusted
+
+ Result: the adjusted register contents. */
+
+ARC_RegisterContents
+arc_write_value (ARC_AuxRegisterDefinition *def,
+ ARC_RegisterContents value)
+{
+ unsigned int i;
+
+ for (i = 0; i < def->field_count; i++)
+ {
+ ARC_FieldDefinition *field = &def->fields[i];
+
+ if (field->fixed)
+ {
+ value &= ~(((1 << field->size) - 1) << field->offset);
+ value |= (field->value_for_write << field->offset);
+ }
+ }
+
+ return value;
+}
+
+
+/* Adjust the value to be written to a register so that any fields it has contain
+ the values that they are required to have by the ARC architectural specification.
+
+ Parameters:
+ gdb_regno : the number of the aux register
+ buffer : the value to be adjusted
+ */
+
+void
+arc_convert_aux_contents_for_write (int gdb_regno, void *buffer)
+{
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_gdb_number(gdb_regno);
+
+ /* Is it an auxiliary register? If not, do nothing. */
+ if (def)
+ {
+ ARC_RegisterContents old;
+ ARC_RegisterContents new;
+
+ memcpy(&old, buffer, BYTES_IN_REGISTER);
+ new = arc_write_value(def, old);
+
+ if (new != old)
+ {
+ DEBUG("*** converted register %s value from %08X to %08X\n",
+ arc_aux_register_name(def), old, new);
+ memcpy(buffer, &new, BYTES_IN_REGISTER);
+ }
+ }
+}
+
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+void
+_initialize_arc_aux_regs (void)
+{
+ arc_pending_register_architecture_change_event = FALSE;
+
+ /* If this module is being built with a test driver. */
+#ifdef STANDALONE_TEST
+ /* N.B. it would be better to set this up in the test driver, but that
+ causes problems when linking! */
+ struct gdbarch_info info;
+ static ARC_VariantsInfo variant;
+ struct gdbarch_tdep *tdep = malloc (sizeof (struct gdbarch_tdep));
+ struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
+
+ tdep->processor_variant_info = &variant;
+ current_gdbarch = gdbarch;
+#endif
+
+ (void) add_cmd (REG_READ_FILE_COMMAND,
+ class_files,
+ arc_aux_reg_file_read_command,
+ _("Read a file describing a set of auxiliary registers.\n"
+ REG_READ_FILE_COMMAND_USAGE
+ "<FILE> is an XML file containing the auxiliary register definitions.\n"),
+ &cmdlist);
+
+ (void) add_cmd (REG_READ_EXTRA_FILE_COMMAND,
+ class_files,
+ arc_aux_reg_file_read_extra_command,
+ _("Read a file describing an additional set of auxiliary registers.\n"
+ REG_READ_EXTRA_FILE_COMMAND_USAGE
+ "<FILE> is an XML file containing the auxiliary register definitions.\n"),
+ &cmdlist);
+
+ (void) add_cmd (AUX_LIST_REGISTER_COMMAND,
+ class_vars,
+ arc_aux_reg_list_command,
+ _("Show a description of one or all auxiliary registers.\n"
+ AUX_LIST_REGISTER_COMMAND_USAGE
+ "<REG> is the name of an auxiliary register.\n"),
+ &cmdlist);
+
+ (void) add_cmd(ARC_BCR_COMMAND,
+ class_info,
+ arc_print_bcr_regs,
+ _("Show Build Configuration Registers in the ARC processor variant.\n"
+ ARC_BCR_COMMAND_USAGE),
+ &infolist);
+
+ (void) add_cmd (AUX_REG_READ_COMMAND,
+ class_vars,
+ arc_aux_reg_read_command,
+ _("Read and show a range of auxiliary registers.\n"
+ AUX_REG_READ_COMMAND_USAGE
+ "REG-FROM and REG-TO are the names or numbers of the registers.\n"
+ "If REG-TO is not specified, one register is displayed.\n"),
+ &cmdlist);
+
+ (void) add_cmd (AUX_REG_WRITE_COMMAND,
+ class_vars,
+ arc_aux_reg_write_command,
+ _("Write to an auxiliary register.\n"
+ AUX_REG_WRITE_COMMAND_USAGE
+ "REG is the name or number of the register.\n"
+ "VALUE can be any expression that evaluates to an integer.\n"),
+ &cmdlist);
+
+ (void) add_cmd (AUX_REG_SHOW_COMMAND,
+ class_vars,
+ arc_aux_reg_show_command,
+ _("Read and show one or all auxiliary registers.\n"
+ AUX_REG_SHOW_COMMAND_USAGE
+ "<REG> is the name of an auxiliary register.\n"),
+ &cmdlist);
+
+ /* Provide the built-in simulator with a functions that it can use to map
+ from gdb register numbers to h/w register numbers, and set the fields
+ of aux registers to any values that they may be required to have on write. */
+ arc_set_register_mapping(&simulator_mapping);
+ arc_set_aux_register_conversion(arc_convert_aux_contents_for_write);
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-registers.h b/gdb/arc-registers.h
new file mode 100644
index 00000000000..9fb6521351a
--- /dev/null
+++ b/gdb/arc-registers.h
@@ -0,0 +1,226 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines operations for manipulating the ARC processor */
+/* core registers and auxiliary registers. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_REGISTERS_H
+#define ARC_REGISTERS_H
+
+/* gdb header files */
+#include "defs.h"
+#include "gdbarch.h"
+
+/* ARC header files */
+#include "arc-support.h"
+#include "arc-tdep.h"
+#include "arc-architecture.h"
+
+
+#define REGISTER_DEFINITION_FILE "arc-registers.xml"
+
+
+/* ARC aux registers with known (well-defined) numbers. */
+#define ARC_HW_LP_START_REGNUM (ARC_RegisterNumber) 0x2
+#define ARC_HW_LP_END_REGNUM (ARC_RegisterNumber) 0x3
+#define ARC_HW_IDENTITY_REGNUM (ARC_RegisterNumber) 0x4
+#define ARC_HW_DEBUG_REGNUM (ARC_RegisterNumber) 0x5
+#define ARC_HW_PC_REGNUM (ARC_RegisterNumber) 0x6
+#define ARC_HW_STATUS32_REGNUM (ARC_RegisterNumber) 0xA
+
+/* Specific ARCangel aux registers for caches. */
+#define ARC_HW_IC_IVIC_REGNUM (ARC_RegisterNumber) 0x10 /* Invalidate ICache. */
+#define ARC_HW_IC_CTRL_REGNUM (ARC_RegisterNumber) 0x11 /* Disable ICache. */
+#define ARC_HW_DC_IVDC_REGNUM (ARC_RegisterNumber) 0x47 /* Invalidate DCache. */
+#define ARC_HW_DC_CTRL_REGNUM (ARC_RegisterNumber) 0x48 /* Disable DCache. */
+
+/* BCRs. */
+#define ARC_HW_MEMSUBSYS_REGNUM (ARC_RegisterNumber) 0x67
+#define ARC_HW_AP_BUILD_REGNUM (ARC_RegisterNumber) 0x76
+
+/* Auxiliary registers for actionpoint 0 (there are up to 8 sets of these). */
+#define ARC_HW_AMV0_REGNUM (ARC_RegisterNumber) 0x220
+#define ARC_HW_AMM0_REGNUM (ARC_RegisterNumber) 0x221
+#define ARC_HW_AC0_REGNUM (ARC_RegisterNumber) 0x222
+
+
+/* Bit masks for use with the cache-related auxiliary registers. */
+#define IC_IVIC_IV 0x00000001
+#define DC_IVDC_IV 0x00000001
+#define IC_CTRL_DC 0x00000001
+#define DC_CTRL_DC 0x00000001
+#define DC_CTRL_IM 0x00000040
+
+
+/* Bit masks for use with the auxiliary DEBUG, IDENTITY, STATUS32 and AP_BUILD registers. */
+#define DEBUG_SH 0x40000000
+#define DEBUG_BH 0x20000000
+#define DEBUG_USER 0x10000000
+#define DEBUG_ACTIONPOINT_HALT 0x00000004
+#define DEBUG_ACTIONPOINT_STATUS 0x000007F8
+#define DEBUG_ACTIONPOINT_STATUS_SHIFT 3
+#define DEBUG_FORCE_HALT 0x00000002
+#define DEBUG_INSTRUCTION_STEP 0x00000800
+#define DEBUG_SINGLE_STEP 0x00000001
+#define DEBUG_LOAD_PENDING 0x80000000
+#define IDENTITY_ARCVER 0x000000FF
+#define STATUS32_USER 0x00000080
+#define STATUS32_L 0x00000100
+#define STATUS32_HALT 0x00000001
+#define AP_BUILD_VERSION 0x000000FF
+#define AP_BUILD_TYPE 0x00000F00
+#define AP_BUILD_TYPE_SHIFT 8
+
+
+typedef enum register_access
+{
+ READ_ONLY,
+ READ_WRITE,
+ WRITE_ONLY
+} RegisterAccess;
+
+
+struct core_register_definition
+{
+ int gdb_regno;
+ ARC_Word mask;
+ RegisterAccess access;
+ Boolean exists;
+};
+
+
+/* The type 'struct aux_register_definition' is incomplete: it is private to this
+ module. */
+typedef struct aux_register_definition ARC_AuxRegisterDefinition;
+typedef struct core_register_definition ARC_CoreRegisterDefinition;
+
+
+/* This type is essentially private: no access to any of its fields should
+ be performed outside of this module. */
+typedef struct _register_info
+{
+ ARC_ProcessorVersion processor;
+ ARC_AuxRegisterDefinition *aux_registers;
+ unsigned int aux_register_count;
+ int first_aux_gdb_regno;
+ unsigned int max_name_length;
+ int PC_number;
+ ARC_CoreRegisterDefinition core_registers[ARC_MAX_CORE_REGS];
+ unsigned int core_register_count;
+} ARC_RegisterInfo;
+
+
+typedef void (*ARC_AuxRegisterFunction)(ARC_AuxRegisterDefinition *def, void *data);
+
+
+extern Boolean arc_pending_register_architecture_change_event;
+
+
+/* Initialization functions. */
+
+void arc_initialize_aux_reg_info (ARC_RegisterInfo *info);
+
+void arc_read_default_aux_registers (struct gdbarch *gdbarch);
+
+
+/* PC-related functions. */
+
+void arc_aux_pc_guard (struct gdbarch *gdbarch, Boolean on);
+
+void arc_aux_check_pc_defined (struct gdbarch *gdbarch);
+
+int arc_aux_pc_number (struct gdbarch *gdbarch);
+
+
+/* Output functions. */
+
+void arc_print_aux_register (ARC_AuxRegisterDefinition *def,
+ ARC_RegisterContents contents);
+
+
+/* Search functions. */
+
+ARC_AuxRegisterDefinition* arc_find_aux_register_by_name (const char *name);
+
+ARC_AuxRegisterDefinition* arc_find_aux_register_by_gdb_number (int gdb_regno);
+
+ARC_AuxRegisterDefinition* arc_find_aux_register_by_hw_number (ARC_RegisterNumber hw_regno);
+
+ARC_RegisterNumber arc_aux_find_register_number (const char *name,
+ ARC_RegisterNumber defaultNumber);
+
+ARC_RegisterNumber arc_core_register_number (int gdb_regno);
+
+int arc_core_register_gdb_number (ARC_RegisterNumber hw_regno);
+
+const char* arc_aux_register_name_of (ARC_RegisterNumber hw_regno);
+
+Boolean arc_is_core_register (int gdb_regno);
+
+
+/* Accessor functions. */
+
+int arc_aux_gdb_register_number (ARC_AuxRegisterDefinition *def);
+
+ARC_RegisterNumber arc_aux_hw_register_number (ARC_AuxRegisterDefinition *def);
+
+RegisterAccess arc_aux_register_access (ARC_AuxRegisterDefinition *def);
+
+Boolean arc_aux_is_unused (ARC_AuxRegisterDefinition *def);
+
+Boolean arc_aux_is_BCR (ARC_AuxRegisterDefinition *def);
+
+const char* arc_aux_register_name (ARC_AuxRegisterDefinition *def);
+
+RegisterAccess arc_core_register_access (ARC_RegisterNumber regno);
+
+
+/* Iterator/summary functions. */
+
+void arc_all_aux_registers (ARC_AuxRegisterFunction function, void *data);
+
+unsigned int arc_aux_register_max_name_length (void);
+
+unsigned int arc_aux_register_count (struct gdbarch *gdbarch);
+
+unsigned int arc_core_register_count (struct gdbarch *gdbarch);
+
+Boolean arc_aux_regs_defined (struct gdbarch *gdbarch);
+
+ARC_ProcessorVersion arc_aux_architecture (struct gdbarch *gdbarch);
+
+/* Register contents conversion functions. */
+
+ARC_RegisterContents arc_write_value (ARC_AuxRegisterDefinition *def, ARC_RegisterContents value);
+
+void arc_convert_aux_contents_for_write (int gdb_regno, void *buffer);
+
+
+#endif /* ARC_REGISTERS_H */
+/******************************************************************************/
diff --git a/gdb/arc-regnums-defs.h b/gdb/arc-regnums-defs.h
index 6071ee43def..bc872954d21 100644
--- a/gdb/arc-regnums-defs.h
+++ b/gdb/arc-regnums-defs.h
@@ -1,108 +1,125 @@
-/* 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 Free Software Foundation, Inc.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Ramana Radhakrishnan <ramana.radhakrishnan@codito.com>
+ Authors:
+ 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.
-*/
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This file defines register numbers for ARC processors. */
+/* */
+/* N.B. this file is NOT a module header file and must NOT have an inclusion */
+/* guard: it may be included at multiple points in a module. */
+/* */
+/* THIS FILE IS NO LONGER USED!!!! */
+/* */
+/******************************************************************************/
+
+#ifndef STANDALONE_TEST
+#error This file is no longer used
+#endif
+
+/* Auxiliary Registers. */
#ifdef RAUX
-#ifdef ARC4_JTAG
-
-RAUX ( STATUS , 0x0, "Status Regnum " , ARC_STATUS_REGNUM , A4 )
-RAUX ( SEMAPHORE , 0x1, "Semaphore Regnum ", ARC_SEMAPHORE_REGNUM , A4 )
-RAUX ( LP_START , 0x2, "Loop Start" , ARC_LP_START_REGNUM , A4 )
-RAUX ( LP_END , 0x3, "Loop End", ARC_LP_END_REGNUM , A4 )
-RAUX ( IDENTITY , 0x4, "Identity", ARC_IDENTITY_REGNUM , A4 )
-RAUX ( DEBUG , 0x5, "Debug" , ARC_DEBUG_REGNUM , A4 )
-
-#else
-
-RAUX ( STATUS , 0x0, "Status Regnum (obsolete)" , ARC_STATUS_REGNUM , ARCompact )
-RAUX ( SEMAPHORE , 0x1, "Semaphore Regnum ", ARC_SEMAPHORE_REGNUM , ARCompact )
-RAUX ( LP_START , 0x2, "Loop Start" , ARC_LP_START_REGNUM , ARCompact )
-RAUX ( LP_END , 0x3, "Loop End", ARC_LP_END_REGNUM , ARCompact )
-RAUX ( IDENTITY , 0x4, "Identity", ARC_IDENTITY_REGNUM , ARCompact )
-RAUX ( DEBUG , 0x5, "Debug" , ARC_DEBUG_REGNUM , ARCompact )
-RAUX ( PC, 0x6,"PC" , ARC_PC_REGNUM ,ARCompact )
-RAUX ( STATUS32 ,0xA,"STATUS32", ARC_STATUS32_REGNUM , ARCompact )
-RAUX ( STATUS32_L1 , 0xB, "STATUS32 register in case of L1 interrupts" ,ARC_STATUS32_L1_REGNUM , ARCompact )
-RAUX ( STATUS32_L2 , 0xC, "STATUS32 register in case of L2 interrupts" ,ARC_STATUS32_L2_REGNUM , ARCompact )
-RAUX ( COUNT0 , 0x21, "Processor Timer 1 Count Value", ARC_COUNT0_REGNUM , ARCompact )
-RAUX ( CONTROL0 , 0x22, "Processor Timer 1 Control Value" , ARC_CONTROL0_REGNUM, ARCompact)
-RAUX ( LIMIT0 , 0x23, "Processor Timer 1 Limit Value" , ARC_LIMIT0_REGNUM, ARCompact )
-RAUX ( INT_VECTOR_BASE , 0x25, "Interrupt Vector Base Register", ARC_INT_VECTOR_BASE_REGNUM , ARCompact )
-RAUX ( AUX_IRQ_MACMODE , 0x41, "Aux IRQ MAC Mode " , ARC_AUX_MACMODE_REGNUM , ARCompact )
-RAUX ( AUX_IRQ_LV12 , 0x42, "Aux IRQ Level 2 " , ARC_AUX_IRQ_LV12_REGNUM , ARCompact )
-RAUX ( COUNT1 , 0x100, "Processor Timer 1 Count Value", ARC_COUNT1_REGNUM , ARCompact )
-RAUX ( CONTROL1 , 0x101, "Processor Timer 1 Control Value" , ARC_CONTROL1_REGNUM , ARCompact)
-RAUX ( LIMIT1 , 0x102, "Processor Timer 1 Limit Value", ARC_LIMIT1_REGNUM , ARCompact)
-RAUX ( AUX_IRQ_LEV , 0x200, "Interrupt Level programming. ", ARC_AUX_IRQ_LEV_REGNUM , ARCompact)
-RAUX ( AUX_IRQ_HINT , 0x201, "Software Triggered Interrupt" , ARC_AUX_IRQ_HINT_REGNUM, ARCompact )
-RAUX ( ERET , 0x400, "Exception Return " , ARC_ERET_REGNUM, ARC700 )
-RAUX ( ERBTA , 0x401, "Exception BTA ", ARC_ERBTA_REGNUM, ARC700 )
-RAUX ( ERSTATUS , 0x402, "Exception Return Status" , ARC_ERSTATUS_REGNUM, ARC700 )
-RAUX ( ECR , 0x403, "Exception Cause Register" , ARC_ECR_REGNUM, ARC700 )
-RAUX ( EFA , 0x404, "Exception Fault Address" , ARC_EFA_REGNUM, ARC700 )
-RAUX ( ICAUSE1 , 0x40A, "Interrupt Cause (Level 1)", ARC_ICAUSE1_REGNUM,ARC700 )
-RAUX ( ICAUSE2 , 0x40B, "Interrupt Cause (Level 2)", ARC_ICAUSE2_REGNUM, ARC700)
-RAUX ( AUX_IENABLE , 0x40C, "Interrupt Mask Programming", ARC_AUX_IENABLE_REGNUM, ARC700 )
-RAUX ( AUX_ITRIGGER , 0x40D, "Interrupt Sensitivity Programming", ARC_AUX_ITRIGGER_REGNUM, ARC700 )
-RAUX ( XPU , 0x410, "User Mode Extension Permissions", ARC_XPU_REGNUM, ARC700 )
-RAUX ( BTA , 0x412, "Branch Target Address", ARC_BTA_REGNUM, ARC700 )
-RAUX ( BTA_L1 , 0x413, "Branch Target Address in Level 1", ARC_BTA_L1_REGNUM, ARC700 )
-RAUX ( BTA_L2 , 0x414, "Branch Target Address in Level 2", ARC_BTA_L2_REGNUM, ARC700 )
-RAUX ( AUX_IRQ_PULSE_CANCEL , 0x415, "Interrupt Pulse Cancel", ARC_AUX_IRQ_PULSE_CANCEL_REGNUM, ARC700 )
-RAUX ( AUX_IRQ_PENDING , 0x416, "Interrupt Pending Register", ARC_AUX_IRQ_PENDING_REGNUM, ARC700 )
-#endif // ARC4_JTAG
+
+RAUX ( STATUS, 0x0, "Status (obsolete)", ARC_STATUS_REGNUM, 0xFEFFFFFF, RO, ARCompact )
+RAUX ( SEMAPHORE, 0x1, "Semaphore", ARC_SEMAPHORE_REGNUM, 0x0000000F, RW, ARCompact )
+RAUX ( LP_START, 0x2, "Loop Start", ARC_LP_START_REGNUM, 0xFFFFFFFE, RW, ARCompact )
+RAUX ( LP_END, 0x3, "Loop End", ARC_LP_END_REGNUM, 0xFFFFFFFE, RW, ARCompact )
+RAUX ( IDENTITY, 0x4, "Identity", ARC_IDENTITY_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RAUX ( DEBUG, 0x5, "Debug", ARC_DEBUG_REGNUM, 0xF0800802, RO, ARCompact )
+RAUX ( PC, 0x6, "PC", ARC_PC_REGNUM, 0xFFFFFFFE, RO, ARCompact )
+RAUX ( STATUS32, 0xA, "STATUS32", ARC_STATUS32_REGNUM, 0x00001FFF, RO, ARCompact )
+RAUX ( STATUS32_L1, 0xB, "STATUS32 register in case of L1 interrupts", ARC_STATUS32_L1_REGNUM, 0x00001FFE, RW, ARCompact )
+RAUX ( STATUS32_L2, 0xC, "STATUS32 register in case of L2 interrupts", ARC_STATUS32_L2_REGNUM, 0x00001FFE, RW, ARCompact )
+RAUX ( COUNT0, 0x21, "Processor Timer 1 Count Value", ARC_COUNT0_REGNUM, 0xFFFFFFFF, RW, ARCompact )
+RAUX ( CONTROL0, 0x22, "Processor Timer 1 Control Value", ARC_CONTROL0_REGNUM, 0x0000000F, RW, ARCompact )
+RAUX ( LIMIT0, 0x23, "Processor Timer 1 Limit Value", ARC_LIMIT0_REGNUM, 0xFFFFFFFF, RW, ARCompact )
+RAUX ( INT_VECTOR_BASE, 0x25, "Interrupt Vector Base Register", ARC_INT_VECTOR_BASE_REGNUM, 0xFFFFFC00, RW, ARCompact )
+RAUX ( AUX_MACMODE, 0x41, "Aux MAC Mode", ARC_AUX_MACMODE_REGNUM, 0xFFFFFFFF, RW, ARCompact )
+RAUX ( AUX_IRQ_LV12, 0x43, "Aux IRQ Level 2", ARC_AUX_IRQ_LV12_REGNUM, 0x00000003, RW, ARCompact )
+RAUX ( COUNT1, 0x100, "Processor Timer 1 Count Value", ARC_COUNT1_REGNUM, 0xFFFFFFFF, RW, ARCompact )
+RAUX ( CONTROL1, 0x101, "Processor Timer 1 Control Value", ARC_CONTROL1_REGNUM, 0x0000000F, RW, ARCompact )
+RAUX ( LIMIT1, 0x102, "Processor Timer 1 Limit Value", ARC_LIMIT1_REGNUM, 0xFFFFFFFF, RW, ARCompact )
+RAUX ( AUX_IRQ_LEV, 0x200, "Interrupt Level programming", ARC_AUX_IRQ_LEV_REGNUM, 0xFFFFFFF8, RW, ARCompact )
+RAUX ( AUX_IRQ_HINT, 0x201, "Software Triggered Interrupt", ARC_AUX_IRQ_HINT_REGNUM, 0x0000001F, RW, ARCompact )
+RAUX ( ERET, 0x400, "Exception Return", ARC_ERET_REGNUM, 0xFFFFFFFE, RW, ARC700 )
+RAUX ( ERBTA, 0x401, "Exception BTA", ARC_ERBTA_REGNUM, 0xFFFFFFFE, RW, ARC700 )
+RAUX ( ERSTATUS, 0x402, "Exception Return Status", ARC_ERSTATUS_REGNUM, 0x00001FFE, RW, ARC700 )
+RAUX ( ECR, 0x403, "Exception Cause Register", ARC_ECR_REGNUM, 0x00FFFFFF, RO, ARC700 )
+RAUX ( EFA, 0x404, "Exception Fault Address", ARC_EFA_REGNUM, 0xFFFFFFFF, RW, ARC700 )
+RAUX ( ICAUSE1, 0x40A, "Interrupt Cause (Level 1)", ARC_ICAUSE1_REGNUM, 0x0000001F, RO, ARC700 )
+RAUX ( ICAUSE2, 0x40B, "Interrupt Cause (Level 2)", ARC_ICAUSE2_REGNUM, 0x0000001F, RO, ARC700 )
+RAUX ( AUX_IENABLE, 0x40C, "Interrupt Mask Programming", ARC_AUX_IENABLE_REGNUM, 0xFFFFFFF8, RW, ARC700 )
+RAUX ( AUX_ITRIGGER, 0x40D, "Interrupt Sensitivity Programming", ARC_AUX_ITRIGGER_REGNUM, 0xFFFFFFF8, RW, ARC700 )
+RAUX ( XPU, 0x410, "User Mode Extension Permissions", ARC_XPU_REGNUM, 0xFFFFFFFF, RW, ARC700 )
+RAUX ( BTA, 0x412, "Branch Target Address", ARC_BTA_REGNUM, 0xFFFFFFFE, RO, ARC700 )
+RAUX ( BTA_L1, 0x413, "Branch Target Address in Level 1", ARC_BTA_L1_REGNUM, 0xFFFFFFFE, RW, ARC700 )
+RAUX ( BTA_L2, 0x414, "Branch Target Address in Level 2", ARC_BTA_L2_REGNUM, 0xFFFFFFFE, RW, ARC700 )
+RAUX ( AUX_IRQ_PULSE_CANCEL, 0x415, "Interrupt Pulse Cancel", ARC_AUX_IRQ_PULSE_CANCEL_REGNUM, 0xFFFFFFFA, WO, ARC700 )
+RAUX ( AUX_IRQ_PENDING, 0x416, "Interrupt Pending Register", ARC_AUX_IRQ_PENDING_REGNUM, 0xFFFFFFF8, RO, ARC700 )
+
#endif // RAUX
+
+/* Build Configuration Registers. */
+
#ifdef RBCR
-#ifndef ARC4_JTAG
-
-RBCR ( DCCM_BASE_BUILD , 0x61, "Base address for DCCM.", ARC_BCR_1_REGNUM, ARCompact)
-RBCR ( CRC_BASE_BUILD , 0x62, "BCRBCR for CRC Unit.", ARC_BCR_2_REGNUM , ARCompact)
-RBCR ( BTA_LINK_BUILD , 0x63, "Interrupt Link Registers Available for BTA",ARC_BCR_3_REGNUM, ARCompact )
-RBCR ( DVBF_BUILD , 0x64, "BCRBCR for Dual Viterbi Instruction.",ARC_BCR_4_REGNUM, ARCompact )
-RBCR ( TEL_INSTR_BUILD , 0x65, "BCRBCR for Extended Arithmetic Instructions. ",ARC_BCR_5_REGNUM, ARCompact)
-RBCR ( MEMSUBSYS , 0x67, "BCRBCR for Memory Subsystem. ",ARC_BCR_7_REGNUM, ARCompact)
-RBCR ( VECBASE_AC_BUILD ,0x68, "BCRBCR for Interrupt Vector Base. ", ARC_BCR_8_REGNUM,ARCompact)
-RBCR ( P_BASE_ADDRESS , 0x69, "Peripheral Base Address" , ARC_BCR_9_REGNUM , ARCompact)
-RBCR ( MMU_BUILD , 0x6F, "MMU Build. " , ARC_BCR_F_REGNUM, ARCompact)
-RBCR ( ARCANGEL_BUILD , 0x70, "ARC Angel Build config. ", ARC_BCR_10_REGNUM, ARCompact)
-RBCR ( D_CACHE_BUILD , 0x72, "D Cache Build Config. ", ARC_BCR_12_REGNUM , ARCompact )
-RBCR ( MADI_BUILD , 0x73 , "Multiple ARC Debug Interface. " , ARC_BCR_13_REGNUM , ARCompact)
-RBCR ( DCCM_BUILD , 0x74, "BCRBCR for DCCM.(Data Closely coupled Memory", ARC_BCR_14_REGNUM, ARCompact)
-RBCR ( TIMER_BUILD , 0x75, "BCRBCR for Timers. " , ARC_BCR_15_REGNUM , ARCompact)
-RBCR ( AP_BUILD, 0x76, "Actionpoints build. ", ARC_BCR_16_REGNUM , ARCompact )
-RBCR ( ICACHE_BUILD , 0x77, "Instruction Cache BCR", ARC_BCR_17_REGNUM , ARCompact )
-RBCR ( ICCM_BUILD , 0x78, "ICCM BCRBCR (Instruction Closely Coupled Memory.", ARC_BCR_18_REGNUM , ARCompact)
-RBCR ( DSPRAM_BUILD , 0x79, "DSP RAM Build", ARC_BCR_19_REGNUM , ARCompact)
-RBCR ( MAC_BUILD , 0x7A, "MAC Unit Build", ARC_BCR_1A_REGNUM , ARCompact)
-RBCR ( MULTIPLY_BUILD , 0x7B, "(32 X 32) Multiply Unit Build", ARC_BCR_1B_REGNUM , ARCompact)
-RBCR ( SWAP_BUILD , 0x7C, "SWAP Build", ARC_BCR_1C_REGNUM , ARCompact)
-RBCR ( NORM_BUILD , 0x7D ,"NORM Unit Build", ARC_BCR_1D_REGNUM, ARCompact)
-RBCR ( MINMAX_BUILD , 0x7E, "Minmax Unit Build", ARC_BCR_1E_REGNUM, ARCompact)
-RBCR ( BARREL_BUILD , 0x7F, "Barrel Shifter Build", ARC_BCR_1F_REGNUM , ARCompact)
-
-
-#endif // ARC4_JTAG
-#endif // RBCR
+
+RBCR ( UNUSED_0, 0x60, "unused", ARC_BCR_0_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( DCCM_BASE_BUILD, 0x61, "Base address for DCCM", ARC_BCR_1_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( CRC_BASE_BUILD, 0x62, "BCR for CRC Unit", ARC_BCR_2_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( BTA_LINK_BUILD, 0x63, "Interrupt Link Registers Available for BTA", ARC_BCR_3_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( DVBF_BUILD, 0x64, "BCR for Dual Viterbi Instruction", ARC_BCR_4_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( TEL_INSTR_BUILD, 0x65, "BCR for Extended Arithmetic Instructions", ARC_BCR_5_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( UNUSED_6, 0x66, "unused", ARC_BCR_6_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( MEMSUBSYS, 0x67, "BCR for Memory Subsystem", ARC_BCR_7_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( VECBASE_AC_BUILD, 0x68, "BCR for Interrupt Vector Base", ARC_BCR_8_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( P_BASE_ADDRESS, 0x69, "Peripheral Base Address", ARC_BCR_9_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( UNUSED_A, 0x6A, "unused", ARC_BCR_A_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( UNUSED_B, 0x6B, "unused", ARC_BCR_B_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( UNUSED_C, 0x6C, "unused", ARC_BCR_C_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( UNUSED_D, 0x6D, "unused", ARC_BCR_D_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( UNUSED_E, 0x6E, "unused", ARC_BCR_E_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( MMU_BUILD, 0x6F, "MMU Build", ARC_BCR_F_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( ARCANGEL_BUILD, 0x70, "ARC Angel Build Config", ARC_BCR_10_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( UNUSED_11, 0x6E, "unused", ARC_BCR_11_REGNUM, 0xFFFFFFFF, UU, ARCompact )
+RBCR ( D_CACHE_BUILD, 0x72, "D Cache Build Config", ARC_BCR_12_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( MADI_BUILD, 0x73, "Multiple ARC Debug Interface", ARC_BCR_13_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( DCCM_BUILD, 0x74, "BCR for DCCM (Data Closely Coupled Memory)", ARC_BCR_14_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( TIMER_BUILD, 0x75, "BCR for Timers", ARC_BCR_15_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( AP_BUILD, 0x76, "Actionpoints build", ARC_BCR_16_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( ICACHE_BUILD, 0x77, "Instruction Cache BCR", ARC_BCR_17_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( ICCM_BUILD, 0x78, "ICCM BCR (Instruction Closely Coupled Memory)", ARC_BCR_18_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( DSPRAM_BUILD, 0x79, "DSP RAM Build", ARC_BCR_19_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( MAC_BUILD, 0x7A, "MAC Unit Build", ARC_BCR_1A_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( MULTIPLY_BUILD, 0x7B, "(32 X 32) Multiply Unit Build", ARC_BCR_1B_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( SWAP_BUILD, 0x7C, "SWAP Build", ARC_BCR_1C_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( NORM_BUILD, 0x7D, "NORM Unit Build", ARC_BCR_1D_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( MINMAX_BUILD, 0x7E, "Minmax Unit Build", ARC_BCR_1E_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+RBCR ( BARREL_BUILD, 0x7F, "Barrel Shifter Build", ARC_BCR_1F_REGNUM, 0xFFFFFFFF, RO, ARCompact )
+
+#endif // RBCR
+
+/******************************************************************************/
diff --git a/gdb/arc-remote-fileio.c b/gdb/arc-remote-fileio.c
new file mode 100644
index 00000000000..5bb22eafe31
--- /dev/null
+++ b/gdb/arc-remote-fileio.c
@@ -0,0 +1,741 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 implements facilities for intercepting I/O (and other) */
+/* operations attempted on an ARC target and performing them on the host, */
+/* using a RPC (Remote Procedure Call) mechanism. */
+/* */
+/* Mechanism: */
+/* When interception is enabled, this module sets a breakpoint at the */
+/* entry point of each operation which is to be intercepted; it finds the */
+/* entry points of named routines in the C runtime library code by using */
+/* gdb's symbol lookup facilities. */
+/* */
+/* When a breakpoint is triggered on the target, the target monitoring */
+/* loop calls the function 'arc_check_interception_breakpoint' to check */
+/* whether the breakpoint triggered is an interception breakpoint; this */
+/* function will return a code indicating either */
+/* */
+/* a) the breakpoint is an interception breakpoint, the interception */
+/* has been performed and execution of the target program should be */
+/* resumed; or */
+/* */
+/* b) the breakpoint is an interception breakpoint, but the intercepted */
+/* routine is 'exit' and execution should not be resumed; or */
+/* */
+/* c) the breakpoint is not an interception breakpoint, so execution */
+/* should not be resumed and the trigger should be reported to gdb. */
+/* */
+/* In case a), this module then reads the routine's parameters from the */
+/* target's registers, performs whatever conversions are required, and */
+/* constructs a gdb RSP File I/O extension 'F' message which it passes to */
+/* the gdb target_fileio module, which performs the requested operation */
+/* on the host machine. */
+/* */
+/* The target_fileio module is passed a set of operations which allow it */
+/* to read data from target memory, write data to target memory, and */
+/* return a result value (and possibly a error code) to the intercepted */
+/* routine. The result value is written into the target's R0 register; */
+/* the error code (if any) is written into the location of the 'errno' */
+/* variable. */
+/* */
+/* Finally, this module copies the routine return address from the BLINK */
+/* register to the PC register - this ensures that when execution of the */
+/* target is resumed, control returns to the code after the call to the */
+/* intercepted routine. */
+/* */
+/* Notes: */
+/* 1) the set of routines to be intercepted, and the parameters to these */
+/* routines, is defined by a table (see below) - so it is simple to */
+/* add more routines to the set; */
+/* */
+/* 2) the 'open' syscall (see man open(2)) has a 'flags' parameter which */
+/* is a bit mask; unfortunately, the bits differ in meaning between */
+/* the host and the elf-32 target program, so the parameter must be */
+/* converted before it can be passed to the target_fileio module; */
+/* */
+/* 3) the 'fstat' syscall (see man fstat(2)) has an out parameter which */
+/* is a 'struct stat' structure (i.e. the address of such a structure */
+/* is a parameter to the syscall): the target_fileio module writes the */
+/* data of the structure to that location in target memory; however, */
+/* the structure does not have the same layout on host and target, so */
+/* the structure must be converted before it can be written to the */
+/* target; */
+/* */
+/* 4) the interception breakpoints are not handled by the core gdb */
+/* breakpoint mechanism; hence, they are not listed by the 'info break'*/
+/* command, and can not be (accidentally) deleted by the user; though */
+/* they could be handled by gdb, that would require the introduction */
+/* of a new "invisible" breakpoint type, and hence more changes to */
+/* supposedly generic code; */
+/* */
+/* 5) it would be more elegant (from one perspective) to intecept these */
+/* operations by placing a breakpoint at the interrupt vector location */
+/* of the 'swi' (SoftWare Interrupt) handler: only one breakpoint */
+/* would then be required, and all syscalls would be intercepted; */
+/* however, this module would then have to simulate a "return from */
+/* exception" in order to resume target execution, which would be more */
+/* complex than the "restart at return address" method currently used. */
+/* */
+/* Restrictions: */
+/* 1) this module places s/w breakpoints at the entry points; therefore, */
+/* the mechanism will not work with programs that are loaded into read */
+/* -only memory; */
+/* */
+/* 2) this mechanism will probably not work if the user sets breakpoints */
+/* on the entry points of the intercepted routines - there will be a */
+/* conflict! */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "symtab.h"
+#include "frame.h"
+#include "block.h"
+#include "target.h"
+#include "target-fileio.h"
+#include "exceptions.h"
+#include "gdb/fileio.h"
+
+/* ARC header files */
+#include "arc-remote-fileio.h"
+#include "config/arc/tm-embed.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_SYSCALL_PARAMS 4
+
+/* These are the intercepted routines. */
+typedef enum
+{
+ READ_CALL,
+ WRITE_CALL,
+ OPEN_CALL,
+ CLOSE_CALL,
+ LSEEK_CALL,
+ FSTAT_CALL,
+ GETTIMEOFDAY_CALL,
+ EXIT_CALL
+} SystemCall;
+
+
+struct lib_function
+{
+ SystemCall call;
+ const char *name;
+ const char *format;
+ Boolean bp_is_set;
+ unsigned int param_count;
+ ARC_RegisterNumber param_register[MAX_SYSCALL_PARAMS];
+ struct bp_target_info breakpoint;
+};
+
+
+/* This structure defines a memory image of the 'stat' structure as it is
+ represented on the ARC target. */
+struct arc_stat
+{
+ ARC_Byte fst_dev [4];
+ ARC_Byte fst_ino [4];
+ ARC_Byte fst_mode [2];
+ ARC_Byte fst_nlink [2];
+ ARC_Byte fst_uid [2];
+ ARC_Byte fst_gid [2];
+ ARC_Byte fst_rdev [4];
+ ARC_Byte fst_size [4];
+ ARC_Byte fst_blksize[4];
+ ARC_Byte fst_blocks [4];
+ ARC_Byte fst_atime [8];
+ ARC_Byte fst_mtime [8];
+ ARC_Byte fst_ctime [8];
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+/* The %x specifiers in the format strings in this table correspond to the
+ parameters to the intercepted functions; the register number of the target
+ register in which the parameter is passed is given by the corresponding
+ entry in the param_register array.
+
+ N.B. the special value of SL as the number of the register in which a
+ parameter is passed indicates that the preceding parameter was the
+ address of a string, and the length of that string (including the
+ terminating NUL) is required here.
+
+ F<n> indicates that the parameter in register <n> is a word of flag
+ bits which must be handled specially!
+
+ X indicates that the array element is not used. */
+
+#define SL 1000
+#define F2 1002
+#define X 9999
+
+static struct lib_function functions[] =
+{
+ { READ_CALL, "_read_r", "Fread,%x,%x,%x", FALSE, 3, {1, 2, 3, X} },
+ { WRITE_CALL, "_write_r", "Fwrite,%x,%x,%x", FALSE, 3, {1, 2, 3, X} },
+ { OPEN_CALL, "_open_r", "Fopen,%x/%x,%x,%x", FALSE, 4, {1, SL, F2, 3} },
+ { CLOSE_CALL, "_close_r", "Fclose,%x", FALSE, 1, {1, X, X, X} },
+ { LSEEK_CALL, "_lseek_r", "Flseek,%x,%x,%x", FALSE, 3, {1, 2, 3, X} },
+ { FSTAT_CALL, "_fstat_r", "Ffstat,%x,%x", FALSE, 2, {1, 2, X, X} },
+ { GETTIMEOFDAY_CALL, "_gettimeofday_r", "Fgettimeofday,%x,%x", FALSE, 2, {1, 2, X, X} },
+ { EXIT_CALL, "_exit_r", NULL, FALSE, 1, {1, X, X, X} }
+};
+
+
+/* A pointer to the set of target operations for the current target. */
+static TargetOperations *target_operations;
+
+/* TRUE if the operation currently being intercepted has NOT been interrupted
+ by the user typing a Ctrl-C. */
+static Boolean not_interrupted;
+
+/* For the Ctrl-C signal handler. */
+static void (*old_signal_handler) (int);
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Read a number of bytes of data from the given address in target memory. */
+
+static int
+read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+{
+ DEBUG("reading %d bytes from %x\n", len, (unsigned int) memaddr);
+
+ return (int) target_read (&current_target, TARGET_OBJECT_MEMORY, NULL, myaddr, memaddr, len);
+}
+
+
+/* Read a number of bytes of data from the given address in target memory. */
+
+static int
+write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+{
+ DEBUG("writing %d bytes to %x\n", len, (unsigned int) memaddr);
+
+ return (int) target_write (&current_target, TARGET_OBJECT_MEMORY, NULL, myaddr, memaddr, len);
+}
+
+
+/* Perform the reply to the intercepted operation: set up the result of the call
+ and the error code (if any) so that the intercepted operation receives them
+ just as though the operation had really been performed upon the target. */
+
+static void
+reply (int retcode, int error)
+{
+ /* Ignore any Ctrl-Cs while performing the reply. */
+ (void) signal (SIGINT, SIG_IGN);
+
+ DEBUG("reply: retcode = %d, error = %d\n", retcode, error);
+
+ /* If an error has occurred. */
+ if (retcode == -1)
+ {
+ ARC_RegisterContents errno_address;
+
+ if (error == FILEIO_EINTR)
+ {
+ DEBUG("*** interrupted by user!\n");
+ /* Set the global flag so that it can be tested later. */
+ not_interrupted = FALSE;
+ return;
+ }
+
+ /* Read the address of the 'errno' variable from R0. */
+ if (target_operations->read_core_register(0, &errno_address, TRUE))
+ /* Write the error number into the 'errno' variable. */
+ (void) write_bytes((CORE_ADDR) errno_address, (gdb_byte*) &error, BYTES_IN_WORD);
+ }
+
+ /* Write the return code into the function result register R0. */
+ (void) target_operations->write_core_register(0, (ARC_RegisterContents) retcode, TRUE);
+}
+
+
+/* Copy a number of bytes of data from one buffer to another. Note that the
+ buffers are not necessarily of the same size. Perform endianess byte-swapping
+ if necessary. */
+
+static void
+copy_bytes (char *from, size_t from_size,
+ ARC_Byte *to, size_t to_size,
+ Boolean target_is_big_endian)
+{
+ /* We can not copy more data than we have been given in the source buffer,
+ or for which there is room in the destination buffer. */
+ unsigned int bytes = (unsigned int) ((from_size > to_size) ? to_size : from_size);
+ unsigned int i;
+
+ /* N.B. 1) the fio_stat structure created by target-fileio.c has the values
+ in big-endian byte order; so if the ARC target is little-endian
+ we must reverse the order;
+
+ 2) the fields in the fio_stat structure may be smaller (or larger!)
+ than the corresponding fields in the ARC target structure - so we
+ copy the *least* significant bytes of the fields, on the grounds
+ that the most significant bytes are probably just sign-extensions! */
+ for (i = 0; i < bytes; i++)
+ to[i] = (ARC_Byte) ((target_is_big_endian) ? from[i]
+ : from[from_size - 1 - i]);
+}
+
+
+/* Write a 'stat' structure to the target at a given address in memory.
+ 'myaddr' points to a fio_stat structure created by the target-fileio module;
+ this structure is meant for use in the RSP protocol, and is designed for
+ independence of host/target systems - therefore, we must create an equivalent
+ structure which is ARC-specific, and write that structure to the target.
+
+ Return the number of bytes of data written. */
+
+static int
+write_fstat (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+{
+ Boolean target_is_big_endian = (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG);
+ struct fio_stat *fst = (struct fio_stat*) myaddr;
+ struct arc_stat ast;
+
+ memset(&ast, 0, sizeof(ast));
+
+#define COPY(from, to) copy_bytes(from, sizeof(from), to, sizeof(to), target_is_big_endian)
+
+ COPY(fst->fst_dev, ast.fst_dev);
+ COPY(fst->fst_ino, ast.fst_ino);
+ COPY(fst->fst_mode, ast.fst_mode);
+ COPY(fst->fst_nlink, ast.fst_nlink);
+ COPY(fst->fst_uid, ast.fst_uid);
+ COPY(fst->fst_gid, ast.fst_gid);
+ COPY(fst->fst_rdev, ast.fst_rdev);
+ COPY(fst->fst_size, ast.fst_size);
+ COPY(fst->fst_blksize, ast.fst_blksize);
+ COPY(fst->fst_blocks, ast.fst_blocks);
+ COPY(fst->fst_atime, ast.fst_atime);
+ COPY(fst->fst_mtime, ast.fst_mtime);
+ COPY(fst->fst_ctime, ast.fst_ctime);
+
+ return write_bytes(memaddr, (gdb_byte*) &ast, (int) sizeof(ast));
+}
+
+
+/* Find the address of the entry point of the given routine in the target program.
+ Return 0 if the entry point can not be found, or is not a function. */
+
+static CORE_ADDR
+findEntryPoint (const char *routine)
+{
+ CORE_ADDR entry = 0;
+ int is_a_field_of_this;
+ struct symbol *sym = lookup_symbol (routine,
+ get_selected_block (0),
+ VAR_DOMAIN,
+ &is_a_field_of_this,
+ (struct symtab **) NULL);
+ if (sym)
+ {
+ if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+ entry = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ else
+ warning(_("%s is not a function"), routine);
+ }
+ else
+ warning(_("can not find entry point of function %s"), routine);
+
+ return entry;
+}
+
+
+/* Insert a s/w breakpoint in the target program code at the entry point of the
+ given library function. */
+
+static void
+insert_breakpoint (struct lib_function *f)
+{
+ if (!f->bp_is_set)
+ {
+ if (arc_elf32_insert_breakpoint(&f->breakpoint) == 0)
+ f->bp_is_set = TRUE;
+ else
+ warning(_("can not set breakpoint at entrypoint of %s"), f->name);
+ }
+}
+
+
+/* Remove a s/w breakpoint from the target program code at the entry point of the
+ given library function. */
+
+static void
+remove_breakpoint (struct lib_function *f)
+{
+ if (f->bp_is_set)
+ {
+ if (arc_elf32_remove_breakpoint(&f->breakpoint) == 0)
+ f->bp_is_set = FALSE;
+ else
+ warning(_("can not unset breakpoint at entrypoint of %s"), f->name);
+ }
+}
+
+
+/* This function handles any Ctrl-C typed by the user whilst the interception of
+ an operation is in progress. */
+
+static void
+Ctrl_C_signal_handler (int signo)
+{
+ /* Ignore any more Ctrl-Cs. */
+ (void) signal (SIGINT, SIG_IGN);
+
+ /* We must use the gdb exception mechanism since the target_fileio_request
+ function calls catch_exceptions, and if we do something else (like a long
+ jump) here, gdb's cleanup list would be left in an inconsistent state! */
+ DEBUG("*** throwing RETURN_QUIT...\n");
+ deprecated_throw_reason (RETURN_QUIT);
+}
+
+
+/* This function is called from the gdb target-fileio module: it sets up this
+ module's handler for Ctrl-C interrupts. */
+
+static void
+set_Ctrl_C_signal_handler (void)
+{
+ old_signal_handler = signal (SIGINT, Ctrl_C_signal_handler);
+}
+
+
+/* This function finds the length of a C string stored in target memory at the
+ given address. */
+
+static unsigned int
+find_string_length (ARC_Address address)
+{
+ unsigned int length = 0;
+
+ while (TRUE)
+ {
+ gdb_byte buf[65];
+ int bytes = read_bytes((CORE_ADDR) address,
+ buf,
+ (int) sizeof(buf) - 1);
+ int i;
+
+ for (i = 0; i < bytes; i++)
+ if (buf[i] == (gdb_byte) '\0')
+ return (unsigned int) (length + i + 1);
+
+ address += bytes;
+ length += bytes;
+ }
+}
+
+
+/* Convert flags to target syscall to what they "should" be! */
+
+static ARC_RegisterContents
+convert_flags (ARC_RegisterContents flags)
+{
+ ARC_RegisterContents result = flags;
+
+/* See gcc/src/newlib/libc/sys/arc/sys/fcntl.h */
+
+/* The following values have been changed for uclibc compatibility. */
+#define _FAPPEND 0x0400 /* append (writes guaranteed at the end) */
+#define _FASYNC 0x2000 /* signal pgrp when data ready */
+#define _FCREAT 0x0040 /* open with file create */
+#define _FTRUNC 0x0200 /* open with truncation */
+#define _FEXCL 0x0080 /* error on open if file exists */
+#define _FSYNC 0x1000 /* do all writes synchronously */
+#define _FNONBLOCK 0x0800 /* non blocking I/O (POSIX style) */
+
+#define REMOVE(flag) if (flags & _F ## flag) result &= ~ _F ## flag
+#define ADD(flag) if (flags & _F ## flag) result |= FILEIO_O_ ## flag
+
+ /* N.B. all "old" bits most be removed from the result word before all
+ "new" bits are added, in case the old and new sets intersect! */
+ REMOVE(APPEND);
+// REMOVE(ASYNC); // no equivalent flag in gdb/fileio.h
+ REMOVE(CREAT);
+ REMOVE(TRUNC);
+ REMOVE(EXCL);
+// REMOVE(SYNC); // no equivalent flag in gdb/fileio.h
+// REMOVE(NONBLOCK); // no equivalent flag in gdb/fileio.h
+ ADD(APPEND);
+// ADD(ASYNC); // no equivalent flag in gdb/fileio.h
+ ADD(CREAT);
+ ADD(TRUNC);
+ ADD(EXCL);
+// ADD(SYNC); // no equivalent flag in gdb/fileio.h
+// ADD(NONBLOCK); // no equivalent flag in gdb/fileio.h
+
+ return result;
+}
+
+
+/* Perform the interception of the given library function.
+ Return TRUE if the interception is completed successfully,
+ FALSE if it is interrupted by the user. */
+
+static Boolean
+perform_interception (struct lib_function *f)
+{
+ ARC_RegisterContents params [MAX_SYSCALL_PARAMS];
+ char request[MAX_SYSCALL_PARAMS * 9 + 40];
+ unsigned int i;
+
+ /* These operations allow the target_fileio module to read data from target
+ memory, write data to target memory, and return a result value (and
+ possibly a error code) to the intercepted routine.
+
+ N.B. if the syscsall is 'fstat', we pass a special write function
+ which converts the 'struct stat' structure to target layout before
+ writing it to target memory. */
+ struct file_io_operations io_operations =
+ {
+ read_bytes,
+ (f->call == FSTAT_CALL) ? write_fstat : write_bytes,
+ reply,
+ set_Ctrl_C_signal_handler
+ };
+
+ /* Evaluate the parameters to be passed to the RPC request. */
+ for (i = 0; i < f->param_count; i++)
+ {
+ ARC_RegisterNumber reg = f->param_register[i];
+
+ if (reg == SL)
+ params[i] = find_string_length((ARC_Address) params[i - 1]);
+ else if (reg == F2)
+ {
+ ARC_RegisterContents flags;
+
+ (void) target_operations->read_core_register(2, &flags, TRUE);
+ params[i] = convert_flags(flags);
+ }
+ else
+ (void) target_operations->read_core_register(reg, &params[i], TRUE);
+ }
+
+ /* Do not close the target program's stdin, stdout or stderr streams on the
+ host: it is possible that the program may be re-loaded and re-run on the
+ target in the same debugging session (so re-initializing its I/O system)
+ so it may try to read/write those streams again - instead, just tell the
+ target that the close succeeded. */
+ if (f->call == CLOSE_CALL)
+ {
+ int fd = (int) params[0];
+
+ if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+ {
+ reply(0, 0);
+ DEBUG("*** RPC close of stream %d ignored\n", fd);
+ return TRUE;
+ }
+ }
+
+ /* Parameters which are extra to those required by the format will simply be
+ ignored. */
+ (void) snprintf(request, sizeof(request), f->format,
+ params[0], params[1], params[2], params[3]);
+
+ DEBUG("RPC request: %s\n", request);
+
+ /* the interception might be interrupted by the user typing Ctrl-C whilst
+ the interception is in progress; if that happens, this flag will be set
+ to FALSE. */
+ not_interrupted = TRUE;
+
+ /* Make the RPC request. */
+ target_fileio_request(request, &io_operations);
+
+ (void) signal (SIGINT, old_signal_handler);
+
+ /* If the call was not interrupted, the interception has been performed. */
+ return not_interrupted;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Set the state of the I/O interception mechanism:
+ ON : set breakpoints on all the functions to be intercepted
+ OFF : clear breakpoints from all the intercepted functions
+ RESET: mark the breakpoints as not being set (if a new program has been
+ downloaded to the target, the s/w breakpoints in the old program
+ have been lost, and so should not be removed). */
+
+void
+arc_set_IO_interception (TargetOperations *operations,
+ InterceptionState state)
+{
+ unsigned int i;
+
+ DEBUG("*** interception: %s\n", (state == INTERCEPTION_RESET) ? "RESET" :
+ (state == INTERCEPTION_ON) ? "ON" :
+ "OFF");
+
+ target_operations = operations;
+
+ for (i = 0; i < ELEMENTS_IN_ARRAY(functions); i++)
+ {
+ struct lib_function* f = &functions[i];
+
+ switch (state)
+ {
+ case INTERCEPTION_RESET:
+ f->bp_is_set = FALSE;
+ break;
+
+ case INTERCEPTION_ON:
+ /* Set a breakpoint on the entry point of the function. */
+ f->breakpoint.placed_address = findEntryPoint(f->name);
+
+ if (f->breakpoint.placed_address != 0)
+ {
+ DEBUG("intercept 0x%08X : %s\n", (unsigned int) f->breakpoint.placed_address, f->name);
+ insert_breakpoint(f);
+ }
+ break;
+
+ case INTERCEPTION_OFF:
+ if (f->breakpoint.placed_address != 0)
+ {
+ remove_breakpoint(f);
+ f->breakpoint.placed_address = 0;
+ }
+ break;
+ }
+ }
+}
+
+
+/* This function is called when the execution of the target program has been
+ halted by a breakpoint trigger. It checks whether the breakpoint that has
+ been triggered is at the entry point of an intercepted function, and, if so,
+ performs the required interception.
+
+ Returns:
+ INTERCEPTION_RESUME : interception has been performed, execution should be resumed
+ INTERCEPTION_HALT : the program is halted (no interception has been performed)
+ INTERCEPTION_EXIT : the program has exited
+ INTERCEPTION_INTERRUPT : the interception has been interrupted by the user
+
+ If the program has exited, the 'exitcode' parameter is set to the program's exit code. */
+
+InterceptionAction
+arc_check_interception_breakpoint (int *exitcode)
+{
+ ARC_RegisterContents pc;
+
+ ENTERMSG;
+
+ *exitcode = 0;
+
+ /* Get the current execution point from the PCL, rather than the PC - this
+ gives the same result on both ARC700 and ARC600 targets. */
+ if (target_operations->read_core_register(ARC_PCL_REGNUM, &pc, TRUE))
+ {
+ unsigned int i;
+
+ DEBUG("checking for interception at 0x%08X\n", pc);
+
+ /* Look at each of the intercepted operations. */
+ for (i = 0; i < ELEMENTS_IN_ARRAY(functions); i++)
+ {
+ struct lib_function *f = &functions[i];
+
+ if (f->breakpoint.placed_address == (CORE_ADDR) pc)
+ {
+ DEBUG("intercepted function %s\n", f->name);
+
+ if (f->call == EXIT_CALL)
+ {
+ ARC_RegisterContents code;
+
+ /* The exit code is in parameter register R1. */
+ if (target_operations->read_core_register(1, &code, TRUE))
+ *exitcode = (int) code;
+
+ return INTERCEPTION_EXIT;
+ }
+ else
+ {
+ /* If the interception is performed. */
+ if (perform_interception(f))
+ {
+ ARC_RegisterContents blink;
+
+ /* Copy BLINK to PC, so that when execution is re-started,
+ control will return to the point after the call of the
+ intercepted function. */
+ if (target_operations->read_core_register (ARC_BLINK_REGNUM, &blink, TRUE) &&
+ target_operations->write_auxiliary_register(arc_pc_regnum, blink, TRUE))
+ {
+ DEBUG("copied BLINK (%x) to PC (was %x)\n", blink, pc);
+ return INTERCEPTION_RESUME;
+ }
+
+ /* If we couldn't set PC, fall through. */
+ }
+ else
+ {
+ /* The interception has been interrupted by a Ctrl-C
+ from the user - do not change the PC, as we want
+ execution to resume at the same point in the code,
+ so that the I/O request will be performed (and
+ intercepted) again: this e.g. allows the user to
+ break into a program that is in a tight loop doing
+ reads or writes. */
+ return INTERCEPTION_INTERRUPT;
+ }
+ }
+ }
+ }
+ }
+
+ return INTERCEPTION_HALT;
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-remote-fileio.h b/gdb/arc-remote-fileio.h
new file mode 100644
index 00000000000..7a2d76c5c02
--- /dev/null
+++ b/gdb/arc-remote-fileio.h
@@ -0,0 +1,64 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Author:
+ 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 header file defines facilities for intercepting I/O (and other) */
+/* operations attempted on an ARC target and performing them on the host, */
+/* using a RPC (Remote Procedure Call) mechanism. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_REMOTE_FILEIO
+#define ARC_REMOTE_FILEIO
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+typedef enum
+{
+ INTERCEPTION_RESUME,
+ INTERCEPTION_HALT,
+ INTERCEPTION_EXIT,
+ INTERCEPTION_INTERRUPT
+} InterceptionAction;
+
+
+typedef enum
+{
+ INTERCEPTION_RESET,
+ INTERCEPTION_ON,
+ INTERCEPTION_OFF
+} InterceptionState;
+
+
+void arc_set_IO_interception (TargetOperations *operations,
+ InterceptionState state);
+
+InterceptionAction arc_check_interception_breakpoint (int *exitcode);
+
+#endif /* ARC_REMOTE_FILEIO */
+/******************************************************************************/
diff --git a/gdb/arc-support.h b/gdb/arc-support.h
new file mode 100644
index 00000000000..76ff0bfea36
--- /dev/null
+++ b/gdb/arc-support.h
@@ -0,0 +1,136 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines some useful types and constants, and macros */
+/* for use in debugging. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_SUPPORT_H
+#define ARC_SUPPORT_H
+
+
+#define ARC_DEBUG 1
+
+#ifdef ARC_DEBUG
+#define DEBUG(...) if (arc_debug_target) fprintf_unfiltered(gdb_stdlog, __VA_ARGS__)
+#define ENTERMSG DEBUG("--- entered %s:%s()\n", __FILE__, __FUNCTION__)
+#define ENTERARGS(fmt, args...) DEBUG("--- entered %s:%s(" fmt ")\n", __FILE__, __FUNCTION__, args)
+#define LEAVEMSG DEBUG("--- exited %s:%s()\n", __FILE__, __FUNCTION__)
+#else
+#define DEBUG(...)
+#define ENTERMSG
+#define ENTERARGS(fmt, args...)
+#define LEAVEMSG
+#endif
+
+
+/* N.B. it must be possible to build some ARC modules without the rest of gdb so
+ that they can be exercised by stand-alone test drivers. */
+#ifdef STANDALONE_TEST
+#define error(...) { printf(__VA_ARGS__); printf("\n"); }
+#define warning(...) { printf(__VA_ARGS__); printf("\n"); }
+#define printf_filtered(...) printf(__VA_ARGS__)
+#define printf_unfiltered(...) printf(__VA_ARGS__)
+#define fprintf_unfiltered(STR, ...) printf(__VA_ARGS__)
+#define internal_error(...) abort()
+#endif
+
+
+/* Useful Boolean type and constants. */
+typedef int Boolean;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+
+/* Useful types for machine-related quantities.
+
+ N.B. the type ARC_RegisterNumber does not denote gdb register numbers;
+ instead, it denotes ARC processor hardware numbers, which are not
+ the same. */
+
+typedef unsigned int ARC_RegisterNumber;
+typedef unsigned int ARC_RegisterContents;
+typedef unsigned int ARC_Address;
+typedef unsigned long long int ARC_Doubleword;
+typedef unsigned int ARC_Word;
+typedef unsigned short int ARC_Halfword;
+typedef unsigned char ARC_Byte;
+
+
+/* Types for machine-access functions. */
+typedef Boolean (*ReadRegisterFunction)(ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure);
+
+typedef Boolean (*WriteRegisterFunction)(ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure);
+
+
+typedef unsigned int (*MemoryTransferFunction)(ARC_Address address,
+ ARC_Byte *data, /* May be not word-aligned. */
+ unsigned int amount);
+
+typedef unsigned int (*MemoryFillFunction) (ARC_Address address,
+ ARC_Word pattern,
+ unsigned int amount);
+
+typedef struct
+{
+ ReadRegisterFunction read_core_register;
+ WriteRegisterFunction write_core_register;
+ ReadRegisterFunction read_auxiliary_register;
+ WriteRegisterFunction write_auxiliary_register;
+ MemoryTransferFunction read_memory;
+ MemoryTransferFunction write_memory;
+ MemoryFillFunction fill_memory;
+} TargetOperations;
+
+
+/* Sizes of machine quantities. */
+#define BYTES_IN_WORD 4
+#define BYTES_IN_REGISTER 4
+#define BITS_IN_BYTE 8
+#define BITS_IN_WORD 32
+#define BITS_IN_ADDRESS 32
+#define BITS_IN_REGISTER 32
+
+
+/* Useful macros. */
+#define ELEMENTS_IN_ARRAY(arr) (unsigned int) (sizeof(arr) / sizeof(arr[0]))
+
+#define IS_WORD_ALIGNED(addr) ((addr) % BYTES_IN_WORD == 0)
+
+
+#endif /* ARC_SUPPORT_H */
+/******************************************************************************/
diff --git a/gdb/arc-tdep.c b/gdb/arc-tdep.c
index 8b542579ad3..f912f896dec 100644
--- a/gdb/arc-tdep.c
+++ b/gdb/arc-tdep.c
@@ -1,1999 +1,2591 @@
-/* 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.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Soam Vasani <soam.vasani@codito.com>
- Ramana Radhakrishnan <ramana.radhakrishnan@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.
-*/
+ 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. In particular, it has knowledge of the processor ABI. */
+/* */
+/* See */
+/* ARCompact Instruction Set Architecture */
+/* Programmer's Reference */
+/* (5115-018) */
+/* */
+/* for a description of ARC processor architecture, and */
+/* */
+/* System V ABI Supplement */
+/* 4093-004 */
+/* */
+/* for a complete definition of the ABI. */
+/* */
+/* */
+/* Stack Frame Layout: */
+/* This shows the layout of the stack frame for the general case of a */
+/* function call; a given function might not have a variable number of */
+/* arguments or local variables, or might not save any registers, so it */
+/* would not have the corresponding frame areas. Additionally, a leaf */
+/* function (i.e. one which calls no other functions) does not need to */
+/* save the contents of the BLINK register (which holds its return */
+/* address), and a function might not have a frame pointer. */
+/* */
+/* N.B. the stack grows downward, so SP points below FP in memory; SP */
+/* always points to the last used word on the stack, not the first */
+/* one. */
+/* */
+/* | | | */
+/* | arg word N | | caller's */
+/* | : | | frame */
+/* | arg word 10 | | */
+/* | arg word 9 | | */
+/* old SP ---> |-----------------------| -- */
+/* | var arg word 8 | | */
+/* | : | | */
+/* | var arg word P+1 | | */
+/* |-----------------------| | */
+/* | | | */
+/* | callee-saved | | */
+/* | registers | | */
+/* | | | */
+/* |-----------------------| | */
+/* | saved blink (*) | | */
+/* |-----------------------| | callee's */
+/* | saved FP | | frame */
+/* FP ---> |-----------------------| | */
+/* | | | */
+/* | local | | */
+/* | variables | | */
+/* | | | */
+/* | register | | */
+/* | spill area | | */
+/* | | | */
+/* | outgoing args | | */
+/* | | | */
+/* SP ---> |-----------------------| -- */
+/* | | */
+/* | unused | */
+/* | | */
+/* | */
+/* | */
+/* V */
+/* downwards */
+/* */
+/* The list of arguments to be passed to a function is considered to be a */
+/* sequence of N words (as though all the parameters were stored in order */
+/* in memory with each parameter occupying an integral number of words). */
+/* Words 1 .. 8 are passed in registers 0 .. 7; if the function has more */
+/* than 8 words of arguments then words 9 .. N are passed on the stack in */
+/* the caller's frame. */
+/* */
+/* If the function has a variable number of arguments, e.g. it has a form */
+/* such as */
+/* function(p1, p2, ...); */
+/* */
+/* and P words are required to hold the values of the named parameters */
+/* (which are passed in registers 0 .. P-1), then the remaining 8 - P */
+/* words passed in registers P .. 7 are spilled into the top of the frame */
+/* so that the anonymous parameter words occupy a continous region. */
+/* */
+/* (*) if saved. */
+/* */
+/* Usage: */
+/* The module exports a function _initialize_arc_tdep: the call to this */
+/* function is generated by the gdb build mechanism, so this function */
+/* should not be explicitly called. */
+/* */
+/* 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>); */
+/* */
+/* */
+/* Build Configuration: */
+/* The ARC gdb may be built in two different configurations, according to */
+/* the nature of the target that it is to debug: */
+/* */
+/* 1) arc-elf32: */
+/* for debugging 'bare-metal' builds of user code (i.e. built with */
+/* newlib) */
+/* */
+/* ARC-specific modules: */
+/* arc-tdep */
+/* arc-elf32-tdep */
+/* arc-xiss */
+/* arc-jtag */
+/* arc-jtag-ops */
+/* arc-jtag-actionpoints */
+/* arc-gpio */
+/* arc-remote-fileio */
+/* arc-registers */
+/* arc-architecture */
+/* arc-board */
+/* arc-arguments */
+/* arc-memory */
+/* arc-inst-tracing */
+/* */
+/* 2) arc-linux-uclibc: */
+/* for deugging user mode Linux applications, via communication to */
+/* the remote gdbserver process, running on Linux for ARC700 */
+/* */
+/* ARC-specific modules: */
+/* arc-tdep */
+/* arc-linux-tdep */
+/* */
+/* This module provides operations which are common to both; operations */
+/* which are specific to one, or which have different variants in each */
+/* configuration, are provided by the other modules. */
+/* */
+/* */
+/* Debug Targets: */
+/* The ARC gdb supports a number of debug targets. These are: */
+/* */
+/* arc-elf32-gdb */
+/* built-in simulator 'target sim' */
+/* ARCangel 4 h/w emulator 'target arcjtag' */
+/* dynamically loaded xISS simulator 'target arcxiss' */
+/* separately executing xISS simulator 'target remote' */
+/* */
+/* arc-linux-uclibc-gdb */
+/* gdbserver running on ARC Linux 'target remote' */
+/* */
+/* It should, in theory, be possible for either debugger to connect to */
+/* any remote target which supports the gdb Remote Serial Protocol. */
+/* However, any such target MUST agree with the debugger on the register */
+/* numbering scheme that is used, as this controls the order of register */
+/* contents held in the RSP 'G' (set all registers) packet and the 'g' */
+/* (get all registers) response packet, as well as the register numbers */
+/* used in the 'P' (set one register) and 'p' (get one register) packets, */
+/* and in the 'T' stop reply packet. The schemes used by each debugger */
+/* are defined in the arc-elf32-tdep and arc-linux-tdep modules. */
+/* */
+/******************************************************************************/
+
+/* system header files */
#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <byteswap.h>
+/* gdb header files */
#include "defs.h"
+#include "config.h"
#include "arch-utils.h"
#include "dis-asm.h"
-#include "gdbtypes.h"
#include "frame.h"
#include "frame-unwind.h"
-#include "target.h"
-#include "breakpoint.h"
#include "inferior.h"
#include "regcache.h"
#include "reggroups.h"
#include "trad-frame.h"
#include "dwarf2-frame.h"
-#include "gdbtypes.h"
-#include "gdb_assert.h"
#include "gdbcore.h"
#include "observer.h"
#include "osabi.h"
+#include "gdbcmd.h"
+#include "block.h"
+#include "dictionary.h"
+#include "language.h"
+#include "demangle.h"
+#include "objfiles.h"
+#include "gdb_assert.h"
-#include "opcode/arc.h"
-
-#include "arc-tdep.h"
-
+/* ARC header files */
-//#define ARC_DEBUG 1
+/* N.B. one and only one of ARC_ELF32_TARGET and ARC_LINUX_TARGET must be defined! */
-#if ARC_DEBUG
-# define ENTERMSG printf ("--- entered %s:%s()\n", __FILE__, __FUNCTION__)
-# define ENTERARGS(fmt, args...) printf ("--- entered %s:%s(" fmt ")\n", __FILE__, __FUNCTION__, args)
-# define LEAVEMSG printf ("--- exited %s:%s()\n", __FILE__, __FUNCTION__)
+#ifdef ARC_ELF32_TARGET
+#ifdef ARC_LINUX_TARGET
+#error ARC build is not correctly configured (both flags set)
#else
-# define ENTERMSG
-# define ENTERARGS(fmt, args...)
-# define LEAVEMSG
+#include "config/arc/tm-embed.h"
+#endif
+#else
+#ifdef ARC_LINUX_TARGET
+#include "config/arc/tm-linux.h"
+#else
+#error ARC build is not correctly configured (no flag set)
+#endif
#endif
-#define ARC_STATUS32_A1 0x8
-#define ARC_STATUS32_A2 0x10
-#define ARC_STATUS32_AE 0x20
-#define ARC_STATUS32_L 0x100
+#include "opcode/arc.h"
+#include "opcodes/arc-dis.h"
+#include "opcodes/arc-ext.h"
+#include "opcodes/arcompact-dis.h"
+#include "arc-support.h"
+#include "arc-tdep.h"
-static CORE_ADDR arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp);
-/* The frame unwind cache for the ARC
- */
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
-struct arc_unwind_cache
+typedef struct
{
- /* blink offset in stack */
- int blink_offset ;
+ const char *name;
+ CORE_ADDR address;
+ Boolean is_argument;
+ Boolean is_callee;
+ Boolean is_array;
+ unsigned int size;
+ unsigned int element_size;
+} LocalVariable;
- /* Caller's PC */
- CORE_ADDR prev_pc;
-
- /* The stack pointer at the time this frame was created; i.e. the
- caller's stack pointer when this function was called. It is used
- to identify this frame. */
-
- CORE_ADDR prev_sp;
- /* The frame base */
- CORE_ADDR frame_base;
- /* Frame size */
- int framesize;
-
- /* offset of sp from the stack frame base */
- LONGEST sp_offset;
- /* offset of fp from the stack frame base */
- LONGEST fp_offset;
- /* Is this a leaf function */
- int is_leaf ;
- /* Is there a frame pointer */
- int uses_fp;
-
-
- /* Offsets for each register in the stack frame */
- struct trad_frame_saved_reg *saved_regs;
-};
+/* The frame unwind cache for the ARC. */
+typedef struct
+{
+ /* BLINK save location offset from previous SP (-ve value). */
+ int blink_save_offset_from_prev_sp;
+ /* The stack pointer at the time this frame was created; i.e. the
+ caller's stack pointer when this function was called. It is used
+ to identify this frame. */
+ CORE_ADDR prev_sp;
+ /* The frame base (as held in FP).
+ N.B. this is NOT the address of the lowest word in the frame! */
+ CORE_ADDR frame_base;
-/* Function Prototypes */
+ /* Change in SP from previous SP (-ve value) - this is computed by scanning
+ the prologue of the function: initially 0, it is updated for each
+ instruction which changes SP (either explicitly by a subtraction from SP
+ or implicitly by a push operation), so at each point in the prologue it
+ gives the difference between the previous SP (i.e. before the function
+ was called) and the current SP at that point; at the end of the prologue
+ it holds the total change in SP, i.e. the size of the frame. */
+ LONGEST delta_sp;
-static CORE_ADDR arc_unwind_sp (struct gdbarch *gdbarch,
- struct frame_info *next_frame);
+ /* Offset of old stack pointer from frame base (+ve value). */
+ LONGEST old_sp_offset_from_fp;
-static CORE_ADDR arc_unwind_pc (struct gdbarch *gdbarch,
- struct frame_info *next_frame);
+ /* Is this a leaf function? */
+ Boolean is_leaf;
+ /* Is there a frame pointer? */
+ Boolean uses_fp;
-static struct arc_unwind_cache * arc_frame_unwind_cache (struct frame_info *next_frame,
- void ** this_prologue);
+ /* Offsets for each register in the stack frame. */
+ struct trad_frame_saved_reg *saved_regs;
+ unsigned int saved_regs_mask;
+} UnwindCache;
-static CORE_ADDR arc_scan_prologue (CORE_ADDR pc,
- struct frame_info *next_frame,
- struct arc_unwind_cache *info);
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
-static int arc_binutils_reg_to_regnum (int reg);
+#define DEBUG_COMMAND "arc-debug"
+#define SHOW_FRAME_COMMAND "arc-show-frame"
+#define SHOW_FRAME_COMMAND_USAGE "Usage: " SHOW_FRAME_COMMAND " [ <FRAME> ]\n"
-extern struct arcDisState arcAnalyzeInstr ( bfd_vma address,disassemble_info* info );
-extern struct arcDisState a4AnalyzeInstr ( bfd_vma address,disassemble_info* info );
+#define NEW_LINE _("\n")
-/* defined in opcodes, but there's no header file with this prototype... */
-disassembler_ftype arcompact_get_disassembler (void *);
-/* Standard register type for the ARC platform .
- * It would be builtin_type_uint32 until
- * we consider the DSP extensions
- */
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
-static struct type *
-arc_register_type (struct gdbarch *gdbarch, int regnum)
-{
- return builtin_type_uint32;
-}
+/* Global debug flag. */
+Boolean arc_debug_target;
-void printFrameInfo(struct arc_unwind_cache * info)
-{
-#ifdef ARC_DEBUG
- printf("-------------------\n");
- printf("%lx \n",info );
- printf("prev_sp = %lx \n",info->prev_sp);
- printf("prev_pc = %lx \n",info->prev_pc);
- printf("frame_base is %lx \n",info->frame_base);
- printf("framesize is %lx \n",info->framesize);
- printf("Blink offset %lx \n",info->blink_offset);
- printf("sp_offset = %lx \n",info->sp_offset );
- printf("fp_offset is %lx \n",info->fp_offset);
- printf("is_leaf = %d, uses_fp=%d",info->is_leaf, info->uses_fp);
-#endif
-}
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
-/* Print the instruction state returned
- by the disassembler . Used for internal
- debugging only
-*/
+#define WORD_ALIGNED(addr) ((addr) & ~(BYTES_IN_WORD - 1))
+#define WORDS_OCCUPIED(bytes) (((bytes) + BYTES_IN_WORD - 1) / BYTES_IN_WORD)
+#define ROUND_UP_TO_WORDS(bytes) (WORDS_OCCUPIED(bytes) * BYTES_IN_WORD)
-void printInsnState(struct arcDisState state)
-{
-#ifdef ARC_DEBUG
- printf("---------------------------------\n");
- printf("Instruction Length %d\n", state.instructionLen);
- printf("Opcode [0x%x] : Cond [%x]\n", state._opcode, state._cond);
- printf("Words 1 [%lx] : 2 [%lx]\n", state.words[0], state.words[1]);
- printf("ea present [%x] : memload [%x]\n", state._ea_present, state._mem_load);
- printf("Load length [%d]:\n", state._load_len);
- printf("Address writeback [%d]\n", state._addrWriteBack);
- printf("ea reg1 is [%x] offset [%x] \n", state.ea_reg1, state._offset);
- printf("ea reg2 is [%x] \n", state.ea_reg2);
- printf("operands buffer is %s \n", state.operandBuffer);
- printf("SourceType is %d \n",state.sourceType);
- printf("Flow is %d\n",state.flow);
- printf("Branch is %d,'%c'\n",state.isBranch, state.isBranch);
-#endif
-}
-/* Scan the prologue and update the
- * corresponding frame cache for the frame unwinder for unwinding
- * frames without debug info . In such a situation GDB attempts to
- * parse the prologue for this purpose . This currently would attempt
- * to parse the prologue generated by our gcc 2.95 .(We should support
- * Metaware generated binaries at some suitable point of time )
- * This function is called with the pc where gdb stopped , the next_frame
- * to be filled in (if need be?) and the existing cached info .
-
- * scan_prologue is called by our unwinder as well
- * as from skip_prologue in the case that it cannot detect
- * the end of the prologue. next_frame is set to NULL if we are called from
- * arc_skip_prologue in an attempt to discover the end of the prologue. In
- * such a case we don't fill the frame info that is passed to us :-)
-
- * Todos.
- * 1. Support 32 bit normal frames generated by GCC 2.95 .
- * 2. Support 16 and 32 bit mixed frames generated by GCC 2.95
- * 3. Support 32 bit normal variadic function frames by GCC 2.95
- * 4. Support 32 bit normal frames from GCC 3.4.x with variadic args
- * 5. Support 16 and 32 bit normal frames from GCC 3.4.x with variadic args
- * 6. Support 16 and 32 bit mixed frames generated by GCC 3.4.x
- * 7. Support Metaware generated prologues .( The difference is
- * in the use of thunks to identify the saving and restoring of
- * callee saves :-) May have to do some hackery even in next_pc.
- * since the call is going to create its own set of problems
- * with our stack setup :-(
- * We attempt to use the disassembler interface from the opcodes
- * library to do our disassembling .
-
- * The usual 32 bit normal
- * gcc -O0 prologue looks like this.
-
- * Complete Prologue for all GCC frames (Cases #1 to #6 in Todos above)
-
- * sub sp, sp, limm ; space for variadic arguments.
- * st.a blink, [sp,-4] ; push blink (if not a leaf function)
- * sub sp, sp , limm ; (optional space creation for callee saves )
- * st r13, [sp] ; pushes of all callee saves.
- * st r14, [sp,4] ; pushes of more callee saves.
- * XXXX
- * st.a fp , [sp,-4] ; push fp (if fp has to be saved )
- * mov fp , sp ; Set the current frame up correctly
- * sub sp , sp , #immediate ; Create space for local vars on the stack.
- */
+/* Macros to be used with disassembling the prologue and update the frame info.
+ The *FI macros are to update the frame info and the ACT macros are to
+ actually do the action on a corresponding match. */
+#define IS_INSTRUCTION(insn_name, search_string) !strcmp(insn_name, search_string)
+#define CHECK_OPERAND_STRING_AND_ACT(target_check, search_string, action) \
+ if (strstr(target_check, search_string) == target_check) \
+ { \
+ action; \
+ return TRUE; \
+ }
-/* Macros to be used with disassembling the prologue
- * and update the frame info.The *FI macros are to update
- * the frame info and the ACT macros are to actually do the
- * action on a corresponding match.
- *
-*/
-#define CHECKOPDSTRING(targetcheck,searchstring) \
- if(strstr(targetcheck,searchstring) == targetcheck) \
- {continue;}
-
-#define CHECKOPDSTRINGANDACT(targetcheck,searchstring,action) \
- if(strstr(targetcheck,searchstring) == targetcheck) \
- {\
- action;\
- continue;}
-
-
-/* The frame info changes by changing the decrementing
- the sp_offset and setting the leaf function to be NIL;
- Also the offset of the blink register from the previous
- value of sp is calculated. Finally this can be updated
- as
- info->blink_offset = info-> prev_sp + info->blink_offset ;
- Also the addition below is coz the offsets are usually negative
-*/
-#define PUSHBLINKACT do { \
- if(info) \
- { \
- info->sp_offset += current_instr._offset; \
- info->blink_offset = info->sp_offset ; \
- info->is_leaf = 0;\
- }}while(0);
-
+/* The frame info changes by changing the decrementing the delta_sp and setting
+ the leaf function flag to be False (if this function prologue is saving blink
+ then it must be going to call another function - so it can not be a leaf!);
+ also the offset of the blink register save location from the previous value
+ of sp is recorded. This will eventually used to compute the address of the
+ save location:
-#define ISPUSHBLINK(state) CHECKOPDSTRING(state.operandBuffer,"blink")
-#define ISPUSHBLINKFI(state) CHECKOPDSTRINGANDACT(state.operandBuffer,"blink",PUSHBLINKACT)
+ <blink saved address> = <prev sp> + <blink offset from prev sp>
+ The addition (+=) below is because the sp offset and the instruction offset
+ are negative - so incrementing the sp offset by the instruction offset is
+ actually making the sp offset more negative, correctly reflecting that SP
+ is moving further down the downwards-growing stack. */
-#define PUSHFPACT do { \
- if(info) \
- { \
- info->sp_offset += current_instr._offset ; \
- info->fp_offset = -info->sp_offset; \
- }}while(0);
-
-#define ISPUSHFP(state) CHECKOPDSTRING(state.operandBuffer,"fp")
-#define ISPUSHFPFI(state) CHECKOPDSTRINGANDACT(state.operandBuffer,"fp",PUSHFPACT)
-#define ISINSTRUCTION(insnname,searchstring) !strcmp(insnname,searchstring)
+#define PUSH_BLINK(offset) \
+ { \
+ info->delta_sp += offset; \
+ info->blink_save_offset_from_prev_sp = (int) info->delta_sp; \
+ info->is_leaf = FALSE; \
+ }
+#define PUSH_BLINK_ACT \
+ do { \
+ if (info) PUSH_BLINK(instr->_offset) \
+ } while (0);
-#define UPDATEFPACT do {\
- if(info) {\
- info->uses_fp = 1;\
- }}while(0);
+#define IS_PUSH_BLINK_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "blink", PUSH_BLINK_ACT)
+/* At the point that that FP is pushed onto the stack (so saving the dynamic
+ link chain pointer to the previous frame), at the address that will be the
+ base of the new frame, we know the offset of SP from the previous SP - so the
+ offset of the old SP from the new frame base is known (the -ve delta_sp is
+ negated to give the +ve old_sp_offset_from_fp). */
+#define PUSH_FP_ACT do { \
+ if (info) \
+ { \
+ info->delta_sp += instr->_offset; \
+ info->old_sp_offset_from_fp = -info->delta_sp; \
+ }} while (0);
-#define ISUPDATEFPFI(state) \
- if(ISINSTRUCTION(state.instrBuffer,"mov")) \
-{ \
- CHECKOPDSTRINGANDACT(state.operandBuffer,"fp,sp",UPDATEFPACT); \
-}
+#define IS_PUSH_FP_FI(state) CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp", PUSH_FP_ACT)
+#define UPDATE_FP_ACT do { \
+ if (info) \
+ info->uses_fp = TRUE; \
+ } while (0);
-#define ISUPDATEFP(state) \
- if(ISINSTRUCTION(state.instrBuffer,"mov")) \
-{ \
- CHECKOPDSTRING(state.operandBuffer,"fp,sp") \
-}
+#define IS_UPDATE_FP_FI(state) \
+ if (IS_INSTRUCTION(state->instrBuffer, "mov")) \
+ { \
+ CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "fp,sp", UPDATE_FP_ACT); \
+ }
+#define UPDATE_STACK_SPACE(state) do { \
+ if (info) { \
+ /* Eat up sp,sp. */ \
+ int immediate = atoi(state->operandBuffer + 6); \
+ info->delta_sp -= immediate; \
+ }} while (0);
-#define ISSUBSP(state) \
-if(ISINSTRUCTION(state.instrBuffer,"sub"))\
-{ \
- CHECKOPDSTRING(state.operandBuffer,"sp,sp") \
+
+#define IS_SUB_SP_FI(state) \
+ if (IS_INSTRUCTION(state->instrBuffer, "sub") || \
+ IS_INSTRUCTION(state->instrBuffer, "sub_s")) \
+ { \
+ CHECK_OPERAND_STRING_AND_ACT(state->operandBuffer, "sp,sp", UPDATE_STACK_SPACE(state)) \
+ }
+
+
+/* -------------------------------------------------------------------------- */
+/* forward declarations */
+/* -------------------------------------------------------------------------- */
+
+static CORE_ADDR scan_prologue (CORE_ADDR entrypoint,
+ struct frame_info *next_frame,
+ UnwindCache *info);
+
+
+/* -------------------------------------------------------------------------- */
+/* local debug functions */
+/* -------------------------------------------------------------------------- */
+
+/* Print information for a frame. */
+
+static void
+printFrameInfo (const char *message,
+ UnwindCache *info,
+ Boolean addresses_known)
+{
+ unsigned int i;
+
+ DEBUG("-------------------\n");
+ DEBUG("%s (info = %p)\n", message, info);
+ DEBUG("prev_sp = %lx\n", (long unsigned int) info->prev_sp);
+ DEBUG("frame_base = %lx\n", (long unsigned int) info->frame_base);
+ DEBUG("blink offset = %d\n", info->blink_save_offset_from_prev_sp);
+ DEBUG("delta_sp = %d\n", (int) info->delta_sp);
+ DEBUG("old_sp_offset_from_fp = %d\n", (int) info->old_sp_offset_from_fp);
+ DEBUG("is_leaf = %d, uses_fp = %d\n", info->is_leaf, info->uses_fp);
+
+ for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++)
+ {
+ if (info->saved_regs_mask & (1 << i))
+ DEBUG("saved register R%02d %s 0x%lx\n",
+ i,
+ (addresses_known) ? "address" : "offset",
+ (unsigned long) info->saved_regs[i].addr);
+ }
+ DEBUG("-------------------\n");
}
-#define UPDATESTACKSPACE(state) do { \
- if(info){ \
-/* Eat up sp,sp */ \
- int tmp = atoi(state.operandBuffer + 6); \
- info->sp_offset -= tmp; \
- }}while(0);
+
+static const char*
+ARC_Debugger_OperandType_Image (enum ARC_Debugger_OperandType value)
+{
+ switch (value)
+ {
+ case ARC_LIMM : return "LIMM";
+ case ARC_SHIMM : return "SHIMM";
+ case ARC_REGISTER : return "REGISTER";
+ case ARCOMPACT_REGISTER: return "COMPACT REGISTER";
+ case ARC_UNDEFINED : return "UNDEFINED";
+ }
+ return "?";
+}
-#define ISSUBSPFI(state) \
-if(ISINSTRUCTION(state.instrBuffer,"sub") \
- || ISINSTRUCTION(state.instrBuffer,"sub_s"))\
-{ \
- CHECKOPDSTRINGANDACT(state.operandBuffer,"sp,sp",UPDATESTACKSPACE(state)) \
+/* Print the instruction state returned by the disassembler.
+ Used for internal debugging only. */
+
+static void
+printInsnState (struct arcDisState state)
+{
+ DEBUG("---------------------------------\n");
+ DEBUG("Instruction Length %d\n", state.instructionLen);
+ DEBUG("Opcode [0x%x] : Cond [%x]\n", state._opcode, state._cond);
+ DEBUG("Words 1 [%lx] : 2 [%lx]\n", state.words[0], state.words[1]);
+ DEBUG("Ea present [%x] : memload [%x]\n", state._ea_present, state._mem_load);
+ DEBUG("Load Length [%d]:\n", state._load_len);
+ DEBUG("Address Writeback [%d]\n", state._addrWriteBack);
+ DEBUG("EA reg1 is [%x] offset [%x]\n", state.ea_reg1, state._offset);
+ DEBUG("EA reg2 is [%x]\n", state.ea_reg2);
+ DEBUG("Instr buffer is %s\n", state.instrBuffer);
+ DEBUG("Operand buffer is %s\n", state.operandBuffer);
+ DEBUG("SourceType is %s\n", ARC_Debugger_OperandType_Image(state.sourceType));
+ DEBUG("Source operand is %u\n", state.source_operand.registerNum); /* All fields of the union have same type. */
+ DEBUG("Flow is %d\n", state.flow);
+ DEBUG("Branch is %d\n", state.isBranch);
+ DEBUG("---------------------------------\n");
}
-/*Function to scan the prologue of a A4 binary
-
-ARCtangent-A4 Prolog
- The stack back-trace data structure is a 16-byte structure which is
- used to save the return register (blink, 4 bytes), the frame pointer
- register (fp, 4-bytes) and 8-bytes is reserved.
-
- The compiler-generated prolog code does the following:
- --> Allocates space for register arguments in case of variadic function
- (functions with variable argument lists)
- --> Saves the return address register (blink)
- --> Saves the caller's frame pointer (fp), if required, and
- sets the new frame pointer to this location
- --> Decrements the stack pointer to account for the new stack frame
- --> Saves required non-volatile general-purpose registers into the
- register save area
- --> Stores the arguments above the stack back-trace data structure
-
-
- Demo Patterns:
- st blink,[sp,4] ; Saves the return address
- st fp,[sp] ; Saves the callers frame pointer
- mov fp,sp ; Saves
- sub sp,sp,24
-
-0xa 538e7e20 sub sp,sp,32 ; Space for variadic args
-0x2 100e3e04 st blink,[sp,4] ; Saves the return address
-0x2 100e3600 st fp,[sp] ; Saves the callers frame pointer
-0xc 636e3800 mov fp,sp ; Resets stack pointer to fp
-0xa 538e7e18 sub sp,sp,24 ; Decrements sp to add for new
- ; stack frame
-0x2 100d81fc st r0,[fp,-4] ; Stores the args
-0x2 100d83f8 st r1,[fp,-8] ; ----"-------
- ...
-*/
+/* -------------------------------------------------------------------------- */
+/* local functions for the disassembler */
+/* -------------------------------------------------------------------------- */
-/* FIXMEA:
-called from arc_skip_prologue as
- skip_pc = arc_scan_prologue(pc,NULL,NULL);
- Then it is supposed to return the first valid pc
- after the prologue
+/* Wrapper for the target_read_memory function. */
- Prologue analysis does the rest...
- Currently our scan prologue does not
- support getting input for the frame unwinder
+static int
+read_memory_for_disassembler (bfd_vma memaddr,
+ bfd_byte *myaddr,
+ unsigned int length,
+ struct disassemble_info *info) // unused
+{
+ return target_read_memory((CORE_ADDR) memaddr, (gdb_byte*) myaddr, (int) length);
+}
-
- pc = frame_func_unwind(next_frame);
- arc_scan_prologue (pc, next_frame, info);
-*/
+/* This is a callback function which gets called by gdb whenever the current
+ object file changes. */
-#ifdef ARC4_JTAG
-static CORE_ADDR
-a4_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame,
- struct arc_unwind_cache *info)
+static void
+set_disassembler (struct objfile *objfile)
{
- /* End of prologue */
- CORE_ADDR prologue_ends_pc = pc;
- int i = 0;
- struct arcDisState current_instr, instr_in_delay;
- int insn_length;
-
- /* Initializations to use the opcodes
- * library .
- */
-
- struct disassemble_info di;
-
- unsigned int saved_regs_mask = 0;
- /* An arbitrary length on the length of the
- prologue. If next_frame is NULL this means that there was
- no debug info and we are called from arc_skip_prologue
- */
- /*FIXMEANOW: pc + 64 is probably the max size of the prologue*/
- CORE_ADDR final_pc = (next_frame)?frame_pc_unwind(next_frame):pc+(16*4);
-
-
-
-
- if (info)
+ if (objfile)
{
- /* All functions start as leaf functions until
- we identify push blink
- */
- info->is_leaf = 1;
+ /* The ARC libopcodes wants obfd so that it can find out what CPU
+ extensions are defined in the file. */
+ set_gdbarch_print_insn(current_gdbarch, arcompact_get_disassembler(objfile->obfd));
+// dump_ARC_extmap();
}
-
-
-
- /* Initializations to use the opcodes
- * library .
- */
- init_disassemble_info(&di, gdb_stderr, fprintf_unfiltered);
- di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach;
- di.endian = gdbarch_byte_order(current_gdbarch);
- di.read_memory_func = target_read_memory;
-
-
- for (prologue_ends_pc= pc;
- prologue_ends_pc< final_pc;
- prologue_ends_pc += current_instr.instructionLen ) /*FIXMEA: This could as
- well be 4 */
+}
+
+
+/* This function is supplied to gdb as the disassembler until such time as we do
+ have a disassembler available. */
+
+static int
+dummy_disassembler (bfd_vma address, disassemble_info *info)
+{
+ error(_("No disassembly operation yet available (no executable file loaded)"));
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions for decoding call chains */
+/* -------------------------------------------------------------------------- */
+
+/* Simple utility function to create a new frame cache structure. */
+
+static UnwindCache*
+create_cache (struct frame_info *next_frame)
+{
+ UnwindCache *cache = FRAME_OBSTACK_ZALLOC (UnwindCache);
+
+ /* Zero all fields. */
+ cache->blink_save_offset_from_prev_sp = 0;
+ cache->prev_sp = 0;
+ cache->frame_base = 0;
+ cache->delta_sp = 0;
+ cache->old_sp_offset_from_fp = 0;
+ cache->is_leaf = FALSE;
+ cache->uses_fp = FALSE;
+
+ /* Allocate space for saved register info. */
+ cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
+
+ return cache;
+}
+
+
+/* Compute the previous frame's stack pointer (which is also the frame's ID's
+ stack address), and this frame's base pointer. */
+
+static void
+find_previous_stack_pointer (UnwindCache *info,
+ struct frame_info *next_frame)
+{
+ ENTERARGS("next_frame = %p", next_frame);
+
+ /* If the frame has a frame pointer. */
+ if (info->uses_fp)
{
- current_instr = a4AnalyzeInstr(prologue_ends_pc, &di);
- printInsnState(current_instr);
-#ifdef ARC_DEBUG
- printf("Prologue PC: %d\n", prologue_ends_pc);
- printf("Final PC: %d\n", final_pc);
-#endif
+ ULONGEST this_base;
+ unsigned int i;
+
+ /* The SP was moved to the FP. This indicates that a new frame
+ was created. Get THIS frame's FP value by unwinding it from
+ the next frame. The old contents of FP were saved in the location
+ at the base of this frame, so this also gives us the address of
+ the FP save location. */
+ this_base = frame_unwind_register_unsigned(next_frame, ARC_FP_REGNUM);
+ info->frame_base = (CORE_ADDR) this_base;
+ info->saved_regs[ARC_FP_REGNUM].addr = (long long) this_base;
+
+ /* The previous SP is the current frame base + the difference between
+ that frame base and the previous SP. */
+ info->prev_sp = info->frame_base + (CORE_ADDR) info->old_sp_offset_from_fp;
+
+ for (i = ARC_ABI_FIRST_CALLEE_SAVED_REGISTER; i < ARC_ABI_LAST_CALLEE_SAVED_REGISTER; i++)
+ {
+ /* If this register has been saved, add the previous stack pointer
+ to the offset from the previous stack pointer at which the
+ register was saved, so giving the address at which it was saved. */
+ if (info->saved_regs_mask & (1 << i))
+ {
+ info->saved_regs[i].addr += info->prev_sp;
+
+#ifdef DUMP_SAVED_REGISTERS
+ /* This is a really useful debugging aid: we can debug a test
+ program which loads known values into the callee-saved
+ registers, then calls another function which uses those
+ registers (and hence must save them) then hits a breakpoint;
+ traversing the stack chain (e.g. with the 'where' command)
+ should then execute this code, and we should see those known
+ values being dumped, so showing that we have got the right
+ addresses for the save locations! */
+ {
+ unsigned int contents;
+ DEBUG("saved R%02d is at 0x%lx\n", i, (long unsigned int) info->saved_regs[i].addr);
- if (current_instr._opcode == 0x2)
- {
- // Saves the return address st blink,[sp,4] 0x100e3e04
- // Save the callers fp st fp,[sp] 0x100e3600
- // Saves the args st rX,[fp, #imm] 0x100d8xxx
- if (current_instr.ea_reg1 == 28)
- {
- if( strstr(current_instr.operandBuffer,"blink") == current_instr.operandBuffer)
- {
- if(info)
- {
- info->sp_offset += current_instr._offset;
- // info->blink_offset = info->sp_offset ;
- info->blink_offset = current_instr._offset;
- info->is_leaf = 0;
-
-#ifdef ARC_DEBUG
- printf("Blink instruction:\n");
- printFrameInfo(info);
-#endif
- }
- continue;
- }
- else
- if(strstr(current_instr.operandBuffer,"fp") == current_instr.operandBuffer)
- {
- if(info)
- {
-/* info->sp_offset += current_instr._offset ; */
-/* info->fp_offset = info->sp_offset; */
- info->fp_offset = 0;
- }
- continue;
- }
- }
- else if (current_instr.ea_reg1 == 27)
- {
- /* Saving of arguments onto the stack using the
- frame pointer (r27). */
- if(info)
- {
- // Save regs offsets
- }
-#ifdef ARC_DEBUG
- printf(" Saving registers onto stack\n%s\n",current_instr.operandBuffer);
-#endif
- continue;
- }
- // ISPUSHBLINK(current_instr);
- }
- else if (current_instr._opcode == 0xc)
- {
- // Resets stack pointer to fp
- // 0x636e3800
- // 636e3800 mov fp,sp
- if (current_instr.words[0] == 0x636e3800)
- {
- if (info)
- {
- info->uses_fp = 1;
- }
- continue;
- }
- }
- else if (current_instr._opcode == 0xa)
- {
- // Decrements stackpointer to add for new stack frame
- // 0x538e7e18 sub sp,sp,#imm
- // 538e7e20 sub sp,sp,32
- if( current_instr.words[0] == 0x538e7e20)
- {
- //sub sp,sp, 32 //// variadic
- if (info)
- {
- int tmp = atoi(current_instr.operandBuffer + 6);
- info->sp_offset -= tmp;
- }
- continue;
- }
- else if((current_instr.words[0] & 0xffffff00) == 0x538e7e00)
- {
- // sub sp,sp,xx
- if(info)
- {
- int tmp = atoi(current_instr.operandBuffer + 6);
- info->sp_offset -= tmp;
- }
- continue;
- }
- }
-
- /* Found a instruction that is not in
- the prologue*/
-#ifdef ARC_DEBUG
- printf("End of Prologue reached \n");
+ if (target_read_memory((CORE_ADDR) info->saved_regs[i].addr,
+ (gdb_byte*) &contents,
+ BYTES_IN_REGISTER) == 0)
+ {
+ DEBUG("saved R%02d contents: 0x%0x\n", i, contents);
+ }
+ }
#endif
- break;
+ }
+ }
}
-
- /* Means we were called from skip_prologue */
- if((next_frame == NULL)&& (info == NULL))
+ else
{
- return prologue_ends_pc;
- }
+ ULONGEST this_sp;
+ /* Get the stack pointer for this frame by getting the saved SP
+ from the next frame. */
+ this_sp = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM);
- info->framesize = -info->sp_offset;
- /* Compute the previous frame's stack pointer (which is also the
- frame's ID's stack address), and this frame's base pointer. */
- if(info->uses_fp)
- {
+ /* The previous SP is this frame's SP plus the known difference between
+ the previous SP and this frame's SP (the delta_sp is negated as it is
+ a negative quantity). */
+ info->prev_sp = (CORE_ADDR) (this_sp + (ULONGEST) (-info->delta_sp));
- ULONGEST this_base;
- /* The SP was moved to the FP. This indicates that a new frame
- was created. Get THIS frame's FP value by unwinding it from
- the next frame. */
- frame_unwind_unsigned_register(next_frame, ARC_FP_REGNUM,
- &this_base);
- info->frame_base = this_base;
- info->saved_regs[ARC_FP_REGNUM].addr = info->frame_base;
-
- /* The previous sp is the current frame base + the offset of the
- fp in the current frame */
- info->prev_sp = info->frame_base + info->fp_offset;
- for(i = 13; i < 26 ; i++ )
- {
- if(saved_regs_mask & (1 << i))
- info->saved_regs[i].addr += info->frame_base ;
- }
-
- printFrameInfo(info);
-
+ /* Assume that the FP is this frame's SP. */
+ info->frame_base = (CORE_ADDR) this_sp;
}
- else
+
+ /* If the function owning this frame is not a leaf function. */
+ if (!info->is_leaf)
{
- ULONGEST this_base;
- /* Assume that the FP is this frame's SP but with that pushed
- stack space added back. */
- frame_unwind_unsigned_register (next_frame, ARC_SP_REGNUM, &this_base);
- info->frame_base = this_base;
-
- /* In such a case it would be the previous SP + the size of the current frame */
- info->prev_sp = info->frame_base + info->framesize;
-
+ /* Usually blink is saved above the callee save registers and below the
+ space created for variable arguments. The quantity
+
+ info->blink_save_offset_from_prev_sp
+
+ is negative, so adding it to the the previous SP gives the address of
+ a location further down the stack from that SP. */
+ info->saved_regs[ARC_BLINK_REGNUM].addr =
+ (LONGEST) (info->prev_sp + info->blink_save_offset_from_prev_sp);
}
-
+}
+
- if(!info->is_leaf)
+/* The workhorse : frame_unwind_cache for the ARC700 target. */
+
+static UnwindCache *
+frame_unwind_cache (struct frame_info *next_frame,
+ void **this_prologue_cache)
+{
+ ENTERMSG;
+
+ if ((*this_prologue_cache) == NULL)
{
+ CORE_ADDR entrypoint = frame_func_unwind(next_frame, NORMAL_FRAME);
+ UnwindCache *cache = create_cache(next_frame);
- /* Usually blink is saved before the callee save registers and
- below the space created for variadic arguments . We maintain
- info->blink_offset as negative when we stored it initially
- */
- info->saved_regs[ARC_BLINK_REGNUM].addr = info->prev_sp + info->blink_offset;
-#ifdef ARC_DEBUG
- printf("blink offset is [%x] \n",info->blink_offset);
-#endif
+ /* Return the newly-created cache. */
+ *this_prologue_cache = cache;
+
+ /* Prologue analysis does the rest... */
+
+ /* Currently our scan prologue does not support getting input for the
+ frame unwinder. */
+ (void) scan_prologue(entrypoint, next_frame, cache);
}
-
- /* The PC is found in blink (the actual register or located on the stack). */
- // FIXMEA:
- //info->saved_regs[ARC_STATUS_REGNUM] |= (info->saved_regs[ARC_BLINK_REGNUM] & 0xffffff)>>2;
- info->saved_regs[ARC_STATUS_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];
- return prologue_ends_pc;
+ return *this_prologue_cache;
}
-#endif
-static CORE_ADDR
-arc_scan_prologue (CORE_ADDR pc, struct frame_info *next_frame,
- struct arc_unwind_cache *info)
+
+/* -------------------------------------------------------------------------- */
+/* local functions for decoding function prologues */
+/* -------------------------------------------------------------------------- */
+
+/* This function determines whether the given register, which is being saved
+ by a function prologue on the stack at a known offset from the current SP,
+ is a callee-saved register. If it is, the information in the frame unwind
+ cache is updated. */
+
+static Boolean
+is_callee_saved_register (unsigned int reg,
+ int offset,
+ UnwindCache * info)
{
-#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf("\narc_scan_prologue called\n");
-#endif
-#else
- /* End of prologue */
- CORE_ADDR prologue_ends_pc = pc;
- int i = 0;
- struct arcDisState current_instr, instr_in_delay;
- int insn_length;
-
- /* Initializations to use the opcodes
- * library .
- */
-
- struct disassemble_info di;
-
- unsigned int saved_regs_mask = 0;
- /* An arbitrary length on the length of the
- prologue. If next_frame is NULL this means that there was
- no debug info and we are called from arc_skip_prologue
- */
- CORE_ADDR final_pc = (next_frame)?frame_pc_unwind(next_frame):pc+64;
-
-
-
-
- if (info)
- {
- /* All functions start as leaf functions until
- we identify push blink
- */
- info->is_leaf = 1;
-
- }
-
-
-
- /* Initializations to use the opcodes
- * library .
- */
- init_disassemble_info(&di, gdb_stderr, fprintf_unfiltered);
- di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach;
- di.endian = gdbarch_byte_order(current_gdbarch);
- di.read_memory_func = target_read_memory;
-
-
- for(prologue_ends_pc= pc; prologue_ends_pc< final_pc;
- prologue_ends_pc += current_instr.instructionLen )
+ if (ARC_ABI_FIRST_CALLEE_SAVED_REGISTER <= reg && reg <= ARC_ABI_LAST_CALLEE_SAVED_REGISTER)
{
- current_instr = arcAnalyzeInstr(prologue_ends_pc, &di);
- printInsnState(current_instr);
- /* Might be a push or a pop */
- if(current_instr._opcode == 0x3)
- {
- if(current_instr._addrWriteBack)
- {
- /* This is a st.a */
- if((current_instr.ea_reg1 == 28) &&
- (current_instr._offset == -4))
- {
-
- /* This is a push something at sp */
- /* Is it a push of the blink */
- ISPUSHBLINKFI(current_instr);
- /* Is it a push for fp */
- ISPUSHFPFI(current_instr);
-
- }
-
- }
- else
- {
- /* Is this a store of some register onto
- the stack using the stack pointer.*/
- if(current_instr.ea_reg1 == 28)
- {
- if(current_instr.sourceType == ARC_REGISTER )
- {
- /* R13..R26 are the callee saved registers. [R27 (fp)
- is also a callee saved register, but it's usually
- pushed using st.a and so handled in the st.a case
- above.] */
- if((current_instr.source_operand.registerNum > 12
- && current_instr.source_operand.registerNum <= 26))
- {
- if(info)
- {
- printFrameInfo(info);
- /* Save up the offsets for the correct instruction */
- info->saved_regs[current_instr.source_operand.registerNum].addr
- = - info->sp_offset - current_instr._offset;
- saved_regs_mask |= (1 << current_instr.source_operand.registerNum);
- }
- continue;
- }
-
- }
-
- }
- /* Is this the store of some register on the
- stack using the frame pointer. We check
- for argument registers getting saved and
- restored.
- */
- if(current_instr.ea_reg1 == 27)
- if((current_instr.source_operand.registerNum <= 7))
- {
- /* Saving argument registers.Don't save them in saved_regs, just skip.
- */
- continue;
- }
-
-
-
- }
- }
-
- if(current_instr._opcode == 0x4)
- {
- /* A major opcode 0x4 instruction */
- /* We are usually interested in a
- mov or a sub */
- ISUPDATEFPFI(current_instr);
- ISSUBSPFI(current_instr);
- }
- if(current_instr._opcode == 0x18)
- {
- /* sub_s sp,sp,constant */
- ISSUBSPFI(current_instr);
- /* push_s blink */
- if(strcmp(current_instr.instrBuffer,"push_s") == 0)
- {
- if(strcmp(current_instr.operandBuffer,"blink") == 0)
- {
- if(info)
- {
- info->sp_offset += 4;
- info->blink_offset = info->sp_offset ;
- info->is_leaf = 0;
- }
- continue;
- }
- }
- }
-
- /* If we reach here . we have
- * reached end of the prologue
- */
- break;
-
- }
-
- /* Means we were called from skip_prologue */
- if((next_frame == NULL)&& (info == NULL))
- {
- return prologue_ends_pc;
+ DEBUG("register R%02u saved\n", reg);
+
+ if (info)
+ {
+ /* We can not determine the address of the location in the stack
+ frame in which the register was saved, as we do not (yet) know
+ the frame or stack pointers for the frame; so the most we can do
+ is to record the offset from the old SP of that location, which
+ we can compute as we know the offset of SP from the old SP, and
+ the offset of the location from SP (which is the offset in the
+ store instruction).
+
+ N.B. the stack grows downward, so the store offset is positive,
+ but the delta-SP is negative, so the save offset is also
+ negative.
+
+ | |
+ old sp ------> |------------|
+ / | | \
+ : | | :
+ : | | : -ve
+ : | | : save offset
+ : |------------| :
+ -ve : | save loc | /
+ delta sp : |------------| <--- store address
+ : / | |
+ : +ve : | |
+ : store : | |
+ : offset : | |
+ \ \ | |
+ sp' ---------> | |
+ | |
+ | |
+ |------------| <---- frame base
+ | |
+ | |
+ | |
+ | | |
+ |
+ V
+ downwards
+
+ where sp' is the stack pointer at the current point in the code */
+
+ info->saved_regs[reg].addr = info->delta_sp + offset;
+
+ /* We now know that this register has been saved, so set the
+ corresponding bit in the save mask. */
+ info->saved_regs_mask |= (1 << reg);
+
+ printFrameInfo("after callee register save", info, FALSE);
+
+ return TRUE;
+ }
}
-
-
- info->framesize = -info->sp_offset;
- /* Compute the previous frame's stack pointer (which is also the
- frame's ID's stack address), and this frame's base pointer. */
- if(info->uses_fp)
+
+ return FALSE;
+}
+
+
+/* This function determines whether the given disassembled instruction may be
+ part of a function prologue. If it is, the information in the frame unwind
+ cache may be updated. */
+
+static Boolean
+is_in_prologue (UnwindCache *info, struct arcDisState *instr)
+{
+ /* Might be a push or a pop */
+ if (instr->_opcode == 0x3)
{
+ if (instr->_addrWriteBack != (char) 0)
+ {
+ /* This is a st.a instruction. */
+ if (instr->ea_reg1 == ARC_ABI_STACK_POINTER)
+ {
+ if (instr->_offset == -4)
+ {
+ /* This is a push something at SP. */
+ /* Is it a push of the blink? */
+ IS_PUSH_BLINK_FI(instr);
+
+ /* Is it a push for fp? */
+ IS_PUSH_FP_FI(instr);
+ }
+ else
+ {
+ if (instr->sourceType == ARC_REGISTER )
+ {
+ /* st.a <reg>, [sp,<offset>] */
+
+ if (is_callee_saved_register(instr->source_operand.registerNum,
+ instr->_offset,
+ info))
+ {
+ /* This is a push onto the stack, so change delta_sp. */
+ info->delta_sp += instr->_offset;
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (instr->sourceType == ARC_REGISTER )
+ {
+ /* Is this a store of some register onto the stack using the
+ stack pointer? */
+ if (instr->ea_reg1 == ARC_ABI_STACK_POINTER)
+ {
+ /* st <reg>, [sp,offset] */
+
+ if (is_callee_saved_register(instr->source_operand.registerNum,
+ instr->_offset,
+ info))
+ /* This is NOT a push onto the stack, so do not change delta_sp. */
+ return TRUE;
+ }
- ULONGEST this_base;
- /* The SP was moved to the FP. This indicates that a new frame
- was created. Get THIS frame's FP value by unwinding it from
- the next frame. */
- frame_unwind_unsigned_register(next_frame, ARC_FP_REGNUM,
- &this_base);
- info->frame_base = this_base;
- info->saved_regs[ARC_FP_REGNUM].addr = info->frame_base;
-
- /* The previous sp is the current frame base + the offset of the
- fp in the current frame */
- info->prev_sp = info->frame_base + info->fp_offset;
- for(i = 13; i < 26 ; i++ )
- {
- if(saved_regs_mask & (1 << i))
- info->saved_regs[i].addr += info->frame_base ;
- }
-
- printFrameInfo(info);
-
+ /* Is this the store of some register on the stack using the
+ frame pointer? We check for argument registers getting saved
+ and restored. */
+ if (instr->ea_reg1 == ARC_ABI_FRAME_POINTER)
+ {
+ if (IS_ARGUMENT_REGISTER(instr->source_operand.registerNum))
+ {
+ /* Saving argument registers. Don't set the bits in the
+ saved mask, just skip. */
+ return TRUE;
+ }
+ }
+ }
+ }
}
- else
+
+ else if (instr->_opcode == 0x4)
{
- ULONGEST this_base;
- /* Assume that the FP is this frame's SP but with that pushed
- stack space added back. */
- frame_unwind_unsigned_register (next_frame, ARC_SP_REGNUM, &this_base);
- info->frame_base = this_base;
-
- /* In such a case it would be the previous SP + the size of the current frame */
- info->prev_sp = info->frame_base + info->framesize;
-
+ /* A major opcode 0x4 instruction. */
+ /* We are usually interested in a mov or a sub. */
+ IS_UPDATE_FP_FI(instr);
+ IS_SUB_SP_FI(instr);
}
-
- if(!info->is_leaf)
+ else if (instr->_opcode == 0x18)
{
+ /* sub_s sp,sp,constant */
+ IS_SUB_SP_FI(instr);
- /* Usually blink is saved before the callee save registers and
- below the space created for variadic arguments . We maintain
- info->blink_offset as negative when we stored it initially
- */
- info->saved_regs[ARC_BLINK_REGNUM].addr = info->prev_sp + info->blink_offset;
-#ifdef ARC_DEBUG
- printf("blink offset is [%x] \n",info->blink_offset);
-#endif
+ /* push_s blink */
+ if (strcmp(instr->instrBuffer, "push_s") == 0)
+ {
+ if (strcmp(instr->operandBuffer, "blink") == 0)
+ {
+ if (info)
+ {
+ /* SP is decremented by the push_s instruction (before it
+ stores blink at the stack location addressed by SP). */
+ PUSH_BLINK(-BYTES_IN_REGISTER)
+ }
+ return TRUE;
+ }
+ }
+ else if (strcmp(instr->instrBuffer, "st_s") == 0)
+ {
+ unsigned int reg;
+ int offset;
+
+ if (sscanf(instr->operandBuffer, "r%u,[sp,%d]", &reg, &offset) == 2)
+ {
+ /* st_s <reg>,[sp,<offset>] */
+
+ if (is_callee_saved_register(reg, offset, info))
+ /* This is NOT a push onto the stack, so do not change delta_sp. */
+ return TRUE;
+ }
+ }
}
-
- /* The PC is found in blink (the actual register or located on the stack). */
- info->saved_regs[PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];
- /*info->saved_regs[ARC_PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];*/
- return prologue_ends_pc;
-#endif
+
+ return FALSE;
}
-/* Skip the prologue for the function at pc.
- * This is done by checking from the line
- * information picked up during dwarf reading
- * FIXME: more stuff to be added when we
- * parse the prologue.
- */
+/* Scan the prologue and update the corresponding frame cache for the frame
+ unwinder for unwinding frames without debug info. In such a situation GDB
+ attempts to parse the prologue for this purpose. This currently would attempt
+ to parse the prologue generated by our gcc 2.95 compiler (we should support
+ Metaware generated binaries at some suitable point of time).
+
+ This function is called with:
+ entrypoint : the address of the functon entry point
+ next_frame : the next frame to be filled in (if need be)
+ info : the existing cached info.
+
+ Returns: the address of the first instruction after the prologue.
+
+ This function is called by our unwinder as well as from arc_skip_prologue
+ in the case that it cannot detect the end of the prologue.
+
+ 'next_frame' and 'info' are NULL if this function is called from
+ arc_skip_prologue in an attempt to discover the end of the prologue.
+ In this case we don't fill in the 'info' structure that is passed in.
+
+ TODOs:
+ 1. Support 32 bit normal frames generated by GCC 2.95
+ 2. Support 16 and 32 bit mixed frames generated by GCC 2.95
+ 3. Support 32 bit normal variadic function frames by GCC 2.95
+ 4. Support 32 bit normal frames from GCC 3.4.x with variadic args
+ 5. Support 16 and 32 bit normal frames from GCC 3.4.x with variadic args
+ 6. Support 16 and 32 bit mixed frames generated by GCC 3.4.x
+ 7. Support Metaware generated prologues
+ (The difference is in the use of thunks to identify the saving and
+ restoring of callee saves: may have to do some hackery even in
+ next_pc, since the call is going to create its own set of problems
+ with our stack setup).
+
+ We attempt to use the disassembler interface from the opcodes library to do
+ our disassembling.
+
+ The usual 32 bit normal gcc -O0 prologue looks like this:
+
+ Complete Prologue for all GCC frames (Cases #1 to #6 in TODOs above):
+
+ sub sp, sp, limm ; space for variadic arguments
+ st.a blink, [sp,-4] ; push blink (if not a leaf function) - decrements sp
+ sub sp, sp , limm ; (optional space creation for callee saves)
+ st r13, [sp] ; push of first callee saved register
+ st r14, [sp,4] ; push of next callee saved register
+ ...
+ st.a fp , [sp,-4] ; push fp (if fp has to be saved) - decrements sp
+ mov fp , sp ; set the current frame up correctly
+ sub sp , sp , #immediate ; create space for local vars on the stack */
+
+/* 3 instructions before and after callee saves, and max number of saves; assume each is 4-byte inst. */
+#define MAX_PROLOGUE_LENGTH ((6 + (ARC_ABI_LAST_CALLEE_SAVED_REGISTER - ARC_ABI_FIRST_CALLEE_SAVED_REGISTER + 1)) * 4)
static CORE_ADDR
-arc_skip_prologue (CORE_ADDR pc)
+scan_prologue (CORE_ADDR entrypoint,
+ struct frame_info *next_frame,
+ UnwindCache *info)
{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_skip_prologue called\n");
-#endif
- // FIXMEA: cleanup #else
- unsigned long inst;
- unsigned long addend = 4;
- CORE_ADDR skip_pc = pc;
- CORE_ADDR func_addr, func_end = 0;
- char *func_name;
- struct symtab_and_line sal;
+ ENTERARGS("next_frame = %p, info = %p", next_frame, info);
- /* If we're in a dummy frame, don't even try to skip the prologue. */
- if (deprecated_pc_in_call_dummy (pc))
- return pc;
+ {
+ /* Will be set to end of prologue. */
+ CORE_ADDR prologue_ends_pc = entrypoint;
+ struct disassemble_info di;
+
+ /* An arbitrary limit on the length of the prologue. If next_frame is
+ NULL this means that there was no debug info and we are called from
+ arc_skip_prologue; otherwise, if we know the frame, we can find the
+ pc within the function.
+
+ N.B. that pc will usually be after the end of the prologue, but
+ it could actually be within the prologue (i.e. execution has
+ halted within the prologue, e.g. at a breakpoint); in that
+ case, do NOT go beyond that pc, as the instructions at the
+ pc and after have not been executed yet, so have had no effect! */
+ CORE_ADDR final_pc = (next_frame) ? frame_pc_unwind(next_frame)
+ : entrypoint + MAX_PROLOGUE_LENGTH;
+
+ if (info)
+ {
+ /* Assume that the function is a leaf function until we find out
+ that it is not (i.e. when we find the 'push blink' instruction
+ in the prologue). */
+ info->is_leaf = TRUE;
- /* See what the symbol table says. */
+ /* No registers known to be saved, as yet. */
+ info->saved_regs_mask = 0;
+ }
- if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end))
- {
- struct symbol *sym;
+ /* Initializations to use the opcodes library. */
+ arc_initialize_disassembler(&di);
+
+ DEBUG("Prologue PC: %lx\n", (unsigned long) prologue_ends_pc);
+ DEBUG("Final PC: %lx\n", (unsigned long) final_pc);
- /* Found a function. */
- sym = lookup_symbol (func_name, NULL, VAR_DOMAIN, NULL, NULL);
- if (sym && SYMBOL_LANGUAGE (sym) != language_asm)
+ /* Look at each instruction in the prologue. */
+ while (prologue_ends_pc < final_pc)
{
- /* Don't use this trick for assembly source files. */
- sal = find_pc_line (func_addr, 0);
- if ((sal.line != 0) && (sal.end < func_end))
- return sal.end;
+ struct arcDisState current_instr = arcAnalyzeInstr(prologue_ends_pc, &di);
+
+ printInsnState(current_instr);
+
+ /* If this instruction is in the prologue, fields in the info will be updated,
+ and the saved registers mask may be updated. */
+ if (!is_in_prologue(info, &current_instr))
+ {
+ /* Found a instruction that is not in the prologue. */
+ DEBUG("End of Prologue reached \n");
+ break;
+ }
+
+ prologue_ends_pc += current_instr.instructionLen;
}
- }
-
-#ifdef ARC4_JTAG
- skip_pc = a4_scan_prologue(pc, NULL, NULL);
-#else
- skip_pc = arc_scan_prologue(pc,NULL,NULL);
-#endif
- return skip_pc; /* End of prologue */
- //#endif
-}
+ /* Means we were not called from arc_skip_prologue. */
+ if (!((next_frame == NULL) && (info == NULL)))
+ {
+ printFrameInfo("after prologue", info, FALSE);
-/* Breakpoint from pc. Return whatever is in the tdep
- * structure. The tdep structure is changed depending
- * on the correct target / architecture chosen.
- */
+ find_previous_stack_pointer(info, next_frame);
-static const unsigned char *
-arc_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
-{
+ /* The PC is found in blink (the actual register or located on the stack). */
+ info->saved_regs[ARC_PC_REGNUM] = info->saved_regs[ARC_BLINK_REGNUM];
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- *lenptr = tdep->arc_breakpoint_size;
- return tdep->arc_breakpoint_insn;
+ printFrameInfo("after previous SP found", info, TRUE);
+ }
+
+ return prologue_ends_pc;
+ }
}
-/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
- dummy frame. The frame ID's base needs to match the TOS value
- saved by save_dummy_frame_tos(), and the PC match the dummy frame's
- breakpoint. */
+/* -------------------------------------------------------------------------- */
+/* local functions for handling function return values */
+/* -------------------------------------------------------------------------- */
-static struct frame_id
-arc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
-{
- return frame_id_build (arc_unwind_sp (gdbarch, next_frame),
- frame_pc_unwind (next_frame));
-}
+/* This function gets the return value of a function from the registers used to
+ return it, according to the convention used by the ABI.
+
+ Parameters:
+ type : the information for the return type of the function
+ regcache : the register cache holding the register contents
+ valbuf : a buffer to be filled with the return value
+*/
+
+static void
+extract_return_value (struct type *type,
+ struct regcache *regcache,
+ gdb_byte *valbuf)
-/* The workhorse : frame_unwind_cache for the ARC700 platform .
- */
-static struct arc_unwind_cache *
-arc_frame_unwind_cache (struct frame_info *next_frame,
- void **this_prologue_cache)
{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_frame_unwind_cache called\n ");
-#endif
- //#else
- CORE_ADDR pc;
- struct arc_unwind_cache *info;
- int i;
-
-
- if ((*this_prologue_cache))
- return (*this_prologue_cache);
-
- info = FRAME_OBSTACK_ZALLOC (struct arc_unwind_cache);
- (*this_prologue_cache) = info;
- info->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-
- /* Zero all fields. */
- info->blink_offset = 0;
- info->prev_pc = 0;
- info->prev_sp = 0;
- info->frame_base = 0;
- info->framesize = 0;
- info->sp_offset = 0;
- info->fp_offset = 0;
- info->prev_pc = 0;
- info->is_leaf = 0;
- info->uses_fp = 0;
-
- /* Prologue analysis does the rest... */
- /* Currently our scan prologue does not
- * support getting input for the frame unwinder
- */
-
- pc = frame_func_unwind(next_frame);
-#ifdef ARC4_JTAG
- a4_scan_prologue (pc, next_frame, info);
-#else
- arc_scan_prologue (pc, next_frame, info);
-#endif
+ unsigned int len = TYPE_LENGTH (type);
+
+ ENTERMSG;
+
+ if (len <= BYTES_IN_REGISTER)
+ {
+ ULONGEST val;
+
+ /* Get the return value from one register. */
+ regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_REGNUM, &val);
+ store_unsigned_integer (valbuf, (int) len, val);
+
+ DEBUG("returning 0x%08lX\n", (unsigned long) val);
+ }
+ else if (len <= BYTES_IN_REGISTER * 2)
+ {
+ ULONGEST low, high;
+
+ /* Get the return value from two registers. */
+ regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM, &low);
+ regcache_cooked_read_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, &high);
- return info;
- //#endif
+ store_unsigned_integer (valbuf, BYTES_IN_REGISTER, low);
+ store_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER, high);
+
+ DEBUG("returning 0x%08lX%08lX\n",
+ (unsigned long) high, (unsigned long) low);
+ }
+ else
+ error(_("%s: type length %u too large"), __FUNCTION__, len);
}
+/* This function loads the return value of a function into the registers used to
+ return it, according to the convention used by the ABI.
-/*
- * Construct frame id for the normal frame
- */
+ Parameters:
+ type : the information for the return type of the function
+ regcache : the register cache holding the register contents
+ valbuf : a buffer holding the return value
+*/
static void
-arc_frame_this_id (struct frame_info *next_frame,
- void **this_prologue_cache,
- struct frame_id *this_id)
+store_return_value (struct type *type,
+ struct regcache *regcache,
+ const gdb_byte *valbuf)
{
- // FIXMEA: cleanup #ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\n arc_frame_this_id called()\n ");
-#endif
- //#else
+ unsigned int len = TYPE_LENGTH (type);
+
+ ENTERMSG;
- struct arc_unwind_cache *info
- = arc_frame_unwind_cache (next_frame, this_prologue_cache);
- CORE_ADDR base;
- CORE_ADDR func;
- struct frame_id id;
+ if (len <= BYTES_IN_REGISTER)
+ {
+ ULONGEST val;
- /* The FUNC is easy. */
- func = frame_func_unwind (next_frame);
+ /* Put the return value into one register. */
+ val = extract_unsigned_integer (valbuf, (int) len);
+ regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_REGNUM, val);
- /* This is meant to halt the backtrace at the entry point (_start). */
- if (func <= gdbarch_tdep (current_gdbarch)->lowest_pc)
- return;
-
- /* Hopefully the prologue analysis either correctly determined the
- frame's base (which is the SP from the previous frame), or set
- that base to "NULL". */
- base = info->prev_sp;
- if (base == 0)
- return;
+ DEBUG("storing 0x%08lX\n", (unsigned long) val);
+ }
+ else if (len <= BYTES_IN_REGISTER * 2)
+ {
+ ULONGEST low, high;
- id = frame_id_build (base, func);
+ /* Put the return value into two registers. */
+ low = extract_unsigned_integer (valbuf, BYTES_IN_REGISTER);
+ high = extract_unsigned_integer (valbuf + BYTES_IN_REGISTER, (int) len - BYTES_IN_REGISTER);
- (*this_id) = id;
- //#endif
+ regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_LOW_REGNUM, low);
+ regcache_cooked_write_unsigned (regcache, ARC_ABI_RETURN_HIGH_REGNUM, high);
+ DEBUG("storing 0x%08lX%08lX\n",
+ (unsigned long) high, (unsigned long) low);
+ }
+ else
+ error(_("arc_store_return_value: type length too large."));
}
-/*
- * Unwind and obtain the register information
- */
-static void
-arc_frame_prev_register (struct frame_info *next_frame,
- void **this_prologue_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *bufferp)
+/* -------------------------------------------------------------------------- */
+/* local functions for handling the stack frame */
+/* -------------------------------------------------------------------------- */
+
+/* This is copied from file stack.c in the gdb sources.
+ It identifies a frame from information (such as frame number) given by the
+ user (in the frame_exp parameter). */
+
+static struct frame_info*
+parse_frame_specification_1 (const char *frame_exp,
+ const char *message,
+ int *selected_frame_p)
{
- // FIXMEA:
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\n arc_frame_prev_register() called for regnum %d\n ",regnum );
-#endif
- //#else
- struct arc_unwind_cache *info
- = arc_frame_unwind_cache (next_frame, this_prologue_cache);
+ int numargs = 0;
+ struct value *args[4];
+ CORE_ADDR addrs[ARRAY_SIZE (args)];
+ if (frame_exp)
+ {
+ while (TRUE)
+ {
+ char *addr_string;
+ struct cleanup *cleanup;
+ const char *p;
- /* If we are asked to unwind the PC, then we need to return blink
- instead. The saved value of PC points into this frame's
- prologue, not the next frame's resume location. */
-#ifdef ARC4_JTAG
- if (regnum == ARC_STATUS_REGNUM)
-#else
- if (regnum == PC_REGNUM)
-#endif
- regnum = ARC_BLINK_REGNUM;
+ /* Skip leading white space. */
+ while (isspace (*frame_exp))
+ frame_exp++;
+
+ if (*frame_exp == '\0')
+ break;
+
+ /* Parse the argument, extract it, save it. */
+ for (p = frame_exp; (*p != '\0') && !isspace (*p); p++);
+
+ addr_string = savestring (frame_exp, (size_t) (p - frame_exp));
+ frame_exp = p;
+ cleanup = make_cleanup (xfree, addr_string);
+
+ /* NOTE: Parse and evaluate expression, but do not use
+ functions such as parse_and_eval_long or
+ parse_and_eval_address to also extract the value.
+ Instead value_as_long and value_as_address are used.
+ This avoids problems with expressions that contain
+ side-effects. */
+ if (numargs >= (int) ARRAY_SIZE (args))
+ error (_("Too many args in frame specification"));
+
+ args[numargs++] = parse_and_eval (addr_string);
+
+ do_cleanups (cleanup);
+ }
+ }
- /* SP is generally not saved to the stack, but this frame is
- identified by NEXT_FRAME's stack pointer at the time of the call.
- The value was already reconstructed into PREV_SP. */
- if (regnum == ARC_SP_REGNUM)
+ /* If no args, default to the selected frame. */
+ if (numargs == 0)
{
- *lvalp = not_lval;
- if (bufferp)
- store_unsigned_integer (bufferp, 4, info->prev_sp);
- return;
+ if (selected_frame_p != NULL)
+ (*selected_frame_p) = 1;
+ return get_selected_frame (message);
}
+ /* None of the remaining use the selected frame. */
+ if (selected_frame_p != NULL)
+ (*selected_frame_p) = 0;
- trad_frame_get_prev_register (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, bufferp);
+ /* Assume the single arg[0] is an integer, and try using that to
+ select a frame relative to current. */
+ if (numargs == 1)
+ {
+ int level = (int) value_as_long (args[0]);
+ struct frame_info *fid = find_relative_frame (get_current_frame (), &level);
+ if (level == 0)
+ /* find_relative_frame was successful. */
+ return fid;
+ }
-#ifdef ARC_DEBUG
- printf("-*-*-*\n Regnum =%d, realnump=%d,%d \n",regnum, (char *)(bufferp), *((char*)bufferp));
-#endif
- //#endif
+ /* Convert each value into a corresponding address. */
+ {
+ int i;
+ for (i = 0; i < numargs; i++)
+ addrs[i] = value_as_address (args[i]);
+ }
+
+ /* Assume that the single arg[0] is an address, use that to identify
+ a frame with a matching ID. Should this also accept stack/pc or
+ stack/pc/special. */
+ if (numargs == 1)
+ {
+ struct frame_id id = frame_id_build_wild (addrs[0]);
+ struct frame_info *fid;
+
+ /* If (s)he specifies the frame with an address, he deserves
+ what (s)he gets. Still, give the highest one that matches.
+ (NOTE: cagney/2004-10-29: Why highest, or outer-most, I don't
+ know). */
+ for (fid = get_current_frame ();
+ fid != NULL;
+ fid = get_prev_frame (fid))
+ {
+ if (frame_id_eq (id, get_frame_id (fid)))
+ {
+ while (frame_id_eq (id, frame_unwind_id (fid)))
+ fid = get_prev_frame (fid);
+ return fid;
+ }
+ }
+ }
+
+ /* We couldn't identify the frame as an existing frame, but
+ perhaps we can create one with a single argument. */
+ if (numargs == 1)
+ return create_new_frame (addrs[0], 0);
+ else if (numargs == 2)
+ return create_new_frame (addrs[0], addrs[1]);
+ else
+ error (_("Too many args in frame specification"));
}
+/* Return an array (and count) of the local variables and parameters declared
+ in the function which owns the given frame.
+ Parameters:
+ frame : the frame information for the function
+ variables: a pointer to an existing array of variable information (may be NULL)
+ count : (IN/OUT) the total number of variables found
+ callee : TRUE if the function is a callee of another function
-static const struct frame_unwind arc_frame_unwind = {
- NORMAL_FRAME,
- arc_frame_this_id,
- arc_frame_prev_register
-};
+ Result:
+ A pointer to an array containing one element for each parameter, and, if
+ 'callee' is FALSE, each local variable, of the function. */
-const struct frame_unwind *
-arc_frame_sniffer (struct frame_info *next_frame)
+static LocalVariable*
+find_variables (struct frame_info *frame,
+ LocalVariable *variables,
+ unsigned int *count,
+ Boolean callee)
{
- return &arc_frame_unwind;
+ struct block *block = get_frame_block (frame, 0);
+ unsigned int vars = *count;
+
+ while (block)
+ {
+ struct dict_iterator iter;
+ struct symbol *sym;
+
+ ALL_BLOCK_SYMBOLS (block, iter, sym)
+ {
+ Boolean is_arg = (SYMBOL_CLASS(sym) == LOC_COMPUTED_ARG);
+ CORE_ADDR addr;
+
+ switch (SYMBOL_CLASS (sym))
+ {
+ case LOC_COMPUTED:
+ case LOC_COMPUTED_ARG:
+ addr = SYMBOL_OPS (sym)->get_variable_address(sym, frame);
+
+ /* For callees, we are only interested in the arguments. */
+ if ((addr != 0) && (!callee || is_arg))
+ {
+ struct type *type = SYMBOL_TYPE (sym);
+
+ vars++;
+ variables = xrealloc(variables, sizeof(LocalVariable) * vars);
+
+ if (variables)
+ {
+ LocalVariable *var = &variables[vars - 1];
+
+ var->name = SYMBOL_PRINT_NAME (sym);
+ var->address = addr;
+ var->is_callee = callee;
+ var->is_argument = is_arg;
+ var->is_array = (TYPE_CODE (type) == TYPE_CODE_ARRAY);
+ var->size = SYMBOL_OPS (sym)->get_variable_size(sym, frame);
+
+ if (var->is_array)
+ var->element_size = TYPE_LENGTH (TYPE_TARGET_TYPE (type));
+ }
+ else
+ {
+ *count = 0;
+ return NULL;
+ }
+ }
+ break;
+
+ default:
+ /* Ignore symbols which are not locals. */
+ break;
+ }
+ }
+
+ /* After handling the function's top-level block, stop. Don't continue
+ to its superblock, the block of per-file symbols. */
+ if (BLOCK_FUNCTION (block))
+ break;
+ block = BLOCK_SUPERBLOCK (block);
+ }
+
+ *count = vars;
+ return variables;
}
-/* read-only registers */
-static int
-arc_cannot_store_register (int regno)
+/* Return an array (and count) of the local variables declared in the function
+ which owns the given frame, and also those declared in the function which is
+ the callee (if any) of that function in the current call chain. */
+
+static LocalVariable*
+find_local_variables (struct frame_info *frame, unsigned int *count)
{
- if(
-#ifndef ARC4_JTAG
- regno == ARC_EFA_REGNUM ||
- regno == ARC_ERET_REGNUM ||
- regno == ARC_STATUS32_L1_REGNUM ||
- regno == ARC_STATUS32_L2_REGNUM ||
- regno == ARC_ERSTATUS_REGNUM ||
-#endif
- regno == ARC_ILINK1_REGNUM ||
- regno == ARC_ILINK2_REGNUM
- )
+ struct frame_info *callee = get_next_frame(frame);
+ LocalVariable *variables;
+
+ *count = 0;
+
+ variables = find_variables(frame, NULL, count, FALSE);
+
+ if (callee)
+ variables = find_variables(callee, variables, count, TRUE);
+
+ return variables;
+}
+
+
+/* Try to add the name of a local variable or function parameter to a line of
+ output, if a given address lies within the range of locations occupied by
+ that data item.
+
+ Parameters:
+ line : the line in which any output is to be placed
+ location : the address of a location on the stack
+ variables : an array of local variables and parameters
+ num_variables : the number of elements in the array
+ is_following_element : set to TRUE if the location lies within an
+ array element, and it is not the 0th element
+ elements_are_word_sized: set to TRUE if the array element is word-sized
+
+ Returns TRUE if the given location holds a local variable or parameter
+ (i.e. information has been added to the line of output). */
+
+static Boolean
+add_local_name (char *line,
+ CORE_ADDR location,
+ LocalVariable *variables,
+ unsigned int num_variables,
+ Boolean *is_following_element,
+ Boolean *elements_are_word_sized)
+{
+ unsigned int i;
+
+ *is_following_element = FALSE;
+ *elements_are_word_sized = FALSE;
+
+ /* Look at each of the local variables / parameters in the array. */
+ for (i = 0; i < num_variables; i++)
{
- /* No warning should be printed. arc_cannot_store_register being
- called does not imply that someone is actually writing to regnum. */
+ LocalVariable *var = &variables[i];
+ int index = -1;
- /*warning("writing to read-only register: %s\n", arc_register_name(regno));*/
- return 1;
- }
- return 0;
+ /* is the variable an array? */
+ if (var->is_array)
+ {
+ /* If we know the size of the array, and the size of its elements. */
+ if (var->size > 0 && var->element_size > 0)
+ {
+ /* What is the offset of the given stack location from the start
+ of the array? */
+ int offset = (int) ((long int) location - (long int) var->address);
+
+ /* Does that offset actually lie within the array? */
+ if (0 <= offset && offset < (int) var->size)
+ {
+ /* Compute the index of the array element which contains the
+ location. */
+ index = offset / var->element_size;
+ }
+
+ if (var->element_size == BYTES_IN_WORD)
+ *elements_are_word_sized = FALSE;
+ }
+ }
+
+ /* If the variable starts in the given location, or the variable is an
+ array and one of its elements contains the location. */
+ if (var->address == location || index >= 0)
+ {
+ int n;
+
+ /* What is the variable? */
+ if (var->is_callee)
+ n = sprintf(line, _("callee parameter"));
+ else if (var->is_argument)
+ n = sprintf(line, _("parameter"));
+ else
+ n = sprintf(line, _("local variable"));
+
+ line[n] = ' ';
+ n++;
+ n += sprintf(line + n, _("'%s'"), var->name);
+ line[n] = ' ';
+
+ /* If it is an array element. */
+ if (index >= 0)
+ {
+ /* Add the array element index to the output. */
+ (void) sprintf(line + n, _("[%u]"), index);
+
+ /* Is it an element which follows another element? */
+ *is_following_element = (index > 0);
+ }
+ else if (var->size > BYTES_IN_WORD)
+ {
+ /* It occupies more than one word. */
+ (void) sprintf(line + n + 1, _("(%u words)"),
+ WORDS_OCCUPIED(var->size));
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
}
-/* Returns true if the insn at PC is a branch. *fall_thru is the address of
- the next insn. *target is the branch target. */
-static int
-arc_next_pc(CORE_ADDR pc, CORE_ADDR *fall_thru, CORE_ADDR *target)
+
+/* Try to identify the given frame, and output that identification. */
+
+static void
+identify_frame (struct frame_info *frame)
{
-#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_next_pc called\n");
-#endif
-#else
- struct arcDisState instr, instr_d;
- int insn_length;
- struct disassemble_info di;
- int two_targets = 0;
-
- init_disassemble_info(&di, NULL, NULL);
- di.arch = gdbarch_bfd_arch_info(current_gdbarch)->arch;
- di.mach = gdbarch_bfd_arch_info(current_gdbarch)->mach;
- di.endian = gdbarch_byte_order(current_gdbarch);
- di.read_memory_func = target_read_memory;
-
- instr = arcAnalyzeInstr(pc, &di);
-
- *fall_thru = pc + instr.instructionLen;
-
-#ifdef ARC_DEBUG
- printf("--- arc_next_pc(%x) = %x, isBranch = %d, tcnt = %d [%x], flow = %s (%d), "
- "reg for indirect jump = %d, nullifyMode = %s\n",
- pc, *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 == BR_exec_always ? "delay slot" : "no delay"));
-#endif
+ enum language func_lang = language_unknown;
+ char *func_name = NULL;
+ char *demangled = NULL;
+ struct symbol *func;
+ struct symtab_and_line sal;
- if(instr.isBranch)
+ find_frame_sal (frame, &sal);
+ func = get_frame_function (frame);
+
+ /* Have we found the function owning the frame? */
+ if (func)
{
- two_targets = 1;
-
- if(instr.flow == direct_jump || instr.flow == direct_call)
- *target = instr.targets[0];
- else
- regcache_cooked_read(current_regcache,
- arc_binutils_reg_to_regnum(instr.register_for_indirect_jump),
- target);
+ func_name = DEPRECATED_SYMBOL_NAME (func);
+ func_lang = SYMBOL_LANGUAGE (func);
}
+ else
+ {
+ struct minimal_symbol *msymbol;
- /* for instructions with delay slots, the fall thru is not the instruction
- immediately after the branch instruction, but the one after that */
- if(instr.isBranch && instr.nullifyMode == BR_exec_always)
+ /* Try to find the symbol most closely associated with the PC
+ corresponding to the frame. */
+ msymbol = lookup_minimal_symbol_by_pc (get_frame_pc (frame));
+
+ if (msymbol != NULL)
+ {
+ func_name = DEPRECATED_SYMBOL_NAME (msymbol);
+ func_lang = SYMBOL_LANGUAGE (msymbol);
+ }
+ }
+
+ /* Have we found a name? */
+ if (func_name)
{
- instr_d = arcAnalyzeInstr(*fall_thru, &di);
- *fall_thru += instr_d.instructionLen;
+ /* If user wants to see raw output, no problem.
+ (demangle is a global flag which can be set by user command). */
+ if (demangle)
+ {
+ demangled = language_demangle (language_def (func_lang),
+ func_name,
+ DMGL_ANSI | DMGL_PARAMS);
+
+ /* If the demangler fails, try the demangled name from the symbol
+ table. That'll have parameters, but that's preferable to
+ displaying a mangled name. */
+ if (demangled == NULL)
+ {
+ if (func == NULL)
+ func_name = _("<unknown function>");
+ else
+ func_name = SYMBOL_PRINT_NAME (func);
+ }
+ else
+ func_name = demangled;
+ }
}
+ else
+ func_name = _("<unknown function>");
- /* zero-overhead loops:
- if(status32[L] == 0 && next_pc == lp_end && lp_count > 1)
- next_pc = lp_start;
- */
- {
- unsigned int lp_end, lp_start, lp_count, status32;
-
- regcache_cooked_read(current_regcache, ARC_LP_START_REGNUM, &lp_start);
- regcache_cooked_read(current_regcache, ARC_LP_END_REGNUM, &lp_end);
- regcache_cooked_read(current_regcache, ARC_LP_COUNT_REGNUM, &lp_count);
-#ifndef ARC4_JTAG
- regcache_cooked_read(current_regcache, ARC_STATUS32_REGNUM, &status32);
-#endif
+ printf_filtered(_("Frame of function: %s"), func_name);
+ if (sal.symtab)
+ printf_filtered(_(" (%s:%d)"), sal.symtab->filename, sal.line);
+ printf_filtered(NEW_LINE);
- if( !(status32 & ARC_STATUS32_L) && *fall_thru == lp_end && lp_count > 1)
- {
- two_targets = 1;
- *target = lp_start;
- }
- }
-
- return two_targets;
-#endif //
+ if (demangled != NULL)
+ xfree (demangled);
}
-/* this is called with insert_breakpoints_p = 1 before single-stepping and
- with insert_breakpoints_p = 0 after the step */
-void
-arc_software_single_step(enum target_signal ignore, int insert_breakpoints_p)
+
+/* -------------------------------------------------------------------------- */
+/* local functions called from gdb */
+/* -------------------------------------------------------------------------- */
+
+/* Standard register type for the ARC platform.
+ It would be builtin_type_uint32 until we consider the DSP extensions. */
+
+static struct type *
+arc_register_type (struct gdbarch *gdbarch, int regnum)
{
-#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_software_single_step called\n" );
-#endif
-#else
- typedef char binsn_quantum[BREAKPOINT_MAX];
-
- static CORE_ADDR fall_thru, branch_target;
- static binsn_quantum break_mem[2];
- static char two_breakpoints;
- CORE_ADDR pc;
-
- {
-#ifdef ARC_DEBUG
- unsigned int efa, ret;
- regcache_cooked_read(current_regcache, ARC_EFA_REGNUM, &efa);
- // regcache_cooked_read(current_regcache, ARC_RET_REGNUM, &ret);
-
- printf("--- arc_software_single_step, efa = %x, ret = %x, (%s)\n", efa, ret,
- (insert_breakpoints_p ? "add" : "remove"));
-#endif
- }
-
- if (insert_breakpoints_p)
- {
- pc = read_pc ();
- two_breakpoints = arc_next_pc (pc, &fall_thru, &branch_target);
-
- if (two_breakpoints && branch_target == pc)
- {
- warning ("Cannot single-step branch-to-self or single instruction zero overhead loop,\n"
- " Stepping across it.");
- /* Don't insert/remove the branch-target breakpoint. */
- two_breakpoints = 0;
- }
-
- target_insert_breakpoint (fall_thru, break_mem[0]);
- if(two_breakpoints)
- target_insert_breakpoint (branch_target, break_mem[1]);
- }
- else
+ return builtin_type_uint32;
+}
+
+
+/* Skip the prologue for the function at pc.
+ Returns the address of the first instruction after the prologue. */
+
+static CORE_ADDR
+arc_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR function_addr, function_end = 0;
+ char *function_name;
+
+ /* This is done by checking from the line information read from the DWARF,
+ if possible; otherwise, we scan the function prologue to find its end. */
+
+ ENTERMSG;
+
+ /* If we're in a dummy frame, don't even try to skip the prologue. */
+ if (deprecated_pc_in_call_dummy (pc))
+ return pc;
+
+ /* See what the symbol table says. */
+ if (find_pc_partial_function (pc, &function_name, &function_addr, &function_end))
{
- target_remove_breakpoint (fall_thru, break_mem[0]);
- if(two_breakpoints)
- target_remove_breakpoint (branch_target, break_mem[1]);
+ /* Found a function. */
+ struct symbol *sym = lookup_symbol (function_name, NULL, VAR_DOMAIN, NULL, NULL);
+
+ if ((sym != NULL) && SYMBOL_LANGUAGE (sym) != language_asm)
+ {
+ /* Don't use this trick for assembly source files. */
+ struct symtab_and_line sal = find_pc_line (function_addr, 0);
+
+ if ((sal.line != 0) && (sal.end < function_end))
+ return sal.end;
+ }
}
-#endif
+
+ /* Find the address of the first instruction after the prologue by scanning
+ through it - no other information is needed, so pass NULL for the other
+ parameters. */
+ return scan_prologue(pc, NULL, NULL);
}
-/*
- * mapping from binutils/gcc register number to
- * GDB register number ("regnum")
- */
-static int
-arc_binutils_reg_to_regnum (int reg)
+
+/* Construct frame id for the normal frame. */
+
+static void
+arc_frame_this_id (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ struct frame_id *this_id)
{
-#ifdef ARC4_JTAG
- if (reg >= 0 && reg <= 26)
- return reg;
- else if (reg == 27) /* fp */
- return ARC_FP_REGNUM;
- else if (reg == 28) /* 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;
+ ENTERMSG;
-#else
- /* from gcc/config/arc/arc.h */
-
- if (reg >= 0 && reg <= 26)
- return reg;
- else if (reg == 27) /* fp */
- return ARC_FP_REGNUM;
- else if (reg == 28) /* 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 (reg >= 32 && reg <= 59) /* reserved */
- ;
- else if (reg == 60) /* lp_count */
- return ARC_LP_COUNT_REGNUM;
- else if (reg == 61) /* reserved */
- ;
- else if (reg == 62) /* no such register */
- ;
-/* else if (reg == 63) /\* PCL *\/ */
-/* return ARC_RET_REGNUM; */
+ /* FIXME: to what should *this_id be set if the frame base can not be found? */
+
+ {
+ /* Find the entry point of the function which owns the frame. */
+ CORE_ADDR entrypoint = frame_func_unwind (next_frame, NORMAL_FRAME);
+
+ /* This is meant to halt the backtrace at the entry point (_start)
+ (it assumes that there is no code at a lower address). */
+ if (entrypoint > gdbarch_tdep (current_gdbarch)->lowest_pc)
+ {
+ UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache);
+ CORE_ADDR base = info->prev_sp;
+
+ /* Hopefully the prologue analysis either correctly determined the
+ frame's base (which is the SP from the previous frame), or set
+ that base to "NULL". */
+ if (base != 0)
+ {
+ /* Build the ID from the frame base address. */
+ *this_id = frame_id_build (base, entrypoint);
+
+#if 0
+ printf("*** Frame ID: %x ==> (%x %x %x)\n",
+ base,
+ this_id->stack_addr,
+ this_id->code_addr,
+ this_id->special_addr);
#endif
- warning ("Unmapped register #%d encountered\n", reg);
- return -1;
+ }
+ }
+ }
}
+/* Unwind and obtain the register information. */
+
static void
-arc_add_reggroups (struct gdbarch *gdbarch)
+arc_frame_prev_register (struct frame_info *next_frame,
+ void **this_prologue_cache,
+ int regnum,
+ int *optimized,
+ enum lval_type *lval,
+ CORE_ADDR *addr,
+ int *realnum,
+ gdb_byte *buffer)
{
- reggroup_add (gdbarch, general_reggroup);
- reggroup_add (gdbarch, all_reggroup);
- reggroup_add (gdbarch, system_reggroup);
+ ENTERARGS("regnum %d ", regnum);
+
+ {
+ UnwindCache *info = frame_unwind_cache (next_frame, this_prologue_cache);
+
+ /* If we are asked to unwind the PC, then we need to return blink
+ instead: the saved value of PC points into this frame's function's prologue,
+ not the next frame's function's resume location. */
+ if (regnum == ARC_PC_REGNUM)
+ regnum = ARC_BLINK_REGNUM;
+
+ /* SP is generally not saved to the stack, but this frame is identified
+ by next_frame's stack pointer at the time of the call. The value was
+ already reconstructed into prev_sp. */
+ if (regnum == ARC_SP_REGNUM)
+ {
+ /* This value is not an L-value, i.e. it can not be changed, because
+ it is implicit in the structure of the call-chain. */
+ *lval = not_lval;
+
+ if (buffer)
+ store_unsigned_integer (buffer, BYTES_IN_REGISTER, info->prev_sp);
+ return;
+ }
+
+ trad_frame_get_prev_register (next_frame,
+ info->saved_regs,
+ regnum,
+ optimized,
+ lval,
+ addr,
+ realnum,
+ buffer);
+
+ DEBUG("-*-*-*\n Regnum = %d, buffer = %p\n", regnum, buffer);
+ }
}
-int
-arc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
- struct reggroup *group)
+
+/* This function is passed to gdb to enable it to unwind frames. */
+
+static const struct frame_unwind *
+arc_frame_sniffer (struct frame_info *next_frame)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- int tdep_answer;
-
- tdep_answer = tdep->register_reggroup_p (regnum, group);
- if(tdep_answer != -1)
- return tdep_answer;
-
- if (group == all_reggroup)
- return 1;
- else if (group == save_reggroup || group == restore_reggroup)
+ static const struct frame_unwind arc_frame_unwind =
{
- /* don't save/restore read-only registers. */
- return (!arc_cannot_store_register(regnum));
- }
- else if (group == general_reggroup)
+ NORMAL_FRAME, // type
+ arc_frame_this_id, // this_id
+ arc_frame_prev_register, // prev_register
+ NULL, // unwind_data
+ NULL, // sniffer
+ NULL, // prev_pc
+ NULL // dealloc_cache
+ };
+
+ return &arc_frame_unwind;
+}
+
+
+/* Get the breakpoint which is appropriate for address at which it is to be set.
+
+ Return whatever is in the ARC-private tdep structure (this has been set up
+ according to the correct target / architecture chosen).
+
+ Fortunately, the ARC processor does not have separate instruction sets (like
+ the ARM's normal 32-bit and 16-bit Thumb instructions), so the bp instruction
+ to be used does not depend on the address (although the ARC does have both
+ 16- and 32-bit instructions, they may be freely intermixed). */
+
+static const unsigned char *
+arc_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int end = gdbarch_byte_order (gdbarch);
+
+ /* Return the breakpoint instruction length. */
+ *lenptr = (int) tdep->breakpoint_size;
+
+ /* Return the breakpoint instruction code. */
+ if (end == BFD_ENDIAN_LITTLE)
+ return tdep->le_breakpoint_instruction;
+ if (end == BFD_ENDIAN_BIG)
+ return tdep->be_breakpoint_instruction;
+
+ internal_error (__FILE__, __LINE__, "target endianness is not known");
+}
+
+
+/* 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
+arc_register_reggroup_p (struct gdbarch *gdbarch,
+ int regnum,
+ struct reggroup *group)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int tdep_answer = tdep->register_reggroup_p (regnum, group);
+
+ /* If the configuration-specific tdep knows about this register. */
+ if (tdep_answer != -1)
+ return tdep_answer;
+
+ if (group == all_reggroup)
+ return 1;
+
+ if (group == save_reggroup || group == restore_reggroup)
{
-#ifndef ARC4_JTAG
- if (regnum == ARC_STATUS32_REGNUM)
- return 0;
-#endif
- return 1;
+ /* Don't save/restore read-only registers. */
+ return (!gdbarch_cannot_store_register(current_gdbarch, regnum));
}
- else
+
+ if (group == system_reggroup)
{
- internal_error(__FILE__, __LINE__, "bad register group");
+ if (regnum == ARC_ILINK1_REGNUM ||
+ regnum == ARC_ILINK2_REGNUM)
+ return 1;
+
+ return 0;
}
+
+ internal_error(__FILE__, __LINE__, _("bad register group"));
+ return 0;
}
+/* This function is used by the DWARF-2 frame sniffer.
+ It is the architecture-specific register state initialization function:
+ it tells gdb how to find certain registers in the DWARF-2 Call Frame Information. */
static void
-arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
- struct dwarf2_frame_state_reg *reg)
+arc_dwarf2_frame_init_reg (struct gdbarch *gdbarch,
+ int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *info)
{
-#ifdef ARC4_JTAG
- // FIXMEA: Clean up. if ( debug_arc_jtag_target_message)
-#ifdef ARC_DEBUG
- printf ("\n arc_dwarf2_frame_init_reg called.\n Regno no:%d,0x%x\n",regnum,regnum);
-#endif
+// ENTERARGS("Regno no:%d, 0x%x", regnum, (unsigned int) regnum);
+
+ /* Make sure that we know the number of the PC! */
+ arc_check_pc_defined(gdbarch);
+
/* The return address column. */
- if (regnum == ARC_STATUS_REGNUM)
- reg->how = DWARF2_FRAME_REG_RA;
-
- /* The call frame address. */
- if (regnum == ARC_SP_REGNUM)
- reg->how = DWARF2_FRAME_REG_CFA;
+ if (regnum == ARC_PC_REGNUM)
+ reg->how = DWARF2_FRAME_REG_RA;
-#else
- /* The return address column. */
- if (regnum == PC_REGNUM)
- reg->how = DWARF2_FRAME_REG_RA;
-
- /* The call frame address. */
- if (regnum == ARC_SP_REGNUM)
- reg->how = DWARF2_FRAME_REG_CFA;
-#endif
+ /* The call frame address. */
+ if (regnum == ARC_SP_REGNUM)
+ reg->how = DWARF2_FRAME_REG_CFA;
}
+
+/* Unwind the frame to find the previous frame's PC. */
+
static CORE_ADDR
arc_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- ULONGEST pc;
-#ifdef ARC4_JTAG
- frame_unwind_unsigned_register (next_frame, ARC_STATUS_REGNUM, &pc);
- pc = pc & 0x00ffffff;
- pc = pc << 2;
-#else
- frame_unwind_unsigned_register (next_frame, PC_REGNUM, &pc);
-#endif
- return pc;
+ ULONGEST pc;
+
+ /* Make sure that we know the number of the PC! */
+ arc_check_pc_defined(gdbarch);
+
+ pc = frame_unwind_register_unsigned (next_frame, ARC_PC_REGNUM);
+
+ DEBUG("unwind PC: 0x%08lx\n", (unsigned long) pc);
+
+ return (CORE_ADDR) pc;
}
+
+/* Unwind the frame to find the previous frame's SP. */
+
static CORE_ADDR
arc_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- ULONGEST sp;
- frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
- return sp;
-}
+ ULONGEST sp;
+ sp = frame_unwind_register_unsigned (next_frame, ARC_SP_REGNUM);
+ DEBUG("unwind SP: 0x%08lx\n", (unsigned long) sp);
-static void
-arc_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
-{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_extract_return_value called\n");
-#endif
- //#else
- ULONGEST val;
- int len = TYPE_LENGTH (type);
-
- if (len <= 4)
- {
- /* Get the return value from R0. */
- regcache_cooked_read_unsigned (regcache, ARC_RETURN1_REGNUM, &val);
- store_unsigned_integer (valbuf, len, val);
- }
- else if (len <= 8)
- {
- /* Get the return value from R0 and R1. */
- /* R0 holds the lower-order bytes */
- regcache_cooked_read_unsigned (regcache, ARC_RETURN1_REGNUM, &val);
- store_unsigned_integer (valbuf, 4, val);
- regcache_cooked_read_unsigned (regcache, ARC_RETURN2_REGNUM, &val);
- store_unsigned_integer ((char *)valbuf + 4, len - 4, val);
- }
- else
- error ("arc_extract_return_value: type length too large");
- //#endif
+ return (CORE_ADDR) sp;
}
-static void
-arc_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
-{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_store_return_value called\n ");
-#endif
- //#else
- ULONGEST val;
- int len = TYPE_LENGTH (type);
-
- if (len <= 4)
- {
- /* Put the return value in R0. */
- val = extract_unsigned_integer (valbuf, len);
- regcache_cooked_write_unsigned (regcache, ARC_RETURN1_REGNUM, val);
- }
- else if (len <= 8)
- {
- /* Put the return value in R10 and R11. */
- val = extract_unsigned_integer (valbuf, 4);
- regcache_cooked_write_unsigned (regcache, ARC_RETURN1_REGNUM, val);
- val = extract_unsigned_integer ((char *)valbuf + 4, len - 4);
- regcache_cooked_write_unsigned (regcache, ARC_RETURN2_REGNUM, val);
- }
- else
- error ("arc_store_return_value: type length too large.");
- //#endif
-}
+/* This function returns the convention used by the ABI for returning a result
+ of the given type from a function; it may also be required to:
+
+ a) set the return value (this is for the situation where the debugger user
+ has issued a "return <value>" command to request immediate return from
+ the current function with the given result; or
+
+ b) get the return value ((this is for the situation where the debugger user
+ has executed a "call <function>" command to execute the specified
+ function in the target program, and that function has a non-void result
+ which must be returned to the user.
+
+ Parameters:
+ gdbarch : gdbarch structure for the backend to use if needed
+ valtype : the information for the return type of the function
+ regcache: the register cache to be used for altered register values
+ readbuf : if non-NULL, read the return value into this buffer
+ writebuf: if non-NULL, write the return value from this buffer
+ */
static enum return_value_convention
-arc_return_value (struct gdbarch *gdbarch, struct type *valtype,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+arc_return_value (struct gdbarch *gdbarch,
+ struct type *valtype,
+ struct regcache *regcache,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_return_value called");
-#endif
- //#else
- /* This will change with the ABI */
- int struct_return = (TYPE_CODE (valtype) == TYPE_CODE_STRUCT ||
- TYPE_CODE (valtype) == TYPE_CODE_UNION ||
- TYPE_LENGTH (valtype) > 8);
-
-
- if (writebuf != NULL)
- {
- gdb_assert (!struct_return);
- arc_store_return_value (valtype, regcache, writebuf);
- }
+ ENTERARGS("readbuf = %p, writebuf = %p", readbuf, writebuf);
- if (readbuf != NULL)
{
- gdb_assert (!struct_return);
- arc_extract_return_value (valtype, regcache, readbuf);
+ /* If the return type is a struct, or a union, or would occupy more
+ than two registers, the ABI uses the "struct return convention": the
+ calling function passes a hidden first parameter to the callee (in R0).
+ That parameter is the address at which the value being returned
+ should be stored. Otherwise, the result is returned in registers. */
+ Boolean is_struct_return = (TYPE_CODE (valtype) == TYPE_CODE_STRUCT ||
+ TYPE_CODE (valtype) == TYPE_CODE_UNION ||
+ TYPE_LENGTH (valtype) > 2 * BYTES_IN_REGISTER);
+
+ /* case a) */
+ if (writebuf != NULL)
+ {
+ /* gdb should not ask us to set a struct return value: it should
+ know the struct return location and write the value there
+ itself. */
+ gdb_assert (!is_struct_return);
+ store_return_value (valtype, regcache, writebuf);
+ }
+
+ /* case b) */
+ if (readbuf != NULL)
+ {
+ /* gdb should not ask us to get a struct return value: it should
+ know the struct return location and read the value from there
+ itself. */
+ gdb_assert (!is_struct_return);
+ extract_return_value (valtype, regcache, readbuf);
+ }
+
+ return (is_struct_return) ? RETURN_VALUE_STRUCT_CONVENTION
+ : RETURN_VALUE_REGISTER_CONVENTION;
}
+}
+
+
+/* Assuming that next_frame->prev is a dummy, return the frame ID of that dummy
+ frame. The frame ID's base needs to match the TOS value saved by
+ save_dummy_frame_tos() (!!!! WHAT IS THIS???), and the PC to match the dummy
+ frame's breakpoint. */
- if (struct_return)
- return RETURN_VALUE_STRUCT_CONVENTION;
- else
- return RETURN_VALUE_REGISTER_CONVENTION;
- //#endif
+static struct frame_id
+arc_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_id_build (arc_unwind_sp (gdbarch, next_frame),
+ frame_pc_unwind (next_frame));
}
-/* Signal Trampoline Frame Unwinder. These
- * unwinders allow frame unwinding to happen
- * from within signal handlers.
- */
-static struct arc_unwind_cache *
+/* Signal Trampoline Frame Unwinder.
+ These unwinders allow frame unwinding to happen from within signal handlers. */
+
+static UnwindCache *
arc_sigtramp_frame_cache (struct frame_info *next_frame,
- void **this_cache)
+ void **this_cache)
{
- // FIXMEA: cleanup#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_sigtramp_frame_cache called");
-#endif
- //#else
- struct arc_unwind_cache *cache;
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- CORE_ADDR addr;
- char buf[4];
-
- if (*this_cache)
- return *this_cache;
+ ENTERMSG;
- cache = FRAME_OBSTACK_ZALLOC (struct arc_unwind_cache);
- (*this_cache) = cache;
- cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-
- /* Zero all fields. */
- cache->blink_offset = 0;
- cache->prev_pc = 0;
- cache->prev_sp = 0;
- cache->frame_base = 0;
- cache->framesize = 0;
- cache->sp_offset = 0;
- cache->fp_offset = 0;
- cache->prev_pc = 0;
- cache->is_leaf = 0;
- cache->uses_fp = 0;
-
-
- frame_unwind_register (next_frame, SP_REGNUM, buf);
- cache->frame_base = extract_unsigned_integer (buf, 4);
-
- addr = tdep->sigcontext_addr (next_frame);
- if (tdep->sc_reg_offset)
+ if (*this_cache == NULL)
{
- int i;
-
- for (i = 0; i < tdep->sc_num_regs; i++)
- if (tdep->sc_reg_offset[i] != -1)
- cache->saved_regs[i].addr = addr + tdep->sc_reg_offset[i];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ UnwindCache *cache = create_cache(next_frame);
+ gdb_byte buf[BYTES_IN_REGISTER];
+
+ *this_cache = cache;
+
+ /* Get the stack pointer and use it as the frame base. */
+ frame_unwind_register (next_frame, ARC_SP_REGNUM, buf);
+ cache->frame_base = (CORE_ADDR) extract_unsigned_integer (buf, BYTES_IN_REGISTER);
+
+ /* If the ARC-private target-dependent info has a table of offsets of
+ saved register contents within a O/S signal context structure. */
+ if (tdep->sc_reg_offset)
+ {
+ /* Find the address of the sigcontext structure. */
+ CORE_ADDR addr = tdep->sigcontext_addr (next_frame);
+ unsigned int i;
+
+ /* For each register, if its contents have been saved within the
+ sigcontext structure, determine the address of those contents. */
+ for (i = 0; i < tdep->sc_num_regs; i++)
+ if (tdep->sc_reg_offset[i] != REGISTER_NOT_PRESENT)
+ cache->saved_regs[i].addr = (LONGEST) (addr + tdep->sc_reg_offset[i]);
+ }
}
- return cache;
- //#endif
+ return *this_cache;
}
+
+/* Construct id for the given frame. */
+
static void
-arc_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
- struct frame_id *this_id)
+arc_sigtramp_frame_this_id (struct frame_info *next_frame,
+ void **this_cache,
+ struct frame_id *this_id)
{
- //FIXMEA: cleanup #ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_sigtramp_frame_this_id called");
-#endif
- //#else
- struct arc_unwind_cache *cache =
- arc_sigtramp_frame_cache (next_frame, this_cache);
-
- (*this_id) = frame_id_build (cache->frame_base, frame_pc_unwind (next_frame));
- //#endif
+ UnwindCache *cache;
+
+ ENTERMSG;
+
+ cache = arc_sigtramp_frame_cache (next_frame, this_cache);
+
+ *this_id = frame_id_build (cache->frame_base, frame_pc_unwind (next_frame));
}
+
+/* Retrieve the value of the register in the frame. */
+
static void
arc_sigtramp_frame_prev_register (struct frame_info *next_frame,
- void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ void **this_cache,
+ int regnum,
+ int *optimizedp,
+ enum lval_type *lvalp,
+ CORE_ADDR *addrp,
+ int *realnump,
+ gdb_byte *valuep)
{
- // FIXMEA: cleanup#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_sigtramp_frame_prev_register called");
-#endif
- //#else
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-
- /* Make sure we've initialized the cache. */
- struct arc_unwind_cache *cache =
- arc_sigtramp_frame_cache (next_frame, this_cache);
+ ENTERMSG;
- /* on a signal, the PC is in ret */
-#ifdef ARC4_JTAG
- if (regnum == ARC_STATUS_REGNUM)
-#else
- if(regnum == PC_REGNUM)
-#endif
- regnum = tdep->pc_regnum_in_sigcontext;
-
- trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
- //#endif
+ {
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+
+ /* Make sure we've initialized the cache. */
+ UnwindCache *cache = arc_sigtramp_frame_cache (next_frame, this_cache);
+
+ /* On a signal, the PC is in ret. */
+ if (regnum == ARC_PC_REGNUM)
+ regnum = tdep->pc_regnum_in_sigcontext;
+
+ trad_frame_get_prev_register (next_frame,
+ cache->saved_regs,
+ regnum,
+ optimizedp,
+ lvalp,
+ addrp,
+ realnump,
+ valuep);
+ }
}
-static const struct frame_unwind arc_sigtramp_frame_unwind =
-{
- SIGTRAMP_FRAME,
- arc_sigtramp_frame_this_id,
- arc_sigtramp_frame_prev_register
-};
-
-const struct frame_unwind *
+static const struct frame_unwind *
arc_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
- //FIXMEA: cleanup#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_sigtramp_frame_sniffer called() ");
-#endif
- //#else
- CORE_ADDR pc = frame_pc_unwind (next_frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+ ENTERMSG;
- /* We shouldn't even bother if we don't have a sigcontext_addr
- handler. */
- if (tdep->sigcontext_addr == NULL)
- return NULL;
-
- if (tdep->sigtramp_p != NULL)
{
- if (tdep->sigtramp_p (next_frame))
- {
- return &arc_sigtramp_frame_unwind;
- }
- }
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
- return NULL;
- //#endif
-}
+ /* We don't even bother if we don't have a sigcontext_addr handler. */
+ if ((tdep->sigcontext_addr != NULL) &&
+ (tdep->is_sigtramp != NULL) &&
+ tdep->is_sigtramp (next_frame))
+ {
+ static const struct frame_unwind arc_sigtramp_frame_unwind =
+ {
+ SIGTRAMP_FRAME, // type
+ arc_sigtramp_frame_this_id, // this_id
+ arc_sigtramp_frame_prev_register, // prev_register
+ NULL, // unwind_data
+ NULL, // sniffer
+ NULL, // prev_pc
+ NULL // dealloc_cache
+ };
+
+ return &arc_sigtramp_frame_unwind;
+ }
+ return NULL;
+ }
+}
-/* Allow calls to be made to functions defined in the debuggee.
- a.k.a dummy calls
-*/
-/* When arguments must be pushed onto the stack, they go on in reverse
- order. The below implements a FILO (stack) to do this.
- Copied from d10v-tdep.c. */
+/* Allow calls to be made to functions defined in the debuggee (A.K.A dummy calls).
-struct stack_item
-{
- int len;
- struct stack_item *prev;
- void *data;
-};
+ Parameters:
+ gdbarch : gdbarch structure for the backend to use if needed.
+ function : the function to be called
+ regcache : the register cache to be used for altered register values
+ bp_addr : return address for the breakpoint.
+ nargs : the number of arguments to the function
+ args : the arguments to be passed to the function
+ sp : current value of SP.
+ struct_return: 1 if structures are returned by the function.
+ struct_addr : hidden address for returning a struct. */
-static struct stack_item *
-push_stack_item (struct stack_item *prev, void *contents, int len)
-{
- struct stack_item *si;
- si = xmalloc (sizeof (struct stack_item));
- si->data = xmalloc (len);
- si->len = len;
- si->prev = prev;
- memcpy (si->data, contents, len);
- return si;
-}
+static CORE_ADDR
+arc_push_dummy_call (struct gdbarch *gdbarch,
+ struct value *function,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr,
+ int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
-static struct stack_item *
-pop_stack_item (struct stack_item *si)
{
- struct stack_item *dead = si;
- si = si->prev;
- xfree (dead->data);
- xfree (dead);
- return si;
-}
+ int arg_reg = ARC_ABI_FIRST_ARGUMENT_REGISTER;
+ ENTERARGS("nargs = %d, struct_return = %d", nargs, struct_return);
+ /* Push the return address. */
+ regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr);
+ DEBUG("set BLINK = %X\n", (unsigned int) bp_addr);
-/* arc_push_dummy_call :
- * gdbarch : gdbarch structure for the backend to use if needed.
- * function :
- * regcache :
- * bp_addr : Return address for the breakpoint.
- * sp : Current value of sp.
- * struct_return: struct_return is 1 if structures are returned by
- * the function.
- * struct_addr: Hidden address for returning a struct.
- */
+ /* Are we returning a value using a structure return instead of a normal
+ value return? If so, struct_addr is the address of the reserved space
+ for the return structure to be written on the stack, and that address
+ is passed to that function as a hidden first argument. */
+ if (struct_return)
+ {
+ /* Pass the return address in the first argument register. */
+ regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
-static CORE_ADDR
-arc_push_dummy_call(struct gdbarch *gdbarch, struct value *function,
- struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
- struct value **args, CORE_ADDR sp, int struct_return,
- CORE_ADDR struct_addr)
+ DEBUG("struct return address 0x%08lX passed in R%d", struct_addr, arg_reg);
-{
- //#ifdef ARC4_JTAG
-#ifdef ARC_DEBUG
- printf ("\narc_push_dummy_call called");
-#endif
- // #else
- int stack_alloc;
- int stack_offset;
- int argreg;
- int argnum;
-
- CORE_ADDR regval;
- struct stack_item *si = NULL;
-
-
- /* Push the return address. */
-#ifdef ARC4_JTAG
- CORE_ADDR modified_bp_addr;
- modified_bp_addr = arc_debug_fetch_regs(ARC_STATUS_REGNUM);
- regcache_raw_collect(regcache, ARC_STATUS_REGNUM, &modified_bp_addr);
- modified_bp_addr = modified_bp_addr & 0xff000000;
- bp_addr = bp_addr >>2;
- modified_bp_addr |= bp_addr;
- regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, modified_bp_addr);
-#else
- regcache_cooked_write_unsigned (regcache, ARC_BLINK_REGNUM, bp_addr);
-#endif
+ arg_reg++;
+ }
- /* Are we returning a value using a structure return or a normal value
- return? struct_addr is the address of the reserved space for the return
- structure to be written on the stack.
- */
- /* FIXME:: Ramana :: What about 4 byte structures returned in r0 as
- claimed by Metaware.
- */
-
- /* Now load as many as possible of the first arguments into registers,
- and push the rest onto the stack. */
- argreg = ARC_ARG0_REGNUM;
-
- if (struct_return)
+ /* If the function has arguments. */
+ if (nargs > 0)
{
- regcache_cooked_write_unsigned (regcache, ARC_ARG0_REGNUM, struct_addr);
- argreg++;
-#ifdef ARC4_JTAG
- sp = sp - 16;
-#endif
- }
+ Boolean big_endian = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG;
+ unsigned int total_space = 0;
+ gdb_byte *memory_image;
+ gdb_byte *data;
+ int i;
+
+ /* How much space do the arguments occupy in total?
+ N.B. must round each argument's size up to an integral number of words. */
+ for (i = 0; i < nargs; i++)
+ {
+ unsigned int len = TYPE_LENGTH (value_type (args[i]));
+ unsigned int space = ROUND_UP_TO_WORDS(len);
- stack_offset = 0;
+ total_space += space;
- for (argnum = 0; argnum < nargs; argnum++)
- {
- int len;
- char *val;
- int reg_demand;
- int i;
-
- len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
- val = (char *) VALUE_CONTENTS (args[argnum]);
-
- /* How may registers worth of storage do we need for this argument? */
- reg_demand = (len / 4) + (len % 4 != 0 ? 1 : 0);
-
- if (argreg + reg_demand - 1 <= ARC_ARG7_REGNUM)
+ DEBUG("function arg[%d]: %d bytes -> %d\n", i, len, space);
+ }
+
+ /* Allocate a buffer to hold a memory image of the arguments. */
+ memory_image = XCALLOC((size_t) total_space, gdb_byte);
+ if (memory_image == NULL)
{
- /* Data passed by value. Fits in available register(s). */
- for (i = 0; i < reg_demand; i++)
- {
- regcache_cooked_write_unsigned (regcache, argreg,
- *(unsigned long *) val);
- argreg++;
- val += 4;
- }
+ /* could not do the call! */
+ return 0;
}
- else if (argreg <= ARC_ARG7_REGNUM)
+
+ /* Now copy all of the arguments into the buffer, correctly aligned. */
+ data = memory_image;
+ for (i = 0; i < nargs; i++)
{
- /* Data passed by value. Does not fit in available register(s).
- Use the register(s) first, then the stack. */
- for (i = 0; i < reg_demand; i++)
- {
- if (argreg <= ARC_ARG7_REGNUM)
- {
- regcache_cooked_write_unsigned (regcache, argreg,
- *(unsigned long *) val);
- argreg++;
- val += 4;
- }
- else
- {
- /* Push item for later so that pushed arguments
- come in the right order. */
- si = push_stack_item (si, val, 4);
- val += 4;
- }
- }
+ unsigned int len = TYPE_LENGTH (value_type (args[i]));
+ unsigned int space = ROUND_UP_TO_WORDS(len);
+ gdb_byte* actual = data;
+ unsigned int w;
+
+ /* Parameters smaller than a word are normally aligned by gcc to the
+ least significant byte, so if we have a big-endian target we put
+ the data at the end of the word rather than at the start. */
+ if ((len < BYTES_IN_WORD) && big_endian)
+ actual += BYTES_IN_WORD - len;
+
+ (void) memcpy(actual, value_contents (args[i]), (size_t) len);
+
+ DEBUG("function arg[%d] =", i);
+ for (w = 0; w < space / BYTES_IN_WORD; w++)
+ DEBUG(" 0x%08X", *((int*) data + w));
+ DEBUG("\n");
+
+ data += space;
}
- else if (len > (2 * 4))
+
+ /* Now load as much as possible of the memory image into registers. */
+ data = memory_image;
+ while (arg_reg <= ARC_ABI_LAST_ARGUMENT_REGISTER)
{
- /* FIXME */
- internal_error (__FILE__, __LINE__, "We don't do this");
+ ARC_RegisterContents contents = *(ARC_RegisterContents*) data;
+
+ DEBUG("passing 0x%08X in register R%d\n", (unsigned int) contents, arg_reg);
+
+ /* Convert to target byte order if necessary. */
+ if (HOST_AND_TARGET_ENDIANNESS_DIFFER(gdbarch))
+ {
+ contents = __bswap_32(contents);
+ DEBUG("byte-swapped to 0x%08X\n", contents);
+ }
+
+ regcache_cooked_write_unsigned (regcache,
+ arg_reg,
+ (ULONGEST) contents);
+
+ data += BYTES_IN_REGISTER;
+ total_space -= BYTES_IN_REGISTER;
+
+ /* If all the data is now in registers. */
+ if (total_space == 0)
+ break;
+
+ arg_reg++;
}
- else
+
+ /* If there is any data left, push it onto the stack (in a single write operation). */
+ if (total_space > 0)
{
- /* Data passed by value. No available registers. Put it on
- the stack. */
- si = push_stack_item (si, val, len);
+ DEBUG("passing %d bytes on stack\n", total_space);
+
+ sp -= total_space;
+ write_memory (sp, data, (int) total_space);
}
- }
- while (si)
- {
- /* fp_arg must be word-aligned (i.e., don't += len) to match
- the function prologue. */
- sp = (sp - si->len) & ~3;
-#ifdef ARC4_JTAG
- write_memory (sp + 16, si->data, si->len);
-#else
- write_memory (sp, si->data, si->len);
-#endif
- si = pop_stack_item (si);
+ xfree(memory_image);
}
- /* Finally, update the SP register. */
- regcache_cooked_write_unsigned (regcache, ARC_SP_REGNUM, sp);
+ /* Finally, update the SP register. */
+ regcache_cooked_write_unsigned (regcache, ARC_SP_REGNUM, sp);
+
+ DEBUG("set SP = %X\n", (unsigned int) sp);
- return sp;
- //#endif
+ return sp;
}
-/* Align Frame */
+
+/* Align frame. */
+
static CORE_ADDR
arc_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
{
- /* Align to the normal alignment on the stack). */
- return sp & ~3;
+ /* Align to the normal alignment on the stack). */
+ return WORD_ALIGNED(sp);
}
/* Print interesting information about the floating point processor
(if present) or emulator. */
+
static void
arc_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
- struct frame_info *frame, const char *args)
+ struct frame_info *frame, const char *args)
{
- printf("Software FPU \n");
+ printf(_("Software FPU\n"));
}
/* Set the main_name to "_main" if required.
This is set as an observer of inferior_created. */
+
static void
arc_set_main_name (struct target_ops *objfile, int from_tty)
{
- struct minimal_symbol *umainsym, *mainsym;
-
- /* Old ARC toolchains prepend an underscore to symbol names. If there is
- an _main but no main, then we're probably debugging a binary that was
- made with the old toolchain. */
- umainsym = lookup_minimal_symbol ("_main", NULL, NULL);
- mainsym = lookup_minimal_symbol ("main", NULL, NULL);
- if(umainsym && !mainsym)
+ /* Old ARC toolchains prepend an underscore to symbol names. If there is
+ an _main but no main, then we're probably debugging a binary that was
+ made with the old toolchain. */
+ struct minimal_symbol *umainsym = lookup_minimal_symbol ("_main", NULL, NULL);
+ struct minimal_symbol *mainsym = lookup_minimal_symbol ("main", NULL, NULL);
+
+ if ((umainsym != NULL) && (mainsym == NULL))
{
- set_main_name ("_main");
+ set_main_name ("_main");
}
- /* If we don't have any symbols, the default, i.e. "main", will get used. */
+ /* If we don't have any symbols, the default, i.e. "main", will get used. */
}
-/* The following piece of code is borrowed from d10v */
-static void
-a4_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr)
+/* This initialization function is called by gdb.
+ See gdbarch.h for a description of its parameters. */
+
+static struct gdbarch*
+arc_gdbarch_init (struct gdbarch_info info,
+ struct gdbarch_list *arches)
{
-#ifdef ARC4_JTAG
- if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
- || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
- store_unsigned_integer (buf, TYPE_LENGTH (type), (addr>>2) & 0xffffff);
- else
- store_unsigned_integer (buf, TYPE_LENGTH (type), addr);
+ /* Allocate the ARC-private target-dependent information structure, and the
+ gdb target-independent information structure. */
+ struct gdbarch_tdep *tdep = xmalloc (sizeof (struct gdbarch_tdep));
+ struct gdbarch *gdbarch = gdbarch_alloc (&info, tdep);
+
+ memset(tdep, 0, sizeof(*tdep));
+
+ /* Put stuff in gdbarch. */
+
+ /* Breakpoint manipulation. */
+ set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc);
+ set_gdbarch_decr_pc_after_break (gdbarch, 0);
+
+ info.osabi = CONFIG_OSABI;
+ gdbarch_init_osabi(info, gdbarch);
+
+ /* Characters are unsigned by default. */
+ set_gdbarch_char_signed (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM);
+ set_gdbarch_register_type (gdbarch, arc_register_type);
+ set_gdbarch_print_float_info (gdbarch, arc_print_float_info);
+
+ /* Advance PC across function entry code. */
+ set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);
+
+ /* Hook in the Dwarf-2 frame sniffer. */
+ dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+
+ /* Signal frames. */
+ frame_unwind_append_sniffer (gdbarch, arc_sigtramp_frame_sniffer);
+
+ /* The stack grows downward. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp);
+ set_gdbarch_unwind_dummy_id (gdbarch, arc_unwind_dummy_id);
+ frame_unwind_append_sniffer (gdbarch, arc_frame_sniffer);
+ set_gdbarch_return_value (gdbarch, arc_return_value);
+
+ /* Add the ARC register groups. */
+ reggroup_add (gdbarch, general_reggroup);
+ reggroup_add (gdbarch, all_reggroup);
+ reggroup_add (gdbarch, system_reggroup);
+
+ set_gdbarch_register_reggroup_p (gdbarch, arc_register_reggroup_p);
+
+ set_gdbarch_cannot_step_breakpoint (gdbarch, 1);
+ set_gdbarch_frame_align(gdbarch, arc_frame_align);
+
+ /* Dummy Frame handling. */
+ set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call);
+ set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
+
+ /* N.B. we do not want to call arcompact_get_disassembler at this point, as we do
+ not as yet have an executable file, so do not know whether we want
+ the disassembler for the A4 architecture (still supported by the
+ opcodes library!) or the one for the ARCompact architecture; also,
+ it is better to pass the arcompact_get_disassembler function a valid bfd
+ structure, rather than a faked one, so that it can read the ARC-
+ specific sections in the ELF file (for whatever reason...).
+
+ So just set up a dummy disassembler at this point (gdb requires that
+ *some* disassembler is defined for an architecture), and set up a
+ callback which will set up the appropriate disassembler once an
+ executable file has been selected for debugging. */
+
+#if 0
+ {
+ /* The arc libopcodes wants abfd so that it can find out what CPU
+ extensions are there. */
+ bfd abfd;
+
+ abfd.sections = NULL;
+
+ set_gdbarch_print_insn(gdbarch, arcompact_get_disassembler(&abfd));
+ }
#endif
+ set_gdbarch_print_insn(gdbarch, dummy_disassembler);
+ (void) observer_attach_new_objfile(set_disassembler);
+
+ /* Set main_name to _main if necessary. Ideally we'd want a hook that
+ gets called when symbols are loaded, but it seems there isn't one; so
+ we'll use this. This will not work if the user does "target remote
+ ..." and then "add-symbol-file ...". */
+ (void) observer_attach_inferior_created (arc_set_main_name);
+
+ /* Initialize the target-dependent modules (if any). */
+ CONFIG_INIT_TDEP
+
+ /* Return a pointer to the new object - indicates that a new architecture
+ has been created. */
+ return gdbarch;
}
-static CORE_ADDR
-a4_pointer_to_address (struct type *type, const void *buf)
+
+static void
+arc_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
{
-#ifdef ARC4_JTAG
- CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH(type));
- /* Is it a code address? */
- if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
- || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
- || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type)))
- return ((addr<<2) & 0x2ffffff);
- else
- return addr;
-#endif
+ /* Do nothing. */
}
-static struct gdbarch *
-arc_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+
+/* -------------------------------------------------------------------------- */
+/* local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+
+/* <command> [ <frame> ]
+ Display annotated stack frame. */
+
+static void
+arc_show_stack_frame_command (char *arg, int from_tty)
{
- struct gdbarch_tdep *tdep;
- struct gdbarch *gdbarch;
+ struct frame_info *fi;
+ gdb_byte value[MAX_REGISTER_SIZE];
+ CORE_ADDR pc, fp, sp, old_sp;
+ CORE_ADDR addr;
+ enum lval_type lval;
+ int optimized;
+ int realnum;
+ int frame_size;
+ unsigned int *frame_contents;
+ LocalVariable *variables;
+ unsigned int num_variables;
+
+ /* Find the frame. */
+ fi = parse_frame_specification_1 (arg, _("No stack."), NULL);
+ gdb_assert(fi != NULL);
+
+ /* Find out PC, FP and SP for the frame. */
+ pc = get_frame_pc(fi);
+ sp = get_frame_sp(fi);
+ get_frame_register(fi, ARC_FP_REGNUM, value);
+ fp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER);
+
+ DEBUG("*** PC = %x, FP = %x, SP = %x\n", (unsigned int) pc, (unsigned int) fp, (unsigned int) sp);
+
+ if (pc == 0)
+ {
+ warning(_("invalid frame"));
+ return;
+ }
- tdep = xmalloc (sizeof (struct gdbarch_tdep));
- gdbarch = gdbarch_alloc (&info, tdep);
-
- /* Fixme :: Worry about default initialization of breakpoints
- for the ARC platform. In our case currently this is handled
- out of arc-linux-tdep.c for default arc linux breakpoints.
- */
+ frame_register_unwind (fi, ARC_SP_REGNUM, &optimized, &lval, &addr, &realnum, value);
+ old_sp = (CORE_ADDR) extract_unsigned_integer (value, BYTES_IN_REGISTER);
- info.osabi = CONFIG_OSABI;
- gdbarch_init_osabi(info, gdbarch);
-
- /* Put stuff in gdbarch. */
+ /* Find the local variables and parameters. */
+ variables = find_local_variables(fi, &num_variables);
- /* Characters are unsigned by default */
- set_gdbarch_char_signed (gdbarch, 0);
+ printf_filtered(NEW_LINE);
+ identify_frame(fi);
- set_gdbarch_print_float_info (gdbarch, arc_print_float_info);
- set_gdbarch_sp_regnum (gdbarch, ARC_SP_REGNUM);
- set_gdbarch_register_type (gdbarch, arc_register_type);
+ DEBUG(_("\n\n*** FRAME: 0x%x .. 0x%x\n\n"), (unsigned int) sp, (unsigned int) (old_sp - 1));
- set_gdbarch_cannot_store_register (gdbarch, arc_cannot_store_register);
+ frame_size = (int) (old_sp - sp);
+ frame_contents = xmalloc((size_t) frame_size);
- /* Advance PC across function entry code. */
- set_gdbarch_skip_prologue (gdbarch, arc_skip_prologue);
+ if (frame_contents)
+ {
+ /* Read all of the frame's contents from target memory. */
+ if (target_read_memory(sp, (gdb_byte*) frame_contents, frame_size) == 0)
+ {
+ int numregs = ARC_TOTAL_REGS;
+ int i = frame_size / BYTES_IN_WORD - 1;
+ unsigned int the_same = 0;
+ unsigned int previous_word = 0;
+ Boolean first_word = TRUE;
+ Boolean is_following_element;
+ Boolean elements_are_word_sized;
-
- /* Hook in the Dwarf-2 frame sniffer. */
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, arc_binutils_reg_to_regnum);
- dwarf2_frame_set_init_reg (gdbarch, arc_dwarf2_frame_init_reg);
- frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+ addr = old_sp - BYTES_IN_WORD;
- /* signal frames */
- frame_unwind_append_sniffer (gdbarch, arc_sigtramp_frame_sniffer);
+ printf_filtered(NEW_LINE);
+ /* Traverse the frame from high address to low address, one word at a time. */
+ while (i >= 0)
+ {
+ unsigned int this_word = frame_contents[i];
+ Boolean print = first_word; /* Always print the first word. */
+ char line[256];
+ int n;
+ /* Start with a blank line. */
+ (void) memset(line, (int) ' ', sizeof(line));
- /* The stack grows downward. */
- set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ /* Does FP and/or SP address this particular stack location? */
+ if (addr == sp && fp == sp)
+ {
+ (void) strcpy(line + 14, _("SP/FP ===> "));
+ line[25] = ' ';
+ print = TRUE;
+ }
+ else if (addr == sp)
+ {
+ (void) strcpy(line + 17, _("SP ===> "));
+ line[25] = ' ';
+ print = TRUE;
+ }
+ else if (addr == fp)
+ {
+ (void) strcpy(line + 17, _("FP ===> "));
+ line[25] = ' ';
+ print = TRUE;
+ }
- set_gdbarch_unwind_pc (gdbarch, arc_unwind_pc);
- set_gdbarch_unwind_sp (gdbarch, arc_unwind_sp);
- set_gdbarch_unwind_dummy_id (gdbarch, arc_unwind_dummy_id);
- frame_unwind_append_sniffer (gdbarch, arc_frame_sniffer);
-
+ /* Does this stack location hold a local variable or parameter? */
+ if ((add_local_name(line + 38,
+ addr,
+ variables,
+ num_variables,
+ &is_following_element,
+ &elements_are_word_sized)))
+ {
+ /* Yes - so we want to print it (but this may be revised below!). */
+ print = TRUE;
+ }
+ else
+ {
+ int r;
+
+ /* Does this location hold a saved register? */
+ for (r = 0; r < numregs; r++)
+ {
+ if (r != ARC_SP_REGNUM &&
+ gdbarch_register_reggroup_p (current_gdbarch, r, all_reggroup))
+ {
+ CORE_ADDR saved_addr;
+
+ /* Find out the location of the saved register without
+ fetching the corresponding value. */
+ frame_register_unwind (fi, r, &optimized, &lval, &saved_addr, &realnum, NULL);
+
+ if (!optimized && lval == lval_memory && saved_addr == addr)
+ {
+ (void) sprintf(line + 38, _("saved register '%s'"), gdbarch_register_name(current_gdbarch, r));
+ print = TRUE;
+ break;
+ }
+ }
+ }
+ }
- set_gdbarch_return_value (gdbarch, arc_return_value);
+ /* Do we think we need to print out the line? */
+ if (print)
+ {
+ /* If the location is a non-zeroth word-sized array element,
+ and this word is the same as the previous word. */
+ if (is_following_element && elements_are_word_sized && (this_word == previous_word))
+ {
+ /* No need to print it - one more word the same! */
+ the_same++;
+ print = FALSE;
+ }
+ }
+ else
+ {
+ /* N.B. this will not be the first word (since print is FALSE) */
+
+ /* This location does not hold anything "interesting", but
+ if this word is not the same as the previous word, we
+ want to print it. */
+ if (this_word == previous_word)
+ the_same++;
+ else
+ print = TRUE;
+ }
- /* Add the arc register groups. */
- arc_add_reggroups (gdbarch);
- set_gdbarch_register_reggroup_p (gdbarch, arc_register_reggroup_p);
-
- /* Breakpoint manipulation. */
- set_gdbarch_breakpoint_from_pc (gdbarch, arc_breakpoint_from_pc);
- set_gdbarch_frame_align(gdbarch,arc_frame_align);
+ /* OK, now we really know whether we need to print out the line. */
+ if (print)
+ {
+ n = sprintf(line, _("0x%08X:"), (unsigned int) addr);
+ line[n] = ' ';
+
+ n = sprintf(line + 25, "%08X", this_word);
+ line[25 + n] = ' ';
+
+ n = (int) sizeof(line) - 1;
+ while (line[n] == ' ') n--;
+ line[n + 1] = '\0';
+
+ /* If we did not print the previous word because it was the
+ same as the word before, but not the same as any preceding
+ words, print it now (there is no point in outputting a
+ message which says simply "... 1 words omitted" - we might
+ just as well print out the word! */
+ if (the_same == 1)
+ printf_filtered(_("0x%08X: %08X\n"), (unsigned int) addr + BYTES_IN_WORD, previous_word);
+ else if (the_same != 0)
+ /* 2 or more words the same... */
+ printf_filtered(_("... %u words omitted\n"), the_same);
+
+ /* Now print out the line with the current word (and other information). */
+ printf_filtered(_("%s\n"), line);
+
+ /* No words omitted. */
+ the_same = 0;
+ }
- /* Dummy Frame handling */
- set_gdbarch_push_dummy_call (gdbarch, arc_push_dummy_call);
- set_gdbarch_call_dummy_location (gdbarch,AT_ENTRY_POINT);
-
- /* Disassembly. */
- {
- /* the arc libopcodes wants abfd so that it can find out what CPU
- extensions are there */
- bfd abfd;
- abfd.sections = NULL;
+ first_word = FALSE;
+ previous_word = this_word;
+ addr -= BYTES_IN_WORD;
+ i--;
+ }
-#ifndef ARC4_JTAG
- set_gdbarch_print_insn(gdbarch, arcompact_get_disassembler(&abfd));
-#else
- set_gdbarch_print_insn(gdbarch, arc_get_disassembler(&abfd));
-#endif
- }
+ printf_filtered(NEW_LINE);
+ }
-#ifdef ARC4_JTAG
- set_gdbarch_address_to_pointer (gdbarch, a4_address_to_pointer);
- set_gdbarch_pointer_to_address (gdbarch, a4_pointer_to_address);
-#endif
- //#ifndef ARC4_JTAG
- /* Set main_name to _main if necessary. Ideally we'd want a hook that
- gets called when symbols are loaded, but it seems there isn't one; so
- we'll use this. This will not work if the user does "target remote
- ..." and then "add-symbol-file ..." */
- observer_attach_inferior_created (arc_set_main_name);
- //#endif
-
-#ifdef ARC4_JTAG
- // set_gdbarch_write_pc (gdbarch, a4_write_pc);
-#endif
+ xfree(frame_contents);
+ }
- CONFIG_INIT_TDEP (gdbarch);
-
- return gdbarch;
+ xfree(variables);
}
-static void
-arc_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+void
+_initialize_arc_tdep (void)
{
+ /* Register the ARC processor architecture with gdb, providing an
+ initialization function and a dump function; 'bfd_arch_arc' is
+ an enumeration value specifically denoting the ARC architecture. */
+ gdbarch_register(bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);
+
+ /* Register ARC-specific commands with gdb. */
+
+ add_setshow_boolean_cmd(DEBUG_COMMAND,
+ no_class,
+ &arc_debug_target,
+ _("Set whether to print ARC debug messages.\n"),
+ _("Show whether to print ARC debug messages.\n"),
+ _("If set debug messages are printed.\n"),
+ NULL,
+ NULL,
+ &setlist,
+ &showlist);
+
+ (void) add_cmd(SHOW_FRAME_COMMAND,
+ class_obscure,
+ arc_show_stack_frame_command,
+ _("Display the stack frame with annotation.\n"
+ SHOW_FRAME_COMMAND_USAGE
+ "<FRAME> may be the number or address of a frame.\n"),
+ &cmdlist);
}
+
+/* Initialize the info structure to enable the disassembler to be used. */
+
void
-_initialize_arc_tdep (void)
+arc_initialize_disassembler (struct disassemble_info *info)
{
- gdbarch_register (bfd_arch_arc, arc_gdbarch_init, arc_dump_tdep);
+ /* N.B. this type cast is not strictly correct: the return types differ! */
+ init_disassemble_info(info, gdb_stdout, (fprintf_ftype) fprintf_filtered);
+ info->arch = gdbarch_bfd_arch_info(current_gdbarch)->arch;
+ info->mach = gdbarch_bfd_arch_info(current_gdbarch)->mach;
+ info->endian = gdbarch_byte_order (current_gdbarch);
+ info->read_memory_func = read_memory_for_disassembler;
}
+/******************************************************************************/
diff --git a/gdb/arc-tdep.h b/gdb/arc-tdep.h
index 4251eb41203..8f330727128 100644
--- a/gdb/arc-tdep.h
+++ b/gdb/arc-tdep.h
@@ -1,109 +1,148 @@
-/* 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.
Contributed by Codito Technologies Pvt. Ltd. (www.codito.com)
- Authors:
- Soam Vasani <soam.vasani@codito.com>
- Ramana Radhakrishnan <ramana.radhakrishnan@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.
-*/
-enum arc700_api_regnums
- {
- ARC_ARG0_REGNUM = 0,
- ARC_ARG1_REGNUM = 1,
- ARC_ARG2_REGNUM = 2,
- ARC_ARG3_REGNUM = 3,
- ARC_ARG4_REGNUM = 4,
- ARC_ARG5_REGNUM = 5,
- ARC_ARG6_REGNUM = 6,
- ARC_ARG7_REGNUM = 7,
-
- /* When a return value is stored in registers, is in either r0 or in
- (r1,r0). Used in arc_extract_return_value */
- ARC_RETURN1_REGNUM = 0,
- ARC_RETURN2_REGNUM = 1
- };
-
-
-
-enum ARCProcessorVersion
- {
- UNSUPPORTED,
- ARCompact,
- ARC600,
- ARC700,
- A5,
- A4,
- };
-
-
-enum ARCExtensionsSupportedInformation
- {
- ARC700_MMU
- };
-
-
-
-typedef struct ARCProcessorInformation
-{
- enum ARCProcessorVersion arcprocessorversion;
- enum ARCExtensionsSupportedInformation extensionsSupported;
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This header file defines some target-dependent information which is */
+/* specific to the ARC gdb port. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_TDEP_H
+#define ARC_TDEP_H
+
+/* ARC header files */
+#include "arc-support.h"
+
+
+#define ARC_PC_REGNUM (gdbarch_pc_regnum (current_gdbarch))
+#define ARC_NUM_REGS (gdbarch_num_regs (current_gdbarch))
+#define ARC_NUM_PSEUDO_REGS (gdbarch_num_pseudo_regs (current_gdbarch))
+#define ARC_TOTAL_REGS (ARC_NUM_REGS + ARC_NUM_PSEUDO_REGS)
+
+
+#define ARC_MAX_CORE_REGS 64
+#define ARC_FIRST_EXTENSION_CORE_REGISTER 32
+#define ARC_LAST_EXTENSION_CORE_REGISTER 59
+#define ARC_NUM_EXTENSION_CORE_REGS (ARC_LAST_EXTENSION_CORE_REGISTER - ARC_FIRST_EXTENSION_CORE_REGISTER + 1)
+#define ARC_NUM_STANDARD_CORE_REGS (ARC_MAX_CORE_REGS - ARC_NUM_EXTENSION_CORE_REGS)
+
+
+#define IS_EXTENSION_CORE_REGISTER(hw_regnum) (ARC_FIRST_EXTENSION_CORE_REGISTER <= (hw_regnum) && (hw_regnum) <= ARC_LAST_EXTENSION_CORE_REGISTER)
+
+
+/* ARC processor ABI-related registers:
+ R0 .. R7 are the registers used to pass arguments in function calls
+ R13 .. R26 are the callee-saved registers
+ when a return value is stored in registers it is in either R0 or in the pair (R0,R1). */
+
+#define ARC_ABI_GLOBAL_POINTER 26
+#define ARC_ABI_FRAME_POINTER 27
+#define ARC_ABI_STACK_POINTER 28
-}ARCVariantsInfo;
+#define ARC_ABI_FIRST_CALLEE_SAVED_REGISTER 13
+#define ARC_ABI_LAST_CALLEE_SAVED_REGISTER 26
+
+#define ARC_ABI_FIRST_ARGUMENT_REGISTER 0
+#define ARC_ABI_LAST_ARGUMENT_REGISTER 7
+#define ARC_ABI_REGISTER_PARAMETER_SPACE ((ARC_ABI_LAST_ARGUMENT_REGISTER - ARC_ABI_FIRST_ARGUMENT_REGISTER + 1) * BYTES_IN_REGISTER)
+
+#define ARC_ABI_RETURN_REGNUM 0
+#define ARC_ABI_RETURN_LOW_REGNUM 0
+#define ARC_ABI_RETURN_HIGH_REGNUM 1
+
+#define IS_ARGUMENT_REGISTER(hw_regnum) (ARC_ABI_FIRST_ARGUMENT_REGISTER <= (hw_regnum) && (hw_regnum) <= ARC_ABI_LAST_ARGUMENT_REGISTER)
+
+
+/* This type is completed in the files arc-elf32-tdep.h and arc-linux-tdep.h,
+ as apppropriate for the arc-elf2 and arc-uclinux builds of gdb. */
+typedef struct arc_variant_info ARC_VariantsInfo;
+
+
+#define REGISTER_NOT_PRESENT (-1) // special value for sc_reg_offset[reg]
+
+
+/* N.B. this assumes that the host is little-endian! */
+#define HOST_AND_TARGET_ENDIANNESS_DIFFER(arch) (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
+
+
+/* This structure holds target-dependent information.
+
+ N.B. this type is used in the target-independent gdb code, but it is treated
+ as an opaque (or private) type: the only use of it is by pointers to
+ objects of this type (passed as parameters or returned as results, or
+ held in other structures); it is only the ARC-specific modules that
+ have knowledge of the structure of this type and access its fields. */
struct gdbarch_tdep
{
- /* Detect sigtramp. */
- int (*sigtramp_p) (struct frame_info *);
-
- /* Get address of sigcontext for sigtramp. */
- CORE_ADDR (*sigcontext_addr) (struct frame_info *);
-
- /* Offset of registers in `struct sigcontext'. */
- int *sc_reg_offset;
- int sc_num_regs;
-
- /* In our linux target, gdbarch_pc_regnum points to stop_pc, which is a
- register that's made-up by the kernel and does not actually exist.
- stop_pc is NOT saved in the sigcontext; what is saved is the ret
- "register". Since ret is a linux-only register, it's regnum is visible
- only in arc-linux-tdep.c; hence initialize pc_regnum_in_sigcontext in
- arc-linux-tdep.c. */
- int pc_regnum_in_sigcontext;
-
- /* Returns false, true, or -1; -1 means the tdep has nothing to say about this
- register and group. */
- int (*register_reggroup_p) (int, struct reggroup *);
-
- /* Breakpoint instruction to be used */
- unsigned char * arc_breakpoint_insn;
- int arc_breakpoint_size;
-
- /* For stopping backtraces. */
- CORE_ADDR lowest_pc;
-
- /* ARC Processor variant information. */
- ARCVariantsInfo * arc_processor_variant_info ;
-
+ /* Detect sigtramp. */
+ Boolean (*is_sigtramp) (struct frame_info*);
+
+ /* Get address of sigcontext for sigtramp. */
+ CORE_ADDR (*sigcontext_addr) (struct frame_info*);
+
+ /* Offset of registers in `struct sigcontext'. */
+ const int *sc_reg_offset;
+ unsigned int sc_num_regs;
+
+ /* In our linux target, gdbarch_pc_regnum points to stop_pc, which is a
+ register that is made up by the kernel and does not actually exist.
+ stop_pc is NOT saved in the sigcontext; what is saved is the ret
+ "register". Since ret is a linux-only register, its regnum is visible
+ only in arc-linux-tdep.c; hence initialize pc_regnum_in_sigcontext in
+ arc-linux-tdep.c. */
+ int pc_regnum_in_sigcontext;
+
+ /* 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. */
+ int (*register_reggroup_p) (int regnum, struct reggroup *group);
+
+ /* Breakpoint instruction to be used. */
+ const unsigned char *be_breakpoint_instruction;
+ const unsigned char *le_breakpoint_instruction;
+ unsigned int breakpoint_size;
+
+ /* For stopping backtraces. */
+ CORE_ADDR lowest_pc;
+
+ /* ARC processor variant information (may be NULL). */
+ ARC_VariantsInfo *processor_variant_info;
};
-void arc_software_single_step(enum target_signal ignore, int insert_breakpoints_p);
+/* Utility functions used by other ARC-specific modules. */
+
+void arc_initialize_disassembler (struct disassemble_info *info);
+
+/* A global debug flag. */
+extern Boolean arc_debug_target;
+#endif /* ARC_TDEP_H */
+/******************************************************************************/
diff --git a/gdb/arc-xiss.c b/gdb/arc-xiss.c
new file mode 100755
index 00000000000..2319f36d2a2
--- /dev/null
+++ b/gdb/arc-xiss.c
@@ -0,0 +1,1787 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 creates an instance of a gdb 'target_ops' structure which */
+/* contains information and operations for debugging using the ARC xISS */
+/* (Fast Instruction Set Simulator) as the target. */
+/* */
+/* Instruction Tracing: */
+/* Two different kind of instruction tracing are supported: */
+/* */
+/* 1) a minimal trace which records only the address of each instruction */
+/* which is executed; */
+/* */
+/* 2) a more detailed trace which includes the ordinal number of the */
+/* instruction in the trace, condition code settings, instruction */
+/* address, instruction disassembly, and the values of source and */
+/* destination operands. */
+/* */
+/* The minimal trace is recorded by the xISS in an internal buffer whose */
+/* size may be determined by the gdb user; this buffer wraps around, so */
+/* that only the addresses of the most recently executed instructions are */
+/* held. This data may then be saved to a file for subsequent inspection. */
+/* The trace data is written in an encoding which gives a reduction in */
+/* size of approximately 80% compared to the raw data. */
+/* */
+/* See the manual */
+/* */
+/* ARC GDB-Insight */
+/* GNU Debugger With Insight GUI */
+/* Getting Started */
+/* 6009-001 */
+/* */
+/* for full information on how to use these trace facilities. */
+/* */
+/* Usage: */
+/* The module exports a function _initialize_arc_xiss: the call to this */
+/* function is generated by the gdb build mechanism, so this function */
+/* should not be explicitly called. */
+/* */
+/******************************************************************************/
+
+/* gdb configuration file */
+#include "config.h"
+
+/* This macro should be defined in the configuration file only if the arcint.h
+ file is available. */
+#ifdef HAVE_LIBXISS
+
+/* system header files */
+#include <unistd.h>
+#include <errno.h>
+#include <dlfcn.h>
+
+/* gdb header files */
+#include "defs.h"
+#include "inferior.h"
+#include "disasm.h"
+#include "gdbcmd.h"
+#include "objfiles.h"
+#include "libiberty.h"
+#include "completer.h"
+#include "gdb_assert.h"
+
+/* ARC header files */
+#include "config/arc/tm-embed.h"
+#include "arc-xiss.h"
+#include "arc-tdep.h"
+#include "arc-elf32-tdep.h"
+#include "arc-architecture.h"
+#include "arc-inst-tracing.h"
+#include "arc-registers.h"
+
+/* This must be defined before arcint.h is included. */
+#define OEM_USE_OF_DEBUGGER_HEADER_FILES 1
+
+/* This defines the interface by which the xISS is accessed. */
+#include "arcint.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local types */
+/* -------------------------------------------------------------------------- */
+
+typedef struct ARC* (*ARC_Interface)(void);
+
+typedef enum
+{
+ XISS_HALTED,
+ XISS_STEPPED,
+ XISS_TO_BE_RUN
+} ExecutionStatus;
+
+
+/* N.B. this is taken from arcint.cpp; there must be a better way of doing this! */
+struct ARC
+{
+ ARC_functab *pftp; /* Pointer to interface function table. */
+};
+
+typedef void* WatchpointCookie;
+
+typedef struct _association
+{
+ WatchpointCookie cookie;
+ CORE_ADDR addr;
+ int length;
+ int type;
+} Association;
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define ARC_TARGET_NAME "arcxiss"
+#define ARC_INTERFACE "get_ARC_interface"
+
+#define SAVE_TRACE_TO_FILE_COMMAND "arc-xiss-save-trace"
+#define EMPTY_TRACE_BUFFER_COMMAND "arc-xiss-empty-trace-buffer"
+#define LIST_TRACE_COMMAND "arc-xiss-list-trace"
+
+#define SAVE_TRACE_TO_FILE_COMMAND_USAGE "Usage: " SAVE_TRACE_TO_FILE_COMMAND " <FILE>\n"
+#define EMPTY_TRACE_BUFFER_COMMAND_USAGE "Usage: " EMPTY_TRACE_BUFFER_COMMAND "\n"
+#define LIST_TRACE_COMMAND_USAGE "Usage: " LIST_TRACE_COMMAND " [ FROM=<VALUE> ] [ TO=<VALUE> ] [ <FILE> ]\n"
+
+
+/* N.B. the xISS does not currently use the context parameter supplied for
+ memory read/write operations, so its value is irrelevant. */
+#define XISS_CONTEXT 0
+
+
+/* The gdb target operations structure for this target. */
+static struct target_ops xISS_target_ops;
+
+/* A set of pointers to operations for reading/writing registers/memory in the
+ xISS target. */
+static TargetOperations operations;
+
+/* Handles for access to the xISS target. */
+static void *xISS_DLL_handle;
+static struct ARC *xiss_instance;
+static ARC_functab *xISS_functions;
+
+/* The status of program execution on the xISS target. */
+static ExecutionStatus xISS_executionStatus;
+
+/* Data for handling instruction tracing. */
+static Boolean xISS_trace_instructions;
+static char *xiss_trace_file;
+static int xiss_trace_buffer_size;
+
+/* This is the table for associating watchpoint details with watchpoint cookies. */
+static Association *associations;
+static unsigned int num_associations;
+
+/* The address of data to which access caused a watchpoint to trigger. */
+static CORE_ADDR stopped_data_address;
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#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)); \
+ result ## _specified = TRUE; \
+ do_cleanups (chain); \
+}
+
+/* This macro must cope with the cases:
+ var = value
+ var =value
+ var= value
+ var=value */
+#define GET_PARAMETER(var) \
+ if (strncasecmp(argv[i], #var "=", sizeof(#var)) == 0) \
+ { \
+ if (argv[i][sizeof(#var)] == '\0') \
+ { \
+ i++; \
+ if (argv[i] == NULL) \
+ invalid = TRUE; \
+ else \
+ { \
+ EXTRACT(argv[i], Ordinal, var) \
+ i++; \
+ } \
+ } \
+ else \
+ { \
+ EXTRACT(argv[i] + sizeof(#var), Ordinal, var) \
+ i++; \
+ } \
+ } \
+ else if (strcasecmp(argv[i], #var) == 0) \
+ { \
+ i++; \
+ if (argv[i] == NULL) \
+ invalid = TRUE; \
+ else \
+ { \
+ if (argv[i][0] == '=') \
+ { \
+ if (argv[i][1] == '\0') \
+ { \
+ i++; \
+ if (argv[i] == NULL) \
+ invalid = TRUE; \
+ else \
+ { \
+ EXTRACT(argv[i], Ordinal, var) \
+ i++; \
+ } \
+ } \
+ else \
+ { \
+ EXTRACT(argv[i] + 1, Ordinal, var) \
+ i++; \
+ } \
+ } \
+ else \
+ invalid = TRUE; \
+ } \
+ }
+
+
+#define CHECK_RANGE(source) \
+{ \
+ if (from_specified) \
+ { \
+ if (from < first || from > last) \
+ { \
+ warning(_("%s contains instruction range %llu .. %llu - using %llu as FROM"), \
+ source, first, last, first); \
+ gdb_flush(gdb_stderr); \
+ from = first; \
+ } \
+ } \
+ else \
+ from = first; \
+ \
+ if (to_specified) \
+ { \
+ if (to < first || to > last) \
+ { \
+ warning(_("%s contains instruction range %llu .. %llu - using %llu as TO"), \
+ source, first, last, last); \
+ gdb_flush(gdb_stderr); \
+ to = last; \
+ } \
+ } \
+ else \
+ to = last; \
+}
+
+
+#define XISS_PROPERTY(key,value) xISS_functions->process_property(xiss_instance, key, value)
+
+#define IS_SUPPORTED(flag) ((xISS_functions->supports_feature(xiss_instance) & (flag)) != 0)
+
+#define XISS_AUX_REG(hw_regno) ((ARC_REG_TYPE) hw_regno + (ARC_REG_TYPE) AUX_BASE)
+#define XISS_CORE_REG(hw_regno) ((ARC_REG_TYPE) hw_regno)
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* -------------------------------------------------------------------------- */
+/* 1) functions for watchpoint table */
+/* -------------------------------------------------------------------------- */
+
+/* These functions implement a linear lookup table which associate an xISS
+ watchpoint cookie with the watchpoint's address, length and type; this is
+ not very efficient, but is quite sufficient for relatively small numbers of
+ watchpoints. If we should need to handle large numbers of watchpoints
+ efficiently, a more sophisticated data structure may be required. */
+
+
+/* Add an association to the table. */
+
+static void
+associate (WatchpointCookie cookie, CORE_ADDR addr, int length, int type)
+{
+ Association *new = NULL;
+ unsigned int i;
+
+ for (i = 0; i < num_associations; i++)
+ {
+ Association *association = &associations[i];
+
+ if (association->cookie == NULL)
+ {
+ new = association;
+ break;
+ }
+ }
+
+ if (new == NULL)
+ {
+ Association *new_associations = xrealloc(associations, sizeof(Association) * (num_associations + 1));
+
+ if (new_associations == NULL)
+ nomem(0);
+
+ associations = new_associations;
+ new = &new_associations[num_associations];
+ num_associations++;
+ }
+
+ new->cookie = cookie;
+ new->addr = addr;
+ new->length = length;
+ new->type = type;
+}
+
+
+/* Remove an association from the table, returning the cookie. */
+
+static WatchpointCookie
+disassociate (CORE_ADDR addr, int length, int type)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_associations; i++)
+ {
+ Association *association = &associations[i];
+
+ if (association->addr == addr &&
+ association->length == length &&
+ association->type == type)
+ {
+ WatchpointCookie cookie = association->cookie;
+
+ association->cookie = NULL;
+ return cookie;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Find the address associated with a cookie. */
+
+static CORE_ADDR
+find (WatchpointCookie cookie)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_associations; i++)
+ {
+ Association *association = &associations[i];
+
+ if (association->cookie == cookie)
+ return association->addr;
+ }
+
+ return 0;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 2) functions for reading/writing registers */
+/* -------------------------------------------------------------------------- */
+
+/* N.B. the register contents returned by these functions, or supplied to them,
+ are in host byte order - the arcint.cpp interface to the xISS requires
+ this. */
+
+/* Read a core register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the read fails
+
+ Result: TRUE if the register contents are read. */
+
+static Boolean
+read_xiss_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure)
+{
+ unsigned long value;
+ int result = xISS_functions->read_reg(xiss_instance, XISS_CORE_REG(hw_regno), &value);
+
+ if (result == 1)
+ {
+ *contents = (ARC_RegisterContents) value;
+ DEBUG("Read value 0x%08X from core register %d\n", *contents, hw_regno);
+ return TRUE;
+ }
+
+ if (warn_on_failure)
+ arc_elf32_core_warning(ERROR_ON_READING_REGISTER, hw_regno);
+ return FALSE;
+}
+
+
+/* Write a core register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the write fails
+
+ Result: TRUE if the register contents are written. */
+
+static Boolean
+write_xiss_core_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure)
+{
+ int result = xISS_functions->write_reg(xiss_instance, XISS_CORE_REG(hw_regno), (unsigned long) contents);
+
+ if (result == 1)
+ {
+ DEBUG("Written value 0x%08X to core register %d\n", contents, hw_regno);
+ return TRUE;
+ }
+
+ if (warn_on_failure)
+ arc_elf32_core_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
+ return FALSE;
+}
+
+
+/* Read an auxiliary register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : set to the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the read fails
+
+ Result: TRUE if the register contents are read. */
+
+static Boolean
+read_xiss_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents *contents,
+ Boolean warn_on_failure)
+{
+ unsigned long value;
+ int result = xISS_functions->read_reg(xiss_instance, XISS_AUX_REG(hw_regno), &value);
+
+ if (result == 1)
+ {
+ *contents = (ARC_RegisterContents) value;
+ DEBUG("Read value 0x%08X from auxiliary register %d\n", *contents, hw_regno);
+ return TRUE;
+ }
+
+ if (warn_on_failure)
+ arc_elf32_aux_warning(ERROR_ON_READING_REGISTER, hw_regno);
+ return FALSE;
+}
+
+
+/* Write an auxiliary register on the target.
+
+ Parameters:
+ hw_regno : the ARC hardware number of the register
+ value : the contents of the register
+ warn_on_failure: TRUE if a warning should be issued if the write fails
+
+ Result: TRUE if the register contents are written. */
+
+static Boolean
+write_xiss_aux_register (ARC_RegisterNumber hw_regno,
+ ARC_RegisterContents contents,
+ Boolean warn_on_failure)
+{
+ ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno);
+ int result;
+
+ if (def)
+ contents = arc_write_value(def, contents);
+
+ result = xISS_functions->write_reg(xiss_instance, XISS_AUX_REG(hw_regno), (unsigned long) contents);
+
+ if (result == 1)
+ {
+ DEBUG("Written value 0x%08X to auxiliary register %d\n", contents, hw_regno);
+ return TRUE;
+ }
+
+ if (warn_on_failure)
+ arc_elf32_aux_warning(ERROR_ON_WRITING_REGISTER, hw_regno);
+ return FALSE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 3) functions for reading/writing memory */
+/* -------------------------------------------------------------------------- */
+
+/* These functions should NOT be used within this module: they are intended
+ purely for use by the arc-memory module for reading/writing multiple words
+ of data at word-aligned addresses. */
+
+static unsigned int
+read_words (ARC_Address address,
+ ARC_Byte *data,
+ unsigned int words)
+{
+ DEBUG("reading %u words from 0x%08X in xISS\n", words, address);
+
+ gdb_assert(IS_WORD_ALIGNED(address));
+
+ return (unsigned int) xISS_functions->read_memory
+ (xiss_instance,
+ (unsigned long) address,
+ data,
+ (unsigned long) words * BYTES_IN_WORD,
+ XISS_CONTEXT);
+}
+
+
+static unsigned int
+write_words (ARC_Address address,
+ ARC_Byte *data,
+ unsigned int words)
+{
+ gdb_assert(IS_WORD_ALIGNED(address));
+
+ DEBUG("writing %u words to 0x%08X in xISS\n", words, address);
+
+ return (unsigned int) xISS_functions->write_memory
+ (xiss_instance,
+ (unsigned long) address,
+ data,
+ (unsigned long) words * BYTES_IN_WORD,
+ XISS_CONTEXT);
+}
+
+
+static unsigned int
+write_pattern (ARC_Address address,
+ ARC_Word pattern,
+ unsigned int words)
+{
+ gdb_assert(IS_WORD_ALIGNED(address));
+
+ DEBUG("writing pattern 0x%08X repeated %u times to 0x%08X in xISS\n", pattern, words, address);
+
+ return (unsigned int) xISS_functions->fill_memory
+ (xiss_instance,
+ (unsigned long) address,
+ &pattern,
+ BYTES_IN_WORD,
+ (unsigned int) words,
+ XISS_CONTEXT);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 4) functions for xISS interface management */
+/* -------------------------------------------------------------------------- */
+
+/* Open the interface to the debug target.
+
+ Parameters:
+ systemfile: the .xis file defining the simulated target
+ from_tty : non-zero if the 'target' command was issued at the terminal
+*/
+
+static Boolean
+open_xISS_interface (const char *systemfile, int from_tty)
+{
+ const char *xiss_home = getenv("XISS_HOME");
+ char library[FILENAME_MAX];
+ ARC_Interface arc_interface;
+
+ if (xiss_home == NULL)
+ error(_("Environment variable XISS_HOME is not set"));
+
+ /* Construct the path to the xISS .so file. */
+ (void) snprintf(library, sizeof(library), "%s/lib/libxiss.so", xiss_home);
+
+ /* Try to dynamically load the shared object library containing the xISS. */
+ xISS_DLL_handle = dlopen(library, RTLD_LAZY);
+
+ if (xISS_DLL_handle == NULL)
+ {
+ const char *diagnostic = dlerror();
+
+ if (strstr(diagnostic, library))
+ error(_("Can not open xISS shared library %s"), diagnostic);
+ else
+ error(_("Can not open xISS shared library %s: %s"), library, diagnostic);
+ }
+
+ /* Find the function in the library which will create an instacne of the xISS. */
+ arc_interface = dlsym(xISS_DLL_handle, ARC_INTERFACE);
+
+ if (arc_interface == NULL)
+ error(_("Can not find function %s in xISS shared library %s"), ARC_INTERFACE, library);
+
+ /* Create an xISS instance. */
+ xiss_instance = arc_interface();
+
+ if (xiss_instance == NULL)
+ error(_("Can not create instance of xISS"));
+
+ /* Get a pointer to the table of functions provided by the interface. */
+ xISS_functions = xiss_instance->pftp;
+
+ DEBUG("xISS interface : %s\n", xISS_functions->id(xiss_instance));
+ DEBUG("xISS interface version: %d\n", xISS_functions->version(xiss_instance));
+
+ /* Tell the xISS what system file to use to define the simulated target. */
+ if (XISS_PROPERTY("xiss_sys", systemfile) != 1)
+ error(_("xISS could not process 'xiss_sys' property"));
+
+ if (IS_SUPPORTED(ARC_FEATURE_fill_memory))
+ operations.fill_memory = write_pattern;
+
+ (void) xISS_functions->prepare_for_new_program(xiss_instance, 1);
+
+ /* This is somewhat inelegant, but commands read from scripts in the gdb
+ testsuite are regarded as though they were being input interactively
+ (i.e. from_tty is 1), and interactive queries may be made (such as
+ asking the user whether the program currently being debugged should be
+ killed first) - and these queries hang the tests!
+
+ So, if the environment variable is set, assume that the gdb test suite is
+ being run, so that no such queries will be made.
+
+ It is not possible to make this check in the top-level command handler
+ loop, as the output from some other commands (e.g. 'file') depend on the
+ from_tty parameter passed to them, and the gdb test scripts expect to get
+ the interactive version of the output! */
+ target_preopen(from_tty && (getenv("ARC_GDB_TEST") == NULL));
+
+ return TRUE;
+}
+
+
+/* Close the JTAG interface to the debug target.
+
+ Parameter:
+ resume: TRUE if program execution on the target should be allowed to resume. */
+
+static void
+close_xISS_interface (Boolean resume)
+{
+ /* If we have a target connected. */
+ if (xiss_instance != NULL)
+ {
+ /* It is meaningless to resume execution of the xISS. */
+ arc_elf32_close(FALSE);
+
+ /* If we are doing instruction tracing. */
+ if (xiss_trace_file)
+ {
+ /* Ensure that the trace file is closed. */
+ if (XISS_PROPERTY("trace_file", "") != 1)
+ error(_("xISS could not process 'trace_file' property"));
+ }
+
+ /* Close the connection. */
+ xISS_functions->destroy(xiss_instance);
+
+ /* Close the library. */
+ if (dlclose(xISS_DLL_handle) != 0)
+ warning(_("error on closing xISS shared library: %s"), dlerror());
+
+ xiss_instance = NULL;
+ xISS_functions = NULL;
+ xISS_DLL_handle = NULL;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 5) functions for starting/stopping the processor */
+/* -------------------------------------------------------------------------- */
+
+/* Run the xISS for whatever quantum of instructions that it executes. */
+static void
+run_processor (void)
+{
+ int result = xISS_functions->run(xiss_instance);
+
+ if (result == 0)
+ warning(_("could not run"));
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 6) local functions called from outside this module (from gdb) */
+/* -------------------------------------------------------------------------- */
+
+/* Connect to the xISS target.
+
+ Parameters:
+ args : user arguments to the 'target' command
+ from_tty: non-zero if the 'target' command was issued at the terminal
+
+ The arguments may be: <XIS_system_file>
+
+ If the name of a system file is not specified, a file 'default.xis' is
+ assumed. */
+
+static void
+arc_xISS_open (char *args, int from_tty)
+{
+ char *systemfile = (args) ? args : "default.xis";
+
+ ENTERARGS("\"%s\" (%d)", (args) ? args : "", from_tty);
+
+ if (access(systemfile, R_OK) != 0)
+ {
+ char *file = getenv("XISS_SYSTEM_FILE");
+
+ if (file == NULL)
+ error(_("Invalid xISS system file '%s': %s"), systemfile, strerror(errno));
+ else
+ if (access(file, R_OK) != 0)
+ error(_("Invalid xISS system file '%s': %s"), file, strerror(errno));
+ else
+ systemfile = file;
+ }
+
+ arc_program_is_loaded = FALSE;
+
+ xISS_trace_instructions = FALSE;
+ xiss_trace_file = NULL;
+ xISS_executionStatus = XISS_HALTED;
+ xiss_trace_buffer_size = 0;
+
+ num_associations = 0;
+ associations = NULL;
+
+ /* Find any well-known aux register numbers that we will need. */
+ arc_elf32_find_register_numbers();
+
+ /* Just to be sure that it is not in the target stack... */
+ (void) unpush_target (&xISS_target_ops);
+
+ /* Now try to open the xISS interface. */
+ if (open_xISS_interface(systemfile, from_tty))
+ {
+ (void) push_target (&xISS_target_ops);
+
+ if (from_tty)
+ printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n"));
+ }
+ else
+ error(_("Can not connect to target"));
+}
+
+
+/* Close the connection to the target. */
+
+static void
+arc_xISS_close (int quitting) /* Ignored. */
+{
+ ENTERMSG;
+
+ close_xISS_interface(FALSE);
+
+ xfree(associations);
+ associations = NULL;
+ num_associations = 0;
+}
+
+
+/* Cause the inferior on the debug target to resume execution, sending a signal
+ if necessary.
+
+ Parameters:
+ ptid : the thread id of the thread to be resumed (ignored)
+ step : 1 means single step, 0 run freely.
+ signal: the number of the signal to be sent
+
+ N.B. signals are not supported. */
+
+static void
+arc_xISS_resume (ptid_t ptid, int step, enum target_signal signal)
+{
+ ENTERARGS("%d, %d, %d", ptid.pid, step, signal);
+
+ if (signal != TARGET_SIGNAL_0)
+ error(_("Signals are not supported by the " ARC_TARGET_NAME " target"));
+
+ if (step)
+ {
+ int result = xISS_functions->step(xiss_instance);
+
+ if (result == 0)
+ error(_("Can not single-step"));
+ else
+ xISS_executionStatus = XISS_STEPPED;
+ }
+ else
+ xISS_executionStatus = XISS_TO_BE_RUN;
+
+ LEAVEMSG;
+}
+
+
+/* Wait for execution on the target to halt (for whatever reason).
+
+ Parameters :
+ ptid : ignored
+ status: set to indicate status at end of the wait
+*/
+
+static ptid_t
+arc_xISS_wait (ptid_t ptid, struct target_waitstatus *status)
+{
+ ENTERARGS("xISS execution status: %d", xISS_executionStatus);
+
+ /* What was done the last time that execution was resumed? */
+ switch (xISS_executionStatus)
+ {
+ case XISS_STEPPED:
+ DEBUG("processor has stepped\n");
+ status->kind = TARGET_WAITKIND_STOPPED;
+ status->value.sig = TARGET_SIGNAL_TRAP;
+ break;
+
+ case XISS_TO_BE_RUN:
+ arc_elf32_execute(status,
+ run_processor,
+ NULL,
+ NULL);
+
+ if (status->kind == TARGET_WAITKIND_EXITED)
+ target_mark_exited (&xISS_target_ops);
+ break;
+
+ case XISS_HALTED:
+ break;
+ }
+
+ LEAVEMSG;
+
+ return inferior_ptid;
+}
+
+
+/* This gets called just before store_regs. */
+
+static void
+arc_xISS_prepare_to_store (struct regcache *regcache)
+{
+ ENTERMSG;
+}
+
+
+static void
+arc_xISS_files_info (struct target_ops *target)
+{
+ /* Do nothing. */
+ ENTERMSG;
+}
+
+
+/* Heavy duty arsenal. Kill the process. */
+
+static void
+arc_xISS_kill (void)
+{
+ ENTERMSG;
+
+ target_mourn_inferior ();
+}
+
+
+/* Load the program into memory via the xISS interface. */
+
+static void
+arc_xISS_load (char *args, int from_tty)
+{
+ /* The program will be downloaded to the simulator. */
+ (void) xISS_functions->prepare_for_new_program(xiss_instance, 1);
+
+ arc_elf32_load_program(args, from_tty);
+
+ /* Tell xISS that program is fully loaded. */
+ if (XISS_PROPERTY("download_complete", "1") != 1)
+ error(_("xISS could not process 'download_complete' property"));
+
+ /* We now have a program ready for execution on the target. */
+}
+
+
+/* Create the inferior that will be executed upon the target.
+
+ Parameters :
+ exec_file: the executable file containing the program to be executed
+ args : the command line arguments to be passed to the program
+ env : the environment (name/value pairs) for the program
+ from_tty : ignored
+ */
+
+static void
+arc_xISS_create_inferior (char *exec_file, char *args, char **env, int from_tty)
+{
+ arc_elf32_create_inferior(exec_file, args, env, &xISS_target_ops);
+}
+
+
+/* Mourn the inferior. */
+
+static void
+arc_xISS_mourn_inferior (void)
+{
+ ENTERMSG;
+
+// (void) unpush_target (&xISS_target_ops);
+
+ /* N.B. we must delete all breakpoints from the target here: the gdb core
+ function generic_mourn_inferior marks all breakpoints as not being
+ inserted on the target, with the result that subsequent calls to
+ remove_breakpoints will NOT remove any breakpoints that are set on
+ the target; this means that if target execution is re-started, gdb
+ will attempt to re-insert the breakpoints, which causes a problem
+ with software breakpoints: the target insert_breakpoint function
+ reads the code at the b/p address (which is the s/w b/p instruction)
+ and saves it as the "overwritten" code - so when the breakpoint is
+ subsequently removed, the b/p instruction is written back to the
+ b/p address again! That is not what is desired... */
+ (void) remove_breakpoints();
+ generic_mourn_inferior();
+ current_target.to_has_execution = 0;
+}
+
+
+/* Check whether the given thread is alive. */
+
+static int
+arc_xISS_thread_alive (ptid_t ptid)
+{
+ ENTERMSG;
+
+ /* We only have one thread. */
+ return 1;
+}
+
+
+/* Check whether our debug target is runnable: return 1 if it is, 0 otherwise. */
+
+static int arc_xISS_can_run (void)
+{
+ /* If we are connected to the xISS i/f, and a program is loaded. */
+ return (xiss_instance != NULL) && arc_program_is_loaded;
+}
+
+
+/* We do not support asynchronous execution of the target program (i.e. commands
+ like 'run' or 'continue' or 'step' can not be executed in background mode
+ by appending a '&' to them) so we do not need to implement the target stop
+ operation (called by the 'interrupt' command); interrupting a running program
+ is handled by the Ctrl-C mechanism. */
+
+#if 0
+static void
+arc_xISS_stop (void)
+{
+ ENTERMSG;
+}
+#endif
+
+
+/* Check if we can set a "hardware" watchpoint of type TYPE. TYPE is
+ one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint, or
+ bp_hardware_breakpoint. COUNT is the number of such watchpoints used so far
+ (including this one). OTHERTYPE is the total number of "hardware" breakpoints
+ and watchpoints of other types that are "already" set
+ (0 if type == bp_hardware_breakpoint).
+
+ Result: 0 if hardware watchpoints are not supported
+ -1 if there are not enough hardware watchpoints
+ 1 if there are enough hardware watchpoints
+
+ N.B. this is not what is stated in target.h, but it does conform to the use
+ made of this function's result in breakpoint.c! */
+
+static int
+arc_xISS_can_use_hw_breakpoint (int type, int count, int othertype)
+{
+ ENTERARGS("type %d, count %d", type, count);
+
+ switch (type)
+ {
+ case bp_hardware_watchpoint:
+ case bp_read_watchpoint:
+ case bp_watchpoint: /* This means bp_write_watchpoint. */
+ return 1;
+ case bp_hardware_breakpoint:
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+
+/* Insert a "hardware" watchpoint on the target.
+
+ Parameters:
+ addr : the start address of the region of memory to be watched
+ length: the length in bytes of the region of memory
+ type : 0 => write, 1 => read, 2 => read/write
+
+ Returns 0 for success, -1 for failure. */
+
+static int
+arc_xISS_insert_watchpoint (CORE_ADDR addr, int length, int type)
+{
+ WatchpointCookie cookie;
+ unsigned int options;
+
+ ENTERARGS("0x%08X:%d %d", (unsigned int) addr, length, type);
+
+ gdb_assert(length > 0);
+
+ switch (type)
+ {
+ case 0:
+ options = ARC_WATCHPOINT_write;
+ break;
+ case 1:
+ options = ARC_WATCHPOINT_read;
+ break;
+ case 2:
+ options = ARC_WATCHPOINT_read | ARC_WATCHPOINT_write;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("invalid watchpoint type: %d"), type);
+ }
+
+ if (xISS_functions->set_mem_watchpoint2(xiss_instance, (unsigned long) addr, length, options, &cookie) == 1)
+ {
+ associate(cookie, addr, length, type);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/* Remove a "hardware" watchpoint from the target.
+
+ Parameters:
+ addr : the start address of the region of memory being watched
+ length: the length in bytes of the region of memory
+ type : 0 => write, 1 => read, 2 => read/write
+
+ Returns 0 for success, non-zero for failure. */
+
+static int
+arc_xISS_remove_watchpoint (CORE_ADDR addr, int length, int type)
+{
+ WatchpointCookie cookie = disassociate(addr, length, type);
+
+ ENTERARGS("0x%x:%d %d", (unsigned int) addr, length, type);
+
+ if (cookie != NULL)
+ return (xISS_functions->remove_watchpoint(xiss_instance, cookie) == 1) ? 0 : 1;
+ return 1;
+}
+
+
+/* Returns non-zero if the execution of the target program has been stopped by
+ the trigger of a "hardware" watchpoint (i.e. on memory read or write), zero
+ otherwise. */
+
+static int
+arc_xISS_stopped_by_watchpoint (void)
+{
+ WatchpointCookie cookie;
+
+ ENTERMSG;
+
+ if (xISS_functions->stopped_at_watchpoint2(xiss_instance, &cookie) == 1)
+ {
+ /* Regrettably, the arcint i/f does not provide a well-defined means for
+ finding out the address of the data which was accessed - to do this
+ we have had to define a special property which returns the required
+ address! */
+ int result = XISS_PROPERTY("watchpoint", "return_hit_address");
+
+ if (result == 0)
+ {
+ DEBUG("xISS could not process 'watchpoint/return_hit_address' property");
+
+ /* The most we can do now is retrieve the start address of the
+ watchpoint which was triggered...
+ N.B. we must retrieve the watchpoint address here, rather than in
+ the arc_xISS_stopped_data_address function, as gdb deletes
+ all breakpoint and watchpoints from the target as soon as
+ execution is halted, which removes the cookie from the table! */
+ stopped_data_address = find(cookie);
+ }
+ else
+ stopped_data_address = (CORE_ADDR) result;
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Get the address of the data that was read/written causing a h/w watchpoint to
+ trigger; the address is returned in the '*addr' parameter.
+ Returns 0 for failure, non-zero for success. */
+
+static int
+arc_xISS_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr)
+{
+ ENTERMSG;
+
+ DEBUG("data addr: 0x%08X\n", (unsigned int) stopped_data_address);
+ *addr = stopped_data_address;
+
+ return 1;
+}
+
+
+/* Can a h/w watchpoint 'length' bytes long be set at address 'addr' in target memory? */
+
+static int
+arc_xISS_region_ok_for_hw_watchpoint (CORE_ADDR addr, int length)
+{
+ /* As far as we know, we can set a h/w watchpoint anywhere. */
+ return 1;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 7) functions for instruction tracing */
+/* -------------------------------------------------------------------------- */
+
+/* Display the instruction at the given address and ordinal position in the
+ instruction trace. */
+
+static void
+display_instruction (Ordinal ordinal, unsigned int address)
+{
+ /* N.B. must use fprintf_filtered here, rather than fprintf_unfiltered, as
+ gdb_print_insn calls fprintf_filtered, and if we mix the use of the
+ two we can get garbled output! */
+ fprintf_filtered(gdb_stdout, "<0x%016llX> 0x%08X ", ordinal, address);
+ (void) gdb_print_insn((CORE_ADDR) address, gdb_stdout, NULL);
+ fprintf_filtered(gdb_stdout, "\n");
+}
+
+
+/* Get the ordinal position of the first instruction in the trace buffer in the
+ sequence of executed instructions from the xISS; return 0 if this number cannot
+ be obtained. */
+
+static Ordinal
+get_instruction_trace_start (void)
+{
+ /* N.B. XISS_PROPERTY returns 0 if the property is not handled. */
+ int start_low = XISS_PROPERTY("instruction_trace", "return_start_count_low");
+ int start_high = XISS_PROPERTY("instruction_trace", "return_start_count_high");
+ Ordinal start = ((Ordinal) start_high) << 32 | (Ordinal) start_low;
+
+ DEBUG("get_instruction_trace_start : %llu\n", start);
+
+ return start;
+}
+
+
+/* Encode the instruction trace buffer retrieved from the xISS: the buffer
+ 'trace' contains 'length' entries which are all PC values. The data is
+ recorded in the currently open trace file in a packed format. */
+
+static void
+encode_instruction_trace (unsigned int trace[], int length)
+{
+ unsigned int lastPC = trace[0];
+ int i;
+
+ /* Store the first entry in the buffer as an absolute address. */
+ arc_encode_PC(ABSOLUTE_31_BITS, lastPC / 2);
+
+ /* Look at all the remaining entries, comparing each with the previous one. */
+ for (i = 1; i < length; i++)
+ {
+ unsigned int thisPC = trace[i];
+ int delta = (int) thisPC - (int) lastPC;
+
+ /* Encode the difference in the PC as a relative offset, if possible.
+ Offsets of 0 (branch to current address), 2, 4, 6 and 8 (instruction
+ sizes + optional immediate size) are handled as special cases. */
+
+ if (delta == 0)
+ arc_encode_PC(NO_CHANGE, 0);
+ else if (delta == 2)
+ arc_encode_PC(PLUS_16_BITS, 0);
+ else if (delta == 4)
+ arc_encode_PC(PLUS_32_BITS, 0);
+ else if (delta == 6)
+ arc_encode_PC(PLUS_48_BITS, 0);
+ else if (delta == 8)
+ arc_encode_PC(PLUS_64_BITS, 0);
+ else if (0 < delta && delta <= MAX_DELTA)
+ arc_encode_PC(DELTA_16_BIT_POSITIVE, ENCODE_DELTA(delta));
+ else if (0 > delta && delta >= -MAX_DELTA)
+ arc_encode_PC(DELTA_16_BIT_NEGATIVE, ENCODE_DELTA(-delta));
+ else
+ arc_encode_PC(ABSOLUTE_31_BITS, thisPC / 2);
+
+ lastPC = thisPC;
+ }
+
+ /* Useful tracing code: dump buffer as raw binary. */
+#if 0
+ {
+ int binary = open("trace.binary", O_CREAT | O_WRONLY, 0666);
+
+ if (binary == -1)
+ warning(_("could not open file trace.binary"));
+ else
+ {
+ (void) write(binary, trace, length * sizeof(unsigned int));
+ (void) close(binary);
+ }
+ }
+#endif
+}
+
+
+/* Decode the instruction trace buffer retrieved from a file. This is the inverse
+ of the encoding performed by the 'encode_instruction_trace' function.
+ The instruction at each PC value decoded is disassembled and displayed only if
+ its ordinal position in the trace is in the range given by the 'from' and 'to'
+ parameters. */
+
+static void
+decode_instruction_trace (Ordinal from, Ordinal to, Ordinal ordinal)
+{
+ ARC_ProgramCounterEncoding encoding;
+ unsigned int thisPC = 0;
+ unsigned int lastPC = 0;
+ unsigned int value;
+
+ while (arc_decode_PC(&encoding, &value))
+ {
+ switch (encoding)
+ {
+ case NO_CHANGE:
+ break;
+ case PLUS_16_BITS:
+ thisPC += 2;
+ break;
+ case PLUS_32_BITS:
+ thisPC += 4;
+ break;
+ case PLUS_48_BITS:
+ thisPC += 6;
+ break;
+ case PLUS_64_BITS:
+ thisPC += 8;
+ break;
+ case DELTA_16_BIT_POSITIVE:
+ thisPC += DECODE_DELTA(value);
+ break;
+ case DELTA_16_BIT_NEGATIVE:
+ thisPC -= DECODE_DELTA(value);
+ break;
+ case ABSOLUTE_31_BITS:
+ thisPC = value * 2;
+ break;
+ }
+
+ if (from <= ordinal && ordinal <= to)
+ display_instruction(ordinal, thisPC);
+
+ lastPC = thisPC;
+ ordinal++;
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 8) helper routines for added commands */
+/* -------------------------------------------------------------------------- */
+
+/* Check that the xISS target is actually connected. */
+
+static void
+check_connected (void)
+{
+ if (xiss_instance == NULL)
+ error(_("Target " ARC_TARGET_NAME " is not connected"));
+}
+
+
+/* Set the size of the buffer to be used by the xISS for instruction trace data. */
+
+static void
+set_trace_buffer_size (int size)
+{
+ char sz[20];
+
+ (void) snprintf(sz, sizeof(sz), "%d", size);
+
+ if (XISS_PROPERTY("trace_buffer_size", sz) != 1)
+ error(_("xISS could not process 'trace_buffer_size' property"));
+}
+
+
+/* Tell the xISS to switch instruction tracing on or off. */
+
+static void
+set_xiss_trace (char *args,
+ int from_tty,
+ struct cmd_list_element *e)
+{
+ check_connected();
+
+ if (XISS_PROPERTY("trace", (xISS_trace_instructions) ? "on" : "off") != 1)
+ error(_("xISS could not process 'trace' property"));
+}
+
+
+/* Show the status of xISS instruction tracing. */
+
+static void
+show_xiss_trace (struct ui_file *file,
+ int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ /* Value will be either "on" or "off". */
+ fprintf_filtered(file,
+ _("xISS instruction tracing is %s.\n"),
+ value);
+}
+
+
+/* Tell the xISS to write the instruction trace to the file whose name is held
+ in the xiss_trace_file global variable. */
+
+static void
+set_xiss_trace_file (char *args,
+ int from_tty,
+ struct cmd_list_element *e)
+{
+ check_connected();
+
+ if (xiss_trace_file)
+ {
+ if (XISS_PROPERTY("trace_file", xiss_trace_file) != 1)
+ error(_("xISS could not process 'trace_file' property"));
+ }
+}
+
+
+/* Show the name of the trace file (if any) which is currently receiving
+ instruction tracing output from the xISS. */
+
+static void
+show_xiss_trace_file (struct ui_file *file,
+ int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ if (*value == '\0')
+ fprintf_filtered(file,
+ _("No output file is set for xISS instruction tracing.\n"));
+ else
+ fprintf_filtered(file,
+ _("The output file for xISS instruction tracing is '%s'.\n"),
+ value);
+}
+
+
+/* Set the size of the buffer used by the xISS for instruction trace data. */
+
+static void
+set_xiss_trace_buffer_size (char *args,
+ int from_tty,
+ struct cmd_list_element *e)
+{
+ check_connected();
+
+ if (xiss_trace_buffer_size < 0)
+ error(_("Trace buffer size must be non-negative"));
+
+ set_trace_buffer_size(xiss_trace_buffer_size);
+}
+
+
+/* Show the size of the buffer used by the xISS for instruction trace data. */
+
+static void
+show_xiss_trace_buffer_size (struct ui_file *file,
+ int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered(file,
+ _("The buffer size for xISS instruction tracing is %s entries.\n"),
+ value);
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 9) local functions implementing commands */
+/* -------------------------------------------------------------------------- */
+
+/* Command: <command> <filename>
+
+ Save the contents of the xISS instruction trace buffer to the named file.
+
+ We should eventually change this to use the ui_out stuff rather than
+ printf_filtered. */
+
+static void
+arc_save_trace_to_file_command (char *arg, int from_tty)
+{
+ int count;
+
+ if (!arg)
+ {
+ printf_filtered (_(SAVE_TRACE_TO_FILE_COMMAND_USAGE));
+ return;
+ }
+
+ check_connected();
+
+ count = xISS_functions->instruction_trace_count(xiss_instance);
+
+ if (count)
+ {
+ unsigned int *buffer;
+
+ if (access(arg, F_OK) == 0)
+ if (!query(_("File already exists. Do you wish to overwrite it?")))
+ return;
+
+ printf_unfiltered(_("%u instructions in trace buffer\n"), count);
+
+ buffer = xmalloc(count * sizeof(unsigned int));
+
+ if (buffer)
+ {
+ Ordinal first = get_instruction_trace_start();
+
+ xISS_functions->get_instruction_traces(xiss_instance, buffer);
+
+ if (arc_start_encoding(arg, first))
+ {
+ encode_instruction_trace(buffer, count);
+ arc_stop_encoding(first + (Ordinal) count - 1);
+ }
+
+ xfree(buffer);
+ }
+ else
+ warning(_("can not allocate buffer to hold instruction trace data"));
+ }
+ else
+ warning(_("no instruction trace data available"));
+}
+
+
+
+/* Command: <command>
+
+ Discard the contents of the xISS instruction trace buffer. */
+
+static void
+arc_empty_trace_buffer (char *arg, int from_tty)
+{
+ if (arg)
+ {
+ printf_filtered (_(EMPTY_TRACE_BUFFER_COMMAND_USAGE));
+ return;
+ }
+
+ check_connected();
+
+ set_trace_buffer_size(0);
+ set_trace_buffer_size(xiss_trace_buffer_size);
+}
+
+
+/* Command: <command> [ FROM=<from> ] [ TO=<to> ] [ <FILE> ]
+
+ Display some or all of the instruction trace, either from the xISS trace
+ buffer or from a named file. */
+
+static void
+arc_list_trace (char *arg, int from_tty)
+{
+ char *file = NULL;
+ Boolean from_specified = FALSE;
+ Boolean to_specified = FALSE;
+ Ordinal from = 0;
+ Ordinal to = 0;
+ Ordinal first;
+ Ordinal last;
+
+ /* Do we have arguments to the command? */
+ if (arg)
+ {
+ char **argv = buildargv (arg);
+ Boolean invalid = FALSE;
+ int i = 0;
+
+ if (argv == NULL)
+ nomem (0);
+
+ while (argv[i] != NULL)
+ {
+// printf("argv[%d] = %s\n", i, argv[i]);
+
+ GET_PARAMETER(from)
+ else
+ GET_PARAMETER(to)
+ else
+ {
+ /* Assume the argument is the file name. */
+ file = xstrdup(argv[i]);
+ i++;
+ }
+ }
+
+ freeargv(argv);
+
+ if (invalid)
+ {
+ printf_filtered (_(LIST_TRACE_COMMAND_USAGE));
+ return;
+ }
+
+ DEBUG("FROM = %llu\n", from);
+ DEBUG("TO = %llu\n", to);
+
+ if (from > to)
+ error("FROM (%lld) > TO (%lld)", from, to);
+ }
+
+ /* If we must get the instruction trace from a file. */
+ if (file)
+ {
+ /* Try to open the named file and start decoding its contents. */
+ if (arc_start_decoding(file, &first, &last))
+ {
+ CHECK_RANGE("file")
+ decode_instruction_trace(from, to, first);
+ arc_stop_decoding();
+ }
+
+ xfree(file);
+ }
+ else
+ {
+ unsigned int count;
+
+ check_connected();
+
+ /* Get the number of entries in the xISS instruction trace buffer. */
+ count = (unsigned int) xISS_functions->instruction_trace_count(xiss_instance);
+
+ if (count > 0)
+ {
+ unsigned int *buffer = xmalloc(count * sizeof(unsigned int));
+
+ if (buffer)
+ {
+ Ordinal i;
+
+ first = get_instruction_trace_start();
+ last = first + (Ordinal) count - 1;
+
+ CHECK_RANGE("trace buffer")
+
+ /* Get the contents of the xISS instruction trace buffer. */
+ xISS_functions->get_instruction_traces(xiss_instance, buffer);
+
+ /* Display the required range of the trace. */
+ for (i = from; i <= to; i++)
+ display_instruction(i, buffer[(int) (i - from)]);
+
+ xfree(buffer);
+ }
+ else
+ warning(_("can not allocate buffer to hold instruction trace data"));
+ }
+ else
+ warning(_("no instruction trace data available"));
+ }
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* 10) initialization functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the xISS target operations. */
+
+static void
+initialize_xISS_target_ops (void)
+{
+ ENTERMSG;
+
+ xISS_target_ops.to_data = &operations;
+
+ xISS_target_ops.to_shortname = ARC_TARGET_NAME;
+ xISS_target_ops.to_longname = "xISS debug target (ARC Processors)";
+ xISS_target_ops.to_doc = "xISS (Fast Instruction Set Simulator) debug target (ARC Processors)";
+
+ xISS_target_ops.to_open = arc_xISS_open;
+ xISS_target_ops.to_close = arc_xISS_close;
+ xISS_target_ops.to_resume = arc_xISS_resume;
+ xISS_target_ops.to_wait = arc_xISS_wait;
+
+ xISS_target_ops.to_fetch_registers = arc_elf32_fetch_registers;
+ xISS_target_ops.to_store_registers = arc_elf32_store_registers;
+ xISS_target_ops.to_prepare_to_store = arc_xISS_prepare_to_store;
+ xISS_target_ops.to_xfer_partial = arc_elf32_xfer_partial;
+ xISS_target_ops.to_files_info = arc_xISS_files_info;
+
+ xISS_target_ops.to_can_use_hw_breakpoint = arc_xISS_can_use_hw_breakpoint;
+// xISS_target_ops.to_insert_hw_breakpoint = arc_xISS_insert_hw_breakpoint;
+// xISS_target_ops.to_remove_hw_breakpoint = arc_xISS_remove_hw_breakpoint;
+ xISS_target_ops.to_insert_watchpoint = arc_xISS_insert_watchpoint;
+ xISS_target_ops.to_remove_watchpoint = arc_xISS_remove_watchpoint;
+ xISS_target_ops.to_stopped_by_watchpoint = arc_xISS_stopped_by_watchpoint;
+ xISS_target_ops.to_stopped_data_address = arc_xISS_stopped_data_address;
+ xISS_target_ops.to_region_ok_for_hw_watchpoint = arc_xISS_region_ok_for_hw_watchpoint;
+
+ xISS_target_ops.to_insert_breakpoint = arc_elf32_insert_breakpoint;
+ xISS_target_ops.to_remove_breakpoint = arc_elf32_remove_breakpoint;
+
+ xISS_target_ops.to_kill = arc_xISS_kill;
+ xISS_target_ops.to_load = arc_xISS_load;
+
+ xISS_target_ops.to_create_inferior = arc_xISS_create_inferior;
+ xISS_target_ops.to_mourn_inferior = arc_xISS_mourn_inferior;
+ xISS_target_ops.to_thread_alive = arc_xISS_thread_alive;
+// xISS_target_ops.to_stop = arc_xISS_stop;
+ xISS_target_ops.to_can_run = arc_xISS_can_run;
+ xISS_target_ops.to_terminal_inferior = NULL;
+
+ xISS_target_ops.to_stratum = process_stratum;
+
+ xISS_target_ops.to_has_all_memory = 1;
+ xISS_target_ops.to_has_memory = 1;
+ xISS_target_ops.to_has_stack = 0; /* Defer setting this until the program has been loaded. */
+ xISS_target_ops.to_has_registers = 1;
+ xISS_target_ops.to_has_execution = 0; /* Defer setting this until the program has been started. */
+
+ xISS_target_ops.to_magic = OPS_MAGIC;
+}
+#endif /* HAVE_LIBXISS */
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Initialize the module. This function is called from the gdb core on start-up. */
+
+/* N.B. the initialization function must be defined even if the rest of this
+ module is excluded, as the call to it from the gdb start-up code is
+ generated by the build mechanism without regard to any conditional
+ compilation! */
+
+void
+_initialize_arc_xiss (void)
+{
+#ifdef HAVE_LIBXISS
+ struct cmd_list_element *cmnd;
+
+ ENTERMSG;
+
+ operations.read_core_register = read_xiss_core_register;
+ operations.write_core_register = write_xiss_core_register;
+ operations.read_auxiliary_register = read_xiss_aux_register;
+ operations.write_auxiliary_register = write_xiss_aux_register;
+ operations.read_memory = read_words;
+ operations.write_memory = write_words;
+ operations.fill_memory = NULL;
+
+ initialize_xISS_target_ops ();
+ add_target (&xISS_target_ops);
+
+ /* Register ARC-specific commands with gdb. */
+
+ (void) add_setshow_boolean_cmd
+ ("arc-xiss-trace",
+ class_trace,
+ &xISS_trace_instructions,
+ _("Set whether the xISS should trace instructions.\n"),
+ _("Show whether the xISS should trace instructions.\n"),
+ NULL,
+ set_xiss_trace,
+ show_xiss_trace,
+ &setlist,
+ &showlist);
+
+ add_setshow_optional_filename_cmd
+ ("arc-xiss-trace-file",
+ class_trace,
+ &xiss_trace_file,
+ _("Set the output file for xISS instruction tracing.\n"),
+ _("Show the output file for xISS instruction tracing.\n"),
+ NULL,
+ set_xiss_trace_file,
+ show_xiss_trace_file,
+ &setlist,
+ &showlist);
+
+ (void) add_setshow_zinteger_cmd
+ ("arc-xiss-trace-buffer-size",
+ class_trace,
+ &xiss_trace_buffer_size,
+ _("Set the size of the trace buffer for xISS instruction tracing.\n"),
+ _("Show the size of the trace buffer for xISS instruction tracing.\n"),
+ NULL,
+ set_xiss_trace_buffer_size,
+ show_xiss_trace_buffer_size,
+ &setlist,
+ &showlist);
+
+ cmnd = add_cmd
+ (SAVE_TRACE_TO_FILE_COMMAND,
+ class_trace,
+ arc_save_trace_to_file_command,
+ _("Save the contents of the xISS instruction trace buffer to a file.\n"
+ SAVE_TRACE_TO_FILE_COMMAND_USAGE
+ "<FILE> is a file to hold the xISS instruction trace buffer contents.\n"),
+ &cmdlist);
+ set_cmd_completer (cmnd, filename_completer);
+
+ (void) add_cmd
+ (EMPTY_TRACE_BUFFER_COMMAND,
+ class_trace,
+ arc_empty_trace_buffer,
+ _("Empty xISS instruction trace buffer.\n"
+ EMPTY_TRACE_BUFFER_COMMAND_USAGE),
+ &cmdlist);
+
+ cmnd = add_cmd
+ (LIST_TRACE_COMMAND,
+ class_trace,
+ arc_list_trace,
+ _("Display xISS instruction trace.\n"
+ LIST_TRACE_COMMAND_USAGE),
+ &cmdlist);
+ set_cmd_completer (cmnd, filename_completer);
+
+#endif /* HAVE_LIBXISS */
+}
+
+/******************************************************************************/
diff --git a/gdb/arc-xiss.h b/gdb/arc-xiss.h
new file mode 100755
index 00000000000..a79030b2bc1
--- /dev/null
+++ b/gdb/arc-xiss.h
@@ -0,0 +1,41 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ 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 header file defines some operations provided by the ARC xISS */
+/* module. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_XISS_H
+#define ARC_XISS_H
+
+
+/* Currently none. */
+
+
+#endif /* ARC_XISS_H */
+/******************************************************************************/
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 019f4c8ac3e..3f5981d2963 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -93,6 +93,10 @@ static int can_use_hardware_watchpoint (struct value *);
static void break_command_1 (char *, int, int);
+// begin ARC
+static void watch_range_command_1 (unsigned int, unsigned int, int, int);
+// end ARC
+
static void mention (struct breakpoint *);
struct breakpoint *set_raw_breakpoint (struct symtab_and_line, enum bptype);
@@ -842,6 +846,13 @@ update_watchpoint (struct breakpoint *b, int reparse)
struct bp_location *loc;
bpstat bs;
+// begin ARC
+ /* If this is a range watchpoint. */
+ if (b->exp == NULL)
+ /* There is no need to change it. */
+ return;
+// end ARC
+
unlink_locations_from_global_list (b);
for (loc = b->loc; loc;)
{
@@ -1017,6 +1028,9 @@ insert_bp_location (struct bp_location *bpt,
/* Initialize the target-specific information. */
memset (&bpt->target_info, 0, sizeof (bpt->target_info));
bpt->target_info.placed_address = bpt->address;
+// begin ARC
+ bpt->target_info.range = bpt->length;
+// end ARC
if (bpt->loc_type == bp_loc_software_breakpoint
|| bpt->loc_type == bp_loc_hardware_breakpoint)
@@ -2103,6 +2117,30 @@ top:
do_cleanups (old_chain);
}
+// begin ARC
+static void
+check_range (struct breakpoint *bp, enum async_reply_reason reason)
+{
+ CORE_ADDR addr;
+
+ if (target_stopped_data_address (&current_target, &addr))
+ {
+ if (addr >= bp->loc->address &&
+ addr < bp->loc->address + bp->loc->length)
+ {
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (reason));
+ mention (bp);
+ ui_out_text(uiout, "triggered by access at address ");
+ ui_out_field_core_addr(uiout, "", addr);
+ ui_out_text (uiout, "\n");
+ }
+ }
+}
+// end ARC
+
/* This is the normal print function for a bpstat. In the future,
much of this logic could (should?) be moved to bpstat_stop_status,
by having it set different print_it values.
@@ -2221,76 +2259,103 @@ print_it_typical (bpstat bs)
case bp_watchpoint:
case bp_hardware_watchpoint:
- if (bs->old_val != NULL)
- {
- annotate_watchpoint (b->number);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
- mention (b);
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "old", stb);
- ui_out_text (uiout, "\nNew value = ");
- value_print (b->val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "new", stb);
- do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
- value_free (bs->old_val);
- bs->old_val = NULL;
- }
+// begin ARC
+ if (b->exp)
+ {
+// end ARC
+ if (bs->old_val != NULL)
+ {
+ annotate_watchpoint (b->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+ mention (b);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ value_print (b->val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ }
+// begin ARC
+ }
+ else
+ check_range(b, EXEC_ASYNC_WATCHPOINT_TRIGGER);
+// end ARC
/* More than one watchpoint may have been triggered. */
return PRINT_UNKNOWN;
break;
case bp_read_watchpoint:
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
- mention (b);
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nValue = ");
- value_print (b->val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "value", stb);
- do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
+// begin ARC
+ if (b->exp)
+ {
+// end ARC
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+ mention (b);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ value_print (b->val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "value", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+// begin ARC
+ }
+ else
+ check_range(b, EXEC_ASYNC_READ_WATCHPOINT_TRIGGER);
+// end ARC
return PRINT_UNKNOWN;
break;
case bp_access_watchpoint:
- if (bs->old_val != NULL)
- {
- annotate_watchpoint (b->number);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
- mention (b);
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "old", stb);
- value_free (bs->old_val);
- bs->old_val = NULL;
- ui_out_text (uiout, "\nNew value = ");
- }
- else
- {
- mention (b);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nValue = ");
- }
- value_print (b->val, stb->stream, 0,Val_pretty_default);
- ui_out_field_stream (uiout, "new", stb);
- do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
+// begin ARC
+ if (b->exp)
+ {
+// end ARC
+ if (bs->old_val != NULL)
+ {
+ annotate_watchpoint (b->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+ mention (b);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
+ ui_out_field_stream (uiout, "old", stb);
+ value_free (bs->old_val);
+ bs->old_val = NULL;
+ ui_out_text (uiout, "\nNew value = ");
+ }
+ else
+ {
+ mention (b);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nValue = ");
+ }
+ value_print (b->val, stb->stream, 0,Val_pretty_default);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
+// begin ARC
+ }
+ else
+ check_range(b, EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER);
+// end ARC
return PRINT_UNKNOWN;
break;
@@ -2529,6 +2594,11 @@ watchpoint_check (void *p)
b = bs->breakpoint_at->owner;
+// begin ARC
+ if (b->exp == NULL)
+ return WP_VALUE_CHANGED;
+// end ARC
+
if (b->exp_valid_block == NULL)
within_current_scope = 1;
else
@@ -2667,7 +2737,17 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
&& b->type != bp_catch_exec) /* a non-watchpoint bp */
{
if (bl->address != bp_addr) /* address doesn't match */
- continue;
+// begin ARC
+ {
+ /* is the address within the b/p range? */
+ if (bp_addr < b->loc->address ||
+ bp_addr > b->loc->address + b->loc->length - 1)
+// end ARC
+ continue;
+// begin ARC
+ }
+// end ARC
+
if (overlay_debugging /* unmapped overlay section */
&& section_is_overlay (bl->section)
&& !section_is_mapped (bl->section))
@@ -2764,86 +2844,107 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid)
struct value *v;
int must_check_value = 0;
- if (b->type == bp_watchpoint)
- /* For a software watchpoint, we must always check the
- watched value. */
- must_check_value = 1;
- else if (b->watchpoint_triggered == watch_triggered_yes)
- /* We have a hardware watchpoint (read, write, or access)
- and the target earlier reported an address watched by
- this watchpoint. */
- must_check_value = 1;
- else if (b->watchpoint_triggered == watch_triggered_unknown
- && b->type == bp_hardware_watchpoint)
- /* We were stopped by a hardware watchpoint, but the target could
- not report the data address. We must check the watchpoint's
- value. Access and read watchpoints are out of luck; without
- a data address, we can't figure it out. */
- must_check_value = 1;
-
- if (must_check_value)
- {
- char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
- b->number);
- struct cleanup *cleanups = make_cleanup (xfree, message);
- int e = catch_errors (watchpoint_check, bs, message,
- RETURN_MASK_ALL);
- do_cleanups (cleanups);
- switch (e)
+// begin ARC
+ if (b->exp == NULL)
+ {
+ CORE_ADDR addr;
+
+ if (!target_stopped_data_address (&current_target, &addr))
+ continue;
+
+ if (addr >= b->loc->address &&
+ addr < b->loc->address + b->loc->length)
+ {
+ /* Stop. */
+ ++(b->hit_count);
+ }
+ }
+ else
+ {
+// end ARC
+ if (b->type == bp_watchpoint)
+ /* For a software watchpoint, we must always check the
+ watched value. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_yes)
+ /* We have a hardware watchpoint (read, write, or access)
+ and the target earlier reported an address watched by
+ this watchpoint. */
+ must_check_value = 1;
+ else if (b->watchpoint_triggered == watch_triggered_unknown
+ && b->type == bp_hardware_watchpoint)
+ /* We were stopped by a hardware watchpoint, but the target could
+ not report the data address. We must check the watchpoint's
+ value. Access and read watchpoints are out of luck; without
+ a data address, we can't figure it out. */
+ must_check_value = 1;
+
+ if (must_check_value)
{
- case WP_DELETED:
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
- /* Stop. */
- break;
- case WP_VALUE_CHANGED:
- if (b->type == bp_read_watchpoint)
- {
- /* Don't stop: read watchpoints shouldn't fire if
- the value has changed. This is for targets
- which cannot set read-only watchpoints. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- }
- ++(b->hit_count);
- break;
- case WP_VALUE_NOT_CHANGED:
- if (b->type == bp_hardware_watchpoint
- || b->type == bp_watchpoint)
- {
- /* Don't stop: write watchpoints shouldn't fire if
- the value hasn't changed. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- }
- /* Stop. */
- ++(b->hit_count);
- break;
- default:
- /* Can't happen. */
- case 0:
- /* Error from catch_errors. */
- printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
- if (b->related_breakpoint)
- b->related_breakpoint->disposition = disp_del_at_next_stop;
- b->disposition = disp_del_at_next_stop;
- /* We've already printed what needs to be printed. */
- bs->print_it = print_it_done;
- break;
+ char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
+ b->number);
+ struct cleanup *cleanups = make_cleanup (xfree, message);
+ int e = catch_errors (watchpoint_check, bs, message,
+ RETURN_MASK_ALL);
+ do_cleanups (cleanups);
+ switch (e)
+ {
+ case WP_DELETED:
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ /* Stop. */
+ break;
+ case WP_VALUE_CHANGED:
+ if (b->type == bp_read_watchpoint)
+ {
+ /* Don't stop: read watchpoints shouldn't fire if
+ the value has changed. This is for targets
+ which cannot set read-only watchpoints. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ ++(b->hit_count);
+ break;
+ case WP_VALUE_NOT_CHANGED:
+ if (b->type == bp_hardware_watchpoint
+ || b->type == bp_watchpoint)
+ {
+ /* Don't stop: write watchpoints shouldn't fire if
+ the value hasn't changed. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+ /* Stop. */
+ ++(b->hit_count);
+ break;
+ default:
+ /* Can't happen. */
+ case 0:
+ /* Error from catch_errors. */
+ printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
+ if (b->related_breakpoint)
+ b->related_breakpoint->disposition = disp_del_at_next_stop;
+ b->disposition = disp_del_at_next_stop;
+ /* We've already printed what needs to be printed. */
+ bs->print_it = print_it_done;
+ break;
+ }
}
- }
- else /* must_check_value == 0 */
- {
- /* This is a case where some watchpoint(s) triggered, but
- not at the address of this watchpoint, or else no
- watchpoint triggered after all. So don't print
- anything for this watchpoint. */
- bs->print_it = print_it_noop;
- bs->stop = 0;
- continue;
- }
+ else /* must_check_value == 0 */
+ {
+ /* This is a case where some watchpoint(s) triggered, but
+ not at the address of this watchpoint, or else no
+ watchpoint triggered after all. So don't print
+ anything for this watchpoint. */
+ bs->print_it = print_it_noop;
+ bs->stop = 0;
+ continue;
+ }
+// begin ARC
+ }
+// end ARC
}
else
{
@@ -3464,14 +3565,31 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
- /* Field 4, the address, is omitted (which makes the columns
- not line up too nicely with the headers, but the effect
- is relatively readable). */
- if (addressprint)
- ui_out_field_skip (uiout, "addr");
- annotate_field (5);
- print_expression (b->exp, stb->stream);
- ui_out_field_stream (uiout, "what", stb);
+// begin ARC
+ if (b->exp)
+ {
+// end ARC
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ print_expression (b->exp, stb->stream);
+ ui_out_field_stream (uiout, "what", stb);
+// begin ARC
+ }
+ else
+ {
+ /* exp_string has format "<address>:<bytes>" */
+ char* colon = strchr(b->exp_string, ':');
+ *colon = 0;
+ ui_out_field_string(uiout, "addr", b->exp_string);
+ ui_out_field_string(uiout, "what", colon+1);
+ ui_out_text(uiout, "-byte range");
+ *colon = ':';
+ }
+// end ARC
break;
case bp_catch_load:
@@ -3546,7 +3664,18 @@ print_one_breakpoint_location (struct breakpoint *b,
if (b->loc == NULL || loc->shlib_disabled)
ui_out_field_string (uiout, "addr", "<PENDING>");
else
- ui_out_field_core_addr (uiout, "addr", loc->address);
+// begin ARC
+ {
+// end ARC
+ ui_out_field_core_addr (uiout, "addr", loc->address);
+// begin ARC
+ if (b->exp == NULL && b->loc->length > 0)
+ {
+ ui_out_field_int(uiout, "what", b->loc->length);
+ ui_out_text(uiout, "-byte range ");
+ }
+ }
+// end ARC
}
annotate_field (5);
if (!header_of_multiple)
@@ -4764,7 +4893,14 @@ mention (struct breakpoint *b)
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
- print_expression (b->exp, stb->stream);
+// begin ARC
+ if (b->exp)
+// end ARC
+ print_expression (b->exp, stb->stream);
+// begin ARC
+ else
+ ui_out_text (uiout, b->exp_string);
+// end ARC
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
@@ -4773,7 +4909,14 @@ mention (struct breakpoint *b)
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
- print_expression (b->exp, stb->stream);
+// begin ARC
+ if (b->exp)
+// end ARC
+ print_expression (b->exp, stb->stream);
+// begin ARC
+ else
+ ui_out_text (uiout, b->exp_string);
+// end ARC
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
@@ -4782,7 +4925,14 @@ mention (struct breakpoint *b)
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
ui_out_field_int (uiout, "number", b->number);
ui_out_text (uiout, ": ");
- print_expression (b->exp, stb->stream);
+// begin ARC
+ if (b->exp)
+// end ARC
+ print_expression (b->exp, stb->stream);
+// begin ARC
+ else
+ ui_out_text (uiout, b->exp_string);
+// end ARC
ui_out_field_stream (uiout, "exp", stb);
do_cleanups (ui_out_chain);
break;
@@ -4850,6 +5000,10 @@ mention (struct breakpoint *b)
{
printf_filtered (" at ");
fputs_filtered (paddress (b->loc->address), gdb_stdout);
+// begin ARC
+ if (b->exp == NULL && b->loc->length > 0)
+ printf_filtered(" covering %u bytes", b->loc->length);
+// end ARC
}
if (b->source_file)
printf_filtered (": file %s, line %d.",
@@ -5536,12 +5690,28 @@ break_command (char *arg, int from_tty)
break_command_1 (arg, 0, from_tty);
}
+// begin ARC
+void
+watch_range_command (unsigned int address, unsigned int bytes, int accessflag, int from_tty)
+{
+ watch_range_command_1 (address, bytes, accessflag, from_tty);
+}
+// end ARC
+
void
tbreak_command (char *arg, int from_tty)
{
break_command_1 (arg, BP_TEMPFLAG, from_tty);
}
+// begin ARC
+void
+hbreak_command_wrapper (char *arg, int from_tty)
+{
+ hbreak_command (arg, from_tty);
+}
+// end ARC
+
static void
hbreak_command (char *arg, int from_tty)
{
@@ -5837,6 +6007,81 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
mention (b);
}
+
+// begin ARC
+/* accessflag: hw_write: watch write,
+ hw_read: watch read,
+ hw_access: watch access (read or write)
+ hw_execute: execute access */
+static void
+watch_range_command_1 (unsigned int address, unsigned int bytes, int accessflag, int from_tty)
+{
+ struct breakpoint *b;
+ struct symtab_and_line sal;
+ int i, other_type_used, target_resources_ok;
+ enum bptype bp_type;
+ enum target_hw_bp_type wp_type;
+ char exp[50];
+
+ (void) sprintf(exp, "0x%08X:%u", address, bytes);
+
+ init_sal (&sal); /* initialize to zeroes */
+
+ if (accessflag == hw_read)
+ {
+ bp_type = bp_read_watchpoint;
+ wp_type = hw_read;
+ }
+ else if (accessflag == hw_access)
+ {
+ bp_type = bp_access_watchpoint;
+ wp_type = hw_access;
+ }
+ else if (accessflag == hw_write)
+ {
+ bp_type = bp_hardware_watchpoint;
+ wp_type = hw_write;
+ }
+ else
+ {
+ bp_type = bp_hardware_breakpoint;
+ wp_type = hw_execute;
+ }
+
+ i = hw_watchpoint_used_count (bp_type, &other_type_used);
+ target_resources_ok =
+ TARGET_CAN_USE_HARDWARE_WATCHPOINT (bp_type, i, other_type_used);
+ if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
+ error (_("Target does not support this type of hardware watchpoint."));
+ if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
+ error (_("Target can only support one kind of HW watchpoint at a time."));
+
+
+ /* Now set up the breakpoint. */
+ b = set_raw_breakpoint (sal, bp_type);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->disposition = disp_donttouch;
+ b->exp = NULL;
+ b->exp_valid_block = NULL;
+ b->exp_string = xstrdup(exp);
+ b->val = NULL;
+ //b->cond = NULL; 6.8 has removed this element?
+ b->cond_string = 0;
+ b->loc->address = (CORE_ADDR) address;
+ b->loc->requested_address = b->loc->address;
+ b->loc->length = bytes;
+
+ b->loc->watchpoint_type = wp_type;
+
+ memset (&b->watchpoint_frame, 0, sizeof (b->watchpoint_frame));
+
+ mention (b);
+}
+// end ARC
+
+
+
/* Return count of locations need to be watched and can be handled
in hardware. If the watchpoint can not be handled
in hardware return zero. */
@@ -7911,8 +8156,18 @@ insert_single_step_breakpoint (CORE_ADDR next_pc)
*bpt_p = deprecated_insert_raw_breakpoint (next_pc);
if (*bpt_p == NULL)
- error (_("Could not insert single-step breakpoint at 0x%s"),
- paddr_nz (next_pc));
+ {
+ /* richards/2008/10/27 ARC bug fix: if setting the (second)
+ * b/p failed, we must unset the first
+ *
+ * gdb bug: 9649
+ */
+ if (single_step_breakpoints[0] != NULL)
+ remove_single_step_breakpoints ();
+
+ error (_("Could not insert single-step breakpoint at 0x%s"),
+ paddr_nz (next_pc));
+ }
}
/* Remove and delete any breakpoints used for software single step. */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 41730c0b311..a741f862d6a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -175,6 +175,11 @@ enum target_hw_bp_type
struct bp_target_info
{
+// begin ARC
+ /* Range breakpoints added */
+ unsigned int range;
+//end ARC
+
/* Address at which the breakpoint was placed. This is normally the
same as ADDRESS from the bp_location, except when adjustment
happens in gdbarch_breakpoint_from_pc. The most common form of
@@ -272,8 +277,8 @@ struct bp_location
is not a special value for this field. Valid for all types except
bp_loc_other. */
CORE_ADDR address;
-
- /* For hardware watchpoints, the size of data ad ADDRESS being watches. */
+
+ /* For hardware watchpoints, the size of data at ADDRESS being watched. */
int length;
/* Type of hardware watchpoint. */
@@ -702,6 +707,10 @@ extern void breakpoint_clear_ignore_counts (void);
extern void break_command (char *, int);
+// begin ARC
+extern void watch_range_command (unsigned int, unsigned int, int, int);
+//end ARC
+
extern void hbreak_command_wrapper (char *, int);
extern void thbreak_command_wrapper (char *, int);
extern void rbreak_command_wrapper (char *, int);
diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
index e6fbe3f1397..dac43454d8c 100644
--- a/gdb/cli/cli-script.c
+++ b/gdb/cli/cli-script.c
@@ -287,8 +287,15 @@ execute_user_command (struct cmd_list_element *c, char *args)
cmdlines = c->user_commands;
if (cmdlines == 0)
+ {
/* Null command */
+// begin ARC
+ /* If there are no user commands to be executed, execute the
+ callback function instead. */
+ c->func(c, NULL, 0);
+// end ARC
return;
+ }
if (++user_call_depth > max_user_call_depth)
error (_("Max user call depth exceeded -- command aborted."));
diff --git a/gdb/config.in b/gdb/config.in
index b6aba7d2852..f5fa97bac80 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -45,6 +45,12 @@
/* Define to the default OS ABI for this configuration. */
#undef GDB_OSABI_DEFAULT
+/* targetfile */
+#undef GDB_TM_FILE
+
+/* hostfile */
+#undef GDB_XM_FILE
+
/* Define to 1 if you have `alloca', as a function or macro. */
#undef HAVE_ALLOCA
@@ -152,6 +158,15 @@
/* Define if you have the expat library. */
#undef HAVE_LIBEXPAT
+/* Define if you have the ARC xISS library. */
+#undef HAVE_LIBXISS
+
+/* Define if you are building the ARC bare-board debugger. */
+#undef ARC_ELF32_TARGET
+
+/* Define if you are building the ARC Linux debugger. */
+#undef ARC_LINUX_TARGET
+
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
diff --git a/gdb/config/arc/a4-jtag.mt b/gdb/config/arc/a4-jtag.mt
deleted file mode 100644
index e3907baec94..00000000000
--- a/gdb/config/arc/a4-jtag.mt
+++ /dev/null
@@ -1,3 +0,0 @@
-# Target: ARC embedded system
-TDEPFILES= arc-tdep.o arc-jtag.o arc-jtag-tdep.o arc-jtag-ops.o
-DEPRECATED_TM_FILE= tm-a4-jtag.h
diff --git a/gdb/config/arc/arc.mt b/gdb/config/arc/arc.mt
deleted file mode 100644
index cb98a49d01b..00000000000
--- a/gdb/config/arc/arc.mt
+++ /dev/null
@@ -1,4 +0,0 @@
-# Target: arc processor
-TDEPFILES= arc-tdep.o monitor.o arc-rom.o dsrec.o remote-arc-sdi.o
-SIM_OBS = remote-sim.o
-SIM = ../sim/arc/libsim.a
diff --git a/gdb/config/arc/embed.mt b/gdb/config/arc/embed.mt
deleted file mode 100644
index a6d47a23052..00000000000
--- a/gdb/config/arc/embed.mt
+++ /dev/null
@@ -1,3 +0,0 @@
-# Target: ARC embedded system
-TDEPFILES= arc-tdep.o arc-jtag.o arc-jtag-tdep.o arc-jtag-ops.o
-DEPRECATED_TM_FILE= tm-embed.h
diff --git a/gdb/config/arc/linux.mt b/gdb/config/arc/linux.mt
deleted file mode 100644
index 0c5f000a9e3..00000000000
--- a/gdb/config/arc/linux.mt
+++ /dev/null
@@ -1,3 +0,0 @@
-# Target: ARC based machine running GNU/Linux
-DEPRECATED_TM_FILE= tm-linux.h
-TDEPFILES= arc-tdep.o arc-linux-tdep.o solib.o solib-svr4.o solib-legacy.o corelow.o
diff --git a/gdb/config/arc/tm-a4-jtag.h b/gdb/config/arc/tm-a4-jtag.h
deleted file mode 100644
index dc5ab71c16f..00000000000
--- a/gdb/config/arc/tm-a4-jtag.h
+++ /dev/null
@@ -1,103 +0,0 @@
-#define ARC4_JTAG 1
-#define CONFIG_OSABI GDB_OSABI_UNKNOWN
-
-struct gdbarch *arc_jtag_init (struct gdbarch *gdbarch);
-#define CONFIG_INIT_TDEP arc_jtag_init
-
-/* The core regnums here are the same as the hardware register numbers. We
- cannot do that for aux registers, because the aux regs on the h/w do not
- have contiguous numbers. */
-enum arc4_jtag_regnums
- {
- ARC_FP_REGNUM = 27,
- ARC_SP_REGNUM ,
- ARC_ILINK1_REGNUM ,
- ARC_ILINK2_REGNUM ,
- ARC_BLINK_REGNUM ,
- /* Extension core regs are 32..59 inclusive. */
- ARC_LP_COUNT_REGNUM = 60,
- /* 61 is reserved, 62 is not a real register. */
- ARC_PCL_REGNUM = 63,
-
- /* Now the aux registers. */
-
- ARC_STATUS_REGNUM = 64,
- ARC_SEMAPHORE_REGNUM ,
- ARC_LP_START_REGNUM ,
- ARC_LP_END_REGNUM ,
- ARC_IDENTITY_REGNUM ,
- ARC_DEBUG_REGNUM ,
-#ifndef ARC4_JTAG
- ARC_PC_REGNUM ,
- ARC_STATUS32_REGNUM ,
- ARC_STATUS32_L1_REGNUM ,
- ARC_STATUS32_L2_REGNUM ,
-
- ARC_COUNT0_REGNUM ,
- ARC_CONTROL0_REGNUM ,
- ARC_LIMIT0_REGNUM ,
- ARC_INT_VECTOR_BASE_REGNUM ,
- ARC_AUX_MACMODE_REGNUM ,
- ARC_AUX_IRQ_LV12_REGNUM ,
-
- ARC_COUNT1_REGNUM ,
- ARC_CONTROL1_REGNUM ,
- ARC_LIMIT1_REGNUM ,
- ARC_AUX_IRQ_LEV_REGNUM ,
- ARC_AUX_IRQ_HINT_REGNUM ,
- ARC_ERET_REGNUM ,
- ARC_ERBTA_REGNUM ,
- ARC_ERSTATUS_REGNUM ,
- ARC_ECR_REGNUM ,
- ARC_EFA_REGNUM ,
- ARC_ICAUSE1_REGNUM ,
- ARC_ICAUSE2_REGNUM ,
- ARC_AUX_IENABLE_REGNUM ,
- ARC_AUX_ITRIGGER_REGNUM ,
- ARC_XPU_REGNUM ,
- ARC_BTA_REGNUM ,
- ARC_BTA_L1_REGNUM ,
- ARC_BTA_L2_REGNUM ,
- ARC_AUX_IRQ_PULSE_CANCEL_REGNUM ,
- ARC_AUX_IRQ_PENDING_REGNUM ,
-
- /* Build configuration registers. */
- ARC_BCR_0_REGNUM ,
- ARC_BCR_1_REGNUM ,
- ARC_BCR_2_REGNUM ,
- ARC_BCR_3_REGNUM ,
- ARC_BCR_4_REGNUM ,
- ARC_BCR_5_REGNUM ,
- ARC_BCR_6_REGNUM ,
- ARC_BCR_7_REGNUM ,
- ARC_BCR_8_REGNUM ,
- ARC_BCR_9_REGNUM ,
- ARC_BCR_A_REGNUM ,
- ARC_BCR_B_REGNUM ,
- ARC_BCR_C_REGNUM ,
- ARC_BCR_D_REGNUM ,
- ARC_BCR_E_REGNUM ,
- ARC_BCR_F_REGNUM ,
- ARC_BCR_10_REGNUM ,
- ARC_BCR_11_REGNUM ,
- ARC_BCR_12_REGNUM ,
-
- ARC_BCR_13_REGNUM ,
- ARC_BCR_14_REGNUM ,
- ARC_BCR_15_REGNUM ,
- ARC_BCR_16_REGNUM ,
- ARC_BCR_17_REGNUM ,
- ARC_BCR_18_REGNUM ,
- ARC_BCR_19_REGNUM ,
- ARC_BCR_1A_REGNUM ,
- ARC_BCR_1B_REGNUM ,
- ARC_BCR_1C_REGNUM ,
- ARC_BCR_1D_REGNUM ,
- ARC_BCR_1E_REGNUM ,
- ARC_BCR_1F_REGNUM ,
-
-#endif
- ARC_NR_REGS
-
- };
-
diff --git a/gdb/config/arc/tm-embed.h b/gdb/config/arc/tm-embed.h
index 9ac1c1adac1..5cd7271fc23 100644
--- a/gdb/config/arc/tm-embed.h
+++ b/gdb/config/arc/tm-embed.h
@@ -1,101 +1,77 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
-#define CONFIG_OSABI GDB_OSABI_UNKNOWN
+ Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
-struct gdbarch *arc_jtag_init (struct gdbarch *gdbarch);
-#define CONFIG_INIT_TDEP arc_jtag_init
+ Contributed by ARC International (www.arc.com)
-/* The core regnums here are the same as the hardware register numbers. We
- cannot do that for aux registers, because the aux regs on the h/w do not
- have contiguous numbers. */
+ Authors:
+ Codito Technologies Pvt. Ltd.
+ 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 header file defines register numbers for the arc-elf32 */
+/* configuration of the ARC gdb. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_TM_EMBED_H
+#define ARC_TM_EMBED_H
+
+#include "gdbarch.h"
+#include "arc-elf32-tdep.h"
+#include "arc-registers.h"
+
+
+#define CONFIG_OSABI GDB_OSABI_UNKNOWN
+
+#define CONFIG_INIT_TDEP (void) arc_elf32_initialize (gdbarch, arches);
+
+
+/* These are hardware register numbers (i.e. NOT gdb register numbers). */
enum arc700_jtag_regnums
- {
- ARC_FP_REGNUM = 27,
- ARC_SP_REGNUM ,
- ARC_ILINK1_REGNUM ,
- ARC_ILINK2_REGNUM ,
- ARC_BLINK_REGNUM ,
- /* Extension core regs are 32..59 inclusive. */
+{
+ /* Regnums 0 .. 26 are R0 .. R26 */
+
+ ARC_FP_REGNUM = 27,
+ ARC_SP_REGNUM,
+ ARC_ILINK1_REGNUM,
+ ARC_ILINK2_REGNUM,
+ ARC_BLINK_REGNUM,
+
+ /* Extension core regs are R32 .. R59 inclusive. */
+
ARC_LP_COUNT_REGNUM = 60,
+
/* 61 is reserved, 62 is not a real register. */
- ARC_PCL_REGNUM = 63,
-
- /* Now the aux registers. */
-
- ARC_STATUS_REGNUM = 64,
- ARC_SEMAPHORE_REGNUM ,
- ARC_LP_START_REGNUM ,
- ARC_LP_END_REGNUM ,
- ARC_IDENTITY_REGNUM ,
- ARC_DEBUG_REGNUM ,
- ARC_PC_REGNUM ,
- ARC_STATUS32_REGNUM ,
- ARC_STATUS32_L1_REGNUM ,
- ARC_STATUS32_L2_REGNUM ,
-
- ARC_COUNT0_REGNUM ,
- ARC_CONTROL0_REGNUM ,
- ARC_LIMIT0_REGNUM ,
- ARC_INT_VECTOR_BASE_REGNUM ,
- ARC_AUX_MACMODE_REGNUM ,
- ARC_AUX_IRQ_LV12_REGNUM ,
-
- ARC_COUNT1_REGNUM ,
- ARC_CONTROL1_REGNUM ,
- ARC_LIMIT1_REGNUM ,
- ARC_AUX_IRQ_LEV_REGNUM ,
- ARC_AUX_IRQ_HINT_REGNUM ,
- ARC_ERET_REGNUM ,
- ARC_ERBTA_REGNUM ,
- ARC_ERSTATUS_REGNUM ,
- ARC_ECR_REGNUM ,
- ARC_EFA_REGNUM ,
- ARC_ICAUSE1_REGNUM ,
- ARC_ICAUSE2_REGNUM ,
- ARC_AUX_IENABLE_REGNUM ,
- ARC_AUX_ITRIGGER_REGNUM ,
- ARC_XPU_REGNUM ,
- ARC_BTA_REGNUM ,
- ARC_BTA_L1_REGNUM ,
- ARC_BTA_L2_REGNUM ,
- ARC_AUX_IRQ_PULSE_CANCEL_REGNUM ,
- ARC_AUX_IRQ_PENDING_REGNUM ,
-
- /* Build configuration registers. */
- ARC_BCR_0_REGNUM ,
- ARC_BCR_1_REGNUM ,
- ARC_BCR_2_REGNUM ,
- ARC_BCR_3_REGNUM ,
- ARC_BCR_4_REGNUM ,
- ARC_BCR_5_REGNUM ,
- ARC_BCR_6_REGNUM ,
- ARC_BCR_7_REGNUM ,
- ARC_BCR_8_REGNUM ,
- ARC_BCR_9_REGNUM ,
- ARC_BCR_A_REGNUM ,
- ARC_BCR_B_REGNUM ,
- ARC_BCR_C_REGNUM ,
- ARC_BCR_D_REGNUM ,
- ARC_BCR_E_REGNUM ,
- ARC_BCR_F_REGNUM ,
- ARC_BCR_10_REGNUM ,
- ARC_BCR_11_REGNUM ,
- ARC_BCR_12_REGNUM ,
-
- ARC_BCR_13_REGNUM ,
- ARC_BCR_14_REGNUM ,
- ARC_BCR_15_REGNUM ,
- ARC_BCR_16_REGNUM ,
- ARC_BCR_17_REGNUM ,
- ARC_BCR_18_REGNUM ,
- ARC_BCR_19_REGNUM ,
- ARC_BCR_1A_REGNUM ,
- ARC_BCR_1B_REGNUM ,
- ARC_BCR_1C_REGNUM ,
- ARC_BCR_1D_REGNUM ,
- ARC_BCR_1E_REGNUM ,
- ARC_BCR_1F_REGNUM ,
-
-
- ARC_NR_REGS
- };
+ ARC_PCL_REGNUM = 63,
+
+ /* end marker: this is not a register, but its integer value gives the number
+ * of registers
+ */
+ ARC_REG_END_MARKER
+};
+
+
+#define ARC_NR_PSEUDO_REGS 0
+#define ARC_NR_REGS (int) (arc_core_register_count(gdbarch) + \
+ arc_aux_register_count (gdbarch))
+#endif /* ARC_TM_EMBED_H */
+/******************************************************************************/
diff --git a/gdb/config/arc/tm-linux.h b/gdb/config/arc/tm-linux.h
index 18b12402fb0..15b0d9e8d0a 100644
--- a/gdb/config/arc/tm-linux.h
+++ b/gdb/config/arc/tm-linux.h
@@ -1,35 +1,87 @@
-#include "config/tm-linux.h"
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
-#define CONFIG_OSABI GDB_OSABI_LINUX
+ Copyright 2005, 2008, 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Codito Technologies Pvt. Ltd.
+ 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 header file defines register numbers for the arc-linux-uclibc */
+/* configuration of the ARC gdb. */
+/* */
+/******************************************************************************/
+
+#ifndef ARC_TM_LINUX_H
+#define ARC_TM_LINUX_H
+
+#include "arc-linux-tdep.h"
+
+
+#define CONFIG_OSABI GDB_OSABI_LINUX
/* Do nothing. */
-#define CONFIG_INIT_TDEP {}
+#define CONFIG_INIT_TDEP {}
+
enum arc700_linux_regnums
- {
- /* Regnums 0..26 are R0..R26 */
- ARC_BTA_REGNUM = 27,
- ARC_LP_START_REGNUM = 28,
- ARC_LP_END_REGNUM = 29,
- ARC_LP_COUNT_REGNUM = 30,
- ARC_STATUS32_REGNUM = 31,
- ARC_BLINK_REGNUM = 32,
- ARC_FP_REGNUM = 33,
- ARC_SP_REGNUM = 34,
- ARC_EFA_REGNUM = 35,
- ARC_RET_REGNUM = 36,
- ARC_ORIG_R8_REGNUM = 37,
- ARC_STOP_PC_REGNUM = 38
- };
-
-#define ARC_NR_REGS 39
-
-/* Pseudo-regs. */
-#define ARC_ILINK1_REGNUM (NUM_REGS)
-#define ARC_ILINK2_REGNUM (NUM_REGS+1)
-#define ARC_ERET_REGNUM (NUM_REGS+2)
-#define ARC_STATUS32_L1_REGNUM (NUM_REGS+3)
-#define ARC_STATUS32_L2_REGNUM (NUM_REGS+4)
-#define ARC_ERSTATUS_REGNUM (NUM_REGS+5)
-
-#define ARC_NR_PSEUDO_REGS 6
+{
+ /* Regnums 0 .. 26 are R0 .. R26 */
+ ARC_BTA_REGNUM = 27,
+ ARC_LP_START_REGNUM = 28,
+ ARC_LP_END_REGNUM = 29,
+ ARC_LP_COUNT_REGNUM = 30,
+ ARC_STATUS32_REGNUM = 31,
+ ARC_BLINK_REGNUM = 32,
+ ARC_FP_REGNUM = 33,
+ ARC_SP_REGNUM = 34,
+ ARC_EFA_REGNUM = 35,
+ ARC_RET_REGNUM = 36,
+ ARC_ORIG_R8_REGNUM = 37,
+ ARC_STOP_PC_REGNUM = 38,
+
+ /* end marker: this is not a register, but its integer value gives the number
+ * of registers
+ */
+ ARC_REG_END_MARKER
+};
+
+
+/* Pseudo-registers. */
+
+enum arc700_linux_pseudo_regnums
+{
+ ARC_ILINK1_REGNUM = (int) ARC_REG_END_MARKER,
+ ARC_ILINK2_REGNUM,
+ ARC_ERET_REGNUM,
+ ARC_STATUS32_L1_REGNUM,
+ ARC_STATUS32_L2_REGNUM,
+ ARC_ERSTATUS_REGNUM
+};
+
+
+#define ARC_NR_PSEUDO_REGS 6
+#define ARC_NR_REGS (int) ARC_REG_END_MARKER
+
+
+#endif /* ARC_TM_LINUX_H */
+/******************************************************************************/
diff --git a/gdb/configure b/gdb/configure
index e0f36b23f48..c39040b7cba 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -313,7 +313,7 @@ ac_includes_default="\
ac_subdirs_all="$ac_subdirs_all gdbtk"
ac_subdirs_all="$ac_subdirs_all multi-ice"
ac_subdirs_all="$ac_subdirs_all gdbserver"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir PACKAGE subdirs TARGET_OBS AWK INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S RANLIB ac_ct_RANLIB YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_MAJOR_VERSION TCL_MINOR_VERSION TCL_CC TCL_DEFS TCL_SHLIB_CFLAGS TCL_SHLIB_LD TCL_SHLIB_LD_LIBS TCL_SHLIB_SUFFIX TCL_DL_LIBS TCL_LD_FLAGS TCL_LD_SEARCH_FLAGS TCL_CC_SEARCH_FLAGS TCL_COMPAT_OBJS TCL_RANLIB TCL_BUILD_LIB_SPEC TCL_LIB_SPEC TCL_LIB_VERSIONS_OK TK_VERSION TK_DEFS TK_BUILD_INCLUDES TK_XINCLUDES TK_XLIBSW TK_BUILD_LIB_SPEC TK_LIB_SPEC TCLHDIR TKHDIR ITCLHDIR ITKHDIR ITCL_VERSION ITCL_DEFS ITCL_BUILD_INCLUDES ITCL_BUILD_LIB_SPEC ITCL_LIB_SPEC ITK_VERSION ITK_DEFS ITK_BUILD_INCLUDES ITK_BUILD_LIB_SPEC ITK_LIB_SPEC X_CFLAGS X_LDFLAGS X_LIBS TCL_DEPS TK_DEPS ITCLLIB ITCL_DEPS ITKLIB ITK_DEPS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBICONV LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT localedir PACKAGE subdirs TARGET_OBS AWK INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S RANLIB ac_ct_RANLIB YACC AR ac_ct_AR DLLTOOL ac_ct_DLLTOOL WINDRES ac_ct_WINDRES MIG ac_ct_MIG READLINE READLINE_DEPS READLINE_CFLAGS HAVE_LIBEXPAT LIBEXPAT LTLIBEXPAT XISS_INCLUDES ALLOCA CONFIG_LDFLAGS TARGET_SYSTEM_ROOT TARGET_SYSTEM_ROOT_DEFINE WARN_CFLAGS WERROR_CFLAGS SER_HARDWIRE WIN32LIBS LIBGUI GUI_CFLAGS_X WIN32LDAPP TCL_VERSION TCL_MAJOR_VERSION TCL_MINOR_VERSION TCL_CC TCL_DEFS TCL_SHLIB_CFLAGS TCL_SHLIB_LD TCL_SHLIB_LD_LIBS TCL_SHLIB_SUFFIX TCL_DL_LIBS TCL_LD_FLAGS TCL_LD_SEARCH_FLAGS TCL_CC_SEARCH_FLAGS TCL_COMPAT_OBJS TCL_RANLIB TCL_BUILD_LIB_SPEC TCL_LIB_SPEC TCL_LIB_VERSIONS_OK TK_VERSION TK_DEFS TK_BUILD_INCLUDES TK_XINCLUDES TK_XLIBSW TK_BUILD_LIB_SPEC TK_LIB_SPEC TCLHDIR TKHDIR ITCLHDIR ITKHDIR ITCL_VERSION ITCL_DEFS ITCL_BUILD_INCLUDES ITCL_BUILD_LIB_SPEC ITCL_LIB_SPEC ITK_VERSION ITK_DEFS ITK_BUILD_INCLUDES ITK_BUILD_LIB_SPEC ITK_LIB_SPEC X_CFLAGS X_LDFLAGS X_LIBS TCL_DEPS TK_DEPS ITCLLIB ITCL_DEPS ITKLIB ITK_DEPS GDBTKLIBS GDBTK_CFLAGS GDBTK_SRC_DIR SIM SIM_OBS ENABLE_CFLAGS PROFILE_CFLAGS CONFIG_OBS CONFIG_DEPS CONFIG_SRCS CONFIG_ALL CONFIG_CLEAN CONFIG_INSTALL CONFIG_UNINSTALL target_subdir frags nm_h LIBICONV LIBOBJS LTLIBOBJS'
ac_subst_files='host_makefile_frag'
# Initialize some variables set by options.
@@ -884,6 +884,7 @@ Optional Packages:
--with-gnu-ld assume the C compiler uses GNU ld default=no
--with-libexpat-prefix[=DIR] search for libexpat in DIR/include and DIR/lib
--without-libexpat-prefix don't search for libexpat in includedir and libdir
+ --with-xiss include xiss support (auto/yes/no)
--without-included-regex don't use included regex; this is the default
on systems with version 2 of the GNU C library
(use with caution on other system)
@@ -5573,9 +5574,179 @@ _ACEOF
fi
+echo "$as_me:$LINENO: checking for inflate" >&5
+echo $ECHO_N "checking for inflate... $ECHO_C" >&6
+if test "${ac_cv_func_inflate+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define inflate to an innocuous variant, in case <limits.h> declares inflate.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define inflate innocuous_inflate
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char inflate (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef inflate
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inflate ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_inflate) || defined (__stub___inflate)
+choke me
+#else
+char (*f) () = inflate;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != inflate;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_inflate=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_inflate=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_inflate" >&5
+echo "${ECHO_T}$ac_cv_func_inflate" >&6
+if test $ac_cv_func_inflate = yes; then
+ :
+else
+
+echo "$as_me:$LINENO: checking for inflate in -lz" >&5
+echo $ECHO_N "checking for inflate in -lz... $ECHO_C" >&6
+if test "${ac_cv_lib_z_inflate+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char inflate ();
+int
+main ()
+{
+inflate ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_z_inflate=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_z_inflate=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_z_inflate" >&5
+echo "${ECHO_T}$ac_cv_lib_z_inflate" >&6
+if test $ac_cv_lib_z_inflate = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+ LIBS="-lz $LIBS"
+
+fi
+
+fi
+
+
# We need to link with -lw to get `wctype' on Solaris before Solaris
# 2.6. Solaris 2.6 and beyond have this function in libc, and have a
-# libw that some versions of the GNU linker cannot hanle (GNU ld 2.9.1
+# libw that some versions of the GNU linker cannot handle (GNU ld 2.9.1
# is known to have this problem). Therefore we avoid libw if we can.
echo "$as_me:$LINENO: checking for wctype" >&5
echo $ECHO_N "checking for wctype... $ECHO_C" >&6
@@ -7228,6 +7399,52 @@ done
fi
fi
+
+
+# Check whether --with-xiss or --without-xiss was given.
+if test "${with_xiss+set}" = set; then
+ withval="$with_xiss"
+
+else
+ with_xiss=auto
+fi;
+echo "$as_me:$LINENO: checking whether to use xiss" >&5
+echo $ECHO_N "checking whether to use xiss... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $with_xiss" >&5
+echo "${ECHO_T}$with_xiss" >&6
+
+if test "${with_xiss}" = yes; then
+ HAVE_LIBXISS=yes
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_LIBXISS 1
+_ACEOF
+
+ XISS_INCLUDES="-I${with_xiss_prefix}/include"
+
+else
+ { echo "$as_me:$LINENO: WARNING: xiss support disabled; target arcxiss will be unavailable." >&5
+echo "$as_me: WARNING: xiss support disabled; target arcxiss will be unavailable." >&2;}
+ HAVE_LIBXISS=no
+fi
+
+
+if test "${target}" = "arc-unknown-elf32"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ARC_ELF32_TARGET 1
+_ACEOF
+
+fi
+if test "${target}" = "arc-unknown-linux-uclibc"; then
+
+cat >>confdefs.h <<\_ACEOF
+#define ARC_LINUX_TARGET 1
+_ACEOF
+
+fi
+
+
# ------------------------- #
# Checks for header files. #
# ------------------------- #
@@ -22997,7 +23214,7 @@ OLD_LIBS=$LIBS
CFLAGS="$CFLAGS -I${srcdir}/../include -I../bfd -I${srcdir}/../bfd"
LDFLAGS="$LDFLAGS -L../bfd -L../libiberty"
intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-LIBS="$LIBS -lbfd -liberty $intl"
+LIBS="$LIBS -lbfd -liberty $intl -lz"
echo "$as_me:$LINENO: checking for ELF support in BFD" >&5
echo $ECHO_N "checking for ELF support in BFD... $ECHO_C" >&6
if test "${gdb_cv_var_elf+set}" = set; then
@@ -24235,7 +24452,7 @@ ac_x_header_dirs='
/usr/openwin/share/include'
if test "$ac_x_includes" = no; then
- # Guess where to find include files, by looking for Intrinsic.h.
+ # Guess where to find include files, by looking for Xlib.h.
# First, try using that file with no special directory specified.
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
@@ -24243,7 +24460,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
_ACEOF
if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
(eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
@@ -24270,7 +24487,7 @@ else
sed 's/^/| /' conftest.$ac_ext >&5
for ac_dir in $ac_x_header_dirs; do
- if test -r "$ac_dir/X11/Intrinsic.h"; then
+ if test -r "$ac_dir/X11/Xlib.h"; then
ac_x_includes=$ac_dir
break
fi
@@ -24284,18 +24501,18 @@ if test "$ac_x_libraries" = no; then
# See if we find them without any special options.
# Don't add to $LIBS permanently.
ac_save_LIBS=$LIBS
- LIBS="-lXt $LIBS"
+ LIBS="-lX11 $LIBS"
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-#include <X11/Intrinsic.h>
+#include <X11/Xlib.h>
int
main ()
{
-XtMalloc (0)
+XrmInitialize ()
;
return 0;
}
@@ -25524,6 +25741,7 @@ s,@READLINE_CFLAGS@,$READLINE_CFLAGS,;t t
s,@HAVE_LIBEXPAT@,$HAVE_LIBEXPAT,;t t
s,@LIBEXPAT@,$LIBEXPAT,;t t
s,@LTLIBEXPAT@,$LTLIBEXPAT,;t t
+s,@XISS_INCLUDES@,$XISS_INCLUDES,;t t
s,@ALLOCA@,$ALLOCA,;t t
s,@CONFIG_LDFLAGS@,$CONFIG_LDFLAGS,;t t
s,@TARGET_SYSTEM_ROOT@,$TARGET_SYSTEM_ROOT,;t t
diff --git a/gdb/configure.ac b/gdb/configure.ac
index 39246aab825..8380c042241 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -381,9 +381,12 @@ AC_CHECK_TOOL(MIG, mig)
# We might need to link with -lm; most simulators need it.
AC_CHECK_LIB(m, main)
+AC_CHECK_FUNC(inflate, [],
+ [AC_CHECK_LIB(z, inflate)])
+
# We need to link with -lw to get `wctype' on Solaris before Solaris
# 2.6. Solaris 2.6 and beyond have this function in libc, and have a
-# libw that some versions of the GNU linker cannot hanle (GNU ld 2.9.1
+# libw that some versions of the GNU linker cannot handle (GNU ld 2.9.1
# is known to have this problem). Therefore we avoid libw if we can.
AC_CHECK_FUNC(wctype, [],
[AC_CHECK_LIB(w, wctype)])
@@ -477,6 +480,32 @@ else
fi
fi
+
+AC_ARG_WITH(xiss,
+ AS_HELP_STRING([--with-xiss], [include xiss support (auto/yes/no)]),
+ [], [with_xiss=auto])
+AC_MSG_CHECKING([whether to use xiss])
+AC_MSG_RESULT([$with_xiss])
+
+if test "${with_xiss}" = yes; then
+ HAVE_LIBXISS=yes
+ AC_DEFINE(HAVE_LIBXISS, 1, [Define if you have the xISS library.])
+ XISS_INCLUDES="-I${with_xiss_prefix}/include"
+ AC_SUBST(XISS_INCLUDES)
+else
+ AC_MSG_WARN([xiss support disabled; target arcxiss will be unavailable.])
+ HAVE_LIBXISS=no
+fi
+
+
+if test "${target}" = "arc-unknown-elf32"; then
+ AC_DEFINE(ARC_ELF32_TARGET, 1, [Define if you are building the ARC bare-board debugger.])
+fi
+if test "${target}" = "arc-unknown-linux-uclibc"; then
+ AC_DEFINE(ARC_LINUX_TARGET, 1, [Define if you are building the ARC Linux debugger.])
+fi
+
+
# ------------------------- #
# Checks for header files. #
# ------------------------- #
@@ -1414,7 +1443,7 @@ OLD_LIBS=$LIBS
CFLAGS="$CFLAGS -I${srcdir}/../include -I../bfd -I${srcdir}/../bfd"
LDFLAGS="$LDFLAGS -L../bfd -L../libiberty"
intl=`echo $LIBINTL | sed 's,${top_builddir}/,,g'`
-LIBS="$LIBS -lbfd -liberty $intl"
+LIBS="$LIBS -lbfd -liberty $intl -lz"
AC_CACHE_CHECK([for ELF support in BFD], gdb_cv_var_elf,
[AC_TRY_LINK(
[#include <stdlib.h>
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index ccfe674f80d..6a15d395cff 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -61,15 +61,19 @@ alpha*-*-*)
;;
arc*-*-linux*)
+ # Target: ARC Linux based targets
gdb_target_obs="arc-tdep.o arc-linux-tdep.o solib.o solib-svr4.o \
- solib-legacy.o corelow.o"
+ corelow.o"
build_gdbserver=yes
;;
-arc-a4-*)
- gdb_target_obs="arc-tdep.o arc-jtag.o arc-jtag-tdep.o arc-jtag-ops.o"
- ;;
+
arc*-*-*)
- gdb_target_obs="arc-tdep.o arc-jtag.o arc-jtag-tdep.o arc-jtag-ops.o"
+ # Target: ARC elf32 based target
+ gdb_target_obs="arc-tdep.o arc-jtag.o arc-elf32-tdep.o arc-jtag-ops.o \
+ arc-jtag-actionpoints.o arc-remote-fileio.o arc-xiss.o \
+ arc-registers.o arc-architecture.o arc-board.o \
+ arc-memory.o arc-arguments.o arc-gpio.o arc-inst-tracing.o"
+ gdb_sim=../sim/arc/libsim.a
;;
am33_2.0*-*-linux*)
diff --git a/gdb/doc/observer.texi b/gdb/doc/observer.texi
index e4c99d8e086..f1a9de56bd4 100644
--- a/gdb/doc/observer.texi
+++ b/gdb/doc/observer.texi
@@ -98,6 +98,23 @@ The inferior has stopped for real.
The target's register contents have changed.
@end deftypefun
+@deftypefun void target_pre_connect (struct target_ops *@var{target})
+Connection to the target is about to be performed.
+@end deftypefun
+
+@deftypefun void target_post_connect (struct target_ops *@var{target})
+Ccnnection to the target has just been performed.
+@end deftypefun
+
+@deftypefun void target_post_disconnect (struct target_ops *@var{target})
+Disconnection from the target has just been performed.
+@end deftypefun
+
+@deftypefun void target_updated (struct target_ops *@var{target})
+The target has been updated.
+@end deftypefun
+
+
@deftypefun void executable_changed (void *@var{unused_args})
The executable being debugged by GDB has changed: The user decided
to debug a different program, or the program he was debugging has
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 8db1b686a18..c4cd9f3d3ef 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -592,10 +592,6 @@ bad CFI data; mismatched DW_CFA_restore_state at 0x%s"), paddr (fs->pc));
fs->regs.reg[reg].loc.offset = -offset;
break;
- case DW_CFA_MWARC_info:
- /* Ignored. */
- insn_ptr = read_uleb128 (insn_ptr, insn_end, &utmp);
- break;
default:
internal_error (__FILE__, __LINE__, _("Unknown CFI encountered."));
}
@@ -1719,8 +1715,6 @@ decode_frame_entry_1 (struct comp_unit *unit, gdb_byte *start, int eh_frame_p)
augmentation += 2;
}
- if (augmentation[0] == 'H' && augmentation [1] == 'C')
- augmentation += 2;
cie->code_alignment_factor =
read_unsigned_leb128 (unit->abfd, buf, &bytes_read);
buf += bytes_read;
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 7deb08e25ba..bf589a2d840 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -265,8 +265,89 @@ dwarf2_evaluate_loc_desc (struct symbol *var, struct frame_info *frame,
return retval;
}
+// begin ARC
+static CORE_ADDR
+dwarf2_find_address (struct symbol *var, struct frame_info *frame,
+ gdb_byte *data, unsigned short size,
+ struct objfile *objfile)
+{
+ struct gdbarch *arch = get_frame_arch (frame);
+ struct value *retval;
+ struct dwarf_expr_baton baton;
+ struct dwarf_expr_context *ctx;
+ CORE_ADDR address;
+
+ /* optimised out */
+ if (size == 0)
+ return 0;
+
+ baton.frame = frame;
+ baton.objfile = objfile;
+
+ ctx = new_dwarf_expr_context ();
+ ctx->baton = &baton;
+ ctx->read_reg = dwarf_expr_read_reg;
+ ctx->read_mem = dwarf_expr_read_mem;
+ ctx->get_frame_base = dwarf_expr_frame_base;
+ ctx->get_tls_address = dwarf_expr_tls_address;
+
+ dwarf_expr_eval (ctx, data, size);
+ if (ctx->num_pieces > 0)
+ {
+ /* what should we do here? */
+ address = 0;
+ }
+ else if (ctx->in_reg)
+ address = 0;
+ else
+ address = dwarf_expr_fetch (ctx, 0);
+
+ free_dwarf_expr_context (ctx);
+
+ return address;
+}
+static unsigned int
+dwarf2_find_size (struct symbol *var, struct frame_info *frame,
+ gdb_byte *data, unsigned short size,
+ struct objfile *objfile)
+{
+ struct gdbarch *arch = get_frame_arch (frame);
+ struct dwarf_expr_baton baton;
+ struct dwarf_expr_context *ctx;
+ unsigned int sz;
+
+ /* optimised out */
+ if (size == 0)
+ return 0;
+
+ baton.frame = frame;
+ baton.objfile = objfile;
+
+ ctx = new_dwarf_expr_context ();
+ ctx->baton = &baton;
+ ctx->read_reg = dwarf_expr_read_reg;
+ ctx->read_mem = dwarf_expr_read_mem;
+ ctx->get_frame_base = dwarf_expr_frame_base;
+ ctx->get_tls_address = dwarf_expr_tls_address;
+
+ dwarf_expr_eval (ctx, data, size);
+ if (ctx->num_pieces > 0)
+ {
+ /* what should we do here? */
+ sz = 0;
+ }
+ else if (ctx->in_reg)
+ sz = 0;
+ else
+ sz = TYPE_LENGTH (SYMBOL_TYPE (var));
+
+ free_dwarf_expr_context (ctx);
+
+ return sz;
+}
+// end ARC
/* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
@@ -434,6 +515,30 @@ locexpr_read_variable (struct symbol *symbol, struct frame_info *frame)
return val;
}
+// begin ARC
+/* Return the address of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static CORE_ADDR
+locexpr_get_variable_address (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ return dwarf2_find_address (symbol, frame, dlbaton->data, dlbaton->size,
+ dlbaton->objfile);
+}
+
+/* Return the size of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static unsigned int
+locexpr_get_variable_size(struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+
+ return dwarf2_find_size (symbol, frame, dlbaton->data, dlbaton->size,
+ dlbaton->objfile);
+}
+// end ARC
+
/* Return non-zero iff we need a frame to evaluate SYMBOL. */
static int
locexpr_read_needs_frame (struct symbol *symbol)
@@ -516,6 +621,10 @@ locexpr_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
evaluator. */
const struct symbol_ops dwarf2_locexpr_funcs = {
locexpr_read_variable,
+// begin ARC
+ locexpr_get_variable_address,
+ locexpr_get_variable_size,
+// end ARC
locexpr_read_needs_frame,
locexpr_describe_location,
locexpr_tracepoint_var_ref
@@ -551,6 +660,46 @@ loclist_read_variable (struct symbol *symbol, struct frame_info *frame)
return val;
}
+// begin ARC
+/* Return the address of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static CORE_ADDR
+loclist_get_variable_address (struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ struct value *val;
+ gdb_byte *data;
+ size_t size;
+
+ data = find_location_expression (dlbaton, &size,
+ frame ? get_frame_address_in_block (frame)
+ : 0);
+ if (data == NULL)
+ return 0;
+
+ return dwarf2_find_address(symbol, frame, data, size, dlbaton->objfile);
+}
+
+/* Return the size of SYMBOL in FRAME using the DWARF-2 expression
+ evaluator to calculate the location. */
+static unsigned int
+loclist_get_variable_size(struct symbol *symbol, struct frame_info *frame)
+{
+ struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (symbol);
+ struct value *val;
+ gdb_byte *data;
+ size_t size;
+
+ data = find_location_expression (dlbaton, &size,
+ frame ? get_frame_address_in_block (frame)
+ : 0);
+ if (data == NULL)
+ return 0;
+
+ return dwarf2_find_size(symbol, frame, data, size, dlbaton->objfile);
+}
+// end ARC
+
/* Return non-zero iff we need a frame to evaluate SYMBOL. */
static int
loclist_read_needs_frame (struct symbol *symbol)
@@ -594,6 +743,10 @@ loclist_tracepoint_var_ref (struct symbol * symbol, struct agent_expr * ax,
evaluator and location lists. */
const struct symbol_ops dwarf2_loclist_funcs = {
loclist_read_variable,
+// begin ARC
+ loclist_get_variable_address,
+ loclist_get_variable_size,
+// end ARC
loclist_read_needs_frame,
loclist_describe_location,
loclist_tracepoint_var_ref
diff --git a/gdb/exec.c b/gdb/exec.c
index 7648b0317a6..2ffeba4dc91 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -31,7 +31,7 @@
#include "value.h"
#include "exec.h"
#include "observer.h"
-#include "arch-utils.c"
+#include "arch-utils.h" /* richards ARC 23/9/08: change .c to .h gdb bug: 9888 */
#include <fcntl.h>
#include "readline/readline.h"
diff --git a/gdb/features/arc-a5-cpu.xml b/gdb/features/arc-a5-cpu.xml
new file mode 100644
index 00000000000..7ff602b23b6
--- /dev/null
+++ b/gdb/features/arc-a5-cpu.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target version="1.0">
+<architecture>A5</architecture>
+<feature name="org.gnu.gdb.arc.registers">
+
+ <auxregister name="STATUS" description="Status (obsolete)" number="0x0" mask ="0xFEFFFFFF" access="RO">
+ <field name="PC" description="program counter (PC[25:2])" size="24" offset="0" access="RO" />
+ <field name="H" description="halt bit" size="1" offset="25" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="interrupt mask bit" size="1" offset="26" access="RO" />
+ <field name="E2" description="interrupt mask bit" size="1" offset="27" access="RO" />
+ <field name="V" description="overflow flag" size="1" offset="28" access="RO" />
+ <field name="C" description="carry flag" size="1" offset="29" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="30" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="31" access="RO" />
+ </auxregister>
+
+ <auxregister name="SEMAPHORE" description="Semaphore" number="0x1" mask ="0x0000000F" access="RW">
+ <field name="S0" description="inter-process/host semaphore 0" size="1" offset="0" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S1" description="inter-process/host semaphore 1" size="1" offset="1" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S2" description="inter-process/host semaphore 2" size="1" offset="2" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S3" description="inter-process/host semaphore 3" size="1" offset="3" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LP_START" description="Loop Start" number="0x2" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="LP_END" description="Loop End" number="0x3" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="IDENTITY" description="Identity" number="0x4" mask ="0xFFFFFFFF" access="RO">
+ <field name="CHIPID" description="unique chip identifier" size="16" offset="16" access="RO" />
+ <field name="ARCNUM" description="additional identity number" size= "8" offset= "8" access="RO" />
+ <field name="ARCVER" description="basecase version number" size= "8" offset= "0" access="RO" />
+ </auxregister>
+
+ <auxregister name="DEBUG" description="Debug" number="0x5" mask ="0xF0800802" access="RW">
+ <field name ="FH" description="force halt" size="1" offset="1" access="WO"/>
+ <field name ="IS" description="single step" size="1" offset="11" access="RW">
+ <meaning value="1" description="single instruction stepping is in force"/>
+ </field>
+ <field name ="ZZ" description="sleep mode" size="1" offset="23" access="RO">
+ <meaning value="1" description="processor is in sleep mode"/>
+ </field>
+ <field name ="BH" description="breakpoint halt" size="1" offset="29" access="RO">
+ <meaning value="1" description="a BRK instruction has been triggered"/>
+ </field>
+ <field name ="SH" description="self halt" size="1" offset="30" access="RO">
+ <meaning value="1" description="processor has halted itself"/>
+ </field>
+ <field name ="LD" description="load pending" size="1" offset="31" access="RO">
+ <meaning value="1" description="a delayed load is waiting to complete"/>
+ </field>
+
+<!-- for testing
+ <field name ="LD" description="duplicate!" size="1" offset="10" access="RO"/>
+ <field name ="OV" description="overlap!" size="3" offset="27" access="RO"/>
+ <field name ="BG" description="too big!" size="8" offset="27" access="RO"/>
+ -->
+ </auxregister>
+
+ <auxregister name="PC" description="program counter" number="0x6" mask ="0xFFFFFFFE" access="RW"/>
+
+ <auxregister name="STATUS32" description="status flags" number="0xA" mask ="0x00001FFF" access="RW" >
+ <field name="H" description="halt bit" size="1" offset= "0" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="STATUS32_L1" description="STATUS32 register in case of L1 interrupts" number="0xB" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="STATUS32_L2" description="STATUS32 register in case of L2 interrupts" number="0xC" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="COUNT0" description="Processor Timer 0 Count Value" number="0x21" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL0" description="Processor Timer 0 Control Value" number="0x22" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT0" description="Processor Timer 0 Limit Value" number="0x23" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="INT_VECTOR_BASE" description="Interrupt Vector Base Register" number="0x25" mask ="0xFFFFFC00" access="RW"/>
+
+ <auxregister name="AUX_MACMODE" description="Aux MAC Mode" number="0x41" mask ="0xFFFFFFFF" access="RW" >
+ <field name="CS" description="" size="1" offset="1" access="RW" >
+ </field>
+ <field name="S2" description="channel 2 saturation flag" size="1" offset="4" access="RO" >
+ <meaning value="1" description="channel 2 has saturated"/>
+ </field>
+ <field name="S1" description="channel 1 saturation flag" size="1" offset="9" access="RO" >
+ <meaning value="1" description="channel 1 has saturated"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_LV12" description="Aux IRQ Level 2" number="0x43" mask ="0x00000003" access="RW" >
+ <field name="L1" description="level 1 interrupt status bit" size="1" offset="0" access="RW" >
+ <meaning value="1" description="level 1 interrupt has been taken"/>
+ </field>
+ <field name="L2" description="level 2 interrupt status bit" size="1" offset="1" access="RW" >
+ <meaning value="1" description="level 2 interrupt has been taken"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="COUNT1" description="Processor Timer 1 Count Value" number="0x100" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL1" description="Processor Timer 1 Control Value" number="0x101" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT1" description="Processor Timer 1 Limit Value" number="0x102" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="AUX_IRQ_LEV" description="Interrupt Level programming" number="0x200" mask ="0xFFFFFFF8" access="RW" >
+ <field name="reserved" onwrite="0" size="3" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_HINT" description="Software Triggered Interrupt" number="0x201" mask ="0x0000001F" access="RW"/>
+
+ <!-- cache control registers -->
+
+ <!-- N.B. are the Invalidation registers write-only? -->
+
+ <auxregister name="IC_IVIC" description="Instruction Cache Invalidation Register" number="0x10" mask ="0xFFFFFFFF" access="WO"/>
+ <auxregister name="IC_CTRL" description="Instruction Cache Control Register" number="0x11" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="DC_IVDC" description="Data Cache Invalidation Register" number="0x47" mask ="0xFFFFFFFF" access="WO"/>
+ <auxregister name="DC_CTRL" description="Data Cache Control Register" number="0x48" mask ="0xFFFFFFFF" access="RW"/>
+
+
+ <!-- actionpoint 0 registers -->
+
+ <auxregister name="AMV0" description="Actionpoint 0 Match Value Register" number="0x220" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AMM0" description="Actionpoint 0 Match Mask Register" number="0x221" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AC0" description="Actionpoint 0 Control Register" number="0x222" mask ="0xFFFFFFFF" access="RW"/>
+
+
+ <!-- Build Configuration Registers -->
+
+ <bcr name="BCR_VER" description="Build Configuration Registers Version" number="0x60" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BASE_BUILD" description="Base Address for Data Closely Coupled Memory" number="0x61" mask="0xFFFFFFFF"/>
+ <bcr name="CRC_BASE_BUILD" description="CRC Unit BCR" number="0x62" mask="0xFFFFFFFF"/>
+ <bcr name="DVBF_BUILD" description="Dual Viterbi Instruction BCR" number="0x64" mask="0xFFFFFFFF"/>
+ <bcr name="TEL_INSTR_BUILD" description="Extended Arithmetic Instructions BCR" number="0x65" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x66" mask="0xFFFFFFFF"/>
+ <bcr name="MEMSUBSYS" description="Memory Subsystem BCR" number="0x67" mask="0xFFFFFFFF"/>
+ <bcr name="VECBASE_AC_BUILD" description="Interrupt Vector Base BCR" number="0x68" mask="0xFFFFFFFF"/>
+ <bcr name="P_BASE_ADDRESS" description="Peripheral Base Address" number="0x69" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6A" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6B" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6C" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6D" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6E" mask="0xFFFFFFFF"/>
+ <bcr name="MMU_BUILD" description="Memory Management Unit BCR" number="0x6F" mask="0xFFFFFFFF"/>
+ <bcr name="ARCANGEL_BUILD" description="ARCAngel BCR" number="0x70" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x71" mask="0xFFFFFFFF"/>
+ <bcr name="DCACHE_BUILD" description="Data Cache BCR" number="0x72" mask="0xFFFFFFFF"/>
+ <bcr name="MADI_BUILD" description="Multiple ARC Debug Interface" number="0x73" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BUILD" description="Data Closely Coupled Memory BCR" number="0x74" mask="0xFFFFFFFF"/>
+ <bcr name="TIMER_BUILD" description="Timers BCR" number="0x75" mask="0xFFFFFFFF"/>
+ <bcr name="AP_BUILD" description="Actionpoints BCR" number="0x76" mask="0xFFFFFFFF"/>
+ <bcr name="ICACHE_BUILD" description="Instruction Cache BCR" number="0x77" mask="0xFFFFFFFF"/>
+ <bcr name="ICCM_BUILD" description="Instruction Closely Coupled Memory BCR" number="0x78" mask="0xFFFFFFFF"/>
+ <bcr name="DSPRAM_BUILD" description="DSP RAM BCR" number="0x79" mask="0xFFFFFFFF"/>
+ <bcr name="MAC_BUILD" description="MAC Unit BCR" number="0x7A" mask="0xFFFFFFFF"/>
+ <bcr name="MULTIPLY_BUILD" description="(32 X 32) Multiply Unit BCR" number="0x7B" mask="0xFFFFFFFF"/>
+ <bcr name="SWAP_BUILD" description="SWAP BCR" number="0x7C" mask="0xFFFFFFFF"/>
+ <bcr name="NORM_BUILD" description="NORM Unit BCR" number="0x7D" mask="0xFFFFFFFF"/>
+ <bcr name="MINMAX_BUILD" description="Minmax Unit BCR" number="0x7E" mask="0xFFFFFFFF"/>
+ <bcr name="BARREL_BUILD" description="Barrel Shifter BCR" number="0x7F" mask="0xFFFFFFFF"/>
+
+<!-- for testing
+
+ <auxregister name="TEST" description="any old bucket of bits" number="0x99999" mask ="0xFFFFFFFF" access="RW">
+ <field name ="AA" description="" size="1" offset="5" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ </field>
+ <field name ="BBBB" description="" size="3" offset="8" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ <meaning value="3" description="value is 3"/>
+ <meaning value="7" description="value is 7"/>
+ </field>
+ <field name ="CCCCCCCCC" description="" size="8" offset="17" access="RO">
+ </field>
+ </auxregister>
+ -->
+
+</feature>
+</target>
diff --git a/gdb/features/arc-registers.dtd b/gdb/features/arc-registers.dtd
new file mode 100644
index 00000000000..b050fa0d3a7
--- /dev/null
+++ b/gdb/features/arc-registers.dtd
@@ -0,0 +1,71 @@
+<!-- Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!-- The root element of an ARC registers description is <target>. -->
+
+<!-- Auxiliary Registers -->
+
+<!ELEMENT target (architecture?, feature*)>
+<!ATTLIST target
+ version CDATA #FIXED "1.0">
+
+<!ELEMENT architecture (#PCDATA)>
+
+<!ELEMENT feature (auxregister*,bcr*,ecr*)>
+<!ATTLIST feature
+ name ID #REQUIRED>
+
+<!ELEMENT auxregister (field*)>
+<!ATTLIST auxregister
+ name CDATA #REQUIRED
+ description CDATA #IMPLIED
+ number CDATA #REQUIRED
+ mask CDATA #IMPLIED
+ access (RO | RW | WO) 'RW'
+ >
+
+<!ELEMENT field (meaning*)>
+<!ATTLIST field
+ name CDATA #REQUIRED
+ description CDATA #IMPLIED
+ onwrite CDATA #IMPLIED
+ offset CDATA #REQUIRED
+ size CDATA #REQUIRED
+ access (RO | RW | WO) 'RW'
+ >
+
+<!ELEMENT meaning EMPTY>
+<!ATTLIST meaning
+ description CDATA #REQUIRED
+ value CDATA #REQUIRED
+ >
+
+<!-- Build Configuration Registers -->
+
+<!ELEMENT bcr (bcrfield*)>
+<!ATTLIST bcr
+ name CDATA #REQUIRED
+ description CDATA #IMPLIED
+ number CDATA #REQUIRED
+ mask CDATA #IMPLIED
+ >
+
+<!ELEMENT bcrfield >
+<!ATTLIST bcrfield
+ name CDATA #REQUIRED
+ description CDATA #IMPLIED
+ offset CDATA #REQUIRED
+ size CDATA #REQUIRED
+ >
+
+<!-- Extension Core Registers -->
+
+<!ELEMENT ecr>
+<!ATTLIST ecr
+ number CDATA #REQUIRED
+ mask CDATA #IMPLIED
+ access (RO | RW | WO) 'RW'
+ >
diff --git a/gdb/features/arc600-cpu.xml b/gdb/features/arc600-cpu.xml
new file mode 100644
index 00000000000..1ecaee4ef86
--- /dev/null
+++ b/gdb/features/arc600-cpu.xml
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target version="1.0">
+<architecture>ARC600</architecture>
+<feature name="org.gnu.gdb.arc.registers">
+
+ <auxregister name="STATUS" description="Status (obsolete)" number="0x0" mask ="0xFEFFFFFF" access="RO">
+ <field name="PC" description="program counter (PC[25:2])" size="24" offset="0" access="RO" />
+ <field name="H" description="halt bit" size="1" offset="25" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="interrupt mask bit" size="1" offset="26" access="RO" />
+ <field name="E2" description="interrupt mask bit" size="1" offset="27" access="RO" />
+ <field name="V" description="overflow flag" size="1" offset="28" access="RO" />
+ <field name="C" description="carry flag" size="1" offset="29" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="30" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="31" access="RO" />
+ </auxregister>
+
+ <auxregister name="SEMAPHORE" description="Semaphore" number="0x1" mask ="0x0000000F" access="RW">
+ <field name="S0" description="inter-process/host semaphore 0" size="1" offset="0" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S1" description="inter-process/host semaphore 1" size="1" offset="1" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S2" description="inter-process/host semaphore 2" size="1" offset="2" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ <field name="S3" description="inter-process/host semaphore 3" size="1" offset="3" access="RW" >
+ <meaning value="1" description="semaphore has been obtained"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LP_START" description="Loop Start" number="0x2" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="LP_END" description="Loop End" number="0x3" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="IDENTITY" description="Identity" number="0x4" mask ="0xFFFFFFFF" access="RO">
+ <field name="CHIPID" description="unique chip identifier" size="16" offset="16" access="RO" />
+ <field name="ARCNUM" description="additional identity number" size= "8" offset= "8" access="RO" />
+ <field name="ARCVER" description="basecase version number" size= "8" offset= "0" access="RO" />
+ </auxregister>
+
+ <auxregister name="DEBUG" description="Debug" number="0x5" mask ="0xF0800802" access="RW">
+ <field name ="FH" description="force halt" size="1" offset="1" access="WO"/>
+ <field name ="IS" description="single step" size="1" offset="11" access="RW">
+ <meaning value="1" description="single instruction stepping is in force"/>
+ </field>
+ <field name ="ZZ" description="sleep mode" size="1" offset="23" access="RO">
+ <meaning value="1" description="processor is in sleep mode"/>
+ </field>
+ <field name ="BH" description="breakpoint halt" size="1" offset="29" access="RO">
+ <meaning value="1" description="a BRK instruction has been triggered"/>
+ </field>
+ <field name ="SH" description="self halt" size="1" offset="30" access="RO">
+ <meaning value="1" description="processor has halted itself"/>
+ </field>
+ <field name ="LD" description="load pending" size="1" offset="31" access="RO">
+ <meaning value="1" description="a delayed load is waiting to complete"/>
+ </field>
+
+<!-- for testing
+ <field name ="LD" description="duplicate!" size="1" offset="10" access="RO"/>
+ <field name ="OV" description="overlap!" size="3" offset="27" access="RO"/>
+ <field name ="BG" description="too big!" size="8" offset="27" access="RO"/>
+ -->
+ </auxregister>
+
+ <auxregister name="PC" description="program counter" number="0x6" mask ="0xFFFFFFFE" access="RW"/>
+
+ <auxregister name="STATUS32" description="status flags" number="0xA" mask ="0x00001FFF" access="RW" >
+ <field name="H" description="halt bit" size="1" offset= "0" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="STATUS32_L1" description="STATUS32 register in case of L1 interrupts" number="0xB" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="STATUS32_L2" description="STATUS32 register in case of L2 interrupts" number="0xC" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ </auxregister>
+
+ <auxregister name="COUNT0" description="Processor Timer 0 Count Value" number="0x21" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL0" description="Processor Timer 0 Control Value" number="0x22" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="IP" description="Interrupt Pending flag" size="1" offset="3" access="RW" >
+ <meaning value="0" description="timer 0 interrupt line is low" />
+ <meaning value="1" description="timer 0 interrupt line is high" />
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT0" description="Processor Timer 0 Limit Value" number="0x23" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="INT_VECTOR_BASE" description="Interrupt Vector Base Register" number="0x25" mask ="0xFFFFFC00" access="RW"/>
+
+ <auxregister name="AUX_MACMODE" description="Aux MAC Mode" number="0x41" mask ="0xFFFFFFFF" access="RW" >
+ <field name="CS" description="" size="1" offset="1" access="RW" >
+ </field>
+ <field name="S2" description="channel 2 saturation flag" size="1" offset="4" access="RO" >
+ <meaning value="1" description="channel 2 has saturated"/>
+ </field>
+ <field name="S1" description="channel 1 saturation flag" size="1" offset="9" access="RO" >
+ <meaning value="1" description="channel 1 has saturated"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_LV12" description="Aux IRQ Level 2" number="0x43" mask ="0x00000003" access="RW" >
+ <field name="L1" description="level 1 interrupt status bit" size="1" offset="0" access="RW" >
+ <meaning value="1" description="level 1 interrupt has been taken"/>
+ </field>
+ <field name="L2" description="level 2 interrupt status bit" size="1" offset="1" access="RW" >
+ <meaning value="1" description="level 2 interrupt has been taken"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="COUNT1" description="Processor Timer 1 Count Value" number="0x100" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL1" description="Processor Timer 1 Control Value" number="0x101" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="IP" description="Interrupt Pending flag" size="1" offset="3" access="RW" >
+ <meaning value="0" description="timer 1 interrupt line is low" />
+ <meaning value="1" description="timer 1 interrupt line is high" />
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT1" description="Processor Timer 1 Limit Value" number="0x102" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="AUX_IRQ_LEV" description="Interrupt Level programming" number="0x200" mask ="0xFFFFFFF8" access="RW" >
+ <field name="reserved" onwrite="0" size="3" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_HINT" description="Software Triggered Interrupt" number="0x201" mask ="0x0000001F" access="RW"/>
+
+ <!-- cache control registers -->
+
+ <!-- N.B. are the Invalidation registers write-only? -->
+
+ <auxregister name="IC_IVIC" description="Instruction Cache Invalidation Register" number="0x10" mask ="0xFFFFFFFF" access="WO"/>
+ <auxregister name="IC_CTRL" description="Instruction Cache Control Register" number="0x11" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="DC_IVDC" description="Data Cache Invalidation Register" number="0x47" mask ="0xFFFFFFFF" access="WO"/>
+ <auxregister name="DC_CTRL" description="Data Cache Control Register" number="0x48" mask ="0xFFFFFFFF" access="RW"/>
+
+
+ <!-- actionpoint 0 registers -->
+
+ <auxregister name="AMV0" description="Actionpoint 0 Match Value Register" number="0x220" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AMM0" description="Actionpoint 0 Match Mask Register" number="0x221" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AC0" description="Actionpoint 0 Control Register" number="0x222" mask ="0xFFFFFFFF" access="RW"/>
+
+
+ <!-- Build Configuration Registers -->
+
+ <bcr name="BCR_VER" description="Build Configuration Registers Version" number="0x60" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BASE_BUILD" description="Base Address for Data Closely Coupled Memory" number="0x61" mask="0xFFFFFFFF"/>
+ <bcr name="CRC_BASE_BUILD" description="CRC Unit BCR" number="0x62" mask="0xFFFFFFFF"/>
+ <bcr name="DVBF_BUILD" description="Dual Viterbi Instruction BCR" number="0x64" mask="0xFFFFFFFF"/>
+ <bcr name="TEL_INSTR_BUILD" description="Extended Arithmetic Instructions BCR" number="0x65" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x66" mask="0xFFFFFFFF"/>
+ <bcr name="MEMSUBSYS" description="Memory Subsystem BCR" number="0x67" mask="0xFFFFFFFF"/>
+ <bcr name="VECBASE_AC_BUILD" description="Interrupt Vector Base BCR" number="0x68" mask="0xFFFFFFFF"/>
+ <bcr name="P_BASE_ADDRESS" description="Peripheral Base Address" number="0x69" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6A" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6B" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6C" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6D" mask="0xFFFFFFFF"/>
+ <bcr name="RF_BUILD" description="Core Registers BCR" number="0x6E" mask="0xFFFFFFFF"/>
+ <bcr name="MMU_BUILD" description="Memory Management Unit BCR" number="0x6F" mask="0xFFFFFFFF"/>
+ <bcr name="ARCANGEL_BUILD" description="ARCAngel BCR" number="0x70" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x71" mask="0xFFFFFFFF"/>
+ <bcr name="DCACHE_BUILD" description="Data Cache BCR" number="0x72" mask="0xFFFFFFFF"/>
+ <bcr name="MADI_BUILD" description="Multiple ARC Debug Interface" number="0x73" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BUILD" description="Data Closely Coupled Memory BCR" number="0x74" mask="0xFFFFFFFF"/>
+ <bcr name="TIMER_BUILD" description="Timers BCR" number="0x75" mask="0xFFFFFFFF"/>
+ <bcr name="AP_BUILD" description="Actionpoints BCR" number="0x76" mask="0xFFFFFFFF"/>
+ <bcr name="ICACHE_BUILD" description="Instruction Cache BCR" number="0x77" mask="0xFFFFFFFF"/>
+ <bcr name="ICCM_BUILD" description="Instruction Closely Coupled Memory BCR" number="0x78" mask="0xFFFFFFFF"/>
+ <bcr name="DSPRAM_BUILD" description="DSP RAM BCR" number="0x79" mask="0xFFFFFFFF"/>
+ <bcr name="MAC_BUILD" description="MAC Unit BCR" number="0x7A" mask="0xFFFFFFFF"/>
+ <bcr name="MULTIPLY_BUILD" description="(32 X 32) Multiply Unit BCR" number="0x7B" mask="0xFFFFFFFF"/>
+ <bcr name="SWAP_BUILD" description="SWAP BCR" number="0x7C" mask="0xFFFFFFFF"/>
+ <bcr name="NORM_BUILD" description="NORM Unit BCR" number="0x7D" mask="0xFFFFFFFF"/>
+ <bcr name="MINMAX_BUILD" description="Minmax Unit BCR" number="0x7E" mask="0xFFFFFFFF"/>
+ <bcr name="BARREL_BUILD" description="Barrel Shifter BCR" number="0x7F" mask="0xFFFFFFFF"/>
+
+<!-- for testing
+
+ <auxregister name="TEST" description="any old bucket of bits" number="0x99999" mask ="0xFFFFFFFF" access="RW">
+ <field name ="AA" description="" size="1" offset="5" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ </field>
+ <field name ="BBBB" description="" size="3" offset="8" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ <meaning value="3" description="value is 3"/>
+ <meaning value="7" description="value is 7"/>
+ </field>
+ <field name ="CCCCCCCCC" description="" size="8" offset="17" access="RO">
+ </field>
+ </auxregister>
+ -->
+
+</feature>
+</target>
diff --git a/gdb/features/arc700-cpu.xml b/gdb/features/arc700-cpu.xml
new file mode 100644
index 00000000000..5fa97d23356
--- /dev/null
+++ b/gdb/features/arc700-cpu.xml
@@ -0,0 +1,416 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target version="1.0">
+<architecture>ARC700</architecture>
+<feature name="org.gnu.gdb.arc.registers">
+
+ <auxregister name="STATUS" description="Status (obsolete)" number="0x0" mask ="0xFEFFFFFF" access="RO">
+ <field name="PC" description="program counter (PC[25:2])" size="24" offset="0" access="RO" />
+ <field name="H" description="halt bit" size="1" offset="25" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="interrupt mask bit" size="1" offset="26" access="RO" />
+ <field name="E2" description="interrupt mask bit" size="1" offset="27" access="RO" />
+ <field name="V" description="overflow flag" size="1" offset="28" access="RO" />
+ <field name="C" description="carry flag" size="1" offset="29" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="30" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="31" access="RO" />
+ </auxregister>
+
+ <auxregister name="LP_START" description="Loop Start" number="0x2" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="LP_END" description="Loop End" number="0x3" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="IDENTITY" description="Identity" number="0x4" mask ="0xFFFFFFFF" access="RO">
+ <field name="CHIPID" description="unique chip identifier" size="16" offset="16" access="RO" />
+ <field name="ARCNUM" description="additional identity number" size= "8" offset= "8" access="RO" />
+ <field name="ARCVER" description="basecase version number" size= "8" offset= "0" access="RO" />
+ </auxregister>
+
+ <auxregister name="DEBUG" description="Debug" number="0x5" mask ="0xF0800802" access="RW">
+ <field name ="FH" description="force halt" size="1" offset="1" access="WO"/>
+ <field name ="IS" description="single step" size="1" offset="11" access="RW">
+ <meaning value="1" description="single instruction stepping is in force"/>
+ </field>
+ <field name ="ZZ" description="sleep mode" size="1" offset="23" access="RO">
+ <meaning value="1" description="processor is in sleep mode"/>
+ </field>
+ <field name ="UB" description="user mode BRK" size="1" offset="28" access="RW">
+ <meaning value="0" description="BRK instructions can not be used in User mode"/>
+ <meaning value="1" description="BRK instructions can be used in User mode"/>
+ </field>
+ <field name ="BH" description="breakpoint halt" size="1" offset="29" access="RO">
+ <meaning value="1" description="a BRK instruction has been triggered"/>
+ </field>
+ <field name ="SH" description="self halt" size="1" offset="30" access="RO">
+ <meaning value="1" description="processor has halted itself"/>
+ </field>
+ <field name ="LD" description="load pending" size="1" offset="31" access="RO">
+ <meaning value="1" description="a delayed load is waiting to complete"/>
+ </field>
+
+<!-- for testing
+ <field name ="LD" description="duplicate!" size="1" offset="10" access="RO"/>
+ <field name ="OV" description="overlap!" size="3" offset="27" access="RO"/>
+ <field name ="BG" description="too big!" size="8" offset="27" access="RO"/>
+ -->
+ </auxregister>
+
+ <auxregister name="PC" description="program counter" number="0x6" mask ="0xFFFFFFFE" access="RW"/>
+
+ <auxregister name="STATUS32" description="status flags" number="0xA" mask ="0x00001FFF" access="RW" >
+ <field name="H" description="halt bit" size="1" offset= "0" access="RO" >
+ <meaning value="1" description="processor is halted"/>
+ </field>
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="A1" description="level 1 interrupt bit" size="1" offset= "3" access="RO" >
+ <meaning value="1" description="a level 1 interrupt service routine is active"/>
+ </field>
+ <field name="A2" description="level 2 interrupt bit" size="1" offset= "4" access="RO" >
+ <meaning value="1" description="a level 2 interrupt service routine is active"/>
+ </field>
+ <field name="AE" description="exception bit" size="1" offset= "5" access="RO" >
+ <meaning value="1" description="an exception is active"/>
+ </field>
+ <field name="DE" description="delay slot bit" size="1" offset= "6" access="RO" >
+ <meaning value="1" description="instruction addressed by PC32 is in the delay slot of a taken branch"/>
+ </field>
+ <field name="U" description="User mode bit" size="1" offset= "7" access="RW" >
+ <meaning value="0" description="processor is in Kernel mode"/>
+ <meaning value="1" description="processor is in User mode"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ <field name="L" description="zero overhead loop bit" size="1" offset="12" access="RO" >
+ <meaning value="0" description="zero overhead loop mechanism is enabled"/>
+ <meaning value="1" description="zero overhead loop mechanism is disabled"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="STATUS32_L1" description="STATUS32 register in case of L1 interrupts" number="0xB" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="A1" description="level 1 interrupt bit" size="1" offset= "3" access="RO" >
+ <meaning value="1" description="a level 1 interrupt service routine is active"/>
+ </field>
+ <field name="A2" description="level 2 interrupt bit" size="1" offset= "4" access="RO" >
+ <meaning value="1" description="a level 2 interrupt service routine is active"/>
+ </field>
+ <field name="AE" description="exception bit" size="1" offset= "5" access="RO" >
+ <meaning value="1" description="an exception is active"/>
+ </field>
+ <field name="DE" description="delay slot bit" size="1" offset= "6" access="RO" >
+ <meaning value="1" description="instruction addressed by PC32 is in the delay slot of a taken branch"/>
+ </field>
+ <field name="U" description="User mode bit" size="1" offset= "7" access="RW" >
+ <meaning value="0" description="processor is in Kernel mode"/>
+ <meaning value="1" description="processor is in User mode"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ <field name="L" description="zero overhead loop bit" size="1" offset="12" access="RO" >
+ <meaning value="0" description="zero overhead loop mechanism is enabled"/>
+ <meaning value="1" description="zero overhead loop mechanism is disabled"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="STATUS32_L2" description="STATUS32 register in case of L2 interrupts" number="0xC" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ <field name="E1" description="level 1 interrupt mask bit" size="1" offset= "1" access="RW" >
+ <meaning value="0" description="level 1 interrupts are enabled"/>
+ <meaning value="1" description="level 1 interrupts are disabled"/>
+ </field>
+ <field name="E2" description="level 2 interrupt mask bit" size="1" offset= "2" access="RW" >
+ <meaning value="0" description="level 2 interrupts are enabled"/>
+ <meaning value="1" description="level 2 interrupts are disabled"/>
+ </field>
+ <field name="A1" description="level 1 interrupt bit" size="1" offset= "3" access="RO" >
+ <meaning value="1" description="a level 1 interrupt service routine is active"/>
+ </field>
+ <field name="A2" description="level 2 interrupt bit" size="1" offset= "4" access="RO" >
+ <meaning value="1" description="a level 2 interrupt service routine is active"/>
+ </field>
+ <field name="AE" description="exception bit" size="1" offset= "5" access="RO" >
+ <meaning value="1" description="an exception is active"/>
+ </field>
+ <field name="DE" description="delay slot bit" size="1" offset= "6" access="RO" >
+ <meaning value="1" description="instruction addressed by PC32 is in the delay slot of a taken branch"/>
+ </field>
+ <field name="U" description="User mode bit" size="1" offset= "7" access="RW" >
+ <meaning value="0" description="processor is in Kernel mode"/>
+ <meaning value="1" description="processor is in User mode"/>
+ </field>
+ <field name="V" description="overflow flag" size="1" offset= "8" access="RO" />
+ <field name="C" description="carry flag" size="1" offset= "9" access="RO" />
+ <field name="N" description="negative flag" size="1" offset="10" access="RO" />
+ <field name="Z" description="zero flag" size="1" offset="11" access="RO" />
+ <field name="L" description="zero overhead loop bit" size="1" offset="12" access="RO" >
+ <meaning value="0" description="zero overhead loop mechanism is enabled" />
+ <meaning value="1" description="zero overhead loop mechanism is disabled" />
+ </field>
+ </auxregister>
+
+ <auxregister name="COUNT0" description="Processor Timer 0 Count Value" number="0x21" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL0" description="Processor Timer 0 Control Value" number="0x22" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT0" description="Processor Timer 0 Limit Value" number="0x23" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="INT_VECTOR_BASE" description="Interrupt Vector Base Register" number="0x25" mask ="0xFFFFFC00" access="RW"/>
+
+ <auxregister name="AUX_MACMODE" description="Aux MAC Mode" number="0x41" mask ="0xFFFFFFFF" access="RW" >
+ <field name="CS" description="" size="1" offset="1" access="RW" >
+ </field>
+ <field name="S2" description="channel 2 saturation flag" size="1" offset="4" access="RO" >
+ <meaning value="1" description="channel 2 has saturated"/>
+ </field>
+ <field name="S1" description="channel 1 saturation flag" size="1" offset="9" access="RO" >
+ <meaning value="1" description="channel 1 has saturated"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_LV12" description="Aux IRQ Level 2" number="0x43" mask ="0x00000003" access="RW" >
+ <field name="L1" description="level 1 interrupt status bit" size="1" offset="0" access="RW" >
+ <meaning value="1" description="level 1 interrupt has been taken"/>
+ </field>
+ <field name="L2" description="level 2 interrupt status bit" size="1" offset="1" access="RW" >
+ <meaning value="1" description="level 2 interrupt has been taken"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="COUNT1" description="Processor Timer 1 Count Value" number="0x100" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="CONTROL1" description="Processor Timer 1 Control Value" number="0x101" mask ="0x0000000F" access="RW" >
+ <field name="IE" description="Interrupt Enable flag" size="1" offset="0" access="RW" >
+ <meaning value="1" description="interrupt will be generated after timer reaches limit condition"/>
+ </field>
+ <field name="NH" description="Not Halted mode flag" size="1" offset="1" access="RW" >
+ <meaning value="0" description="timer counts every clock cycle"/>
+ <meaning value="1" description="timer counts clock cycles only when processor is running"/>
+ </field>
+ <field name="W" description="Watchdog mode flag" size="1" offset="2" access="RW" >
+ <meaning value="1" description="system Reset signal will be generated after timer reaches limit condition"/>
+ </field>
+ </auxregister>
+
+ <auxregister name="LIMIT1" description="Processor Timer 1 Limit Value" number="0x102" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="AUX_IRQ_LEV" description="Interrupt Level programming" number="0x200" mask ="0xFFFFFFF8" access="RW" >
+ <field name="reserved" onwrite="0" size="3" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_HINT" description="Software Triggered Interrupt" number="0x201" mask ="0x0000001F" access="RW"/>
+
+ <auxregister name="ERET" description="Exception Return" number="0x400" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="ERBTA" description="Exception BTA" number="0x401" mask ="0xFFFFFFFE" access="RW"/>
+
+ <auxregister name="ERSTATUS" description="Exception Return Status" number="0x402" mask ="0x00001FFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="ECR" description="Exception Cause Register" number="0x403" mask ="0x00FFFFFF" access="RO">
+ <field name="Vector Number" description="" size="8" offset="16" access="RO" />
+ <field name="Cause Code" description="exact cause of exception" size="8" offset="8" access="RO" />
+ <field name="Parameter" description="additional information" size="8" offset="0" access="RO" />
+ </auxregister>
+ <auxregister name="EFA" description="Exception Fault Address" number="0x404" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="ICAUSE1" description="Interrupt Cause (Level 1)" number="0x40A" mask ="0x0000001F" access="RO"/>
+ <auxregister name="ICAUSE2" description="Interrupt Cause (Level 2)" number="0x40B" mask ="0x0000001F" access="RO"/>
+
+ <auxregister name="AUX_IENABLE" description="Interrupt Mask Programming" number="0x40C" mask ="0xFFFFFFF8" access="RW" >
+ <field name="reserved" onwrite="7" size="3" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="AUX_ITRIGGER" description="Interrupt Sensitivity Programming" number="0x40D" mask ="0xFFFFFFF8" access="RW" >
+ <field name="reserved" onwrite="7" size="3" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="XPU" description="User Mode Extension Permissions" number="0x410" mask ="0xFFFFFFFF" access="RW"/>
+
+ <auxregister name="BTA" description="Branch Target Address" number="0x412" mask ="0xFFFFFFFE" access="RO" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RO" />
+ </auxregister>
+
+ <auxregister name="BTA_L1" description="Branch Target Address in Level 1" number="0x413" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="BTA_L2" description="Branch Target Address in Level 2" number="0x414" mask ="0xFFFFFFFE" access="RW" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="RW" />
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_PULSE_CANCEL" description="Interrupt Pulse Cancel" number="0x415" mask ="0xFFFFFFFA" access="WO" >
+ <field name="reserved" onwrite="0" size="1" offset="0" access="WO" />
+ <field name="reserved" onwrite="0" size="1" offset="2" access="WO" />
+ </auxregister>
+
+ <auxregister name="AUX_IRQ_PENDING" description="Interrupt Pending Register" number="0x416" mask ="0xFFFFFFF8" access="RO"/>
+
+
+ <!-- cache control registers -->
+
+ <auxregister name="IC_IVIC" description="Instruction Cache Invalidation Register" number="0x10" mask ="0xFFFFFFFF" access="WO"/>
+ <auxregister name="IC_CTRL" description="Instruction Cache Control Register" number="0x11" mask ="0x0000003F" access="RW" >
+ <field name="DC" description="enables/disables the cache" size="1" offset="0" access="RW" >
+ <meaning value="0" description="cache is enabled" />
+ <meaning value="1" description="cache is disabled" />
+ </field>
+ <field name="EB" description="enables/disables cache bypass" size="1" offset="1" access="RO" >
+ <meaning value="0" description="bypass is disabled" />
+ <meaning value="1" description="bypass is enabled" />
+ </field>
+ <field name="reserved" onwrite="0" size="1" offset="2" />
+ <field name="SB" description="success of last cache operation" size="1" offset="3" access="RW" >
+ <meaning value="0" description="last cache operation failed" />
+ <meaning value="1" description="last cache operation succeeded" />
+ </field>
+ <field name="RA" description="replacement algorithm" size="1" offset="4" access="RO" >
+ <meaning value="0" description="random replacement" />
+ </field>
+ <field name="AT" description="address debug type" size="1" offset="5" access="RW" >
+ <meaning value="0" description="Direct Cache RAM Access" />
+ <meaning value="1" description="Cache Controlled RAM Access" />
+ </field>
+ <field name="reserved" onwrite="0" size="26" offset="6" />
+ </auxregister>
+ <auxregister name="DC_IVDC" description="Data Cache Invalidation Register" number="0x47" mask ="0x00000001" access="WO" >
+ <field name="IV" description="invalidates the entire cache" size="1" offset="0" access="WO" >
+ <meaning value="0" description="no action" />
+ <meaning value="1" description="invalidate the cache" />
+ </field>
+ <field name="reserved" onwrite="0" size="31" offset="1" />
+ </auxregister>
+ <auxregister name="DC_CTRL" description="Data Cache Control Register" number="0x48" mask ="0x000001FF" access="RW" >
+ <field name="DC" description="enables/disables the cache" size="1" offset="0" access="RW" >
+ <meaning value="0" description="cache is enabled" />
+ <meaning value="1" description="cache is disabled" />
+ </field>
+ <field name="EB" description="enables/disables cache bypass" size="1" offset="1" access="RO" >
+ <meaning value="0" description="bypass is disabled" />
+ <meaning value="1" description="bypass is enabled" />
+ </field>
+ <field name="SB" description="success of last cache operation" size="1" offset="2" access="RW" >
+ <meaning value="0" description="last cache operation failed" />
+ <meaning value="1" description="last cache operation succeeded" />
+ </field>
+ <field name="RA" description="replacement algorithm" size="2" offset="3" access="RO" >
+ <meaning value="0" description="random replacement" />
+ </field>
+ <field name="AT" description="address debug type" size="1" offset="5" access="RW" >
+ <meaning value="0" description="Direct Cache RAM Access" />
+ <meaning value="1" description="Cache Controlled RAM Access" />
+ </field>
+ <field name="IM" description="invalidate mode" size="1" offset="6" access="RW" >
+ <meaning value="0" description="invalidate data cache only" />
+ <meaning value="1" description="invalidate data cache and flush dirty entries" />
+ </field>
+ <field name="LM" description="lock mode" size="1" offset="7" access="RW" >
+ <meaning value="0" description="disable flush on locked entry" />
+ <meaning value="1" description="enable flush on locked entry" />
+ </field>
+ <field name="FS" description="flush status" size="1" offset="8" access="RO" >
+ <meaning value="0" description="idle" />
+ <meaning value="1" description="flush operation is in progress" />
+ </field>
+ <field name="reserved" onwrite="0" size="23" offset="9" />
+ </auxregister>
+
+
+ <!-- actionpoint 0 registers -->
+
+ <auxregister name="AMV0" description="Actionpoint 0 Match Value Register" number="0x220" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AMM0" description="Actionpoint 0 Match Mask Register" number="0x221" mask ="0xFFFFFFFF" access="RW"/>
+ <auxregister name="AC0" description="Actionpoint 0 Control Register" number="0x222" mask ="0xFFFFFFFF" access="RW"/>
+
+
+ <!-- Build Configuration Registers -->
+
+ <bcr name="BCR_VER" description="Build Configuration Registers Version" number="0x60" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BASE_BUILD" description="Base Address for Data Closely Coupled Memory" number="0x61" mask="0xFFFFFFFF"/>
+ <bcr name="CRC_BASE_BUILD" description="CRC Unit BCR" number="0x62" mask="0xFFFFFFFF"/>
+ <bcr name="BTA_LINK_BUILD" description="Interrupt Link Registers available for BTA" number="0x63" mask="0xFFFFFFFF"/>
+ <bcr name="DVBF_BUILD" description="Dual Viterbi Instruction BCR" number="0x64" mask="0xFFFFFFFF"/>
+ <bcr name="TEL_INSTR_BUILD" description="Extended Arithmetic Instructions BCR" number="0x65" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x66" mask="0xFFFFFFFF"/>
+ <bcr name="MEMSUBSYS" description="Memory Subsystem BCR" number="0x67" mask="0xFFFFFFFF"/>
+ <bcr name="VECBASE_AC_BUILD" description="Interrupt Vector Base BCR" number="0x68" mask="0xFFFFFFFF"/>
+ <bcr name="P_BASE_ADDRESS" description="Peripheral Base Address" number="0x69" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6A" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6B" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6C" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x6D" mask="0xFFFFFFFF"/>
+ <bcr name="RF_BUILD" description="Core Registers BCR" number="0x6E" mask="0xFFFFFFFF"/>
+ <bcr name="MMU_BUILD" description="Memory Management Unit BCR" number="0x6F" mask="0xFFFFFFFF"/>
+ <bcr name="ARCANGEL_BUILD" description="ARCAngel BCR" number="0x70" mask="0xFFFFFFFF"/>
+ <bcr name="unused" description="unused" number="0x71" mask="0xFFFFFFFF"/>
+ <bcr name="DCACHE_BUILD" description="Data Cache BCR" number="0x72" mask="0xFFFFFFFF"/>
+ <bcr name="MADI_BUILD" description="Multiple ARC Debug Interface" number="0x73" mask="0xFFFFFFFF"/>
+ <bcr name="DCCM_BUILD" description="Data Closely Coupled Memory BCR" number="0x74" mask="0xFFFFFFFF"/>
+ <bcr name="TIMER_BUILD" description="Timers BCR" number="0x75" mask="0xFFFFFFFF"/>
+ <bcr name="AP_BUILD" description="Actionpoints BCR" number="0x76" mask="0xFFFFFFFF"/>
+ <bcr name="ICACHE_BUILD" description="Instruction Cache BCR" number="0x77" mask="0xFFFFFFFF"/>
+ <bcr name="ICCM_BUILD" description="Instruction Closely Coupled Memory BCR" number="0x78" mask="0xFFFFFFFF"/>
+ <bcr name="DSPRAM_BUILD" description="DSP RAM BCR" number="0x79" mask="0xFFFFFFFF"/>
+ <bcr name="MAC_BUILD" description="MAC Unit BCR" number="0x7A" mask="0xFFFFFFFF"/>
+ <bcr name="MULTIPLY_BUILD" description="(32 X 32) Multiply Unit BCR" number="0x7B" mask="0xFFFFFFFF"/>
+ <bcr name="SWAP_BUILD" description="SWAP BCR" number="0x7C" mask="0xFFFFFFFF"/>
+ <bcr name="NORM_BUILD" description="NORM Unit BCR" number="0x7D" mask="0xFFFFFFFF"/>
+ <bcr name="MINMAX_BUILD" description="Minmax Unit BCR" number="0x7E" mask="0xFFFFFFFF"/>
+ <bcr name="BARREL_BUILD" description="Barrel Shifter BCR" number="0x7F" mask="0xFFFFFFFF"/>
+
+<!-- for testing
+
+ <auxregister name="TEST" description="any old bucket of bits" number="0x99999" mask ="0xFFFFFFFF" access="RW">
+ <field name ="AA" description="" size="1" offset="5" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ </field>
+ <field name ="BBBB" description="" size="3" offset="8" access="RO">
+ <meaning value="0" description="value is 0"/>
+ <meaning value="1" description="value is 1"/>
+ <meaning value="3" description="value is 3"/>
+ <meaning value="7" description="value is 7"/>
+ </field>
+ <field name ="CCCCCCCCC" description="" size="8" offset="17" access="RO">
+ </field>
+ </auxregister>
+ -->
+
+</feature>
+</target>
diff --git a/gdb/gdb-events.c b/gdb/gdb-events.c
index d6884751dad..f24ece5feeb 100644
--- a/gdb/gdb-events.c
+++ b/gdb/gdb-events.c
@@ -122,6 +122,18 @@ architecture_changed_event (void)
current_event_hooks->architecture_changed ();
}
+// begin ARC
+void
+reg_architecture_changed_event (void)
+{
+ if (gdb_events_debug)
+ fprintf_unfiltered (gdb_stdlog, "reg_architecture_changed_event\n");
+ if (!current_event_hooks->reg_architecture_changed)
+ return;
+ current_event_hooks->reg_architecture_changed ();
+}
+// end ARC
+
struct gdb_events *
deprecated_set_gdb_event_hooks (struct gdb_events *vector)
{
@@ -148,6 +160,9 @@ enum gdb_event
tracepoint_delete,
tracepoint_modify,
architecture_changed,
+// begin ARC
+ reg_architecture_changed,
+// end ARC
nr_gdb_events
};
@@ -271,6 +286,16 @@ queue_architecture_changed (void)
append (event);
}
+// begin ARC
+static void
+queue_reg_architecture_changed (void)
+{
+ struct event *event = XMALLOC (struct event);
+ event->type = reg_architecture_changed;
+ append (event);
+}
+// end ARC
+
void
gdb_events_deliver (struct gdb_events *vector)
{
@@ -319,6 +344,11 @@ gdb_events_deliver (struct gdb_events *vector)
case architecture_changed:
vector->architecture_changed ();
break;
+// begin ARC
+ case reg_architecture_changed:
+ vector->reg_architecture_changed ();
+ break;
+// end ARC
}
delivering_events = event->next;
xfree (event);
@@ -337,6 +367,9 @@ _initialize_gdb_events (void)
queue_event_hooks.tracepoint_delete = queue_tracepoint_delete;
queue_event_hooks.tracepoint_modify = queue_tracepoint_modify;
queue_event_hooks.architecture_changed = queue_architecture_changed;
+// begin ARC
+ queue_event_hooks.reg_architecture_changed = queue_reg_architecture_changed;
+// end ARC
add_setshow_zinteger_cmd ("event", class_maintenance,
&gdb_events_debug, _("\
diff --git a/gdb/gdb-events.h b/gdb/gdb-events.h
index 9c38c0afb6f..5a6dd4af0bf 100644
--- a/gdb/gdb-events.h
+++ b/gdb/gdb-events.h
@@ -55,6 +55,9 @@ typedef void (gdb_events_tracepoint_create_ftype) (int number);
typedef void (gdb_events_tracepoint_delete_ftype) (int number);
typedef void (gdb_events_tracepoint_modify_ftype) (int number);
typedef void (gdb_events_architecture_changed_ftype) (void);
+// begin ARC
+typedef void (gdb_events_reg_architecture_changed_ftype) (void);
+// end ARC
/* gdb-events: object. */
@@ -68,6 +71,9 @@ struct gdb_events
gdb_events_tracepoint_delete_ftype *tracepoint_delete;
gdb_events_tracepoint_modify_ftype *tracepoint_modify;
gdb_events_architecture_changed_ftype *architecture_changed;
+// begin ARC
+ gdb_events_reg_architecture_changed_ftype *reg_architecture_changed;
+// end ARC
};
@@ -81,6 +87,9 @@ extern void tracepoint_create_event (int number);
extern void tracepoint_delete_event (int number);
extern void tracepoint_modify_event (int number);
extern void architecture_changed_event (void);
+// begin ARC
+extern void reg_architecture_changed_event (void);
+// end ARC
/* Install custom gdb-events hooks. */
extern struct gdb_events *deprecated_set_gdb_event_hooks (struct gdb_events *vector);
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index d967ff5dca0..f7fe7d47c93 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -330,7 +330,7 @@ spu-low.o: spu-low.c $(server_h)
reg-arc.o : reg-arc.c $(regdef_h)
reg-arc.c : $(srcdir)/../regformats/reg-arc.dat $(regdat_sh)
- sh $(regdat_sh) $(srcdir)/../regformats/reg-arc.dat reg-arc.c
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-arc.dat reg-arc.c
reg-arm.o : reg-arm.c $(regdef_h)
reg-arm.c : $(srcdir)/../regformats/reg-arm.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-arm.dat reg-arm.c
diff --git a/gdb/gdbserver/build_gdbserver.sh b/gdb/gdbserver/build_gdbserver.sh
new file mode 100755
index 00000000000..bdf886f695e
--- /dev/null
+++ b/gdb/gdbserver/build_gdbserver.sh
@@ -0,0 +1,6 @@
+#Bash script to build gdbserver
+export CFLAGS="-mA7 -static -O0"
+export LDFLAGS="-mA7"
+export CC=arc-linux-uclibc-gcc
+./configure --host=i386-redhat-linux-gnu --target=arc-linux-uclibc
+make
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index c0d246b5463..c3c2d56eb8b 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -26,11 +26,16 @@ srv_hostio_err_objs="hostio-errno.o"
# Input is taken from the "${target}" variable.
case "${target}" in
- arc*-*-linux*) srv_regobj=reg-arc.o
- srv_tgtobj="linux-low.o linux-arc-low.o"
- srv_linux_usrregs=yes
- srv_linux_thread_db=yes
- ;;
+ arc*-*-linux*) srv_regobj=reg-arc.o
+ srv_tgtobj="linux-low.o linux-arc-low.o"
+ srv_linux_usrregs=yes
+ srv_linux_thread_db=yes
+ ;;
+ arc*-*) srv_regobj=reg-arc.o
+ srv_tgtobj="linux-low.o linux-arc-low.o"
+ srv_linux_usrregs=yes
+ srv_linux_thread_db=yes
+ ;;
arm*-*-linux*) srv_tgtobj="linux-low.o linux-arm-low.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
diff --git a/gdb/gdbserver/linux-arc-low.c b/gdb/gdbserver/linux-arc-low.c
index 28c7ead3deb..c5faa1df4a5 100644
--- a/gdb/gdbserver/linux-arc-low.c
+++ b/gdb/gdbserver/linux-arc-low.c
@@ -113,7 +113,7 @@ arc_breakpoint_at (CORE_ADDR where)
{
unsigned long insn;
- (*the_target->read_memory) (where, (char *) &insn, arc_breakpoint_len);
+ (*the_target->read_memory) (where, (unsigned char *) &insn, arc_breakpoint_len);
if (insn == arc_breakpoint)
return 1;
@@ -141,7 +141,7 @@ struct linux_target_ops the_low_target = {
arc_cannot_store_register,
arc_get_pc,
arc_set_pc,
- (const char *) &arc_breakpoint,
+ (const unsigned char *) &arc_breakpoint,
arc_breakpoint_len,
arc_reinsert_addr,
0,
diff --git a/gdb/gdbserver/proc-service.c b/gdb/gdbserver/proc-service.c
index 065bfdf3885..fc7bc19fbe5 100644
--- a/gdb/gdbserver/proc-service.c
+++ b/gdb/gdbserver/proc-service.c
@@ -28,6 +28,7 @@
#include "linux-low.h"
#include "gdb_proc_service.h"
+typedef unsigned long paddr_t;
typedef struct ps_prochandle *gdb_ps_prochandle_t;
typedef void *gdb_ps_read_buf_t;
@@ -61,7 +62,7 @@ gregset_info(void)
ps_err_e
ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
- const char *name, psaddr_t *sym_addr)
+ const char *name, paddr_t *sym_addr)
{
CORE_ADDR addr;
char *uscorename;
@@ -89,7 +90,8 @@ ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
return PS_NOSYM;
}
- *sym_addr = (psaddr_t) (unsigned long) addr;
+ *sym_addr = (paddr_t) (unsigned long) addr;
+
return PS_OK;
}
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 496334cacf0..2e049ee22a4 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -169,9 +169,7 @@ remote_open (char *name)
}
#endif
-/* #ifdef HAVE_SGTTY */
- /* soam */
-#if 0
+#ifdef HAVE_SGTTY
{
struct sgttyb sg;
@@ -773,8 +771,7 @@ getpkt (char *buf)
c1 = fromhex (readchar ());
c2 = fromhex (readchar ());
-/* if (csum == (c1 << 4) + c2) */
- if(1) /* (soam) for testing */
+ if (csum == (c1 << 4) + c2)
break;
fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
diff --git a/gdb/gpio.h b/gdb/gpio.h
deleted file mode 100644
index 86aa4cab8a9..00000000000
--- a/gdb/gpio.h
+++ /dev/null
@@ -1,38 +0,0 @@
-struct GPIO_ioctl {
- // This is used for general input and output in the same ioctl.
- // inlen is replaced by the number of input bytes consumed.
- // inlen is always even and represents a number of pairs:
- // [0/1/2,value]: write value to port_base+0/1/2.
- // [0x80/0x81/0x82, --]: read value from port_base+0/1/2
- // and append result to outbuf.
- // Thus one can intermix read and write in the same ioctl.
- unsigned inlen; char *inbuf;
- // outlen is replaced by # of output bytes written.
- unsigned outlen; char *outbuf;
- };
-
-// IO control numbers
-
-// Linux kernel uses 0x54XX for special purposes. Avoid such.
-// We'll pick large numbers.
-// We don't use the linux convention of dividing the IOC into a bunch
-// of bit fields. We can always switch to this later, as the
-// IOC 0 returns the driver version (which IOC value will never change).
-
-#define GPIO_IOC_VERSION 0 // returns version
-#define GPIO_IOC_BASE 0xaa3a0000 // Intended for use on ARCangel 3!
-
-// Switch base address of parallel port. 0x3f8 is assumed.
-// WARNING! You can write on any port whatsoever with this driver.
-// BE CAREFUL!
-#define GPIO_IOC_SET_PORT_BASE (GPIO_IOC_BASE+1) // cmd, arg=port base
-
-// General input/output ioctl. See GPIO_ioctl struct.
-#define GPIO_IOC_DO_IO (GPIO_IOC_BASE+2) // cmd, arg=GPIO_ioctl *
-
-// For emergency purposes in case the driver is goofed up.
-#define GPIO_IOC_HARDRESET (GPIO_IOC_BASE+3) // cmd, no arg
-
-// Do you have an antiquated parallel port? You might need to ask
-// the driver to use outb_p and inb_p (_p = pause). Default is not to.
-#define GPIO_IOC_SET_PAUSE (GPIO_IOC_BASE+4) // arg = 1 => use pause; o/wise not.
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 972f9e22324..4e76260972a 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1603,15 +1603,25 @@ default_print_registers_info (struct gdbarch *gdbarch,
continue;
}
- /* If the register name is empty, it is undefined for this
- processor, so don't display anything. */
- if (gdbarch_register_name (gdbarch, i) == NULL
- || *(gdbarch_register_name (gdbarch, i)) == '\0')
- continue;
-
- fputs_filtered (gdbarch_register_name (gdbarch, i), file);
- print_spaces_filtered (15 - strlen (gdbarch_register_name
- (gdbarch, i)), file);
+ {
+ /* richards ARC 29/10/27 gdb bug: 9884
+ call the gdbarch_register_name once only!
+ */
+ const char* name = gdbarch_register_name (gdbarch, i);
+
+ /* If the register name is empty, it is undefined for this
+ processor, so don't display anything. */
+ if (name == NULL || *name == '\0')
+ continue;
+
+ fputs_filtered (name, file);
+
+ /* richards ARC 29/9/08 gdb bug: 9885
+ Some ARC register names are longer than 15 chars!
+ There should be a gdbarch_max_register_name_length function
+ which could be called here instead of using an integer literal. */
+ print_spaces_filtered (22 - strlen (name), file);
+ }
/* Get the data in raw format. */
if (! frame_register_read (frame, i, buffer))
diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
index e51f27249b5..9a961f47d18 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -24,441 +24,14 @@
#include "gdbcmd.h"
#include "remote.h"
#include "gdb/fileio.h"
-#include "gdb_wait.h"
-#include "gdb_stat.h"
#include "exceptions.h"
#include "remote-fileio.h"
+#include "target-fileio.h"
-#include <fcntl.h>
-#include <sys/time.h>
-#ifdef __CYGWIN__
-#include <sys/cygwin.h> /* For cygwin_conv_to_full_posix_path. */
-#endif
#include <signal.h>
-static struct {
- int *fd_map;
- int fd_map_size;
-} remote_fio_data;
-
-#define FIO_FD_INVALID -1
-#define FIO_FD_CONSOLE_IN -2
-#define FIO_FD_CONSOLE_OUT -3
-
-static int remote_fio_system_call_allowed = 0;
-
-static int
-remote_fileio_init_fd_map (void)
-{
- int i;
-
- if (!remote_fio_data.fd_map)
- {
- remote_fio_data.fd_map = (int *) xmalloc (10 * sizeof (int));
- remote_fio_data.fd_map_size = 10;
- remote_fio_data.fd_map[0] = FIO_FD_CONSOLE_IN;
- remote_fio_data.fd_map[1] = FIO_FD_CONSOLE_OUT;
- remote_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
- for (i = 3; i < 10; ++i)
- remote_fio_data.fd_map[i] = FIO_FD_INVALID;
- }
- return 3;
-}
-
-static int
-remote_fileio_resize_fd_map (void)
-{
- int i = remote_fio_data.fd_map_size;
-
- if (!remote_fio_data.fd_map)
- return remote_fileio_init_fd_map ();
- remote_fio_data.fd_map_size += 10;
- remote_fio_data.fd_map =
- (int *) xrealloc (remote_fio_data.fd_map,
- remote_fio_data.fd_map_size * sizeof (int));
- for (; i < remote_fio_data.fd_map_size; i++)
- remote_fio_data.fd_map[i] = FIO_FD_INVALID;
- return remote_fio_data.fd_map_size - 10;
-}
-
-static int
-remote_fileio_next_free_fd (void)
-{
- int i;
-
- for (i = 0; i < remote_fio_data.fd_map_size; ++i)
- if (remote_fio_data.fd_map[i] == FIO_FD_INVALID)
- return i;
- return remote_fileio_resize_fd_map ();
-}
-
-static int
-remote_fileio_fd_to_targetfd (int fd)
-{
- int target_fd = remote_fileio_next_free_fd ();
- remote_fio_data.fd_map[target_fd] = fd;
- return target_fd;
-}
-
-static int
-remote_fileio_map_fd (int target_fd)
-{
- remote_fileio_init_fd_map ();
- if (target_fd < 0 || target_fd >= remote_fio_data.fd_map_size)
- return FIO_FD_INVALID;
- return remote_fio_data.fd_map[target_fd];
-}
-
-static void
-remote_fileio_close_target_fd (int target_fd)
-{
- remote_fileio_init_fd_map ();
- if (target_fd >= 0 && target_fd < remote_fio_data.fd_map_size)
- remote_fio_data.fd_map[target_fd] = FIO_FD_INVALID;
-}
-
-static int
-remote_fileio_oflags_to_host (long flags)
-{
- int hflags = 0;
-
- if (flags & FILEIO_O_CREAT)
- hflags |= O_CREAT;
- if (flags & FILEIO_O_EXCL)
- hflags |= O_EXCL;
- if (flags & FILEIO_O_TRUNC)
- hflags |= O_TRUNC;
- if (flags & FILEIO_O_APPEND)
- hflags |= O_APPEND;
- if (flags & FILEIO_O_RDONLY)
- hflags |= O_RDONLY;
- if (flags & FILEIO_O_WRONLY)
- hflags |= O_WRONLY;
- if (flags & FILEIO_O_RDWR)
- hflags |= O_RDWR;
-/* On systems supporting binary and text mode, always open files in
- binary mode. */
-#ifdef O_BINARY
- hflags |= O_BINARY;
-#endif
- return hflags;
-}
-
-static mode_t
-remote_fileio_mode_to_host (long mode, int open_call)
-{
- mode_t hmode = 0;
-
- if (!open_call)
- {
- if (mode & FILEIO_S_IFREG)
- hmode |= S_IFREG;
- if (mode & FILEIO_S_IFDIR)
- hmode |= S_IFDIR;
- if (mode & FILEIO_S_IFCHR)
- hmode |= S_IFCHR;
- }
- if (mode & FILEIO_S_IRUSR)
- hmode |= S_IRUSR;
- if (mode & FILEIO_S_IWUSR)
- hmode |= S_IWUSR;
- if (mode & FILEIO_S_IXUSR)
- hmode |= S_IXUSR;
-#ifdef S_IRGRP
- if (mode & FILEIO_S_IRGRP)
- hmode |= S_IRGRP;
-#endif
-#ifdef S_IWGRP
- if (mode & FILEIO_S_IWGRP)
- hmode |= S_IWGRP;
-#endif
-#ifdef S_IXGRP
- if (mode & FILEIO_S_IXGRP)
- hmode |= S_IXGRP;
-#endif
- if (mode & FILEIO_S_IROTH)
- hmode |= S_IROTH;
-#ifdef S_IWOTH
- if (mode & FILEIO_S_IWOTH)
- hmode |= S_IWOTH;
-#endif
-#ifdef S_IXOTH
- if (mode & FILEIO_S_IXOTH)
- hmode |= S_IXOTH;
-#endif
- return hmode;
-}
-
-static LONGEST
-remote_fileio_mode_to_target (mode_t mode)
-{
- mode_t tmode = 0;
-
- if (S_ISREG(mode))
- tmode |= FILEIO_S_IFREG;
- if (S_ISDIR(mode))
- tmode |= FILEIO_S_IFDIR;
- if (S_ISCHR(mode))
- tmode |= FILEIO_S_IFCHR;
- if (mode & S_IRUSR)
- tmode |= FILEIO_S_IRUSR;
- if (mode & S_IWUSR)
- tmode |= FILEIO_S_IWUSR;
- if (mode & S_IXUSR)
- tmode |= FILEIO_S_IXUSR;
-#ifdef S_IRGRP
- if (mode & S_IRGRP)
- tmode |= FILEIO_S_IRGRP;
-#endif
-#ifdef S_IWRGRP
- if (mode & S_IWGRP)
- tmode |= FILEIO_S_IWGRP;
-#endif
-#ifdef S_IXGRP
- if (mode & S_IXGRP)
- tmode |= FILEIO_S_IXGRP;
-#endif
- if (mode & S_IROTH)
- tmode |= FILEIO_S_IROTH;
-#ifdef S_IWOTH
- if (mode & S_IWOTH)
- tmode |= FILEIO_S_IWOTH;
-#endif
-#ifdef S_IXOTH
- if (mode & S_IXOTH)
- tmode |= FILEIO_S_IXOTH;
-#endif
- return tmode;
-}
-
-static int
-remote_fileio_errno_to_target (int error)
-{
- switch (error)
- {
- case EPERM:
- return FILEIO_EPERM;
- case ENOENT:
- return FILEIO_ENOENT;
- case EINTR:
- return FILEIO_EINTR;
- case EIO:
- return FILEIO_EIO;
- case EBADF:
- return FILEIO_EBADF;
- case EACCES:
- return FILEIO_EACCES;
- case EFAULT:
- return FILEIO_EFAULT;
- case EBUSY:
- return FILEIO_EBUSY;
- case EEXIST:
- return FILEIO_EEXIST;
- case ENODEV:
- return FILEIO_ENODEV;
- case ENOTDIR:
- return FILEIO_ENOTDIR;
- case EISDIR:
- return FILEIO_EISDIR;
- case EINVAL:
- return FILEIO_EINVAL;
- case ENFILE:
- return FILEIO_ENFILE;
- case EMFILE:
- return FILEIO_EMFILE;
- case EFBIG:
- return FILEIO_EFBIG;
- case ENOSPC:
- return FILEIO_ENOSPC;
- case ESPIPE:
- return FILEIO_ESPIPE;
- case EROFS:
- return FILEIO_EROFS;
- case ENOSYS:
- return FILEIO_ENOSYS;
- case ENAMETOOLONG:
- return FILEIO_ENAMETOOLONG;
- }
- return FILEIO_EUNKNOWN;
-}
-
-static int
-remote_fileio_seek_flag_to_host (long num, int *flag)
-{
- if (!flag)
- return 0;
- switch (num)
- {
- case FILEIO_SEEK_SET:
- *flag = SEEK_SET;
- break;
- case FILEIO_SEEK_CUR:
- *flag = SEEK_CUR;
- break;
- case FILEIO_SEEK_END:
- *flag = SEEK_END;
- break;
- default:
- return -1;
- }
- return 0;
-}
-
-static int
-remote_fileio_extract_long (char **buf, LONGEST *retlong)
-{
- char *c;
- int sign = 1;
-
- if (!buf || !*buf || !**buf || !retlong)
- return -1;
- c = strchr (*buf, ',');
- if (c)
- *c++ = '\0';
- else
- c = strchr (*buf, '\0');
- while (strchr ("+-", **buf))
- {
- if (**buf == '-')
- sign = -sign;
- ++*buf;
- }
- for (*retlong = 0; **buf; ++*buf)
- {
- *retlong <<= 4;
- if (**buf >= '0' && **buf <= '9')
- *retlong += **buf - '0';
- else if (**buf >= 'a' && **buf <= 'f')
- *retlong += **buf - 'a' + 10;
- else if (**buf >= 'A' && **buf <= 'F')
- *retlong += **buf - 'A' + 10;
- else
- return -1;
- }
- *retlong *= sign;
- *buf = c;
- return 0;
-}
-
-static int
-remote_fileio_extract_int (char **buf, long *retint)
-{
- int ret;
- LONGEST retlong;
-
- if (!retint)
- return -1;
- ret = remote_fileio_extract_long (buf, &retlong);
- if (!ret)
- *retint = (long) retlong;
- return ret;
-}
-
-static int
-remote_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length)
-{
- char *c;
- LONGEST retlong;
-
- if (!buf || !*buf || !**buf || !ptrval || !length)
- return -1;
- c = strchr (*buf, '/');
- if (!c)
- return -1;
- *c++ = '\0';
- if (remote_fileio_extract_long (buf, &retlong))
- return -1;
- *ptrval = (CORE_ADDR) retlong;
- *buf = c;
- if (remote_fileio_extract_long (buf, &retlong))
- return -1;
- *length = (int) retlong;
- return 0;
-}
-
-/* Convert to big endian */
-static void
-remote_fileio_to_be (LONGEST num, char *buf, int bytes)
-{
- int i;
-
- for (i = 0; i < bytes; ++i)
- buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
-}
-
-static void
-remote_fileio_to_fio_uint (long num, fio_uint_t fnum)
-{
- remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
-}
-
-static void
-remote_fileio_to_fio_mode (mode_t num, fio_mode_t fnum)
-{
- remote_fileio_to_be (remote_fileio_mode_to_target(num), (char *) fnum, 4);
-}
-
-static void
-remote_fileio_to_fio_time (time_t num, fio_time_t fnum)
-{
- remote_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
-}
-
-static void
-remote_fileio_to_fio_long (LONGEST num, fio_long_t fnum)
-{
- remote_fileio_to_be (num, (char *) fnum, 8);
-}
-
-static void
-remote_fileio_to_fio_ulong (LONGEST num, fio_ulong_t fnum)
-{
- remote_fileio_to_be (num, (char *) fnum, 8);
-}
-
-static void
-remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
-{
- LONGEST blksize;
-
- /* `st_dev' is set in the calling function */
- remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
- remote_fileio_to_fio_mode (st->st_mode, fst->fst_mode);
- remote_fileio_to_fio_uint ((long) st->st_nlink, fst->fst_nlink);
- remote_fileio_to_fio_uint ((long) st->st_uid, fst->fst_uid);
- remote_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid);
- remote_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev);
- remote_fileio_to_fio_ulong ((LONGEST) st->st_size, fst->fst_size);
-#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- blksize = st->st_blksize;
-#else
- blksize = 512;
-#endif
- remote_fileio_to_fio_ulong (blksize, fst->fst_blksize);
-#if HAVE_STRUCT_STAT_ST_BLOCKS
- remote_fileio_to_fio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks);
-#else
- /* FIXME: This is correct for DJGPP, but other systems that don't
- have st_blocks, if any, might prefer 512 instead of st_blksize.
- (eliz, 30-12-2003) */
- remote_fileio_to_fio_ulong (((LONGEST) st->st_size + blksize - 1)
- / blksize,
- fst->fst_blocks);
-#endif
- remote_fileio_to_fio_time (st->st_atime, fst->fst_atime);
- remote_fileio_to_fio_time (st->st_mtime, fst->fst_mtime);
- remote_fileio_to_fio_time (st->st_ctime, fst->fst_ctime);
-}
-
-static void
-remote_fileio_to_fio_timeval (struct timeval *tv, struct fio_timeval *ftv)
-{
- remote_fileio_to_fio_time (tv->tv_sec, ftv->ftv_sec);
- remote_fileio_to_fio_long (tv->tv_usec, ftv->ftv_usec);
-}
static int remote_fio_ctrl_c_flag = 0;
-static int remote_fio_no_longjmp = 0;
#if defined (HAVE_SIGACTION) && defined (SA_RESTART)
static struct sigaction remote_fio_sa;
@@ -508,7 +81,7 @@ remote_fileio_ctrl_c_signal_handler (int signo)
{
remote_fileio_sig_set (SIG_IGN);
remote_fio_ctrl_c_flag = 1;
- if (!remote_fio_no_longjmp)
+ if (!target_fio_no_longjmp)
deprecated_throw_reason (RETURN_QUIT);
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
}
@@ -543,30 +116,6 @@ remote_fileio_reply (int retcode, int error)
putpkt (buf);
}
-static void
-remote_fileio_ioerror (void)
-{
- remote_fileio_reply (-1, FILEIO_EIO);
-}
-
-static void
-remote_fileio_badfd (void)
-{
- remote_fileio_reply (-1, FILEIO_EBADF);
-}
-
-static void
-remote_fileio_return_errno (int retcode)
-{
- remote_fileio_reply (retcode,
- retcode < 0 ? remote_fileio_errno_to_target (errno) : 0);
-}
-
-static void
-remote_fileio_return_success (int retcode)
-{
- remote_fileio_reply (retcode, 0);
-}
/* Wrapper function for remote_write_bytes() which has the disadvantage to
write only one packet, regardless of the requested number of bytes to
@@ -586,791 +135,11 @@ remote_fileio_write_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
return ret;
}
-static void
-remote_fileio_func_open (char *buf)
-{
- CORE_ADDR ptrval;
- int length, retlength;
- long num;
- int flags, fd;
- mode_t mode;
- char *pathname;
- struct stat st;
-
- /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
- {
- remote_fileio_ioerror ();
- return;
- }
- /* 2. Parameter: open flags */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- flags = remote_fileio_oflags_to_host (num);
- /* 3. Parameter: open mode */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- mode = remote_fileio_mode_to_host (num, 1);
-
- /* Request pathname using 'm' packet */
- pathname = alloca (length);
- retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
- if (retlength != length)
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* Check if pathname exists and is not a regular file or directory. If so,
- return an appropriate error code. Same for trying to open directories
- for writing. */
- if (!stat (pathname, &st))
- {
- if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
- {
- remote_fileio_reply (-1, FILEIO_ENODEV);
- return;
- }
- if (S_ISDIR (st.st_mode)
- && ((flags & O_WRONLY) == O_WRONLY || (flags & O_RDWR) == O_RDWR))
- {
- remote_fileio_reply (-1, FILEIO_EISDIR);
- return;
- }
- }
-
- remote_fio_no_longjmp = 1;
- fd = open (pathname, flags, mode);
- if (fd < 0)
- {
- remote_fileio_return_errno (-1);
- return;
- }
-
- fd = remote_fileio_fd_to_targetfd (fd);
- remote_fileio_return_success (fd);
-}
-
-static void
-remote_fileio_func_close (char *buf)
-{
- long num;
- int fd;
-
- /* Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- fd = remote_fileio_map_fd ((int) num);
- if (fd == FIO_FD_INVALID)
- {
- remote_fileio_badfd ();
- return;
- }
-
- remote_fio_no_longjmp = 1;
- if (fd != FIO_FD_CONSOLE_IN && fd != FIO_FD_CONSOLE_OUT && close (fd))
- remote_fileio_return_errno (-1);
- remote_fileio_close_target_fd ((int) num);
- remote_fileio_return_success (0);
-}
static void
-remote_fileio_func_read (char *buf)
+set_ctrl_c_signal_handler(void)
{
- long target_fd, num;
- LONGEST lnum;
- CORE_ADDR ptrval;
- int fd, ret, retlength;
- gdb_byte *buffer;
- size_t length;
- off_t old_offset, new_offset;
-
- /* 1. Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &target_fd))
- {
- remote_fileio_ioerror ();
- return;
- }
- fd = remote_fileio_map_fd ((int) target_fd);
- if (fd == FIO_FD_INVALID)
- {
- remote_fileio_badfd ();
- return;
- }
- /* 2. Parameter: buffer pointer */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- ptrval = (CORE_ADDR) lnum;
- /* 3. Parameter: buffer length */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- length = (size_t) num;
-
- switch (fd)
- {
- case FIO_FD_CONSOLE_OUT:
- remote_fileio_badfd ();
- return;
- case FIO_FD_CONSOLE_IN:
- {
- static char *remaining_buf = NULL;
- static int remaining_length = 0;
-
- buffer = (gdb_byte *) xmalloc (32768);
- if (remaining_buf)
- {
- remote_fio_no_longjmp = 1;
- if (remaining_length > length)
- {
- memcpy (buffer, remaining_buf, length);
- memmove (remaining_buf, remaining_buf + length,
- remaining_length - length);
- remaining_length -= length;
- ret = length;
- }
- else
- {
- memcpy (buffer, remaining_buf, remaining_length);
- xfree (remaining_buf);
- remaining_buf = NULL;
- ret = remaining_length;
- }
- }
- else
- {
- ret = ui_file_read (gdb_stdtargin, (char *) buffer, 32767);
- remote_fio_no_longjmp = 1;
- if (ret > 0 && (size_t)ret > length)
- {
- remaining_buf = (char *) xmalloc (ret - length);
- remaining_length = ret - length;
- memcpy (remaining_buf, buffer + length, remaining_length);
- ret = length;
- }
- }
- }
- break;
- default:
- buffer = (gdb_byte *) xmalloc (length);
- /* POSIX defines EINTR behaviour of read in a weird way. It's allowed
- for read() to return -1 even if "some" bytes have been read. It
- has been corrected in SUSv2 but that doesn't help us much...
- Therefore a complete solution must check how many bytes have been
- read on EINTR to return a more reliable value to the target */
- old_offset = lseek (fd, 0, SEEK_CUR);
- remote_fio_no_longjmp = 1;
- ret = read (fd, buffer, length);
- if (ret < 0 && errno == EINTR)
- {
- new_offset = lseek (fd, 0, SEEK_CUR);
- /* If some data has been read, return the number of bytes read.
- The Ctrl-C flag is set in remote_fileio_reply() anyway */
- if (old_offset != new_offset)
- ret = new_offset - old_offset;
- }
- break;
- }
-
- if (ret > 0)
- {
- retlength = remote_fileio_write_bytes (ptrval, buffer, ret);
- if (retlength != ret)
- ret = -1; /* errno has been set to EIO in remote_fileio_write_bytes() */
- }
-
- if (ret < 0)
- remote_fileio_return_errno (-1);
- else
- remote_fileio_return_success (ret);
-
- xfree (buffer);
-}
-
-static void
-remote_fileio_func_write (char *buf)
-{
- long target_fd, num;
- LONGEST lnum;
- CORE_ADDR ptrval;
- int fd, ret, retlength;
- gdb_byte *buffer;
- size_t length;
-
- /* 1. Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &target_fd))
- {
- remote_fileio_ioerror ();
- return;
- }
- fd = remote_fileio_map_fd ((int) target_fd);
- if (fd == FIO_FD_INVALID)
- {
- remote_fileio_badfd ();
- return;
- }
- /* 2. Parameter: buffer pointer */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- ptrval = (CORE_ADDR) lnum;
- /* 3. Parameter: buffer length */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- length = (size_t) num;
-
- buffer = (gdb_byte *) xmalloc (length);
- retlength = remote_read_bytes (ptrval, buffer, length);
- if (retlength != length)
- {
- xfree (buffer);
- remote_fileio_ioerror ();
- return;
- }
-
- remote_fio_no_longjmp = 1;
- switch (fd)
- {
- case FIO_FD_CONSOLE_IN:
- remote_fileio_badfd ();
- xfree (buffer);
- return;
- case FIO_FD_CONSOLE_OUT:
- ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr,
- (char *) buffer, length);
- gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
- ret = length;
- break;
- default:
- ret = write (fd, buffer, length);
- if (ret < 0 && errno == EACCES)
- errno = EBADF; /* Cygwin returns EACCESS when writing to a R/O file.*/
- break;
- }
-
- if (ret < 0)
- remote_fileio_return_errno (-1);
- else
- remote_fileio_return_success (ret);
-
- xfree (buffer);
-}
-
-static void
-remote_fileio_func_lseek (char *buf)
-{
- long num;
- LONGEST lnum;
- int fd, flag;
- off_t offset, ret;
-
- /* 1. Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- fd = remote_fileio_map_fd ((int) num);
- if (fd == FIO_FD_INVALID)
- {
- remote_fileio_badfd ();
- return;
- }
- else if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
- {
- remote_fileio_reply (-1, FILEIO_ESPIPE);
- return;
- }
-
- /* 2. Parameter: offset */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- offset = (off_t) lnum;
- /* 3. Parameter: flag */
- if (remote_fileio_extract_int (&buf, &num))
- {
- remote_fileio_ioerror ();
- return;
- }
- if (remote_fileio_seek_flag_to_host (num, &flag))
- {
- remote_fileio_reply (-1, FILEIO_EINVAL);
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = lseek (fd, offset, flag);
-
- if (ret == (off_t) -1)
- remote_fileio_return_errno (-1);
- else
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_rename (char *buf)
-{
- CORE_ADDR old_ptr, new_ptr;
- int old_len, new_len, retlength;
- char *oldpath, *newpath;
- int ret, of, nf;
- struct stat ost, nst;
-
- /* 1. Parameter: Ptr to oldpath / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &old_ptr, &old_len))
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &new_ptr, &new_len))
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* Request oldpath using 'm' packet */
- oldpath = alloca (old_len);
- retlength = remote_read_bytes (old_ptr, (gdb_byte *) oldpath, old_len);
- if (retlength != old_len)
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* Request newpath using 'm' packet */
- newpath = alloca (new_len);
- retlength = remote_read_bytes (new_ptr, (gdb_byte *) newpath, new_len);
- if (retlength != new_len)
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* Only operate on regular files and directories */
- of = stat (oldpath, &ost);
- nf = stat (newpath, &nst);
- if ((!of && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode))
- || (!nf && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode)))
- {
- remote_fileio_reply (-1, FILEIO_EACCES);
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = rename (oldpath, newpath);
-
- if (ret == -1)
- {
- /* Special case: newpath is a non-empty directory. Some systems
- return ENOTEMPTY, some return EEXIST. We coerce that to be
- always EEXIST. */
- if (errno == ENOTEMPTY)
- errno = EEXIST;
-#ifdef __CYGWIN__
- /* Workaround some Cygwin problems with correct errnos. */
- if (errno == EACCES)
- {
- if (!of && !nf && S_ISDIR (nst.st_mode))
- {
- if (S_ISREG (ost.st_mode))
- errno = EISDIR;
- else
- {
- char oldfullpath[PATH_MAX + 1];
- char newfullpath[PATH_MAX + 1];
- int len;
-
- cygwin_conv_to_full_posix_path (oldpath, oldfullpath);
- cygwin_conv_to_full_posix_path (newpath, newfullpath);
- len = strlen (oldfullpath);
- if (newfullpath[len] == '/'
- && !strncmp (oldfullpath, newfullpath, len))
- errno = EINVAL;
- else
- errno = EEXIST;
- }
- }
- }
-#endif
-
- remote_fileio_return_errno (-1);
- }
- else
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_unlink (char *buf)
-{
- CORE_ADDR ptrval;
- int length, retlength;
- char *pathname;
- int ret;
- struct stat st;
-
- /* Parameter: Ptr to pathname / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
- {
- remote_fileio_ioerror ();
- return;
- }
- /* Request pathname using 'm' packet */
- pathname = alloca (length);
- retlength = remote_read_bytes (ptrval, (gdb_byte *) pathname, length);
- if (retlength != length)
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* Only operate on regular files (and directories, which allows to return
- the correct return code) */
- if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
- {
- remote_fileio_reply (-1, FILEIO_ENODEV);
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = unlink (pathname);
-
- if (ret == -1)
- remote_fileio_return_errno (-1);
- else
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_stat (char *buf)
-{
- CORE_ADDR statptr, nameptr;
- int ret, namelength, retlength;
- char *pathname;
- LONGEST lnum;
- struct stat st;
- struct fio_stat fst;
-
- /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &nameptr, &namelength))
- {
- remote_fileio_ioerror ();
- return;
- }
-
- /* 2. Parameter: Ptr to struct stat */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- statptr = (CORE_ADDR) lnum;
-
- /* Request pathname using 'm' packet */
- pathname = alloca (namelength);
- retlength = remote_read_bytes (nameptr, (gdb_byte *) pathname, namelength);
- if (retlength != namelength)
- {
- remote_fileio_ioerror ();
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = stat (pathname, &st);
-
- if (ret == -1)
- {
- remote_fileio_return_errno (-1);
- return;
- }
- /* Only operate on regular files and directories */
- if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
- {
- remote_fileio_reply (-1, FILEIO_EACCES);
- return;
- }
- if (statptr)
- {
- remote_fileio_to_fio_stat (&st, &fst);
- remote_fileio_to_fio_uint (0, fst.fst_dev);
-
- retlength = remote_fileio_write_bytes (statptr,
- (gdb_byte *) &fst, sizeof fst);
- if (retlength != sizeof fst)
- {
- remote_fileio_return_errno (-1);
- return;
- }
- }
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_fstat (char *buf)
-{
- CORE_ADDR ptrval;
- int fd, ret, retlength;
- long target_fd;
- LONGEST lnum;
- struct stat st;
- struct fio_stat fst;
- struct timeval tv;
-
- /* 1. Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &target_fd))
- {
- remote_fileio_ioerror ();
- return;
- }
- fd = remote_fileio_map_fd ((int) target_fd);
- if (fd == FIO_FD_INVALID)
- {
- remote_fileio_badfd ();
- return;
- }
- /* 2. Parameter: Ptr to struct stat */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- ptrval = (CORE_ADDR) lnum;
-
- remote_fio_no_longjmp = 1;
- if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
- {
- remote_fileio_to_fio_uint (1, fst.fst_dev);
- st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
- st.st_nlink = 1;
-#ifdef HAVE_GETUID
- st.st_uid = getuid ();
-#else
- st.st_uid = 0;
-#endif
-#ifdef HAVE_GETGID
- st.st_gid = getgid ();
-#else
- st.st_gid = 0;
-#endif
- st.st_rdev = 0;
- st.st_size = 0;
-#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- st.st_blksize = 512;
-#endif
-#if HAVE_STRUCT_STAT_ST_BLOCKS
- st.st_blocks = 0;
-#endif
- if (!gettimeofday (&tv, NULL))
- st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec;
- else
- st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0;
- ret = 0;
- }
- else
- ret = fstat (fd, &st);
-
- if (ret == -1)
- {
- remote_fileio_return_errno (-1);
- return;
- }
- if (ptrval)
- {
- remote_fileio_to_fio_stat (&st, &fst);
-
- retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &fst, sizeof fst);
- if (retlength != sizeof fst)
- {
- remote_fileio_return_errno (-1);
- return;
- }
- }
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_gettimeofday (char *buf)
-{
- LONGEST lnum;
- CORE_ADDR ptrval;
- int ret, retlength;
- struct timeval tv;
- struct fio_timeval ftv;
-
- /* 1. Parameter: struct timeval pointer */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- ptrval = (CORE_ADDR) lnum;
- /* 2. Parameter: some pointer value... */
- if (remote_fileio_extract_long (&buf, &lnum))
- {
- remote_fileio_ioerror ();
- return;
- }
- /* ...which has to be NULL */
- if (lnum)
- {
- remote_fileio_reply (-1, FILEIO_EINVAL);
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = gettimeofday (&tv, NULL);
-
- if (ret == -1)
- {
- remote_fileio_return_errno (-1);
- return;
- }
-
- if (ptrval)
- {
- remote_fileio_to_fio_timeval (&tv, &ftv);
-
- retlength = remote_fileio_write_bytes (ptrval, (gdb_byte *) &ftv, sizeof ftv);
- if (retlength != sizeof ftv)
- {
- remote_fileio_return_errno (-1);
- return;
- }
- }
- remote_fileio_return_success (ret);
-}
-
-static void
-remote_fileio_func_isatty (char *buf)
-{
- long target_fd;
- int fd;
-
- /* Parameter: file descriptor */
- if (remote_fileio_extract_int (&buf, &target_fd))
- {
- remote_fileio_ioerror ();
- return;
- }
- remote_fio_no_longjmp = 1;
- fd = remote_fileio_map_fd ((int) target_fd);
- remote_fileio_return_success (fd == FIO_FD_CONSOLE_IN ||
- fd == FIO_FD_CONSOLE_OUT ? 1 : 0);
-}
-
-static void
-remote_fileio_func_system (char *buf)
-{
- CORE_ADDR ptrval;
- int ret, length, retlength;
- char *cmdline = NULL;
-
- /* Parameter: Ptr to commandline / length incl. trailing zero */
- if (remote_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
- {
- remote_fileio_ioerror ();
- return;
- }
-
- if (length)
- {
- /* Request commandline using 'm' packet */
- cmdline = alloca (length);
- retlength = remote_read_bytes (ptrval, (gdb_byte *) cmdline, length);
- if (retlength != length)
- {
- remote_fileio_ioerror ();
- return;
- }
- }
-
- /* Check if system(3) has been explicitely allowed using the
- `set remote system-call-allowed 1' command. If length is 0,
- indicating a NULL parameter to the system call, return zero to
- indicate a shell is not available. Otherwise fail with EPERM. */
- if (!remote_fio_system_call_allowed)
- {
- if (!length)
- remote_fileio_return_success (0);
- else
- remote_fileio_reply (-1, FILEIO_EPERM);
- return;
- }
-
- remote_fio_no_longjmp = 1;
- ret = system (cmdline);
-
- if (!length)
- remote_fileio_return_success (ret);
- else if (ret == -1)
- remote_fileio_return_errno (-1);
- else
- remote_fileio_return_success (WEXITSTATUS (ret));
-}
-
-static struct {
- char *name;
- void (*func)(char *);
-} remote_fio_func_map[] = {
- { "open", remote_fileio_func_open },
- { "close", remote_fileio_func_close },
- { "read", remote_fileio_func_read },
- { "write", remote_fileio_func_write },
- { "lseek", remote_fileio_func_lseek },
- { "rename", remote_fileio_func_rename },
- { "unlink", remote_fileio_func_unlink },
- { "stat", remote_fileio_func_stat },
- { "fstat", remote_fileio_func_fstat },
- { "gettimeofday", remote_fileio_func_gettimeofday },
- { "isatty", remote_fileio_func_isatty },
- { "system", remote_fileio_func_system },
- { NULL, NULL }
-};
-
-static int
-do_remote_fileio_request (struct ui_out *uiout, void *buf_arg)
-{
- char *buf = buf_arg;
- char *c;
- int idx;
-
remote_fileio_sig_set (remote_fileio_ctrl_c_signal_handler);
-
- c = strchr (++buf, ',');
- if (c)
- *c++ = '\0';
- else
- c = strchr (buf, '\0');
- for (idx = 0; remote_fio_func_map[idx].name; ++idx)
- if (!strcmp (remote_fio_func_map[idx].name, buf))
- break;
- if (!remote_fio_func_map[idx].name) /* ERROR: No such function. */
- return RETURN_ERROR;
- remote_fio_func_map[idx].func (c);
- return 0;
}
/* Close any open descriptors, and reinitialize the file mapping. */
@@ -1378,85 +147,28 @@ do_remote_fileio_request (struct ui_out *uiout, void *buf_arg)
void
remote_fileio_reset (void)
{
- int ix;
-
- for (ix = 0; ix != remote_fio_data.fd_map_size; ix++)
- {
- int fd = remote_fio_data.fd_map[ix];
-
- if (fd >= 0)
- close (fd);
- }
- if (remote_fio_data.fd_map)
- {
- free (remote_fio_data.fd_map);
- remote_fio_data.fd_map = NULL;
- remote_fio_data.fd_map_size = 0;
- }
+ target_fileio_reset();
}
void
remote_fileio_request (char *buf)
{
- int ex;
+ static struct file_io_operations operations =
+ {
+ remote_read_bytes,
+ remote_fileio_write_bytes,
+ remote_fileio_reply,
+ set_ctrl_c_signal_handler
+ };
remote_fileio_sig_init ();
-
- remote_fio_ctrl_c_flag = 0;
- remote_fio_no_longjmp = 0;
-
- ex = catch_exceptions (uiout, do_remote_fileio_request, (void *)buf,
- RETURN_MASK_ALL);
- switch (ex)
- {
- case RETURN_ERROR:
- remote_fileio_reply (-1, FILEIO_ENOSYS);
- break;
- case RETURN_QUIT:
- remote_fileio_reply (-1, FILEIO_EINTR);
- break;
- default:
- break;
- }
-
+ target_fileio_request(buf, &operations);
remote_fileio_sig_exit ();
}
-static void
-set_system_call_allowed (char *args, int from_tty)
-{
- if (args)
- {
- char *arg_end;
- int val = strtoul (args, &arg_end, 10);
- if (*args && *arg_end == '\0')
- {
- remote_fio_system_call_allowed = !!val;
- return;
- }
- }
- error (_("Illegal argument for \"set remote system-call-allowed\" command"));
-}
-
-static void
-show_system_call_allowed (char *args, int from_tty)
-{
- if (args)
- error (_("Garbage after \"show remote system-call-allowed\" command: `%s'"), args);
- printf_unfiltered ("Calling host system(3) call from target is %sallowed\n",
- remote_fio_system_call_allowed ? "" : "not ");
-}
-
void
initialize_remote_fileio (struct cmd_list_element *remote_set_cmdlist,
struct cmd_list_element *remote_show_cmdlist)
{
- add_cmd ("system-call-allowed", no_class,
- set_system_call_allowed,
- _("Set if the host system(3) call is allowed for the target."),
- &remote_set_cmdlist);
- add_cmd ("system-call-allowed", no_class,
- show_system_call_allowed,
- _("Show if the host system(3) call is allowed for the target."),
- &remote_show_cmdlist);
+ initialize_target_fileio(remote_set_cmdlist, remote_show_cmdlist);
}
diff --git a/gdb/remote-sim.c b/gdb/remote-sim.c
index 918eab856f3..c3a84437018 100644
--- a/gdb/remote-sim.c
+++ b/gdb/remote-sim.c
@@ -469,13 +469,17 @@ gdbsim_create_inferior (char *exec_file, char *args, char **env, int from_tty)
}
else
argv = NULL;
- sim_create_inferior (gdbsim_desc, exec_bfd, argv, env);
- inferior_ptid = pid_to_ptid (42);
- target_mark_running (&gdbsim_ops);
- insert_breakpoints (); /* Needed to get correct instruction in cache */
+ // ARC 12/01/09 check return status
+ // GDB Bug #9734
+ if (sim_create_inferior (gdbsim_desc, exec_bfd, argv, env) == SIM_RC_OK)
+ {
+ inferior_ptid = pid_to_ptid (42);
+ target_mark_running (&gdbsim_ops);
+ insert_breakpoints (); /* Needed to get correct instruction in cache */
- clear_proceed_status ();
+ clear_proceed_status ();
+ }
}
/* The open routine takes the rest of the parameters from the command,
diff --git a/gdb/stack.c b/gdb/stack.c
index 374848b5c3e..f151dc15036 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -831,7 +831,8 @@ parse_frame_specification_1 (const char *frame_exp, const char *message,
{
int i;
for (i = 0; i < numargs; i++)
- addrs[i] = value_as_address (args[0]);
+ addrs[i] = value_as_address (args[i]); // ARC BUG FIX 29/9/08
+ // see http://sourceware.org/ml/gdb-patches/2009-01/msg00476.html
}
/* Assume that the single arg[0] is an address, use that to identify
@@ -892,8 +893,29 @@ frame_info (char *addr_exp, int from_tty)
const char *pc_regname;
int selected_frame_p;
struct gdbarch *gdbarch;
+ CORE_ADDR pc;
fi = parse_frame_specification_1 (addr_exp, "No stack.", &selected_frame_p);
+
+ /* richards ARC 22/9/2008
+ * Try to detect that an invalid frame has been selected (e.g. a frame
+ * number has been given, but there is no such frame on the stack);
+ * N.B. this works for the ARC gdb port, but 0 might be a valid code
+ * address on other processors, so this needs more investigation!
+ *
+ * We should not try to submit this fix to the FSF until we know that it
+ * is generally valid.
+ *
+ * gdb bug: 9458
+ * ARC bug: 95315
+ */
+ pc = get_frame_pc (fi);
+ if (pc == 0)
+ {
+ warning("invalid frame");
+ return;
+ }
+
gdbarch = get_frame_arch (fi);
/* Name of the value returned by get_frame_pc(). Per comments, "pc"
@@ -914,7 +936,7 @@ frame_info (char *addr_exp, int from_tty)
func = get_frame_function (fi);
/* FIXME: cagney/2002-11-28: Why bother? Won't sal.symtab contain
the same value? */
- s = find_pc_symtab (get_frame_pc (fi));
+ s = find_pc_symtab (pc);
if (func)
{
/* It seems appropriate to use SYMBOL_PRINT_NAME() here, to
diff --git a/gdb/symtab.h b/gdb/symtab.h
index c19e74124c2..0d751a7008e 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -574,6 +574,26 @@ struct symbol_ops
struct value *(*read_variable) (struct symbol * symbol,
struct frame_info * frame);
+// begin ARC
+ /* Return the address of the variable SYMBOL, relative to the stack
+ frame FRAME. If the variable has been optimized out, return
+ zero.
+
+ Iff `read_needs_frame (SYMBOL)' is zero, then FRAME may be zero. */
+
+ CORE_ADDR (*get_variable_address) (struct symbol * symbol,
+ struct frame_info * frame);
+
+ /* Return the size of the variable SYMBOL, relative to the stack
+ frame FRAME. If the variable has been optimized out, return
+ zero.
+
+ Iff `read_needs_frame (SYMBOL)' is zero, then FRAME may be zero. */
+
+ unsigned int (*get_variable_size) (struct symbol * symbol,
+ struct frame_info * frame);
+// end ARC
+
/* Return non-zero if we need a frame to find the value of the SYMBOL. */
int (*read_needs_frame) (struct symbol * symbol);
diff --git a/gdb/target-fileio.c b/gdb/target-fileio.c
new file mode 100644
index 00000000000..fdc64c9baa7
--- /dev/null
+++ b/gdb/target-fileio.c
@@ -0,0 +1,1344 @@
+/* Target File-I/O communications
+
+ Copyright (C) 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdb_string.h"
+#include "gdbcmd.h"
+#include "gdb/fileio.h"
+#include "gdb_wait.h"
+#include "gdb_stat.h"
+#include "exceptions.h"
+#include "target-fileio.h"
+
+#include <fcntl.h>
+#include <sys/time.h>
+#ifdef __CYGWIN__
+#include <sys/cygwin.h> /* For cygwin_conv_to_full_posix_path. */
+#endif
+
+static struct {
+ int *fd_map;
+ int fd_map_size;
+} target_fio_data;
+
+#define FIO_FD_INVALID -1
+#define FIO_FD_CONSOLE_IN -2
+#define FIO_FD_CONSOLE_OUT -3
+
+static int target_fio_system_call_allowed = 0;
+
+static int
+target_fileio_init_fd_map (void)
+{
+ int i;
+
+ if (!target_fio_data.fd_map)
+ {
+ target_fio_data.fd_map = (int *) xmalloc (10 * sizeof (int));
+ target_fio_data.fd_map_size = 10;
+ target_fio_data.fd_map[0] = FIO_FD_CONSOLE_IN;
+ target_fio_data.fd_map[1] = FIO_FD_CONSOLE_OUT;
+ target_fio_data.fd_map[2] = FIO_FD_CONSOLE_OUT;
+ for (i = 3; i < 10; ++i)
+ target_fio_data.fd_map[i] = FIO_FD_INVALID;
+ }
+ return 3;
+}
+
+static int
+target_fileio_resize_fd_map (void)
+{
+ int i = target_fio_data.fd_map_size;
+
+ if (!target_fio_data.fd_map)
+ return target_fileio_init_fd_map ();
+ target_fio_data.fd_map_size += 10;
+ target_fio_data.fd_map =
+ (int *) xrealloc (target_fio_data.fd_map,
+ target_fio_data.fd_map_size * sizeof (int));
+ for (; i < target_fio_data.fd_map_size; i++)
+ target_fio_data.fd_map[i] = FIO_FD_INVALID;
+ return target_fio_data.fd_map_size - 10;
+}
+
+static int
+target_fileio_next_free_fd (void)
+{
+ int i;
+
+ for (i = 0; i < target_fio_data.fd_map_size; ++i)
+ if (target_fio_data.fd_map[i] == FIO_FD_INVALID)
+ return i;
+ return target_fileio_resize_fd_map ();
+}
+
+static int
+target_fileio_fd_to_targetfd (int fd)
+{
+ int target_fd =target_fileio_next_free_fd ();
+ target_fio_data.fd_map[target_fd] = fd;
+ return target_fd;
+}
+
+static int
+target_fileio_map_fd (int target_fd)
+{
+ target_fileio_init_fd_map ();
+ if (target_fd < 0 || target_fd >= target_fio_data.fd_map_size)
+ return FIO_FD_INVALID;
+ return target_fio_data.fd_map[target_fd];
+}
+
+static void
+target_fileio_close_target_fd (int target_fd)
+{
+ target_fileio_init_fd_map ();
+ if (target_fd >= 0 && target_fd < target_fio_data.fd_map_size)
+ target_fio_data.fd_map[target_fd] = FIO_FD_INVALID;
+}
+
+static int
+target_fileio_oflags_to_host (long flags)
+{
+ int hflags = 0;
+
+ if (flags & FILEIO_O_CREAT)
+ hflags |= O_CREAT;
+ if (flags & FILEIO_O_EXCL)
+ hflags |= O_EXCL;
+ if (flags & FILEIO_O_TRUNC)
+ hflags |= O_TRUNC;
+ if (flags & FILEIO_O_APPEND)
+ hflags |= O_APPEND;
+ if (flags & FILEIO_O_RDONLY)
+ hflags |= O_RDONLY;
+ if (flags & FILEIO_O_WRONLY)
+ hflags |= O_WRONLY;
+ if (flags & FILEIO_O_RDWR)
+ hflags |= O_RDWR;
+/* On systems supporting binary and text mode, always open files in
+ binary mode. */
+#ifdef O_BINARY
+ hflags |= O_BINARY;
+#endif
+ return hflags;
+}
+
+static mode_t
+target_fileio_mode_to_host (long mode, int open_call)
+{
+ mode_t hmode = 0;
+
+ if (!open_call)
+ {
+ if (mode & FILEIO_S_IFREG)
+ hmode |= S_IFREG;
+ if (mode & FILEIO_S_IFDIR)
+ hmode |= S_IFDIR;
+ if (mode & FILEIO_S_IFCHR)
+ hmode |= S_IFCHR;
+ }
+ if (mode & FILEIO_S_IRUSR)
+ hmode |= S_IRUSR;
+ if (mode & FILEIO_S_IWUSR)
+ hmode |= S_IWUSR;
+ if (mode & FILEIO_S_IXUSR)
+ hmode |= S_IXUSR;
+#ifdef S_IRGRP
+ if (mode & FILEIO_S_IRGRP)
+ hmode |= S_IRGRP;
+#endif
+#ifdef S_IWGRP
+ if (mode & FILEIO_S_IWGRP)
+ hmode |= S_IWGRP;
+#endif
+#ifdef S_IXGRP
+ if (mode & FILEIO_S_IXGRP)
+ hmode |= S_IXGRP;
+#endif
+ if (mode & FILEIO_S_IROTH)
+ hmode |= S_IROTH;
+#ifdef S_IWOTH
+ if (mode & FILEIO_S_IWOTH)
+ hmode |= S_IWOTH;
+#endif
+#ifdef S_IXOTH
+ if (mode & FILEIO_S_IXOTH)
+ hmode |= S_IXOTH;
+#endif
+ return hmode;
+}
+
+static LONGEST
+target_fileio_mode_to_target (mode_t mode)
+{
+ mode_t tmode = 0;
+
+ if (S_ISREG(mode))
+ tmode |= FILEIO_S_IFREG;
+ if (S_ISDIR(mode))
+ tmode |= FILEIO_S_IFDIR;
+ if (S_ISCHR(mode))
+ tmode |= FILEIO_S_IFCHR;
+ if (mode & S_IRUSR)
+ tmode |= FILEIO_S_IRUSR;
+ if (mode & S_IWUSR)
+ tmode |= FILEIO_S_IWUSR;
+ if (mode & S_IXUSR)
+ tmode |= FILEIO_S_IXUSR;
+#ifdef S_IRGRP
+ if (mode & S_IRGRP)
+ tmode |= FILEIO_S_IRGRP;
+#endif
+#ifdef S_IWRGRP
+ if (mode & S_IWGRP)
+ tmode |= FILEIO_S_IWGRP;
+#endif
+#ifdef S_IXGRP
+ if (mode & S_IXGRP)
+ tmode |= FILEIO_S_IXGRP;
+#endif
+ if (mode & S_IROTH)
+ tmode |= FILEIO_S_IROTH;
+#ifdef S_IWOTH
+ if (mode & S_IWOTH)
+ tmode |= FILEIO_S_IWOTH;
+#endif
+#ifdef S_IXOTH
+ if (mode & S_IXOTH)
+ tmode |= FILEIO_S_IXOTH;
+#endif
+ return tmode;
+}
+
+static int
+target_fileio_errno_to_target (int error)
+{
+ switch (error)
+ {
+ case EPERM:
+ return FILEIO_EPERM;
+ case ENOENT:
+ return FILEIO_ENOENT;
+ case EINTR:
+ return FILEIO_EINTR;
+ case EIO:
+ return FILEIO_EIO;
+ case EBADF:
+ return FILEIO_EBADF;
+ case EACCES:
+ return FILEIO_EACCES;
+ case EFAULT:
+ return FILEIO_EFAULT;
+ case EBUSY:
+ return FILEIO_EBUSY;
+ case EEXIST:
+ return FILEIO_EEXIST;
+ case ENODEV:
+ return FILEIO_ENODEV;
+ case ENOTDIR:
+ return FILEIO_ENOTDIR;
+ case EISDIR:
+ return FILEIO_EISDIR;
+ case EINVAL:
+ return FILEIO_EINVAL;
+ case ENFILE:
+ return FILEIO_ENFILE;
+ case EMFILE:
+ return FILEIO_EMFILE;
+ case EFBIG:
+ return FILEIO_EFBIG;
+ case ENOSPC:
+ return FILEIO_ENOSPC;
+ case ESPIPE:
+ return FILEIO_ESPIPE;
+ case EROFS:
+ return FILEIO_EROFS;
+ case ENOSYS:
+ return FILEIO_ENOSYS;
+ case ENAMETOOLONG:
+ return FILEIO_ENAMETOOLONG;
+ }
+ return FILEIO_EUNKNOWN;
+}
+
+static int
+target_fileio_seek_flag_to_host (long num, int *flag)
+{
+ if (!flag)
+ return 0;
+ switch (num)
+ {
+ case FILEIO_SEEK_SET:
+ *flag = SEEK_SET;
+ break;
+ case FILEIO_SEEK_CUR:
+ *flag = SEEK_CUR;
+ break;
+ case FILEIO_SEEK_END:
+ *flag = SEEK_END;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static int
+target_fileio_extract_long (char **buf, LONGEST *retlong)
+{
+ char *c;
+ int sign = 1;
+
+ if (!buf || !*buf || !**buf || !retlong)
+ return -1;
+ c = strchr (*buf, ',');
+ if (c)
+ *c++ = '\0';
+ else
+ c = strchr (*buf, '\0');
+ while (strchr ("+-", **buf))
+ {
+ if (**buf == '-')
+ sign = -sign;
+ ++*buf;
+ }
+ for (*retlong = 0; **buf; ++*buf)
+ {
+ *retlong <<= 4;
+ if (**buf >= '0' && **buf <= '9')
+ *retlong += **buf - '0';
+ else if (**buf >= 'a' && **buf <= 'f')
+ *retlong += **buf - 'a' + 10;
+ else if (**buf >= 'A' && **buf <= 'F')
+ *retlong += **buf - 'A' + 10;
+ else
+ return -1;
+ }
+ *retlong *= sign;
+ *buf = c;
+ return 0;
+}
+
+static int
+target_fileio_extract_int (char **buf, long *retint)
+{
+ int ret;
+ LONGEST retlong;
+
+ if (!retint)
+ return -1;
+ ret =target_fileio_extract_long (buf, &retlong);
+ if (!ret)
+ *retint = (long) retlong;
+ return ret;
+}
+
+static int
+target_fileio_extract_ptr_w_len (char **buf, CORE_ADDR *ptrval, int *length)
+{
+ char *c;
+ LONGEST retlong;
+
+ if (!buf || !*buf || !**buf || !ptrval || !length)
+ return -1;
+ c = strchr (*buf, '/');
+ if (!c)
+ return -1;
+ *c++ = '\0';
+ if (target_fileio_extract_long (buf, &retlong))
+ return -1;
+ *ptrval = (CORE_ADDR) retlong;
+ *buf = c;
+ if (target_fileio_extract_long (buf, &retlong))
+ return -1;
+ *length = (int) retlong;
+ return 0;
+}
+
+/* Convert to big endian */
+static void
+target_fileio_to_be (LONGEST num, char *buf, int bytes)
+{
+ int i;
+
+ for (i = 0; i < bytes; ++i)
+ buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
+}
+
+static void
+target_fileio_to_fio_uint (long num, fio_uint_t fnum)
+{
+ target_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
+}
+
+static void
+target_fileio_to_fio_mode (mode_t num, fio_mode_t fnum)
+{
+ target_fileio_to_be (target_fileio_mode_to_target(num), (char *) fnum, 4);
+}
+
+static void
+target_fileio_to_fio_time (time_t num, fio_time_t fnum)
+{
+ target_fileio_to_be ((LONGEST) num, (char *) fnum, 4);
+}
+
+static void
+target_fileio_to_fio_long (LONGEST num, fio_long_t fnum)
+{
+ target_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+target_fileio_to_fio_ulong (LONGEST num, fio_ulong_t fnum)
+{
+ target_fileio_to_be (num, (char *) fnum, 8);
+}
+
+static void
+target_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
+{
+ LONGEST blksize;
+
+ /* `st_dev' is set in the calling function */
+ target_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
+ target_fileio_to_fio_mode (st->st_mode, fst->fst_mode);
+ target_fileio_to_fio_uint ((long) st->st_nlink, fst->fst_nlink);
+ target_fileio_to_fio_uint ((long) st->st_uid, fst->fst_uid);
+ target_fileio_to_fio_uint ((long) st->st_gid, fst->fst_gid);
+ target_fileio_to_fio_uint ((long) st->st_rdev, fst->fst_rdev);
+ target_fileio_to_fio_ulong ((LONGEST) st->st_size, fst->fst_size);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ blksize = st->st_blksize;
+#else
+ blksize = 512;
+#endif
+ target_fileio_to_fio_ulong (blksize, fst->fst_blksize);
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+ target_fileio_to_fio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks);
+#else
+ /* FIXME: This is correct for DJGPP, but other systems that don't
+ have st_blocks, if any, might prefer 512 instead of st_blksize.
+ (eliz, 30-12-2003) */
+ target_fileio_to_fio_ulong (((LONGEST) st->st_size + blksize - 1)
+ / blksize,
+ fst->fst_blocks);
+#endif
+ target_fileio_to_fio_time (st->st_atime, fst->fst_atime);
+ target_fileio_to_fio_time (st->st_mtime, fst->fst_mtime);
+ target_fileio_to_fio_time (st->st_ctime, fst->fst_ctime);
+}
+
+static void
+target_fileio_to_fio_timeval (struct timeval *tv, struct fio_timeval *ftv)
+{
+ target_fileio_to_fio_time (tv->tv_sec, ftv->ftv_sec);
+ target_fileio_to_fio_long (tv->tv_usec, ftv->ftv_usec);
+}
+
+int target_fio_no_longjmp = 0;
+
+
+static void
+target_fileio_func_open (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR ptrval;
+ int length, retlength;
+ long num;
+ int flags, fd;
+ mode_t mode;
+ char *pathname;
+ struct stat st;
+
+ /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ operations->ioerror ();
+ return;
+ }
+ /* 2. Parameter: open flags */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ flags =target_fileio_oflags_to_host (num);
+ /* 3. Parameter: open mode */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ mode =target_fileio_mode_to_host (num, 1);
+
+ /* Read pathname */
+ pathname = alloca (length);
+ retlength = operations->read_bytes (ptrval, (gdb_byte *) pathname, length);
+ if (retlength != length)
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* Check if pathname exists and is not a regular file or directory. If so,
+ return an appropriate error code. Same for trying to open directories
+ for writing. */
+ if (!stat (pathname, &st))
+ {
+ if (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ operations->reply (-1, FILEIO_ENODEV);
+ return;
+ }
+ if (S_ISDIR (st.st_mode)
+ && ((flags & O_WRONLY) == O_WRONLY || (flags & O_RDWR) == O_RDWR))
+ {
+ operations->reply (-1, FILEIO_EISDIR);
+ return;
+ }
+ }
+
+ target_fio_no_longjmp = 1;
+ fd = open (pathname, flags, mode);
+ if (fd < 0)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+
+ fd =target_fileio_fd_to_targetfd (fd);
+ operations->return_success (fd);
+}
+
+static void
+target_fileio_func_close (char *buf, struct file_io_operations *operations)
+{
+ long num;
+ int fd;
+
+ /* Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ fd =target_fileio_map_fd ((int) num);
+ if (fd == FIO_FD_INVALID)
+ {
+ operations->badfd ();
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ if (fd != FIO_FD_CONSOLE_IN && fd != FIO_FD_CONSOLE_OUT && close (fd))
+ operations->return_errno (-1);
+ target_fileio_close_target_fd ((int) num);
+ operations->return_success (0);
+}
+
+static void
+target_fileio_func_read (char *buf, struct file_io_operations *operations)
+{
+ long target_fd, num;
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ gdb_byte *buffer;
+ size_t length;
+ off_t old_offset, new_offset;
+
+ /* 1. Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &target_fd))
+ {
+ operations->ioerror ();
+ return;
+ }
+ fd =target_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ operations->badfd ();
+ return;
+ }
+ /* 2. Parameter: buffer pointer */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 3. Parameter: buffer length */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ length = (size_t) num;
+
+ switch (fd)
+ {
+ case FIO_FD_CONSOLE_OUT:
+ operations->badfd ();
+ return;
+ case FIO_FD_CONSOLE_IN:
+ {
+ static char *remaining_buf = NULL;
+ static int remaining_length = 0;
+
+ buffer = (gdb_byte *) xmalloc (32768);
+ if (remaining_buf)
+ {
+ target_fio_no_longjmp = 1;
+ if (remaining_length > length)
+ {
+ memcpy (buffer, remaining_buf, length);
+ memmove (remaining_buf, remaining_buf + length,
+ remaining_length - length);
+ remaining_length -= length;
+ ret = length;
+ }
+ else
+ {
+ memcpy (buffer, remaining_buf, remaining_length);
+ xfree (remaining_buf);
+ remaining_buf = NULL;
+ ret = remaining_length;
+ }
+ }
+ else
+ {
+ ret = ui_file_read (gdb_stdtargin, (char *) buffer, 32767);
+ target_fio_no_longjmp = 1;
+ if (ret > 0 && (size_t)ret > length)
+ {
+ remaining_buf = (char *) xmalloc (ret - length);
+ remaining_length = ret - length;
+ memcpy (remaining_buf, buffer + length, remaining_length);
+ ret = length;
+ }
+ }
+ }
+ break;
+ default:
+ buffer = (gdb_byte *) xmalloc (length);
+ /* POSIX defines EINTR behaviour of read in a weird way. It's allowed
+ for read() to return -1 even if "some" bytes have been read. It
+ has been corrected in SUSv2 but that doesn't help us much...
+ Therefore a complete solution must check how many bytes have been
+ read on EINTR to return a more reliable value to the target */
+ old_offset = lseek (fd, 0, SEEK_CUR);
+ target_fio_no_longjmp = 1;
+ ret = read (fd, buffer, length);
+ if (ret < 0 && errno == EINTR)
+ {
+ new_offset = lseek (fd, 0, SEEK_CUR);
+ /* If some data has been read, return the number of bytes read.
+ The Ctrl-C flag is set in target_fileio_reply() anyway */
+ if (old_offset != new_offset)
+ ret = new_offset - old_offset;
+ }
+ break;
+ }
+
+ if (ret > 0)
+ {
+ retlength = operations->write_bytes (ptrval, buffer, ret);
+ if (retlength != ret)
+ ret = -1; /* errno has been set to EIO in remote_write_bytes() */
+ }
+
+ if (ret < 0)
+ operations->return_errno (-1);
+ else
+ operations->return_success (ret);
+
+ xfree (buffer);
+}
+
+static void
+target_fileio_func_write (char *buf, struct file_io_operations *operations)
+{
+ long target_fd, num;
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ gdb_byte *buffer;
+ size_t length;
+
+ /* 1. Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &target_fd))
+ {
+ operations->ioerror ();
+ return;
+ }
+ fd =target_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ operations->badfd ();
+ return;
+ }
+ /* 2. Parameter: buffer pointer */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 3. Parameter: buffer length */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ length = (size_t) num;
+
+ buffer = (gdb_byte *) xmalloc (length);
+ retlength = operations->read_bytes (ptrval, buffer, length);
+ if (retlength != length)
+ {
+ xfree (buffer);
+ operations->ioerror ();
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ switch (fd)
+ {
+ case FIO_FD_CONSOLE_IN:
+ operations->badfd ();
+ xfree (buffer);
+ return;
+ case FIO_FD_CONSOLE_OUT:
+ ui_file_write (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr,
+ (char *) buffer, length);
+ gdb_flush (target_fd == 1 ? gdb_stdtarg : gdb_stdtargerr);
+ ret = length;
+ break;
+ default:
+ ret = write (fd, buffer, length);
+ if (ret < 0 && errno == EACCES)
+ errno = EBADF; /* Cygwin returns EACCESS when writing to a R/O file.*/
+ break;
+ }
+
+ if (ret < 0)
+ operations->return_errno (-1);
+ else
+ operations->return_success (ret);
+
+ xfree (buffer);
+}
+
+static void
+target_fileio_func_lseek (char *buf, struct file_io_operations *operations)
+{
+ long num;
+ LONGEST lnum;
+ int fd, flag;
+ off_t offset, ret;
+
+ /* 1. Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ fd =target_fileio_map_fd ((int) num);
+ if (fd == FIO_FD_INVALID)
+ {
+ operations->badfd ();
+ return;
+ }
+ else if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+ {
+ operations->reply (-1, FILEIO_ESPIPE);
+ return;
+ }
+
+ /* 2. Parameter: offset */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ offset = (off_t) lnum;
+ /* 3. Parameter: flag */
+ if (target_fileio_extract_int (&buf, &num))
+ {
+ operations->ioerror ();
+ return;
+ }
+ if (target_fileio_seek_flag_to_host (num, &flag))
+ {
+ operations->reply (-1, FILEIO_EINVAL);
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = lseek (fd, offset, flag);
+
+ if (ret == (off_t) -1)
+ operations->return_errno (-1);
+ else
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_rename (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR old_ptr, new_ptr;
+ int old_len, new_len, retlength;
+ char *oldpath, *newpath;
+ int ret, of, nf;
+ struct stat ost, nst;
+
+ /* 1. Parameter: Ptr to oldpath / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &old_ptr, &old_len))
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* 2. Parameter: Ptr to newpath / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &new_ptr, &new_len))
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* Request oldpath */
+ oldpath = alloca (old_len);
+ retlength = operations->read_bytes (old_ptr, (gdb_byte *) oldpath, old_len);
+ if (retlength != old_len)
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* Request newpath */
+ newpath = alloca (new_len);
+ retlength = operations->read_bytes (new_ptr, (gdb_byte *) newpath, new_len);
+ if (retlength != new_len)
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* Only operate on regular files and directories */
+ of = stat (oldpath, &ost);
+ nf = stat (newpath, &nst);
+ if ((!of && !S_ISREG (ost.st_mode) && !S_ISDIR (ost.st_mode))
+ || (!nf && !S_ISREG (nst.st_mode) && !S_ISDIR (nst.st_mode)))
+ {
+ operations->reply (-1, FILEIO_EACCES);
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = rename (oldpath, newpath);
+
+ if (ret == -1)
+ {
+ /* Special case: newpath is a non-empty directory. Some systems
+ return ENOTEMPTY, some return EEXIST. We coerce that to be
+ always EEXIST. */
+ if (errno == ENOTEMPTY)
+ errno = EEXIST;
+#ifdef __CYGWIN__
+ /* Workaround some Cygwin problems with correct errnos. */
+ if (errno == EACCES)
+ {
+ if (!of && !nf && S_ISDIR (nst.st_mode))
+ {
+ if (S_ISREG (ost.st_mode))
+ errno = EISDIR;
+ else
+ {
+ char oldfullpath[PATH_MAX + 1];
+ char newfullpath[PATH_MAX + 1];
+ int len;
+
+ cygwin_conv_to_full_posix_path (oldpath, oldfullpath);
+ cygwin_conv_to_full_posix_path (newpath, newfullpath);
+ len = strlen (oldfullpath);
+ if (newfullpath[len] == '/'
+ && !strncmp (oldfullpath, newfullpath, len))
+ errno = EINVAL;
+ else
+ errno = EEXIST;
+ }
+ }
+ }
+#endif
+
+ operations->return_errno (-1);
+ }
+ else
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_unlink (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR ptrval;
+ int length, retlength;
+ char *pathname;
+ int ret;
+ struct stat st;
+
+ /* Parameter: Ptr to pathname / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ operations->ioerror ();
+ return;
+ }
+ /* Request pathname */
+ pathname = alloca (length);
+ retlength = operations->read_bytes (ptrval, (gdb_byte *) pathname, length);
+ if (retlength != length)
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* Only operate on regular files (and directories, which allows to return
+ the correct return code) */
+ if (!stat (pathname, &st) && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ operations->reply (-1, FILEIO_ENODEV);
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = unlink (pathname);
+
+ if (ret == -1)
+ operations->return_errno (-1);
+ else
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_stat (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR statptr, nameptr;
+ int ret, namelength, retlength;
+ char *pathname;
+ LONGEST lnum;
+ struct stat st;
+ struct fio_stat fst;
+
+ /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &nameptr, &namelength))
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ /* 2. Parameter: Ptr to struct stat */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ statptr = (CORE_ADDR) lnum;
+
+ /* Request pathname */
+ pathname = alloca (namelength);
+ retlength = operations->read_bytes (nameptr, (gdb_byte *) pathname, namelength);
+ if (retlength != namelength)
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = stat (pathname, &st);
+
+ if (ret == -1)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+ /* Only operate on regular files and directories */
+ if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode))
+ {
+ operations->reply (-1, FILEIO_EACCES);
+ return;
+ }
+ if (statptr)
+ {
+ target_fileio_to_fio_stat (&st, &fst);
+ target_fileio_to_fio_uint (0, fst.fst_dev);
+
+ retlength = operations->write_bytes (statptr,
+ (gdb_byte *) &fst, sizeof fst);
+ if (retlength != sizeof fst)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+ }
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_fstat (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR ptrval;
+ int fd, ret, retlength;
+ long target_fd;
+ LONGEST lnum;
+ struct stat st;
+ struct fio_stat fst;
+ struct timeval tv;
+
+ /* 1. Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &target_fd))
+ {
+ operations->ioerror ();
+ return;
+ }
+ fd =target_fileio_map_fd ((int) target_fd);
+ if (fd == FIO_FD_INVALID)
+ {
+ operations->badfd ();
+ return;
+ }
+ /* 2. Parameter: Ptr to struct stat */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+
+ // ARC bug fix 25/11/2008
+ memset(&st, 0, sizeof(st));
+ memset(&fst, 0, sizeof(fst));
+
+ target_fio_no_longjmp = 1;
+ if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
+ {
+ target_fileio_to_fio_uint (1, fst.fst_dev);
+ st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
+ st.st_nlink = 1;
+#ifdef HAVE_GETUID
+ st.st_uid = getuid ();
+#else
+ st.st_uid = 0;
+#endif
+#ifdef HAVE_GETGID
+ st.st_gid = getgid ();
+#else
+ st.st_gid = 0;
+#endif
+ st.st_rdev = 0;
+ st.st_size = 0;
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+ st.st_blksize = 512;
+#endif
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+ st.st_blocks = 0;
+#endif
+
+ /* N.B. st.st_ino is not set! */
+
+ if (!gettimeofday (&tv, NULL))
+ st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec;
+ else
+ st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0;
+ ret = 0;
+ }
+ else {
+ ret = fstat (fd, &st);
+ target_fileio_to_fio_uint (st.st_dev, fst.fst_dev); // ARC bug fix 10/11/2008 gdb bug: 9655
+ }
+
+ if (ret == -1)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+ if (ptrval)
+ {
+ target_fileio_to_fio_stat (&st, &fst);
+
+ retlength = operations->write_bytes (ptrval, (gdb_byte *) &fst, sizeof fst);
+ if (retlength != sizeof fst)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+ }
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_gettimeofday (char *buf, struct file_io_operations *operations)
+{
+ LONGEST lnum;
+ CORE_ADDR ptrval;
+ int ret, retlength;
+ struct timeval tv;
+ struct fio_timeval ftv;
+
+ /* 1. Parameter: struct timeval pointer */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ ptrval = (CORE_ADDR) lnum;
+ /* 2. Parameter: some pointer value... */
+ if (target_fileio_extract_long (&buf, &lnum))
+ {
+ operations->ioerror ();
+ return;
+ }
+ /* ...which has to be NULL */
+ if (lnum)
+ {
+ operations->reply (-1, FILEIO_EINVAL);
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = gettimeofday (&tv, NULL);
+
+ if (ret == -1)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+
+ if (ptrval)
+ {
+ target_fileio_to_fio_timeval (&tv, &ftv);
+
+ retlength = operations->write_bytes (ptrval, (gdb_byte *) &ftv, sizeof ftv);
+ if (retlength != sizeof ftv)
+ {
+ operations->return_errno (-1);
+ return;
+ }
+ }
+ operations->return_success (ret);
+}
+
+static void
+target_fileio_func_isatty (char *buf, struct file_io_operations *operations)
+{
+ long target_fd;
+ int fd;
+
+ /* Parameter: file descriptor */
+ if (target_fileio_extract_int (&buf, &target_fd))
+ {
+ operations->ioerror ();
+ return;
+ }
+ target_fio_no_longjmp = 1;
+ fd =target_fileio_map_fd ((int) target_fd);
+ operations->return_success (fd == FIO_FD_CONSOLE_IN ||
+ fd == FIO_FD_CONSOLE_OUT ? 1 : 0);
+}
+
+static void
+target_fileio_func_system (char *buf, struct file_io_operations *operations)
+{
+ CORE_ADDR ptrval;
+ int ret, length, retlength;
+ char *cmdline = NULL;
+
+ /* Parameter: Ptr to commandline / length incl. trailing zero */
+ if (target_fileio_extract_ptr_w_len (&buf, &ptrval, &length))
+ {
+ operations->ioerror ();
+ return;
+ }
+
+ if (length)
+ {
+ /* Request commandline */
+ cmdline = alloca (length);
+ retlength = operations->read_bytes (ptrval, (gdb_byte *) cmdline, length);
+ if (retlength != length)
+ {
+ operations->ioerror ();
+ return;
+ }
+ }
+
+ /* Check if system(3) has been explicitely allowed using the
+ `set remote system-call-allowed 1' command. If length is 0,
+ indicating a NULL parameter to the system call, return zero to
+ indicate a shell is not available. Otherwise fail with EPERM. */
+ if (!target_fio_system_call_allowed)
+ {
+ if (!length)
+ operations->return_success (0);
+ else
+ operations->reply (-1, FILEIO_EPERM);
+ return;
+ }
+
+ target_fio_no_longjmp = 1;
+ ret = system (cmdline);
+
+ if (!length)
+ operations->return_success (ret);
+ else if (ret == -1)
+ operations->return_errno (-1);
+ else
+ operations->return_success (WEXITSTATUS (ret));
+}
+
+static struct {
+ char *name;
+ void (*func)(char *, struct file_io_operations *);
+} target_fio_func_map[] = {
+ { "open", target_fileio_func_open },
+ { "close", target_fileio_func_close },
+ { "read", target_fileio_func_read },
+ { "write", target_fileio_func_write },
+ { "lseek", target_fileio_func_lseek },
+ { "rename", target_fileio_func_rename },
+ { "unlink", target_fileio_func_unlink },
+ { "stat", target_fileio_func_stat },
+ { "fstat", target_fileio_func_fstat },
+ { "gettimeofday", target_fileio_func_gettimeofday },
+ { "isatty", target_fileio_func_isatty },
+ { "system", target_fileio_func_system },
+ { NULL, NULL }
+};
+
+struct request_args {
+ char *buf;
+ struct file_io_operations *operations;
+};
+
+static int
+do_target_fileio_request (struct ui_out *uiout, void *args)
+{
+ struct request_args* request = (struct request_args*) args;
+ char *buf = request->buf;
+ char *c;
+ int idx;
+
+ request->operations->set_ctrl_c_signal_handler();
+
+ c = strchr (++buf, ',');
+ if (c)
+ *c++ = '\0';
+ else
+ c = strchr (buf, '\0');
+ for (idx = 0; target_fio_func_map[idx].name; ++idx)
+ if (!strcmp (target_fio_func_map[idx].name, buf))
+ break;
+ if (!target_fio_func_map[idx].name) /* ERROR: No such function. */
+ return RETURN_ERROR;
+ target_fio_func_map[idx].func (c, request->operations);
+ return 0;
+}
+
+/* Close any open descriptors, and reinitialize the file mapping. */
+
+void
+target_fileio_reset (void)
+{
+ int ix;
+
+ for (ix = 0; ix != target_fio_data.fd_map_size; ix++)
+ {
+ int fd = target_fio_data.fd_map[ix];
+
+ if (fd >= 0)
+ close (fd);
+ }
+ if (target_fio_data.fd_map)
+ {
+ free (target_fio_data.fd_map);
+ target_fio_data.fd_map = NULL;
+ target_fio_data.fd_map_size = 0;
+ }
+}
+
+
+void
+target_fileio_request (char *buf, struct file_io_operations *operations)
+{
+ struct request_args args = {buf, operations};
+ int ex;
+
+ target_fio_no_longjmp = 0;
+
+ ex = catch_exceptions (uiout, do_target_fileio_request, (void *)&args,
+ RETURN_MASK_ALL);
+ switch (ex)
+ {
+ case RETURN_ERROR:
+ operations->reply (-1, FILEIO_ENOSYS);
+ break;
+ case RETURN_QUIT:
+ operations->reply (-1, FILEIO_EINTR);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+set_system_call_allowed (char *args, int from_tty)
+{
+ if (args)
+ {
+ char *arg_end;
+ int val = strtoul (args, &arg_end, 10);
+ if (*args && *arg_end == '\0')
+ {
+ target_fio_system_call_allowed = !!val;
+ return;
+ }
+ }
+ error (_("Illegal argument for \"set remote system-call-allowed\" command"));
+}
+
+static void
+show_system_call_allowed (char *args, int from_tty)
+{
+ if (args)
+ error (_("Garbage after \"show remote system-call-allowed\" command: `%s'"), args);
+ printf_unfiltered ("Calling host system(3) call from target is %sallowed\n",
+ target_fio_system_call_allowed ? "" : "not ");
+}
+
+void
+initialize_target_fileio (struct cmd_list_element *set_cmdlist,
+ struct cmd_list_element *show_cmdlist)
+{
+ add_cmd ("system-call-allowed", no_class,
+ set_system_call_allowed,
+ _("Set if the host system(3) call is allowed for the target."),
+ &set_cmdlist);
+ add_cmd ("system-call-allowed", no_class,
+ show_system_call_allowed,
+ _("Show if the host system(3) call is allowed for the target."),
+ &show_cmdlist);
+}
diff --git a/gdb/target-fileio.h b/gdb/target-fileio.h
new file mode 100644
index 00000000000..46efd90428a
--- /dev/null
+++ b/gdb/target-fileio.h
@@ -0,0 +1,53 @@
+/* Target File-I/O communications
+
+ Copyright (C) 2003, 2007, 2008 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef TARGET_FILEIO_H
+#define TARGET_FILEIO_H
+
+struct cmd_list_element;
+
+struct file_io_operations {
+ int (*read_bytes) (CORE_ADDR memaddr, gdb_byte *myaddr, int len);
+ int (*write_bytes)(CORE_ADDR memaddr, gdb_byte *myaddr, int len);
+ void (*reply)(int retcode, int error);
+ void (*set_ctrl_c_signal_handler)(void);
+};
+
+
+#define ioerror() reply(-1, FILEIO_EIO)
+#define badfd() reply(-1, FILEIO_EBADF)
+#define return_errno(retcode) reply(retcode, ((retcode) < 0) ? target_fileio_errno_to_target (errno) : 0)
+#define return_success(retcode) reply(retcode, 0)
+
+
+/* Unified interface to target fileio */
+extern void target_fileio_request (char *buf, struct file_io_operations *operations);
+
+/* Cleanup any target fileio state. */
+extern void target_fileio_reset (void);
+
+extern void initialize_target_fileio (
+ struct cmd_list_element *set_cmdlist,
+ struct cmd_list_element *show_cmdlist);
+
+
+extern int target_fio_no_longjmp;
+
+#endif
diff --git a/gdb/target.c b/gdb/target.c
index 87ddf249e0a..3887f1774c2 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -39,6 +39,10 @@
#include "gdbcore.h"
#include "exceptions.h"
#include "target-descriptions.h"
+// begin ARC
+#include "observer.h"
+#include "cli/cli-decode.h"
+// end ARC
static void target_info (char *, int);
@@ -228,9 +232,28 @@ target_command (char *arg, int from_tty)
/* Add a possible target architecture to the list. */
+// begin ARC
+static void
+pre_open_notify (char *name, int from_tty)
+{
+ observer_notify_target_pre_connect(&current_target);
+}
+
+static void
+post_open_notify (char *name, int from_tty)
+{
+ observer_notify_target_post_connect(&current_target);
+}
+// end ARC
+
+
void
add_target (struct target_ops *t)
{
+// begin ARC
+ struct cmd_list_element *cmd;
+// end ARC
+
/* Provide default values for all "must have" methods. */
if (t->to_xfer_partial == NULL)
t->to_xfer_partial = default_xfer_partial;
@@ -258,7 +281,16 @@ Remaining arguments are interpreted by the target protocol. For more\n\
information on the arguments for a particular protocol, type\n\
`help target ' followed by the protocol name."),
&targetlist, "target ", 0, &cmdlist);
+
+// begin ARC
+ cmd =
+// end ARC
add_cmd (t->to_shortname, no_class, t->to_open, t->to_doc, &targetlist);
+
+// begin ARC
+ (void) add_cmd ("", no_class, pre_open_notify, "", &cmd->hook_pre);
+ (void) add_cmd ("", no_class, post_open_notify, "", &cmd->hook_post);
+// end ARC
}
/* Stub functions */
@@ -389,6 +421,7 @@ update_current_target (void)
INHERIT (to_shortname, t);
INHERIT (to_longname, t);
INHERIT (to_doc, t);
+ INHERIT (to_data, t); // ARC 16/02/2009 gdb bug: 9886
INHERIT (to_open, t);
INHERIT (to_close, t);
INHERIT (to_attach, t);
@@ -645,6 +678,10 @@ update_current_target (void)
if (targetdebug)
setup_target_debug ();
+
+// begin ARC
+ observer_notify_target_updated(&current_target);
+// end ARC
}
/* Mark OPS as a running target. This reverses the effect
@@ -685,7 +722,7 @@ target_mark_exited (struct target_ops *ops)
break;
if (t == NULL)
internal_error (__FILE__, __LINE__,
- "Attempted to mark unpushed target \"%s\" as running",
+ "Attempted to mark unpushed target \"%s\" as non-running", // ARC 17/11/08 correct message gdb bug: 9887
ops->to_shortname);
ops->to_has_execution = 0;
@@ -1649,6 +1686,9 @@ void
target_detach (char *args, int from_tty)
{
(current_target.to_detach) (args, from_tty);
+// begin ARC
+ observer_notify_target_post_disconnect(&current_target);
+// end ARC
}
void
@@ -1760,7 +1800,13 @@ find_default_attach (char *args, int from_tty)
struct target_ops *t;
t = find_default_run_target ("attach");
+// begin ARC
+ observer_notify_target_pre_connect(t);
+// end ARC
(t->to_attach) (args, from_tty);
+// begin ARC
+ observer_notify_target_post_connect(t);
+// end ARC
return;
}
@@ -2060,6 +2106,9 @@ debug_to_close (int quitting)
{
target_close (&debug_target, quitting);
fprintf_unfiltered (gdb_stdlog, "target_close (%d)\n", quitting);
+// begin ARC
+ observer_notify_target_post_disconnect(&debug_target);
+// end ARC
}
void
@@ -2069,6 +2118,9 @@ target_close (struct target_ops *targ, int quitting)
targ->to_xclose (targ, quitting);
else if (targ->to_close != NULL)
targ->to_close (quitting);
+// begin ARC
+ observer_notify_target_post_disconnect(targ);
+// end ARC
}
static void
@@ -2092,6 +2144,9 @@ static void
debug_to_detach (char *args, int from_tty)
{
debug_target.to_detach (args, from_tty);
+// begin ARC
+ observer_notify_target_post_disconnect(&debug_target);
+// end ARC
fprintf_unfiltered (gdb_stdlog, "target_detach (%s, %d)\n", args, from_tty);
}
diff --git a/gdb/testsuite/config/arc-jtag.exp b/gdb/testsuite/config/arc-jtag.exp
deleted file mode 100644
index 16891111772..00000000000
--- a/gdb/testsuite/config/arc-jtag.exp
+++ /dev/null
@@ -1,112 +0,0 @@
-# Test Framework Driver for GDB using the arcjtag target.
-
-# Copyright 2005 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This 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.
-
-load_lib gdb.exp
-
-#
-# gdb_target_arcjtag
-# Set gdb to target arcjtag.
-#
-proc gdb_target_arcjtag { } {
- global gdb_prompt
- global exit_status
-
- # our arcjtag target doesn't take any options (yet)
- #set target_arcjtag_options "[board_info target gdb,target_sim_options]";
-
- send_gdb "target arcjtag\n"
-
- gdb_expect 60 {
- -re "A program is being debugged already.*Kill it.*y or n. $" {
- send_gdb "y\n"
- verbose "\t\tKilling previous program being debugged"
- exp_continue
- }
- -re "Connected to the arcjtag target.*$gdb_prompt $" {
- verbose "Set target to arcjtag"
- }
- -re "$gdb_prompt $" {
- verbose "Retrying target arcjtag..."
- send_gdb "arc-reset-board\n"
- send_gdb "target arcjtag\n"
-
- gdb_expect 60 {
- -re "A program is being debugged already.*Kill it.*y or n. $" {
- send_gdb "y\n"
- verbose "\t\tKilling previous program being debugged"
- exp_continue
- }
- -re "Connected to the arcjtag target.*$gdb_prompt $" {
- verbose "Set target to arcjtag"
- }
- timeout {
- perror "Couldn't set target to arcjtag (timeout)."
- return 1
- }
- }
- }
- timeout {
- perror "Couldn't set target to arcjtag (timeout)."
- return 1
- }
- }
-
- return 0
-}
-
-#
-# gdb_load -- load a file into the debugger.
-# return a -1 if anything goes wrong.
-#
-proc gdb_load { arg } {
- global verbose
- global loadpath
- global loadfile
- global GDB
- global gdb_prompt
-
- if { $arg != "" } {
- if [gdb_file_cmd $arg] then { return -1 }
- }
-
- if { [gdb_target_arcjtag] != 0 } {
- return -1
- }
-
- # gotta do something about the timeout....
- send_gdb "load\n"
-
- gdb_expect 180 {
- -re ".*$gdb_prompt $" {
- if $verbose>1 then {
- send_user "Loaded $arg into $GDB\n"
- }
- return 0
- }
- -re "$gdb_prompt $" {
- if $verbose>1 then {
- perror "GDB couldn't load."
- }
- }
- timeout {
- perror "Timed out trying to load $arg."
- }
- }
-
- return 1
-}
diff --git a/gdb/testsuite/config/remote-gdbserver.exp b/gdb/testsuite/config/remote-gdbserver.exp
deleted file mode 100644
index 60d106debc5..00000000000
--- a/gdb/testsuite/config/remote-gdbserver.exp
+++ /dev/null
@@ -1,570 +0,0 @@
-# Test framework for GDB (remote protocol) using a "gdbserver",
-# ie. a debug agent running as a native process on the same or
-# a different host.
-
-# Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This 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.
-
-# Please email any bugs, comments, and/or additions to this file to:
-# bug-gdb@prep.ai.mit.edu
-
-# This file was written by Michael Snyder. (msnyder@redhat.com)
-
-#
-# This module to be used for testing gdb with a "gdbserver"
-# built either from libremote or from gdb/gdbserver.
-#
-
-# Load the basic testing library, and the remote stuff.
-load_lib ../config/monitor.exp
-load_lib telnet.exp
-#
-# To be addressed or set in your baseboard config file:
-#
-# set_board_info gdb_protocol "remote"
-# Unles you have a gdbserver that uses a different protocol...
-#
-# set_board_info use_gdb_stub 1
-# This tells the rest of the test suite not to do things
-# like "run" which don't work well on remote targets.
-#
-# set_board_info gdb,do_reload_on_run 1
-# Unles you have a gdbserver that can handle multiple sessions.
-#
-# set_board_info noargs 1
-# At present there is no provision in the remote protocol
-# for passing arguments. This test framework does not
-# address the issue, so it's best to set this variable
-# in your baseboard configuration file.
-# FIXME: there's no reason why the test harness couldn't
-# pass commandline args when it spawns gdbserver.
-#
-# set_board_info gdb,noinferiorio 1
-# Neither the traditional gdbserver nor the one in libremote
-# can presently capture stdout and relay it to GDB via the
-# 'O' packet. This means that tests involving printf will
-# fail unles you set this varibale in your baseboard
-# configuration file.
-#
-# set_board_info gdb,no_hardware_watchpoints 1
-# Unles you have a gdbserver that supports hardware watchpoints.
-# FIXME: gdb should detect if the target doesn't support them,
-# and fall back to using software watchpoints.
-#
-# set_board_info gdb_server_prog
-# This will be the path to the gdbserver program you want to test.
-# Defaults to "gdbserver".
-#
-# set_board_info sockethost
-# The name of the host computer whose socket is being used.
-# Defaults to "localhost". Note: old gdbserver requires
-# that you define this, but libremote/gdbserver does not.
-#
-# set_board_info socketport
-# Port id to use for socket connection. If not set explicitly,
-# it will start at "2345" and increment for each use.
-#
-# set_board_info rsh_prog
-# The program to use to spawn executables on the remote board.
-# Default: "rsh"
-#
-# set_board_info rcp_prog
-# The program to use to copy test executables to the remote board.
-# Default: "rcp"
-#
-# set_board_info nfsdir
-# If rcp_prog is set to "cp", specify the local directory name that
-# is NFS mounted by the board.
-
-#
-# gdb_load -- load a file into the debugger.
-# return a -1 if anything goes wrong.
-#
-
-global server_exec;
-global portnum;
-set portnum "2000";
-
-proc gdb_load { args } {
- global server_exec;
- global portnum;
- global verbose;
- global gdb_prompt;
-
- # Port id -- either specified in baseboard file, or managed here.
- if [target_info exists gdb,socketport] {
- set portnum [target_info gdb,socketport];
- } else {
- # Bump the port number to avoid conflicts with hung ports.
- incr portnum;
- }
-
- # Extract the local and remote host ids from the target board struct.
-
- if [target_info exists sockethost] {
- set debughost [target_info sockethost];
- } else {
- set debughost "localhost:";
- }
- # Extract the protocol
- if [target_info exists gdb_protocol] {
- set protocol [target_info gdb_protocol];
- } else {
- set protocol "remote";
- }
-
- # Extract the name of the gdbserver, if known (default 'gdbserver').
- if [target_info exists gdb_server_prog] {
- set gdbserver [target_info gdb_server_prog];
- } else {
- set gdbserver "gdbserver";
- }
- # Extract the socket hostname
- if [target_info exists sockethost] {
- set sockethost [target_info sockethost];
- } else {
- set sockethost ""
- }
-
- # Get target name
- if [target_info exists hostname] {
- set target_address [target_info hostname];
- } else {
- set target_address "localhost"
- }
-
- # Get the username on the target
- if [target_info exists "username"] {
- set username [target_info username];
- } else {
- set username "";
- }
-
- # Get download dir
- if [target_info exists download_dir] {
- set download_dir [target_info download_dir];
- } else {
- set download_dir "/tmp"
- }
-
- # Get tests dir
- if [target_info exists tests_dir] {
- set tests_dir [target_info tests_dir];
- } else {
- set tests_dir $download_dir
- }
-
- # Export the host:port pair.
- set gdbport $debughost$portnum;
-
- if { $args == "" || $args == "{}" } {
- if [info exists server_exec] {
- set args $server_exec;
- } else {
- send_gdb "info files\n";
- gdb_expect 30 {
- -re "Symbols from \"(\[^\"\]+)\"" {
- set args $expect_out(1,string);
- exp_continue;
- }
- -re "Local exec file:\[\r\n\]+\[ \t\]*`(\[^'\]+)'," {
- set args $expect_out(1,string);
- exp_continue;
- }
- -re "$gdb_prompt $" { }
- }
- }
- }
-
- # remember new exec file
- set server_exec $args;
-
- # Download the test files into the test_board
- gdbserver_download $target_address $username $server_exec \
- $download_dir/a-$portnum.out
-
- # tell gdb what file we are debugging
- if [gdb_file_cmd $args] {
- return -1;
- }
-
- if [target_info exists solib_path] {
- send_gdb "set solib-absolute-prefix [target_info solib_path]\n"
- gdb_expect 30 {
- -re "$gdb_prompt $" {
- if $verbose>1 then {
- send_user "set library path\n"
- }
- }
- default {
- perror "Couldn't set library path\n"
- return -1
- }
- }
- }
-
- for {set i 1} {$i <= 3} {incr i} {
- # Fire off the debug agent
- set server_spawn_id [gdbserver_spawn $target_address $username \
- "$gdbserver $target_address:$portnum $tests_dir/a-$portnum.out 2>&1"]
-
- if { $server_spawn_id <= 0 } { return -1 }
-
- # Wait for the server to produce at least one line and an additional
- # character of output. This will wait until any TCP socket has been
- # created, so that GDB can connect.
- expect {
- # expect output from $server_spawn_id
- -i $server_spawn_id
- -re ".*\n." { }
- }
-
- # We can't just call close, because if gdbserver is local then that means
- # that it will get a SIGHUP. Doing it this way could also allow us to
- # get at the inferior's input or output if necessary, and means that we
- # don't need to redirect output.
- expect_background {
- -i $server_spawn_id
- -re "." { }
- eof {
- # The spawn ID is already closed now (but not yet waited for).
- wait -nowait -i $expect_out(spawn_id)
- }
- }
-
- # attach to the "serial port"
- if {[gdb_target_cmd $protocol $gdbport] == 0 } {
- break
- }
- verbose -log "Unable to connect to target. Re-trying.."
- }
-
- # do the real load if needed
- if [target_info exists gdb_server_do_load] {
- send_gdb "load\n"
- set timeout 2400
- verbose "Timeout is now $timeout seconds" 2
- gdb_expect {
- -re ".*$gdb_prompt $" {
- if $verbose>1 then {
- send_user "Loaded $arg into $GDB\n"
- }
- set timeout 30
- verbose "Timeout is now $timeout seconds" 2
- return 1
- }
- -re "$gdb_prompt $" {
- if $verbose>1 then {
- perror "GDB couldn't load."
- }
- }
- timeout {
- if $verbose>1 then {
- perror "Timed out trying to load $arg."
- }
- }
- }
- }
-
- return 0;
-}
-
-
-# Use RSH or telnet depending on the program chosen
-# by the board file.
-# Return spawn_id
-proc gdbserver_spawn { dest username commandline } {
- global board_info
- if ![target_info exists rsh_prog] {
- if { [which remsh] != 0 } {
- set RSH remsh
- } else {
- set RSH rsh
- }
- } else {
- set RSH [target_info rsh_prog];
- }
-
- if { $RSH == "rsh" } {
- return [rsh_gdbserver_spawn $dest $username $commandline]
- } else {
-
- if { $RSH == "telnet" } {
- # Spawn the shell
- return [telnet_gdbserver_spawn $dest $username $commandline]
-
- # expect the shell prompt obtained from
- # the board description.
- # Now spawn gdbserver with its parameters
- # and dont expect any output from the gdbserver
- # other than the shell prompt
- # FIXME ?? Where do I close the telnet
- # session ( could use gdb_finish for closing the telnet session)
-
-
-
- } else {
- verbose "Unknown rsh program "
- return -1
- }
- }
-}
-
-proc mynewtelnet_open_and_exec { dest port shell_prompt commandline } {
- global board_info
-
- spawn "telnet-exec.exp" $dest $commandline
- set board_info($dest,fileid) $spawn_id;
- return $spawn_id;
-}
-
-
-proc mytelnet_open_and_exec { dest port shell_prompt commandline } {
- set tries 0
- set result -1
- set need_respawn 1
-
- verbose "Starting a telnet connection to $dest:$port $shell_prompt " 2
- while { $result < 0 && $tries <= 3 } {
- if { $need_respawn } {
- set need_respawn 0
- spawn "telnet" $dest $port
- }
- expect {
- "Trying " {
- exp_continue
- }
- -re "$shell_prompt.*$" {
- verbose "Got prompt $shell_prompt\n"
- set result 0
- exp_send $commandline
-
- }
- -re "nt Name:|ogin:" {
- if [board_info $connhost exists telnet_username] {
- exp_send "[board_info $connhost telnet_username]\n"
- exp_continue
- }
- if [board_info $connhost exists username] {
- exp_send "[board_info $connhost username]\n"
- exp_continue
- }
- perror "telnet: need to login"
- break
- }
- "assword:" {
- if [board_info $connhost exists telnet_password] {
- exp_send "[board_info $connhost telnet_password]\n"
- exp_continue
- }
- if [board_info $connhost exists password] {
- exp_send "[board_info $connhost password]\n"
- exp_continue
- }
- perror "telnet: need a password"
- break
- }
- -re "advance.*y/n.*\\?" {
- exp_send "n\n"
- exp_continue
- }
- -re {([Aa]dvanced|[Ss]imple) or ([Ss]imple|[Aa]dvanced)} {
- exp_send "simple\n"
- exp_continue
- }
- "Connected to" {
- exp_continue
- }
- "unknown host" {
- exp_send "\003"
- perror "telnet: unknown host"
- break
- }
- "VxWorks Boot" {
- exp_send "@\n"
- sleep 20
- exp_continue
- }
- -re "Escape character is.*\\.\[\r\n\]" {
- exp_continue
- }
- "has logged on from" {
- exp_continue
- }
- "You have no Kerberos tickets" {
- warning "telnet: no kerberos Tickets, please kinit"
- break
- }
- -re "Connection refused.*$" {
- catch "exp_send \"\003\"" foo
- sleep 5
- warning "telnet: connection refused."
- }
- -re "Sorry, this system is engaged.*" {
- exp_send "\003"
- warning "telnet: already connected."
- }
- "Connection closed by foreign host.*$" {
- warning "telnet: connection closed by foreign host."
- break
- }
- -re "\[\r\n\]+" {
- exp_continue
- }
- timeout {
- exp_send "\n"
- }
- eof {
- warning "telnet: got unexpected EOF from telnet."
- catch close
- catch wait
- set need_respawn 1
- sleep 5
- }
- }
- incr tries
- }
-
-
- verbose "spawn id is $spawn_id"
- set board_info($dest,fileid) $spawn_id;
- return $spawn_id
-}
-
-# Use telnet to spawn a session
-proc telnet_gdbserver_spawn { dest username commandline } {
- global board_info
- set remote $dest
- set telnet_prog "telnet"
- set prompt [target_info shell_prompt]
- set mport 23
- verbose "commandline is $commandline"
- return [mynewtelnet_open_and_exec $remote $mport $prompt $commandline]
-}
-
-
-#
-# Use $RSH to spawn $commandline on remote machine $dest as user $username.
-# (Note $username on $dest will have to have appropriate .rhost entries.)
-#
-proc rsh_gdbserver_spawn { dest username commandline } {
- global board_info
-
- if [target_info exists rsh_prog] {
- set RSH [target_info rsh_prog];
- } else {
- set RSH rsh
- }
-
- if [board_info $dest exists hostname] {
- set remote [board_info $dest hostname];
- } else {
- set remote $dest;
- }
-
- if { $username == "" } {
- set rsh_useropts ""
- } else {
- set rsh_useropts "-l"
- }
-
- verbose "spawn $RSH $rsh_useropts $username $remote $commandline";
- spawn $RSH $rsh_useropts $username $remote $commandline;
- set board_info($dest,fileid) $spawn_id;
-
- set timeout 60
- expect {
- # expect output from $spawn_id
- -i $spawn_id
- -re "(.*No route to host)|(poll: protocol failure in circuit setup)|(.*Unknown host)|(.*Connection refused)|(Login incorrect)|(Permission denied)" {
- verbose -log "$RSH to $remote failed, output \"$expect_out(buffer)\""
- return -1
- }
- -re ".*\r" { }
- timeout {
- verbose -log "$RSH to $remote timedout (timeout=$timeout)"
- return -1
- }
- eof {
- verbose -log "$RSH to $remote failed"
- return -1
- }
- }
-
- return $spawn_id;
-}
-
-#
-# Download $srcfile to $destfile on $desthost as user $username using rcp.
-#
-
-proc gdbserver_download {desthost username srcfile destfile} {
- if [target_info exists rsh_prog] {
- set RSH [target_info rsh_prog];
- } else {
- set RSH rsh
- }
-
- if ![target_info exists rcp_prog] {
- set RCP rcp
- } else {
- set RCP [target_info rcp_prog];
- }
-
- if [board_info $desthost exists name] {
- set desthost [board_info $desthost name];
- }
-
- if [board_info $desthost exists hostname] {
- set desthost [board_info $desthost hostname];
- }
-
- if { $username == "" } {
- set rsh_useropts ""
- set rcp_dest $desthost
- } else {
- set rsh_useropts "-l $username"
- set rcp_dest "$username@$desthost"
- }
-
- # Delete the output file
- # set status [catch "exec $RSH $rsh_useropts $desthost rm -f $destfile |& cat" output]
-
- if { $RCP != "cp" } {
- set status [catch "exec $RCP $srcfile $rcp_dest:$destfile |& cat" output]
- } else {
- if [target_info exists nfsdir] {
- set nfsdir [target_info nfsdir];
- verbose -log "nfsdir is $nfsdir"
- set status [catch "exec cp $srcfile $nfsdir/$destfile |& cat" output]
- } else {
- verbose "\nnfsdir not set\n"
- set status 1
- }
- }
- if { $status == 0 } {
- if [target_info exists nfsdir] {
- verbose "Copied $srcfile to $nfsdir/$destfile" 2
- return $destfile;
- } else {
- verbose "Copied $srcfile to $desthost:$destfile" 2
- return $destfile;
- }
- } else {
- verbose "Download to $desthost failed, $output."
- return ""
- }
-}
diff --git a/gdb/testsuite/gdb.arch/arc-step-jtag.exp b/gdb/testsuite/gdb.arch/arc-step-jtag.exp
deleted file mode 100644
index a51f00e4b54..00000000000
--- a/gdb/testsuite/gdb.arch/arc-step-jtag.exp
+++ /dev/null
@@ -1,88 +0,0 @@
-if $tracelevel {
- strace $tracelevel
-}
-
-# Test single-stepping zero-overhead-loops and delay slots
-
-if ![istarget "arc-*-*"] then {
- verbose "Skipping ARC single-step tests."
- return
-}
-
-if ![istarget "*elf32*"] then {
- verbose "Skipping ARC JTAG single-step tests."
- return
-}
-
-set testfile "arc-step-jtag"
-set srcfile ${testfile}.s
-set binfile ${objdir}/${subdir}/${testfile}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ""] != "" } {
- gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
-}
-
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-
-if { [ gdb_load ${binfile} ] != 0 } {
- gdb_suppress_entire_file "Load failed, so all tests in this file will automatically fail."
-}
-
-#
-# Run to `main' where we begin our tests.
-#
-
-gdb_test "adv _main" ".* in _main .*" "advance to _main"
-
-gdb_test "stepi" ".* Lmov .*" "step mov instruction"
-gdb_test "p \$r0" ".*= 1" "r0 value after mov instruction"
-
-gdb_test "stepi" ".* Lmov_s .*" "step mov_s instruction"
-gdb_test "p \$r0" ".*= 2" "r0 value after mov_s instruction"
-
-gdb_test "stepi" ".* Lb .*" "step b instruction"
-
-gdb_test "stepi" ".* Lb_s .*" "step b_s instruction"
-
-gdb_test "stepi" ".* Lbdotd_dslot .*" "step b.d branch"
-gdb_test "stepi" ".* Lbdotd .*" "step b.d delay slot"
-gdb_test "p \$r0" ".*= 5" "r0 value after b.d delay slot"
-
-gdb_test "stepi" ".* Lbl .*" "step bl instruction"
-
-gdb_test "stepi" ".* Lj_sdotd_dslot .*" "step j_s.d \[blink\] branch"
-gdb_test "stepi" ".* Lj_sdotd .*" "step j_s.d \[blink\] delay slot"
-gdb_test "p \$r0" ".*= 6" "r0 value after j_s.d \[blink\] delay slot"
-
-gdb_test "stepi" ".* Lj .*" "step j instruction"
-
-gdb_test "stepi" ".*" "step mov instruction"
-gdb_test "stepi" ".* ZOLstart .*" "step lp instruction"
-
-gdb_test "p \$lp_count" ".*= 3" "lp_count value"
-gdb_test "p \$lp_end - \$lp_start" \
- ".* = 8" "lp_end - lp_start == 8"
-
-gdb_test "p \$r0" ".* = 6" "r0 value before loop"
-
-# step thru the loop, checking the value of r0
-
-# first iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 7" "r0 value after 1 iteration"
-gdb_test "stepi" ".* ZOLstart .*" "step across end of ZOL"
-
-# second iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 8" "r0 value after 2 iterations"
-gdb_test "stepi" ".* ZOLstart .*" "step across end of ZOL"
-
-# last iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 9" "r0 value after 3 iterations"
-gdb_test "stepi" ".* ZOLend .*" "step out of end of ZOL"
-
-# exit(r0)
-gdb_test "continue" ".*Program exited.*011.*" \
- "value of r0 on exit"
diff --git a/gdb/testsuite/gdb.arch/arc-step-jtag.s b/gdb/testsuite/gdb.arch/arc-step-jtag.s
deleted file mode 100644
index 7ad8e1f9fb2..00000000000
--- a/gdb/testsuite/gdb.arch/arc-step-jtag.s
+++ /dev/null
@@ -1,46 +0,0 @@
-_main:
- .global _main
-main:
- .global main
-
- mov r0,1 ; 32 bit instruction
-Lmov:
- mov_s r0,2 ; 16 bit instruction
-Lmov_s:
- b Lb ; 32 bit, no delay slot
- mov r0,3
- nop
-Lb:
- b_s Lb_s ; 16 bit, no delay slot
- mov r0,4
- nop
-Lb_s:
- b.d Lbdotd ; 32 bit, delay slot
-Lbdotd_dslot:
- mov r0,5
- nop
-Lbdotd:
-
- bl Lbl
-Lj_sdotd:
- j Lj
-Lbl:
- j_s.d [blink] ; 16 bit, delay slot
-Lj_sdotd_dslot:
- mov r0,6
-Lj:
- mov lp_count,3 ; zero-overhead loop
- lp ZOLend
-ZOLstart:
- add r0,r0,1
-ZOLmiddle:
- nop
-ZOLend:
- ;; r0 should be 9
-
-
- ;; exit(r0)
- flag 1
- nop
- nop
- nop
diff --git a/gdb/testsuite/gdb.arch/arc-step.exp b/gdb/testsuite/gdb.arch/arc-step.exp
deleted file mode 100644
index e958b5fbf61..00000000000
--- a/gdb/testsuite/gdb.arch/arc-step.exp
+++ /dev/null
@@ -1,83 +0,0 @@
-if $tracelevel {
- strace $tracelevel
-}
-
-# Test single-stepping zero-overhead-loops and delay slots
-
-if ![istarget "arc-*-*"] then {
- verbose "Skipping ARC single-step tests."
- return
-}
-
-if ![istarget "*linux*"] then {
- verbose "Skipping ARC linux single-step tests."
- return
-}
-
-set testfile "arc-step"
-set srcfile ${testfile}.s
-set binfile ${objdir}/${subdir}/${testfile}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ""] != "" } {
- gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
-}
-
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-gdb_load ${binfile}
-
-#
-# Run to `main' where we begin our tests.
-#
-
-gdb_test "adv _main" ".* in _main .*" "advance to _main"
-
-gdb_test "stepi" ".* Lmov .*" "step mov instruction"
-gdb_test "p \$r0" ".*= 1" "r0 value after mov instruction"
-
-gdb_test "stepi" ".* Lmov_s .*" "step mov_s instruction"
-gdb_test "p \$r0" ".*= 2" "r0 value after mov_s instruction"
-
-gdb_test "stepi" ".* Lb .*" "step b instruction"
-
-gdb_test "stepi" ".* Lb_s .*" "step b_s instruction"
-
-gdb_test "stepi" ".* Lbdotd .*" "step b.d instruction"
-gdb_test "p \$r0" ".*= 5" "r0 value after b.d instruction"
-
-gdb_test "stepi" ".* Lbl .*" "step bl instruction"
-
-gdb_test "stepi" ".* Lj_sdotd .*" "step j_s.d \[blink\] instruction"
-gdb_test "p \$r0" ".*= 6" "r0 value after j_s.d \[blink\] instruction"
-
-gdb_test "stepi" ".* Lj .*" "step j instruction"
-
-gdb_test "stepi" ".*" "step mov instruction"
-gdb_test "stepi" ".* ZOLstart .*" "step lp instruction"
-
-gdb_test "p \$lp_count" ".*= 3" "lp_count value"
-gdb_test "p \$lp_end - \$lp_start" \
- ".* = 8" "lp_end - lp_start == 8"
-
-gdb_test "p \$r0" ".* = 6" "r0 value before loop"
-
-# step thru the loop, checking the value of r0
-
-# first iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 7" "r0 value after 1 iteration"
-gdb_test "stepi" ".* ZOLstart .*" "step across end of ZOL"
-
-# second iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 8" "r0 value after 1 iteration"
-gdb_test "stepi" ".* ZOLstart .*" "step across end of ZOL"
-
-# last iteration
-gdb_test "stepi" ".* ZOLmiddle .*" "step add instruction (inside ZOL)"
-gdb_test "p \$r0" ".* = 9" "r0 value after 1 iteration"
-gdb_test "stepi" ".* ZOLend .*" "step out of end of ZOL"
-
-# exit(r0)
-gdb_test "continue" ".*Program exited.*011.*" \
- "value of r0 on exit"
diff --git a/gdb/testsuite/gdb.arch/arc-step.s b/gdb/testsuite/gdb.arch/arc-step.s
deleted file mode 100644
index 8dce39a0e8d..00000000000
--- a/gdb/testsuite/gdb.arch/arc-step.s
+++ /dev/null
@@ -1,43 +0,0 @@
-_main:
- .global _main
-main:
- .global main
-
- mov r0,1 ; 32 bit instruction
-Lmov:
- mov_s r0,2 ; 16 bit instruction
-Lmov_s:
- b Lb ; 32 bit, no delay slot
- mov r0,3
- nop
-Lb:
- b_s Lb_s ; 16 bit, no delay slot
- mov r0,4
- nop
-Lb_s:
- b.d Lbdotd ; 32 bit, delay slot
- mov r0,5
- nop
-Lbdotd:
-
- bl Lbl
-Lj_sdotd:
- j Lj
-Lbl:
- j_s.d [blink] ; 16 bit, delay slot
- mov r0,6
-Lj:
- mov lp_count,3 ; zero-overhead loop
- lp ZOLend
-ZOLstart:
- add r0,r0,1
-ZOLmiddle:
- nop
-ZOLend:
- ;; r0 should be 9
-
-
- ;; exit(r0)
- ;; mov r0,0
- mov r8,1
- trap_s 0
diff --git a/gdb/testsuite/gdb.asm/arc.inc b/gdb/testsuite/gdb.asm/arc.inc
deleted file mode 100644
index e22c35c081d..00000000000
--- a/gdb/testsuite/gdb.asm/arc.inc
+++ /dev/null
@@ -1,55 +0,0 @@
-
- comment "subroutine prologue"
- .macro gdbasm_enter
- st.a blink,[sp,-4]
- st.a fp, [sp,-4]
- mov fp,sp
- .endm
-
- comment "subroutine epilogue"
- .macro gdbasm_leave
- ld.ab fp, [sp,4]
- ld blink,[sp,0]
- j.d [blink]
- add sp,sp,4
- .endm
-
- .macro gdbasm_call subr
- bl \subr
- .endm
-
- .macro gdbasm_several_nops
- nop
- nop
- nop
- nop
- .endm
-
- comment "exit (0)"
- .macro gdbasm_exit0
- mov_s r0,0
- trap_s 0
- .endm
-
- comment "crt0 startup"
- .macro gdbasm_startup
- mov fp, 0
- .endm
-
- comment "Declare a data variable"
- .macro gdbasm_datavar name value
- .data
-\name:
- .long \value
- .endm
-
- comment "Declare the start of a subroutine"
- .macro gdbasm_declare name
- .type \name, @function
-\name:
- .endm
-
- comment "End a subroutine"
- .macro gdbasm_end name
- .size \name, .-name
- .endm
diff --git a/gdb/testsuite/gdb.asm/asm-source.exp b/gdb/testsuite/gdb.asm/asm-source.exp
index a94fd9895af..0f531a96347 100644
--- a/gdb/testsuite/gdb.asm/asm-source.exp
+++ b/gdb/testsuite/gdb.asm/asm-source.exp
@@ -48,12 +48,6 @@ switch -glob -- [istarget] {
"*arm-*-*" {
set asm-arch arm
}
- "arc-*-*" {
- set asm-arch arc
- set asm-flags "-I${srcdir}/${subdir} -I${objdir}/${subdir}"
- set debug-flags "-gdwarf-2"
- append link-flags " -marclinux"
- }
"xscale-*-*" {
set asm-arch arm
}
diff --git a/gdb/testsuite/gdb.base/callfuncs.exp b/gdb/testsuite/gdb.base/callfuncs.exp
index 1a4da6e0b69..de1f6479281 100644
--- a/gdb/testsuite/gdb.base/callfuncs.exp
+++ b/gdb/testsuite/gdb.base/callfuncs.exp
@@ -266,6 +266,15 @@ proc fetch_all_registers {test} {
}
exp_continue
}
+ -re "^COUNT0\[ \t\]+\[^\r\n\]+\[\r\n\]+" {
+ if [istarget "arc*"] {
+ # Filter out COUNT0 which is an instruction counter on the simulator,
+ # giving spurious differences.
+ } else {
+ lappend all_registers_lines $expect_out(0,string)
+ }
+ exp_continue
+ }
-re "^\[^ \t\]+\[ \t\]+\[^\r\n\]+\[\r\n\]+" {
lappend all_registers_lines $expect_out(0,string)
exp_continue
diff --git a/gdb/testsuite/gdb.base/float.exp b/gdb/testsuite/gdb.base/float.exp
index ca84466cae0..e0f0d9ffabc 100644
--- a/gdb/testsuite/gdb.base/float.exp
+++ b/gdb/testsuite/gdb.base/float.exp
@@ -97,8 +97,6 @@ if { [istarget "alpha*-*-*"] } then {
gdb_test "info float" "fr4.*fr4R.*fr31R.*" "info float"
} elseif [istarget "sparc*-*-*"] then {
gdb_test "info float" "f0.*f1.*f31.*d0.*d30.*" "info float"
-} elseif [istarget "arc*-*-*"] then {
- gdb_test "info float" "Software FPU.*"
} else {
gdb_test "info float" "No floating.point info available for this processor." "info float (unknown target)"
}
diff --git a/gdb/testsuite/gdb.base/relocate.exp b/gdb/testsuite/gdb.base/relocate.exp
index 46f7ab6ae1f..a7beba94f94 100644
--- a/gdb/testsuite/gdb.base/relocate.exp
+++ b/gdb/testsuite/gdb.base/relocate.exp
@@ -78,7 +78,7 @@ set static_bar_addr [get_var_address static_bar]
# Make sure they have different addresses.
if { "${static_foo_addr}" == "${static_bar_addr}" } {
- fail "static variables have different addresses"
+ fail "static variables have same address"
} else {
pass "static variables have different addresses"
}
@@ -89,7 +89,7 @@ set global_bar_addr [get_var_address global_bar]
# Make sure they have different addresses.
if { "${global_foo_addr}" == "${global_bar_addr}" } {
- fail "global variables have different addresses"
+ fail "global variables have same address"
} else {
pass "global variables have different addresses"
}
@@ -100,7 +100,7 @@ set function_bar_addr [get_var_address function_bar]
# Make sure they have different addresses.
if { "${function_foo_addr}" == "${function_bar_addr}" } {
- fail "functions have different addresses"
+ fail "functions have same address"
} else {
pass "functions have different addresses"
}
@@ -126,7 +126,7 @@ set new_function_foo_addr [get_var_address function_foo]
# Make sure they have different addresses.
if { "${function_foo_addr}" == "${new_function_foo_addr}" } {
- fail "function foo has a different address"
+ fail "function foo has the same address"
} else {
pass "function foo has a different address"
}
diff --git a/gdb/testsuite/lib/arc-gdbserver.exp b/gdb/testsuite/lib/arc-gdbserver.exp
deleted file mode 100644
index 6674e9240d0..00000000000
--- a/gdb/testsuite/lib/arc-gdbserver.exp
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software
-# Foundation, Inc.
-#
-# This file is part of DejaGnu.
-#
-# DejaGnu is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# DejaGnu 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 DejaGnu; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-# gdbserver running cross
-
-#load the config file
-load_generic_config "remote-gdbserver"
-
-
-process_multilib_options ""
-
-# The default compiler for this target.
-set_board_info compiler "$env(GDBTEST_CC)"
-set_board_info cflags "$env(GDBTEST_CFLAGS)"
-set_board_info assembler "$env(GDBTEST_AS) $env(GDBTEST_ASFLAGS)"
-set_board_info linker "$env(GDBTEST_LD)"
-set_board_info ldflags "$env(GDBTEST_LDFLAGS)"
-
-# We will be using the standard GDB remote protocol
-set_board_info gdb_protocol "remote"
-
-set_board_info netport "$env(GDBTEST_GDBSERVER_HOST):$env(GDBTEST_GDBSERVER_PORT)"
-
-# Path to the gdbserver executable, if required.
-set_board_info gdb_server_prog $env(GDBTEST_GDBSERVER_PATH)
-# "../gdbserver/gdbserver"
-
-# Name of the computer whose socket will be used, if required.
-set_board_info sockethost "$env(GDBTEST_GDBSERVER_HOST):"
-
-# Port ID to use for socket connection
-set_board_info gdb,socketport $env(GDBTEST_GDBSERVER_PORT)
-
-# Use techniques appropriate to a stub
-set_board_info use_gdb_stub 1
-
-# This gdbserver can only run a process once per session.
-set_board_info gdb,do_reload_on_run 1
-
-# There's no support for argument-passing (yet).
-set_board_info noargs 1
-
-# Can't do FILE IO in current gdbserver
-set_board_info gdb,nofileio 1
-
-# Can't do input (or output) in the current gdbserver.
-set_board_info gdb,noinferiorio 1
-
-# Can't do hardware watchpoints, in general
-set_board_info gdb,no_hardware_watchpoints 1
-
-# Copy the testcases using cp
-set_board_info rcp_prog "cp"
-
-
-# Set nfs directory
-# On my machine this is how it is mounted. - ramana
-# kanika:/home/opt/share on /mnt/nfsmounts type nfs (rw,addr=192.168.100.68)
-set_board_info nfsdir $env(GDBTEST_NFSDIR)
-
-# Set the test directory on the board. Where is this mounted
-# on the board.
-set_board_info tests_dir $env(GDBTEST_TESTS_DIR)
-
-# run on target using rsh
-set_board_info rsh_prog "rsh"
-
-# Download directory
-set_board_info download_dir $env(GDBTEST_DOWNLOAD_DIR)
-
-# Hostname
-set_board_info hostname $env(GDBTEST_GDBSERVER_HOST)
-set_board_info username "root"
-set_board_info sockethost "$env(GDBTEST_GDBSERVER_HOST):"
-
-#Shell prompt
-set_board_info shell_prompt "\[arcLinux\]$"
-
-#set_board_info board,connect "telnet"
-
-# timeout
-#set_board_info gdb,timeout 300
diff --git a/gdb/testsuite/lib/arc-jtag.exp b/gdb/testsuite/lib/arc-jtag.exp
deleted file mode 100644
index c613f307a79..00000000000
--- a/gdb/testsuite/lib/arc-jtag.exp
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# The baseboard file for the arcjtag target
-#
-
-load_generic_config "arc-jtag"
-
-set_board_info compiler "$env(GDBTEST_CC)"
-set_board_info cflags "$env(GDBTEST_CFLAGS)"
-set_board_info assembler "$env(GDBTEST_AS) $env(GDBTEST_ASFLAGS)"
-set_board_info linker "$env(GDBTEST_LD)"
-set_board_info ldflags "$env(GDBTEST_LDFLAGS)"
-
-#Reload the file before running
-set_board_info gdb,do_reload_on_run 1
-
-#Arguments cannot be passed
-set_board_info noargs 1
-
-#File IO not supported
-set_board_info gdb,nofileio 1
-
-#Inferior is unable to do I/O
-set_board_info gdb,noinferiorio 1
-
-#Signals not supported
-set_board_info gdb,nosignals 1
-
-#Skip the huge.exp test
-set_board_info gdb,skip_huge_test 1
-
-#We use "target arcjtag" to talk to JTAG
-set_board_info gdb_protocol "arcjtag"
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index cbfa253579a..edf52e04698 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -191,7 +191,21 @@ proc delete_breakpoints {} {
proc gdb_run_cmd {args} {
global gdb_prompt
- if [target_info exists gdb_init_command] {
+
+ send_gdb "target sim\n"
+ gdb_expect 120 {
+ -re "Connected to the simulator.*$gdb_prompt $" {
+ verbose "Connected to simulator." 2
+ }
+ }
+
+ send_gdb "load\n"
+ gdb_expect 120 {
+ -re ".*$gdb_prompt $" {
+ }
+ }
+
+ if [target_info exists gdb_init_command] {
send_gdb "[target_info gdb_init_command]\n";
gdb_expect 30 {
-re "$gdb_prompt $" { }
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index 73de76f0883..6fbaa224386 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -250,10 +250,6 @@ proc gdbserver_start { options arguments } {
proc gdbserver_spawn { child_args } {
set target_exec [gdbserver_download]
- if [target_info exists tests_dir] {
- set tests_dir [target_info tests_dir]
- set gdbserver_server_exec $tests_dir/$gdbserver_server_exec
- }
# Fire off the debug agent. This flavour of gdbserver takes as
# arguments the port information, the name of the executable file to
# be debugged, and any arguments.
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index a67b0cc8a8c..99cc80bc64c 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -773,6 +773,19 @@ proc mi_run_cmd {args} {
}
global mi_gdb_prompt
+ send_gdb "target sim\n"
+ gdb_expect 120 {
+ -re "Connected to the simulator.*$gdb_prompt $" {
+ verbose "Connected to simulator." 2
+ }
+ }
+
+ send_gdb "load\n"
+ gdb_expect 120 {
+ -re ".*$gdb_prompt $" {
+ }
+ }
+
if [target_info exists gdb_init_command] {
send_gdb "[target_info gdb_init_command]\n";
gdb_expect 30 {
diff --git a/gdb/testsuite/lib/telnet-exec.exp b/gdb/testsuite/lib/telnet-exec.exp
deleted file mode 100644
index 8bbaa8de232..00000000000
--- a/gdb/testsuite/lib/telnet-exec.exp
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/expect -f
-
-#
-#
-#
-
-
-set host "192.168.100.222"
-set debuggee [lindex $argv 0]
-
-set timeout 360
-set env(TERM) vt100; # actual value doesn't matter, just has to be set
-
-spawn telnet $host
-sleep 1; # wait for telnet to happen
-send "PS1=\\# \r"
-expect "\# "
-#expect "\[arcLinux\]\$"
-#send_user "one\n"
-
-
-send "cd /nfs/gdbserver-tests/ \r"
-expect "\# "
-#expect "\[arcLinux\]\$"
-send_user "starting gdbserver...\n"
-send "./gdbserver host:4004 /nfs/gdbserver-tests/ramana-tests/a-4004.out \r"
-
-expect "xxx"
-send "exit" \ No newline at end of file
diff --git a/gdb/version.in b/gdb/version.in
index 99b56c20aca..21afad37646 100644
--- a/gdb/version.in
+++ b/gdb/version.in
@@ -1 +1 @@
-6.8-arc-20070620
+6.8