blob: 2c7de60639f57af8b3ca048bf07060a5e0a159d5 [file] [log] [blame]
/* 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);
}
/******************************************************************************/