/* Low level interface to simulators, for the remote server for GDB. Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001 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 "server.h" #include "bfd.h" #include "callback.h" /* GDB simulator callback interface */ #include "remote-sim.h" /* GDB simulator interface */ extern int remote_debug; extern host_callback default_callback; /* in sim/common/callback.c */ static char my_registers[REGISTER_BYTES] __attribute__ ((aligned)); char * registers = my_registers; 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 mygeneric_load (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 lma; /* use load address, not virtual address */ buffer = xmalloc (size); lma = s->lma; /* Is this really necessary? I guess it gives the user something to look at during a long download. */ printf ("Loading section %s, size 0x%lx lma 0x%lx\n", bfd_get_section_name (loadfile_bfd, s), (unsigned long) size, (unsigned long) lma); /* chops high 32 bits. FIXME!! */ bfd_get_section_contents (loadfile_bfd, s, buffer, 0, size); write_inferior_memory (lma, buffer, size); free (buffer); } } } printf ("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 (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_argv[nargs] = "-E"; new_argv[nargs + 1] = bfd_big_endian (abfd) ? "big" : "little"; new_argv[nargs + 2] = NULL; argv = new_argv; #endif /* Create an instance of the simulator. */ default_callback.init (&default_callback); gdbsim_desc = sim_open (SIM_OPEN_STANDALONE, &default_callback, abfd, argv); if (gdbsim_desc == 0) exit (1); /* Load the program into the simulator. */ if (abfd) if (sim_load (gdbsim_desc, program, NULL, 0) == SIM_RC_FAIL) mygeneric_load (abfd); /* Create an inferior process in the simulator. This initializes SP. */ sim_create_inferior (gdbsim_desc, abfd, argv, /* env */ NULL); sim_resume (gdbsim_desc, 1, 0); /* execute one instr */ return pid; } /* Kill the inferior process. Make us have no inferior. */ void kill_inferior (void) { sim_close (gdbsim_desc, 0); default_callback.shutdown (&default_callback); } /* Fetch one register. */ static void fetch_register (int regno) { sim_fetch_register (gdbsim_desc, regno, ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno)); } /* Fetch all registers, or just one, from the child process. */ void fetch_inferior_registers (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 (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)], REGISTER_RAW_SIZE (regno)); } /* Return nonzero if the given thread is still alive. */ int mythread_alive (int pid) { return 1; } /* Wait for process, returns status */ unsigned char mywait (char *status) { int sigrc; enum sim_stop reason; sim_stop_reason (gdbsim_desc, &reason, &sigrc); switch (reason) { case sim_exited: if (remote_debug) printf ("\nChild exited with retcode = %x \n", sigrc); *status = 'W'; return sigrc; #if 0 case sim_stopped: if (remote_debug) printf ("\nChild terminated with signal = %x \n", sigrc); *status = 'X'; return sigrc; #endif default: /* should this be sim_signalled or sim_stopped? FIXME!! */ if (remote_debug) printf ("\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 (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 (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 (CORE_ADDR memaddr, char *myaddr, int len) { sim_write (gdbsim_desc, memaddr, myaddr, len); /* should check for error. FIXME!! */ return 0; } void initialize_low (void) { }