From d9951af428a55c7ecc156c3d8aa4ccea02b99745 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Thu, 5 Sep 1996 01:01:05 +0000 Subject: [PATCH] * Makefile.in: Add mswin to SUBDIRS. Add rules for mswin/libwingdb.a and remote-wiggler.o. * breakpoint.c (breakpoint_here_p): Clean up bp enabled test. * (breakpoint_inserted_here_p): New func, just like breakpoint_here_p, except it's honest. Honestly. * breakpoint.h: Proto for above. start-sanitize-gdbtk * configure configure.in: Add host *windows* to list of hosts that don't support GDBtk. end-sanitize-gdbtk * configure configure.in: Add mswin to configdirs if host is i[3456]86-*-windows. * core-aout.c (fetch_core_registers register_addr) gdbcore.h: Change all vars that can contain addresses to type CORE_ADDR. * findvar.c (supply_register): Allow val to be NULL. This means that regno is unsupported. * (read_pc read_pc_pid write_pc write_pc_pid): Make non-pid forms just call pid forms with inferior_pid so that there's only once place to hack PC's and such. * infrun.c (proceed): Don't skip breakpoints if user changed PC. * remote-wiggler.c: New file. Support for BDM interface from Macraigor Systems. * serial.c: Enhance serial logging capability. Add hex and octal output modes (set remotelogbase {hex|octal|ascii}. Also log breaks, timeouts, errors, and eofs. * serial.h: Redefine SERIAL_SEND_BREAK to go through a wrapper function so that we can log breaks. Don't export serial_logfile or serial_logfp. * top.c (execute_command): Don't test for serial_logfp here. Just call serial_log_comand, and let serial.c sort it out. * valops.c (value_of_variable): Don't attempt to establish frames for static and global variables. This makes things work a bit better if the stack or frame pointer is trashed. * config/m68k/monitor.mt (TDEPFILES): Add remote-wiggler.o. * config/m68k/tm-m68k.h: Define STACK_ALIGN. CPU32 can't hack misaligned stacks during function calls. --- gdb/Makefile.in | 14 +- gdb/config/m68k/tm-m68k.h | 4 + gdb/configure | 160 +---- gdb/configure.in | 8 +- gdb/core-aout.c | 37 +- gdb/remote-wiggler.c | 1570 +++++++++++++++++++++++++++++++++++++++++++++ gdb/serial.c | 105 ++- gdb/serial.h | 8 +- gdb/top.c | 4 +- 9 files changed, 1708 insertions(+), 202 deletions(-) create mode 100644 gdb/remote-wiggler.c diff --git a/gdb/Makefile.in b/gdb/Makefile.in index a8d2101..344558c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -487,7 +487,7 @@ NTSOBS = standalone.o NTSSTART = kdb-start.o -SUBDIRS = doc testsuite nlm +SUBDIRS = doc testsuite nlm mswin # For now, shortcut the "configure GDB for fewer languages" stuff. YYFILES = c-exp.tab.c f-exp.tab.c m2-exp.tab.c @@ -582,7 +582,9 @@ init.c: $(OBS) $(TSOBS) @rm -f init.c-tmp @echo '/* Do not modify this file. */' >init.c-tmp @echo '/* It is created automatically by the Makefile. */'>>init.c-tmp - @echo 'void initialize_all_files () {' >>init.c-tmp + @echo '#include "ansidecl.h"' >>init.c-tmp + @echo 'extern void initialize_all_files PARAMS ((void));' >>init.c-tmp + @echo 'void initialize_all_files PARAMS ((void)) {' >>init.c-tmp @for i in $(OBS) $(TSOBS); do \ filename=`echo $$i | sed \ -e '/^Onindy.o/d' \ @@ -601,7 +603,7 @@ init.c: $(OBS) $(TSOBS) case $$filename in \ "") ;; \ *) sed <$(srcdir)/$$filename >>init.c-tmp -n \ - -e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\([a-z_0-9A-Z]*\).*/ {extern void \1 (); \1 ();}/p' ; ;; \ + -e '/^_initialize_[a-z_0-9A-Z]* *(/s/^\([a-z_0-9A-Z]*\).*/ {extern void \1 PARAMS ((void)); \1 ();}/p' ; ;; \ esac ; \ done @echo '}' >>init.c-tmp @@ -620,6 +622,9 @@ nlm: force libgdb: libgdb-files $(LIBGDB_OBS) +mswin/libwingdb.a: force + rootme=`pwd`; export rootme; $(MAKE) $(FLAGS_TO_PASS) DO=all DODIRS=mswin subdir_do + # libproc is not listed here because all-libproc is a dependency of all-gui, # not all-gdb, and thus might be built after us. LIBGDBDEPS=$(COMMON_OBS) $(LIBGDB_OBS) $(TSOBS) $(ADD_DEPS) $(CDEPS) init.o @@ -1406,6 +1411,9 @@ remote-vx29k.o: remote-vx29k.c $(wait_h) complaints.h $(defs_h) $(gdbcmd_h) \ vx-share/ptrace.h vx-share/xdr_ld.h vx-share/xdr_ptrace.h \ vx-share/xdr_rdb.h gdb_string.h +remote-wiggler.o: remote-wiggler.c $(wait_h) complaints.h $(defs_h) \ + $(gdbcmd_h) $(gdbcore_h) $(inferior_h) target.h + remote-utils.o: remote-utils.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \ $(inferior_h) $(remote_utils_h) gdb_string.h diff --git a/gdb/config/m68k/tm-m68k.h b/gdb/config/m68k/tm-m68k.h index 0c98e1d..6305f59 100644 --- a/gdb/config/m68k/tm-m68k.h +++ b/gdb/config/m68k/tm-m68k.h @@ -57,6 +57,10 @@ extern void m68k_find_saved_regs PARAMS ((struct frame_info *, struct frame_save #define INNER_THAN < +/* Stack must be kept short aligned when doing function calls. */ + +#define STACK_ALIGN(ADDR) (((ADDR) + 1) & ~1) + /* Sequence of bytes for breakpoint instruction. This is a TRAP instruction. The last 4 bits (0xf below) is the vector. Systems which don't use 0xf should define BPT_VECTOR diff --git a/gdb/configure b/gdb/configure index 70ec00d..8bcdc99 100755 --- a/gdb/configure +++ b/gdb/configure @@ -1869,147 +1869,9 @@ EOF fi -echo $ac_n "checking whether malloc must be declared""... $ac_c" 1>&6 -if eval "test \"`echo '$''{'bfd_cv_decl_needed_malloc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -int main() { return 0; } -int t() { -char *(*pfn) = (char *(*)) malloc -; return 0; } -EOF -if { (eval echo configure:1900: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - bfd_cv_decl_needed_malloc=no -else - rm -rf conftest* - bfd_cv_decl_needed_malloc=yes -fi -rm -f conftest* - -fi - -echo "$ac_t""$bfd_cv_decl_needed_malloc" 1>&6 -if test $bfd_cv_decl_needed_malloc = yes; then - bfd_tr_decl=NEED_DECLARATION_`echo malloc | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <&6 -if eval "test \"`echo '$''{'bfd_cv_decl_needed_realloc'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -int main() { return 0; } -int t() { -char *(*pfn) = (char *(*)) realloc -; return 0; } -EOF -if { (eval echo configure:1947: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - bfd_cv_decl_needed_realloc=no -else - rm -rf conftest* - bfd_cv_decl_needed_realloc=yes -fi -rm -f conftest* - -fi - -echo "$ac_t""$bfd_cv_decl_needed_realloc" 1>&6 -if test $bfd_cv_decl_needed_realloc = yes; then - bfd_tr_decl=NEED_DECLARATION_`echo realloc | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <&6 -if eval "test \"`echo '$''{'bfd_cv_decl_needed_free'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - cat > conftest.$ac_ext < -#ifdef HAVE_STRING_H -#include -#else -#ifdef HAVE_STRINGS_H -#include -#endif -#endif -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -int main() { return 0; } -int t() { -char *(*pfn) = (char *(*)) free -; return 0; } -EOF -if { (eval echo configure:1994: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* - bfd_cv_decl_needed_free=no -else - rm -rf conftest* - bfd_cv_decl_needed_free=yes -fi -rm -f conftest* - -fi - -echo "$ac_t""$bfd_cv_decl_needed_free" 1>&6 -if test $bfd_cv_decl_needed_free = yes; then - bfd_tr_decl=NEED_DECLARATION_`echo free | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` - cat >> confdefs.h <&2 enable_gdbtk=no ;; - *cygwin32*) + *cygwin32* | *windows*) echo "configure: warning: GDB does not support GDBtk on host ${host}. GDBtk will be disabled." 1>&2 enable_gdbtk=no ;; *) @@ -2107,9 +1969,7 @@ else # Default is on for everything but go32 and cygwin32 case "$host" in - *go32*) - ;; - *cygwin32*) + *go32* | *cygwin32* | *windows*) ;; *) enable_gdbtk=yes ;; @@ -2406,12 +2266,12 @@ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2415: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2275: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -2538,12 +2398,12 @@ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2547: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2407: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* @@ -2685,6 +2545,8 @@ i[3456]86-*-sysv*) gdb_host=i386v ;; i[3456]86-*-isc*) gdb_host=i386v32 ;; i[3456]86-*-os9k) gdb_host=i386os9k ;; i[3456]86-*-cygwin32) gdb_host=cygwin32 ;; +i[3456]86-*-windows) gdb_host=windows + configdirs="${configdirs} mswin" ;; m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; m68030-sony-*) gdb_host=news1000 ;; diff --git a/gdb/configure.in b/gdb/configure.in index 7c241a1..df786c2 100644 --- a/gdb/configure.in +++ b/gdb/configure.in @@ -208,7 +208,7 @@ AC_ARG_ENABLE(gdbtk, *go32*) AC_MSG_WARN([GDB does not support GDBtk on host ${host}. GDBtk will be disabled.]) enable_gdbtk=no ;; - *cygwin32*) + *cygwin32* | *windows*) AC_MSG_WARN([GDB does not support GDBtk on host ${host}. GDBtk will be disabled.]) enable_gdbtk=no ;; *) @@ -222,9 +222,7 @@ esac], [ # Default is on for everything but go32 and cygwin32 case "$host" in - *go32*) - ;; - *cygwin32*) + *go32* | *cygwin32* | *windows*) ;; *) enable_gdbtk=yes ;; @@ -346,6 +344,8 @@ i[3456]86-*-sysv*) gdb_host=i386v ;; i[3456]86-*-isc*) gdb_host=i386v32 ;; i[3456]86-*-os9k) gdb_host=i386os9k ;; i[3456]86-*-cygwin32) gdb_host=cygwin32 ;; +i[3456]86-*-windows) gdb_host=windows + configdirs="${configdirs} mswin" ;; m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; m68030-sony-*) gdb_host=news1000 ;; diff --git a/gdb/core-aout.c b/gdb/core-aout.c index ec755c5..a529cf9 100644 --- a/gdb/core-aout.c +++ b/gdb/core-aout.c @@ -52,8 +52,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #endif -static void -fetch_core_registers PARAMS ((char *, unsigned, int, unsigned)); +static void fetch_core_registers PARAMS ((char *core_reg_sect, + unsigned core_reg_size, int which, + CORE_ADDR reg_addr)); /* Extract the register values out of the core file and store them where `read_register' will find them. @@ -73,12 +74,12 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) char *core_reg_sect; unsigned core_reg_size; int which; - unsigned reg_addr; + CORE_ADDR reg_addr; { - register int regno; - register unsigned int addr; + int regno; + CORE_ADDR addr; int bad_reg = -1; - register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ + CORE_ADDR reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ int numregs = ARCH_NUM_REGS; /* If u.u_ar0 was an absolute address in the core file, relativize it now, @@ -87,23 +88,21 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) CORE_REGISTER_ADDR to offset to the other registers. If this is a modern core file without a upage, reg_ptr will be zero and this is all a big NOP. */ - if (reg_ptr > (int) core_reg_size) + if (reg_ptr > core_reg_size) reg_ptr -= KERNEL_U_ADDR; for (regno = 0; regno < numregs; regno++) { addr = CORE_REGISTER_ADDR (regno, reg_ptr); - if (addr >= core_reg_size) { - if (bad_reg < 0) - bad_reg = regno; - } else { - supply_register (regno, core_reg_sect + addr); - } + if (addr >= core_reg_size + && bad_reg < 0) + bad_reg = regno; + else + supply_register (regno, core_reg_sect + addr); } + if (bad_reg >= 0) - { - error ("Register %s not found in core file.", reg_names[bad_reg]); - } + error ("Register %s not found in core file.", reg_names[bad_reg]); } @@ -112,12 +111,12 @@ fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) /* Return the address in the core dump or inferior of register REGNO. BLOCKEND is the address of the end of the user structure. */ -unsigned int +CORE_ADDR register_addr (regno, blockend) int regno; - int blockend; + CORE_ADDR blockend; { - int addr; + CORE_ADDR addr; if (regno < 0 || regno >= ARCH_NUM_REGS) error ("Invalid register number %d.", regno); diff --git a/gdb/remote-wiggler.c b/gdb/remote-wiggler.c new file mode 100644 index 0000000..f70ca70 --- /dev/null +++ b/gdb/remote-wiggler.c @@ -0,0 +1,1570 @@ +/* Remote target communications for the Macraigor Systems BDM Wiggler + Copyright 1996 Free Software Foundation, Inc. + +This file is part of GDB. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "defs.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include +#include "frame.h" +#include "inferior.h" +#include "bfd.h" +#include "symfile.h" +#include "target.h" +#include "wait.h" +#include "gdbcmd.h" +#include "objfiles.h" +#include "gdb-stabs.h" + +#include "dcache.h" + +#ifdef USG +#include +#endif + +#include +#include "serial.h" + +/* Wiggler serial protocol definitions */ + +#define DLE 020 /* Quote char */ +#define SYN 026 /* Start of packet */ +#define RAW_SYN ((026 << 8) | 026) /* get_quoted_char found a naked SYN */ + +/* Status flags */ + +#define WIGGLER_FLAG_RESET 0x01 /* Target is being reset */ +#define WIGGLER_FLAG_STOPPED 0x02 /* Target is halted */ +#define WIGGLER_FLAG_BDM 0x04 /* Target is in BDM */ +#define WIGGLER_FLAG_PWF 0x08 /* Power failed */ +#define WIGGLER_FLAG_CABLE_DISC 0x10 /* BDM cable disconnected */ + +#define WIGGLER_AYT 0x0 /* Are you there? */ +#define WIGGLER_GET_VERSION 0x1 /* Get Version */ +#define WIGGLER_SET_BAUD_RATE 0x2 /* Set Baud Rate */ +#define WIGGLER_INIT 0x10 /* Initialize Wiggler */ +#define WIGGLER_SET_SPEED 0x11 /* Set Speed */ +#define WIGGLER_GET_STATUS_MASK 0x12 /* Get Status Mask */ +#define WIGGLER_GET_CTRS 0x13 /* Get Error Counters */ +#define WIGGLER_SET_FUNC_CODE 0x14 /* Set Function Code */ +#define WIGGLER_SET_CTL_FLAGS 0x15 /* Set Control Flags */ +#define WIGGLER_SET_BUF_ADDR 0x16 /* Set Register Buffer Address */ +#define WIGGLER_RUN 0x20 /* Run Target from PC */ +#define WIGGLER_RUN_ADDR 0x21 /* Run Target from Specified Address */ +#define WIGGLER_STOP 0x22 /* Stop Target */ +#define WIGGLER_RESET_RUN 0x23 /* Reset Target and Run */ +#define WIGGLER_RESET 0x24 /* Reset Target and Halt */ +#define WIGGLER_STEP 0x25 /* Single step */ +#define WIGGLER_READ_REGS 0x30 /* Read Registers */ +#define WIGGLER_WRITE_REGS 0x31 /* Write Registers */ +#define WIGGLER_READ_MEM 0x32 /* Read Memory */ +#define WIGGLER_WRITE_MEM 0x33 /* Write Memory */ +#define WIGGLER_FILL_MEM 0x34 /* Fill Memory */ +#define WIGGLER_MOVE_MEM 0x35 /* Move Memory */ + +#define WIGGLER_READ_INT_MEM 0x80 /* Read Internal Memory */ +#define WIGGLER_WRITE_INT_MEM 0x81 /* Write Internal Memory */ +#define WIGGLER_JUMP 0x82 /* Jump to Subroutine */ + +#define WIGGLER_SET_STATUS 0x0a /* Set status */ +#define WIGGLER_FLAG_STOP 0x0 /* Stop the target, enter BDM */ +#define WIGGLER_FLAG_START 0x01 /* Start the target at PC */ +#define WIGGLER_FLAG_RETURN_STATUS 0x04 /* Return async status */ + +/* Stuff that should be in tm-xxx files. */ +#if 1 +#define BDM_NUM_REGS 24 +#define BDM_REGMAP 0, 1, 2, 3, 4, 5, 6, 7, /* d0 -> d7 */ \ + 8, 9, 10, 11, 12, 13, 14, 15, /* a0 -> a7 */ \ + 18, 16, /* ps, pc */ \ + -1, -1, -1, -1, -1, -1, -1, -1, /* fp0 -> fp7 */ \ + -1, -1, -1, -1, -1 /* fpcontrol, fpstatus, fpiaddr, fpcode, fpflags */ +#define BDM_BREAKPOINT 0x4a, 0xfa /* BGND insn */ +#else +#define BDM_NUM_REGS 24 +#define BDM_REGMAP 8, 9, 10, 11, 12, 13, 14, 15, /* d0 -> d7 */ \ + 16, 17, 18, 19, 20, 21, 22, 23, /* a0 -> a7 */ \ + 4, 0, /* ps, pc */ \ + -1, -1, -1, -1, -1, -1, -1, -1, /* fp0 -> fp7 */ \ + -1, -1, -1, -1, -1 /* fpcontrol, fpstatus, fpiaddr, fpcode, fpflags */ +#define WIGGLER_POLL +#endif + +/* Prototypes for local functions */ + +static void wiggler_stop PARAMS ((void)); + +static void put_packet PARAMS ((unsigned char *packet, int pktlen)); +static unsigned char * get_packet PARAMS ((int cmd, int *pktlen, int timeout)); + +static int wiggler_write_bytes PARAMS ((CORE_ADDR memaddr, + char *myaddr, int len)); + +static int wiggler_read_bytes PARAMS ((CORE_ADDR memaddr, + char *myaddr, int len)); + +static void wiggler_files_info PARAMS ((struct target_ops *ignore)); + +static int wiggler_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, + int len, int should_write, + struct target_ops *target)); + +static void wiggler_prepare_to_store PARAMS ((void)); + +static void wiggler_fetch_registers PARAMS ((int regno)); + +static void wiggler_resume PARAMS ((int pid, int step, + enum target_signal siggnal)); + +static int wiggler_start_remote PARAMS ((char *dummy)); + +static void wiggler_open PARAMS ((char *name, int from_tty)); + +static void wiggler_close PARAMS ((int quitting)); + +static void wiggler_store_registers PARAMS ((int regno)); + +static void wiggler_mourn PARAMS ((void)); + +static int readchar PARAMS ((int timeout)); + +static void reset_packet PARAMS ((void)); + +static void output_packet PARAMS ((void)); + +static int get_quoted_char PARAMS ((int timeout)); + +static void put_quoted_char PARAMS ((int c)); + +static int wiggler_wait PARAMS ((int pid, struct target_waitstatus *status)); + +static void wiggler_kill PARAMS ((void)); + +static void wiggler_detach PARAMS ((char *args, int from_tty)); + +static void wiggler_interrupt PARAMS ((int signo)); + +static void wiggler_interrupt_twice PARAMS ((int signo)); + +static void interrupt_query PARAMS ((void)); + +static unsigned char * do_command PARAMS ((int cmd, int *statusp, int *lenp)); + +static unsigned char * read_bdm_registers PARAMS ((int first_bdm_regno, + int last_bdm_regno, + int *numregs)); + +extern struct target_ops wiggler_ops; /* Forward decl */ + +static int last_run_status; + +/* This was 5 seconds, which is a long time to sit and wait. + Unless this is going though some terminal server or multiplexer or + other form of hairy serial connection, I would think 2 seconds would + be plenty. */ + +/* Changed to allow option to set timeout value. + was static int remote_timeout = 2; */ +extern int remote_timeout; + +/* Descriptor for I/O to remote machine. Initialize it to NULL so that + wiggler_open knows that we don't have a file open when the program + starts. */ +serial_t wiggler_desc = NULL; + +static void +wiggler_error (s, error_code) + char *s; + int error_code; +{ + char buf[100]; + + fputs_filtered (s, gdb_stderr); + + switch (error_code) + { + case 1: s = "Unknown fault"; break; + case 2: s = "Power failed"; break; + case 3: s = "Cable disconnected"; break; + case 4: s = "Couldn't enter BDM"; break; + case 5: s = "Target stuck in reset"; break; + case 6: s = "Port not configured"; break; + case 7: s = "Write verify failed"; break; + case 11: s = "Bus error"; break; + case 12: s = "Checksum error"; break; + case 13: s = "Illegal command"; break; + case 14: s = "Parameter error"; break; + default: + sprintf (buf, "Unknown error code %d", error_code); + } + + error (s); +} + +/* Return nonzero if the thread TH is still alive on the remote system. */ + +static int +wiggler_thread_alive (th) + int th; +{ + return 1; +} + +/* Clean up connection to a remote debugger. */ + +/* ARGSUSED */ +static void +wiggler_close (quitting) + int quitting; +{ + if (wiggler_desc) + SERIAL_CLOSE (wiggler_desc); + wiggler_desc = NULL; +} + +/* Stub for catch_errors. */ + +static int +wiggler_start_remote (dummy) + char *dummy; +{ + unsigned char buf[10], *p; + int pktlen; + int status; + int error_code; + int speed; + + immediate_quit = 1; /* Allow user to interrupt it */ + + SERIAL_SEND_BREAK (wiggler_desc); /* Wake up the wiggler */ + + do_command (WIGGLER_AYT, &status, &pktlen); + + p = do_command (WIGGLER_GET_VERSION, &status, &pktlen); + + printf_unfiltered ("[Wiggler version %x.%x, capability 0x%x]\n", + p[0], p[1], (p[2] << 16) | p[3]); + +#if 1 + speed = 80; /* Divide clock by 4000 */ + + buf[0] = WIGGLER_INIT; + buf[1] = speed >> 8; + buf[2] = speed & 0xff; + buf[3] = 0; /* CPU32 for now */ + put_packet (buf, 4); /* Init Wiggler params */ + p = get_packet (buf[0], &pktlen, remote_timeout); + + if (pktlen < 2) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + wiggler_error ("WIGGLER_INIT:", error_code); +#endif + +#if 0 + /* Reset the target */ + + do_command (WIGGLER_RESET_RUN, &status, &pktlen); +/* do_command (WIGGLER_RESET, &status, &pktlen);*/ +#endif + + /* If processor is still running, stop it. */ + + if (!(status & WIGGLER_FLAG_BDM)) + wiggler_stop (); + +#if 1 + buf[0] = WIGGLER_SET_CTL_FLAGS; + buf[1] = 0; + buf[2] = 1; /* Asynchronously return status when target stops */ + put_packet (buf, 3); + + p = get_packet (buf[0], &pktlen, remote_timeout); + + if (pktlen < 2) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + wiggler_error ("WIGGLER_SET_CTL_FLAGS:", error_code); +#endif + + immediate_quit = 0; + +/* This is really the job of start_remote however, that makes an assumption + that the target is about to print out a status message of some sort. That + doesn't happen here (in fact, it may not be possible to get the monitor to + send the appropriate packet). */ + + flush_cached_frames (); + registers_changed (); + stop_pc = read_pc (); + set_current_frame (create_new_frame (read_fp (), stop_pc)); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, -1, 1); + + return 1; +} + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +static DCACHE *wiggler_dcache; + +static void +wiggler_open (name, from_tty) + char *name; + int from_tty; +{ + if (name == 0) + error ("To open a Wiggler connection, you need to specify what serial\n\ +device the Wiggler is attached to (e.g. /dev/ttya)."); + + target_preopen (from_tty); + + unpush_target (&wiggler_ops); + + wiggler_dcache = dcache_init (wiggler_read_bytes, wiggler_write_bytes); + + wiggler_desc = SERIAL_OPEN (name); + if (!wiggler_desc) + perror_with_name (name); + + if (baud_rate != -1) + { + if (SERIAL_SETBAUDRATE (wiggler_desc, baud_rate)) + { + SERIAL_CLOSE (wiggler_desc); + perror_with_name (name); + } + } + + SERIAL_RAW (wiggler_desc); + + /* If there is something sitting in the buffer we might take it as a + response to a command, which would be bad. */ + SERIAL_FLUSH_INPUT (wiggler_desc); + + if (from_tty) + { + puts_filtered ("Remote target wiggler connected to "); + puts_filtered (name); + puts_filtered ("\n"); + } + push_target (&wiggler_ops); /* Switch to using remote target now */ + + /* Without this, some commands which require an active target (such as kill) + won't work. This variable serves (at least) double duty as both the pid + of the target process (if it has such), and as a flag indicating that a + target is active. These functions should be split out into seperate + variables, especially since GDB will someday have a notion of debugging + several processes. */ + + inferior_pid = 42000; + /* Start the remote connection; if error (0), discard this target. + In particular, if the user quits, be sure to discard it + (we'd be in an inconsistent state otherwise). */ + if (!catch_errors (wiggler_start_remote, (char *)0, + "Couldn't establish connection to remote target\n", RETURN_MASK_ALL)) + pop_target(); +} + +/* This takes a program previously attached to and detaches it. After + this is done, GDB can be used to debug some other program. We + better not have left any breakpoints in the target program or it'll + die when it hits one. */ + +static void +wiggler_detach (args, from_tty) + char *args; + int from_tty; +{ + if (args) + error ("Argument given to \"detach\" when remotely debugging."); + + pop_target (); + if (from_tty) + puts_filtered ("Ending remote debugging.\n"); +} + +/* Tell the remote machine to resume. */ + +static void +wiggler_resume (pid, step, siggnal) + int pid, step; + enum target_signal siggnal; +{ + int pktlen; + + dcache_flush (wiggler_dcache); + + if (step) + do_command (WIGGLER_STEP, &last_run_status, &pktlen); + else + do_command (WIGGLER_RUN, &last_run_status, &pktlen); +} + +static void +wiggler_stop () +{ + int status; + int pktlen; + + do_command (WIGGLER_STOP, &status, &pktlen); + + if (!(status & WIGGLER_FLAG_BDM)) + error ("Can't stop target via BDM"); +} + +static volatile int wiggler_interrupt_flag; + +/* Send ^C to target to halt it. Target will respond, and send us a + packet. */ + +static void +wiggler_interrupt (signo) + int signo; +{ + /* If this doesn't work, try more severe steps. */ + signal (signo, wiggler_interrupt_twice); + + if (remote_debug) + printf_unfiltered ("wiggler_interrupt called\n"); + + { + char buf[1]; + + wiggler_stop (); + buf[0] = WIGGLER_AYT; + put_packet (buf, 1); + wiggler_interrupt_flag = 1; + } +} + +static void (*ofunc)(); + +/* The user typed ^C twice. */ +static void +wiggler_interrupt_twice (signo) + int signo; +{ + signal (signo, ofunc); + + interrupt_query (); + + signal (signo, wiggler_interrupt); +} + +/* Ask the user what to do when an interrupt is received. */ + +static void +interrupt_query () +{ + target_terminal_ours (); + + if (query ("Interrupted while waiting for the program.\n\ +Give up (and stop debugging it)? ")) + { + target_mourn_inferior (); + return_to_top_level (RETURN_QUIT); + } + + target_terminal_inferior (); +} + +/* If nonzero, ignore the next kill. */ +static int kill_kludge; + +/* Wait until the remote machine stops, then return, + storing status in STATUS just as `wait' would. + Returns "pid" (though it's not clear what, if anything, that + means in the case of this target). */ + +static int +wiggler_wait (pid, target_status) + int pid; + struct target_waitstatus *target_status; +{ + unsigned char *p; + int error_code, status; + int pktlen; + + wiggler_interrupt_flag = 0; + + target_status->kind = TARGET_WAITKIND_STOPPED; + target_status->value.sig = TARGET_SIGNAL_TRAP; + + /* Target may already be stopped by the time we get here. */ + + if (!(last_run_status & WIGGLER_FLAG_BDM)) + { + ofunc = (void (*)()) signal (SIGINT, wiggler_interrupt); + + p = get_packet (WIGGLER_AYT, &pktlen, -1); + + signal (SIGINT, ofunc); + + if (pktlen < 2) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + wiggler_error ("target_wait:", error_code); + + if (status & WIGGLER_FLAG_PWF) + error ("Wiggler lost VCC at BDM interface."); + else if (status & WIGGLER_FLAG_CABLE_DISC) + error ("BDM cable appears to have been disconnected."); + + if (!(status & WIGGLER_FLAG_BDM)) + error ("Wiggler woke up, but wasn't stopped: 0x%x", status); + + if (wiggler_interrupt_flag) + target_status->value.sig = TARGET_SIGNAL_INT; + } + + /* This test figures out if we just executed a BGND insn, and if it's one of + our breakpoints. If so, then we back up PC. N.B. When a BGND insn is + executed, the PC points at the loc just after the insn (ie: it's always + two bytes *after* the BGND). So, it's not sufficient to just see if PC-2 + is a BGND insn because we could have gotten there via a jump. We dis- + ambiguate this case by examining the ATEMP register (which is only + accessible from BDM). This will tell us if we entered BDM because we + executed a BGND insn. */ + + if (breakpoint_inserted_here_p (read_pc () - 2)) /* One of our breakpoints? */ + { /* Yes, see if we actually executed it */ +#if 0 /* Temporarily disabled until atemp reading is fixed. */ + int atemp; + int numregs; + + p = read_bdm_registers (23, 23, &numregs); + atemp = extract_unsigned_integer (p, 4); + + if (atemp == 1) /* And, did we hit a breakpoint insn? */ +#endif + write_pc (read_pc () - 2); /* Yes, then back up PC */ + } + + return inferior_pid; +} + +/* Read the remote registers into the block REGS. */ +/* Currently we just read all the registers, so we don't use regno. */ +/* ARGSUSED */ + +static unsigned char * +read_bdm_registers (first_bdm_regno, last_bdm_regno, numregs) + int first_bdm_regno; + int last_bdm_regno; + int *numregs; +{ + unsigned char buf[10]; + int i; + unsigned char *p; + unsigned char *regs; + int error_code, status; + int pktlen; + + buf[0] = WIGGLER_READ_REGS; + buf[1] = first_bdm_regno >> 8; + buf[2] = first_bdm_regno & 0xff; + buf[3] = last_bdm_regno >> 8; + buf[4] = last_bdm_regno & 0xff; + + put_packet (buf, 5); + p = get_packet (WIGGLER_READ_REGS, &pktlen, remote_timeout); + + if (pktlen < 5) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + wiggler_error ("read_bdm_registers:", error_code); + + i = p[3]; + if (i == 0) + i = 256; + + if (i > pktlen - 4 + || ((i & 3) != 0)) + error ("Register block size bad: %d", i); + + *numregs = i / 4; + + regs = p + 4; + + return regs; +} + +static void +dump_all_bdm_regs () +{ + unsigned char *regs; + int numregs; + int i; + + regs = read_bdm_registers (0, BDM_NUM_REGS - 1, &numregs); + + printf_unfiltered ("rpc = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("usp = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("ssp = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("vbr = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("sr = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("sfc = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("dfc = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("atemp = 0x%x ", + (int)extract_unsigned_integer (regs, 4)); + regs += 4; + printf_unfiltered ("\n"); + + for (i = 0; i <= 7; i++) + printf_unfiltered ("d%i = 0x%x ", i, + (int)extract_unsigned_integer (regs + i * 4, 4)); + regs += 8 * 4; + printf_unfiltered ("\n"); + + for (i = 0; i <= 7; i++) + printf_unfiltered ("a%i = 0x%x ", i, + (int)extract_unsigned_integer (regs + i * 4, 4)); + printf_unfiltered ("\n"); +} + +static int bdm_regmap[] = {BDM_REGMAP}; + +/* Read the remote registers into the block REGS. */ +/* Currently we just read all the registers, so we don't use regno. */ +/* ARGSUSED */ +static void +wiggler_fetch_registers (regno) + int regno; +{ + int i; + unsigned char *regs; + int first_regno, last_regno; + int first_bdm_regno, last_bdm_regno; + int numregs; + + if (regno == -1) + { + first_regno = 0; + last_regno = NUM_REGS - 1; + + first_bdm_regno = 0; + last_bdm_regno = BDM_NUM_REGS - 1; + } + else + { + first_regno = regno; + last_regno = regno; + + first_bdm_regno = bdm_regmap [regno]; + last_bdm_regno = bdm_regmap [regno]; + } + + if (first_bdm_regno == -1) + { + supply_register (first_regno, NULL); + return; /* Unsupported register */ + } + + regs = read_bdm_registers (first_bdm_regno, last_bdm_regno, &numregs); + + for (i = first_regno; i <= last_regno; i++) + { + int bdm_regno, regoffset; + + bdm_regno = bdm_regmap [i]; + if (bdm_regno != -1) + { + regoffset = bdm_regno - first_bdm_regno; + + if (regoffset >= numregs) + continue; + + supply_register (i, regs + 4 * regoffset); + } + else + supply_register (i, NULL); /* Unsupported register */ + } +} + +static void +wiggler_prepare_to_store () +{ +} + +/* Store register REGNO, or all registers if REGNO == -1, from the contents + of REGISTERS. FIXME: ignores errors. */ + +static void +wiggler_store_registers (regno) + int regno; +{ + unsigned char buf[10 + 256]; + int i; + unsigned char *p; + int error_code, status; + int pktlen; + int first_regno, last_regno; + int first_bdm_regno, last_bdm_regno; + + if (regno == -1) + { + first_regno = 0; + last_regno = NUM_REGS - 1; + + first_bdm_regno = 0; + last_bdm_regno = BDM_NUM_REGS - 1; + } + else + { + first_regno = regno; + last_regno = regno; + + first_bdm_regno = bdm_regmap [regno]; + last_bdm_regno = bdm_regmap [regno]; + } + + if (first_bdm_regno == -1) + return; /* Unsupported register */ + + buf[0] = WIGGLER_WRITE_REGS; + buf[3] = 4; + + for (i = first_regno; i <= last_regno; i++) + { + int bdm_regno; + + bdm_regno = bdm_regmap [i]; + + buf[1] = bdm_regno >> 8; + buf[2] = bdm_regno & 0xff; + + memcpy (&buf[4], ®isters[REGISTER_BYTE (i)], 4); + put_packet (buf, 4 + 4); + p = get_packet (WIGGLER_WRITE_REGS, &pktlen, remote_timeout); + + if (pktlen < 3) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + wiggler_error ("wiggler_store_registers:", error_code); + } +} + +/* Write memory data directly to the remote machine. + This does not inform the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +wiggler_write_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[256 + 10]; + unsigned char *p; + int origlen; + + origlen = len; + + buf[0] = WIGGLER_WRITE_MEM; + buf[5] = 1; /* Write as bytes */ + buf[6] = 0; /* Don't verify */ + + while (len > 0) + { + int numbytes; + int pktlen; + int status, error_code; + + numbytes = min (len, 256 - 8); +/* numbytes = min (len, 40);*/ + + buf[1] = memaddr >> 24; + buf[2] = memaddr >> 16; + buf[3] = memaddr >> 8; + buf[4] = memaddr; + + buf[7] = numbytes; + + memcpy (&buf[8], myaddr, numbytes); + put_packet (buf, 8 + numbytes); + p = get_packet (WIGGLER_WRITE_MEM, &pktlen, remote_timeout); + if (pktlen < 3) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code == 11) /* Got a bus error? */ + { + CORE_ADDR error_address; + + error_address = p[3] << 24; + error_address |= p[4] << 16; + error_address |= p[5] << 8; + error_address |= p[6]; + numbytes = error_address - memaddr; + + len -= numbytes; + + errno = EIO; + + break; + } + else if (error_code != 0) + wiggler_error ("wiggler_store_registers:", error_code); + + len -= numbytes; + memaddr += numbytes; + myaddr += numbytes; + } + + return origlen - len; +} + +/* Read memory data directly from the remote machine. + This does not use the data cache; the data cache uses this. + MEMADDR is the address in the remote memory space. + MYADDR is the address of the buffer in our space. + LEN is the number of bytes. + + Returns number of bytes transferred, or 0 for error. */ + +static int +wiggler_read_bytes (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + char buf[256 + 10]; + unsigned char *p; + int origlen; + + origlen = len; + + buf[0] = WIGGLER_READ_MEM; + buf[5] = 1; /* Read as bytes */ + + while (len > 0) + { + int numbytes; + int pktlen; + int status, error_code; + + numbytes = min (len, 256 - 7); + + buf[1] = memaddr >> 24; + buf[2] = memaddr >> 16; + buf[3] = memaddr >> 8; + buf[4] = memaddr; + + buf[6] = numbytes; + + put_packet (buf, 7); + p = get_packet (WIGGLER_READ_MEM, &pktlen, remote_timeout); + if (pktlen < 4) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code == 0x11) /* Got a bus error? */ + { + CORE_ADDR error_address; + + error_address = p[3] << 24; + error_address |= p[4] << 16; + error_address |= p[5] << 8; + error_address |= p[6]; + numbytes = error_address - memaddr; + + len -= numbytes; + + errno = EIO; + + break; + } + else if (error_code != 0) + wiggler_error ("wiggler_store_registers:", error_code); + + memcpy (myaddr, &p[4], numbytes); + + len -= numbytes; + memaddr += numbytes; + myaddr += numbytes; + } + + return origlen - len; +} + +/* Read or write LEN bytes from inferior memory at MEMADDR, transferring + to or from debugger address MYADDR. Write to inferior if SHOULD_WRITE is + nonzero. Returns length of data written or read; 0 for error. */ + +/* ARGSUSED */ +static int +wiggler_xfer_memory(memaddr, myaddr, len, should_write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int should_write; + struct target_ops *target; /* ignored */ +{ + return dcache_xfer_memory (wiggler_dcache, memaddr, myaddr, len, should_write); +} + +static void +wiggler_files_info (ignore) + struct target_ops *ignore; +{ + puts_filtered ("Debugging a target over a serial line.\n"); +} + +/* Stuff for dealing with the packets which are part of this protocol. + See comment at top of file for details. */ + +/* Read a single character from the remote side, handling wierd errors. */ + +static int +readchar (timeout) + int timeout; +{ + int ch; + + ch = SERIAL_READCHAR (wiggler_desc, timeout); + + switch (ch) + { + case SERIAL_EOF: + error ("Remote connection closed"); + case SERIAL_ERROR: + perror_with_name ("Remote communication error"); + case SERIAL_TIMEOUT: + default: + return ch; + } +} + +#if 0 +/* Read a character from the data stream, dequoting as necessary. SYN is + treated special. Any SYNs appearing in the data stream are returned as the + distinct value RAW_SYN (which has a value > 8 bits and therefore cannot be + mistaken for real data). */ + +static int +get_quoted_char (timeout) + int timeout; +{ + int ch; + + ch = readchar (timeout); + + switch (ch) + { + case SERIAL_TIMEOUT: + error ("Timeout in mid-packet, aborting"); + case SYN: + return RAW_SYN; + case DLE: + ch = readchar (timeout); + if (ch == SYN) + return RAW_SYN; + return ch & ~0100; + default: + return ch; + } +} + +static unsigned char pkt[256 * 2 + 10], *pktp; /* Worst case */ + +static void +reset_packet () +{ + pktp = pkt; +} + +static void +output_packet () +{ + if (SERIAL_WRITE (wiggler_desc, pkt, pktp - pkt)) + perror_with_name ("output_packet: write failed"); + + reset_packet (); +} + +/* Output a quoted character. SYNs and DLEs are quoted. Everything else goes + through untouched. */ + +static void +put_quoted_char (c) + int c; +{ + switch (c) + { + case SYN: + case DLE: + *pktp++ = DLE; + c |= 0100; + } + + *pktp++ = c; +} + +/* Send a packet to the Wiggler. The packet framed by a SYN character, a byte + count and a checksum. The byte count only counts the number of bytes + between the count and the checksum. A count of zero actually means 256. + Any SYNs within the packet (including the checksum and count) must be + quoted. The quote character must be quoted as well. Quoting is done by + replacing the character with the two-character sequence DLE, {char} | 0100. + Note that the quoting mechanism has no effect on the byte count. + */ + +static void +stu_put_packet (buf, len) + unsigned char *buf; + int len; +{ + unsigned char checksum; + unsigned char c; + + if (len == 0 || len > 256) + abort (); /* Can't represent 0 length packet */ + + reset_packet (); + + checksum = 0; + + put_quoted_char (RAW_SYN); + + c = len; + + do + { + checksum += c; + + put_quoted_char (c); + + c = *buf++; + } + while (len-- > 0); + + put_quoted_char (-checksum & 0xff); + + output_packet (); +} + +#else + +/* Send a packet to the Wiggler. The packet framed by a SYN character, a byte + count and a checksum. The byte count only counts the number of bytes + between the count and the checksum. A count of zero actually means 256. + Any SYNs within the packet (including the checksum and count) must be + quoted. The quote character must be quoted as well. Quoting is done by + replacing the character with the two-character sequence DLE, {char} | 0100. + Note that the quoting mechanism has no effect on the byte count. + */ + +static void +put_packet (buf, len) + unsigned char *buf; + int len; +{ + unsigned char checksum; + unsigned char c; + unsigned char *packet, *packet_ptr; + + packet = alloca (len + 1 + 1); /* packet + SYN + checksum */ + packet_ptr = packet; + + checksum = 0; + + *packet_ptr++ = 0x55; + + while (len-- > 0) + { + c = *buf++; + + checksum += c; + *packet_ptr++ = c; + } + + *packet_ptr++ = -checksum; + if (SERIAL_WRITE (wiggler_desc, packet, packet_ptr - packet)) + perror_with_name ("output_packet: write failed"); +} +#endif + +#if 0 +/* Get a packet from the Wiggler. Timeout is only enforced for the first byte + of the packet. Subsequent bytes are expected to arrive in time <= + remote_timeout. Returns a pointer to a static buffer containing the payload + of the packet. *LENP contains the length of the packet. +*/ + +static unsigned char * +stu_get_packet (cmd, lenp, timeout) + unsigned char cmd; + int *lenp; +{ + int ch; + int len; + static unsigned char buf[256 + 10], *p; + unsigned char checksum; + + find_packet: + + ch = get_quoted_char (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + + if (ch != RAW_SYN) + goto find_packet; + + found_syn: /* Found the start of a packet */ + + p = buf; + checksum = 0; + + len = get_quoted_char (remote_timeout); + + if (len == RAW_SYN) + goto found_syn; + + checksum += len; + + if (len == 0) + len = 256; + + len++; /* Include checksum */ + + while (len-- > 0) + { + ch = get_quoted_char (remote_timeout); + if (ch == RAW_SYN) + goto found_syn; + + *p++ = ch; + checksum += ch; + } + + if (checksum != 0) + goto find_packet; + + if (cmd != buf[0]) + error ("Response phase error. Got 0x%x, expected 0x%x", buf[0], cmd); + + *lenp = p - buf - 1; + return buf; +} + +#else + +/* Get a packet from the Wiggler. Timeout is only enforced for the first byte + of the packet. Subsequent bytes are expected to arrive in time <= + remote_timeout. Returns a pointer to a static buffer containing the payload + of the packet. *LENP contains the length of the packet. +*/ + +static unsigned char * +get_packet (cmd, lenp, timeout) + int cmd; + int *lenp; +{ + int ch; + int len; + int i; + static unsigned char packet[512]; + unsigned char *packet_ptr; + unsigned char checksum; + + find_packet: + + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + + if (ch != 0x55) + goto find_packet; + +/* Found the start of a packet */ + + packet_ptr = packet; + checksum = 0; + +/* Read command char. That sort of tells us how long the packet is. */ + + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + + *packet_ptr++ = ch; + checksum += ch; + +/* Get status. */ + + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + *packet_ptr++ = ch; + checksum += ch; + +/* Get error code. */ + + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + *packet_ptr++ = ch; + checksum += ch; + + switch (ch) /* Figure out length of packet */ + { + case 0x7: /* Write verify error? */ + len = 8; /* write address, value read back */ + break; + case 0x11: /* Bus error? */ + /* write address, read flag */ + case 0x15: /* Internal error */ + len = 5; /* error code, vector */ + break; + default: /* Error w/no params */ + len = 0; + case 0x0: /* Normal result */ + switch (packet[0]) + { + case WIGGLER_AYT: /* Are You There? */ + case WIGGLER_SET_BAUD_RATE: /* Set Baud Rate */ + case WIGGLER_INIT: /* Initialize wiggler */ + case WIGGLER_SET_SPEED: /* Set Speed */ + case WIGGLER_SET_FUNC_CODE: /* Set Function Code */ + case WIGGLER_SET_CTL_FLAGS: /* Set Control Flags */ + case WIGGLER_SET_BUF_ADDR: /* Set Register Buffer Address */ + case WIGGLER_RUN: /* Run Target from PC */ + case WIGGLER_RUN_ADDR: /* Run Target from Specified Address */ + case WIGGLER_STOP: /* Stop Target */ + case WIGGLER_RESET_RUN: /* Reset Target and Run */ + case WIGGLER_RESET: /* Reset Target and Halt */ + case WIGGLER_STEP: /* Single Step */ + case WIGGLER_WRITE_REGS: /* Write Register */ + case WIGGLER_WRITE_MEM: /* Write Memory */ + case WIGGLER_FILL_MEM: /* Fill Memory */ + case WIGGLER_MOVE_MEM: /* Move Memory */ + case WIGGLER_WRITE_INT_MEM: /* Write Internal Memory */ + case WIGGLER_JUMP: /* Jump to Subroutine */ + len = 0; + break; + case WIGGLER_GET_VERSION: /* Get Version */ + len = 4; + break; + case WIGGLER_GET_STATUS_MASK: /* Get Status Mask */ + len = 1; + break; + case WIGGLER_GET_CTRS: /* Get Error Counters */ + case WIGGLER_READ_REGS: /* Read Register */ + case WIGGLER_READ_MEM: /* Read Memory */ + case WIGGLER_READ_INT_MEM: /* Read Internal Memory */ + len = 257; + break; + default: + fprintf_filtered (gdb_stderr, "Unknown packet type 0x%x\n", ch); + goto find_packet; + } + } + + if (len == 257) /* Byte stream? */ + { /* Yes, byte streams contain the length */ + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + *packet_ptr++ = ch; + checksum += ch; + len = ch; + if (len == 0) + len = 256; + } + + while (len-- >= 0) /* Do rest of packet and checksum */ + { + ch = readchar (timeout); + + if (ch < 0) + error ("get_packet (readchar): %d", ch); + *packet_ptr++ = ch; + checksum += ch; + } + + if (checksum != 0) + goto find_packet; + + if (cmd != -1 && cmd != packet[0]) + error ("Response phase error. Got 0x%x, expected 0x%x", packet[0], cmd); + + *lenp = packet_ptr - packet - 1; /* Subtract checksum byte */ + return packet; +} +#endif + +/* Execute a simple (one-byte) command. Returns a pointer to the data + following the error code. */ + +static unsigned char * +do_command (cmd, statusp, lenp) + int cmd; + int *statusp; + int *lenp; +{ + unsigned char buf[100], *p; + int status, error_code; + char errbuf[100]; + + buf[0] = cmd; + put_packet (buf, 1); /* Send command */ + p = get_packet (*buf, lenp, remote_timeout); + + if (*lenp < 3) + error ("Truncated response packet from Wiggler"); + + status = p[1]; + error_code = p[2]; + + if (error_code != 0) + { + sprintf (errbuf, "do_command (0x%x):", cmd); + wiggler_error (errbuf, error_code); + } + + if (status & WIGGLER_FLAG_PWF) + error ("Wiggler can't detect VCC at BDM interface."); + else if (status & WIGGLER_FLAG_CABLE_DISC) + error ("BDM cable appears to be disconnected."); + + *statusp = status; + + return p + 3; +} + +static void +wiggler_kill () +{ + /* For some mysterious reason, wait_for_inferior calls kill instead of + mourn after it gets TARGET_WAITKIND_SIGNALLED. Work around it. */ + if (kill_kludge) + { + kill_kludge = 0; + target_mourn_inferior (); + return; + } + + /* Don't wait for it to die. I'm not really sure it matters whether + we do or not. */ + target_mourn_inferior (); +} + +static void +wiggler_mourn () +{ + unpush_target (&wiggler_ops); + generic_mourn_inferior (); +} + +/* All we actually do is set the PC to the start address of exec_bfd, and start + the program at that point. */ + +static void +wiggler_create_inferior (exec_file, args, env) + char *exec_file; + char *args; + char **env; +{ + if (args && (*args != '\000')) + error ("Args are not supported by BDM."); + + clear_proceed_status (); + proceed (bfd_get_start_address (exec_bfd), TARGET_SIGNAL_0, 0); +} + +static void +wiggler_load (args, from_tty) + char *args; + int from_tty; +{ + generic_load (args, from_tty); + inferior_pid = 0; +} + +/* BDM (at least on CPU32) uses a different breakpoint */ + +static int +wiggler_insert_breakpoint (addr, contents_cache) + CORE_ADDR addr; + char *contents_cache; +{ + static char break_insn[] = {BDM_BREAKPOINT}; + int val; + + val = target_read_memory (addr, contents_cache, sizeof break_insn); + + if (val == 0) + val = target_write_memory (addr, break_insn, sizeof break_insn); + + return val; +} + +static void +bdm_command (args, from_tty) + char *args; + int from_tty; +{ + error ("bdm command must be followed by `reset'"); +} + +static void +bdm_reset_command (args, from_tty) + char *args; + int from_tty; +{ + int status, pktlen; + + if (!wiggler_desc) + error ("Not connected to wiggler."); + + do_command (WIGGLER_RESET, &status, &pktlen); + dcache_flush (wiggler_dcache); + registers_changed (); +} + +static void +bdm_restart_command (args, from_tty) + char *args; + int from_tty; +{ + int status, pktlen; + + if (!wiggler_desc) + error ("Not connected to wiggler."); + + do_command (WIGGLER_RESET_RUN, &status, &pktlen); + last_run_status = status; + clear_proceed_status (); + wait_for_inferior (); + normal_stop (); +} + +/* Define the target subroutine names */ + +struct target_ops wiggler_ops = { + "wiggler", /* to_shortname */ + "", /* to_longname */ + "", /* to_doc */ + wiggler_open, /* to_open */ + wiggler_close, /* to_close */ + NULL, /* to_attach */ + wiggler_detach, /* to_detach */ + wiggler_resume, /* to_resume */ + wiggler_wait, /* to_wait */ + wiggler_fetch_registers, /* to_fetch_registers */ + wiggler_store_registers, /* to_store_registers */ + wiggler_prepare_to_store, /* to_prepare_to_store */ + wiggler_xfer_memory, /* to_xfer_memory */ + wiggler_files_info, /* to_files_info */ + wiggler_insert_breakpoint, /* to_insert_breakpoint */ + memory_remove_breakpoint, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + wiggler_kill, /* to_kill */ + wiggler_load, /* to_load */ + NULL, /* to_lookup_symbol */ + wiggler_create_inferior, /* to_create_inferior */ + wiggler_mourn, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + wiggler_thread_alive, /* to_thread_alive */ + 0, /* to_stop */ + process_stratum, /* to_stratum */ + NULL, /* to_next */ + 1, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 1, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_remote_wiggler () +{ + extern struct cmd_list_element *cmdlist; + static struct cmd_list_element *bdm_cmd_list = NULL; + + add_target (&wiggler_ops); + + add_show_from_set (add_set_cmd ("remotetimeout", no_class, + var_integer, (char *)&remote_timeout, + "Set timeout value for remote read.\n", &setlist), + &showlist); + + add_prefix_cmd ("bdm", class_obscure, bdm_command, "", &bdm_cmd_list, "bdm ", + 0, &cmdlist); + + add_cmd ("reset", class_obscure, bdm_reset_command, "", &bdm_cmd_list); + add_cmd ("restart", class_obscure, bdm_restart_command, "", &bdm_cmd_list); +} diff --git a/gdb/serial.c b/gdb/serial.c index 151881a..c30fda6 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -38,11 +38,16 @@ static serial_t scb_base; /* Non-NULL gives filename which contains a recording of the remote session, suitable for playback by gdbserver. */ -char *serial_logfile = NULL; -FILE *serial_logfp = NULL; +static char *serial_logfile = NULL; +static FILE *serial_logfp = NULL; static struct serial_ops *serial_interface_lookup PARAMS ((char *)); -static void serial_logchar PARAMS ((int)); +static void serial_logchar PARAMS ((int ch, int timeout)); +static char logbase_hex[] = "hex"; +static char logbase_octal[] = "octal"; +static char logbase_ascii[] = "ascii"; +static char *logbase_enums[] = {logbase_hex, logbase_octal, logbase_ascii, NULL}; +static char *serial_logbase = logbase_ascii; static int serial_reading = 0; @@ -52,6 +57,9 @@ void serial_log_command (cmd) const char *cmd; { + if (!serial_logfp) + return; + if (serial_reading || serial_writing) { fputc_unfiltered ('\n', serial_logfp); @@ -64,21 +72,50 @@ serial_log_command (cmd) fflush (serial_logfp); } +/* Define bogus char to represent a BREAK. Should be careful to choose a value + that can't be confused with a normal char, or an error code. */ +#define SERIAL_BREAK 1235 + static void -serial_logchar (ch) +serial_logchar (ch, timeout) int ch; + int timeout; { + if (serial_logbase != logbase_ascii) + fputc_unfiltered (' ', serial_logfp); + switch (ch) { - case '\\': fputs_unfiltered ("\\\\", serial_logfp); break; - case '\b': fputs_unfiltered ("\\b", serial_logfp); break; - case '\f': fputs_unfiltered ("\\f", serial_logfp); break; - case '\n': fputs_unfiltered ("\\n", serial_logfp); break; - case '\r': fputs_unfiltered ("\\r", serial_logfp); break; - case '\t': fputs_unfiltered ("\\t", serial_logfp); break; - case '\v': fputs_unfiltered ("\\v", serial_logfp); break; - default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break; - } + case SERIAL_TIMEOUT: + fprintf_unfiltered (serial_logfp, "", timeout); + return; + case SERIAL_ERROR: + fprintf_unfiltered (serial_logfp, "", safe_strerror (errno)); + return; + case SERIAL_EOF: + fputs_unfiltered ("", serial_logfp); + return; + case SERIAL_BREAK: + fputs_unfiltered ("", serial_logfp); + return; + default: + if (serial_logbase == logbase_hex) + fprintf_unfiltered (serial_logfp, "%02x", ch & 0xff); + else if (serial_logbase == logbase_octal) + fprintf_unfiltered (serial_logfp, "%03o", ch & 0xff); + else + switch (ch) + { + case '\\': fputs_unfiltered ("\\\\", serial_logfp); break; + case '\b': fputs_unfiltered ("\\b", serial_logfp); break; + case '\f': fputs_unfiltered ("\\f", serial_logfp); break; + case '\n': fputs_unfiltered ("\\n", serial_logfp); break; + case '\r': fputs_unfiltered ("\\r", serial_logfp); break; + case '\t': fputs_unfiltered ("\\t", serial_logfp); break; + case '\v': fputs_unfiltered ("\\v", serial_logfp); break; + default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break; + } + } } int @@ -98,13 +135,12 @@ serial_write (scb, str, len) } if (!serial_writing) { - serial_logchar ('w'); - serial_logchar (' '); + fputs_unfiltered ("w ", serial_logfp); serial_writing = 1; } for (count = 0; count < len; count++) { - serial_logchar (str[count]); + serial_logchar (str[count] & 0xff, 0); } /* Make sure that the log file is as up-to-date as possible, in case we are getting ready to dump core or something. */ @@ -130,11 +166,10 @@ serial_readchar (scb, timeout) } if (!serial_reading) { - serial_logchar ('r'); - serial_logchar (' '); + fputs_unfiltered ("r ", serial_logfp); serial_reading = 1; } - serial_logchar (ch); + serial_logchar (ch, timeout); /* Make sure that the log file is as up-to-date as possible, in case we are getting ready to dump core or something. */ fflush (serial_logfp); @@ -142,6 +177,30 @@ serial_readchar (scb, timeout) return (ch); } +int +serial_send_break (scb) + serial_t scb; +{ + if (serial_logfp != NULL) + { + if (serial_reading) + { + fputc_unfiltered ('\n', serial_logfp); + serial_reading = 0; + } + if (!serial_writing) + { + fputs_unfiltered ("w ", serial_logfp); + serial_writing = 1; + } + serial_logchar (SERIAL_BREAK, 0); + /* Make sure that the log file is as up-to-date as possible, + in case we are getting ready to dump core or something. */ + fflush (serial_logfp); + } + return (scb -> ops -> send_break (scb)); +} + static struct serial_ops * serial_interface_lookup (name) char *name; @@ -471,6 +530,8 @@ serial_printf (va_alist) void _initialize_serial () { + struct cmd_list_element *cmd; + #if 0 add_com ("connect", class_obscure, connect_command, "Connect the terminal directly up to the command monitor.\n\ @@ -484,4 +545,10 @@ This file is used to record the remote session for future playback\n\ by gdbserver.", &setlist), &showlist); + add_show_from_set (add_set_enum_cmd ("remotelogbase", no_class, + logbase_enums, + (char *)&serial_logbase, + "Set ...", + &setlist), + &showlist); } diff --git a/gdb/serial.h b/gdb/serial.h index ca4639c..f1963d0 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -97,8 +97,9 @@ serial_t serial_fdopen PARAMS ((const int fd)); /* Send a break between 0.25 and 0.5 seconds long. */ -#define SERIAL_SEND_BREAK(SERIAL_T) \ - ((*(SERIAL_T)->ops->send_break) (SERIAL_T)) +extern int serial_send_break PARAMS ((serial_t scb)); + +#define SERIAL_SEND_BREAK(SERIAL_T) serial_send_break (SERIAL_T) /* Turn the port into raw mode. */ @@ -176,9 +177,6 @@ extern void serial_printf PARAMS ((serial_t desc, const char *, ...)) /* File in which to record the remote debugging session */ -extern char *serial_logfile; -extern FILE *serial_logfp; - extern void serial_log_command PARAMS ((const char *)); #endif /* SERIAL_H */ diff --git a/gdb/top.c b/gdb/top.c index ae07224..a5a90f4 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -1171,7 +1171,6 @@ execute_command (p, from_tty) register enum language flang; static int warned = 0; /* FIXME: These should really be in an appropriate header file */ - extern FILE *serial_logfp; extern void serial_log_command PARAMS ((const char *)); free_all_values (); @@ -1180,8 +1179,7 @@ execute_command (p, from_tty) if (p == NULL) return; - if (serial_logfp != NULL) - serial_log_command (p); + serial_log_command (p); while (*p == ' ' || *p == '\t') p++; if (*p) -- 2.7.4