From: Andrew Cagney Date: Mon, 21 Jul 2003 18:56:05 +0000 (+0000) Subject: 2003-07-21 Andrew Cagney X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d95a89033d01d8f5132a8a4f79dc4c2d9deb54b1;p=binutils-gdb.git 2003-07-21 Andrew Cagney From 2003-07-04 Kei Sakamoto : * m32r-tdep.c, m32r-stub.c, m32r-tdep.c: Rewrite. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 97c94842087..a3dc614558c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2003-07-21 Andrew Cagney + + From 2003-07-04 Kei Sakamoto : + * m32r-tdep.c, m32r-stub.c, m32r-tdep.c: Rewrite. + 2003-07-20 Stephane Carrez * m68hc11-tdep.c (m68hc11_pseudo_register_read): Use diff --git a/gdb/m32r-rom.c b/gdb/m32r-rom.c index f8ac1542409..54e2cd9e39b 100644 --- a/gdb/m32r-rom.c +++ b/gdb/m32r-rom.c @@ -1,626 +1,635 @@ -// OBSOLETE /* Remote debugging interface to m32r and mon2000 ROM monitors for GDB, -// OBSOLETE the GNU debugger. -// OBSOLETE Copyright 1996, 1997, 1998, 1999, 2000, 2001 -// OBSOLETE Free Software Foundation, Inc. -// OBSOLETE -// OBSOLETE Adapted by Michael Snyder of Cygnus Support. -// OBSOLETE -// OBSOLETE This file is part of GDB. -// OBSOLETE -// OBSOLETE This program is free software; you can redistribute it and/or modify -// OBSOLETE it under the terms of the GNU General Public License as published by -// OBSOLETE the Free Software Foundation; either version 2 of the License, or -// OBSOLETE (at your option) any later version. -// OBSOLETE -// OBSOLETE This program is distributed in the hope that it will be useful, -// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of -// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// OBSOLETE GNU General Public License for more details. -// OBSOLETE -// OBSOLETE You should have received a copy of the GNU General Public License -// OBSOLETE along with this program; if not, write to the Free Software -// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330, -// OBSOLETE Boston, MA 02111-1307, USA. */ -// OBSOLETE -// OBSOLETE /* This module defines communication with the Mitsubishi m32r monitor */ -// OBSOLETE -// OBSOLETE #include "defs.h" -// OBSOLETE #include "gdbcore.h" -// OBSOLETE #include "target.h" -// OBSOLETE #include "monitor.h" -// OBSOLETE #include "serial.h" -// OBSOLETE #include "symtab.h" -// OBSOLETE #include "command.h" -// OBSOLETE #include "gdbcmd.h" -// OBSOLETE #include "symfile.h" /* for generic load */ -// OBSOLETE #include /* for time_t */ -// OBSOLETE #include "gdb_string.h" -// OBSOLETE #include "objfiles.h" /* for ALL_OBJFILES etc. */ -// OBSOLETE #include "inferior.h" /* for write_pc() */ -// OBSOLETE #include -// OBSOLETE #include "regcache.h" -// OBSOLETE -// OBSOLETE extern void report_transfer_performance (unsigned long, time_t, time_t); -// OBSOLETE -// OBSOLETE /* -// OBSOLETE * All this stuff just to get my host computer's IP address! -// OBSOLETE */ -// OBSOLETE #include -// OBSOLETE #include /* for hostent */ -// OBSOLETE #include /* for struct in_addr */ -// OBSOLETE #if 1 -// OBSOLETE #include /* for inet_ntoa */ -// OBSOLETE #endif -// OBSOLETE -// OBSOLETE static char *board_addr; /* user-settable IP address for M32R-EVA */ -// OBSOLETE static char *server_addr; /* user-settable IP address for gdb host */ -// OBSOLETE static char *download_path; /* user-settable path for SREC files */ -// OBSOLETE -// OBSOLETE -// OBSOLETE /* -// OBSOLETE * Function: m32r_load_1 (helper function) -// OBSOLETE */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_load_section (bfd *abfd, asection *s, void *obj) -// OBSOLETE { -// OBSOLETE unsigned int *data_count = obj; -// OBSOLETE if (s->flags & SEC_LOAD) -// OBSOLETE { -// OBSOLETE bfd_size_type section_size = bfd_section_size (abfd, s); -// OBSOLETE bfd_vma section_base = bfd_section_lma (abfd, s); -// OBSOLETE unsigned int buffer, i; -// OBSOLETE -// OBSOLETE *data_count += section_size; -// OBSOLETE -// OBSOLETE printf_filtered ("Loading section %s, size 0x%lx lma ", -// OBSOLETE bfd_section_name (abfd, s), section_size); -// OBSOLETE print_address_numeric (section_base, 1, gdb_stdout); -// OBSOLETE printf_filtered ("\n"); -// OBSOLETE gdb_flush (gdb_stdout); -// OBSOLETE monitor_printf ("%s mw\r", paddr_nz (section_base)); -// OBSOLETE for (i = 0; i < section_size; i += 4) -// OBSOLETE { -// OBSOLETE QUIT; -// OBSOLETE monitor_expect (" -> ", NULL, 0); -// OBSOLETE bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4); -// OBSOLETE monitor_printf ("%x\n", buffer); -// OBSOLETE } -// OBSOLETE monitor_expect (" -> ", NULL, 0); -// OBSOLETE monitor_printf ("q\n"); -// OBSOLETE monitor_expect_prompt (NULL, 0); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE m32r_load_1 (void *dummy) -// OBSOLETE { -// OBSOLETE int data_count = 0; -// OBSOLETE -// OBSOLETE bfd_map_over_sections ((bfd *) dummy, m32r_load_section, &data_count); -// OBSOLETE return data_count; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* -// OBSOLETE * Function: m32r_load (an alternate way to load) -// OBSOLETE */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_load (char *filename, int from_tty) -// OBSOLETE { -// OBSOLETE bfd *abfd; -// OBSOLETE asection *s; -// OBSOLETE unsigned int i, data_count = 0; -// OBSOLETE time_t start_time, end_time; /* for timing of download */ -// OBSOLETE -// OBSOLETE if (filename == NULL || filename[0] == 0) -// OBSOLETE filename = get_exec_file (1); -// OBSOLETE -// OBSOLETE abfd = bfd_openr (filename, 0); -// OBSOLETE if (!abfd) -// OBSOLETE error ("Unable to open file %s\n", filename); -// OBSOLETE if (bfd_check_format (abfd, bfd_object) == 0) -// OBSOLETE error ("File is not an object file\n"); -// OBSOLETE start_time = time (NULL); -// OBSOLETE #if 0 -// OBSOLETE for (s = abfd->sections; s; s = s->next) -// OBSOLETE if (s->flags & SEC_LOAD) -// OBSOLETE { -// OBSOLETE bfd_size_type section_size = bfd_section_size (abfd, s); -// OBSOLETE bfd_vma section_base = bfd_section_vma (abfd, s); -// OBSOLETE unsigned int buffer; -// OBSOLETE -// OBSOLETE data_count += section_size; -// OBSOLETE -// OBSOLETE printf_filtered ("Loading section %s, size 0x%lx vma ", -// OBSOLETE bfd_section_name (abfd, s), section_size); -// OBSOLETE print_address_numeric (section_base, 1, gdb_stdout); -// OBSOLETE printf_filtered ("\n"); -// OBSOLETE gdb_flush (gdb_stdout); -// OBSOLETE monitor_printf ("%x mw\r", section_base); -// OBSOLETE for (i = 0; i < section_size; i += 4) -// OBSOLETE { -// OBSOLETE monitor_expect (" -> ", NULL, 0); -// OBSOLETE bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4); -// OBSOLETE monitor_printf ("%x\n", buffer); -// OBSOLETE } -// OBSOLETE monitor_expect (" -> ", NULL, 0); -// OBSOLETE monitor_printf ("q\n"); -// OBSOLETE monitor_expect_prompt (NULL, 0); -// OBSOLETE } -// OBSOLETE #else -// OBSOLETE if (!(catch_errors (m32r_load_1, abfd, "Load aborted!\n", RETURN_MASK_ALL))) -// OBSOLETE { -// OBSOLETE monitor_printf ("q\n"); -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE #endif -// OBSOLETE end_time = time (NULL); -// OBSOLETE printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd)); -// OBSOLETE report_transfer_performance (data_count, start_time, end_time); -// OBSOLETE -// OBSOLETE /* Finally, make the PC point at the start address */ -// OBSOLETE if (exec_bfd) -// OBSOLETE write_pc (bfd_get_start_address (exec_bfd)); -// OBSOLETE -// OBSOLETE inferior_ptid = null_ptid; /* No process now */ -// OBSOLETE -// OBSOLETE /* This is necessary because many things were based on the PC at the -// OBSOLETE time that we attached to the monitor, which is no longer valid -// OBSOLETE now that we have loaded new code (and just changed the PC). -// OBSOLETE Another way to do this might be to call normal_stop, except that -// OBSOLETE the stack may not be valid, and things would get horribly -// OBSOLETE confused... */ -// OBSOLETE -// OBSOLETE clear_symtab_users (); -// OBSOLETE } -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_load_gen (char *filename, int from_tty) -// OBSOLETE { -// OBSOLETE generic_load (filename, from_tty); -// OBSOLETE } -// OBSOLETE -// OBSOLETE static void m32r_open (char *args, int from_tty); -// OBSOLETE static void mon2000_open (char *args, int from_tty); -// OBSOLETE -// OBSOLETE /* This array of registers needs to match the indexes used by GDB. The -// OBSOLETE whole reason this exists is because the various ROM monitors use -// OBSOLETE different names than GDB does, and don't support all the registers -// OBSOLETE either. So, typing "info reg sp" becomes an "A7". */ -// OBSOLETE -// OBSOLETE static char *m32r_regnames[] = -// OBSOLETE {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", -// OBSOLETE "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", -// OBSOLETE "psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch", -// OBSOLETE }; -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_supply_register (char *regname, int regnamelen, char *val, int vallen) -// OBSOLETE { -// OBSOLETE int regno; -// OBSOLETE int num_regs = sizeof (m32r_regnames) / sizeof (m32r_regnames[0]); -// OBSOLETE -// OBSOLETE for (regno = 0; regno < num_regs; regno++) -// OBSOLETE if (strncmp (regname, m32r_regnames[regno], regnamelen) == 0) -// OBSOLETE break; -// OBSOLETE -// OBSOLETE if (regno >= num_regs) -// OBSOLETE return; /* no match */ -// OBSOLETE -// OBSOLETE if (regno == ACCL_REGNUM) -// OBSOLETE { /* special handling for 64-bit acc reg */ -// OBSOLETE monitor_supply_register (ACCH_REGNUM, val); -// OBSOLETE val = strchr (val, ':'); /* skip past ':' to get 2nd word */ -// OBSOLETE if (val != NULL) -// OBSOLETE monitor_supply_register (ACCL_REGNUM, val + 1); -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE monitor_supply_register (regno, val); -// OBSOLETE if (regno == PSW_REGNUM) -// OBSOLETE { -// OBSOLETE unsigned long psw = strtoul (val, NULL, 16); -// OBSOLETE char *zero = "00000000", *one = "00000001"; -// OBSOLETE -// OBSOLETE #ifdef SM_REGNUM -// OBSOLETE /* Stack mode bit */ -// OBSOLETE monitor_supply_register (SM_REGNUM, (psw & 0x80) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef BSM_REGNUM -// OBSOLETE /* Backup stack mode bit */ -// OBSOLETE monitor_supply_register (BSM_REGNUM, (psw & 0x8000) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef IE_REGNUM -// OBSOLETE /* Interrupt enable bit */ -// OBSOLETE monitor_supply_register (IE_REGNUM, (psw & 0x40) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef BIE_REGNUM -// OBSOLETE /* Backup interrupt enable bit */ -// OBSOLETE monitor_supply_register (BIE_REGNUM, (psw & 0x4000) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef COND_REGNUM -// OBSOLETE /* Condition bit (carry etc.) */ -// OBSOLETE monitor_supply_register (COND_REGNUM, (psw & 0x1) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef CBR_REGNUM -// OBSOLETE monitor_supply_register (CBR_REGNUM, (psw & 0x1) ? one : zero); -// OBSOLETE #endif -// OBSOLETE #ifdef BPC_REGNUM -// OBSOLETE monitor_supply_register (BPC_REGNUM, zero); /* KLUDGE: (???????) */ -// OBSOLETE #endif -// OBSOLETE #ifdef BCARRY_REGNUM -// OBSOLETE monitor_supply_register (BCARRY_REGNUM, zero); /* KLUDGE: (??????) */ -// OBSOLETE #endif -// OBSOLETE } -// OBSOLETE -// OBSOLETE if (regno == SPI_REGNUM || regno == SPU_REGNUM) -// OBSOLETE { /* special handling for stack pointer (spu or spi) */ -// OBSOLETE unsigned long stackmode = read_register (PSW_REGNUM) & 0x80; -// OBSOLETE -// OBSOLETE if (regno == SPI_REGNUM && !stackmode) /* SP == SPI */ -// OBSOLETE monitor_supply_register (SP_REGNUM, val); -// OBSOLETE else if (regno == SPU_REGNUM && stackmode) /* SP == SPU */ -// OBSOLETE monitor_supply_register (SP_REGNUM, val); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* m32r RevC board monitor */ -// OBSOLETE -// OBSOLETE static struct target_ops m32r_ops; -// OBSOLETE -// OBSOLETE static char *m32r_inits[] = -// OBSOLETE {"\r", NULL}; -// OBSOLETE -// OBSOLETE static struct monitor_ops m32r_cmds; -// OBSOLETE -// OBSOLETE static void -// OBSOLETE init_m32r_cmds (void) -// OBSOLETE { -// OBSOLETE m32r_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST; -// OBSOLETE m32r_cmds.init = m32r_inits; /* Init strings */ -// OBSOLETE m32r_cmds.cont = "go\r"; /* continue command */ -// OBSOLETE m32r_cmds.step = "step\r"; /* single step */ -// OBSOLETE m32r_cmds.stop = NULL; /* interrupt command */ -// OBSOLETE m32r_cmds.set_break = "%x +bp\r"; /* set a breakpoint */ -// OBSOLETE m32r_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */ -// OBSOLETE m32r_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */ -// OBSOLETE m32r_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */ -// OBSOLETE m32r_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */ -// OBSOLETE m32r_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */ -// OBSOLETE m32r_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */ -// OBSOLETE m32r_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */ -// OBSOLETE m32r_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */ -// OBSOLETE m32r_cmds.setmem.term = NULL; /* setmem.term */ -// OBSOLETE m32r_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */ -// OBSOLETE m32r_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */ -// OBSOLETE m32r_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */ -// OBSOLETE m32r_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */ -// OBSOLETE m32r_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */ -// OBSOLETE m32r_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */ -// OBSOLETE m32r_cmds.getmem.term = NULL; /* getmem.term */ -// OBSOLETE m32r_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */ -// OBSOLETE m32r_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */ -// OBSOLETE m32r_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */ -// OBSOLETE m32r_cmds.setreg.term = NULL; /* setreg.term */ -// OBSOLETE m32r_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */ -// OBSOLETE m32r_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */ -// OBSOLETE m32r_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */ -// OBSOLETE m32r_cmds.getreg.term = NULL; /* getreg.term */ -// OBSOLETE m32r_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */ -// OBSOLETE m32r_cmds.dump_registers = ".reg\r"; /* dump_registers */ -// OBSOLETE m32r_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */ -// OBSOLETE m32r_cmds.supply_register = m32r_supply_register; /* supply_register */ -// OBSOLETE m32r_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */ -// OBSOLETE m32r_cmds.load = NULL; /* download command */ -// OBSOLETE m32r_cmds.loadresp = NULL; /* load response */ -// OBSOLETE m32r_cmds.prompt = "ok "; /* monitor command prompt */ -// OBSOLETE m32r_cmds.line_term = "\r"; /* end-of-line terminator */ -// OBSOLETE m32r_cmds.cmd_end = NULL; /* optional command terminator */ -// OBSOLETE m32r_cmds.target = &m32r_ops; /* target operations */ -// OBSOLETE m32r_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */ -// OBSOLETE m32r_cmds.regnames = m32r_regnames; /* registers names */ -// OBSOLETE m32r_cmds.magic = MONITOR_OPS_MAGIC; /* magic */ -// OBSOLETE } /* init_m32r_cmds */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_open (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE monitor_open (args, &m32r_cmds, from_tty); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Mon2000 monitor (MSA2000 board) */ -// OBSOLETE -// OBSOLETE static struct target_ops mon2000_ops; -// OBSOLETE static struct monitor_ops mon2000_cmds; -// OBSOLETE -// OBSOLETE static void -// OBSOLETE init_mon2000_cmds (void) -// OBSOLETE { -// OBSOLETE mon2000_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST; -// OBSOLETE mon2000_cmds.init = m32r_inits; /* Init strings */ -// OBSOLETE mon2000_cmds.cont = "go\r"; /* continue command */ -// OBSOLETE mon2000_cmds.step = "step\r"; /* single step */ -// OBSOLETE mon2000_cmds.stop = NULL; /* interrupt command */ -// OBSOLETE mon2000_cmds.set_break = "%x +bp\r"; /* set a breakpoint */ -// OBSOLETE mon2000_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */ -// OBSOLETE mon2000_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */ -// OBSOLETE mon2000_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */ -// OBSOLETE mon2000_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */ -// OBSOLETE mon2000_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */ -// OBSOLETE mon2000_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */ -// OBSOLETE mon2000_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */ -// OBSOLETE mon2000_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */ -// OBSOLETE mon2000_cmds.setmem.term = NULL; /* setmem.term */ -// OBSOLETE mon2000_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */ -// OBSOLETE mon2000_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */ -// OBSOLETE mon2000_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */ -// OBSOLETE mon2000_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */ -// OBSOLETE mon2000_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */ -// OBSOLETE mon2000_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */ -// OBSOLETE mon2000_cmds.getmem.term = NULL; /* getmem.term */ -// OBSOLETE mon2000_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */ -// OBSOLETE mon2000_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */ -// OBSOLETE mon2000_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */ -// OBSOLETE mon2000_cmds.setreg.term = NULL; /* setreg.term */ -// OBSOLETE mon2000_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */ -// OBSOLETE mon2000_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */ -// OBSOLETE mon2000_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */ -// OBSOLETE mon2000_cmds.getreg.term = NULL; /* getreg.term */ -// OBSOLETE mon2000_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */ -// OBSOLETE mon2000_cmds.dump_registers = ".reg\r"; /* dump_registers */ -// OBSOLETE mon2000_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */ -// OBSOLETE mon2000_cmds.supply_register = m32r_supply_register; /* supply_register */ -// OBSOLETE mon2000_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */ -// OBSOLETE mon2000_cmds.load = NULL; /* download command */ -// OBSOLETE mon2000_cmds.loadresp = NULL; /* load response */ -// OBSOLETE mon2000_cmds.prompt = "Mon2000>"; /* monitor command prompt */ -// OBSOLETE mon2000_cmds.line_term = "\r"; /* end-of-line terminator */ -// OBSOLETE mon2000_cmds.cmd_end = NULL; /* optional command terminator */ -// OBSOLETE mon2000_cmds.target = &mon2000_ops; /* target operations */ -// OBSOLETE mon2000_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */ -// OBSOLETE mon2000_cmds.regnames = m32r_regnames; /* registers names */ -// OBSOLETE mon2000_cmds.magic = MONITOR_OPS_MAGIC; /* magic */ -// OBSOLETE } /* init_mon2000_cmds */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE mon2000_open (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE monitor_open (args, &mon2000_cmds, from_tty); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: set_board_address -// OBSOLETE Tell the BootOne monitor what it's ethernet IP address is. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_set_board_address (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE int resp_len; -// OBSOLETE char buf[1024]; -// OBSOLETE -// OBSOLETE if (args && *args) -// OBSOLETE { -// OBSOLETE monitor_printf ("ulip %s\n", args); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); -// OBSOLETE /* now parse the result for success */ -// OBSOLETE } -// OBSOLETE else -// OBSOLETE error ("Requires argument (IP address for M32R-EVA board)"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: set_server_address -// OBSOLETE Tell the BootOne monitor what gdb's ethernet IP address is. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_set_server_address (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE int resp_len; -// OBSOLETE char buf[1024]; -// OBSOLETE -// OBSOLETE if (args && *args) -// OBSOLETE { -// OBSOLETE monitor_printf ("uhip %s\n", args); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); -// OBSOLETE /* now parse the result for success */ -// OBSOLETE } -// OBSOLETE else -// OBSOLETE error ("Requires argument (IP address of GDB's host computer)"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: set_download_path -// OBSOLETE Tell the BootOne monitor the default path for downloadable SREC files. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_set_download_path (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE int resp_len; -// OBSOLETE char buf[1024]; -// OBSOLETE -// OBSOLETE if (args && *args) -// OBSOLETE { -// OBSOLETE monitor_printf ("up %s\n", args); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); -// OBSOLETE /* now parse the result for success */ -// OBSOLETE } -// OBSOLETE else -// OBSOLETE error ("Requires argument (default path for downloadable SREC files)"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE static void -// OBSOLETE m32r_upload_command (char *args, int from_tty) -// OBSOLETE { -// OBSOLETE bfd *abfd; -// OBSOLETE asection *s; -// OBSOLETE time_t start_time, end_time; /* for timing of download */ -// OBSOLETE int resp_len, data_count = 0; -// OBSOLETE char buf[1024]; -// OBSOLETE struct hostent *hostent; -// OBSOLETE struct in_addr inet_addr; -// OBSOLETE -// OBSOLETE /* first check to see if there's an ethernet port! */ -// OBSOLETE monitor_printf ("ust\r"); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); -// OBSOLETE if (!strchr (buf, ':')) -// OBSOLETE error ("No ethernet connection!"); -// OBSOLETE -// OBSOLETE if (board_addr == 0) -// OBSOLETE { -// OBSOLETE /* scan second colon in the output from the "ust" command */ -// OBSOLETE char *myIPaddress = strchr (strchr (buf, ':') + 1, ':') + 1; -// OBSOLETE -// OBSOLETE while (isspace (*myIPaddress)) -// OBSOLETE myIPaddress++; -// OBSOLETE -// OBSOLETE if (!strncmp (myIPaddress, "0.0.", 4)) /* empty */ -// OBSOLETE error ("Please use 'set board-address' to set the M32R-EVA board's IP address."); -// OBSOLETE if (strchr (myIPaddress, '(')) -// OBSOLETE *(strchr (myIPaddress, '(')) = '\0'; /* delete trailing junk */ -// OBSOLETE board_addr = xstrdup (myIPaddress); -// OBSOLETE } -// OBSOLETE if (server_addr == 0) -// OBSOLETE { -// OBSOLETE buf[0] = 0; -// OBSOLETE gethostname (buf, sizeof (buf)); -// OBSOLETE if (buf[0] != 0) -// OBSOLETE hostent = gethostbyname (buf); -// OBSOLETE if (hostent != 0) -// OBSOLETE { -// OBSOLETE #if 1 -// OBSOLETE memcpy (&inet_addr.s_addr, hostent->h_addr, -// OBSOLETE sizeof (inet_addr.s_addr)); -// OBSOLETE server_addr = (char *) inet_ntoa (inet_addr); -// OBSOLETE #else -// OBSOLETE server_addr = (char *) inet_ntoa (hostent->h_addr); -// OBSOLETE #endif -// OBSOLETE } -// OBSOLETE if (server_addr == 0) /* failed? */ -// OBSOLETE error ("Need to know gdb host computer's IP address (use 'set server-address')"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE if (args == 0 || args[0] == 0) /* no args: upload the current file */ -// OBSOLETE args = get_exec_file (1); -// OBSOLETE -// OBSOLETE if (args[0] != '/' && download_path == 0) -// OBSOLETE { -// OBSOLETE if (current_directory) -// OBSOLETE download_path = xstrdup (current_directory); -// OBSOLETE else -// OBSOLETE error ("Need to know default download path (use 'set download-path')"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE start_time = time (NULL); -// OBSOLETE monitor_printf ("uhip %s\r", server_addr); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ -// OBSOLETE monitor_printf ("ulip %s\r", board_addr); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ -// OBSOLETE if (args[0] != '/') -// OBSOLETE monitor_printf ("up %s\r", download_path); /* use default path */ -// OBSOLETE else -// OBSOLETE monitor_printf ("up\r"); /* rooted filename/path */ -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ -// OBSOLETE -// OBSOLETE if (strrchr (args, '.') && !strcmp (strrchr (args, '.'), ".srec")) -// OBSOLETE monitor_printf ("ul %s\r", args); -// OBSOLETE else /* add ".srec" suffix */ -// OBSOLETE monitor_printf ("ul %s.srec\r", args); -// OBSOLETE resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ -// OBSOLETE -// OBSOLETE if (buf[0] == 0 || strstr (buf, "complete") == 0) -// OBSOLETE error ("Upload file not found: %s.srec\nCheck IP addresses and download path.", args); -// OBSOLETE else -// OBSOLETE printf_filtered (" -- Ethernet load complete.\n"); -// OBSOLETE -// OBSOLETE end_time = time (NULL); -// OBSOLETE abfd = bfd_openr (args, 0); -// OBSOLETE if (abfd != NULL) -// OBSOLETE { /* Download is done -- print section statistics */ -// OBSOLETE if (bfd_check_format (abfd, bfd_object) == 0) -// OBSOLETE { -// OBSOLETE printf_filtered ("File is not an object file\n"); -// OBSOLETE } -// OBSOLETE for (s = abfd->sections; s; s = s->next) -// OBSOLETE if (s->flags & SEC_LOAD) -// OBSOLETE { -// OBSOLETE bfd_size_type section_size = bfd_section_size (abfd, s); -// OBSOLETE bfd_vma section_base = bfd_section_lma (abfd, s); -// OBSOLETE unsigned int buffer; -// OBSOLETE -// OBSOLETE data_count += section_size; -// OBSOLETE -// OBSOLETE printf_filtered ("Loading section %s, size 0x%lx lma ", -// OBSOLETE bfd_section_name (abfd, s), section_size); -// OBSOLETE print_address_numeric (section_base, 1, gdb_stdout); -// OBSOLETE printf_filtered ("\n"); -// OBSOLETE gdb_flush (gdb_stdout); -// OBSOLETE } -// OBSOLETE /* Finally, make the PC point at the start address */ -// OBSOLETE write_pc (bfd_get_start_address (abfd)); -// OBSOLETE report_transfer_performance (data_count, start_time, end_time); -// OBSOLETE printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd)); -// OBSOLETE } -// OBSOLETE inferior_ptid = null_ptid; /* No process now */ -// OBSOLETE -// OBSOLETE /* This is necessary because many things were based on the PC at the -// OBSOLETE time that we attached to the monitor, which is no longer valid -// OBSOLETE now that we have loaded new code (and just changed the PC). -// OBSOLETE Another way to do this might be to call normal_stop, except that -// OBSOLETE the stack may not be valid, and things would get horribly -// OBSOLETE confused... */ -// OBSOLETE -// OBSOLETE clear_symtab_users (); -// OBSOLETE } -// OBSOLETE -// OBSOLETE void -// OBSOLETE _initialize_m32r_rom (void) -// OBSOLETE { -// OBSOLETE /* Initialize m32r RevC monitor target */ -// OBSOLETE init_m32r_cmds (); -// OBSOLETE init_monitor_ops (&m32r_ops); -// OBSOLETE -// OBSOLETE m32r_ops.to_shortname = "m32r"; -// OBSOLETE m32r_ops.to_longname = "m32r monitor"; -// OBSOLETE m32r_ops.to_load = m32r_load_gen; /* monitor lacks a download command */ -// OBSOLETE m32r_ops.to_doc = "Debug via the m32r monitor.\n\ -// OBSOLETE Specify the serial device it is connected to (e.g. /dev/ttya)."; -// OBSOLETE m32r_ops.to_open = m32r_open; -// OBSOLETE add_target (&m32r_ops); -// OBSOLETE -// OBSOLETE /* Initialize mon2000 monitor target */ -// OBSOLETE init_mon2000_cmds (); -// OBSOLETE init_monitor_ops (&mon2000_ops); -// OBSOLETE -// OBSOLETE mon2000_ops.to_shortname = "mon2000"; -// OBSOLETE mon2000_ops.to_longname = "Mon2000 monitor"; -// OBSOLETE mon2000_ops.to_load = m32r_load_gen; /* monitor lacks a download command */ -// OBSOLETE mon2000_ops.to_doc = "Debug via the Mon2000 monitor.\n\ -// OBSOLETE Specify the serial device it is connected to (e.g. /dev/ttya)."; -// OBSOLETE mon2000_ops.to_open = mon2000_open; -// OBSOLETE add_target (&mon2000_ops); -// OBSOLETE -// OBSOLETE add_show_from_set -// OBSOLETE (add_set_cmd ("download-path", class_obscure, var_string, -// OBSOLETE (char *) &download_path, -// OBSOLETE "Set the default path for downloadable SREC files.", -// OBSOLETE &setlist), -// OBSOLETE &showlist); -// OBSOLETE -// OBSOLETE add_show_from_set -// OBSOLETE (add_set_cmd ("board-address", class_obscure, var_string, -// OBSOLETE (char *) &board_addr, -// OBSOLETE "Set IP address for M32R-EVA target board.", -// OBSOLETE &setlist), -// OBSOLETE &showlist); -// OBSOLETE -// OBSOLETE add_show_from_set -// OBSOLETE (add_set_cmd ("server-address", class_obscure, var_string, -// OBSOLETE (char *) &server_addr, -// OBSOLETE "Set IP address for download server (GDB's host computer).", -// OBSOLETE &setlist), -// OBSOLETE &showlist); -// OBSOLETE -// OBSOLETE add_com ("upload", class_obscure, m32r_upload_command, -// OBSOLETE "Upload the srec file via the monitor's Ethernet upload capability."); -// OBSOLETE -// OBSOLETE add_com ("tload", class_obscure, m32r_load, "test upload command."); -// OBSOLETE } +/* Remote debugging interface to m32r and mon2000 ROM monitors for GDB, + the GNU debugger. + Copyright 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + Adapted by Michael Snyder of Cygnus Support. + + 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. */ + +/* This module defines communication with the Renesas m32r monitor */ + +#include "defs.h" +#include "gdbcore.h" +#include "target.h" +#include "monitor.h" +#include "serial.h" +#include "symtab.h" +#include "command.h" +#include "gdbcmd.h" +#include "symfile.h" /* for generic load */ +#include /* for time_t */ +#include "gdb_string.h" +#include "objfiles.h" /* for ALL_OBJFILES etc. */ +#include "inferior.h" /* for write_pc() */ +#include +#include "regcache.h" + +extern void report_transfer_performance (unsigned long, time_t, time_t); + +/* + * All this stuff just to get my host computer's IP address! + */ +#include +#include /* for hostent */ +#include /* for struct in_addr */ +#if 1 +#include /* for inet_ntoa */ +#endif + +static char *board_addr; /* user-settable IP address for M32R-EVA */ +static char *server_addr; /* user-settable IP address for gdb host */ +static char *download_path; /* user-settable path for SREC files */ + + +/* REGNUM */ +#define PSW_REGNUM 16 +#define SPI_REGNUM 18 +#define SPU_REGNUM 19 +#define ACCL_REGNUM 22 +#define ACCH_REGNUM 23 + + +/* + * Function: m32r_load_1 (helper function) + */ + +static void +m32r_load_section (bfd *abfd, asection *s, void *obj) +{ + unsigned int *data_count = obj; + if (s->flags & SEC_LOAD) + { + bfd_size_type section_size = bfd_section_size (abfd, s); + bfd_vma section_base = bfd_section_lma (abfd, s); + unsigned int buffer, i; + + *data_count += section_size; + + printf_filtered ("Loading section %s, size 0x%lx lma ", + bfd_section_name (abfd, s), section_size); + print_address_numeric (section_base, 1, gdb_stdout); + printf_filtered ("\n"); + gdb_flush (gdb_stdout); + monitor_printf ("%s mw\r", paddr_nz (section_base)); + for (i = 0; i < section_size; i += 4) + { + QUIT; + monitor_expect (" -> ", NULL, 0); + bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4); + monitor_printf ("%x\n", buffer); + } + monitor_expect (" -> ", NULL, 0); + monitor_printf ("q\n"); + monitor_expect_prompt (NULL, 0); + } +} + +static int +m32r_load_1 (void *dummy) +{ + int data_count = 0; + + bfd_map_over_sections ((bfd *) dummy, m32r_load_section, &data_count); + return data_count; +} + +/* + * Function: m32r_load (an alternate way to load) + */ + +static void +m32r_load (char *filename, int from_tty) +{ + bfd *abfd; + asection *s; + unsigned int i, data_count = 0; + time_t start_time, end_time; /* for timing of download */ + + if (filename == NULL || filename[0] == 0) + filename = get_exec_file (1); + + abfd = bfd_openr (filename, 0); + if (!abfd) + error ("Unable to open file %s\n", filename); + if (bfd_check_format (abfd, bfd_object) == 0) + error ("File is not an object file\n"); + start_time = time (NULL); +#if 0 + for (s = abfd->sections; s; s = s->next) + if (s->flags & SEC_LOAD) + { + bfd_size_type section_size = bfd_section_size (abfd, s); + bfd_vma section_base = bfd_section_vma (abfd, s); + unsigned int buffer; + + data_count += section_size; + + printf_filtered ("Loading section %s, size 0x%lx vma ", + bfd_section_name (abfd, s), section_size); + print_address_numeric (section_base, 1, gdb_stdout); + printf_filtered ("\n"); + gdb_flush (gdb_stdout); + monitor_printf ("%x mw\r", section_base); + for (i = 0; i < section_size; i += 4) + { + monitor_expect (" -> ", NULL, 0); + bfd_get_section_contents (abfd, s, (char *) &buffer, i, 4); + monitor_printf ("%x\n", buffer); + } + monitor_expect (" -> ", NULL, 0); + monitor_printf ("q\n"); + monitor_expect_prompt (NULL, 0); + } +#else + if (!(catch_errors (m32r_load_1, abfd, "Load aborted!\n", RETURN_MASK_ALL))) + { + monitor_printf ("q\n"); + return; + } +#endif + end_time = time (NULL); + printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd)); + report_transfer_performance (data_count, start_time, end_time); + + /* Finally, make the PC point at the start address */ + if (exec_bfd) + write_pc (bfd_get_start_address (exec_bfd)); + + inferior_ptid = null_ptid; /* No process now */ + + /* This is necessary because many things were based on the PC at the + time that we attached to the monitor, which is no longer valid + now that we have loaded new code (and just changed the PC). + Another way to do this might be to call normal_stop, except that + the stack may not be valid, and things would get horribly + confused... */ + + clear_symtab_users (); +} + +static void +m32r_load_gen (char *filename, int from_tty) +{ + generic_load (filename, from_tty); +} + +static void m32r_open (char *args, int from_tty); +static void mon2000_open (char *args, int from_tty); + +/* This array of registers needs to match the indexes used by GDB. The + whole reason this exists is because the various ROM monitors use + different names than GDB does, and don't support all the registers + either. So, typing "info reg sp" becomes an "A7". */ + +static char *m32r_regnames[] = + { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch", +}; + +static void +m32r_supply_register (char *regname, int regnamelen, char *val, int vallen) +{ + int regno; + int num_regs = sizeof (m32r_regnames) / sizeof (m32r_regnames[0]); + + for (regno = 0; regno < num_regs; regno++) + if (strncmp (regname, m32r_regnames[regno], regnamelen) == 0) + break; + + if (regno >= num_regs) + return; /* no match */ + + if (regno == ACCL_REGNUM) + { /* special handling for 64-bit acc reg */ + monitor_supply_register (ACCH_REGNUM, val); + val = strchr (val, ':'); /* skip past ':' to get 2nd word */ + if (val != NULL) + monitor_supply_register (ACCL_REGNUM, val + 1); + } + else + { + monitor_supply_register (regno, val); + if (regno == PSW_REGNUM) + { + unsigned long psw = strtoul (val, NULL, 16); + char *zero = "00000000", *one = "00000001"; + +#ifdef SM_REGNUM + /* Stack mode bit */ + monitor_supply_register (SM_REGNUM, (psw & 0x80) ? one : zero); +#endif +#ifdef BSM_REGNUM + /* Backup stack mode bit */ + monitor_supply_register (BSM_REGNUM, (psw & 0x8000) ? one : zero); +#endif +#ifdef IE_REGNUM + /* Interrupt enable bit */ + monitor_supply_register (IE_REGNUM, (psw & 0x40) ? one : zero); +#endif +#ifdef BIE_REGNUM + /* Backup interrupt enable bit */ + monitor_supply_register (BIE_REGNUM, (psw & 0x4000) ? one : zero); +#endif +#ifdef COND_REGNUM + /* Condition bit (carry etc.) */ + monitor_supply_register (COND_REGNUM, (psw & 0x1) ? one : zero); +#endif +#ifdef CBR_REGNUM + monitor_supply_register (CBR_REGNUM, (psw & 0x1) ? one : zero); +#endif +#ifdef BPC_REGNUM + monitor_supply_register (BPC_REGNUM, zero); /* KLUDGE: (???????) */ +#endif +#ifdef BCARRY_REGNUM + monitor_supply_register (BCARRY_REGNUM, zero); /* KLUDGE: (??????) */ +#endif + } + + if (regno == SPI_REGNUM || regno == SPU_REGNUM) + { /* special handling for stack pointer (spu or spi) */ + unsigned long stackmode = read_register (PSW_REGNUM) & 0x80; + + if (regno == SPI_REGNUM && !stackmode) /* SP == SPI */ + monitor_supply_register (SP_REGNUM, val); + else if (regno == SPU_REGNUM && stackmode) /* SP == SPU */ + monitor_supply_register (SP_REGNUM, val); + } + } +} + +/* m32r RevC board monitor */ + +static struct target_ops m32r_ops; + +static char *m32r_inits[] = { "\r", NULL }; + +static struct monitor_ops m32r_cmds; + +static void +init_m32r_cmds (void) +{ + m32r_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST; + m32r_cmds.init = m32r_inits; /* Init strings */ + m32r_cmds.cont = "go\r"; /* continue command */ + m32r_cmds.step = "step\r"; /* single step */ + m32r_cmds.stop = NULL; /* interrupt command */ + m32r_cmds.set_break = "%x +bp\r"; /* set a breakpoint */ + m32r_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */ + m32r_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */ + m32r_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */ + m32r_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */ + m32r_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */ + m32r_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */ + m32r_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */ + m32r_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */ + m32r_cmds.setmem.term = NULL; /* setmem.term */ + m32r_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */ + m32r_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */ + m32r_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */ + m32r_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */ + m32r_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */ + m32r_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */ + m32r_cmds.getmem.term = NULL; /* getmem.term */ + m32r_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */ + m32r_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */ + m32r_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */ + m32r_cmds.setreg.term = NULL; /* setreg.term */ + m32r_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */ + m32r_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */ + m32r_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */ + m32r_cmds.getreg.term = NULL; /* getreg.term */ + m32r_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */ + m32r_cmds.dump_registers = ".reg\r"; /* dump_registers */ + m32r_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */ + m32r_cmds.supply_register = m32r_supply_register; /* supply_register */ + m32r_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */ + m32r_cmds.load = NULL; /* download command */ + m32r_cmds.loadresp = NULL; /* load response */ + m32r_cmds.prompt = "ok "; /* monitor command prompt */ + m32r_cmds.line_term = "\r"; /* end-of-line terminator */ + m32r_cmds.cmd_end = NULL; /* optional command terminator */ + m32r_cmds.target = &m32r_ops; /* target operations */ + m32r_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */ + m32r_cmds.regnames = m32r_regnames; /* registers names */ + m32r_cmds.magic = MONITOR_OPS_MAGIC; /* magic */ +} /* init_m32r_cmds */ + +static void +m32r_open (char *args, int from_tty) +{ + monitor_open (args, &m32r_cmds, from_tty); +} + +/* Mon2000 monitor (MSA2000 board) */ + +static struct target_ops mon2000_ops; +static struct monitor_ops mon2000_cmds; + +static void +init_mon2000_cmds (void) +{ + mon2000_cmds.flags = MO_CLR_BREAK_USES_ADDR | MO_REGISTER_VALUE_FIRST; + mon2000_cmds.init = m32r_inits; /* Init strings */ + mon2000_cmds.cont = "go\r"; /* continue command */ + mon2000_cmds.step = "step\r"; /* single step */ + mon2000_cmds.stop = NULL; /* interrupt command */ + mon2000_cmds.set_break = "%x +bp\r"; /* set a breakpoint */ + mon2000_cmds.clr_break = "%x -bp\r"; /* clear a breakpoint */ + mon2000_cmds.clr_all_break = "bpoff\r"; /* clear all breakpoints */ + mon2000_cmds.fill = "%x %x %x fill\r"; /* fill (start length val) */ + mon2000_cmds.setmem.cmdb = "%x 1 %x fill\r"; /* setmem.cmdb (addr, value) */ + mon2000_cmds.setmem.cmdw = "%x 1 %x fillh\r"; /* setmem.cmdw (addr, value) */ + mon2000_cmds.setmem.cmdl = "%x 1 %x fillw\r"; /* setmem.cmdl (addr, value) */ + mon2000_cmds.setmem.cmdll = NULL; /* setmem.cmdll (addr, value) */ + mon2000_cmds.setmem.resp_delim = NULL; /* setmem.resp_delim */ + mon2000_cmds.setmem.term = NULL; /* setmem.term */ + mon2000_cmds.setmem.term_cmd = NULL; /* setmem.term_cmd */ + mon2000_cmds.getmem.cmdb = "%x %x dump\r"; /* getmem.cmdb (addr, len) */ + mon2000_cmds.getmem.cmdw = NULL; /* getmem.cmdw (addr, len) */ + mon2000_cmds.getmem.cmdl = NULL; /* getmem.cmdl (addr, len) */ + mon2000_cmds.getmem.cmdll = NULL; /* getmem.cmdll (addr, len) */ + mon2000_cmds.getmem.resp_delim = ": "; /* getmem.resp_delim */ + mon2000_cmds.getmem.term = NULL; /* getmem.term */ + mon2000_cmds.getmem.term_cmd = NULL; /* getmem.term_cmd */ + mon2000_cmds.setreg.cmd = "%x to %%%s\r"; /* setreg.cmd (name, value) */ + mon2000_cmds.setreg.resp_delim = NULL; /* setreg.resp_delim */ + mon2000_cmds.setreg.term = NULL; /* setreg.term */ + mon2000_cmds.setreg.term_cmd = NULL; /* setreg.term_cmd */ + mon2000_cmds.getreg.cmd = NULL; /* getreg.cmd (name) */ + mon2000_cmds.getreg.resp_delim = NULL; /* getreg.resp_delim */ + mon2000_cmds.getreg.term = NULL; /* getreg.term */ + mon2000_cmds.getreg.term_cmd = NULL; /* getreg.term_cmd */ + mon2000_cmds.dump_registers = ".reg\r"; /* dump_registers */ + mon2000_cmds.register_pattern = "\\(\\w+\\) += \\([0-9a-fA-F]+\\b\\)"; /* register_pattern */ + mon2000_cmds.supply_register = m32r_supply_register; /* supply_register */ + mon2000_cmds.load_routine = NULL; /* load_routine (defaults to SRECs) */ + mon2000_cmds.load = NULL; /* download command */ + mon2000_cmds.loadresp = NULL; /* load response */ + mon2000_cmds.prompt = "Mon2000>"; /* monitor command prompt */ + mon2000_cmds.line_term = "\r"; /* end-of-line terminator */ + mon2000_cmds.cmd_end = NULL; /* optional command terminator */ + mon2000_cmds.target = &mon2000_ops; /* target operations */ + mon2000_cmds.stopbits = SERIAL_1_STOPBITS; /* number of stop bits */ + mon2000_cmds.regnames = m32r_regnames; /* registers names */ + mon2000_cmds.magic = MONITOR_OPS_MAGIC; /* magic */ +} /* init_mon2000_cmds */ + +static void +mon2000_open (char *args, int from_tty) +{ + monitor_open (args, &mon2000_cmds, from_tty); +} + +/* Function: set_board_address + Tell the BootOne monitor what it's ethernet IP address is. */ + +static void +m32r_set_board_address (char *args, int from_tty) +{ + int resp_len; + char buf[1024]; + + if (args && *args) + { + monitor_printf ("ulip %s\n", args); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + /* now parse the result for success */ + } + else + error ("Requires argument (IP address for M32R-EVA board)"); +} + +/* Function: set_server_address + Tell the BootOne monitor what gdb's ethernet IP address is. */ + +static void +m32r_set_server_address (char *args, int from_tty) +{ + int resp_len; + char buf[1024]; + + if (args && *args) + { + monitor_printf ("uhip %s\n", args); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + /* now parse the result for success */ + } + else + error ("Requires argument (IP address of GDB's host computer)"); +} + +/* Function: set_download_path + Tell the BootOne monitor the default path for downloadable SREC files. */ + +static void +m32r_set_download_path (char *args, int from_tty) +{ + int resp_len; + char buf[1024]; + + if (args && *args) + { + monitor_printf ("up %s\n", args); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + /* now parse the result for success */ + } + else + error ("Requires argument (default path for downloadable SREC files)"); +} + +static void +m32r_upload_command (char *args, int from_tty) +{ + bfd *abfd; + asection *s; + time_t start_time, end_time; /* for timing of download */ + int resp_len, data_count = 0; + char buf[1024]; + struct hostent *hostent; + struct in_addr inet_addr; + + /* first check to see if there's an ethernet port! */ + monitor_printf ("ust\r"); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); + if (!strchr (buf, ':')) + error ("No ethernet connection!"); + + if (board_addr == 0) + { + /* scan second colon in the output from the "ust" command */ + char *myIPaddress = strchr (strchr (buf, ':') + 1, ':') + 1; + + while (isspace (*myIPaddress)) + myIPaddress++; + + if (!strncmp (myIPaddress, "0.0.", 4)) /* empty */ + error + ("Please use 'set board-address' to set the M32R-EVA board's IP address."); + if (strchr (myIPaddress, '(')) + *(strchr (myIPaddress, '(')) = '\0'; /* delete trailing junk */ + board_addr = xstrdup (myIPaddress); + } + if (server_addr == 0) + { + buf[0] = 0; + gethostname (buf, sizeof (buf)); + if (buf[0] != 0) + hostent = gethostbyname (buf); + if (hostent != 0) + { +#if 1 + memcpy (&inet_addr.s_addr, hostent->h_addr, + sizeof (inet_addr.s_addr)); + server_addr = (char *) inet_ntoa (inet_addr); +#else + server_addr = (char *) inet_ntoa (hostent->h_addr); +#endif + } + if (server_addr == 0) /* failed? */ + error + ("Need to know gdb host computer's IP address (use 'set server-address')"); + } + + if (args == 0 || args[0] == 0) /* no args: upload the current file */ + args = get_exec_file (1); + + if (args[0] != '/' && download_path == 0) + { + if (current_directory) + download_path = xstrdup (current_directory); + else + error + ("Need to know default download path (use 'set download-path')"); + } + + start_time = time (NULL); + monitor_printf ("uhip %s\r", server_addr); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ + monitor_printf ("ulip %s\r", board_addr); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ + if (args[0] != '/') + monitor_printf ("up %s\r", download_path); /* use default path */ + else + monitor_printf ("up\r"); /* rooted filename/path */ + resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ + + if (strrchr (args, '.') && !strcmp (strrchr (args, '.'), ".srec")) + monitor_printf ("ul %s\r", args); + else /* add ".srec" suffix */ + monitor_printf ("ul %s.srec\r", args); + resp_len = monitor_expect_prompt (buf, sizeof (buf)); /* parse result? */ + + if (buf[0] == 0 || strstr (buf, "complete") == 0) + error + ("Upload file not found: %s.srec\nCheck IP addresses and download path.", + args); + else + printf_filtered (" -- Ethernet load complete.\n"); + + end_time = time (NULL); + abfd = bfd_openr (args, 0); + if (abfd != NULL) + { /* Download is done -- print section statistics */ + if (bfd_check_format (abfd, bfd_object) == 0) + { + printf_filtered ("File is not an object file\n"); + } + for (s = abfd->sections; s; s = s->next) + if (s->flags & SEC_LOAD) + { + bfd_size_type section_size = bfd_section_size (abfd, s); + bfd_vma section_base = bfd_section_lma (abfd, s); + unsigned int buffer; + + data_count += section_size; + + printf_filtered ("Loading section %s, size 0x%lx lma ", + bfd_section_name (abfd, s), section_size); + print_address_numeric (section_base, 1, gdb_stdout); + printf_filtered ("\n"); + gdb_flush (gdb_stdout); + } + /* Finally, make the PC point at the start address */ + write_pc (bfd_get_start_address (abfd)); + report_transfer_performance (data_count, start_time, end_time); + printf_filtered ("Start address 0x%lx\n", bfd_get_start_address (abfd)); + } + inferior_ptid = null_ptid; /* No process now */ + + /* This is necessary because many things were based on the PC at the + time that we attached to the monitor, which is no longer valid + now that we have loaded new code (and just changed the PC). + Another way to do this might be to call normal_stop, except that + the stack may not be valid, and things would get horribly + confused... */ + + clear_symtab_users (); +} + +void +_initialize_m32r_rom (void) +{ + /* Initialize m32r RevC monitor target */ + init_m32r_cmds (); + init_monitor_ops (&m32r_ops); + + m32r_ops.to_shortname = "m32r"; + m32r_ops.to_longname = "m32r monitor"; + m32r_ops.to_load = m32r_load_gen; /* monitor lacks a download command */ + m32r_ops.to_doc = "Debug via the m32r monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + m32r_ops.to_open = m32r_open; + add_target (&m32r_ops); + + /* Initialize mon2000 monitor target */ + init_mon2000_cmds (); + init_monitor_ops (&mon2000_ops); + + mon2000_ops.to_shortname = "mon2000"; + mon2000_ops.to_longname = "Mon2000 monitor"; + mon2000_ops.to_load = m32r_load_gen; /* monitor lacks a download command */ + mon2000_ops.to_doc = "Debug via the Mon2000 monitor.\n\ +Specify the serial device it is connected to (e.g. /dev/ttya)."; + mon2000_ops.to_open = mon2000_open; + add_target (&mon2000_ops); + + add_show_from_set + (add_set_cmd ("download-path", class_obscure, var_string, + (char *) &download_path, + "Set the default path for downloadable SREC files.", + &setlist), &showlist); + + add_show_from_set + (add_set_cmd ("board-address", class_obscure, var_string, + (char *) &board_addr, + "Set IP address for M32R-EVA target board.", + &setlist), &showlist); + + add_show_from_set + (add_set_cmd ("server-address", class_obscure, var_string, + (char *) &server_addr, + "Set IP address for download server (GDB's host computer).", + &setlist), &showlist); + + add_com ("upload", class_obscure, m32r_upload_command, + "Upload the srec file via the monitor's Ethernet upload capability."); + + add_com ("tload", class_obscure, m32r_load, "test upload command."); +} diff --git a/gdb/m32r-stub.c b/gdb/m32r-stub.c index d9be3eb84e6..c7033ea17a3 100644 --- a/gdb/m32r-stub.c +++ b/gdb/m32r-stub.c @@ -1,1718 +1,1779 @@ -// OBSOLETE /**************************************************************************** -// OBSOLETE -// OBSOLETE THIS SOFTWARE IS NOT COPYRIGHTED -// OBSOLETE -// OBSOLETE HP offers the following for use in the public domain. HP makes no -// OBSOLETE warranty with regard to the software or it's performance and the -// OBSOLETE user accepts the software "AS IS" with all faults. -// OBSOLETE -// OBSOLETE HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD -// OBSOLETE TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES -// OBSOLETE OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -// OBSOLETE -// OBSOLETE ****************************************************************************/ -// OBSOLETE -// OBSOLETE /**************************************************************************** -// OBSOLETE * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ -// OBSOLETE * -// OBSOLETE * Module name: remcom.c $ -// OBSOLETE * Revision: 1.34 $ -// OBSOLETE * Date: 91/03/09 12:29:49 $ -// OBSOLETE * Contributor: Lake Stevens Instrument Division$ -// OBSOLETE * -// OBSOLETE * Description: low level support for gdb debugger. $ -// OBSOLETE * -// OBSOLETE * Considerations: only works on target hardware $ -// OBSOLETE * -// OBSOLETE * Written by: Glenn Engel $ -// OBSOLETE * ModuleState: Experimental $ -// OBSOLETE * -// OBSOLETE * NOTES: See Below $ -// OBSOLETE * -// OBSOLETE * Modified for M32R by Michael Snyder, Cygnus Support. -// OBSOLETE * -// OBSOLETE * To enable debugger support, two things need to happen. One, a -// OBSOLETE * call to set_debug_traps() is necessary in order to allow any breakpoints -// OBSOLETE * or error conditions to be properly intercepted and reported to gdb. -// OBSOLETE * Two, a breakpoint needs to be generated to begin communication. This -// OBSOLETE * is most easily accomplished by a call to breakpoint(). Breakpoint() -// OBSOLETE * simulates a breakpoint by executing a trap #1. -// OBSOLETE * -// OBSOLETE * The external function exceptionHandler() is -// OBSOLETE * used to attach a specific handler to a specific M32R vector number. -// OBSOLETE * It should use the same privilege level it runs at. It should -// OBSOLETE * install it as an interrupt gate so that interrupts are masked -// OBSOLETE * while the handler runs. -// OBSOLETE * -// OBSOLETE * Because gdb will sometimes write to the stack area to execute function -// OBSOLETE * calls, this program cannot rely on using the supervisor stack so it -// OBSOLETE * uses it's own stack area reserved in the int array remcomStack. -// OBSOLETE * -// OBSOLETE ************* -// OBSOLETE * -// OBSOLETE * The following gdb commands are supported: -// OBSOLETE * -// OBSOLETE * command function Return value -// OBSOLETE * -// OBSOLETE * g return the value of the CPU registers hex data or ENN -// OBSOLETE * G set the value of the CPU registers OK or ENN -// OBSOLETE * -// OBSOLETE * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN -// OBSOLETE * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN -// OBSOLETE * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN -// OBSOLETE * AA..AA -// OBSOLETE * -// OBSOLETE * c Resume at current address SNN ( signal NN) -// OBSOLETE * cAA..AA Continue at address AA..AA SNN -// OBSOLETE * -// OBSOLETE * s Step one instruction SNN -// OBSOLETE * sAA..AA Step one instruction from AA..AA SNN -// OBSOLETE * -// OBSOLETE * k kill -// OBSOLETE * -// OBSOLETE * ? What was the last sigval ? SNN (signal NN) -// OBSOLETE * -// OBSOLETE * All commands and responses are sent with a packet which includes a -// OBSOLETE * checksum. A packet consists of -// OBSOLETE * -// OBSOLETE * $#. -// OBSOLETE * -// OBSOLETE * where -// OBSOLETE * :: -// OBSOLETE * :: > -// OBSOLETE * -// OBSOLETE * When a packet is received, it is first acknowledged with either '+' or '-'. -// OBSOLETE * '+' indicates a successful transfer. '-' indicates a failed transfer. -// OBSOLETE * -// OBSOLETE * Example: -// OBSOLETE * -// OBSOLETE * Host: Reply: -// OBSOLETE * $m0,10#2a +$00010203040506070809101112131415#42 -// OBSOLETE * -// OBSOLETE ****************************************************************************/ -// OBSOLETE -// OBSOLETE -// OBSOLETE /************************************************************************ -// OBSOLETE * -// OBSOLETE * external low-level support routines -// OBSOLETE */ -// OBSOLETE extern void putDebugChar(); /* write a single character */ -// OBSOLETE extern int getDebugChar(); /* read and return a single char */ -// OBSOLETE extern void exceptionHandler(); /* assign an exception handler */ -// OBSOLETE -// OBSOLETE /***************************************************************************** -// OBSOLETE * BUFMAX defines the maximum number of characters in inbound/outbound buffers -// OBSOLETE * at least NUMREGBYTES*2 are needed for register packets -// OBSOLETE */ -// OBSOLETE #define BUFMAX 400 -// OBSOLETE -// OBSOLETE static char initialized; /* boolean flag. != 0 means we've been initialized */ -// OBSOLETE -// OBSOLETE int remote_debug; -// OBSOLETE /* debug > 0 prints ill-formed commands in valid packets & checksum errors */ -// OBSOLETE -// OBSOLETE static const unsigned char hexchars[]="0123456789abcdef"; -// OBSOLETE -// OBSOLETE #define NUMREGS 24 -// OBSOLETE -// OBSOLETE /* Number of bytes of registers. */ -// OBSOLETE #define NUMREGBYTES (NUMREGS * 4) -// OBSOLETE enum regnames { R0, R1, R2, R3, R4, R5, R6, R7, -// OBSOLETE R8, R9, R10, R11, R12, R13, R14, R15, -// OBSOLETE PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH }; -// OBSOLETE -// OBSOLETE enum SYS_calls { -// OBSOLETE SYS_null, -// OBSOLETE SYS_exit, -// OBSOLETE SYS_open, -// OBSOLETE SYS_close, -// OBSOLETE SYS_read, -// OBSOLETE SYS_write, -// OBSOLETE SYS_lseek, -// OBSOLETE SYS_unlink, -// OBSOLETE SYS_getpid, -// OBSOLETE SYS_kill, -// OBSOLETE SYS_fstat, -// OBSOLETE SYS_sbrk, -// OBSOLETE SYS_fork, -// OBSOLETE SYS_execve, -// OBSOLETE SYS_wait4, -// OBSOLETE SYS_link, -// OBSOLETE SYS_chdir, -// OBSOLETE SYS_stat, -// OBSOLETE SYS_utime, -// OBSOLETE SYS_chown, -// OBSOLETE SYS_chmod, -// OBSOLETE SYS_time, -// OBSOLETE SYS_pipe }; -// OBSOLETE -// OBSOLETE static int registers[NUMREGS]; -// OBSOLETE -// OBSOLETE #define STACKSIZE 8096 -// OBSOLETE static unsigned char remcomInBuffer[BUFMAX]; -// OBSOLETE static unsigned char remcomOutBuffer[BUFMAX]; -// OBSOLETE static int remcomStack[STACKSIZE/sizeof(int)]; -// OBSOLETE static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; -// OBSOLETE -// OBSOLETE static unsigned int save_vectors[18]; /* previous exception vectors */ -// OBSOLETE -// OBSOLETE /* Indicate to caller of mem2hex or hex2mem that there has been an error. */ -// OBSOLETE static volatile int mem_err = 0; -// OBSOLETE -// OBSOLETE /* Store the vector number here (since GDB only gets the signal -// OBSOLETE number through the usual means, and that's not very specific). */ -// OBSOLETE int gdb_m32r_vector = -1; -// OBSOLETE -// OBSOLETE #if 0 -// OBSOLETE #include "syscall.h" /* for SYS_exit, SYS_write etc. */ -// OBSOLETE #endif -// OBSOLETE -// OBSOLETE /* Global entry points: -// OBSOLETE */ -// OBSOLETE -// OBSOLETE extern void handle_exception(int); -// OBSOLETE extern void set_debug_traps(void); -// OBSOLETE extern void breakpoint(void); -// OBSOLETE -// OBSOLETE /* Local functions: -// OBSOLETE */ -// OBSOLETE -// OBSOLETE static int computeSignal(int); -// OBSOLETE static void putpacket(unsigned char *); -// OBSOLETE static unsigned char *getpacket(void); -// OBSOLETE -// OBSOLETE static unsigned char *mem2hex(unsigned char *, unsigned char *, int, int); -// OBSOLETE static unsigned char *hex2mem(unsigned char *, unsigned char *, int, int); -// OBSOLETE static int hexToInt(unsigned char **, int *); -// OBSOLETE static unsigned char *bin2mem(unsigned char *, unsigned char *, int, int); -// OBSOLETE static void stash_registers(void); -// OBSOLETE static void restore_registers(void); -// OBSOLETE static int prepare_to_step(int); -// OBSOLETE static int finish_from_step(void); -// OBSOLETE static unsigned long crc32 (unsigned char *, int, unsigned long); -// OBSOLETE -// OBSOLETE static void gdb_error(char *, char *); -// OBSOLETE static int gdb_putchar(int), gdb_puts(char *), gdb_write(char *, int); -// OBSOLETE -// OBSOLETE static unsigned char *strcpy (unsigned char *, const unsigned char *); -// OBSOLETE static int strlen (const unsigned char *); -// OBSOLETE -// OBSOLETE /* -// OBSOLETE * This function does all command procesing for interfacing to gdb. -// OBSOLETE */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE handle_exception(int exceptionVector) -// OBSOLETE { -// OBSOLETE int sigval, stepping; -// OBSOLETE int addr, length, i; -// OBSOLETE unsigned char * ptr; -// OBSOLETE unsigned char buf[16]; -// OBSOLETE int binary; -// OBSOLETE -// OBSOLETE /* Do not call finish_from_step() if this is not a trap #1 -// OBSOLETE * (breakpoint trap). Without this check, the finish_from_step() -// OBSOLETE * might interpret a system call trap as a single step trap. This -// OBSOLETE * can happen if: the stub receives 's' and exits, but an interrupt -// OBSOLETE * was pending; the interrupt is now handled and causes the stub to -// OBSOLETE * be reentered because some function makes a system call. -// OBSOLETE */ -// OBSOLETE if (exceptionVector == 1) /* Trap exception? */ -// OBSOLETE if (!finish_from_step()) /* Go see if stepping state needs update. */ -// OBSOLETE return; /* "false step": let the target continue */ -// OBSOLETE -// OBSOLETE gdb_m32r_vector = exceptionVector; -// OBSOLETE -// OBSOLETE if (remote_debug) -// OBSOLETE { -// OBSOLETE mem2hex((unsigned char *) &exceptionVector, buf, 4, 0); -// OBSOLETE gdb_error("Handle exception %s, ", buf); -// OBSOLETE mem2hex((unsigned char *) ®isters[PC], buf, 4, 0); -// OBSOLETE gdb_error("PC == 0x%s\n", buf); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* reply to host that an exception has occurred */ -// OBSOLETE sigval = computeSignal( exceptionVector ); -// OBSOLETE -// OBSOLETE ptr = remcomOutBuffer; -// OBSOLETE -// OBSOLETE *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ -// OBSOLETE *ptr++ = hexchars[sigval >> 4]; -// OBSOLETE *ptr++ = hexchars[sigval & 0xf]; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[PC >> 4]; -// OBSOLETE *ptr++ = hexchars[PC & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[PC], ptr, 4, 0); /* PC */ -// OBSOLETE *ptr++ = ';'; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[R13 >> 4]; -// OBSOLETE *ptr++ = hexchars[R13 & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[R13], ptr, 4, 0); /* FP */ -// OBSOLETE *ptr++ = ';'; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[R15 >> 4]; -// OBSOLETE *ptr++ = hexchars[R15 & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[R15], ptr, 4, 0); /* SP */ -// OBSOLETE *ptr++ = ';'; -// OBSOLETE *ptr++ = 0; -// OBSOLETE -// OBSOLETE if (exceptionVector == 0) /* simulated SYS call stuff */ -// OBSOLETE { -// OBSOLETE mem2hex((unsigned char *) ®isters[PC], buf, 4, 0); -// OBSOLETE switch (registers[R0]) { -// OBSOLETE case SYS_exit: -// OBSOLETE gdb_error("Target program has exited at %s\n", buf); -// OBSOLETE ptr = remcomOutBuffer; -// OBSOLETE *ptr++ = 'W'; -// OBSOLETE sigval = registers[R1] & 0xff; -// OBSOLETE *ptr++ = hexchars[sigval >> 4]; -// OBSOLETE *ptr++ = hexchars[sigval & 0xf]; -// OBSOLETE *ptr++ = 0; -// OBSOLETE break; -// OBSOLETE case SYS_open: -// OBSOLETE gdb_error("Target attempts SYS_open call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_close: -// OBSOLETE gdb_error("Target attempts SYS_close call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_read: -// OBSOLETE gdb_error("Target attempts SYS_read call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_write: -// OBSOLETE if (registers[R1] == 1 || /* write to stdout */ -// OBSOLETE registers[R1] == 2) /* write to stderr */ -// OBSOLETE { /* (we can do that) */ -// OBSOLETE registers[R0] = gdb_write((void *) registers[R2], registers[R3]); -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE gdb_error("Target attempts SYS_write call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_lseek: -// OBSOLETE gdb_error("Target attempts SYS_lseek call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_unlink: -// OBSOLETE gdb_error("Target attempts SYS_unlink call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_getpid: -// OBSOLETE gdb_error("Target attempts SYS_getpid call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_kill: -// OBSOLETE gdb_error("Target attempts SYS_kill call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE case SYS_fstat: -// OBSOLETE gdb_error("Target attempts SYS_fstat call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE default: -// OBSOLETE gdb_error("Target attempts unknown SYS call at %s\n", buf); -// OBSOLETE break; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE putpacket(remcomOutBuffer); -// OBSOLETE -// OBSOLETE stepping = 0; -// OBSOLETE -// OBSOLETE while (1==1) { -// OBSOLETE remcomOutBuffer[0] = 0; -// OBSOLETE ptr = getpacket(); -// OBSOLETE binary = 0; -// OBSOLETE switch (*ptr++) { -// OBSOLETE default: /* Unknown code. Return an empty reply message. */ -// OBSOLETE break; -// OBSOLETE case 'R': -// OBSOLETE if (hexToInt (&ptr, &addr)) -// OBSOLETE registers[PC] = addr; -// OBSOLETE strcpy(remcomOutBuffer, "OK"); -// OBSOLETE break; -// OBSOLETE case '!': -// OBSOLETE strcpy(remcomOutBuffer, "OK"); -// OBSOLETE break; -// OBSOLETE case 'X': /* XAA..AA,LLLL:#cs */ -// OBSOLETE binary = 1; -// OBSOLETE case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ -// OBSOLETE /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ -// OBSOLETE { -// OBSOLETE if (hexToInt(&ptr,&addr)) -// OBSOLETE if (*(ptr++) == ',') -// OBSOLETE if (hexToInt(&ptr,&length)) -// OBSOLETE if (*(ptr++) == ':') -// OBSOLETE { -// OBSOLETE mem_err = 0; -// OBSOLETE if (binary) -// OBSOLETE bin2mem (ptr, (unsigned char *) addr, length, 1); -// OBSOLETE else -// OBSOLETE hex2mem(ptr, (unsigned char*) addr, length, 1); -// OBSOLETE if (mem_err) { -// OBSOLETE strcpy (remcomOutBuffer, "E03"); -// OBSOLETE gdb_error ("memory fault", ""); -// OBSOLETE } else { -// OBSOLETE strcpy(remcomOutBuffer,"OK"); -// OBSOLETE } -// OBSOLETE ptr = 0; -// OBSOLETE } -// OBSOLETE if (ptr) -// OBSOLETE { -// OBSOLETE strcpy(remcomOutBuffer,"E02"); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE break; -// OBSOLETE case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ -// OBSOLETE /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ -// OBSOLETE if (hexToInt(&ptr,&addr)) -// OBSOLETE if (*(ptr++) == ',') -// OBSOLETE if (hexToInt(&ptr,&length)) -// OBSOLETE { -// OBSOLETE ptr = 0; -// OBSOLETE mem_err = 0; -// OBSOLETE mem2hex((unsigned char*) addr, remcomOutBuffer, length, 1); -// OBSOLETE if (mem_err) { -// OBSOLETE strcpy (remcomOutBuffer, "E03"); -// OBSOLETE gdb_error ("memory fault", ""); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE if (ptr) -// OBSOLETE { -// OBSOLETE strcpy(remcomOutBuffer,"E01"); -// OBSOLETE } -// OBSOLETE break; -// OBSOLETE case '?': -// OBSOLETE remcomOutBuffer[0] = 'S'; -// OBSOLETE remcomOutBuffer[1] = hexchars[sigval >> 4]; -// OBSOLETE remcomOutBuffer[2] = hexchars[sigval % 16]; -// OBSOLETE remcomOutBuffer[3] = 0; -// OBSOLETE break; -// OBSOLETE case 'd': -// OBSOLETE remote_debug = !(remote_debug); /* toggle debug flag */ -// OBSOLETE break; -// OBSOLETE case 'g': /* return the value of the CPU registers */ -// OBSOLETE mem2hex((unsigned char*) registers, remcomOutBuffer, NUMREGBYTES, 0); -// OBSOLETE break; -// OBSOLETE case 'P': /* set the value of a single CPU register - return OK */ -// OBSOLETE { -// OBSOLETE int regno; -// OBSOLETE -// OBSOLETE if (hexToInt (&ptr, ®no) && *ptr++ == '=') -// OBSOLETE if (regno >= 0 && regno < NUMREGS) -// OBSOLETE { -// OBSOLETE int stackmode; -// OBSOLETE -// OBSOLETE hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0); -// OBSOLETE /* -// OBSOLETE * Since we just changed a single CPU register, let's -// OBSOLETE * make sure to keep the several stack pointers consistant. -// OBSOLETE */ -// OBSOLETE stackmode = registers[PSW] & 0x80; -// OBSOLETE if (regno == R15) /* stack pointer changed */ -// OBSOLETE { /* need to change SPI or SPU */ -// OBSOLETE if (stackmode == 0) -// OBSOLETE registers[SPI] = registers[R15]; -// OBSOLETE else -// OBSOLETE registers[SPU] = registers[R15]; -// OBSOLETE } -// OBSOLETE else if (regno == SPU) /* "user" stack pointer changed */ -// OBSOLETE { -// OBSOLETE if (stackmode != 0) /* stack in user mode: copy SP */ -// OBSOLETE registers[R15] = registers[SPU]; -// OBSOLETE } -// OBSOLETE else if (regno == SPI) /* "interrupt" stack pointer changed */ -// OBSOLETE { -// OBSOLETE if (stackmode == 0) /* stack in interrupt mode: copy SP */ -// OBSOLETE registers[R15] = registers[SPI]; -// OBSOLETE } -// OBSOLETE else if (regno == PSW) /* stack mode may have changed! */ -// OBSOLETE { /* force SP to either SPU or SPI */ -// OBSOLETE if (stackmode == 0) /* stack in user mode */ -// OBSOLETE registers[R15] = registers[SPI]; -// OBSOLETE else /* stack in interrupt mode */ -// OBSOLETE registers[R15] = registers[SPU]; -// OBSOLETE } -// OBSOLETE strcpy (remcomOutBuffer, "OK"); -// OBSOLETE break; -// OBSOLETE } -// OBSOLETE strcpy (remcomOutBuffer, "E01"); -// OBSOLETE break; -// OBSOLETE } -// OBSOLETE case 'G': /* set the value of the CPU registers - return OK */ -// OBSOLETE hex2mem(ptr, (unsigned char*) registers, NUMREGBYTES, 0); -// OBSOLETE strcpy(remcomOutBuffer,"OK"); -// OBSOLETE break; -// OBSOLETE case 's': /* sAA..AA Step one instruction from AA..AA(optional) */ -// OBSOLETE stepping = 1; -// OBSOLETE case 'c': /* cAA..AA Continue from address AA..AA(optional) */ -// OBSOLETE /* try to read optional parameter, pc unchanged if no parm */ -// OBSOLETE if (hexToInt(&ptr,&addr)) -// OBSOLETE registers[ PC ] = addr; -// OBSOLETE -// OBSOLETE if (stepping) /* single-stepping */ -// OBSOLETE { -// OBSOLETE if (!prepare_to_step(0)) /* set up for single-step */ -// OBSOLETE { -// OBSOLETE /* prepare_to_step has already emulated the target insn: -// OBSOLETE Send SIGTRAP to gdb, don't resume the target at all. */ -// OBSOLETE ptr = remcomOutBuffer; -// OBSOLETE *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */ -// OBSOLETE *ptr++ = '0'; -// OBSOLETE *ptr++ = '5'; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[PC >> 4]; /* send PC */ -// OBSOLETE *ptr++ = hexchars[PC & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[PC], ptr, 4, 0); -// OBSOLETE *ptr++ = ';'; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[R13 >> 4]; /* send FP */ -// OBSOLETE *ptr++ = hexchars[R13 & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[R13], ptr, 4, 0); -// OBSOLETE *ptr++ = ';'; -// OBSOLETE -// OBSOLETE *ptr++ = hexchars[R15 >> 4]; /* send SP */ -// OBSOLETE *ptr++ = hexchars[R15 & 0xf]; -// OBSOLETE *ptr++ = ':'; -// OBSOLETE ptr = mem2hex((unsigned char *)®isters[R15], ptr, 4, 0); -// OBSOLETE *ptr++ = ';'; -// OBSOLETE *ptr++ = 0; -// OBSOLETE -// OBSOLETE break; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE else /* continuing, not single-stepping */ -// OBSOLETE { -// OBSOLETE /* OK, about to do a "continue". First check to see if the -// OBSOLETE target pc is on an odd boundary (second instruction in the -// OBSOLETE word). If so, we must do a single-step first, because -// OBSOLETE ya can't jump or return back to an odd boundary! */ -// OBSOLETE if ((registers[PC] & 2) != 0) -// OBSOLETE prepare_to_step(1); -// OBSOLETE } -// OBSOLETE -// OBSOLETE return; -// OBSOLETE -// OBSOLETE case 'D': /* Detach */ -// OBSOLETE #if 0 -// OBSOLETE /* I am interpreting this to mean, release the board from control -// OBSOLETE by the remote stub. To do this, I am restoring the original -// OBSOLETE (or at least previous) exception vectors. -// OBSOLETE */ -// OBSOLETE for (i = 0; i < 18; i++) -// OBSOLETE exceptionHandler (i, save_vectors[i]); -// OBSOLETE putpacket ("OK"); -// OBSOLETE return; /* continue the inferior */ -// OBSOLETE #else -// OBSOLETE strcpy(remcomOutBuffer,"OK"); -// OBSOLETE break; -// OBSOLETE #endif -// OBSOLETE case 'q': -// OBSOLETE if (*ptr++ == 'C' && -// OBSOLETE *ptr++ == 'R' && -// OBSOLETE *ptr++ == 'C' && -// OBSOLETE *ptr++ == ':') -// OBSOLETE { -// OBSOLETE unsigned long start, len, our_crc; -// OBSOLETE -// OBSOLETE if (hexToInt (&ptr, (int *) &start) && -// OBSOLETE *ptr++ == ',' && -// OBSOLETE hexToInt (&ptr, (int *) &len)) -// OBSOLETE { -// OBSOLETE remcomOutBuffer[0] = 'C'; -// OBSOLETE our_crc = crc32 ((unsigned char *) start, len, 0xffffffff); -// OBSOLETE mem2hex ((char *) &our_crc, -// OBSOLETE &remcomOutBuffer[1], -// OBSOLETE sizeof (long), -// OBSOLETE 0); -// OBSOLETE } /* else do nothing */ -// OBSOLETE } /* else do nothing */ -// OBSOLETE break; -// OBSOLETE -// OBSOLETE case 'k': /* kill the program */ -// OBSOLETE continue; -// OBSOLETE } /* switch */ -// OBSOLETE -// OBSOLETE /* reply to the request */ -// OBSOLETE putpacket(remcomOutBuffer); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* qCRC support */ -// OBSOLETE -// OBSOLETE /* Table used by the crc32 function to calcuate the checksum. */ -// OBSOLETE static unsigned long crc32_table[256] = {0, 0}; -// OBSOLETE -// OBSOLETE static unsigned long -// OBSOLETE crc32 (unsigned char *buf, int len, unsigned long crc) -// OBSOLETE { -// OBSOLETE if (! crc32_table[1]) -// OBSOLETE { -// OBSOLETE /* Initialize the CRC table and the decoding table. */ -// OBSOLETE int i, j; -// OBSOLETE unsigned long c; -// OBSOLETE -// OBSOLETE for (i = 0; i < 256; i++) -// OBSOLETE { -// OBSOLETE for (c = i << 24, j = 8; j > 0; --j) -// OBSOLETE c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); -// OBSOLETE crc32_table[i] = c; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE while (len--) -// OBSOLETE { -// OBSOLETE crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; -// OBSOLETE buf++; -// OBSOLETE } -// OBSOLETE return crc; -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE hex (unsigned char ch) -// OBSOLETE { -// OBSOLETE if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10); -// OBSOLETE if ((ch >= '0') && (ch <= '9')) return (ch-'0'); -// OBSOLETE if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10); -// OBSOLETE return (-1); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* scan for the sequence $# */ -// OBSOLETE -// OBSOLETE unsigned char * -// OBSOLETE getpacket (void) -// OBSOLETE { -// OBSOLETE unsigned char *buffer = &remcomInBuffer[0]; -// OBSOLETE unsigned char checksum; -// OBSOLETE unsigned char xmitcsum; -// OBSOLETE int count; -// OBSOLETE char ch; -// OBSOLETE -// OBSOLETE while (1) -// OBSOLETE { -// OBSOLETE /* wait around for the start character, ignore all other characters */ -// OBSOLETE while ((ch = getDebugChar ()) != '$') -// OBSOLETE ; -// OBSOLETE -// OBSOLETE retry: -// OBSOLETE checksum = 0; -// OBSOLETE xmitcsum = -1; -// OBSOLETE count = 0; -// OBSOLETE -// OBSOLETE /* now, read until a # or end of buffer is found */ -// OBSOLETE while (count < BUFMAX) -// OBSOLETE { -// OBSOLETE ch = getDebugChar (); -// OBSOLETE if (ch == '$') -// OBSOLETE goto retry; -// OBSOLETE if (ch == '#') -// OBSOLETE break; -// OBSOLETE checksum = checksum + ch; -// OBSOLETE buffer[count] = ch; -// OBSOLETE count = count + 1; -// OBSOLETE } -// OBSOLETE buffer[count] = 0; -// OBSOLETE -// OBSOLETE if (ch == '#') -// OBSOLETE { -// OBSOLETE ch = getDebugChar (); -// OBSOLETE xmitcsum = hex (ch) << 4; -// OBSOLETE ch = getDebugChar (); -// OBSOLETE xmitcsum += hex (ch); -// OBSOLETE -// OBSOLETE if (checksum != xmitcsum) -// OBSOLETE { -// OBSOLETE if (remote_debug) -// OBSOLETE { -// OBSOLETE unsigned char buf[16]; -// OBSOLETE -// OBSOLETE mem2hex((unsigned char *) &checksum, buf, 4, 0); -// OBSOLETE gdb_error("Bad checksum: my count = %s, ", buf); -// OBSOLETE mem2hex((unsigned char *) &xmitcsum, buf, 4, 0); -// OBSOLETE gdb_error("sent count = %s\n", buf); -// OBSOLETE gdb_error(" -- Bad buffer: \"%s\"\n", buffer); -// OBSOLETE } -// OBSOLETE putDebugChar ('-'); /* failed checksum */ -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE putDebugChar ('+'); /* successful transfer */ -// OBSOLETE -// OBSOLETE /* if a sequence char is present, reply the sequence ID */ -// OBSOLETE if (buffer[2] == ':') -// OBSOLETE { -// OBSOLETE putDebugChar (buffer[0]); -// OBSOLETE putDebugChar (buffer[1]); -// OBSOLETE -// OBSOLETE return &buffer[3]; -// OBSOLETE } -// OBSOLETE -// OBSOLETE return &buffer[0]; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* send the packet in buffer. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE putpacket (unsigned char *buffer) -// OBSOLETE { -// OBSOLETE unsigned char checksum; -// OBSOLETE int count; -// OBSOLETE char ch; -// OBSOLETE -// OBSOLETE /* $#. */ -// OBSOLETE do { -// OBSOLETE putDebugChar('$'); -// OBSOLETE checksum = 0; -// OBSOLETE count = 0; -// OBSOLETE -// OBSOLETE while (ch=buffer[count]) { -// OBSOLETE putDebugChar(ch); -// OBSOLETE checksum += ch; -// OBSOLETE count += 1; -// OBSOLETE } -// OBSOLETE putDebugChar('#'); -// OBSOLETE putDebugChar(hexchars[checksum >> 4]); -// OBSOLETE putDebugChar(hexchars[checksum % 16]); -// OBSOLETE } while (getDebugChar() != '+'); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Address of a routine to RTE to if we get a memory fault. */ -// OBSOLETE -// OBSOLETE static void (*volatile mem_fault_routine)() = 0; -// OBSOLETE -// OBSOLETE static void -// OBSOLETE set_mem_err (void) -// OBSOLETE { -// OBSOLETE mem_err = 1; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Check the address for safe access ranges. As currently defined, -// OBSOLETE this routine will reject the "expansion bus" address range(s). -// OBSOLETE To make those ranges useable, someone must implement code to detect -// OBSOLETE whether there's anything connected to the expansion bus. */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE mem_safe (unsigned char *addr) -// OBSOLETE { -// OBSOLETE #define BAD_RANGE_ONE_START ((unsigned char *) 0x600000) -// OBSOLETE #define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000) -// OBSOLETE #define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000) -// OBSOLETE #define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000) -// OBSOLETE -// OBSOLETE if (addr < BAD_RANGE_ONE_START) return 1; /* safe */ -// OBSOLETE if (addr < BAD_RANGE_ONE_END) return 0; /* unsafe */ -// OBSOLETE if (addr < BAD_RANGE_TWO_START) return 1; /* safe */ -// OBSOLETE if (addr < BAD_RANGE_TWO_END) return 0; /* unsafe */ -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* These are separate functions so that they are so short and sweet -// OBSOLETE that the compiler won't save any registers (if there is a fault -// OBSOLETE to mem_fault, they won't get restored, so there better not be any -// OBSOLETE saved). */ -// OBSOLETE static int -// OBSOLETE get_char (unsigned char *addr) -// OBSOLETE { -// OBSOLETE #if 1 -// OBSOLETE if (mem_fault_routine && !mem_safe(addr)) -// OBSOLETE { -// OBSOLETE mem_fault_routine (); -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE #endif -// OBSOLETE return *addr; -// OBSOLETE } -// OBSOLETE -// OBSOLETE static void -// OBSOLETE set_char (unsigned char *addr, unsigned char val) -// OBSOLETE { -// OBSOLETE #if 1 -// OBSOLETE if (mem_fault_routine && !mem_safe (addr)) -// OBSOLETE { -// OBSOLETE mem_fault_routine (); -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE #endif -// OBSOLETE *addr = val; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Convert the memory pointed to by mem into hex, placing result in buf. -// OBSOLETE Return a pointer to the last char put in buf (null). -// OBSOLETE If MAY_FAULT is non-zero, then we should set mem_err in response to -// OBSOLETE a fault; if zero treat a fault like any other fault in the stub. */ -// OBSOLETE -// OBSOLETE static unsigned char * -// OBSOLETE mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) -// OBSOLETE { -// OBSOLETE int i; -// OBSOLETE unsigned char ch; -// OBSOLETE -// OBSOLETE if (may_fault) -// OBSOLETE mem_fault_routine = set_mem_err; -// OBSOLETE for (i=0;i> 4]; -// OBSOLETE *buf++ = hexchars[ch % 16]; -// OBSOLETE } -// OBSOLETE *buf = 0; -// OBSOLETE if (may_fault) -// OBSOLETE mem_fault_routine = 0; -// OBSOLETE return(buf); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Convert the hex array pointed to by buf into binary to be placed in mem. -// OBSOLETE Return a pointer to the character AFTER the last byte written. */ -// OBSOLETE -// OBSOLETE static unsigned char* -// OBSOLETE hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) -// OBSOLETE { -// OBSOLETE int i; -// OBSOLETE unsigned char ch; -// OBSOLETE -// OBSOLETE if (may_fault) -// OBSOLETE mem_fault_routine = set_mem_err; -// OBSOLETE for (i=0;i=0) -// OBSOLETE { -// OBSOLETE *intValue = (*intValue <<4) | hexValue; -// OBSOLETE numChars ++; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE break; -// OBSOLETE (*ptr)++; -// OBSOLETE } -// OBSOLETE return (numChars); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* -// OBSOLETE Table of branch instructions: -// OBSOLETE -// OBSOLETE 10B6 RTE return from trap or exception -// OBSOLETE 1FCr JMP jump -// OBSOLETE 1ECr JL jump and link -// OBSOLETE 7Fxx BRA branch -// OBSOLETE FFxxxxxx BRA branch (long) -// OBSOLETE B09rxxxx BNEZ branch not-equal-zero -// OBSOLETE Br1rxxxx BNE branch not-equal -// OBSOLETE 7Dxx BNC branch not-condition -// OBSOLETE FDxxxxxx BNC branch not-condition (long) -// OBSOLETE B0Arxxxx BLTZ branch less-than-zero -// OBSOLETE B0Crxxxx BLEZ branch less-equal-zero -// OBSOLETE 7Exx BL branch and link -// OBSOLETE FExxxxxx BL branch and link (long) -// OBSOLETE B0Drxxxx BGTZ branch greater-than-zero -// OBSOLETE B0Brxxxx BGEZ branch greater-equal-zero -// OBSOLETE B08rxxxx BEQZ branch equal-zero -// OBSOLETE Br0rxxxx BEQ branch equal -// OBSOLETE 7Cxx BC branch condition -// OBSOLETE FCxxxxxx BC branch condition (long) -// OBSOLETE */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE isShortBranch (unsigned char *instr) -// OBSOLETE { -// OBSOLETE unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */ -// OBSOLETE -// OBSOLETE if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */ -// OBSOLETE return 1; /* return from trap or exception */ -// OBSOLETE -// OBSOLETE if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */ -// OBSOLETE if ((instr[1] & 0xF0) == 0xC0) -// OBSOLETE return 2; /* jump thru a register */ -// OBSOLETE -// OBSOLETE if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */ -// OBSOLETE instr0 == 0x7E || instr0 == 0x7F) -// OBSOLETE return 3; /* eight bit PC offset */ -// OBSOLETE -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE isLongBranch (unsigned char *instr) -// OBSOLETE { -// OBSOLETE if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */ -// OBSOLETE instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */ -// OBSOLETE return 4; -// OBSOLETE if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */ -// OBSOLETE { -// OBSOLETE if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */ -// OBSOLETE (instr[1] & 0xF0) == 0x10) -// OBSOLETE return 5; -// OBSOLETE if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */ -// OBSOLETE if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 || -// OBSOLETE (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 || -// OBSOLETE (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0) -// OBSOLETE return 6; -// OBSOLETE } -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* if address is NOT on a 4-byte boundary, or high-bit of instr is zero, -// OBSOLETE then it's a 2-byte instruction, else it's a 4-byte instruction. */ -// OBSOLETE -// OBSOLETE #define INSTRUCTION_SIZE(addr) \ -// OBSOLETE ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4) -// OBSOLETE -// OBSOLETE static int -// OBSOLETE isBranch (unsigned char *instr) -// OBSOLETE { -// OBSOLETE if (INSTRUCTION_SIZE(instr) == 2) -// OBSOLETE return isShortBranch(instr); -// OBSOLETE else -// OBSOLETE return isLongBranch(instr); -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE willBranch (unsigned char *instr, int branchCode) -// OBSOLETE { -// OBSOLETE switch (branchCode) -// OBSOLETE { -// OBSOLETE case 0: return 0; /* not a branch */ -// OBSOLETE case 1: return 1; /* RTE */ -// OBSOLETE case 2: return 1; /* JL or JMP */ -// OBSOLETE case 3: /* BC, BNC, BL, BRA (short) */ -// OBSOLETE case 4: /* BC, BNC, BL, BRA (long) */ -// OBSOLETE switch (instr[0] & 0x0F) -// OBSOLETE { -// OBSOLETE case 0xC: /* Branch if Condition Register */ -// OBSOLETE return (registers[CBR] != 0); -// OBSOLETE case 0xD: /* Branch if NOT Condition Register */ -// OBSOLETE return (registers[CBR] == 0); -// OBSOLETE case 0xE: /* Branch and Link */ -// OBSOLETE case 0xF: /* Branch (unconditional) */ -// OBSOLETE return 1; -// OBSOLETE default: /* oops? */ -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE case 5: /* BNE, BEQ */ -// OBSOLETE switch (instr[1] & 0xF0) -// OBSOLETE { -// OBSOLETE case 0x00: /* Branch if r1 equal to r2 */ -// OBSOLETE return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]); -// OBSOLETE case 0x10: /* Branch if r1 NOT equal to r2 */ -// OBSOLETE return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]); -// OBSOLETE default: /* oops? */ -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */ -// OBSOLETE switch (instr[1] & 0xF0) -// OBSOLETE { -// OBSOLETE case 0x80: /* Branch if reg equal to zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] == 0); -// OBSOLETE case 0x90: /* Branch if reg NOT equal to zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] != 0); -// OBSOLETE case 0xA0: /* Branch if reg less than zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] < 0); -// OBSOLETE case 0xB0: /* Branch if reg greater or equal to zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] >= 0); -// OBSOLETE case 0xC0: /* Branch if reg less than or equal to zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] <= 0); -// OBSOLETE case 0xD0: /* Branch if reg greater than zero */ -// OBSOLETE return (registers[instr[1] & 0x0F] > 0); -// OBSOLETE default: /* oops? */ -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE default: /* oops? */ -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE branchDestination (unsigned char *instr, int branchCode) -// OBSOLETE { -// OBSOLETE switch (branchCode) { -// OBSOLETE default: -// OBSOLETE case 0: /* not a branch */ -// OBSOLETE return 0; -// OBSOLETE case 1: /* RTE */ -// OBSOLETE return registers[BPC] & ~3; /* pop BPC into PC */ -// OBSOLETE case 2: /* JL or JMP */ -// OBSOLETE return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */ -// OBSOLETE case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */ -// OBSOLETE return (((int) instr) & ~3) + ((char) instr[1] << 2); -// OBSOLETE case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */ -// OBSOLETE return ((int) instr + -// OBSOLETE ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) << 2)); -// OBSOLETE case 5: /* BNE, BEQ (16-bit relative offset) */ -// OBSOLETE case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */ -// OBSOLETE return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2)); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* An explanatory note: in the last three return expressions, I have -// OBSOLETE cast the most-significant byte of the return offset to char. -// OBSOLETE What this accomplishes is sign extension. If the other -// OBSOLETE less-significant bytes were signed as well, they would get sign -// OBSOLETE extended too and, if negative, their leading bits would clobber -// OBSOLETE the bits of the more-significant bytes ahead of them. There are -// OBSOLETE other ways I could have done this, but sign extension from -// OBSOLETE odd-sized integers is always a pain. */ -// OBSOLETE } -// OBSOLETE -// OBSOLETE static void -// OBSOLETE branchSideEffects (unsigned char *instr, int branchCode) -// OBSOLETE { -// OBSOLETE switch (branchCode) -// OBSOLETE { -// OBSOLETE case 1: /* RTE */ -// OBSOLETE return; /* I this is already handled... */ -// OBSOLETE case 2: /* JL (or JMP) */ -// OBSOLETE case 3: /* BL (or BC, BNC, BRA) */ -// OBSOLETE case 4: -// OBSOLETE if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */ -// OBSOLETE registers[R14] = (registers[PC] & ~3) + 4; -// OBSOLETE return; -// OBSOLETE default: /* any other branch has no side effects */ -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE static struct STEPPING_CONTEXT { -// OBSOLETE int stepping; /* true when we've started a single-step */ -// OBSOLETE unsigned long target_addr; /* the instr we're trying to execute */ -// OBSOLETE unsigned long target_size; /* the size of the target instr */ -// OBSOLETE unsigned long noop_addr; /* where we've inserted a no-op, if any */ -// OBSOLETE unsigned long trap1_addr; /* the trap following the target instr */ -// OBSOLETE unsigned long trap2_addr; /* the trap at a branch destination, if any */ -// OBSOLETE unsigned short noop_save; /* instruction overwritten by our no-op */ -// OBSOLETE unsigned short trap1_save; /* instruction overwritten by trap1 */ -// OBSOLETE unsigned short trap2_save; /* instruction overwritten by trap2 */ -// OBSOLETE unsigned short continue_p; /* true if NOT returning to gdb after step */ -// OBSOLETE } stepping; -// OBSOLETE -// OBSOLETE /* Function: prepare_to_step -// OBSOLETE Called from handle_exception to prepare the user program to single-step. -// OBSOLETE Places a trap instruction after the target instruction, with special -// OBSOLETE extra handling for branch instructions and for instructions in the -// OBSOLETE second half-word of a word. -// OBSOLETE -// OBSOLETE Returns: True if we should actually execute the instruction; -// OBSOLETE False if we are going to emulate executing the instruction, -// OBSOLETE in which case we simply report to GDB that the instruction -// OBSOLETE has already been executed. */ -// OBSOLETE -// OBSOLETE #define TRAP1 0x10f1; /* trap #1 instruction */ -// OBSOLETE #define NOOP 0x7000; /* noop instruction */ -// OBSOLETE -// OBSOLETE static unsigned short trap1 = TRAP1; -// OBSOLETE static unsigned short noop = NOOP; -// OBSOLETE -// OBSOLETE static int -// OBSOLETE prepare_to_step(continue_p) -// OBSOLETE int continue_p; /* if this isn't REALLY a single-step (see below) */ -// OBSOLETE { -// OBSOLETE unsigned long pc = registers[PC]; -// OBSOLETE int branchCode = isBranch((unsigned char *) pc); -// OBSOLETE unsigned char *p; -// OBSOLETE -// OBSOLETE /* zero out the stepping context -// OBSOLETE (paranoia -- it should already be zeroed) */ -// OBSOLETE for (p = (unsigned char *) &stepping; -// OBSOLETE p < ((unsigned char *) &stepping) + sizeof(stepping); -// OBSOLETE p++) -// OBSOLETE *p = 0; -// OBSOLETE -// OBSOLETE if (branchCode != 0) /* next instruction is a branch */ -// OBSOLETE { -// OBSOLETE branchSideEffects((unsigned char *) pc, branchCode); -// OBSOLETE if (willBranch((unsigned char *)pc, branchCode)) -// OBSOLETE registers[PC] = branchDestination((unsigned char *) pc, branchCode); -// OBSOLETE else -// OBSOLETE registers[PC] = pc + INSTRUCTION_SIZE(pc); -// OBSOLETE return 0; /* branch "executed" -- just notify GDB */ -// OBSOLETE } -// OBSOLETE else if (((int) pc & 2) != 0) /* "second-slot" instruction */ -// OBSOLETE { -// OBSOLETE /* insert no-op before pc */ -// OBSOLETE stepping.noop_addr = pc - 2; -// OBSOLETE stepping.noop_save = *(unsigned short *) stepping.noop_addr; -// OBSOLETE *(unsigned short *) stepping.noop_addr = noop; -// OBSOLETE /* insert trap after pc */ -// OBSOLETE stepping.trap1_addr = pc + 2; -// OBSOLETE stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; -// OBSOLETE *(unsigned short *) stepping.trap1_addr = trap1; -// OBSOLETE } -// OBSOLETE else /* "first-slot" instruction */ -// OBSOLETE { -// OBSOLETE /* insert trap after pc */ -// OBSOLETE stepping.trap1_addr = pc + INSTRUCTION_SIZE(pc); -// OBSOLETE stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; -// OBSOLETE *(unsigned short *) stepping.trap1_addr = trap1; -// OBSOLETE } -// OBSOLETE /* "continue_p" means that we are actually doing a continue, and not -// OBSOLETE being requested to single-step by GDB. Sometimes we have to do -// OBSOLETE one single-step before continuing, because the PC is on a half-word -// OBSOLETE boundary. There's no way to simply resume at such an address. */ -// OBSOLETE stepping.continue_p = continue_p; -// OBSOLETE stepping.stepping = 1; /* starting a single-step */ -// OBSOLETE return 1; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: finish_from_step -// OBSOLETE Called from handle_exception to finish up when the user program -// OBSOLETE returns from a single-step. Replaces the instructions that had -// OBSOLETE been overwritten by traps or no-ops, -// OBSOLETE -// OBSOLETE Returns: True if we should notify GDB that the target stopped. -// OBSOLETE False if we only single-stepped because we had to before we -// OBSOLETE could continue (ie. we were trying to continue at a -// OBSOLETE half-word boundary). In that case don't notify GDB: -// OBSOLETE just "continue continuing". */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE finish_from_step (void) -// OBSOLETE { -// OBSOLETE if (stepping.stepping) /* anything to do? */ -// OBSOLETE { -// OBSOLETE int continue_p = stepping.continue_p; -// OBSOLETE unsigned char *p; -// OBSOLETE -// OBSOLETE if (stepping.noop_addr) /* replace instr "under" our no-op */ -// OBSOLETE *(unsigned short *) stepping.noop_addr = stepping.noop_save; -// OBSOLETE if (stepping.trap1_addr) /* replace instr "under" our trap */ -// OBSOLETE *(unsigned short *) stepping.trap1_addr = stepping.trap1_save; -// OBSOLETE if (stepping.trap2_addr) /* ditto our other trap, if any */ -// OBSOLETE *(unsigned short *) stepping.trap2_addr = stepping.trap2_save; -// OBSOLETE -// OBSOLETE for (p = (unsigned char *) &stepping; /* zero out the stepping context */ -// OBSOLETE p < ((unsigned char *) &stepping) + sizeof(stepping); -// OBSOLETE p++) -// OBSOLETE *p = 0; -// OBSOLETE -// OBSOLETE return !(continue_p); -// OBSOLETE } -// OBSOLETE else /* we didn't single-step, therefore this must be a legitimate stop */ -// OBSOLETE return 1; -// OBSOLETE } -// OBSOLETE -// OBSOLETE struct PSWreg { /* separate out the bit flags in the PSW register */ -// OBSOLETE int pad1 : 16; -// OBSOLETE int bsm : 1; -// OBSOLETE int bie : 1; -// OBSOLETE int pad2 : 5; -// OBSOLETE int bc : 1; -// OBSOLETE int sm : 1; -// OBSOLETE int ie : 1; -// OBSOLETE int pad3 : 5; -// OBSOLETE int c : 1; -// OBSOLETE } *psw; -// OBSOLETE -// OBSOLETE /* Upon entry the value for LR to save has been pushed. -// OBSOLETE We unpush that so that the value for the stack pointer saved is correct. -// OBSOLETE Upon entry, all other registers are assumed to have not been modified -// OBSOLETE since the interrupt/trap occured. */ -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE stash_registers: -// OBSOLETE push r0 -// OBSOLETE push r1 -// OBSOLETE seth r1, #shigh(registers) -// OBSOLETE add3 r1, r1, #low(registers) -// OBSOLETE pop r0 ; r1 -// OBSOLETE st r0, @(4,r1) -// OBSOLETE pop r0 ; r0 -// OBSOLETE st r0, @r1 -// OBSOLETE addi r1, #4 ; only add 4 as subsequent saves are `pre inc' -// OBSOLETE st r2, @+r1 -// OBSOLETE st r3, @+r1 -// OBSOLETE st r4, @+r1 -// OBSOLETE st r5, @+r1 -// OBSOLETE st r6, @+r1 -// OBSOLETE st r7, @+r1 -// OBSOLETE st r8, @+r1 -// OBSOLETE st r9, @+r1 -// OBSOLETE st r10, @+r1 -// OBSOLETE st r11, @+r1 -// OBSOLETE st r12, @+r1 -// OBSOLETE st r13, @+r1 ; fp -// OBSOLETE pop r0 ; lr (r14) -// OBSOLETE st r0, @+r1 -// OBSOLETE st sp, @+r1 ; sp contains right value at this point -// OBSOLETE mvfc r0, cr0 -// OBSOLETE st r0, @+r1 ; cr0 == PSW -// OBSOLETE mvfc r0, cr1 -// OBSOLETE st r0, @+r1 ; cr1 == CBR -// OBSOLETE mvfc r0, cr2 -// OBSOLETE st r0, @+r1 ; cr2 == SPI -// OBSOLETE mvfc r0, cr3 -// OBSOLETE st r0, @+r1 ; cr3 == SPU -// OBSOLETE mvfc r0, cr6 -// OBSOLETE st r0, @+r1 ; cr6 == BPC -// OBSOLETE st r0, @+r1 ; PC == BPC -// OBSOLETE mvfaclo r0 -// OBSOLETE st r0, @+r1 ; ACCL -// OBSOLETE mvfachi r0 -// OBSOLETE st r0, @+r1 ; ACCH -// OBSOLETE jmp lr"); -// OBSOLETE -// OBSOLETE /* C routine to clean up what stash_registers did. -// OBSOLETE It is called after calling stash_registers. -// OBSOLETE This is separate from stash_registers as we want to do this in C -// OBSOLETE but doing stash_registers in C isn't straightforward. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE cleanup_stash (void) -// OBSOLETE { -// OBSOLETE psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */ -// OBSOLETE psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */ -// OBSOLETE psw->ie = psw->bie; -// OBSOLETE psw->c = psw->bc; -// OBSOLETE registers[CBR] = psw->bc; /* fix up pre-trap "C" register */ -// OBSOLETE -// OBSOLETE #if 0 /* FIXME: Was in previous version. Necessary? -// OBSOLETE (Remember that we use the "rte" insn to return from the -// OBSOLETE trap/interrupt so the values of bsm, bie, bc are important. */ -// OBSOLETE psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */ -// OBSOLETE #endif -// OBSOLETE -// OBSOLETE /* FIXME: Copied from previous version. This can probably be deleted -// OBSOLETE since methinks stash_registers has already done this. */ -// OBSOLETE registers[PC] = registers[BPC]; /* pre-trap PC */ -// OBSOLETE -// OBSOLETE /* FIXME: Copied from previous version. Necessary? */ -// OBSOLETE if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */ -// OBSOLETE registers[SPU] = registers[R15]; -// OBSOLETE else -// OBSOLETE registers[SPI] = registers[R15]; -// OBSOLETE } -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE restore_and_return: -// OBSOLETE seth r0, #shigh(registers+8) -// OBSOLETE add3 r0, r0, #low(registers+8) -// OBSOLETE ld r2, @r0+ ; restore r2 -// OBSOLETE ld r3, @r0+ ; restore r3 -// OBSOLETE ld r4, @r0+ ; restore r4 -// OBSOLETE ld r5, @r0+ ; restore r5 -// OBSOLETE ld r6, @r0+ ; restore r6 -// OBSOLETE ld r7, @r0+ ; restore r7 -// OBSOLETE ld r8, @r0+ ; restore r8 -// OBSOLETE ld r9, @r0+ ; restore r9 -// OBSOLETE ld r10, @r0+ ; restore r10 -// OBSOLETE ld r11, @r0+ ; restore r11 -// OBSOLETE ld r12, @r0+ ; restore r12 -// OBSOLETE ld r13, @r0+ ; restore r13 -// OBSOLETE ld r14, @r0+ ; restore r14 -// OBSOLETE ld r15, @r0+ ; restore r15 -// OBSOLETE addi r0, #4 ; don't restore PSW (rte will do it) -// OBSOLETE ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only) -// OBSOLETE mvtc r1, cr1 -// OBSOLETE ld r1, @r0+ ; restore cr2 == SPI -// OBSOLETE mvtc r1, cr2 -// OBSOLETE ld r1, @r0+ ; restore cr3 == SPU -// OBSOLETE mvtc r1, cr3 -// OBSOLETE addi r0, #4 ; skip BPC -// OBSOLETE ld r1, @r0+ ; restore cr6 (BPC) == PC -// OBSOLETE mvtc r1, cr6 -// OBSOLETE ld r1, @r0+ ; restore ACCL -// OBSOLETE mvtaclo r1 -// OBSOLETE ld r1, @r0+ ; restore ACCH -// OBSOLETE mvtachi r1 -// OBSOLETE seth r0, #shigh(registers) -// OBSOLETE add3 r0, r0, #low(registers) -// OBSOLETE ld r1, @(4,r0) ; restore r1 -// OBSOLETE ld r0, @r0 ; restore r0 -// OBSOLETE rte"); -// OBSOLETE -// OBSOLETE /* General trap handler, called after the registers have been stashed. -// OBSOLETE NUM is the trap/exception number. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE process_exception (int num) -// OBSOLETE { -// OBSOLETE cleanup_stash (); -// OBSOLETE asm volatile (" -// OBSOLETE seth r1, #shigh(stackPtr) -// OBSOLETE add3 r1, r1, #low(stackPtr) -// OBSOLETE ld r15, @r1 ; setup local stack (protect user stack) -// OBSOLETE mv r0, %0 -// OBSOLETE bl handle_exception -// OBSOLETE bl restore_and_return" -// OBSOLETE : : "r" (num) : "r0", "r1"); -// OBSOLETE } -// OBSOLETE -// OBSOLETE void _catchException0 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException0: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #0 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException1 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException1: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE bl cleanup_stash -// OBSOLETE seth r1, #shigh(stackPtr) -// OBSOLETE add3 r1, r1, #low(stackPtr) -// OBSOLETE ld r15, @r1 ; setup local stack (protect user stack) -// OBSOLETE seth r1, #shigh(registers + 21*4) ; PC -// OBSOLETE add3 r1, r1, #low(registers + 21*4) -// OBSOLETE ld r0, @r1 -// OBSOLETE addi r0, #-4 ; back up PC for breakpoint trap. -// OBSOLETE st r0, @r1 ; FIXME: what about bp in right slot? -// OBSOLETE ldi r0, #1 -// OBSOLETE bl handle_exception -// OBSOLETE bl restore_and_return"); -// OBSOLETE -// OBSOLETE void _catchException2 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException2: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #2 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException3 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException3: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #3 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException4 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException4: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #4 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException5 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException5: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #5 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException6 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException6: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #6 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException7 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException7: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #7 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException8 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException8: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #8 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException9 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException9: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #9 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException10 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException10: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #10 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException11 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException11: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #11 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException12 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException12: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #12 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException13 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException13: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #13 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException14 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException14: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #14 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException15 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException15: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #15 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException16 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException16: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #16 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE void _catchException17 (); -// OBSOLETE -// OBSOLETE asm (" -// OBSOLETE _catchException17: -// OBSOLETE push lr -// OBSOLETE bl stash_registers -// OBSOLETE ; Note that at this point the pushed value of `lr' has been popped -// OBSOLETE ldi r0, #17 -// OBSOLETE bl process_exception"); -// OBSOLETE -// OBSOLETE -// OBSOLETE /* this function is used to set up exception handlers for tracing and -// OBSOLETE breakpoints */ -// OBSOLETE void -// OBSOLETE set_debug_traps (void) -// OBSOLETE { -// OBSOLETE /* extern void remcomHandler(); */ -// OBSOLETE int i; -// OBSOLETE -// OBSOLETE for (i = 0; i < 18; i++) /* keep a copy of old vectors */ -// OBSOLETE if (save_vectors[i] == 0) /* only copy them the first time */ -// OBSOLETE save_vectors[i] = getExceptionHandler (i); -// OBSOLETE -// OBSOLETE stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1]; -// OBSOLETE -// OBSOLETE exceptionHandler (0, _catchException0); -// OBSOLETE exceptionHandler (1, _catchException1); -// OBSOLETE exceptionHandler (2, _catchException2); -// OBSOLETE exceptionHandler (3, _catchException3); -// OBSOLETE exceptionHandler (4, _catchException4); -// OBSOLETE exceptionHandler (5, _catchException5); -// OBSOLETE exceptionHandler (6, _catchException6); -// OBSOLETE exceptionHandler (7, _catchException7); -// OBSOLETE exceptionHandler (8, _catchException8); -// OBSOLETE exceptionHandler (9, _catchException9); -// OBSOLETE exceptionHandler (10, _catchException10); -// OBSOLETE exceptionHandler (11, _catchException11); -// OBSOLETE exceptionHandler (12, _catchException12); -// OBSOLETE exceptionHandler (13, _catchException13); -// OBSOLETE exceptionHandler (14, _catchException14); -// OBSOLETE exceptionHandler (15, _catchException15); -// OBSOLETE exceptionHandler (16, _catchException16); -// OBSOLETE /* exceptionHandler (17, _catchException17); */ -// OBSOLETE -// OBSOLETE initialized = 1; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* This function will generate a breakpoint exception. It is used at the -// OBSOLETE beginning of a program to sync up with a debugger and can be used -// OBSOLETE otherwise as a quick means to stop program execution and "break" into -// OBSOLETE the debugger. */ -// OBSOLETE -// OBSOLETE #define BREAKPOINT() asm volatile (" trap #2"); -// OBSOLETE -// OBSOLETE void -// OBSOLETE breakpoint (void) -// OBSOLETE { -// OBSOLETE if (initialized) -// OBSOLETE BREAKPOINT(); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* STDOUT section: -// OBSOLETE Stuff pertaining to simulating stdout by sending chars to gdb to be echoed. -// OBSOLETE Functions: gdb_putchar(char ch) -// OBSOLETE gdb_puts(char *str) -// OBSOLETE gdb_write(char *str, int len) -// OBSOLETE gdb_error(char *format, char *parm) -// OBSOLETE */ -// OBSOLETE -// OBSOLETE /* Function: gdb_putchar(int) -// OBSOLETE Make gdb write a char to stdout. -// OBSOLETE Returns: the char */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE gdb_putchar (int ch) -// OBSOLETE { -// OBSOLETE char buf[4]; -// OBSOLETE -// OBSOLETE buf[0] = 'O'; -// OBSOLETE buf[1] = hexchars[ch >> 4]; -// OBSOLETE buf[2] = hexchars[ch & 0x0F]; -// OBSOLETE buf[3] = 0; -// OBSOLETE putpacket(buf); -// OBSOLETE return ch; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: gdb_write(char *, int) -// OBSOLETE Make gdb write n bytes to stdout (not assumed to be null-terminated). -// OBSOLETE Returns: number of bytes written */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE gdb_write (char *data, int len) -// OBSOLETE { -// OBSOLETE char *buf, *cpy; -// OBSOLETE int i; -// OBSOLETE -// OBSOLETE buf = remcomOutBuffer; -// OBSOLETE buf[0] = 'O'; -// OBSOLETE i = 0; -// OBSOLETE while (i < len) -// OBSOLETE { -// OBSOLETE for (cpy = buf+1; -// OBSOLETE i < len && cpy < buf + sizeof(remcomOutBuffer) - 3; -// OBSOLETE i++) -// OBSOLETE { -// OBSOLETE *cpy++ = hexchars[data[i] >> 4]; -// OBSOLETE *cpy++ = hexchars[data[i] & 0x0F]; -// OBSOLETE } -// OBSOLETE *cpy = 0; -// OBSOLETE putpacket(buf); -// OBSOLETE } -// OBSOLETE return len; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: gdb_puts(char *) -// OBSOLETE Make gdb write a null-terminated string to stdout. -// OBSOLETE Returns: the length of the string */ -// OBSOLETE -// OBSOLETE static int -// OBSOLETE gdb_puts (char *str) -// OBSOLETE { -// OBSOLETE return gdb_write(str, strlen(str)); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: gdb_error(char *, char *) -// OBSOLETE Send an error message to gdb's stdout. -// OBSOLETE First string may have 1 (one) optional "%s" in it, which -// OBSOLETE will cause the optional second string to be inserted. */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE gdb_error (char *format, char *parm) -// OBSOLETE { -// OBSOLETE char buf[400], *cpy; -// OBSOLETE int len; -// OBSOLETE -// OBSOLETE if (remote_debug) -// OBSOLETE { -// OBSOLETE if (format && *format) -// OBSOLETE len = strlen(format); -// OBSOLETE else -// OBSOLETE return; /* empty input */ -// OBSOLETE -// OBSOLETE if (parm && *parm) -// OBSOLETE len += strlen(parm); -// OBSOLETE -// OBSOLETE for (cpy = buf; *format; ) -// OBSOLETE { -// OBSOLETE if (format[0] == '%' && format[1] == 's') /* include second string */ -// OBSOLETE { -// OBSOLETE format += 2; /* advance two chars instead of just one */ -// OBSOLETE while (parm && *parm) -// OBSOLETE *cpy++ = *parm++; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE *cpy++ = *format++; -// OBSOLETE } -// OBSOLETE *cpy = '\0'; -// OBSOLETE gdb_puts(buf); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE static unsigned char * -// OBSOLETE strcpy (unsigned char *dest, const unsigned char *src) -// OBSOLETE { -// OBSOLETE unsigned char *ret = dest; -// OBSOLETE -// OBSOLETE if (dest && src) -// OBSOLETE { -// OBSOLETE while (*src) -// OBSOLETE *dest++ = *src++; -// OBSOLETE *dest = 0; -// OBSOLETE } -// OBSOLETE return ret; -// OBSOLETE } -// OBSOLETE -// OBSOLETE static int -// OBSOLETE strlen (const unsigned char *src) -// OBSOLETE { -// OBSOLETE int ret; -// OBSOLETE -// OBSOLETE for (ret = 0; *src; src++) -// OBSOLETE ret++; -// OBSOLETE -// OBSOLETE return ret; -// OBSOLETE } -// OBSOLETE -// OBSOLETE #if 0 -// OBSOLETE void exit (code) -// OBSOLETE int code; -// OBSOLETE { -// OBSOLETE _exit (code); -// OBSOLETE } -// OBSOLETE -// OBSOLETE int atexit (void *p) -// OBSOLETE { -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE -// OBSOLETE void abort (void) -// OBSOLETE { -// OBSOLETE _exit (1); -// OBSOLETE } -// OBSOLETE #endif +/**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for M32R by Michael Snyder, Cygnus Support. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + * The external function exceptionHandler() is + * used to attach a specific handler to a specific M32R vector number. + * It should use the same privilege level it runs at. It should + * install it as an interrupt gate so that interrupts are masked + * while the handler runs. + * + * Because gdb will sometimes write to the stack area to execute function + * calls, this program cannot rely on using the supervisor stack so it + * uses it's own stack area reserved in the int array remcomStack. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * G set the value of the CPU registers OK or ENN + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN + * AA..AA + * + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + + +/************************************************************************ + * + * external low-level support routines + */ +extern void putDebugChar (); /* write a single character */ +extern int getDebugChar (); /* read and return a single char */ +extern void exceptionHandler (); /* assign an exception handler */ + +/***************************************************************************** + * BUFMAX defines the maximum number of characters in inbound/outbound buffers + * at least NUMREGBYTES*2 are needed for register packets + */ +#define BUFMAX 400 + +static char initialized; /* boolean flag. != 0 means we've been initialized */ + +int remote_debug; +/* debug > 0 prints ill-formed commands in valid packets & checksum errors */ + +static const unsigned char hexchars[] = "0123456789abcdef"; + +#define NUMREGS 24 + +/* Number of bytes of registers. */ +#define NUMREGBYTES (NUMREGS * 4) +enum regnames +{ R0, R1, R2, R3, R4, R5, R6, R7, + R8, R9, R10, R11, R12, R13, R14, R15, + PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH +}; + +enum SYS_calls +{ + SYS_null, + SYS_exit, + SYS_open, + SYS_close, + SYS_read, + SYS_write, + SYS_lseek, + SYS_unlink, + SYS_getpid, + SYS_kill, + SYS_fstat, + SYS_sbrk, + SYS_fork, + SYS_execve, + SYS_wait4, + SYS_link, + SYS_chdir, + SYS_stat, + SYS_utime, + SYS_chown, + SYS_chmod, + SYS_time, + SYS_pipe +}; + +static int registers[NUMREGS]; + +#define STACKSIZE 8096 +static unsigned char remcomInBuffer[BUFMAX]; +static unsigned char remcomOutBuffer[BUFMAX]; +static int remcomStack[STACKSIZE / sizeof (int)]; +static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + +static unsigned int save_vectors[18]; /* previous exception vectors */ + +/* Indicate to caller of mem2hex or hex2mem that there has been an error. */ +static volatile int mem_err = 0; + +/* Store the vector number here (since GDB only gets the signal + number through the usual means, and that's not very specific). */ +int gdb_m32r_vector = -1; + +#if 0 +#include "syscall.h" /* for SYS_exit, SYS_write etc. */ +#endif + +/* Global entry points: + */ + +extern void handle_exception (int); +extern void set_debug_traps (void); +extern void breakpoint (void); + +/* Local functions: + */ + +static int computeSignal (int); +static void putpacket (unsigned char *); +static unsigned char *getpacket (void); + +static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int); +static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int); +static int hexToInt (unsigned char **, int *); +static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int); +static void stash_registers (void); +static void restore_registers (void); +static int prepare_to_step (int); +static int finish_from_step (void); +static unsigned long crc32 (unsigned char *, int, unsigned long); + +static void gdb_error (char *, char *); +static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int); + +static unsigned char *strcpy (unsigned char *, const unsigned char *); +static int strlen (const unsigned char *); + +/* + * This function does all command procesing for interfacing to gdb. + */ + +void +handle_exception (int exceptionVector) +{ + int sigval, stepping; + int addr, length, i; + unsigned char *ptr; + unsigned char buf[16]; + int binary; + + if (!finish_from_step ()) + return; /* "false step": let the target continue */ + + gdb_m32r_vector = exceptionVector; + + if (remote_debug) + { + mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0); + gdb_error ("Handle exception %s, ", buf); + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + gdb_error ("PC == 0x%s\n", buf); + } + + /* reply to host that an exception has occurred */ + sigval = computeSignal (exceptionVector); + + ptr = remcomOutBuffer; + + *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */ + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + + *ptr++ = hexchars[PC >> 4]; + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */ + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */ + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */ + *ptr++ = ';'; + *ptr++ = 0; + + if (exceptionVector == 0) /* simulated SYS call stuff */ + { + mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0); + switch (registers[R0]) + { + case SYS_exit: + gdb_error ("Target program has exited at %s\n", buf); + ptr = remcomOutBuffer; + *ptr++ = 'W'; + sigval = registers[R1] & 0xff; + *ptr++ = hexchars[sigval >> 4]; + *ptr++ = hexchars[sigval & 0xf]; + *ptr++ = 0; + break; + case SYS_open: + gdb_error ("Target attempts SYS_open call at %s\n", buf); + break; + case SYS_close: + gdb_error ("Target attempts SYS_close call at %s\n", buf); + break; + case SYS_read: + gdb_error ("Target attempts SYS_read call at %s\n", buf); + break; + case SYS_write: + if (registers[R1] == 1 || /* write to stdout */ + registers[R1] == 2) /* write to stderr */ + { /* (we can do that) */ + registers[R0] = + gdb_write ((void *) registers[R2], registers[R3]); + return; + } + else + gdb_error ("Target attempts SYS_write call at %s\n", buf); + break; + case SYS_lseek: + gdb_error ("Target attempts SYS_lseek call at %s\n", buf); + break; + case SYS_unlink: + gdb_error ("Target attempts SYS_unlink call at %s\n", buf); + break; + case SYS_getpid: + gdb_error ("Target attempts SYS_getpid call at %s\n", buf); + break; + case SYS_kill: + gdb_error ("Target attempts SYS_kill call at %s\n", buf); + break; + case SYS_fstat: + gdb_error ("Target attempts SYS_fstat call at %s\n", buf); + break; + default: + gdb_error ("Target attempts unknown SYS call at %s\n", buf); + break; + } + } + + putpacket (remcomOutBuffer); + + stepping = 0; + + while (1 == 1) + { + remcomOutBuffer[0] = 0; + ptr = getpacket (); + binary = 0; + switch (*ptr++) + { + default: /* Unknown code. Return an empty reply message. */ + break; + case 'R': + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + strcpy (remcomOutBuffer, "OK"); + break; + case '!': + strcpy (remcomOutBuffer, "OK"); + break; + case 'X': /* XAA..AA,LLLL:#cs */ + binary = 1; + case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ + /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */ + { + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + if (*(ptr++) == ':') + { + mem_err = 0; + if (binary) + bin2mem (ptr, (unsigned char *) addr, length, 1); + else + hex2mem (ptr, (unsigned char *) addr, length, 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + else + { + strcpy (remcomOutBuffer, "OK"); + } + ptr = 0; + } + if (ptr) + { + strcpy (remcomOutBuffer, "E02"); + } + } + break; + case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ + /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */ + if (hexToInt (&ptr, &addr)) + if (*(ptr++) == ',') + if (hexToInt (&ptr, &length)) + { + ptr = 0; + mem_err = 0; + mem2hex ((unsigned char *) addr, remcomOutBuffer, length, + 1); + if (mem_err) + { + strcpy (remcomOutBuffer, "E03"); + gdb_error ("memory fault", ""); + } + } + if (ptr) + { + strcpy (remcomOutBuffer, "E01"); + } + break; + case '?': + remcomOutBuffer[0] = 'S'; + remcomOutBuffer[1] = hexchars[sigval >> 4]; + remcomOutBuffer[2] = hexchars[sigval % 16]; + remcomOutBuffer[3] = 0; + break; + case 'd': + remote_debug = !(remote_debug); /* toggle debug flag */ + break; + case 'g': /* return the value of the CPU registers */ + mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES, + 0); + break; + case 'P': /* set the value of a single CPU register - return OK */ + { + int regno; + + if (hexToInt (&ptr, ®no) && *ptr++ == '=') + if (regno >= 0 && regno < NUMREGS) + { + int stackmode; + + hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0); + /* + * Since we just changed a single CPU register, let's + * make sure to keep the several stack pointers consistant. + */ + stackmode = registers[PSW] & 0x80; + if (regno == R15) /* stack pointer changed */ + { /* need to change SPI or SPU */ + if (stackmode == 0) + registers[SPI] = registers[R15]; + else + registers[SPU] = registers[R15]; + } + else if (regno == SPU) /* "user" stack pointer changed */ + { + if (stackmode != 0) /* stack in user mode: copy SP */ + registers[R15] = registers[SPU]; + } + else if (regno == SPI) /* "interrupt" stack pointer changed */ + { + if (stackmode == 0) /* stack in interrupt mode: copy SP */ + registers[R15] = registers[SPI]; + } + else if (regno == PSW) /* stack mode may have changed! */ + { /* force SP to either SPU or SPI */ + if (stackmode == 0) /* stack in user mode */ + registers[R15] = registers[SPI]; + else /* stack in interrupt mode */ + registers[R15] = registers[SPU]; + } + strcpy (remcomOutBuffer, "OK"); + break; + } + strcpy (remcomOutBuffer, "E01"); + break; + } + case 'G': /* set the value of the CPU registers - return OK */ + hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0); + strcpy (remcomOutBuffer, "OK"); + break; + case 's': /* sAA..AA Step one instruction from AA..AA(optional) */ + stepping = 1; + case 'c': /* cAA..AA Continue from address AA..AA(optional) */ + /* try to read optional parameter, pc unchanged if no parm */ + if (hexToInt (&ptr, &addr)) + registers[PC] = addr; + + if (stepping) /* single-stepping */ + { + if (!prepare_to_step (0)) /* set up for single-step */ + { + /* prepare_to_step has already emulated the target insn: + Send SIGTRAP to gdb, don't resume the target at all. */ + ptr = remcomOutBuffer; + *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */ + *ptr++ = '0'; + *ptr++ = '5'; + + *ptr++ = hexchars[PC >> 4]; /* send PC */ + *ptr++ = hexchars[PC & 0xf]; + *ptr++ = ':'; + ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R13 >> 4]; /* send FP */ + *ptr++ = hexchars[R13 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); + *ptr++ = ';'; + + *ptr++ = hexchars[R15 >> 4]; /* send SP */ + *ptr++ = hexchars[R15 & 0xf]; + *ptr++ = ':'; + ptr = + mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); + *ptr++ = ';'; + *ptr++ = 0; + + break; + } + } + else /* continuing, not single-stepping */ + { + /* OK, about to do a "continue". First check to see if the + target pc is on an odd boundary (second instruction in the + word). If so, we must do a single-step first, because + ya can't jump or return back to an odd boundary! */ + if ((registers[PC] & 2) != 0) + prepare_to_step (1); + } + + return; + + case 'D': /* Detach */ +#if 0 + /* I am interpreting this to mean, release the board from control + by the remote stub. To do this, I am restoring the original + (or at least previous) exception vectors. + */ + for (i = 0; i < 18; i++) + exceptionHandler (i, save_vectors[i]); + putpacket ("OK"); + return; /* continue the inferior */ +#else + strcpy (remcomOutBuffer, "OK"); + break; +#endif + case 'q': + if (*ptr++ == 'C' && + *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':') + { + unsigned long start, len, our_crc; + + if (hexToInt (&ptr, (int *) &start) && + *ptr++ == ',' && hexToInt (&ptr, (int *) &len)) + { + remcomOutBuffer[0] = 'C'; + our_crc = crc32 ((unsigned char *) start, len, 0xffffffff); + mem2hex ((char *) &our_crc, + &remcomOutBuffer[1], sizeof (long), 0); + } /* else do nothing */ + } /* else do nothing */ + break; + + case 'k': /* kill the program */ + continue; + } /* switch */ + + /* reply to the request */ + putpacket (remcomOutBuffer); + } +} + +/* qCRC support */ + +/* Table used by the crc32 function to calcuate the checksum. */ +static unsigned long crc32_table[256] = { 0, 0 }; + +static unsigned long +crc32 (unsigned char *buf, int len, unsigned long crc) +{ + if (!crc32_table[1]) + { + /* Initialize the CRC table and the decoding table. */ + int i, j; + unsigned long c; + + for (i = 0; i < 256; i++) + { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); + crc32_table[i] = c; + } + } + + while (len--) + { + crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; + buf++; + } + return crc; +} + +static int +hex (unsigned char ch) +{ + if ((ch >= 'a') && (ch <= 'f')) + return (ch - 'a' + 10); + if ((ch >= '0') && (ch <= '9')) + return (ch - '0'); + if ((ch >= 'A') && (ch <= 'F')) + return (ch - 'A' + 10); + return (-1); +} + +/* scan for the sequence $# */ + +unsigned char * +getpacket (void) +{ + unsigned char *buffer = &remcomInBuffer[0]; + unsigned char checksum; + unsigned char xmitcsum; + int count; + char ch; + + while (1) + { + /* wait around for the start character, ignore all other characters */ + while ((ch = getDebugChar ()) != '$') + ; + + retry: + checksum = 0; + xmitcsum = -1; + count = 0; + + /* now, read until a # or end of buffer is found */ + while (count < BUFMAX) + { + ch = getDebugChar (); + if (ch == '$') + goto retry; + if (ch == '#') + break; + checksum = checksum + ch; + buffer[count] = ch; + count = count + 1; + } + buffer[count] = 0; + + if (ch == '#') + { + ch = getDebugChar (); + xmitcsum = hex (ch) << 4; + ch = getDebugChar (); + xmitcsum += hex (ch); + + if (checksum != xmitcsum) + { + if (remote_debug) + { + unsigned char buf[16]; + + mem2hex ((unsigned char *) &checksum, buf, 4, 0); + gdb_error ("Bad checksum: my count = %s, ", buf); + mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0); + gdb_error ("sent count = %s\n", buf); + gdb_error (" -- Bad buffer: \"%s\"\n", buffer); + } + putDebugChar ('-'); /* failed checksum */ + } + else + { + putDebugChar ('+'); /* successful transfer */ + + /* if a sequence char is present, reply the sequence ID */ + if (buffer[2] == ':') + { + putDebugChar (buffer[0]); + putDebugChar (buffer[1]); + + return &buffer[3]; + } + + return &buffer[0]; + } + } + } +} + +/* send the packet in buffer. */ + +static void +putpacket (unsigned char *buffer) +{ + unsigned char checksum; + int count; + char ch; + + /* $#. */ + do + { + putDebugChar ('$'); + checksum = 0; + count = 0; + + while (ch = buffer[count]) + { + putDebugChar (ch); + checksum += ch; + count += 1; + } + putDebugChar ('#'); + putDebugChar (hexchars[checksum >> 4]); + putDebugChar (hexchars[checksum % 16]); + } + while (getDebugChar () != '+'); +} + +/* Address of a routine to RTE to if we get a memory fault. */ + +static void (*volatile mem_fault_routine) () = 0; + +static void +set_mem_err (void) +{ + mem_err = 1; +} + +/* Check the address for safe access ranges. As currently defined, + this routine will reject the "expansion bus" address range(s). + To make those ranges useable, someone must implement code to detect + whether there's anything connected to the expansion bus. */ + +static int +mem_safe (unsigned char *addr) +{ +#define BAD_RANGE_ONE_START ((unsigned char *) 0x600000) +#define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000) +#define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000) +#define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000) + + if (addr < BAD_RANGE_ONE_START) + return 1; /* safe */ + if (addr < BAD_RANGE_ONE_END) + return 0; /* unsafe */ + if (addr < BAD_RANGE_TWO_START) + return 1; /* safe */ + if (addr < BAD_RANGE_TWO_END) + return 0; /* unsafe */ +} + +/* These are separate functions so that they are so short and sweet + that the compiler won't save any registers (if there is a fault + to mem_fault, they won't get restored, so there better not be any + saved). */ +static int +get_char (unsigned char *addr) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return 0; + } +#endif + return *addr; +} + +static void +set_char (unsigned char *addr, unsigned char val) +{ +#if 1 + if (mem_fault_routine && !mem_safe (addr)) + { + mem_fault_routine (); + return; + } +#endif + *addr = val; +} + +/* Convert the memory pointed to by mem into hex, placing result in buf. + Return a pointer to the last char put in buf (null). + If MAY_FAULT is non-zero, then we should set mem_err in response to + a fault; if zero treat a fault like any other fault in the stub. */ + +static unsigned char * +mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = get_char (mem++); + if (may_fault && mem_err) + return (buf); + *buf++ = hexchars[ch >> 4]; + *buf++ = hexchars[ch % 16]; + } + *buf = 0; + if (may_fault) + mem_fault_routine = 0; + return (buf); +} + +/* Convert the hex array pointed to by buf into binary to be placed in mem. + Return a pointer to the character AFTER the last byte written. */ + +static unsigned char * +hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + ch = hex (*buf++) << 4; + ch = ch + hex (*buf++); + set_char (mem++, ch); + if (may_fault && mem_err) + return (mem); + } + if (may_fault) + mem_fault_routine = 0; + return (mem); +} + +/* Convert the binary stream in BUF to memory. + + Gdb will escape $, #, and the escape char (0x7d). + COUNT is the total number of bytes to write into + memory. */ +static unsigned char * +bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault) +{ + int i; + unsigned char ch; + + if (may_fault) + mem_fault_routine = set_mem_err; + for (i = 0; i < count; i++) + { + /* Check for any escaped characters. Be paranoid and + only unescape chars that should be escaped. */ + if (*buf == 0x7d) + { + switch (*(buf + 1)) + { + case 0x3: /* # */ + case 0x4: /* $ */ + case 0x5d: /* escape char */ + buf++; + *buf |= 0x20; + break; + default: + /* nothing */ + break; + } + } + + set_char (mem++, *buf++); + + if (may_fault && mem_err) + return mem; + } + + if (may_fault) + mem_fault_routine = 0; + return mem; +} + +/* this function takes the m32r exception vector and attempts to + translate this number into a unix compatible signal value */ + +static int +computeSignal (int exceptionVector) +{ + int sigval; + switch (exceptionVector) + { + case 0: + sigval = 23; + break; /* I/O trap */ + case 1: + sigval = 5; + break; /* breakpoint */ + case 2: + sigval = 5; + break; /* breakpoint */ + case 3: + sigval = 5; + break; /* breakpoint */ + case 4: + sigval = 5; + break; /* breakpoint */ + case 5: + sigval = 5; + break; /* breakpoint */ + case 6: + sigval = 5; + break; /* breakpoint */ + case 7: + sigval = 5; + break; /* breakpoint */ + case 8: + sigval = 5; + break; /* breakpoint */ + case 9: + sigval = 5; + break; /* breakpoint */ + case 10: + sigval = 5; + break; /* breakpoint */ + case 11: + sigval = 5; + break; /* breakpoint */ + case 12: + sigval = 5; + break; /* breakpoint */ + case 13: + sigval = 5; + break; /* breakpoint */ + case 14: + sigval = 5; + break; /* breakpoint */ + case 15: + sigval = 5; + break; /* breakpoint */ + case 16: + sigval = 10; + break; /* BUS ERROR (alignment) */ + case 17: + sigval = 2; + break; /* INTerrupt */ + default: + sigval = 7; + break; /* "software generated" */ + } + return (sigval); +} + +/**********************************************/ +/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */ +/* RETURN NUMBER OF CHARS PROCESSED */ +/**********************************************/ +static int +hexToInt (unsigned char **ptr, int *intValue) +{ + int numChars = 0; + int hexValue; + + *intValue = 0; + while (**ptr) + { + hexValue = hex (**ptr); + if (hexValue >= 0) + { + *intValue = (*intValue << 4) | hexValue; + numChars++; + } + else + break; + (*ptr)++; + } + return (numChars); +} + +/* + Table of branch instructions: + + 10B6 RTE return from trap or exception + 1FCr JMP jump + 1ECr JL jump and link + 7Fxx BRA branch + FFxxxxxx BRA branch (long) + B09rxxxx BNEZ branch not-equal-zero + Br1rxxxx BNE branch not-equal + 7Dxx BNC branch not-condition + FDxxxxxx BNC branch not-condition (long) + B0Arxxxx BLTZ branch less-than-zero + B0Crxxxx BLEZ branch less-equal-zero + 7Exx BL branch and link + FExxxxxx BL branch and link (long) + B0Drxxxx BGTZ branch greater-than-zero + B0Brxxxx BGEZ branch greater-equal-zero + B08rxxxx BEQZ branch equal-zero + Br0rxxxx BEQ branch equal + 7Cxx BC branch condition + FCxxxxxx BC branch condition (long) + */ + +static int +isShortBranch (unsigned char *instr) +{ + unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */ + + if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */ + return 1; /* return from trap or exception */ + + if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */ + if ((instr[1] & 0xF0) == 0xC0) + return 2; /* jump thru a register */ + + if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */ + instr0 == 0x7E || instr0 == 0x7F) + return 3; /* eight bit PC offset */ + + return 0; +} + +static int +isLongBranch (unsigned char *instr) +{ + if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */ + instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */ + return 4; + if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */ + { + if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */ + (instr[1] & 0xF0) == 0x10) + return 5; + if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */ + if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 || + (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 || + (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0) + return 6; + } + return 0; +} + +/* if address is NOT on a 4-byte boundary, or high-bit of instr is zero, + then it's a 2-byte instruction, else it's a 4-byte instruction. */ + +#define INSTRUCTION_SIZE(addr) \ + ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4) + +static int +isBranch (unsigned char *instr) +{ + if (INSTRUCTION_SIZE (instr) == 2) + return isShortBranch (instr); + else + return isLongBranch (instr); +} + +static int +willBranch (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 0: + return 0; /* not a branch */ + case 1: + return 1; /* RTE */ + case 2: + return 1; /* JL or JMP */ + case 3: /* BC, BNC, BL, BRA (short) */ + case 4: /* BC, BNC, BL, BRA (long) */ + switch (instr[0] & 0x0F) + { + case 0xC: /* Branch if Condition Register */ + return (registers[CBR] != 0); + case 0xD: /* Branch if NOT Condition Register */ + return (registers[CBR] == 0); + case 0xE: /* Branch and Link */ + case 0xF: /* Branch (unconditional) */ + return 1; + default: /* oops? */ + return 0; + } + case 5: /* BNE, BEQ */ + switch (instr[1] & 0xF0) + { + case 0x00: /* Branch if r1 equal to r2 */ + return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]); + case 0x10: /* Branch if r1 NOT equal to r2 */ + return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]); + default: /* oops? */ + return 0; + } + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */ + switch (instr[1] & 0xF0) + { + case 0x80: /* Branch if reg equal to zero */ + return (registers[instr[1] & 0x0F] == 0); + case 0x90: /* Branch if reg NOT equal to zero */ + return (registers[instr[1] & 0x0F] != 0); + case 0xA0: /* Branch if reg less than zero */ + return (registers[instr[1] & 0x0F] < 0); + case 0xB0: /* Branch if reg greater or equal to zero */ + return (registers[instr[1] & 0x0F] >= 0); + case 0xC0: /* Branch if reg less than or equal to zero */ + return (registers[instr[1] & 0x0F] <= 0); + case 0xD0: /* Branch if reg greater than zero */ + return (registers[instr[1] & 0x0F] > 0); + default: /* oops? */ + return 0; + } + default: /* oops? */ + return 0; + } +} + +static int +branchDestination (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + default: + case 0: /* not a branch */ + return 0; + case 1: /* RTE */ + return registers[BPC] & ~3; /* pop BPC into PC */ + case 2: /* JL or JMP */ + return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */ + case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */ + return (((int) instr) & ~3) + ((char) instr[1] << 2); + case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */ + return ((int) instr + + ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) << + 2)); + case 5: /* BNE, BEQ (16-bit relative offset) */ + case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */ + return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2)); + } + + /* An explanatory note: in the last three return expressions, I have + cast the most-significant byte of the return offset to char. + What this accomplishes is sign extension. If the other + less-significant bytes were signed as well, they would get sign + extended too and, if negative, their leading bits would clobber + the bits of the more-significant bytes ahead of them. There are + other ways I could have done this, but sign extension from + odd-sized integers is always a pain. */ +} + +static void +branchSideEffects (unsigned char *instr, int branchCode) +{ + switch (branchCode) + { + case 1: /* RTE */ + return; /* I this is already handled... */ + case 2: /* JL (or JMP) */ + case 3: /* BL (or BC, BNC, BRA) */ + case 4: + if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */ + registers[R14] = (registers[PC] & ~3) + 4; + return; + default: /* any other branch has no side effects */ + return; + } +} + +static struct STEPPING_CONTEXT +{ + int stepping; /* true when we've started a single-step */ + unsigned long target_addr; /* the instr we're trying to execute */ + unsigned long target_size; /* the size of the target instr */ + unsigned long noop_addr; /* where we've inserted a no-op, if any */ + unsigned long trap1_addr; /* the trap following the target instr */ + unsigned long trap2_addr; /* the trap at a branch destination, if any */ + unsigned short noop_save; /* instruction overwritten by our no-op */ + unsigned short trap1_save; /* instruction overwritten by trap1 */ + unsigned short trap2_save; /* instruction overwritten by trap2 */ + unsigned short continue_p; /* true if NOT returning to gdb after step */ +} stepping; + +/* Function: prepare_to_step + Called from handle_exception to prepare the user program to single-step. + Places a trap instruction after the target instruction, with special + extra handling for branch instructions and for instructions in the + second half-word of a word. + + Returns: True if we should actually execute the instruction; + False if we are going to emulate executing the instruction, + in which case we simply report to GDB that the instruction + has already been executed. */ + +#define TRAP1 0x10f1; /* trap #1 instruction */ +#define NOOP 0x7000; /* noop instruction */ + +static unsigned short trap1 = TRAP1; +static unsigned short noop = NOOP; + +static int +prepare_to_step (continue_p) + int continue_p; /* if this isn't REALLY a single-step (see below) */ +{ + unsigned long pc = registers[PC]; + int branchCode = isBranch ((unsigned char *) pc); + unsigned char *p; + + /* zero out the stepping context + (paranoia -- it should already be zeroed) */ + for (p = (unsigned char *) &stepping; + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + if (branchCode != 0) /* next instruction is a branch */ + { + branchSideEffects ((unsigned char *) pc, branchCode); + if (willBranch ((unsigned char *) pc, branchCode)) + registers[PC] = branchDestination ((unsigned char *) pc, branchCode); + else + registers[PC] = pc + INSTRUCTION_SIZE (pc); + return 0; /* branch "executed" -- just notify GDB */ + } + else if (((int) pc & 2) != 0) /* "second-slot" instruction */ + { + /* insert no-op before pc */ + stepping.noop_addr = pc - 2; + stepping.noop_save = *(unsigned short *) stepping.noop_addr; + *(unsigned short *) stepping.noop_addr = noop; + /* insert trap after pc */ + stepping.trap1_addr = pc + 2; + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + else /* "first-slot" instruction */ + { + /* insert trap after pc */ + stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc); + stepping.trap1_save = *(unsigned short *) stepping.trap1_addr; + *(unsigned short *) stepping.trap1_addr = trap1; + } + /* "continue_p" means that we are actually doing a continue, and not + being requested to single-step by GDB. Sometimes we have to do + one single-step before continuing, because the PC is on a half-word + boundary. There's no way to simply resume at such an address. */ + stepping.continue_p = continue_p; + stepping.stepping = 1; /* starting a single-step */ + return 1; +} + +/* Function: finish_from_step + Called from handle_exception to finish up when the user program + returns from a single-step. Replaces the instructions that had + been overwritten by traps or no-ops, + + Returns: True if we should notify GDB that the target stopped. + False if we only single-stepped because we had to before we + could continue (ie. we were trying to continue at a + half-word boundary). In that case don't notify GDB: + just "continue continuing". */ + +static int +finish_from_step (void) +{ + if (stepping.stepping) /* anything to do? */ + { + int continue_p = stepping.continue_p; + unsigned char *p; + + if (stepping.noop_addr) /* replace instr "under" our no-op */ + *(unsigned short *) stepping.noop_addr = stepping.noop_save; + if (stepping.trap1_addr) /* replace instr "under" our trap */ + *(unsigned short *) stepping.trap1_addr = stepping.trap1_save; + if (stepping.trap2_addr) /* ditto our other trap, if any */ + *(unsigned short *) stepping.trap2_addr = stepping.trap2_save; + + for (p = (unsigned char *) &stepping; /* zero out the stepping context */ + p < ((unsigned char *) &stepping) + sizeof (stepping); p++) + *p = 0; + + return !(continue_p); + } + else /* we didn't single-step, therefore this must be a legitimate stop */ + return 1; +} + +struct PSWreg +{ /* separate out the bit flags in the PSW register */ + int pad1:16; + int bsm:1; + int bie:1; + int pad2:5; + int bc:1; + int sm:1; + int ie:1; + int pad3:5; + int c:1; +} *psw; + +/* Upon entry the value for LR to save has been pushed. + We unpush that so that the value for the stack pointer saved is correct. + Upon entry, all other registers are assumed to have not been modified + since the interrupt/trap occured. */ + +asm ("\n\ +stash_registers:\n\ + push r0\n\ + push r1\n\ + seth r1, #shigh(registers)\n\ + add3 r1, r1, #low(registers)\n\ + pop r0 ; r1\n\ + st r0, @(4,r1)\n\ + pop r0 ; r0\n\ + st r0, @r1\n\ + addi r1, #4 ; only add 4 as subsequent saves are `pre inc'\n\ + st r2, @+r1\n\ + st r3, @+r1\n\ + st r4, @+r1\n\ + st r5, @+r1\n\ + st r6, @+r1\n\ + st r7, @+r1\n\ + st r8, @+r1\n\ + st r9, @+r1\n\ + st r10, @+r1\n\ + st r11, @+r1\n\ + st r12, @+r1\n\ + st r13, @+r1 ; fp\n\ + pop r0 ; lr (r14)\n\ + st r0, @+r1\n\ + st sp, @+r1 ; sp contains right value at this point\n\ + mvfc r0, cr0\n\ + st r0, @+r1 ; cr0 == PSW\n\ + mvfc r0, cr1\n\ + st r0, @+r1 ; cr1 == CBR\n\ + mvfc r0, cr2\n\ + st r0, @+r1 ; cr2 == SPI\n\ + mvfc r0, cr3\n\ + st r0, @+r1 ; cr3 == SPU\n\ + mvfc r0, cr6\n\ + st r0, @+r1 ; cr6 == BPC\n\ + st r0, @+r1 ; PC == BPC\n\ + mvfaclo r0\n\ + st r0, @+r1 ; ACCL\n\ + mvfachi r0\n\ + st r0, @+r1 ; ACCH\n\ + jmp lr"); + +/* C routine to clean up what stash_registers did. + It is called after calling stash_registers. + This is separate from stash_registers as we want to do this in C + but doing stash_registers in C isn't straightforward. */ + +static void +cleanup_stash (void) +{ + psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */ + psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */ + psw->ie = psw->bie; + psw->c = psw->bc; + registers[CBR] = psw->bc; /* fix up pre-trap "C" register */ + +#if 0 /* FIXME: Was in previous version. Necessary? + (Remember that we use the "rte" insn to return from the + trap/interrupt so the values of bsm, bie, bc are important. */ + psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */ +#endif + + /* FIXME: Copied from previous version. This can probably be deleted + since methinks stash_registers has already done this. */ + registers[PC] = registers[BPC]; /* pre-trap PC */ + + /* FIXME: Copied from previous version. Necessary? */ + if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */ + registers[SPU] = registers[R15]; + else + registers[SPI] = registers[R15]; +} + +asm ("\n\ +restore_and_return:\n\ + seth r0, #shigh(registers+8)\n\ + add3 r0, r0, #low(registers+8)\n\ + ld r2, @r0+ ; restore r2\n\ + ld r3, @r0+ ; restore r3\n\ + ld r4, @r0+ ; restore r4\n\ + ld r5, @r0+ ; restore r5\n\ + ld r6, @r0+ ; restore r6\n\ + ld r7, @r0+ ; restore r7\n\ + ld r8, @r0+ ; restore r8\n\ + ld r9, @r0+ ; restore r9\n\ + ld r10, @r0+ ; restore r10\n\ + ld r11, @r0+ ; restore r11\n\ + ld r12, @r0+ ; restore r12\n\ + ld r13, @r0+ ; restore r13\n\ + ld r14, @r0+ ; restore r14\n\ + ld r15, @r0+ ; restore r15\n\ + ld r1, @r0+ ; restore cr0 == PSW\n\ + mvtc r1, cr0\n\ + ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)\n\ + mvtc r1, cr1\n\ + ld r1, @r0+ ; restore cr2 == SPI\n\ + mvtc r1, cr2\n\ + ld r1, @r0+ ; restore cr3 == SPU\n\ + mvtc r1, cr3\n\ + addi r0, #4 ; skip BPC\n\ + ld r1, @r0+ ; restore cr6 (BPC) == PC\n\ + mvtc r1, cr6\n\ + ld r1, @r0+ ; restore ACCL\n\ + mvtaclo r1\n\ + ld r1, @r0+ ; restore ACCH\n\ + mvtachi r1\n\ + seth r0, #shigh(registers)\n\ + add3 r0, r0, #low(registers)\n\ + ld r1, @(4,r0) ; restore r1\n\ + ld r0, @r0 ; restore r0\n\ + rte"); + +/* General trap handler, called after the registers have been stashed. + NUM is the trap/exception number. */ + +static void +process_exception (int num) +{ + cleanup_stash (); + asm volatile ("\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + mv r0, %0\n\ + bl handle_exception\n\ + bl restore_and_return"::"r" (num):"r0", "r1"); +} + +void _catchException0 (); + +asm ("\n\ +_catchException0:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #0\n\ + bl process_exception"); + +void _catchException1 (); + +asm ("\n\ +_catchException1:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + bl cleanup_stash\n\ + seth r1, #shigh(stackPtr)\n\ + add3 r1, r1, #low(stackPtr)\n\ + ld r15, @r1 ; setup local stack (protect user stack)\n\ + seth r1, #shigh(registers + 21*4) ; PC\n\ + add3 r1, r1, #low(registers + 21*4)\n\ + ld r0, @r1\n\ + addi r0, #-4 ; back up PC for breakpoint trap.\n\ + st r0, @r1 ; FIXME: what about bp in right slot?\n\ + ldi r0, #1\n\ + bl handle_exception\n\ + bl restore_and_return"); + +void _catchException2 (); + +asm ("\n\ +_catchException2:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #2\n\ + bl process_exception"); + +void _catchException3 (); + +asm ("\n\ +_catchException3:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #3\n\ + bl process_exception"); + +void _catchException4 (); + +asm ("\n\ +_catchException4:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #4\n\ + bl process_exception"); + +void _catchException5 (); + +asm ("\n\ +_catchException5:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #5\n\ + bl process_exception"); + +void _catchException6 (); + +asm ("\n\ +_catchException6:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #6\n\ + bl process_exception"); + +void _catchException7 (); + +asm ("\n\ +_catchException7:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #7\n\ + bl process_exception"); + +void _catchException8 (); + +asm ("\n\ +_catchException8:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #8\n\ + bl process_exception"); + +void _catchException9 (); + +asm ("\n\ +_catchException9:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #9\n\ + bl process_exception"); + +void _catchException10 (); + +asm ("\n\ +_catchException10:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #10\n\ + bl process_exception"); + +void _catchException11 (); + +asm ("\n\ +_catchException11:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #11\n\ + bl process_exception"); + +void _catchException12 (); + +asm ("\n\ +_catchException12:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #12\n\ + bl process_exception"); + +void _catchException13 (); + +asm ("\n\ +_catchException13:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #13\n\ + bl process_exception"); + +void _catchException14 (); + +asm ("\n\ +_catchException14:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #14\n\ + bl process_exception"); + +void _catchException15 (); + +asm ("\n\ +_catchException15:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #15\n\ + bl process_exception"); + +void _catchException16 (); + +asm ("\n\ +_catchException16:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #16\n\ + bl process_exception"); + +void _catchException17 (); + +asm ("\n\ +_catchException17:\n\ + push lr\n\ + bl stash_registers\n\ + ; Note that at this point the pushed value of `lr' has been popped\n\ + ldi r0, #17\n\ + bl process_exception"); + + +/* this function is used to set up exception handlers for tracing and + breakpoints */ +void +set_debug_traps (void) +{ + /* extern void remcomHandler(); */ + int i; + + for (i = 0; i < 18; i++) /* keep a copy of old vectors */ + if (save_vectors[i] == 0) /* only copy them the first time */ + save_vectors[i] = getExceptionHandler (i); + + stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1]; + + exceptionHandler (0, _catchException0); + exceptionHandler (1, _catchException1); + exceptionHandler (2, _catchException2); + exceptionHandler (3, _catchException3); + exceptionHandler (4, _catchException4); + exceptionHandler (5, _catchException5); + exceptionHandler (6, _catchException6); + exceptionHandler (7, _catchException7); + exceptionHandler (8, _catchException8); + exceptionHandler (9, _catchException9); + exceptionHandler (10, _catchException10); + exceptionHandler (11, _catchException11); + exceptionHandler (12, _catchException12); + exceptionHandler (13, _catchException13); + exceptionHandler (14, _catchException14); + exceptionHandler (15, _catchException15); + exceptionHandler (16, _catchException16); + /* exceptionHandler (17, _catchException17); */ + + initialized = 1; +} + +/* This function will generate a breakpoint exception. It is used at the + beginning of a program to sync up with a debugger and can be used + otherwise as a quick means to stop program execution and "break" into + the debugger. */ + +#define BREAKPOINT() asm volatile (" trap #2"); + +void +breakpoint (void) +{ + if (initialized) + BREAKPOINT (); +} + +/* STDOUT section: + Stuff pertaining to simulating stdout by sending chars to gdb to be echoed. + Functions: gdb_putchar(char ch) + gdb_puts(char *str) + gdb_write(char *str, int len) + gdb_error(char *format, char *parm) + */ + +/* Function: gdb_putchar(int) + Make gdb write a char to stdout. + Returns: the char */ + +static int +gdb_putchar (int ch) +{ + char buf[4]; + + buf[0] = 'O'; + buf[1] = hexchars[ch >> 4]; + buf[2] = hexchars[ch & 0x0F]; + buf[3] = 0; + putpacket (buf); + return ch; +} + +/* Function: gdb_write(char *, int) + Make gdb write n bytes to stdout (not assumed to be null-terminated). + Returns: number of bytes written */ + +static int +gdb_write (char *data, int len) +{ + char *buf, *cpy; + int i; + + buf = remcomOutBuffer; + buf[0] = 'O'; + i = 0; + while (i < len) + { + for (cpy = buf + 1; + i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++) + { + *cpy++ = hexchars[data[i] >> 4]; + *cpy++ = hexchars[data[i] & 0x0F]; + } + *cpy = 0; + putpacket (buf); + } + return len; +} + +/* Function: gdb_puts(char *) + Make gdb write a null-terminated string to stdout. + Returns: the length of the string */ + +static int +gdb_puts (char *str) +{ + return gdb_write (str, strlen (str)); +} + +/* Function: gdb_error(char *, char *) + Send an error message to gdb's stdout. + First string may have 1 (one) optional "%s" in it, which + will cause the optional second string to be inserted. */ + +static void +gdb_error (char *format, char *parm) +{ + char buf[400], *cpy; + int len; + + if (remote_debug) + { + if (format && *format) + len = strlen (format); + else + return; /* empty input */ + + if (parm && *parm) + len += strlen (parm); + + for (cpy = buf; *format;) + { + if (format[0] == '%' && format[1] == 's') /* include second string */ + { + format += 2; /* advance two chars instead of just one */ + while (parm && *parm) + *cpy++ = *parm++; + } + else + *cpy++ = *format++; + } + *cpy = '\0'; + gdb_puts (buf); + } +} + +static unsigned char * +strcpy (unsigned char *dest, const unsigned char *src) +{ + unsigned char *ret = dest; + + if (dest && src) + { + while (*src) + *dest++ = *src++; + *dest = 0; + } + return ret; +} + +static int +strlen (const unsigned char *src) +{ + int ret; + + for (ret = 0; *src; src++) + ret++; + + return ret; +} + +#if 0 +void +exit (code) + int code; +{ + _exit (code); +} + +int +atexit (void *p) +{ + return 0; +} + +void +abort (void) +{ + _exit (1); +} +#endif diff --git a/gdb/m32r-tdep.c b/gdb/m32r-tdep.c index 93edbf99a2d..a40f67d17d5 100644 --- a/gdb/m32r-tdep.c +++ b/gdb/m32r-tdep.c @@ -1,708 +1,989 @@ -// OBSOLETE /* Target-dependent code for the Mitsubishi m32r for GDB, the GNU debugger. -// OBSOLETE -// OBSOLETE Copyright 1996, 1998, 1999, 2000, 2001, 2003 Free Software -// OBSOLETE Foundation, Inc. -// OBSOLETE -// OBSOLETE This file is part of GDB. -// OBSOLETE -// OBSOLETE This program is free software; you can redistribute it and/or modify -// OBSOLETE it under the terms of the GNU General Public License as published by -// OBSOLETE the Free Software Foundation; either version 2 of the License, or -// OBSOLETE (at your option) any later version. -// OBSOLETE -// OBSOLETE This program is distributed in the hope that it will be useful, -// OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of -// OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// OBSOLETE GNU General Public License for more details. -// OBSOLETE -// OBSOLETE You should have received a copy of the GNU General Public License -// OBSOLETE along with this program; if not, write to the Free Software -// OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330, -// OBSOLETE Boston, MA 02111-1307, USA. */ -// OBSOLETE -// OBSOLETE #include "defs.h" -// OBSOLETE #include "frame.h" -// OBSOLETE #include "inferior.h" -// OBSOLETE #include "target.h" -// OBSOLETE #include "value.h" -// OBSOLETE #include "bfd.h" -// OBSOLETE #include "gdb_string.h" -// OBSOLETE #include "gdbcore.h" -// OBSOLETE #include "symfile.h" -// OBSOLETE #include "regcache.h" -// OBSOLETE -// OBSOLETE /* Function: m32r_use_struct_convention -// OBSOLETE Return nonzero if call_function should allocate stack space for a -// OBSOLETE struct return? */ -// OBSOLETE int -// OBSOLETE m32r_use_struct_convention (int gcc_p, struct type *type) -// OBSOLETE { -// OBSOLETE return (TYPE_LENGTH (type) > 8); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: frame_find_saved_regs -// OBSOLETE Return the frame_saved_regs structure for the frame. -// OBSOLETE Doesn't really work for dummy frames, but it does pass back -// OBSOLETE an empty frame_saved_regs, so I guess that's better than total failure */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE m32r_frame_find_saved_regs (struct frame_info *fi, -// OBSOLETE struct frame_saved_regs *regaddr) -// OBSOLETE { -// OBSOLETE memcpy (regaddr, &fi->fsr, sizeof (struct frame_saved_regs)); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Turn this on if you want to see just how much instruction decoding -// OBSOLETE if being done, its quite a lot -// OBSOLETE */ -// OBSOLETE #if 0 -// OBSOLETE static void -// OBSOLETE dump_insn (char *commnt, CORE_ADDR pc, int insn) -// OBSOLETE { -// OBSOLETE printf_filtered (" %s %08x %08x ", -// OBSOLETE commnt, (unsigned int) pc, (unsigned int) insn); -// OBSOLETE TARGET_PRINT_INSN (pc, &tm_print_insn_info); -// OBSOLETE printf_filtered ("\n"); -// OBSOLETE } -// OBSOLETE #define insn_debug(args) { printf_filtered args; } -// OBSOLETE #else -// OBSOLETE #define dump_insn(a,b,c) {} -// OBSOLETE #define insn_debug(args) {} -// OBSOLETE #endif -// OBSOLETE -// OBSOLETE #define DEFAULT_SEARCH_LIMIT 44 -// OBSOLETE -// OBSOLETE /* Function: scan_prologue -// OBSOLETE This function decodes the target function prologue to determine -// OBSOLETE 1) the size of the stack frame, and 2) which registers are saved on it. -// OBSOLETE It saves the offsets of saved regs in the frame_saved_regs argument, -// OBSOLETE and returns the frame size. */ -// OBSOLETE -// OBSOLETE /* -// OBSOLETE The sequence it currently generates is: -// OBSOLETE -// OBSOLETE if (varargs function) { ddi sp,#n } -// OBSOLETE push registers -// OBSOLETE if (additional stack <= 256) { addi sp,#-stack } -// OBSOLETE else if (additional stack < 65k) { add3 sp,sp,#-stack -// OBSOLETE -// OBSOLETE } else if (additional stack) { -// OBSOLETE seth sp,#(stack & 0xffff0000) -// OBSOLETE or3 sp,sp,#(stack & 0x0000ffff) -// OBSOLETE sub sp,r4 -// OBSOLETE } -// OBSOLETE if (frame pointer) { -// OBSOLETE mv sp,fp -// OBSOLETE } -// OBSOLETE -// OBSOLETE These instructions are scheduled like everything else, so you should stop at -// OBSOLETE the first branch instruction. -// OBSOLETE -// OBSOLETE */ -// OBSOLETE -// OBSOLETE /* This is required by skip prologue and by m32r_init_extra_frame_info. -// OBSOLETE The results of decoding a prologue should be cached because this -// OBSOLETE thrashing is getting nuts. -// OBSOLETE I am thinking of making a container class with two indexes, name and -// OBSOLETE address. It may be better to extend the symbol table. -// OBSOLETE */ -// OBSOLETE -// OBSOLETE static void -// OBSOLETE decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit, CORE_ADDR *pl_endptr, /* var parameter */ -// OBSOLETE unsigned long *framelength, struct frame_info *fi, -// OBSOLETE struct frame_saved_regs *fsr) -// OBSOLETE { -// OBSOLETE unsigned long framesize; -// OBSOLETE int insn; -// OBSOLETE int op1; -// OBSOLETE int maybe_one_more = 0; -// OBSOLETE CORE_ADDR after_prologue = 0; -// OBSOLETE CORE_ADDR after_stack_adjust = 0; -// OBSOLETE CORE_ADDR current_pc; -// OBSOLETE -// OBSOLETE -// OBSOLETE framesize = 0; -// OBSOLETE after_prologue = 0; -// OBSOLETE insn_debug (("rd prolog l(%d)\n", scan_limit - current_pc)); -// OBSOLETE -// OBSOLETE for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2) -// OBSOLETE { -// OBSOLETE -// OBSOLETE insn = read_memory_unsigned_integer (current_pc, 2); -// OBSOLETE dump_insn ("insn-1", current_pc, insn); /* MTZ */ -// OBSOLETE -// OBSOLETE /* If this is a 32 bit instruction, we dont want to examine its -// OBSOLETE immediate data as though it were an instruction */ -// OBSOLETE if (current_pc & 0x02) -// OBSOLETE { /* Clear the parallel execution bit from 16 bit instruction */ -// OBSOLETE if (maybe_one_more) -// OBSOLETE { /* The last instruction was a branch, usually terminates -// OBSOLETE the series, but if this is a parallel instruction, -// OBSOLETE it may be a stack framing instruction */ -// OBSOLETE if (!(insn & 0x8000)) -// OBSOLETE { -// OBSOLETE insn_debug (("Really done")); -// OBSOLETE break; /* nope, we are really done */ -// OBSOLETE } -// OBSOLETE } -// OBSOLETE insn &= 0x7fff; /* decode this instruction further */ -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE if (maybe_one_more) -// OBSOLETE break; /* This isnt the one more */ -// OBSOLETE if (insn & 0x8000) -// OBSOLETE { -// OBSOLETE insn_debug (("32 bit insn\n")); -// OBSOLETE if (current_pc == scan_limit) -// OBSOLETE scan_limit += 2; /* extend the search */ -// OBSOLETE current_pc += 2; /* skip the immediate data */ -// OBSOLETE if (insn == 0x8faf) /* add3 sp, sp, xxxx */ -// OBSOLETE /* add 16 bit sign-extended offset */ -// OBSOLETE { -// OBSOLETE insn_debug (("stack increment\n")); -// OBSOLETE framesize += -((short) read_memory_unsigned_integer (current_pc, 2)); -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE if (((insn >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */ -// OBSOLETE read_memory_unsigned_integer (current_pc + 2, 2) == 0x0f24) -// OBSOLETE { /* subtract 24 bit sign-extended negative-offset */ -// OBSOLETE dump_insn ("insn-2", current_pc + 2, insn); -// OBSOLETE insn = read_memory_unsigned_integer (current_pc - 2, 4); -// OBSOLETE dump_insn ("insn-3(l4)", current_pc - 2, insn); -// OBSOLETE if (insn & 0x00800000) /* sign extend */ -// OBSOLETE insn |= 0xff000000; /* negative */ -// OBSOLETE else -// OBSOLETE insn &= 0x00ffffff; /* positive */ -// OBSOLETE framesize += insn; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE after_prologue = current_pc; -// OBSOLETE continue; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE op1 = insn & 0xf000; /* isolate just the first nibble */ -// OBSOLETE -// OBSOLETE if ((insn & 0xf0ff) == 0x207f) -// OBSOLETE { /* st reg, @-sp */ -// OBSOLETE int regno; -// OBSOLETE insn_debug (("push\n")); -// OBSOLETE #if 0 /* No, PUSH FP is not an indication that we will use a frame pointer. */ -// OBSOLETE if (((insn & 0xffff) == 0x2d7f) && fi) -// OBSOLETE fi->using_frame_pointer = 1; -// OBSOLETE #endif -// OBSOLETE framesize += 4; -// OBSOLETE #if 0 -// OBSOLETE /* Why should we increase the scan limit, just because we did a push? -// OBSOLETE And if there is a reason, surely we would only want to do it if we -// OBSOLETE had already reached the scan limit... */ -// OBSOLETE if (current_pc == scan_limit) -// OBSOLETE scan_limit += 2; -// OBSOLETE #endif -// OBSOLETE regno = ((insn >> 8) & 0xf); -// OBSOLETE if (fsr) /* save_regs offset */ -// OBSOLETE fsr->regs[regno] = framesize; -// OBSOLETE after_prologue = 0; -// OBSOLETE continue; -// OBSOLETE } -// OBSOLETE if ((insn >> 8) == 0x4f) /* addi sp, xx */ -// OBSOLETE /* add 8 bit sign-extended offset */ -// OBSOLETE { -// OBSOLETE int stack_adjust = (char) (insn & 0xff); -// OBSOLETE -// OBSOLETE /* there are probably two of these stack adjustments: -// OBSOLETE 1) A negative one in the prologue, and -// OBSOLETE 2) A positive one in the epilogue. -// OBSOLETE We are only interested in the first one. */ -// OBSOLETE -// OBSOLETE if (stack_adjust < 0) -// OBSOLETE { -// OBSOLETE framesize -= stack_adjust; -// OBSOLETE after_prologue = 0; -// OBSOLETE /* A frameless function may have no "mv fp, sp". -// OBSOLETE In that case, this is the end of the prologue. */ -// OBSOLETE after_stack_adjust = current_pc + 2; -// OBSOLETE } -// OBSOLETE continue; -// OBSOLETE } -// OBSOLETE if (insn == 0x1d8f) -// OBSOLETE { /* mv fp, sp */ -// OBSOLETE if (fi) -// OBSOLETE fi->using_frame_pointer = 1; /* fp is now valid */ -// OBSOLETE insn_debug (("done fp found\n")); -// OBSOLETE after_prologue = current_pc + 2; -// OBSOLETE break; /* end of stack adjustments */ -// OBSOLETE } -// OBSOLETE if (insn == 0x7000) /* Nop looks like a branch, continue explicitly */ -// OBSOLETE { -// OBSOLETE insn_debug (("nop\n")); -// OBSOLETE after_prologue = current_pc + 2; -// OBSOLETE continue; /* nop occurs between pushes */ -// OBSOLETE } -// OBSOLETE /* End of prolog if any of these are branch instructions */ -// OBSOLETE if ((op1 == 0x7000) -// OBSOLETE || (op1 == 0xb000) -// OBSOLETE || (op1 == 0xf000)) -// OBSOLETE { -// OBSOLETE after_prologue = current_pc; -// OBSOLETE insn_debug (("Done: branch\n")); -// OBSOLETE maybe_one_more = 1; -// OBSOLETE continue; -// OBSOLETE } -// OBSOLETE /* Some of the branch instructions are mixed with other types */ -// OBSOLETE if (op1 == 0x1000) -// OBSOLETE { -// OBSOLETE int subop = insn & 0x0ff0; -// OBSOLETE if ((subop == 0x0ec0) || (subop == 0x0fc0)) -// OBSOLETE { -// OBSOLETE insn_debug (("done: jmp\n")); -// OBSOLETE after_prologue = current_pc; -// OBSOLETE maybe_one_more = 1; -// OBSOLETE continue; /* jmp , jl */ -// OBSOLETE } -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE if (current_pc >= scan_limit) -// OBSOLETE { -// OBSOLETE if (pl_endptr) -// OBSOLETE { -// OBSOLETE #if 1 -// OBSOLETE if (after_stack_adjust != 0) -// OBSOLETE /* We did not find a "mv fp,sp", but we DID find -// OBSOLETE a stack_adjust. Is it safe to use that as the -// OBSOLETE end of the prologue? I just don't know. */ -// OBSOLETE { -// OBSOLETE *pl_endptr = after_stack_adjust; -// OBSOLETE if (framelength) -// OBSOLETE *framelength = framesize; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE #endif -// OBSOLETE /* We reached the end of the loop without finding the end -// OBSOLETE of the prologue. No way to win -- we should report failure. -// OBSOLETE The way we do that is to return the original start_pc. -// OBSOLETE GDB will set a breakpoint at the start of the function (etc.) */ -// OBSOLETE *pl_endptr = start_pc; -// OBSOLETE } -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE if (after_prologue == 0) -// OBSOLETE after_prologue = current_pc; -// OBSOLETE -// OBSOLETE insn_debug ((" framesize %d, firstline %08x\n", framesize, after_prologue)); -// OBSOLETE if (framelength) -// OBSOLETE *framelength = framesize; -// OBSOLETE if (pl_endptr) -// OBSOLETE *pl_endptr = after_prologue; -// OBSOLETE } /* decode_prologue */ -// OBSOLETE -// OBSOLETE /* Function: skip_prologue -// OBSOLETE Find end of function prologue */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_skip_prologue (CORE_ADDR pc) -// OBSOLETE { -// OBSOLETE CORE_ADDR func_addr, func_end; -// OBSOLETE struct symtab_and_line sal; -// OBSOLETE -// OBSOLETE /* See what the symbol table says */ -// OBSOLETE -// OBSOLETE if (find_pc_partial_function (pc, NULL, &func_addr, &func_end)) -// OBSOLETE { -// OBSOLETE sal = find_pc_line (func_addr, 0); -// OBSOLETE -// OBSOLETE if (sal.line != 0 && sal.end <= func_end) -// OBSOLETE { -// OBSOLETE -// OBSOLETE insn_debug (("BP after prologue %08x\n", sal.end)); -// OBSOLETE func_end = sal.end; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE /* Either there's no line info, or the line after the prologue is after -// OBSOLETE the end of the function. In this case, there probably isn't a -// OBSOLETE prologue. */ -// OBSOLETE { -// OBSOLETE insn_debug (("No line info, line(%x) sal_end(%x) funcend(%x)\n", -// OBSOLETE sal.line, sal.end, func_end)); -// OBSOLETE func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE else -// OBSOLETE func_end = pc + DEFAULT_SEARCH_LIMIT; -// OBSOLETE decode_prologue (pc, func_end, &sal.end, 0, 0, 0); -// OBSOLETE return sal.end; -// OBSOLETE } -// OBSOLETE -// OBSOLETE static unsigned long -// OBSOLETE m32r_scan_prologue (struct frame_info *fi, struct frame_saved_regs *fsr) -// OBSOLETE { -// OBSOLETE struct symtab_and_line sal; -// OBSOLETE CORE_ADDR prologue_start, prologue_end, current_pc; -// OBSOLETE unsigned long framesize = 0; -// OBSOLETE -// OBSOLETE /* this code essentially duplicates skip_prologue, -// OBSOLETE but we need the start address below. */ -// OBSOLETE -// OBSOLETE if (find_pc_partial_function (fi->pc, NULL, &prologue_start, &prologue_end)) -// OBSOLETE { -// OBSOLETE sal = find_pc_line (prologue_start, 0); -// OBSOLETE -// OBSOLETE if (sal.line == 0) /* no line info, use current PC */ -// OBSOLETE if (prologue_start == entry_point_address ()) -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE prologue_start = fi->pc; -// OBSOLETE prologue_end = prologue_start + 48; /* We're in the boondocks: -// OBSOLETE allow for 16 pushes, an add, -// OBSOLETE and "mv fp,sp" */ -// OBSOLETE } -// OBSOLETE #if 0 -// OBSOLETE prologue_end = min (prologue_end, fi->pc); -// OBSOLETE #endif -// OBSOLETE insn_debug (("fipc(%08x) start(%08x) end(%08x)\n", -// OBSOLETE fi->pc, prologue_start, prologue_end)); -// OBSOLETE prologue_end = min (prologue_end, prologue_start + DEFAULT_SEARCH_LIMIT); -// OBSOLETE decode_prologue (prologue_start, prologue_end, &prologue_end, &framesize, -// OBSOLETE fi, fsr); -// OBSOLETE return framesize; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: init_extra_frame_info -// OBSOLETE This function actually figures out the frame address for a given pc and -// OBSOLETE sp. This is tricky on the m32r because we sometimes don't use an explicit -// OBSOLETE frame pointer, and the previous stack pointer isn't necessarily recorded -// OBSOLETE on the stack. The only reliable way to get this info is to -// OBSOLETE examine the prologue. */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE m32r_init_extra_frame_info (struct frame_info *fi) -// OBSOLETE { -// OBSOLETE int reg; -// OBSOLETE -// OBSOLETE if (fi->next) -// OBSOLETE fi->pc = FRAME_SAVED_PC (fi->next); -// OBSOLETE -// OBSOLETE memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs); -// OBSOLETE -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) -// OBSOLETE { -// OBSOLETE /* We need to setup fi->frame here because run_stack_dummy gets it wrong -// OBSOLETE by assuming it's always FP. */ -// OBSOLETE fi->frame = deprecated_read_register_dummy (fi->pc, fi->frame, -// OBSOLETE SP_REGNUM); -// OBSOLETE fi->framesize = 0; -// OBSOLETE return; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE fi->using_frame_pointer = 0; -// OBSOLETE fi->framesize = m32r_scan_prologue (fi, &fi->fsr); -// OBSOLETE -// OBSOLETE if (!fi->next) -// OBSOLETE if (fi->using_frame_pointer) -// OBSOLETE { -// OBSOLETE fi->frame = read_register (FP_REGNUM); -// OBSOLETE } -// OBSOLETE else -// OBSOLETE fi->frame = read_register (SP_REGNUM); -// OBSOLETE else -// OBSOLETE /* fi->next means this is not the innermost frame */ if (fi->using_frame_pointer) -// OBSOLETE /* we have an FP */ -// OBSOLETE if (fi->next->fsr.regs[FP_REGNUM] != 0) /* caller saved our FP */ -// OBSOLETE fi->frame = read_memory_integer (fi->next->fsr.regs[FP_REGNUM], 4); -// OBSOLETE for (reg = 0; reg < NUM_REGS; reg++) -// OBSOLETE if (fi->fsr.regs[reg] != 0) -// OBSOLETE fi->fsr.regs[reg] = fi->frame + fi->framesize - fi->fsr.regs[reg]; -// OBSOLETE } -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: m32r_virtual_frame_pointer -// OBSOLETE Return the register that the function uses for a frame pointer, -// OBSOLETE plus any necessary offset to be applied to the register before -// OBSOLETE any frame pointer offsets. */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE m32r_virtual_frame_pointer (CORE_ADDR pc, long *reg, long *offset) -// OBSOLETE { -// OBSOLETE struct frame_info *fi = deprecated_frame_xmalloc (); -// OBSOLETE struct cleanup *old_chain = make_cleanup (xfree, fi); -// OBSOLETE -// OBSOLETE /* Set up a dummy frame_info. */ -// OBSOLETE fi->next = NULL; -// OBSOLETE fi->prev = NULL; -// OBSOLETE fi->frame = 0; -// OBSOLETE fi->pc = pc; -// OBSOLETE -// OBSOLETE /* Analyze the prolog and fill in the extra info. */ -// OBSOLETE m32r_init_extra_frame_info (fi); -// OBSOLETE -// OBSOLETE /* Results will tell us which type of frame it uses. */ -// OBSOLETE if (fi->using_frame_pointer) -// OBSOLETE { -// OBSOLETE *reg = FP_REGNUM; -// OBSOLETE *offset = 0; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE { -// OBSOLETE *reg = SP_REGNUM; -// OBSOLETE *offset = 0; -// OBSOLETE } -// OBSOLETE do_cleanups (old_chain); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: find_callers_reg -// OBSOLETE Find REGNUM on the stack. Otherwise, it's in an active register. One thing -// OBSOLETE we might want to do here is to check REGNUM against the clobber mask, and -// OBSOLETE somehow flag it as invalid if it isn't saved on the stack somewhere. This -// OBSOLETE would provide a graceful failure mode when trying to get the value of -// OBSOLETE caller-saves registers for an inner frame. */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_find_callers_reg (struct frame_info *fi, int regnum) -// OBSOLETE { -// OBSOLETE for (; fi; fi = fi->next) -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) -// OBSOLETE return deprecated_read_register_dummy (fi->pc, fi->frame, regnum); -// OBSOLETE else if (fi->fsr.regs[regnum] != 0) -// OBSOLETE return read_memory_integer (fi->fsr.regs[regnum], -// OBSOLETE REGISTER_RAW_SIZE (regnum)); -// OBSOLETE return read_register (regnum); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: frame_chain Given a GDB frame, determine the address of -// OBSOLETE the calling function's frame. This will be used to create a new -// OBSOLETE GDB frame struct, and then INIT_EXTRA_FRAME_INFO and -// OBSOLETE DEPRECATED_INIT_FRAME_PC will be called for the new frame. For -// OBSOLETE m32r, we save the frame size when we initialize the frame_info. */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_frame_chain (struct frame_info *fi) -// OBSOLETE { -// OBSOLETE CORE_ADDR fn_start, callers_pc, fp; -// OBSOLETE -// OBSOLETE /* is this a dummy frame? */ -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) -// OBSOLETE return fi->frame; /* dummy frame same as caller's frame */ -// OBSOLETE -// OBSOLETE /* is caller-of-this a dummy frame? */ -// OBSOLETE callers_pc = FRAME_SAVED_PC (fi); /* find out who called us: */ -// OBSOLETE fp = m32r_find_callers_reg (fi, FP_REGNUM); -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (callers_pc, fp, fp)) -// OBSOLETE return fp; /* dummy frame's frame may bear no relation to ours */ -// OBSOLETE -// OBSOLETE if (find_pc_partial_function (fi->pc, 0, &fn_start, 0)) -// OBSOLETE if (fn_start == entry_point_address ()) -// OBSOLETE return 0; /* in _start fn, don't chain further */ -// OBSOLETE if (fi->framesize == 0) -// OBSOLETE { -// OBSOLETE printf_filtered ("cannot determine frame size @ %s , pc(%s)\n", -// OBSOLETE paddr (fi->frame), -// OBSOLETE paddr (fi->pc)); -// OBSOLETE return 0; -// OBSOLETE } -// OBSOLETE insn_debug (("m32rx frame %08x\n", fi->frame + fi->framesize)); -// OBSOLETE return fi->frame + fi->framesize; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: push_return_address (pc) -// OBSOLETE Set up the return address for the inferior function call. -// OBSOLETE Necessary for targets that don't actually execute a JSR/BSR instruction -// OBSOLETE (ie. when using an empty CALL_DUMMY) */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_push_return_address (CORE_ADDR pc, CORE_ADDR sp) -// OBSOLETE { -// OBSOLETE write_register (RP_REGNUM, CALL_DUMMY_ADDRESS ()); -// OBSOLETE return sp; -// OBSOLETE } -// OBSOLETE -// OBSOLETE -// OBSOLETE /* Function: pop_frame -// OBSOLETE Discard from the stack the innermost frame, -// OBSOLETE restoring all saved registers. */ -// OBSOLETE -// OBSOLETE struct frame_info * -// OBSOLETE m32r_pop_frame (struct frame_info *frame) -// OBSOLETE { -// OBSOLETE int regnum; -// OBSOLETE -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) -// OBSOLETE generic_pop_dummy_frame (); -// OBSOLETE else -// OBSOLETE { -// OBSOLETE for (regnum = 0; regnum < NUM_REGS; regnum++) -// OBSOLETE if (frame->fsr.regs[regnum] != 0) -// OBSOLETE write_register (regnum, -// OBSOLETE read_memory_integer (frame->fsr.regs[regnum], 4)); -// OBSOLETE -// OBSOLETE write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); -// OBSOLETE write_register (SP_REGNUM, read_register (FP_REGNUM)); -// OBSOLETE if (read_register (PSW_REGNUM) & 0x80) -// OBSOLETE write_register (SPU_REGNUM, read_register (SP_REGNUM)); -// OBSOLETE else -// OBSOLETE write_register (SPI_REGNUM, read_register (SP_REGNUM)); -// OBSOLETE } -// OBSOLETE flush_cached_frames (); -// OBSOLETE return NULL; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: frame_saved_pc -// OBSOLETE Find the caller of this frame. We do this by seeing if RP_REGNUM is saved -// OBSOLETE in the stack anywhere, otherwise we get it from the registers. */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_frame_saved_pc (struct frame_info *fi) -// OBSOLETE { -// OBSOLETE if (DEPRECATED_PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) -// OBSOLETE return deprecated_read_register_dummy (fi->pc, fi->frame, PC_REGNUM); -// OBSOLETE else -// OBSOLETE return m32r_find_callers_reg (fi, RP_REGNUM); -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: push_arguments -// OBSOLETE Setup the function arguments for calling a function in the inferior. -// OBSOLETE -// OBSOLETE On the Mitsubishi M32R architecture, there are four registers (R0 to R3) -// OBSOLETE which are dedicated for passing function arguments. Up to the first -// OBSOLETE four arguments (depending on size) may go into these registers. -// OBSOLETE The rest go on the stack. -// OBSOLETE -// OBSOLETE Arguments that are smaller than 4 bytes will still take up a whole -// OBSOLETE register or a whole 32-bit word on the stack, and will be -// OBSOLETE right-justified in the register or the stack word. This includes -// OBSOLETE chars, shorts, and small aggregate types. -// OBSOLETE -// OBSOLETE Arguments of 8 bytes size are split between two registers, if -// OBSOLETE available. If only one register is available, the argument will -// OBSOLETE be split between the register and the stack. Otherwise it is -// OBSOLETE passed entirely on the stack. Aggregate types with sizes between -// OBSOLETE 4 and 8 bytes are passed entirely on the stack, and are left-justified -// OBSOLETE within the double-word (as opposed to aggregates smaller than 4 bytes -// OBSOLETE which are right-justified). -// OBSOLETE -// OBSOLETE Aggregates of greater than 8 bytes are first copied onto the stack, -// OBSOLETE and then a pointer to the copy is passed in the place of the normal -// OBSOLETE argument (either in a register if available, or on the stack). -// OBSOLETE -// OBSOLETE Functions that must return an aggregate type can return it in the -// OBSOLETE normal return value registers (R0 and R1) if its size is 8 bytes or -// OBSOLETE less. For larger return values, the caller must allocate space for -// OBSOLETE the callee to copy the return value to. A pointer to this space is -// OBSOLETE passed as an implicit first argument, always in R0. */ -// OBSOLETE -// OBSOLETE CORE_ADDR -// OBSOLETE m32r_push_arguments (int nargs, struct value **args, CORE_ADDR sp, -// OBSOLETE unsigned char struct_return, CORE_ADDR struct_addr) -// OBSOLETE { -// OBSOLETE int stack_offset, stack_alloc; -// OBSOLETE int argreg; -// OBSOLETE int argnum; -// OBSOLETE struct type *type; -// OBSOLETE CORE_ADDR regval; -// OBSOLETE char *val; -// OBSOLETE char valbuf[4]; -// OBSOLETE int len; -// OBSOLETE int odd_sized_struct; -// OBSOLETE -// OBSOLETE /* first force sp to a 4-byte alignment */ -// OBSOLETE sp = sp & ~3; -// OBSOLETE -// OBSOLETE argreg = ARG0_REGNUM; -// OBSOLETE /* The "struct return pointer" pseudo-argument goes in R0 */ -// OBSOLETE if (struct_return) -// OBSOLETE write_register (argreg++, struct_addr); -// OBSOLETE -// OBSOLETE /* Now make sure there's space on the stack */ -// OBSOLETE for (argnum = 0, stack_alloc = 0; -// OBSOLETE argnum < nargs; argnum++) -// OBSOLETE stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3); -// OBSOLETE sp -= stack_alloc; /* make room on stack for args */ -// OBSOLETE -// OBSOLETE -// OBSOLETE /* Now load as many as possible of the first arguments into -// OBSOLETE registers, and push the rest onto the stack. There are 16 bytes -// OBSOLETE in four registers available. Loop thru args from first to last. */ -// OBSOLETE -// OBSOLETE argreg = ARG0_REGNUM; -// OBSOLETE for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) -// OBSOLETE { -// OBSOLETE type = VALUE_TYPE (args[argnum]); -// OBSOLETE len = TYPE_LENGTH (type); -// OBSOLETE memset (valbuf, 0, sizeof (valbuf)); -// OBSOLETE if (len < 4) -// OBSOLETE { /* value gets right-justified in the register or stack word */ -// OBSOLETE memcpy (valbuf + (4 - len), -// OBSOLETE (char *) VALUE_CONTENTS (args[argnum]), len); -// OBSOLETE val = valbuf; -// OBSOLETE } -// OBSOLETE else -// OBSOLETE val = (char *) VALUE_CONTENTS (args[argnum]); -// OBSOLETE -// OBSOLETE if (len > 4 && (len & 3) != 0) -// OBSOLETE odd_sized_struct = 1; /* such structs go entirely on stack */ -// OBSOLETE else -// OBSOLETE odd_sized_struct = 0; -// OBSOLETE while (len > 0) -// OBSOLETE { -// OBSOLETE if (argreg > ARGLAST_REGNUM || odd_sized_struct) -// OBSOLETE { /* must go on the stack */ -// OBSOLETE write_memory (sp + stack_offset, val, 4); -// OBSOLETE stack_offset += 4; -// OBSOLETE } -// OBSOLETE /* NOTE WELL!!!!! This is not an "else if" clause!!! -// OBSOLETE That's because some *&^%$ things get passed on the stack -// OBSOLETE AND in the registers! */ -// OBSOLETE if (argreg <= ARGLAST_REGNUM) -// OBSOLETE { /* there's room in a register */ -// OBSOLETE regval = extract_address (val, REGISTER_RAW_SIZE (argreg)); -// OBSOLETE write_register (argreg++, regval); -// OBSOLETE } -// OBSOLETE /* Store the value 4 bytes at a time. This means that things -// OBSOLETE larger than 4 bytes may go partly in registers and partly -// OBSOLETE on the stack. */ -// OBSOLETE len -= REGISTER_RAW_SIZE (argreg); -// OBSOLETE val += REGISTER_RAW_SIZE (argreg); -// OBSOLETE } -// OBSOLETE } -// OBSOLETE return sp; -// OBSOLETE } -// OBSOLETE -// OBSOLETE /* Function: fix_call_dummy -// OBSOLETE If there is real CALL_DUMMY code (eg. on the stack), this function -// OBSOLETE has the responsability to insert the address of the actual code that -// OBSOLETE is the target of the target function call. */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE m32r_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, -// OBSOLETE struct value **args, struct type *type, int gcc_p) -// OBSOLETE { -// OBSOLETE /* ld24 r8, <(imm24) fun> */ -// OBSOLETE *(unsigned long *) (dummy) = (fun & 0x00ffffff) | 0xe8000000; -// OBSOLETE } -// OBSOLETE -// OBSOLETE -// OBSOLETE /* Function: m32r_write_sp -// OBSOLETE Because SP is really a read-only register that mirrors either SPU or SPI, -// OBSOLETE we must actually write one of those two as well, depending on PSW. */ -// OBSOLETE -// OBSOLETE void -// OBSOLETE m32r_write_sp (CORE_ADDR val) -// OBSOLETE { -// OBSOLETE unsigned long psw = read_register (PSW_REGNUM); -// OBSOLETE -// OBSOLETE if (psw & 0x80) /* stack mode: user or interrupt */ -// OBSOLETE write_register (SPU_REGNUM, val); -// OBSOLETE else -// OBSOLETE write_register (SPI_REGNUM, val); -// OBSOLETE write_register (SP_REGNUM, val); -// OBSOLETE } -// OBSOLETE -// OBSOLETE void -// OBSOLETE _initialize_m32r_tdep (void) -// OBSOLETE { -// OBSOLETE tm_print_insn = print_insn_m32r; -// OBSOLETE } +/* Target-dependent code for Renesas M32R, for GDB. + + Copyright 1996, 1998, 1999, 2000, 2001, 2002, 2003 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 "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include "value.h" +#include "inferior.h" +#include "symfile.h" +#include "objfiles.h" +#include "language.h" +#include "arch-utils.h" +#include "regcache.h" +#include "trad-frame.h" + +#include "gdb_assert.h" + +struct gdbarch_tdep +{ + /* gdbarch target dependent data here. Currently unused for M32R. */ +}; + +/* m32r register names. */ + +enum +{ + R0_REGNUM = 0, + R3_REGNUM = 3, + M32R_FP_REGNUM = 13, + LR_REGNUM = 14, + M32R_SP_REGNUM = 15, + PSW_REGNUM = 16, + M32R_PC_REGNUM = 21, + /* m32r calling convention. */ + ARG1_REGNUM = R0_REGNUM, + ARGN_REGNUM = R3_REGNUM, + RET1_REGNUM = R0_REGNUM, +}; + +/* Local functions */ + +extern void _initialize_m32r_tdep (void); + +static CORE_ADDR +m32r_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + /* Align to the size of an instruction (so that they can safely be + pushed onto the stack. */ + return sp & ~3; +} + +/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of + EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc + and TYPE is the type (which is known to be struct, union or array). + + The m32r returns anything less than 8 bytes in size in + registers. */ + +static int +m32r_use_struct_convention (int gcc_p, struct type *type) +{ + return (TYPE_LENGTH (type) > 8); +} + + +/* BREAKPOINT */ +#define M32R_BE_BREAKPOINT32 {0x10, 0xf1, 0x70, 0x00} +#define M32R_LE_BREAKPOINT32 {0xf1, 0x10, 0x00, 0x70} +#define M32R_BE_BREAKPOINT16 {0x10, 0xf1} +#define M32R_LE_BREAKPOINT16 {0xf1, 0x10} + +static int +m32r_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache) +{ + int val; + unsigned char *bp; + int bplen; + + bplen = (addr & 3) ? 2 : 4; + + /* Save the memory contents. */ + val = target_read_memory (addr, contents_cache, bplen); + if (val != 0) + return val; /* return error */ + + /* Determine appropriate breakpoint contents and size for this address. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + if (((addr & 3) == 0) && + ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80))) + { + static unsigned char insn[] = M32R_BE_BREAKPOINT32; + bp = insn; + bplen = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_BE_BREAKPOINT16; + bp = insn; + bplen = sizeof (insn); + } + } + else + { /* little-endian */ + if (((addr & 3) == 0) && + ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80))) + { + static unsigned char insn[] = M32R_LE_BREAKPOINT32; + bp = insn; + bplen = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_LE_BREAKPOINT16; + bp = insn; + bplen = sizeof (insn); + } + } + + /* Write the breakpoint. */ + val = target_write_memory (addr, (char *) bp, bplen); + return val; +} + +static int +m32r_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache) +{ + int val; + int bplen; + + /* Determine appropriate breakpoint contents and size for this address. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + if (((addr & 3) == 0) && + ((contents_cache[0] & 0x80) || (contents_cache[2] & 0x80))) + { + static unsigned char insn[] = M32R_BE_BREAKPOINT32; + bplen = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_BE_BREAKPOINT16; + bplen = sizeof (insn); + } + } + else + { + /* little-endian */ + if (((addr & 3) == 0) && + ((contents_cache[1] & 0x80) || (contents_cache[3] & 0x80))) + { + static unsigned char insn[] = M32R_BE_BREAKPOINT32; + bplen = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_BE_BREAKPOINT16; + bplen = sizeof (insn); + } + } + + /* Write contents. */ + val = target_write_memory (addr, contents_cache, bplen); + return val; +} + +static const unsigned char * +m32r_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr) +{ + unsigned char *bp; + + /* Determine appropriate breakpoint. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + if ((*pcptr & 3) == 0) + { + static unsigned char insn[] = M32R_BE_BREAKPOINT32; + bp = insn; + *lenptr = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_BE_BREAKPOINT16; + bp = insn; + *lenptr = sizeof (insn); + } + } + else + { + if ((*pcptr & 3) == 0) + { + static unsigned char insn[] = M32R_LE_BREAKPOINT32; + bp = insn; + *lenptr = sizeof (insn); + } + else + { + static unsigned char insn[] = M32R_LE_BREAKPOINT16; + bp = insn; + *lenptr = sizeof (insn); + } + } + + return bp; +} + + +char *m32r_register_names[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "fp", "lr", "sp", + "psw", "cbr", "spi", "spu", "bpc", "pc", "accl", "acch", + "evb" +}; + +static int +m32r_num_regs (void) +{ + return (sizeof (m32r_register_names) / sizeof (m32r_register_names[0])); +} + +static const char * +m32r_register_name (int reg_nr) +{ + if (reg_nr < 0) + return NULL; + if (reg_nr >= m32r_num_regs ()) + return NULL; + return m32r_register_names[reg_nr]; +} + + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +static struct type * +m32r_register_type (struct gdbarch *gdbarch, int reg_nr) +{ + if (reg_nr == M32R_PC_REGNUM) + return builtin_type_void_func_ptr; + else if (reg_nr == M32R_SP_REGNUM || reg_nr == M32R_FP_REGNUM) + return builtin_type_void_data_ptr; + else + return builtin_type_int32; +} + + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. + + Things always get returned in RET1_REGNUM, RET2_REGNUM. */ + +static void +m32r_store_return_value (struct type *type, struct regcache *regcache, + const void *valbuf) +{ + CORE_ADDR regval; + int len = TYPE_LENGTH (type); + + regval = extract_unsigned_integer (valbuf, len > 4 ? 4 : len); + regcache_cooked_write_unsigned (regcache, RET1_REGNUM, regval); + + if (len > 4) + { + regval = extract_unsigned_integer (valbuf + 4, len - 4); + regcache_cooked_write_unsigned (regcache, RET1_REGNUM + 1, regval); + } +} + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +static CORE_ADDR +m32r_extract_struct_value_address (struct regcache *regcache) +{ + ULONGEST addr; + regcache_cooked_read_unsigned (regcache, ARG1_REGNUM, &addr); + return addr; +} + + +/* This is required by skip_prologue. The results of decoding a prologue + should be cached because this thrashing is getting nuts. */ + +static void +decode_prologue (CORE_ADDR start_pc, CORE_ADDR scan_limit, + CORE_ADDR *pl_endptr) +{ + unsigned long framesize; + int insn; + int op1; + int maybe_one_more = 0; + CORE_ADDR after_prologue = 0; + CORE_ADDR after_stack_adjust = 0; + CORE_ADDR current_pc; + + framesize = 0; + after_prologue = 0; + + for (current_pc = start_pc; current_pc < scan_limit; current_pc += 2) + { + insn = read_memory_unsigned_integer (current_pc, 2); + + /* If this is a 32 bit instruction, we dont want to examine its + immediate data as though it were an instruction */ + if (current_pc & 0x02) + { + /* Clear the parallel execution bit from 16 bit instruction */ + if (maybe_one_more) + { + /* The last instruction was a branch, usually terminates + the series, but if this is a parallel instruction, + it may be a stack framing instruction */ + if (!(insn & 0x8000)) + { + /* nope, we are really done */ + break; + } + } + /* decode this instruction further */ + insn &= 0x7fff; + } + else + { + if (maybe_one_more) + break; /* This isnt the one more */ + if (insn & 0x8000) + { + if (current_pc == scan_limit) + scan_limit += 2; /* extend the search */ + current_pc += 2; /* skip the immediate data */ + if (insn == 0x8faf) /* add3 sp, sp, xxxx */ + /* add 16 bit sign-extended offset */ + { + framesize += + -((short) read_memory_unsigned_integer (current_pc, 2)); + } + else + { + if (((insn >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */ + read_memory_unsigned_integer (current_pc + 2, + 2) == 0x0f24) + /* subtract 24 bit sign-extended negative-offset */ + { + insn = read_memory_unsigned_integer (current_pc - 2, 4); + if (insn & 0x00800000) /* sign extend */ + insn |= 0xff000000; /* negative */ + else + insn &= 0x00ffffff; /* positive */ + framesize += insn; + } + } + after_prologue = current_pc; + continue; + } + } + op1 = insn & 0xf000; /* isolate just the first nibble */ + + if ((insn & 0xf0ff) == 0x207f) + { /* st reg, @-sp */ + int regno; + framesize += 4; + regno = ((insn >> 8) & 0xf); + after_prologue = 0; + continue; + } + if ((insn >> 8) == 0x4f) /* addi sp, xx */ + /* add 8 bit sign-extended offset */ + { + int stack_adjust = (char) (insn & 0xff); + + /* there are probably two of these stack adjustments: + 1) A negative one in the prologue, and + 2) A positive one in the epilogue. + We are only interested in the first one. */ + + if (stack_adjust < 0) + { + framesize -= stack_adjust; + after_prologue = 0; + /* A frameless function may have no "mv fp, sp". + In that case, this is the end of the prologue. */ + after_stack_adjust = current_pc + 2; + } + continue; + } + if (insn == 0x1d8f) + { /* mv fp, sp */ + after_prologue = current_pc + 2; + break; /* end of stack adjustments */ + } + /* Nop looks like a branch, continue explicitly */ + if (insn == 0x7000) + { + after_prologue = current_pc + 2; + continue; /* nop occurs between pushes */ + } + /* End of prolog if any of these are branch instructions */ + if ((op1 == 0x7000) || (op1 == 0xb000) || (op1 == 0xf000)) + { + after_prologue = current_pc; + maybe_one_more = 1; + continue; + } + /* Some of the branch instructions are mixed with other types */ + if (op1 == 0x1000) + { + int subop = insn & 0x0ff0; + if ((subop == 0x0ec0) || (subop == 0x0fc0)) + { + after_prologue = current_pc; + maybe_one_more = 1; + continue; /* jmp , jl */ + } + } + } + + if (current_pc >= scan_limit) + { + if (pl_endptr) + { + if (after_stack_adjust != 0) + /* We did not find a "mv fp,sp", but we DID find + a stack_adjust. Is it safe to use that as the + end of the prologue? I just don't know. */ + { + *pl_endptr = after_stack_adjust; + } + else + /* We reached the end of the loop without finding the end + of the prologue. No way to win -- we should report failure. + The way we do that is to return the original start_pc. + GDB will set a breakpoint at the start of the function (etc.) */ + *pl_endptr = start_pc; + } + return; + } + if (after_prologue == 0) + after_prologue = current_pc; + + if (pl_endptr) + *pl_endptr = after_prologue; +} /* decode_prologue */ + +/* Function: skip_prologue + Find end of function prologue */ + +#define DEFAULT_SEARCH_LIMIT 44 + +CORE_ADDR +m32r_skip_prologue (CORE_ADDR pc) +{ + CORE_ADDR func_addr, func_end; + struct symtab_and_line sal; + + /* See what the symbol table says */ + + if (find_pc_partial_function (pc, NULL, &func_addr, &func_end)) + { + sal = find_pc_line (func_addr, 0); + + if (sal.line != 0 && sal.end <= func_end) + { + func_end = sal.end; + } + else + /* Either there's no line info, or the line after the prologue is after + the end of the function. In this case, there probably isn't a + prologue. */ + { + func_end = min (func_end, func_addr + DEFAULT_SEARCH_LIMIT); + } + } + else + func_end = pc + DEFAULT_SEARCH_LIMIT; + decode_prologue (pc, func_end, &sal.end); + return sal.end; +} + + +struct m32r_unwind_cache +{ + /* The previous frame's inner most stack address. Used as this + frame ID's stack_addr. */ + CORE_ADDR prev_sp; + /* The frame's base, optionally used by the high-level debug info. */ + CORE_ADDR base; + int size; + /* How far the SP and r13 (FP) have been offset from the start of + the stack frame (as defined by the previous frame's stack + pointer). */ + LONGEST sp_offset; + LONGEST r13_offset; + int uses_frame; + /* Table indicating the location of each and every register. */ + struct trad_frame_saved_reg *saved_regs; +}; + +/* Put here the code to store, into fi->saved_regs, the addresses of + the saved registers of frame described by FRAME_INFO. This + includes special registers such as pc and fp saved in special ways + in the stack frame. sp is even more special: the address we return + for it IS the sp for the next frame. */ + +static struct m32r_unwind_cache * +m32r_frame_unwind_cache (struct frame_info *next_frame, + void **this_prologue_cache) +{ + CORE_ADDR pc; + ULONGEST prev_sp; + ULONGEST this_base; + unsigned long op; + int i; + struct m32r_unwind_cache *info; + + if ((*this_prologue_cache)) + return (*this_prologue_cache); + + info = FRAME_OBSTACK_ZALLOC (struct m32r_unwind_cache); + (*this_prologue_cache) = info; + info->saved_regs = trad_frame_alloc_saved_regs (next_frame); + + info->size = 0; + info->sp_offset = 0; + + info->uses_frame = 0; + for (pc = frame_func_unwind (next_frame); + pc > 0 && pc < frame_pc_unwind (next_frame); pc += 2) + { + if ((pc & 2) == 0) + { + op = get_frame_memory_unsigned (next_frame, pc, 4); + if ((op & 0x80000000) == 0x80000000) + { + /* 32-bit instruction */ + if ((op & 0xffff0000) == 0x8faf0000) + { + /* add3 sp,sp,xxxx */ + short n = op & 0xffff; + info->sp_offset += n; + } + else if (((op >> 8) == 0xe4) && /* ld24 r4, xxxxxx; sub sp, r4 */ + get_frame_memory_unsigned (next_frame, pc + 4, + 2) == 0x0f24) + { + unsigned long n = op & 0xffffff; + info->sp_offset += n; + pc += 2; + } + else + break; + + pc += 2; + continue; + } + } + + /* 16-bit instructions */ + op = get_frame_memory_unsigned (next_frame, pc, 2) & 0x7fff; + if ((op & 0xf0ff) == 0x207f) + { + /* st rn, @-sp */ + int regno = ((op >> 8) & 0xf); + info->sp_offset -= 4; + info->saved_regs[regno].addr = info->sp_offset; + } + else if ((op & 0xff00) == 0x4f00) + { + /* addi sp, xx */ + int n = (char) (op & 0xff); + info->sp_offset += n; + } + else if (op == 0x1d8f) + { + /* mv fp, sp */ + info->uses_frame = 1; + info->r13_offset = info->sp_offset; + } + else if (op == 0x7000) + /* nop */ + continue; + else + break; + } + + info->size = -info->sp_offset; + + /* Compute the previous frame's stack pointer (which is also the + frame's ID's stack address), and this frame's base pointer. */ + if (info->uses_frame) + { + /* The SP was moved to the FP. This indicates that a new frame + was created. Get THIS frame's FP value by unwinding it from + the next frame. */ + frame_unwind_unsigned_register (next_frame, M32R_FP_REGNUM, &this_base); + /* The FP points at the last saved register. Adjust the FP back + to before the first saved register giving the SP. */ + prev_sp = this_base + info->size; + } + else + { + /* Assume that the FP is this frame's SP but with that pushed + stack space added back. */ + frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &this_base); + prev_sp = this_base + info->size; + } + + /* Convert that SP/BASE into real addresses. */ + info->prev_sp = prev_sp; + info->base = this_base; + + /* Adjust all the saved registers so that they contain addresses and + not offsets. */ + for (i = 0; i < NUM_REGS - 1; i++) + if (trad_frame_addr_p (info->saved_regs, i)) + info->saved_regs[i].addr = (info->prev_sp + info->saved_regs[i].addr); + + /* The call instruction moves the caller's PC in the callee's LR. + Since this is an unwind, do the reverse. Copy the location of LR + into PC (the address / regnum) so that a request for PC will be + converted into a request for the LR. */ + info->saved_regs[M32R_PC_REGNUM] = info->saved_regs[LR_REGNUM]; + + /* The previous frame's SP needed to be computed. Save the computed + value. */ + trad_frame_set_value (info->saved_regs, M32R_SP_REGNUM, prev_sp); + + return info; +} + +static CORE_ADDR +m32r_read_pc (ptid_t ptid) +{ + ptid_t save_ptid; + CORE_ADDR pc; + + save_ptid = inferior_ptid; + inferior_ptid = ptid; + pc = (int) read_register (M32R_PC_REGNUM); + inferior_ptid = save_ptid; + return pc; +} + +static void +m32r_write_pc (CORE_ADDR val, ptid_t ptid) +{ + ptid_t save_ptid; + + save_ptid = inferior_ptid; + inferior_ptid = ptid; + write_register (M32R_PC_REGNUM, val); + inferior_ptid = save_ptid; +} + +static CORE_ADDR +m32r_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + ULONGEST sp; + frame_unwind_unsigned_register (next_frame, M32R_SP_REGNUM, &sp); + return sp; +} + + +static CORE_ADDR +m32r_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, + struct regcache *regcache, CORE_ADDR bp_addr, int nargs, + struct value **args, CORE_ADDR sp, int struct_return, + CORE_ADDR struct_addr) +{ + int stack_offset, stack_alloc; + int argreg = ARG1_REGNUM; + int argnum; + struct type *type; + enum type_code typecode; + CORE_ADDR regval; + char *val; + char valbuf[MAX_REGISTER_SIZE]; + int len; + int odd_sized_struct; + + /* first force sp to a 4-byte alignment */ + sp = sp & ~3; + + /* Set the return address. For the m32r, the return breakpoint is + always at BP_ADDR. */ + regcache_cooked_write_unsigned (regcache, LR_REGNUM, bp_addr); + + /* If STRUCT_RETURN is true, then the struct return address (in + STRUCT_ADDR) will consume the first argument-passing register. + Both adjust the register count and store that value. */ + if (struct_return) + { + regcache_cooked_write_unsigned (regcache, argreg, struct_addr); + argreg++; + } + + /* Now make sure there's space on the stack */ + for (argnum = 0, stack_alloc = 0; argnum < nargs; argnum++) + stack_alloc += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3); + sp -= stack_alloc; /* make room on stack for args */ + + for (argnum = 0, stack_offset = 0; argnum < nargs; argnum++) + { + type = VALUE_TYPE (args[argnum]); + typecode = TYPE_CODE (type); + len = TYPE_LENGTH (type); + + memset (valbuf, 0, sizeof (valbuf)); + + /* Passes structures that do not fit in 2 registers by reference. */ + if (len > 8 + && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) + { + store_unsigned_integer (valbuf, 4, VALUE_ADDRESS (args[argnum])); + typecode = TYPE_CODE_PTR; + len = 4; + val = valbuf; + } + else if (len < 4) + { + /* value gets right-justified in the register or stack word */ + memcpy (valbuf + (REGISTER_RAW_SIZE (argreg) - len), + (char *) VALUE_CONTENTS (args[argnum]), len); + val = valbuf; + } + else + val = (char *) VALUE_CONTENTS (args[argnum]); + + while (len > 0) + { + if (argreg > ARGN_REGNUM) + { + /* must go on the stack */ + write_memory (sp + stack_offset, val, 4); + stack_offset += 4; + } + else if (argreg <= ARGN_REGNUM) + { + /* there's room in a register */ + regval = + extract_unsigned_integer (val, REGISTER_RAW_SIZE (argreg)); + regcache_cooked_write_unsigned (regcache, argreg++, regval); + } + + /* Store the value 4 bytes at a time. This means that things + larger than 4 bytes may go partly in registers and partly + on the stack. */ + len -= REGISTER_RAW_SIZE (argreg); + val += REGISTER_RAW_SIZE (argreg); + } + } + + /* Finally, update the SP register. */ + regcache_cooked_write_unsigned (regcache, M32R_SP_REGNUM, sp); + + return sp; +} + + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + +static void +m32r_extract_return_value (struct type *type, struct regcache *regcache, + void *dst) +{ + bfd_byte *valbuf = dst; + int len = TYPE_LENGTH (type); + ULONGEST tmp; + + /* By using store_unsigned_integer we avoid having to do + anything special for small big-endian values. */ + regcache_cooked_read_unsigned (regcache, RET1_REGNUM, &tmp); + store_unsigned_integer (valbuf, (len > 4 ? len - 4 : len), tmp); + + /* Ignore return values more than 8 bytes in size because the m32r + returns anything more than 8 bytes in the stack. */ + if (len > 4) + { + regcache_cooked_read_unsigned (regcache, RET1_REGNUM + 1, &tmp); + store_unsigned_integer (valbuf + len - 4, 4, tmp); + } +} + + +static CORE_ADDR +m32r_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + ULONGEST pc; + frame_unwind_unsigned_register (next_frame, M32R_PC_REGNUM, &pc); + return pc; +} + +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +static void +m32r_frame_this_id (struct frame_info *next_frame, + void **this_prologue_cache, struct frame_id *this_id) +{ + struct m32r_unwind_cache *info + = m32r_frame_unwind_cache (next_frame, this_prologue_cache); + CORE_ADDR base; + CORE_ADDR func; + struct minimal_symbol *msym_stack; + struct frame_id id; + + /* The FUNC is easy. */ + func = frame_func_unwind (next_frame); + + /* This is meant to halt the backtrace at "_start". Make sure we + don't halt it at a generic dummy frame. */ + if (inside_entry_file (func)) + return; + + /* Check if the stack is empty. */ + msym_stack = lookup_minimal_symbol ("_stack", NULL, NULL); + if (msym_stack && info->base == SYMBOL_VALUE_ADDRESS (msym_stack)) + return; + + /* Hopefully the prologue analysis either correctly determined the + frame's base (which is the SP from the previous frame), or set + that base to "NULL". */ + base = info->prev_sp; + if (base == 0) + return; + + id = frame_id_build (base, func); + + /* Check that we're not going round in circles with the same frame + ID (but avoid applying the test to sentinel frames which do go + round in circles). Can't use frame_id_eq() as that doesn't yet + compare the frame's PC value. */ + if (frame_relative_level (next_frame) >= 0 + && get_frame_type (next_frame) != DUMMY_FRAME + && frame_id_eq (get_frame_id (next_frame), id)) + return; + + (*this_id) = id; +} + +static void +m32r_frame_prev_register (struct frame_info *next_frame, + void **this_prologue_cache, + int regnum, int *optimizedp, + enum lval_type *lvalp, CORE_ADDR *addrp, + int *realnump, void *bufferp) +{ + struct m32r_unwind_cache *info + = m32r_frame_unwind_cache (next_frame, this_prologue_cache); + trad_frame_prev_register (next_frame, info->saved_regs, regnum, + optimizedp, lvalp, addrp, realnump, bufferp); +} + +static const struct frame_unwind m32r_frame_unwind = { + NORMAL_FRAME, + m32r_frame_this_id, + m32r_frame_prev_register +}; + +static const struct frame_unwind * +m32r_frame_p (CORE_ADDR pc) +{ + return &m32r_frame_unwind; +} + +static CORE_ADDR +m32r_frame_base_address (struct frame_info *next_frame, void **this_cache) +{ + struct m32r_unwind_cache *info + = m32r_frame_unwind_cache (next_frame, this_cache); + return info->base; +} + +static const struct frame_base m32r_frame_base = { + &m32r_frame_unwind, + m32r_frame_base_address, + m32r_frame_base_address, + m32r_frame_base_address +}; + +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +m32r_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +{ + return frame_id_build (m32r_unwind_sp (gdbarch, next_frame), + frame_pc_unwind (next_frame)); +} + + +static gdbarch_init_ftype m32r_gdbarch_init; + +static struct gdbarch * +m32r_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + + /* If there is already a candidate, use it. */ + arches = gdbarch_list_lookup_by_info (arches, &info); + if (arches != NULL) + return arches->gdbarch; + + /* Allocate space for the new architecture. */ + tdep = XMALLOC (struct gdbarch_tdep); + gdbarch = gdbarch_alloc (&info, tdep); + + set_gdbarch_read_pc (gdbarch, m32r_read_pc); + set_gdbarch_write_pc (gdbarch, m32r_write_pc); + set_gdbarch_unwind_sp (gdbarch, m32r_unwind_sp); + + set_gdbarch_num_regs (gdbarch, m32r_num_regs ()); + set_gdbarch_sp_regnum (gdbarch, M32R_SP_REGNUM); + set_gdbarch_register_name (gdbarch, m32r_register_name); + set_gdbarch_register_type (gdbarch, m32r_register_type); + + set_gdbarch_extract_return_value (gdbarch, m32r_extract_return_value); + set_gdbarch_push_dummy_call (gdbarch, m32r_push_dummy_call); + set_gdbarch_store_return_value (gdbarch, m32r_store_return_value); + set_gdbarch_extract_struct_value_address (gdbarch, + m32r_extract_struct_value_address); + set_gdbarch_use_struct_convention (gdbarch, m32r_use_struct_convention); + + set_gdbarch_skip_prologue (gdbarch, m32r_skip_prologue); + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_decr_pc_after_break (gdbarch, 0); + set_gdbarch_function_start_offset (gdbarch, 0); + set_gdbarch_breakpoint_from_pc (gdbarch, m32r_breakpoint_from_pc); + set_gdbarch_memory_insert_breakpoint (gdbarch, + m32r_memory_insert_breakpoint); + set_gdbarch_memory_remove_breakpoint (gdbarch, + m32r_memory_remove_breakpoint); + + set_gdbarch_frame_args_skip (gdbarch, 0); + set_gdbarch_frameless_function_invocation (gdbarch, + frameless_look_for_prologue); + + set_gdbarch_frame_align (gdbarch, m32r_frame_align); + + frame_unwind_append_predicate (gdbarch, m32r_frame_p); + frame_base_set_default (gdbarch, &m32r_frame_base); + + /* Methods for saving / extracting a dummy frame's ID. The ID's + stack address must match the SP value returned by + PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */ + set_gdbarch_unwind_dummy_id (gdbarch, m32r_unwind_dummy_id); + + /* Return the unwound PC value. */ + set_gdbarch_unwind_pc (gdbarch, m32r_unwind_pc); + + set_gdbarch_print_insn (gdbarch, print_insn_m32r); + + return gdbarch; +} + +void +_initialize_m32r_tdep (void) +{ + register_gdbarch_init (bfd_arch_m32r, m32r_gdbarch_init); +}