summaryrefslogtreecommitdiff
path: root/sim/arc/sim-if.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/arc/sim-if.c')
-rw-r--r--sim/arc/sim-if.c883
1 files changed, 648 insertions, 235 deletions
diff --git a/sim/arc/sim-if.c b/sim/arc/sim-if.c
index be4d99eccbe..4c5433daddc 100644
--- a/sim/arc/sim-if.c
+++ b/sim/arc/sim-if.c
@@ -1,6 +1,6 @@
/* Main simulator entry points specific to the ARC.
- Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
This file is part of GDB, the GNU debugger.
@@ -18,10 +18,144 @@
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include "sim-main.h"
-#include "sim-options.h"
-#include "libiberty.h"
-#include "bfd.h"
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This module provides operations to: */
+/* */
+/* 1) create an "instance" of the ARC simulator */
+/* 2) destroy an "instance" of the ARC simulator */
+/* 3) create an "inferior" to run on the simulator */
+/* 4) execute a simulator-related command */
+/* */
+/* N.B. there can be only one simulator instance at a time because of the */
+/* use of the current_state global variable. */
+/* */
+/* This module is also responsible for setting up the "command line" */
+/* arguments and environment (name/value pairs) to be passed to the */
+/* program that is to be debugged. This data is passed on the stack above */
+/* the top of stack as it is known to the program. */
+/* */
+/* E.g. if we are passing 4 arguments to main, we must place the data on */
+/* the stack as: */
+/* */
+/* . */
+/* . */
+/* stack[top + A3] <== <arg_3> */
+/* . */
+/* . */
+/* stack[top + A2] <== <arg_2> */
+/* . */
+/* . */
+/* stack[top + A1] <== <arg_1> */
+/* . */
+/* . */
+/* stack[top + A0] <== <arg_0> */
+/* stack[top + 28] <== 0x0 # ? NULL terminator */
+/* stack[top + 24] <== 0x0 # envp NULL terminator */
+/* stack[top + 20] <== 0x0 # argv NULL terminator */
+/* stack[top + 16] <== TOP + A3 # argv[3] */
+/* stack[top + 12] <== TOP + A2 # argv[2] */
+/* stack[top + 8] <== TOP + A1 # argv[1] */
+/* stack[top + 4] <== TOP + A0 # argv[0] */
+/* stack[top ] <== 0x4 # argc */
+/* */
+/* where TOP = &stack[top] */
+/* and A0 .. A3 are the offsets of the stored arguments from the stack */
+/* top. */
+/* */
+/* */
+/* Notes: */
+/* The interface to this module is somewhat muddled: both sim_open and */
+/* sim_create_inferior have a BFD parameter which denotes the executable */
+/* file which is to be run; but for sim_open this parameter may be NULL. */
+/* */
+/* Also, both sim_open and sim_create_inferior have an argv parameter, */
+/* but for sim_open *some* of the strings in this array parameter may be */
+/* command-line arguments to be passed to the program to be executed, */
+/* whilst the others are arguments for the simulator itself; but for */
+/* sim_create_inferior, *all* of the strings (if any) in this parameter */
+/* are such command-line arguments. */
+/* */
+/* Finally, sim_create_inferior has an envp parameter which holds a set */
+/* of name/value pairs to be passed as the environment of the executed */
+/* program, whereas sim_open does not; but this is not (currently) done. */
+/* */
+/* */
+/* This complexity arises from the variety of ways in which a simulator */
+/* instance may be created and used: */
+/* */
+/* a) the instance may be created by gdb before the executable file is */
+/* known; e.g. the user may issue the commands */
+/* */
+/* set endian big | little */
+/* target sim */
+/* file <executable> */
+/* load */
+/* run */
+/* */
+/* and in this case the BFD parameter to sim_open is NULL, and its */
+/* argv parameter does not hold the executable's arguments; */
+/* */
+/* b) the instance may be created by gdb after the executable file is */
+/* known; e.g. the user may issue the commands */
+/* */
+/* file <executable> */
+/* target sim */
+/* load */
+/* run */
+/* */
+/* and in this case the BFD parameter to sim_open is non-NULL, and */
+/* its argv parameter does not hold the executable's arguments; */
+/* */
+/* c) the instance may be created by a standalone executable; e.g. */
+/* known; e.g. the user may issue the command */
+/* */
+/* run <executable> [ <arg1> .. <argN> ] */
+/* */
+/* and in this case the BFD parameter to sim_open is non-NULL, and */
+/* its argv parameter does hold the executable's arguments. */
+/* */
+/* Note that in each case, the argv parameter to sim_create_inferior */
+/* holds the command-line arguments for the executable (so, there is */
+/* apparently no need for them to be passed in the sim_open argv also!). */
+/* */
+/* The arguments to the executed program may also be specified in several */
+/* ways; e.g by use of the gdb 'set args' command, or as arguments to the */
+/* gdb 'run' command; or, in the case of a standalone executable, on the */
+/* command line. */
+/* */
+/* Note that the executable program can be run (by gdb) repeatedly with */
+/* different argument lists, i.e. there may be multiple calls of */
+/* sim_create_inferior after a call of sim_open; and each of these lists */
+/* may require a different amount of memory to hold them on the stack. */
+/* */
+/* */
+/* It is necessary to define a memory region with a particular start */
+/* address and size in the simulator memory (all accesses outside this */
+/* address range by the executed program are erroneous, thus allowing */
+/* invalid accesses to be detected); this region must include the program */
+/* text, (un)initialized data, heap and stack. This must also include */
+/* the argument/environment data which is passed above the top of the */
+/* stack. */
+/* */
+/* If the executable file is known (i.e. we have a non-NULL BFD), */
+/* the bounds of the memory region required for the program may be */
+/* extracted from the section header information in the file; if the */
+/* arguments/environment are known, the space required to hold them on */
+/* the stack may be computed. This allows the total space to be computed, */
+/* and so a memory region holding it may be defined. */
+/* */
+/* However, if a subsequent execution of the program should require a */
+/* greater total space (because its arguments have changed) it is then */
+/* necessary to define an additional memory region to provide the extra */
+/* space; it is not possible to redefine the existing region, or a new */
+/* region of the new size (as memory regions may not overlap). */
+/* */
+/******************************************************************************/
+
+/* system header files */
#ifdef HAVE_STRING_H
#include <string.h>
@@ -34,13 +168,53 @@
#include <stdlib.h>
#endif
-static void free_state (SIM_DESC);
-static void print_arc_misc_cpu (SIM_CPU *cpu, int verbose);
+/* simulator / binutils header files */
+
+#include "sim-main.h"
+#include "sim-options.h"
+#include "libiberty.h"
+#include "bfd.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* conditional compilation flags */
+/* -------------------------------------------------------------------------- */
-/* Records simulator descriptor so utilities like arc_dump_regs can be
- called from gdb. */
+//#define LOGGING
+//#define PUSH_ENVIRONMENT_ONTO_STACK
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible data */
+/* -------------------------------------------------------------------------- */
+
+/* Records simulator descriptor so utilities like arc_dump_regs can be called
+ from gdb. */
SIM_DESC current_state;
-
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define DEFAULT_ENVIRONMENT_SPACE 2048
+
+#define TARGET_POINTER_SIZE 4
+#define TARGET_INT_SIZE 4
+
+
+/* -------------------------------------------------------------------------- */
+/* local macros */
+/* -------------------------------------------------------------------------- */
+
+#define IS_LITTLE_ENDIAN(abfd) (abfd) ? bfd_little_endian (abfd) \
+ : (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
/* Cover function of sim_state_free to free the cpu buffers as well. */
static void
@@ -52,158 +226,334 @@ free_state (SIM_DESC sd)
sim_state_free (sd);
}
-/* Find out heap and stack end boundaries, and return required memory
- size; if this cannot be calcualted, return DEFAULT_MEMSIZE.
- If INIT_P is nonzero, initialize memory above the stack with argv and envp.
- If this initialization fails, return 0. */
+
+/* PROFILE_CPU_CALLBACK */
+
+static void
+print_arc_misc_cpu (SIM_CPU *cpu, int verbose)
+{
+ if (CPU_PROFILE_FLAGS (cpu) [PROFILE_INSN_IDX])
+ {
+ SIM_DESC sd = CPU_STATE (cpu);
+ char buf[20];
+
+ sim_io_printf (sd, "Miscellaneous Statistics\n\n");
+ sim_io_printf (sd, " %-*s %s\n\n",
+ PROFILE_LABEL_WIDTH, "Fill nops:",
+ sim_add_commas (buf, sizeof (buf),
+ CPU_ARC_MISC_PROFILE (cpu)->fillnop_count));
+ }
+}
+
+
+#ifdef LOGGING
+static void
+dump (SIM_DESC sd, char** argv, char** envp)
+{
+ char **cpp, **rpp;
+ char* tag;
+ int cnt;
+
+ for (cpp = argv, tag = "argv", cnt = 2; cnt--; cpp = envp, tag = "env")
+ {
+ if (cpp)
+ {
+ int i = 0;
+
+ for (rpp = cpp; *rpp; rpp++, i++)
+ sim_io_eprintf(sd, "%s[%d] = %s\n", tag, i, *rpp);
+ }
+ }
+}
+#endif
+
+/* Setup copy arguments / environment to the stack area of SD according
+ to argv and envp. Either or both of argv and envp may be NULL.
+ Return 0 on failure, nonzero on success. */
+
static int
-init_stack (struct bfd *abfd, char **argv,
- SIM_DESC sd, int default_memsize, int init_p)
+setup_stack (SIM_DESC sd, int little_endian_p, char** argv, char** envp)
{
- USI stack_start = 0, stack_top = 0, heap_start = 0, heap_end = 0;
- USI prog_end = 0;
- char *null_env = NULL;
- char **envp = &null_env;
- int argc;
- char **cpp, **rpp, *str;
- size_t len;
- int cp, wpp;
- int n_ptr = 0, cnt;
- /* All CPUs have the same memory map, apparently. */
- SIM_CPU *cpu = STATE_CPU (sd, 0);
- bfd_byte buf[4];
+ SIM_CPU* cpu = STATE_CPU (sd, 0);
+ int wpp = sd->memory.stack_top + TARGET_INT_SIZE;
+ int cp = sd->memory.argument_data_start;
+ int count;
+ char** cpp;
+
+#ifdef LOGGING
+ sim_io_eprintf(sd, "setup stack (%c/E) %d args\n",
+ (little_endian_p) ? 'L' : 'B',
+ sd->memory.num_arguments);
+ dump(sd, argv, envp);
+#endif
+
+ if (sd->memory.stack_top <= sd->memory.stack_start)
+ {
+ host_callback *callback = STATE_CALLBACK (sd);
+
+ (*callback->printf_filtered) (callback, "stack overflow\n");
+ return 0;
+ }
+
+ /* Can't use sim_core_write_unaligned_4 without everything
+ initialized when tracing, and then these writes would get into
+ the trace. */
+#define write_dword(addr, data) \
+ do \
+ { \
+ bfd_byte buf[4]; \
+ USI data_ = data; \
+ USI addr_ = addr; \
+ if (little_endian_p) \
+ bfd_putl32 (data_, buf); \
+ else \
+ bfd_putb32 (data_, buf); \
+ if (sim_core_write_buffer (sd, cpu, 0, buf, addr_, 4) != 4) \
+ { \
+ sim_io_eprintf(sd, "failed to write word to address 0x%x\n", addr);\
+ return 0; \
+ } \
+ } \
+ while (0)
+
+
+ /* Push the arguments and environment onto the stack. */
+
+ write_dword (sd->memory.stack_top, sd->memory.num_arguments);
+ for (cpp = argv, count = 2; count--; cpp = envp)
+ {
+ if (cpp)
+ {
+ char* argument;
+ char** rpp;
+
+ for (rpp = cpp; (argument = *cpp); cpp++)
+ {
+ size_t len = strlen(argument) + 1;
+
+#ifdef LOGGING
+ sim_io_eprintf(sd, "pushing argument '%s' onto program stack at address 0x%x\n", argument, cp);
+#endif
+
+ if (sim_core_write_buffer (sd, cpu, 0, argument, cp, len) != len)
+ {
+ sim_io_eprintf(sd, "could not push argument '%s' onto program stack at address 0x%x\n", argument, cp);
+ return 0;
+ }
+ write_dword (wpp, cp);
+ cp += len;
+ wpp += TARGET_POINTER_SIZE;
+ }
+ }
+
+ write_dword (wpp, 0); // NULL array terminator
+ wpp += TARGET_POINTER_SIZE;
+
+ }
+ write_dword (wpp, 0); /* uClibc aux_dat NULL terminator. */
+ /* success */
+ return 1;
+}
+
+
+/* Find out heap and stack end boundaries, and calculate required memory size;
+ if this cannot be done, use the default memory size.
+ ABFD, ARGV and/or ENVP may be NULL.
+ If this calculation fails, return 0. */
+
+static int
+determine_memory_requirements (SIM_DESC sd, struct bfd *abfd, char **argv,
+ char **envp, struct sim_memory* memory)
+{
+ USI stack_start = 0, stack_top = 0, heap_start = 0, heap_end = 0;
+ USI program_end = 0;
+ USI memory_size;
+ USI data_start;
+ int argc = 0;
+ size_t total_argument_length = 0;
+ int num_pointers = 0;
+
+ /* N.B. the *_end variables actually denote the next byte after the end of
+ the sections to which they refer; however, they are used consistently
+ in this way, so that is not a problem! */
+
+ /* If we have an executable file to look at. */
if (abfd)
{
- asection *s;
-
- for (s = abfd->sections; s; s = s->next)
- if (strcmp (bfd_get_section_name (abfd, s), ".stack") == 0)
- {
- stack_start = bfd_get_section_vma (abfd, s);
- stack_top = stack_start + bfd_section_size (abfd, s);
- stack_top &= -4; /* 4 == target pointer size */
- default_memsize = stack_top;
- }
- else if (strcmp (bfd_get_section_name (abfd, s), ".heap") == 0)
- {
- heap_start = bfd_get_section_vma (abfd, s);
- heap_end = heap_start + bfd_section_size (abfd, s);
- }
- else
- {
- USI s_end
- = bfd_get_section_vma (abfd, s) + bfd_section_size (abfd, s);
-
- if (prog_end < s_end)
- prog_end = s_end;
- }
- if (heap_end == 0)
- {
- if (prog_end > stack_start)
- return 0;
- heap_start = prog_end;
- heap_end = stack_start;
- }
- if (!argv)
- n_ptr == 1;
- else
+ asection* section;
+
+ /* Look at each section in the file. */
+ for (section = abfd->sections; section; section = section->next)
+ {
+ if (strcmp (bfd_get_section_name (abfd, section), ".stack") == 0)
+ {
+ stack_start = bfd_get_section_vma (abfd, section);
+ stack_top = stack_start + bfd_section_size (abfd, section);
+ stack_top &= -TARGET_POINTER_SIZE;
+
+ /* N.B. this assumes that the target memory region to be
+ created has the range 0 .. stack_top - 1, i.e. that there
+ is nothing in the program that has to be loaded at
+ addresses above the stack top. */
+ memory_size = stack_top;
+ }
+ else if (strcmp (bfd_get_section_name (abfd, section), ".heap") == 0)
+ {
+ heap_start = bfd_get_section_vma (abfd, section);
+ heap_end = heap_start + bfd_section_size (abfd, section);
+ }
+ else if (bfd_get_section_flags(abfd, section) & SEC_LOAD)
+ {
+ USI section_end = bfd_get_section_vma (abfd, section) +
+ bfd_section_size (abfd, section);
+
+ /* Keep track of the end address of whatever else is to be
+ loaded. */
+ if (program_end < section_end)
+ program_end = section_end;
+ }
+ }
+
+ /* If we know the start of the stack, check for an overlap. */
+ if (stack_start > 0 && program_end > stack_start)
{
- for (cpp = envp, len = 0, cnt = 2; cnt--; cpp = argv)
- {
- argc = 0;
- for (rpp = cpp; *rpp; rpp++)
- argc++, len += strlen (*rpp) + 1;
- n_ptr += argc + 1;
- }
+ sim_io_eprintf(sd,
+ "program data overlaps program stack at 0x%x (0x%x)\n",
+ stack_start, program_end);
+ return 0;
}
- n_ptr ++; //* For uclibc aux_dat */
- if (!stack_top)
- stack_top = (default_memsize + 3) & -4; /* 4 == target pointer size */
- wpp = stack_top + 4;
- cp = wpp + n_ptr * 4;
- default_memsize = cp + len;
- /* Round up to multiple of 32. strlen expects memory to come in chunks
- that are at least cache-line (32 bytes) sized. */
- default_memsize += 31;
- default_memsize &= -32;
+
+ /* No heap section found? */
+ if (heap_end == 0)
+ {
+ /* Assume the heap lies between the program data and the stack. */
+ heap_start = program_end;
+ heap_end = stack_start;
+ }
}
- if (abfd && init_p)
+
+
+ /* If we have arguments or environment variables to pass to the program. */
+
+ if (argv)
{
- int little_endian_p = bfd_little_endian (abfd);
+ char **rpp;
- if (stack_top <= stack_start)
- {
- host_callback *callback = STATE_CALLBACK (sd);
+ for (rpp = argv; *rpp; rpp++, num_pointers++)
+ total_argument_length += strlen (*rpp) + 1;
- (*callback->printf_filtered) (callback, "stack overflow\n");
- return 0;
- }
+ argc = num_pointers;
+ }
+ num_pointers++; /* For NULL terminator. */
- /* Can't use sim_core_write_unaligned_4 without everything
- initialized when tracing, and then these writes would get into
- the trace. */
-#define write_dword(addr, data) \
- do \
- { \
- USI data_ = data; \
- USI addr_ = addr; \
- if (little_endian_p) \
- bfd_putl32 (data_, buf); \
- else \
- bfd_putb32 (data_, buf); \
- if (sim_core_write_buffer (sd, cpu, 0, buf, addr_, 4) != 4) \
- return 0; \
- } \
- while (0)
+ if (envp)
+ {
+ char** rpp;
- write_dword (stack_top, argc);
- for (cpp = argv, cnt = 2; cnt--; cpp = envp)
- {
- for (rpp = cpp; str = *cpp++;)
- {
- len = strlen (str) + 1;
- if (sim_core_write_buffer (sd, cpu, 0, str, cp, len) != len)
- return 0;
- write_dword (wpp, cp);
- cp += len;
- wpp += 4;
- }
- write_dword (wpp, 0);
- wpp += 4;
- }
- write_dword (wpp, 0);
- sd->heap_start = heap_start;
- sd->heap_end = heap_end;
- sd->stack_top = stack_top;
+ for (rpp = envp; *rpp; rpp++, num_pointers++)
+ total_argument_length += strlen (*rpp) + 1;
+ }
+ num_pointers++; /* For NULL terminator. */
+
+ num_pointers++; /* For uclibc aux_dat. */
+
+ /* If we could not get the stack bounds from the executable file (and hence
+ do not know the memory size), use the default memory size and take the
+ top of the stack as being at the end of that memory range (aligned to
+ the size of a target pointer). */
+ if (!stack_top)
+ stack_top = (USI) ((ARC_DEFAULT_MEM_SIZE + 3) & -TARGET_POINTER_SIZE);
+
+ data_start = (USI) (stack_top +
+ TARGET_INT_SIZE + /* For argc. */
+ num_pointers * TARGET_POINTER_SIZE);
+
+ /* We need enough memory to hold the program stack, plus the data to be passed
+ above the top of the stack. */
+ memory_size = (USI) (data_start + total_argument_length);
+
+#ifdef PUSH_ENVIRONMENT_ONTO_STACK
+ if (!envp)
+ memory_size += DEFAULT_ENVIRONMENT_SPACE;
+#endif
+
+ /* Round up to multiple of 32: strlen expects memory to come in chunks
+ that are at least cache-line (32 bytes) sized.
+ FIXME: is that true? */
+ memory_size += 31;
+ memory_size &= -32;
+
+ memory->heap_start = heap_start;
+ memory->heap_end = heap_end;
+ memory->stack_top = stack_top;
+ memory->stack_start = stack_start;
+ memory->total_size = memory_size;
+ memory->argument_data_start = data_start;
+ memory->num_arguments = (USI) argc;
+
+#ifdef LOGGING
+ sim_io_eprintf(sd, "heap start : 0x%x\n", heap_start);
+ sim_io_eprintf(sd, "heap end : 0x%x\n", heap_end);
+ sim_io_eprintf(sd, "stack start : 0x%x\n", stack_start);
+ sim_io_eprintf(sd, "stack top : 0x%x\n", stack_top);
+ sim_io_eprintf(sd, "memory size : 0x%x\n", memory_size);
+ sim_io_eprintf(sd, "arg data start: 0x%x\n", data_start);
+ sim_io_eprintf(sd, "%d args\n", argc);
+#endif
+
+ /* Success. */
+ return 1;
+}
+
+
+static void
+define_memory_region (SIM_DESC sd, USI start, USI size)
+{
+ /* Allocate core managed memory if none specified by user. */
+ if (!sd->memory_regions_defined_by_user)
+ {
+#ifdef LOGGING
+ sim_io_printf (sd, "memory region 0x%x,0x%x\n", start, size);
+#endif
+ sim_do_commandf (sd, "memory region 0x%x,0x%x", start, size);
}
- return default_memsize;
}
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
/* Create an instance of the simulator. */
SIM_DESC
-sim_open (kind, callback, abfd, argv)
- SIM_OPEN_KIND kind;
- host_callback *callback;
- struct bfd *abfd;
- char **argv;
+sim_open (SIM_OPEN_KIND kind,
+ host_callback *callback,
+ struct bfd *abfd, /* May be NULL. */
+ char **argv)
{
SIM_DESC sd = sim_state_alloc (kind, callback);
- char c;
- int i;
- int default_memsize;
- char ** prog_argv;
+ int little_endian_p;
+ char** prog_argv;
+ char c;
- /* The cpu data is kept in a separately allocated chunk of memory. */
+ SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+#ifdef LOGGING
+ sim_io_eprintf (sd, "sim_open: %p\n", abfd);
+ dump(sd, argv, NULL);
+#endif
+
+ /* The cpu data is kept in a separately-allocated chunk of memory. */
if (sim_cpu_alloc_all (sd, 1, cgen_cpu_max_extra_bytes ()) != SIM_RC_OK)
{
free_state (sd);
return 0;
}
-#if 0 /* FIXME: pc is in mach-specific struct */
- /* FIXME: watchpoints code shouldn't need this */
+#if 0 /* FIXME: pc is in mach-specific struct. */
+ /* FIXME: watchpoints code shouldn't need this. */
{
SIM_CPU *current_cpu = STATE_CPU (sd, 0);
STATE_WATCHPOINTS (sd)->pc = &(PC);
@@ -217,7 +567,7 @@ sim_open (kind, callback, abfd, argv)
return 0;
}
-#ifdef HAVE_DV_SOCKSER /* FIXME: was done differently before */
+#ifdef HAVE_DV_SOCKSER /* FIXME: was done differently before. */
if (dv_sockser_install (sd) != SIM_RC_OK)
{
free_state (sd);
@@ -225,7 +575,7 @@ sim_open (kind, callback, abfd, argv)
}
#endif
-#if 0 /* FIXME: 'twould be nice if we could do this */
+#if 0 /* FIXME: 'twould be nice if we could do this. */
/* These options override any module options.
Obviously ambiguity should be avoided, however the caller may wish to
augment the meaning of an option. */
@@ -242,6 +592,11 @@ sim_open (kind, callback, abfd, argv)
return 0;
}
+#ifdef LOGGING
+ /* sim_parse_args may set up STATE_PROG_ARGV(sd), in the case that kind == SIM_OPEN_STANDALONE. */
+ dump(sd, STATE_PROG_ARGV (sd), NULL);
+#endif
+
/* Check for/establish the reference program image, and set arch info. */
if (sim_analyze_program (sd,
(STATE_PROG_ARGV (sd) != NULL
@@ -254,18 +609,17 @@ sim_open (kind, callback, abfd, argv)
}
prog_argv = STATE_PROG_ARGV (sd);
+
+ /* If we have not been given an executable file. */
if (!abfd)
{
- char *name;
-
- /* FIXME: If the test below fails, we will use ARC_DEFAULT_MEMSIZE.
- We should have some way to remember this, so that we can
- emit an error in sim_create_inferior if the required memory
- size is larger. */
+ /* If the test below fails, we will use ARC_DEFAULT_MEM_SIZE. */
if (prog_argv != NULL && *prog_argv != NULL)
{
- name = *prog_argv;
+ char* name = *prog_argv;
+
abfd = bfd_openr (name, 0);
+
if (abfd == NULL || !bfd_check_format (abfd, bfd_object))
{
free_state (sd);
@@ -274,21 +628,47 @@ sim_open (kind, callback, abfd, argv)
}
}
- default_memsize
- = init_stack (abfd, prog_argv, sd, ARC_DEFAULT_MEM_SIZE, 0);
- /* Allocate core managed memory if none specified by user.
- Use address 4 here in case the user wanted address 0 unmapped. */
- if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
- sim_do_commandf (sd, "memory region 0,0x%x", default_memsize);
+ /* Establish any remaining configuration options. */
+ if (sim_config (sd) != SIM_RC_OK)
+ {
+ free_state (sd);
+ return 0;
+ }
+
+ little_endian_p = IS_LITTLE_ENDIAN(abfd);
+
+ /* Check whether core managed memory has been specified by user.
+ Use address 4 here in case the user wanted address 0 unmapped.
+ N.B. this is really not a very good check - we want to know whether the
+ user has explicitly specified the target's memory regions, so that we
+ don't define a region ourself (which might overlap), and we try to
+ find that out by seeing if we can read the memory at address 0x4 !!!! */
+ sd->memory_regions_defined_by_user =
+ sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) != 0;
- if (!init_stack (abfd, prog_argv, sd, default_memsize, 1)
- /* Establish any remaining configuration options. */
- || sim_config (sd) != SIM_RC_OK)
+ /* Calculate the memory size required without actually initializing the stack. */
+ if (!determine_memory_requirements(sd, abfd, prog_argv, NULL, &sd->memory))
{
free_state (sd);
return 0;
}
+ define_memory_region (sd, 0, sd->memory.total_size);
+
+ /* If the simulator is being used stand-alone, we know that the program
+ arguments we have been given here are not going to change later on (when
+ sim_create_inferior is called) - so we can go ahead and set up the stack
+ with those arguments right now. */
+ if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
+ {
+ /* Now that we do know the memory size, initialize the stack. */
+ if (!setup_stack (sd, little_endian_p, prog_argv, NULL))
+ {
+ free_state (sd);
+ return 0;
+ }
+ }
+
if (sim_post_argv_init (sd) != SIM_RC_OK)
{
free_state (sd);
@@ -297,16 +677,18 @@ sim_open (kind, callback, abfd, argv)
/* Open a copy of the cpu descriptor table. */
{
- CGEN_CPU_DESC cd
- = arc_cgen_cpu_open_1 (STATE_ARCHITECTURE (sd)->printable_name,
- (abfd && bfd_little_endian (abfd)
- ? CGEN_ENDIAN_LITTLE: CGEN_ENDIAN_BIG));
+ CGEN_CPU_DESC cd = arc_cgen_cpu_open_1
+ (STATE_ARCHITECTURE (sd)->printable_name,
+ (little_endian_p ? CGEN_ENDIAN_LITTLE : CGEN_ENDIAN_BIG));
+ int i;
+
for (i = 0; i < MAX_NR_PROCESSORS; ++i)
{
SIM_CPU *cpu = STATE_CPU (sd, i);
CPU_CPU_DESC (cpu) = cd;
CPU_DISASSEMBLER (cpu) = sim_cgen_disassemble_insn;
}
+
arc_cgen_init_dis (cd);
}
@@ -314,63 +696,130 @@ sim_open (kind, callback, abfd, argv)
Must be done after arc_cgen_cpu_open. */
cgen_init (sd);
- for (c = 0; c < MAX_NR_PROCESSORS; ++c)
+ for (c = 0; c < MAX_NR_PROCESSORS; c++)
{
/* Only needed for profiling, but the structure member is small. */
memset (CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i)), 0,
sizeof (* CPU_ARC_MISC_PROFILE (STATE_CPU (sd, i))));
- /* Hook in callback for reporting these stats */
- PROFILE_INFO_CPU_CALLBACK (CPU_PROFILE_DATA (STATE_CPU (sd, i)))
- = print_arc_misc_cpu;
+
+ /* Hook in callback for reporting these stats. */
+ PROFILE_INFO_CPU_CALLBACK (CPU_PROFILE_DATA (STATE_CPU (sd, i))) =
+ print_arc_misc_cpu;
}
- /* Store in a global so things like sparc32_dump_regs can be invoked
+ /* Store in a global so things like arc32_dump_regs can be invoked
from the gdb command line. */
current_state = sd;
return sd;
}
+
void
-sim_close (sd, quitting)
- SIM_DESC sd;
- int quitting;
+sim_close (SIM_DESC sd, int quitting)
{
arc_cgen_cpu_close (CPU_CPU_DESC (STATE_CPU (sd, 0)));
sim_module_uninstall (sd);
}
-
+
+
SIM_RC
-sim_create_inferior (sd, abfd, argv, envp)
- SIM_DESC sd;
- struct bfd *abfd;
- char **argv;
- char **envp;
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **envp)
{
SIM_CPU *current_cpu = STATE_CPU (sd, 0);
SIM_ADDR addr;
+#ifndef PUSH_ENVIRONMENT_ONTO_STACK
+ envp = NULL;
+#endif
+#ifdef LOGGING
+ sim_io_eprintf (sd, "sim_create_inferior: %p\n", abfd);
+ dump (sd, argv, envp);
+#endif
+
if (abfd != NULL)
- addr = bfd_get_start_address (abfd);
+ {
+ int little_endian_p = bfd_little_endian (abfd);
+
+ if (little_endian_p)
+ {
+ if (CURRENT_TARGET_BYTE_ORDER == BIG_ENDIAN)
+ {
+ sim_io_eprintf (sd, "Target is big-endian but executable file %s is little-endian.\n",
+ bfd_get_filename (abfd));
+ return SIM_RC_FAIL;
+ }
+ }
+ else
+ {
+ if (CURRENT_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
+ {
+ sim_io_eprintf (sd, "Target is little-endian but executable file %s is big-endian.\n",
+ bfd_get_filename(abfd));
+ return SIM_RC_FAIL;
+ }
+ }
+
+ addr = bfd_get_start_address (abfd);
+ }
else
addr = 0;
+
sim_pc_set (current_cpu, addr);
- /* Initialize stack pointer. */
- if (!sd->stack_top
- && !init_stack (abfd, argv, sd, 1, 1))
- return 0;
- current_cpu->endbrk = sd->heap_start;
-
- a5f_h_cr_set (current_cpu, 28, (sd)->stack_top);
- /* Set r0/r1 to argc / argv */
- a5f_h_cr_set (current_cpu, 0, GETMEMSI (current_cpu, 0, sd->stack_top));
- a5f_h_cr_set (current_cpu, 1, sd->stack_top+4);
-
-#ifdef ARC_LINUX
- m32rbf_h_cr_set (current_cpu,
- arc_decode_gdb_ctrl_regnum(SPI_REGNUM), 0x1f00000);
- m32rbf_h_cr_set (current_cpu,
- arc_decode_gdb_ctrl_regnum(SPU_REGNUM), 0x1f00000);
+
+ /* If the simulator is being used stand-alone, we have already set up the
+ stack (when sim_open was called); but if the simulator is being used by
+ gdb we must set up the stack each time that sim_create_inferior is
+ called, in case the program arguments have changed since last time. */
+ if (STATE_OPEN_KIND(sd) == SIM_OPEN_DEBUG)
+ {
+ struct sim_memory memory;
+
+ if (determine_memory_requirements (sd, abfd, argv, envp, &memory))
+ {
+ USI current_size = sd->memory.total_size;
+
+ if (memory.total_size > current_size)
+ {
+#ifdef LOGGING
+ sim_io_eprintf (sd, "program requires memory size 0x%x bytes"
+ " but simulator currently has memory size 0x%x bytes\n",
+ memory.total_size, current_size);
+#endif
+
+ /* Define another memory region to provide the extra memory
+ required. */
+ define_memory_region (sd, current_size,
+ memory.total_size - current_size);
+
+ /* Update all the memory details. */
+ sd->memory = memory;
+ }
+ else
+ {
+ /* Update all the memory details *except* the current size. */
+ sd->memory = memory;
+ sd->memory.total_size = current_size;
+ }
+
+ if (!setup_stack (sd, IS_LITTLE_ENDIAN (abfd), argv, envp))
+ return SIM_RC_FAIL;
+ }
+ else
+ return SIM_RC_FAIL;
+ }
+
+ current_cpu->endbrk = sd->memory.heap_start;
+
+ /* Set r28 (SP) to the stack top, and set r0/r1 to argc/argv. */
+ a5f_h_cr_set (current_cpu, 0, sd->memory.num_arguments);
+ a5f_h_cr_set (current_cpu, 1, sd->memory.stack_top + 4);
+ a5f_h_cr_set (current_cpu, 28, sd->memory.stack_top);
+
+#ifdef LOGGING
+ sim_io_eprintf (sd, "R0 = 0x%08X\n", sd->memory.num_arguments);
+ sim_io_eprintf (sd, "R1 = 0x%08X\n", sd->memory.stack_top + 4);
+ sim_io_eprintf (sd, "SP = 0x%08X\n", sd->memory.stack_top);
#endif
#if 0
@@ -381,39 +830,10 @@ sim_create_inferior (sd, abfd, argv, envp)
return SIM_RC_OK;
}
-/* PROFILE_CPU_CALLBACK */
-
-static void
-print_arc_misc_cpu (SIM_CPU *cpu, int verbose)
-{
- SIM_DESC sd = CPU_STATE (cpu);
- char buf[20];
-
- if (CPU_PROFILE_FLAGS (cpu) [PROFILE_INSN_IDX])
- {
- sim_io_printf (sd, "Miscellaneous Statistics\n\n");
- sim_io_printf (sd, " %-*s %s\n\n",
- PROFILE_LABEL_WIDTH, "Fill nops:",
- sim_add_commas (buf, sizeof (buf),
- CPU_ARC_MISC_PROFILE (cpu)->fillnop_count));
- if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_m32rx)
- sim_io_printf (sd, " %-*s %s\n\n",
- PROFILE_LABEL_WIDTH, "Parallel insns:",
- sim_add_commas (buf, sizeof (buf),
- CPU_ARC_MISC_PROFILE (cpu)->parallel_count));
- if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_m32r2)
- sim_io_printf (sd, " %-*s %s\n\n",
- PROFILE_LABEL_WIDTH, "Parallel insns:",
- sim_add_commas (buf, sizeof (buf),
- CPU_ARC_MISC_PROFILE (cpu)->parallel_count));
- }
-}
void
-sim_do_command (sd, cmd)
- SIM_DESC sd;
- char *cmd;
-{
+sim_do_command (SIM_DESC sd, char* cmd)
+{
char **argv;
if (cmd == NULL)
@@ -421,6 +841,8 @@ sim_do_command (sd, cmd)
argv = buildargv (cmd);
+ /* Is the command 'info reg[ister] <name>' ? */
+
if (argv[0] != NULL
&& strcasecmp (argv[0], "info") == 0
&& argv[1] != NULL
@@ -428,24 +850,13 @@ sim_do_command (sd, cmd)
{
SI val;
- /* We only support printing bbpsw,bbpc here as there is no equivalent
- functionality in gdb. */
if (argv[2] == NULL)
- sim_io_eprintf (sd, "Missing register in `%s'\n", cmd);
+ sim_io_eprintf (sd, "Missing register in `%s'\n", cmd);
else if (argv[3] != NULL)
- sim_io_eprintf (sd, "Too many arguments in `%s'\n", cmd);
-#if 0
- else if (strcasecmp (argv[2], "bbpsw") == 0)
- {
- val = m32rbf_h_cr_get (STATE_CPU (sd, 0), H_CR_BBPSW);
- sim_io_printf (sd, "bbpsw 0x%x %d\n", val, val);
- }
- else if (strcasecmp (argv[2], "bbpc") == 0)
- {
- val = m32rbf_h_cr_get (STATE_CPU (sd, 0), H_CR_BBPC);
- sim_io_printf (sd, "bbpc 0x%x %d\n", val, val);
- }
-#endif
+ sim_io_eprintf (sd, "Too many arguments in `%s'\n", cmd);
+
+ /* Should we recognize some/all of the ARC register names here? */
+
else
sim_io_eprintf (sd, "Printing of register `%s' not supported with `sim info'\n",
argv[2]);
@@ -458,3 +869,5 @@ sim_do_command (sd, cmd)
freeargv (argv);
}
+
+/******************************************************************************/