diff options
Diffstat (limited to 'gdb/arc-elf32-tdep.c')
-rwxr-xr-x | gdb/arc-elf32-tdep.c | 2064 |
1 files changed, 2064 insertions, 0 deletions
diff --git a/gdb/arc-elf32-tdep.c b/gdb/arc-elf32-tdep.c new file mode 100755 index 0000000..2c7de60 --- /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(¤t_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); +} + +/******************************************************************************/ |