/* Low level interface to simulators, for the remote server for GDB. Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "defs.h" #include "bfd.h" #include "server.h" #include "callback.h" /* GDB simulator callback interface */ #include "remote-sim.h" /* GDB simulator interface */ extern host_callback default_callback; /* in sim/common/callback.c */ char registers[REGISTER_BYTES]; int target_byte_order; /* used by simulator */ /* We record the result of sim_open so we can pass it back to the other sim_foo routines. */ static SIM_DESC gdbsim_desc = 0; /* This version of "load" should be usable for any simulator that does not support loading itself. */ static void generic_load (loadfile_bfd) bfd *loadfile_bfd; { asection *s; for (s = loadfile_bfd->sections; s; s = s->next) { if (s->flags & SEC_LOAD) { bfd_size_type size; size = bfd_get_section_size_before_reloc (s); if (size > 0) { char *buffer; bfd_vma vma; buffer = xmalloc (size); vma = bfd_get_section_vma (loadfile_bfd, s); /* Is this really necessary? I guess it gives the user something to look at during a long download. */ fprintf (stderr, "Loading section %s, size 0x%lx vma 0x%lx\n", bfd_get_section_name (loadfile_bfd, s), (unsigned long) size, (unsigned long) vma); /* chops high 32 bits. FIXME!! */ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size); write_inferior_memory (vma, buffer, size); free (buffer); } } } fprintf (stderr, "Start address 0x%lx\n", (unsigned long)loadfile_bfd->start_address); /* We were doing this in remote-mips.c, I suspect it is right for other targets too. */ /* write_pc (loadfile_bfd->start_address); */ /* FIXME!! */ } int create_inferior (program, argv) char *program; char **argv; { bfd *abfd; int pid = 0; #ifdef TARGET_BYTE_ORDER_SELECTABLE char **new_argv; int nargs; #endif abfd = bfd_openr (program, 0); if (!abfd) { fprintf (stderr, "gdbserver: can't open %s: %s\n", program, bfd_errmsg (bfd_get_error ())); exit (1); } if (!bfd_check_format (abfd, bfd_object)) { fprintf (stderr, "gdbserver: unknown load format for %s: %s\n", program, bfd_errmsg (bfd_get_error ())); exit (1); } #ifdef TARGET_BYTE_ORDER_SELECTABLE /* Add "-E big" or "-E little" to the argument list depending on the endianness of the program to be loaded. */ for (nargs = 0; argv[nargs] != NULL; nargs++) /* count the args */ ; new_argv = alloca (sizeof (char *) * (nargs + 3)); /* allocate new args */ for (nargs = 0; argv[nargs] != NULL; nargs++) /* copy old to new */ new_argv[nargs] = argv[nargs]; new_args[nargs] = "-E"; new_args[nargs + 1] = bfd_big_endian (abfd) ? "big" : "little"; new_args[nargs + 2] = NULL; argv = new_args; #endif /* Create an instance of the simulator. */ default_callback.init (&default_callback); gdbsim_desc = sim_open (SIM_OPEN_STANDALONE, &default_callback, argv); if (gdbsim_desc == 0) exit (1); /* Load the program into the simulator. */ if (sim_load (gdbsim_desc, program, NULL, 0) == SIM_RC_FAIL) generic_load (abfd); /* Create an inferior process in the simulator. This initializes SP. */ sim_create_inferior (gdbsim_desc, argv, /* env */ NULL); return pid; } /* Kill the inferior process. Make us have no inferior. */ void kill_inferior () { sim_close (gdbsim_desc, 0); default_callback.shutdown (&default_callback); } /* Fetch one register. */ static void fetch_register (regno) int regno; { sim_fetch_register (gdbsim_desc, regno, ®isters[REGISTER_BYTE (regno)]); } /* Fetch all registers, or just one, from the child process. */ void fetch_inferior_registers (regno) int regno; { if (regno == -1 || regno == 0) for (regno = 0; regno < NUM_REGS/*-NUM_FREGS*/; regno++) fetch_register (regno); else fetch_register (regno); } /* Store our register values back into the inferior. If REGNO is -1, do this for all registers. Otherwise, REGNO specifies which register (so we can save time). */ void store_inferior_registers (regno) int regno; { if (regno == -1) { for (regno = 0; regno < NUM_REGS; regno++) store_inferior_registers (regno); } else sim_store_register (gdbsim_desc, regno, ®isters[REGISTER_BYTE (regno)]); } /* Return nonzero if the given thread is still alive. */ int mythread_alive (pid) int pid; { return 1; } /* Wait for process, returns status */ unsigned char mywait (status) char *status; { int sigrc; enum sim_stop reason; sim_stop_reason (gdbsim_desc, &reason, &sigrc); switch (reason) { case sim_exited: fprintf (stderr, "\nChild exited with retcode = %x \n", sigrc); *status = 'W'; return sigrc; #if 0 case sim_stopped: fprintf (stderr, "\nChild terminated with signal = %x \n", sigrc); *status = 'X'; return sigrc; #endif default: /* should this be sim_signalled or sim_stopped? FIXME!! */ fprintf (stderr, "\nChild received signal = %x \n", sigrc); fetch_inferior_registers (0); *status = 'T'; return (unsigned char) sigrc; } } /* Resume execution of the inferior process. If STEP is nonzero, single-step it. If SIGNAL is nonzero, give it that signal. */ void myresume (step, signo) int step; int signo; { /* Should be using target_signal_to_host() or signal numbers in target.h to convert GDB signal number to target signal number. */ sim_resume (gdbsim_desc, step, signo); } /* Copy LEN bytes from inferior's memory starting at MEMADDR to debugger memory starting at MYADDR. */ void read_inferior_memory (memaddr, myaddr, len) CORE_ADDR memaddr; char *myaddr; int len; { sim_read (gdbsim_desc, memaddr, myaddr, len); } /* Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory at MEMADDR. On failure (cannot write the inferior) returns the value of errno. */ int write_inferior_memory (memaddr, myaddr, len) CORE_ADDR memaddr; char *myaddr; int len; { sim_write (gdbsim_desc, memaddr, myaddr, len); /* should check for error. FIXME!! */ return 0; } #if 0 void initialize () { inferior_pid = 0; } int have_inferior_p () { return inferior_pid != 0; } #endif