diff options
Diffstat (limited to 'gdb/arc-xiss.c')
-rwxr-xr-x | gdb/arc-xiss.c | 1787 |
1 files changed, 1787 insertions, 0 deletions
diff --git a/gdb/arc-xiss.c b/gdb/arc-xiss.c new file mode 100755 index 0000000..2319f36 --- /dev/null +++ b/gdb/arc-xiss.c @@ -0,0 +1,1787 @@ +/* Target dependent code for ARC processor family, for GDB, the GNU debugger. + + Copyright 2009 Free Software Foundation, Inc. + + Contributed by ARC International (www.arc.com) + + Authors: + Richard Stuckey <richard.stuckey@arc.com> + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/******************************************************************************/ +/* */ +/* Outline: */ +/* This module creates an instance of a gdb 'target_ops' structure which */ +/* contains information and operations for debugging using the ARC xISS */ +/* (Fast Instruction Set Simulator) as the target. */ +/* */ +/* Instruction Tracing: */ +/* Two different kind of instruction tracing are supported: */ +/* */ +/* 1) a minimal trace which records only the address of each instruction */ +/* which is executed; */ +/* */ +/* 2) a more detailed trace which includes the ordinal number of the */ +/* instruction in the trace, condition code settings, instruction */ +/* address, instruction disassembly, and the values of source and */ +/* destination operands. */ +/* */ +/* The minimal trace is recorded by the xISS in an internal buffer whose */ +/* size may be determined by the gdb user; this buffer wraps around, so */ +/* that only the addresses of the most recently executed instructions are */ +/* held. This data may then be saved to a file for subsequent inspection. */ +/* The trace data is written in an encoding which gives a reduction in */ +/* size of approximately 80% compared to the raw data. */ +/* */ +/* See the manual */ +/* */ +/* ARC GDB-Insight */ +/* GNU Debugger With Insight GUI */ +/* Getting Started */ +/* 6009-001 */ +/* */ +/* for full information on how to use these trace facilities. */ +/* */ +/* Usage: */ +/* The module exports a function _initialize_arc_xiss: the call to this */ +/* function is generated by the gdb build mechanism, so this function */ +/* should not be explicitly called. */ +/* */ +/******************************************************************************/ + +/* gdb configuration file */ +#include "config.h" + +/* This macro should be defined in the configuration file only if the arcint.h + file is available. */ +#ifdef HAVE_LIBXISS + +/* system header files */ +#include <unistd.h> +#include <errno.h> +#include <dlfcn.h> + +/* gdb header files */ +#include "defs.h" +#include "inferior.h" +#include "disasm.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "libiberty.h" +#include "completer.h" +#include "gdb_assert.h" + +/* ARC header files */ +#include "config/arc/tm-embed.h" +#include "arc-xiss.h" +#include "arc-tdep.h" +#include "arc-elf32-tdep.h" +#include "arc-architecture.h" +#include "arc-inst-tracing.h" +#include "arc-registers.h" + +/* This must be defined before arcint.h is included. */ +#define OEM_USE_OF_DEBUGGER_HEADER_FILES 1 + +/* This defines the interface by which the xISS is accessed. */ +#include "arcint.h" + + +/* -------------------------------------------------------------------------- */ +/* local types */ +/* -------------------------------------------------------------------------- */ + +typedef struct ARC* (*ARC_Interface)(void); + +typedef enum +{ + XISS_HALTED, + XISS_STEPPED, + XISS_TO_BE_RUN +} ExecutionStatus; + + +/* N.B. this is taken from arcint.cpp; there must be a better way of doing this! */ +struct ARC +{ + ARC_functab *pftp; /* Pointer to interface function table. */ +}; + +typedef void* WatchpointCookie; + +typedef struct _association +{ + WatchpointCookie cookie; + CORE_ADDR addr; + int length; + int type; +} Association; + + +/* -------------------------------------------------------------------------- */ +/* local data */ +/* -------------------------------------------------------------------------- */ + +#define ARC_TARGET_NAME "arcxiss" +#define ARC_INTERFACE "get_ARC_interface" + +#define SAVE_TRACE_TO_FILE_COMMAND "arc-xiss-save-trace" +#define EMPTY_TRACE_BUFFER_COMMAND "arc-xiss-empty-trace-buffer" +#define LIST_TRACE_COMMAND "arc-xiss-list-trace" + +#define SAVE_TRACE_TO_FILE_COMMAND_USAGE "Usage: " SAVE_TRACE_TO_FILE_COMMAND " <FILE>\n" +#define EMPTY_TRACE_BUFFER_COMMAND_USAGE "Usage: " EMPTY_TRACE_BUFFER_COMMAND "\n" +#define LIST_TRACE_COMMAND_USAGE "Usage: " LIST_TRACE_COMMAND " [ FROM=<VALUE> ] [ TO=<VALUE> ] [ <FILE> ]\n" + + +/* N.B. the xISS does not currently use the context parameter supplied for + memory read/write operations, so its value is irrelevant. */ +#define XISS_CONTEXT 0 + + +/* The gdb target operations structure for this target. */ +static struct target_ops xISS_target_ops; + +/* A set of pointers to operations for reading/writing registers/memory in the + xISS target. */ +static TargetOperations operations; + +/* Handles for access to the xISS target. */ +static void *xISS_DLL_handle; +static struct ARC *xiss_instance; +static ARC_functab *xISS_functions; + +/* The status of program execution on the xISS target. */ +static ExecutionStatus xISS_executionStatus; + +/* Data for handling instruction tracing. */ +static Boolean xISS_trace_instructions; +static char *xiss_trace_file; +static int xiss_trace_buffer_size; + +/* This is the table for associating watchpoint details with watchpoint cookies. */ +static Association *associations; +static unsigned int num_associations; + +/* The address of data to which access caused a watchpoint to trigger. */ +static CORE_ADDR stopped_data_address; + + +/* -------------------------------------------------------------------------- */ +/* local macros */ +/* -------------------------------------------------------------------------- */ + +#define EXTRACT(argument, type, result) \ +{ \ + struct expression *expr = parse_expression(argument); \ + struct value *val = evaluate_expression(expr); \ + struct cleanup *chain = make_cleanup(free_current_contents, &expr); \ + \ + result = *(type*) (value_contents (val)); \ + result ## _specified = TRUE; \ + do_cleanups (chain); \ +} + +/* This macro must cope with the cases: + var = value + var =value + var= value + var=value */ +#define GET_PARAMETER(var) \ + if (strncasecmp(argv[i], #var "=", sizeof(#var)) == 0) \ + { \ + if (argv[i][sizeof(#var)] == '\0') \ + { \ + i++; \ + if (argv[i] == NULL) \ + invalid = TRUE; \ + else \ + { \ + EXTRACT(argv[i], Ordinal, var) \ + i++; \ + } \ + } \ + else \ + { \ + EXTRACT(argv[i] + sizeof(#var), Ordinal, var) \ + i++; \ + } \ + } \ + else if (strcasecmp(argv[i], #var) == 0) \ + { \ + i++; \ + if (argv[i] == NULL) \ + invalid = TRUE; \ + else \ + { \ + if (argv[i][0] == '=') \ + { \ + if (argv[i][1] == '\0') \ + { \ + i++; \ + if (argv[i] == NULL) \ + invalid = TRUE; \ + else \ + { \ + EXTRACT(argv[i], Ordinal, var) \ + i++; \ + } \ + } \ + else \ + { \ + EXTRACT(argv[i] + 1, Ordinal, var) \ + i++; \ + } \ + } \ + else \ + invalid = TRUE; \ + } \ + } + + +#define CHECK_RANGE(source) \ +{ \ + if (from_specified) \ + { \ + if (from < first || from > last) \ + { \ + warning(_("%s contains instruction range %llu .. %llu - using %llu as FROM"), \ + source, first, last, first); \ + gdb_flush(gdb_stderr); \ + from = first; \ + } \ + } \ + else \ + from = first; \ + \ + if (to_specified) \ + { \ + if (to < first || to > last) \ + { \ + warning(_("%s contains instruction range %llu .. %llu - using %llu as TO"), \ + source, first, last, last); \ + gdb_flush(gdb_stderr); \ + to = last; \ + } \ + } \ + else \ + to = last; \ +} + + +#define XISS_PROPERTY(key,value) xISS_functions->process_property(xiss_instance, key, value) + +#define IS_SUPPORTED(flag) ((xISS_functions->supports_feature(xiss_instance) & (flag)) != 0) + +#define XISS_AUX_REG(hw_regno) ((ARC_REG_TYPE) hw_regno + (ARC_REG_TYPE) AUX_BASE) +#define XISS_CORE_REG(hw_regno) ((ARC_REG_TYPE) hw_regno) + + +/* -------------------------------------------------------------------------- */ +/* local functions */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* 1) functions for watchpoint table */ +/* -------------------------------------------------------------------------- */ + +/* These functions implement a linear lookup table which associate an xISS + watchpoint cookie with the watchpoint's address, length and type; this is + not very efficient, but is quite sufficient for relatively small numbers of + watchpoints. If we should need to handle large numbers of watchpoints + efficiently, a more sophisticated data structure may be required. */ + + +/* Add an association to the table. */ + +static void +associate (WatchpointCookie cookie, CORE_ADDR addr, int length, int type) +{ + Association *new = NULL; + unsigned int i; + + for (i = 0; i < num_associations; i++) + { + Association *association = &associations[i]; + + if (association->cookie == NULL) + { + new = association; + break; + } + } + + if (new == NULL) + { + Association *new_associations = xrealloc(associations, sizeof(Association) * (num_associations + 1)); + + if (new_associations == NULL) + nomem(0); + + associations = new_associations; + new = &new_associations[num_associations]; + num_associations++; + } + + new->cookie = cookie; + new->addr = addr; + new->length = length; + new->type = type; +} + + +/* Remove an association from the table, returning the cookie. */ + +static WatchpointCookie +disassociate (CORE_ADDR addr, int length, int type) +{ + unsigned int i; + + for (i = 0; i < num_associations; i++) + { + Association *association = &associations[i]; + + if (association->addr == addr && + association->length == length && + association->type == type) + { + WatchpointCookie cookie = association->cookie; + + association->cookie = NULL; + return cookie; + } + } + + return NULL; +} + + +/* Find the address associated with a cookie. */ + +static CORE_ADDR +find (WatchpointCookie cookie) +{ + unsigned int i; + + for (i = 0; i < num_associations; i++) + { + Association *association = &associations[i]; + + if (association->cookie == cookie) + return association->addr; + } + + return 0; +} + + +/* -------------------------------------------------------------------------- */ +/* 2) functions for reading/writing registers */ +/* -------------------------------------------------------------------------- */ + +/* N.B. the register contents returned by these functions, or supplied to them, + are in host byte order - the arcint.cpp interface to the xISS requires + this. */ + +/* Read a core register on the target. + + Parameters: + hw_regno : the ARC hardware number of the register + value : set to the contents of the register + warn_on_failure: TRUE if a warning should be issued if the read fails + + Result: TRUE if the register contents are read. */ + +static Boolean +read_xiss_core_register (ARC_RegisterNumber hw_regno, + ARC_RegisterContents *contents, + Boolean warn_on_failure) +{ + unsigned long value; + int result = xISS_functions->read_reg(xiss_instance, XISS_CORE_REG(hw_regno), &value); + + if (result == 1) + { + *contents = (ARC_RegisterContents) value; + DEBUG("Read value 0x%08X from core register %d\n", *contents, hw_regno); + return TRUE; + } + + if (warn_on_failure) + arc_elf32_core_warning(ERROR_ON_READING_REGISTER, hw_regno); + return FALSE; +} + + +/* Write a core register on the target. + + Parameters: + hw_regno : the ARC hardware number of the register + value : set to the contents of the register + warn_on_failure: TRUE if a warning should be issued if the write fails + + Result: TRUE if the register contents are written. */ + +static Boolean +write_xiss_core_register (ARC_RegisterNumber hw_regno, + ARC_RegisterContents contents, + Boolean warn_on_failure) +{ + int result = xISS_functions->write_reg(xiss_instance, XISS_CORE_REG(hw_regno), (unsigned long) contents); + + if (result == 1) + { + DEBUG("Written value 0x%08X to core register %d\n", contents, hw_regno); + return TRUE; + } + + if (warn_on_failure) + arc_elf32_core_warning(ERROR_ON_WRITING_REGISTER, hw_regno); + return FALSE; +} + + +/* Read an auxiliary register on the target. + + Parameters: + hw_regno : the ARC hardware number of the register + value : set to the contents of the register + warn_on_failure: TRUE if a warning should be issued if the read fails + + Result: TRUE if the register contents are read. */ + +static Boolean +read_xiss_aux_register (ARC_RegisterNumber hw_regno, + ARC_RegisterContents *contents, + Boolean warn_on_failure) +{ + unsigned long value; + int result = xISS_functions->read_reg(xiss_instance, XISS_AUX_REG(hw_regno), &value); + + if (result == 1) + { + *contents = (ARC_RegisterContents) value; + DEBUG("Read value 0x%08X from auxiliary register %d\n", *contents, hw_regno); + return TRUE; + } + + if (warn_on_failure) + arc_elf32_aux_warning(ERROR_ON_READING_REGISTER, hw_regno); + return FALSE; +} + + +/* Write an auxiliary register on the target. + + Parameters: + hw_regno : the ARC hardware number of the register + value : the contents of the register + warn_on_failure: TRUE if a warning should be issued if the write fails + + Result: TRUE if the register contents are written. */ + +static Boolean +write_xiss_aux_register (ARC_RegisterNumber hw_regno, + ARC_RegisterContents contents, + Boolean warn_on_failure) +{ + ARC_AuxRegisterDefinition *def = arc_find_aux_register_by_hw_number(hw_regno); + int result; + + if (def) + contents = arc_write_value(def, contents); + + result = xISS_functions->write_reg(xiss_instance, XISS_AUX_REG(hw_regno), (unsigned long) contents); + + if (result == 1) + { + DEBUG("Written value 0x%08X to auxiliary register %d\n", contents, hw_regno); + return TRUE; + } + + if (warn_on_failure) + arc_elf32_aux_warning(ERROR_ON_WRITING_REGISTER, hw_regno); + return FALSE; +} + + +/* -------------------------------------------------------------------------- */ +/* 3) functions for reading/writing memory */ +/* -------------------------------------------------------------------------- */ + +/* These functions should NOT be used within this module: they are intended + purely for use by the arc-memory module for reading/writing multiple words + of data at word-aligned addresses. */ + +static unsigned int +read_words (ARC_Address address, + ARC_Byte *data, + unsigned int words) +{ + DEBUG("reading %u words from 0x%08X in xISS\n", words, address); + + gdb_assert(IS_WORD_ALIGNED(address)); + + return (unsigned int) xISS_functions->read_memory + (xiss_instance, + (unsigned long) address, + data, + (unsigned long) words * BYTES_IN_WORD, + XISS_CONTEXT); +} + + +static unsigned int +write_words (ARC_Address address, + ARC_Byte *data, + unsigned int words) +{ + gdb_assert(IS_WORD_ALIGNED(address)); + + DEBUG("writing %u words to 0x%08X in xISS\n", words, address); + + return (unsigned int) xISS_functions->write_memory + (xiss_instance, + (unsigned long) address, + data, + (unsigned long) words * BYTES_IN_WORD, + XISS_CONTEXT); +} + + +static unsigned int +write_pattern (ARC_Address address, + ARC_Word pattern, + unsigned int words) +{ + gdb_assert(IS_WORD_ALIGNED(address)); + + DEBUG("writing pattern 0x%08X repeated %u times to 0x%08X in xISS\n", pattern, words, address); + + return (unsigned int) xISS_functions->fill_memory + (xiss_instance, + (unsigned long) address, + &pattern, + BYTES_IN_WORD, + (unsigned int) words, + XISS_CONTEXT); +} + + +/* -------------------------------------------------------------------------- */ +/* 4) functions for xISS interface management */ +/* -------------------------------------------------------------------------- */ + +/* Open the interface to the debug target. + + Parameters: + systemfile: the .xis file defining the simulated target + from_tty : non-zero if the 'target' command was issued at the terminal +*/ + +static Boolean +open_xISS_interface (const char *systemfile, int from_tty) +{ + const char *xiss_home = getenv("XISS_HOME"); + char library[FILENAME_MAX]; + ARC_Interface arc_interface; + + if (xiss_home == NULL) + error(_("Environment variable XISS_HOME is not set")); + + /* Construct the path to the xISS .so file. */ + (void) snprintf(library, sizeof(library), "%s/lib/libxiss.so", xiss_home); + + /* Try to dynamically load the shared object library containing the xISS. */ + xISS_DLL_handle = dlopen(library, RTLD_LAZY); + + if (xISS_DLL_handle == NULL) + { + const char *diagnostic = dlerror(); + + if (strstr(diagnostic, library)) + error(_("Can not open xISS shared library %s"), diagnostic); + else + error(_("Can not open xISS shared library %s: %s"), library, diagnostic); + } + + /* Find the function in the library which will create an instacne of the xISS. */ + arc_interface = dlsym(xISS_DLL_handle, ARC_INTERFACE); + + if (arc_interface == NULL) + error(_("Can not find function %s in xISS shared library %s"), ARC_INTERFACE, library); + + /* Create an xISS instance. */ + xiss_instance = arc_interface(); + + if (xiss_instance == NULL) + error(_("Can not create instance of xISS")); + + /* Get a pointer to the table of functions provided by the interface. */ + xISS_functions = xiss_instance->pftp; + + DEBUG("xISS interface : %s\n", xISS_functions->id(xiss_instance)); + DEBUG("xISS interface version: %d\n", xISS_functions->version(xiss_instance)); + + /* Tell the xISS what system file to use to define the simulated target. */ + if (XISS_PROPERTY("xiss_sys", systemfile) != 1) + error(_("xISS could not process 'xiss_sys' property")); + + if (IS_SUPPORTED(ARC_FEATURE_fill_memory)) + operations.fill_memory = write_pattern; + + (void) xISS_functions->prepare_for_new_program(xiss_instance, 1); + + /* This is somewhat inelegant, but commands read from scripts in the gdb + testsuite are regarded as though they were being input interactively + (i.e. from_tty is 1), and interactive queries may be made (such as + asking the user whether the program currently being debugged should be + killed first) - and these queries hang the tests! + + So, if the environment variable is set, assume that the gdb test suite is + being run, so that no such queries will be made. + + It is not possible to make this check in the top-level command handler + loop, as the output from some other commands (e.g. 'file') depend on the + from_tty parameter passed to them, and the gdb test scripts expect to get + the interactive version of the output! */ + target_preopen(from_tty && (getenv("ARC_GDB_TEST") == NULL)); + + return TRUE; +} + + +/* Close the JTAG interface to the debug target. + + Parameter: + resume: TRUE if program execution on the target should be allowed to resume. */ + +static void +close_xISS_interface (Boolean resume) +{ + /* If we have a target connected. */ + if (xiss_instance != NULL) + { + /* It is meaningless to resume execution of the xISS. */ + arc_elf32_close(FALSE); + + /* If we are doing instruction tracing. */ + if (xiss_trace_file) + { + /* Ensure that the trace file is closed. */ + if (XISS_PROPERTY("trace_file", "") != 1) + error(_("xISS could not process 'trace_file' property")); + } + + /* Close the connection. */ + xISS_functions->destroy(xiss_instance); + + /* Close the library. */ + if (dlclose(xISS_DLL_handle) != 0) + warning(_("error on closing xISS shared library: %s"), dlerror()); + + xiss_instance = NULL; + xISS_functions = NULL; + xISS_DLL_handle = NULL; + } +} + + +/* -------------------------------------------------------------------------- */ +/* 5) functions for starting/stopping the processor */ +/* -------------------------------------------------------------------------- */ + +/* Run the xISS for whatever quantum of instructions that it executes. */ +static void +run_processor (void) +{ + int result = xISS_functions->run(xiss_instance); + + if (result == 0) + warning(_("could not run")); +} + + +/* -------------------------------------------------------------------------- */ +/* 6) local functions called from outside this module (from gdb) */ +/* -------------------------------------------------------------------------- */ + +/* Connect to the xISS target. + + Parameters: + args : user arguments to the 'target' command + from_tty: non-zero if the 'target' command was issued at the terminal + + The arguments may be: <XIS_system_file> + + If the name of a system file is not specified, a file 'default.xis' is + assumed. */ + +static void +arc_xISS_open (char *args, int from_tty) +{ + char *systemfile = (args) ? args : "default.xis"; + + ENTERARGS("\"%s\" (%d)", (args) ? args : "", from_tty); + + if (access(systemfile, R_OK) != 0) + { + char *file = getenv("XISS_SYSTEM_FILE"); + + if (file == NULL) + error(_("Invalid xISS system file '%s': %s"), systemfile, strerror(errno)); + else + if (access(file, R_OK) != 0) + error(_("Invalid xISS system file '%s': %s"), file, strerror(errno)); + else + systemfile = file; + } + + arc_program_is_loaded = FALSE; + + xISS_trace_instructions = FALSE; + xiss_trace_file = NULL; + xISS_executionStatus = XISS_HALTED; + xiss_trace_buffer_size = 0; + + num_associations = 0; + associations = NULL; + + /* Find any well-known aux register numbers that we will need. */ + arc_elf32_find_register_numbers(); + + /* Just to be sure that it is not in the target stack... */ + (void) unpush_target (&xISS_target_ops); + + /* Now try to open the xISS interface. */ + if (open_xISS_interface(systemfile, from_tty)) + { + (void) push_target (&xISS_target_ops); + + if (from_tty) + printf_filtered (_("Connected to the " ARC_TARGET_NAME " target.\n")); + } + else + error(_("Can not connect to target")); +} + + +/* Close the connection to the target. */ + +static void +arc_xISS_close (int quitting) /* Ignored. */ +{ + ENTERMSG; + + close_xISS_interface(FALSE); + + xfree(associations); + associations = NULL; + num_associations = 0; +} + + +/* Cause the inferior on the debug target to resume execution, sending a signal + if necessary. + + Parameters: + ptid : the thread id of the thread to be resumed (ignored) + step : 1 means single step, 0 run freely. + signal: the number of the signal to be sent + + N.B. signals are not supported. */ + +static void +arc_xISS_resume (ptid_t ptid, int step, enum target_signal signal) +{ + ENTERARGS("%d, %d, %d", ptid.pid, step, signal); + + if (signal != TARGET_SIGNAL_0) + error(_("Signals are not supported by the " ARC_TARGET_NAME " target")); + + if (step) + { + int result = xISS_functions->step(xiss_instance); + + if (result == 0) + error(_("Can not single-step")); + else + xISS_executionStatus = XISS_STEPPED; + } + else + xISS_executionStatus = XISS_TO_BE_RUN; + + LEAVEMSG; +} + + +/* Wait for execution on the target to halt (for whatever reason). + + Parameters : + ptid : ignored + status: set to indicate status at end of the wait +*/ + +static ptid_t +arc_xISS_wait (ptid_t ptid, struct target_waitstatus *status) +{ + ENTERARGS("xISS execution status: %d", xISS_executionStatus); + + /* What was done the last time that execution was resumed? */ + switch (xISS_executionStatus) + { + case XISS_STEPPED: + DEBUG("processor has stepped\n"); + status->kind = TARGET_WAITKIND_STOPPED; + status->value.sig = TARGET_SIGNAL_TRAP; + break; + + case XISS_TO_BE_RUN: + arc_elf32_execute(status, + run_processor, + NULL, + NULL); + + if (status->kind == TARGET_WAITKIND_EXITED) + target_mark_exited (&xISS_target_ops); + break; + + case XISS_HALTED: + break; + } + + LEAVEMSG; + + return inferior_ptid; +} + + +/* This gets called just before store_regs. */ + +static void +arc_xISS_prepare_to_store (struct regcache *regcache) +{ + ENTERMSG; +} + + +static void +arc_xISS_files_info (struct target_ops *target) +{ + /* Do nothing. */ + ENTERMSG; +} + + +/* Heavy duty arsenal. Kill the process. */ + +static void +arc_xISS_kill (void) +{ + ENTERMSG; + + target_mourn_inferior (); +} + + +/* Load the program into memory via the xISS interface. */ + +static void +arc_xISS_load (char *args, int from_tty) +{ + /* The program will be downloaded to the simulator. */ + (void) xISS_functions->prepare_for_new_program(xiss_instance, 1); + + arc_elf32_load_program(args, from_tty); + + /* Tell xISS that program is fully loaded. */ + if (XISS_PROPERTY("download_complete", "1") != 1) + error(_("xISS could not process 'download_complete' property")); + + /* We now have a program ready for execution on the target. */ +} + + +/* Create the inferior that will be executed upon the target. + + Parameters : + exec_file: the executable file containing the program to be executed + args : the command line arguments to be passed to the program + env : the environment (name/value pairs) for the program + from_tty : ignored + */ + +static void +arc_xISS_create_inferior (char *exec_file, char *args, char **env, int from_tty) +{ + arc_elf32_create_inferior(exec_file, args, env, &xISS_target_ops); +} + + +/* Mourn the inferior. */ + +static void +arc_xISS_mourn_inferior (void) +{ + ENTERMSG; + +// (void) unpush_target (&xISS_target_ops); + + /* N.B. we must delete all breakpoints from the target here: the gdb core + function generic_mourn_inferior marks all breakpoints as not being + inserted on the target, with the result that subsequent calls to + remove_breakpoints will NOT remove any breakpoints that are set on + the target; this means that if target execution is re-started, gdb + will attempt to re-insert the breakpoints, which causes a problem + with software breakpoints: the target insert_breakpoint function + reads the code at the b/p address (which is the s/w b/p instruction) + and saves it as the "overwritten" code - so when the breakpoint is + subsequently removed, the b/p instruction is written back to the + b/p address again! That is not what is desired... */ + (void) remove_breakpoints(); + generic_mourn_inferior(); + current_target.to_has_execution = 0; +} + + +/* Check whether the given thread is alive. */ + +static int +arc_xISS_thread_alive (ptid_t ptid) +{ + ENTERMSG; + + /* We only have one thread. */ + return 1; +} + + +/* Check whether our debug target is runnable: return 1 if it is, 0 otherwise. */ + +static int arc_xISS_can_run (void) +{ + /* If we are connected to the xISS i/f, and a program is loaded. */ + return (xiss_instance != NULL) && arc_program_is_loaded; +} + + +/* We do not support asynchronous execution of the target program (i.e. commands + like 'run' or 'continue' or 'step' can not be executed in background mode + by appending a '&' to them) so we do not need to implement the target stop + operation (called by the 'interrupt' command); interrupting a running program + is handled by the Ctrl-C mechanism. */ + +#if 0 +static void +arc_xISS_stop (void) +{ + ENTERMSG; +} +#endif + + +/* Check if we can set a "hardware" watchpoint of type TYPE. TYPE is + one of bp_hardware_watchpoint, bp_read_watchpoint, bp_write_watchpoint, or + bp_hardware_breakpoint. COUNT is the number of such watchpoints used so far + (including this one). OTHERTYPE is the total number of "hardware" breakpoints + and watchpoints of other types that are "already" set + (0 if type == bp_hardware_breakpoint). + + Result: 0 if hardware watchpoints are not supported + -1 if there are not enough hardware watchpoints + 1 if there are enough hardware watchpoints + + N.B. this is not what is stated in target.h, but it does conform to the use + made of this function's result in breakpoint.c! */ + +static int +arc_xISS_can_use_hw_breakpoint (int type, int count, int othertype) +{ + ENTERARGS("type %d, count %d", type, count); + + switch (type) + { + case bp_hardware_watchpoint: + case bp_read_watchpoint: + case bp_watchpoint: /* This means bp_write_watchpoint. */ + return 1; + case bp_hardware_breakpoint: + return 0; + default: + return 0; + } +} + + +/* Insert a "hardware" watchpoint on the target. + + Parameters: + addr : the start address of the region of memory to be watched + length: the length in bytes of the region of memory + type : 0 => write, 1 => read, 2 => read/write + + Returns 0 for success, -1 for failure. */ + +static int +arc_xISS_insert_watchpoint (CORE_ADDR addr, int length, int type) +{ + WatchpointCookie cookie; + unsigned int options; + + ENTERARGS("0x%08X:%d %d", (unsigned int) addr, length, type); + + gdb_assert(length > 0); + + switch (type) + { + case 0: + options = ARC_WATCHPOINT_write; + break; + case 1: + options = ARC_WATCHPOINT_read; + break; + case 2: + options = ARC_WATCHPOINT_read | ARC_WATCHPOINT_write; + break; + default: + internal_error (__FILE__, __LINE__, _("invalid watchpoint type: %d"), type); + } + + if (xISS_functions->set_mem_watchpoint2(xiss_instance, (unsigned long) addr, length, options, &cookie) == 1) + { + associate(cookie, addr, length, type); + return 0; + } + + return 1; +} + + +/* Remove a "hardware" watchpoint from the target. + + Parameters: + addr : the start address of the region of memory being watched + length: the length in bytes of the region of memory + type : 0 => write, 1 => read, 2 => read/write + + Returns 0 for success, non-zero for failure. */ + +static int +arc_xISS_remove_watchpoint (CORE_ADDR addr, int length, int type) +{ + WatchpointCookie cookie = disassociate(addr, length, type); + + ENTERARGS("0x%x:%d %d", (unsigned int) addr, length, type); + + if (cookie != NULL) + return (xISS_functions->remove_watchpoint(xiss_instance, cookie) == 1) ? 0 : 1; + return 1; +} + + +/* Returns non-zero if the execution of the target program has been stopped by + the trigger of a "hardware" watchpoint (i.e. on memory read or write), zero + otherwise. */ + +static int +arc_xISS_stopped_by_watchpoint (void) +{ + WatchpointCookie cookie; + + ENTERMSG; + + if (xISS_functions->stopped_at_watchpoint2(xiss_instance, &cookie) == 1) + { + /* Regrettably, the arcint i/f does not provide a well-defined means for + finding out the address of the data which was accessed - to do this + we have had to define a special property which returns the required + address! */ + int result = XISS_PROPERTY("watchpoint", "return_hit_address"); + + if (result == 0) + { + DEBUG("xISS could not process 'watchpoint/return_hit_address' property"); + + /* The most we can do now is retrieve the start address of the + watchpoint which was triggered... + N.B. we must retrieve the watchpoint address here, rather than in + the arc_xISS_stopped_data_address function, as gdb deletes + all breakpoint and watchpoints from the target as soon as + execution is halted, which removes the cookie from the table! */ + stopped_data_address = find(cookie); + } + else + stopped_data_address = (CORE_ADDR) result; + + return 1; + } + + return 0; +} + + +/* Get the address of the data that was read/written causing a h/w watchpoint to + trigger; the address is returned in the '*addr' parameter. + Returns 0 for failure, non-zero for success. */ + +static int +arc_xISS_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr) +{ + ENTERMSG; + + DEBUG("data addr: 0x%08X\n", (unsigned int) stopped_data_address); + *addr = stopped_data_address; + + return 1; +} + + +/* Can a h/w watchpoint 'length' bytes long be set at address 'addr' in target memory? */ + +static int +arc_xISS_region_ok_for_hw_watchpoint (CORE_ADDR addr, int length) +{ + /* As far as we know, we can set a h/w watchpoint anywhere. */ + return 1; +} + + +/* -------------------------------------------------------------------------- */ +/* 7) functions for instruction tracing */ +/* -------------------------------------------------------------------------- */ + +/* Display the instruction at the given address and ordinal position in the + instruction trace. */ + +static void +display_instruction (Ordinal ordinal, unsigned int address) +{ + /* N.B. must use fprintf_filtered here, rather than fprintf_unfiltered, as + gdb_print_insn calls fprintf_filtered, and if we mix the use of the + two we can get garbled output! */ + fprintf_filtered(gdb_stdout, "<0x%016llX> 0x%08X ", ordinal, address); + (void) gdb_print_insn((CORE_ADDR) address, gdb_stdout, NULL); + fprintf_filtered(gdb_stdout, "\n"); +} + + +/* Get the ordinal position of the first instruction in the trace buffer in the + sequence of executed instructions from the xISS; return 0 if this number cannot + be obtained. */ + +static Ordinal +get_instruction_trace_start (void) +{ + /* N.B. XISS_PROPERTY returns 0 if the property is not handled. */ + int start_low = XISS_PROPERTY("instruction_trace", "return_start_count_low"); + int start_high = XISS_PROPERTY("instruction_trace", "return_start_count_high"); + Ordinal start = ((Ordinal) start_high) << 32 | (Ordinal) start_low; + + DEBUG("get_instruction_trace_start : %llu\n", start); + + return start; +} + + +/* Encode the instruction trace buffer retrieved from the xISS: the buffer + 'trace' contains 'length' entries which are all PC values. The data is + recorded in the currently open trace file in a packed format. */ + +static void +encode_instruction_trace (unsigned int trace[], int length) +{ + unsigned int lastPC = trace[0]; + int i; + + /* Store the first entry in the buffer as an absolute address. */ + arc_encode_PC(ABSOLUTE_31_BITS, lastPC / 2); + + /* Look at all the remaining entries, comparing each with the previous one. */ + for (i = 1; i < length; i++) + { + unsigned int thisPC = trace[i]; + int delta = (int) thisPC - (int) lastPC; + + /* Encode the difference in the PC as a relative offset, if possible. + Offsets of 0 (branch to current address), 2, 4, 6 and 8 (instruction + sizes + optional immediate size) are handled as special cases. */ + + if (delta == 0) + arc_encode_PC(NO_CHANGE, 0); + else if (delta == 2) + arc_encode_PC(PLUS_16_BITS, 0); + else if (delta == 4) + arc_encode_PC(PLUS_32_BITS, 0); + else if (delta == 6) + arc_encode_PC(PLUS_48_BITS, 0); + else if (delta == 8) + arc_encode_PC(PLUS_64_BITS, 0); + else if (0 < delta && delta <= MAX_DELTA) + arc_encode_PC(DELTA_16_BIT_POSITIVE, ENCODE_DELTA(delta)); + else if (0 > delta && delta >= -MAX_DELTA) + arc_encode_PC(DELTA_16_BIT_NEGATIVE, ENCODE_DELTA(-delta)); + else + arc_encode_PC(ABSOLUTE_31_BITS, thisPC / 2); + + lastPC = thisPC; + } + + /* Useful tracing code: dump buffer as raw binary. */ +#if 0 + { + int binary = open("trace.binary", O_CREAT | O_WRONLY, 0666); + + if (binary == -1) + warning(_("could not open file trace.binary")); + else + { + (void) write(binary, trace, length * sizeof(unsigned int)); + (void) close(binary); + } + } +#endif +} + + +/* Decode the instruction trace buffer retrieved from a file. This is the inverse + of the encoding performed by the 'encode_instruction_trace' function. + The instruction at each PC value decoded is disassembled and displayed only if + its ordinal position in the trace is in the range given by the 'from' and 'to' + parameters. */ + +static void +decode_instruction_trace (Ordinal from, Ordinal to, Ordinal ordinal) +{ + ARC_ProgramCounterEncoding encoding; + unsigned int thisPC = 0; + unsigned int lastPC = 0; + unsigned int value; + + while (arc_decode_PC(&encoding, &value)) + { + switch (encoding) + { + case NO_CHANGE: + break; + case PLUS_16_BITS: + thisPC += 2; + break; + case PLUS_32_BITS: + thisPC += 4; + break; + case PLUS_48_BITS: + thisPC += 6; + break; + case PLUS_64_BITS: + thisPC += 8; + break; + case DELTA_16_BIT_POSITIVE: + thisPC += DECODE_DELTA(value); + break; + case DELTA_16_BIT_NEGATIVE: + thisPC -= DECODE_DELTA(value); + break; + case ABSOLUTE_31_BITS: + thisPC = value * 2; + break; + } + + if (from <= ordinal && ordinal <= to) + display_instruction(ordinal, thisPC); + + lastPC = thisPC; + ordinal++; + } +} + + +/* -------------------------------------------------------------------------- */ +/* 8) helper routines for added commands */ +/* -------------------------------------------------------------------------- */ + +/* Check that the xISS target is actually connected. */ + +static void +check_connected (void) +{ + if (xiss_instance == NULL) + error(_("Target " ARC_TARGET_NAME " is not connected")); +} + + +/* Set the size of the buffer to be used by the xISS for instruction trace data. */ + +static void +set_trace_buffer_size (int size) +{ + char sz[20]; + + (void) snprintf(sz, sizeof(sz), "%d", size); + + if (XISS_PROPERTY("trace_buffer_size", sz) != 1) + error(_("xISS could not process 'trace_buffer_size' property")); +} + + +/* Tell the xISS to switch instruction tracing on or off. */ + +static void +set_xiss_trace (char *args, + int from_tty, + struct cmd_list_element *e) +{ + check_connected(); + + if (XISS_PROPERTY("trace", (xISS_trace_instructions) ? "on" : "off") != 1) + error(_("xISS could not process 'trace' property")); +} + + +/* Show the status of xISS instruction tracing. */ + +static void +show_xiss_trace (struct ui_file *file, + int from_tty, + struct cmd_list_element *c, + const char *value) +{ + /* Value will be either "on" or "off". */ + fprintf_filtered(file, + _("xISS instruction tracing is %s.\n"), + value); +} + + +/* Tell the xISS to write the instruction trace to the file whose name is held + in the xiss_trace_file global variable. */ + +static void +set_xiss_trace_file (char *args, + int from_tty, + struct cmd_list_element *e) +{ + check_connected(); + + if (xiss_trace_file) + { + if (XISS_PROPERTY("trace_file", xiss_trace_file) != 1) + error(_("xISS could not process 'trace_file' property")); + } +} + + +/* Show the name of the trace file (if any) which is currently receiving + instruction tracing output from the xISS. */ + +static void +show_xiss_trace_file (struct ui_file *file, + int from_tty, + struct cmd_list_element *c, + const char *value) +{ + if (*value == '\0') + fprintf_filtered(file, + _("No output file is set for xISS instruction tracing.\n")); + else + fprintf_filtered(file, + _("The output file for xISS instruction tracing is '%s'.\n"), + value); +} + + +/* Set the size of the buffer used by the xISS for instruction trace data. */ + +static void +set_xiss_trace_buffer_size (char *args, + int from_tty, + struct cmd_list_element *e) +{ + check_connected(); + + if (xiss_trace_buffer_size < 0) + error(_("Trace buffer size must be non-negative")); + + set_trace_buffer_size(xiss_trace_buffer_size); +} + + +/* Show the size of the buffer used by the xISS for instruction trace data. */ + +static void +show_xiss_trace_buffer_size (struct ui_file *file, + int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered(file, + _("The buffer size for xISS instruction tracing is %s entries.\n"), + value); +} + + +/* -------------------------------------------------------------------------- */ +/* 9) local functions implementing commands */ +/* -------------------------------------------------------------------------- */ + +/* Command: <command> <filename> + + Save the contents of the xISS instruction trace buffer to the named file. + + We should eventually change this to use the ui_out stuff rather than + printf_filtered. */ + +static void +arc_save_trace_to_file_command (char *arg, int from_tty) +{ + int count; + + if (!arg) + { + printf_filtered (_(SAVE_TRACE_TO_FILE_COMMAND_USAGE)); + return; + } + + check_connected(); + + count = xISS_functions->instruction_trace_count(xiss_instance); + + if (count) + { + unsigned int *buffer; + + if (access(arg, F_OK) == 0) + if (!query(_("File already exists. Do you wish to overwrite it?"))) + return; + + printf_unfiltered(_("%u instructions in trace buffer\n"), count); + + buffer = xmalloc(count * sizeof(unsigned int)); + + if (buffer) + { + Ordinal first = get_instruction_trace_start(); + + xISS_functions->get_instruction_traces(xiss_instance, buffer); + + if (arc_start_encoding(arg, first)) + { + encode_instruction_trace(buffer, count); + arc_stop_encoding(first + (Ordinal) count - 1); + } + + xfree(buffer); + } + else + warning(_("can not allocate buffer to hold instruction trace data")); + } + else + warning(_("no instruction trace data available")); +} + + + +/* Command: <command> + + Discard the contents of the xISS instruction trace buffer. */ + +static void +arc_empty_trace_buffer (char *arg, int from_tty) +{ + if (arg) + { + printf_filtered (_(EMPTY_TRACE_BUFFER_COMMAND_USAGE)); + return; + } + + check_connected(); + + set_trace_buffer_size(0); + set_trace_buffer_size(xiss_trace_buffer_size); +} + + +/* Command: <command> [ FROM=<from> ] [ TO=<to> ] [ <FILE> ] + + Display some or all of the instruction trace, either from the xISS trace + buffer or from a named file. */ + +static void +arc_list_trace (char *arg, int from_tty) +{ + char *file = NULL; + Boolean from_specified = FALSE; + Boolean to_specified = FALSE; + Ordinal from = 0; + Ordinal to = 0; + Ordinal first; + Ordinal last; + + /* Do we have arguments to the command? */ + if (arg) + { + char **argv = buildargv (arg); + Boolean invalid = FALSE; + int i = 0; + + if (argv == NULL) + nomem (0); + + while (argv[i] != NULL) + { +// printf("argv[%d] = %s\n", i, argv[i]); + + GET_PARAMETER(from) + else + GET_PARAMETER(to) + else + { + /* Assume the argument is the file name. */ + file = xstrdup(argv[i]); + i++; + } + } + + freeargv(argv); + + if (invalid) + { + printf_filtered (_(LIST_TRACE_COMMAND_USAGE)); + return; + } + + DEBUG("FROM = %llu\n", from); + DEBUG("TO = %llu\n", to); + + if (from > to) + error("FROM (%lld) > TO (%lld)", from, to); + } + + /* If we must get the instruction trace from a file. */ + if (file) + { + /* Try to open the named file and start decoding its contents. */ + if (arc_start_decoding(file, &first, &last)) + { + CHECK_RANGE("file") + decode_instruction_trace(from, to, first); + arc_stop_decoding(); + } + + xfree(file); + } + else + { + unsigned int count; + + check_connected(); + + /* Get the number of entries in the xISS instruction trace buffer. */ + count = (unsigned int) xISS_functions->instruction_trace_count(xiss_instance); + + if (count > 0) + { + unsigned int *buffer = xmalloc(count * sizeof(unsigned int)); + + if (buffer) + { + Ordinal i; + + first = get_instruction_trace_start(); + last = first + (Ordinal) count - 1; + + CHECK_RANGE("trace buffer") + + /* Get the contents of the xISS instruction trace buffer. */ + xISS_functions->get_instruction_traces(xiss_instance, buffer); + + /* Display the required range of the trace. */ + for (i = from; i <= to; i++) + display_instruction(i, buffer[(int) (i - from)]); + + xfree(buffer); + } + else + warning(_("can not allocate buffer to hold instruction trace data")); + } + else + warning(_("no instruction trace data available")); + } +} + + +/* -------------------------------------------------------------------------- */ +/* 10) initialization functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize the xISS target operations. */ + +static void +initialize_xISS_target_ops (void) +{ + ENTERMSG; + + xISS_target_ops.to_data = &operations; + + xISS_target_ops.to_shortname = ARC_TARGET_NAME; + xISS_target_ops.to_longname = "xISS debug target (ARC Processors)"; + xISS_target_ops.to_doc = "xISS (Fast Instruction Set Simulator) debug target (ARC Processors)"; + + xISS_target_ops.to_open = arc_xISS_open; + xISS_target_ops.to_close = arc_xISS_close; + xISS_target_ops.to_resume = arc_xISS_resume; + xISS_target_ops.to_wait = arc_xISS_wait; + + xISS_target_ops.to_fetch_registers = arc_elf32_fetch_registers; + xISS_target_ops.to_store_registers = arc_elf32_store_registers; + xISS_target_ops.to_prepare_to_store = arc_xISS_prepare_to_store; + xISS_target_ops.to_xfer_partial = arc_elf32_xfer_partial; + xISS_target_ops.to_files_info = arc_xISS_files_info; + + xISS_target_ops.to_can_use_hw_breakpoint = arc_xISS_can_use_hw_breakpoint; +// xISS_target_ops.to_insert_hw_breakpoint = arc_xISS_insert_hw_breakpoint; +// xISS_target_ops.to_remove_hw_breakpoint = arc_xISS_remove_hw_breakpoint; + xISS_target_ops.to_insert_watchpoint = arc_xISS_insert_watchpoint; + xISS_target_ops.to_remove_watchpoint = arc_xISS_remove_watchpoint; + xISS_target_ops.to_stopped_by_watchpoint = arc_xISS_stopped_by_watchpoint; + xISS_target_ops.to_stopped_data_address = arc_xISS_stopped_data_address; + xISS_target_ops.to_region_ok_for_hw_watchpoint = arc_xISS_region_ok_for_hw_watchpoint; + + xISS_target_ops.to_insert_breakpoint = arc_elf32_insert_breakpoint; + xISS_target_ops.to_remove_breakpoint = arc_elf32_remove_breakpoint; + + xISS_target_ops.to_kill = arc_xISS_kill; + xISS_target_ops.to_load = arc_xISS_load; + + xISS_target_ops.to_create_inferior = arc_xISS_create_inferior; + xISS_target_ops.to_mourn_inferior = arc_xISS_mourn_inferior; + xISS_target_ops.to_thread_alive = arc_xISS_thread_alive; +// xISS_target_ops.to_stop = arc_xISS_stop; + xISS_target_ops.to_can_run = arc_xISS_can_run; + xISS_target_ops.to_terminal_inferior = NULL; + + xISS_target_ops.to_stratum = process_stratum; + + xISS_target_ops.to_has_all_memory = 1; + xISS_target_ops.to_has_memory = 1; + xISS_target_ops.to_has_stack = 0; /* Defer setting this until the program has been loaded. */ + xISS_target_ops.to_has_registers = 1; + xISS_target_ops.to_has_execution = 0; /* Defer setting this until the program has been started. */ + + xISS_target_ops.to_magic = OPS_MAGIC; +} +#endif /* HAVE_LIBXISS */ + + +/* -------------------------------------------------------------------------- */ +/* externally visible functions */ +/* -------------------------------------------------------------------------- */ + +/* Initialize the module. This function is called from the gdb core on start-up. */ + +/* N.B. the initialization function must be defined even if the rest of this + module is excluded, as the call to it from the gdb start-up code is + generated by the build mechanism without regard to any conditional + compilation! */ + +void +_initialize_arc_xiss (void) +{ +#ifdef HAVE_LIBXISS + struct cmd_list_element *cmnd; + + ENTERMSG; + + operations.read_core_register = read_xiss_core_register; + operations.write_core_register = write_xiss_core_register; + operations.read_auxiliary_register = read_xiss_aux_register; + operations.write_auxiliary_register = write_xiss_aux_register; + operations.read_memory = read_words; + operations.write_memory = write_words; + operations.fill_memory = NULL; + + initialize_xISS_target_ops (); + add_target (&xISS_target_ops); + + /* Register ARC-specific commands with gdb. */ + + (void) add_setshow_boolean_cmd + ("arc-xiss-trace", + class_trace, + &xISS_trace_instructions, + _("Set whether the xISS should trace instructions.\n"), + _("Show whether the xISS should trace instructions.\n"), + NULL, + set_xiss_trace, + show_xiss_trace, + &setlist, + &showlist); + + add_setshow_optional_filename_cmd + ("arc-xiss-trace-file", + class_trace, + &xiss_trace_file, + _("Set the output file for xISS instruction tracing.\n"), + _("Show the output file for xISS instruction tracing.\n"), + NULL, + set_xiss_trace_file, + show_xiss_trace_file, + &setlist, + &showlist); + + (void) add_setshow_zinteger_cmd + ("arc-xiss-trace-buffer-size", + class_trace, + &xiss_trace_buffer_size, + _("Set the size of the trace buffer for xISS instruction tracing.\n"), + _("Show the size of the trace buffer for xISS instruction tracing.\n"), + NULL, + set_xiss_trace_buffer_size, + show_xiss_trace_buffer_size, + &setlist, + &showlist); + + cmnd = add_cmd + (SAVE_TRACE_TO_FILE_COMMAND, + class_trace, + arc_save_trace_to_file_command, + _("Save the contents of the xISS instruction trace buffer to a file.\n" + SAVE_TRACE_TO_FILE_COMMAND_USAGE + "<FILE> is a file to hold the xISS instruction trace buffer contents.\n"), + &cmdlist); + set_cmd_completer (cmnd, filename_completer); + + (void) add_cmd + (EMPTY_TRACE_BUFFER_COMMAND, + class_trace, + arc_empty_trace_buffer, + _("Empty xISS instruction trace buffer.\n" + EMPTY_TRACE_BUFFER_COMMAND_USAGE), + &cmdlist); + + cmnd = add_cmd + (LIST_TRACE_COMMAND, + class_trace, + arc_list_trace, + _("Display xISS instruction trace.\n" + LIST_TRACE_COMMAND_USAGE), + &cmdlist); + set_cmd_completer (cmnd, filename_completer); + +#endif /* HAVE_LIBXISS */ +} + +/******************************************************************************/ |