From: Stu Grossman Date: Wed, 26 May 1993 20:49:21 +0000 (+0000) Subject: * gdbserver/{remote-gutils.c remote-server.c Makefile.in X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e20520b8f9ced9bd3f133ecd2f7a6b840bf371e4;p=binutils-gdb.git * gdbserver/{remote-gutils.c remote-server.c Makefile.in configure.in remote-inflow.c remote-utils.c}: New files to support GDB remote server. Currently only works for Lynx. --- diff --git a/gdb/gdbserver/configure.in b/gdb/gdbserver/configure.in new file mode 100644 index 00000000000..707f8a5d90e --- /dev/null +++ b/gdb/gdbserver/configure.in @@ -0,0 +1,331 @@ +srcname="Remote GDB server" +srctrigger=remote-server.c +gdb_serial_driver=../ser-unix.c + +# per-host: + +# per-target: + +# Hack alert! We want this directory to be configured only for the target, +# which is where it will be running, so we just eliminate the per-host section, +# and make the per-target stuff setup host & host_cpu according to the target. + +host_cpu=$target_cpu +host=$target + +# Map host cpu into the config cpu subdirectory name. +# The default is $host_cpu. + +case "${host_cpu}" in + +c[12]) gdb_host_cpu=convex ;; +hppa*) gdb_host_cpu=pa ;; +i[34]86) gdb_host_cpu=i386 ;; +m68*) gdb_host_cpu=m68k ;; +np1) gdb_host_cpu=gould ;; +pyramid) gdb_host_cpu=pyr ;; +*) gdb_host_cpu=$target_cpu ;; + +esac + +# map host info into gdb names. + +case "${host}" in + +a29k-*-*) gdb_host=ultra3 ;; + +arm-*-*) gdb_host=arm ;; + +c[12]-*-*) gdb_host=convex ;; + +hppa*-hp-bsd*) gdb_host=hppabsd ;; +hppa*-hp-hpux*) gdb_host=hppahpux ;; + +i[34]86-ncr-*) gdb_host=ncr3000 ;; +i[34]86-sequent-*) gdb_host=symmetry ;; + +i[34]86-*-bsd*) gdb_host=i386bsd ;; +i[34]86-*-lynx*) gdb_host=i386lynx ;; +i[34]86-*-go32) gdb_host=go32 + gdb_serial_driver=ser-go32.c + ;; +i[34]86-*-linux) gdb_host=linux ;; +i[34]86-*-mach) gdb_host=i386mach ;; +i[34]86-*-sco3.2v4*) gdb_host=i386sco4 ;; +i[34]86-*-sco*) gdb_host=i386sco ;; +i[34]86-*-solaris*) gdb_host=i386sol2 ;; +i[34]86-*-sunos*) gdb_host=sun386 ;; +i[34]86-*-sysv3.2) gdb_host=i386v32 ;; +i[34]86-*-sysv4*) gdb_host=i386v4 ;; +i[34]86-*-sysv*) gdb_host=i386v ;; + +m680[01]0-sun-sunos3*) gdb_host=sun2os3 ;; +m680[01]0-sun-sunos4*) gdb_host=sun2os4 ;; +m68030-sony-*) gdb_host=news1000 ;; + +m68*-altos-*) gdb_host=altos ;; +m68*-apollo*-sysv*) gdb_host=apollo68v ;; +m68*-apollo*-bsd*) gdb_host=apollo68b ;; +m68*-att-*) gdb_host=3b1 ;; +m68*-cbm-sysv4*) gdb_host=amix ;; +m68*-hp-bsd*) gdb_host=hp300bsd ;; +m68*-hp-hpux*) gdb_host=hp300hpux ;; +m68*-isi-*) gdb_host=isi ;; +m68*-sony-*) gdb_host=news ;; +m68*-sun-sunos3*) gdb_host=sun3os3 ;; +m68*-sun-sunos4*) gdb_host=sun3os4 ;; +m68*-sun-*) gdb_host=sun3os4 ;; + +m88k-motorola-*) gdb_host=delta88 ;; +m88k-*-*) gdb_host=m88k ;; + +mips-dec-*) gdb_host=decstation ;; +mips-little-*) gdb_host=littlemips ;; +mips-sgi-irix3) gdb_host=irix3 ;; +mips-sgi-irix4*) gdb_host=irix4 ;; +mips-sony-*) gdb_host=bigmips ;; + +none-*-*) gdb_host=none ;; + +np1-*-*) gdb_host=np1 ;; + +ns32k-umax-*) gdb_host=umax ;; +ns32k-utek-sysv) gdb_host=merlin ;; + +pn-*-*) gdb_host=pn ;; + +pyramid-*-*) gdb_host=pyramid ;; + +romp-*-*) gdb_host=rtbsd ;; + +rs6000-*-*) gdb_host=rs6000 ;; + +sparc-*-solaris2*) gdb_host=sun4sol2 ;; +sparc-*-sunos4*) gdb_host=sun4os4 ;; +sparc-*-*) gdb_host=sun4os4 ;; + +tahoe-*-*) gdb_host=tahoe ;; + +vax-*-bsd*) gdb_host=vaxbsd ;; +vax-*-ultrix2*) gdb_host=vaxult2 ;; +vax-*-ultrix*) gdb_host=vaxult ;; + +esac + +if [ ! -f ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ]; then + echo '***' "GDB remote does not support host ${host}" 1>&2 + exit 1 +fi + +# We really shouldn't depend on there being a space after XM_FILE= ... +hostfile=`awk '$1 == "XM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` + +# per-target: + +# Map target cpu into the config cpu subdirectory name. +# The default is $target_cpu. + +case "${target_cpu}" in + +c[12]) gdb_target_cpu=convex ;; +hppa*) gdb_target_cpu=pa ;; +i[34]86) gdb_target_cpu=i386 ;; +m68*) gdb_target_cpu=m68k ;; +np1) gdb_target_cpu=gould ;; +pn) gdb_target_cpu=gould ;; +pyramid) gdb_target_cpu=pyr ;; +sparc*) gdb_target_cpu=sparc ;; +*) gdb_target_cpu=$target_cpu ;; + +esac + +# map target info into gdb names. + +case "${target}" in + +a29k-*-aout) gdb_target=a29k ;; +a29k-*-coff) gdb_target=a29k ;; +a29k-*-elf) gdb_target=a29k ;; +a29k-*-ebmon) gdb_target=a29k ;; +a29k-*-kern) gdb_target=a29k-kern ;; +a29k-*-none) gdb_target=a29k ;; +a29k-*-sym1) gdb_target=ultra3 ;; +a29k-*-udi) gdb_target=a29k-udi ;; + +arm-*-*) gdb_target=arm ;; + +c1-*-*) gdb_target=convex ;; +c2-*-*) gdb_target=convex ;; + +h8300-*-*) gdb_target=h8300hms ;; +h8500-*-*) gdb_target=h8500hms ;; + +sh-*-*) gdb_target=sh ;; + +hppa*-*-bsd*) gdb_target=hppabsd ;; +hppa*-*-hpux*) gdb_target=hppahpux ;; + +i[34]86-sequent-*) gdb_target=symmetry ;; +i[34]86-ncr-*) gdb_target=ncr3000 ;; + +i[34]86-*-aout) gdb_target=i386aout ;; +i[34]86-*-coff) gdb_target=i386v ;; +i[34]86-*-elf) gdb_target=i386v ;; + +i[34]86-*-bsd*) gdb_target=i386bsd ;; +i[34]86-*-lynx*) gdb_target=i386lynx ;; +i[34]86-*-go32) gdb_target=i386aout ;; +i[34]86-*-solaris*) gdb_target=i386sol2 ;; +i[34]86-*-sunos*) gdb_target=sun386 ;; +i[34]86-*-sysv4*) gdb_target=i386v4 ;; +i[34]86-*-sco*) gdb_target=i386v ;; +i[34]86-*-sysv*) gdb_target=i386v ;; +i[34]86-*-linux) gdb_target=linux ;; + +i960-*-bout) gdb_target=vxworks960 ;; +i960-*-coff) gdb_target=nindy960 ;; +i960-*-elf) gdb_target=nindy960 ;; + +i960-*-nindy) gdb_target=nindy960 ;; +i960-*-vxworks) gdb_target=vxworks960 ;; + +m68000-*-aout) gdb_target=m68k-nofp ;; +m68000-*-coff) gdb_target=m68k-nofp ;; +m68000-*-elf) gdb_target=m68k-nofp ;; +m68000-*-sunos3*) gdb_target=sun2os3 ;; +m68000-*-sunos4*) gdb_target=sun2os4 ;; + +m68*-cbm-sysv4*) gdb_target=amix ;; +m68*-hp-bsd*) gdb_target=hp300bsd ;; +m68*-hp-hpux*) gdb_target=hp300hpux ;; + +m68*-altos-*) gdb_target=altos ;; +m68*-att-*) gdb_target=3b1 ;; +m68*-ericsson-*) gdb_target=es1800 ;; +m68*-isi-*) gdb_target=isi ;; +m68*-netx-*) gdb_target=vxworks68 ;; +m68*-sony-*) gdb_target=news ;; +m68*-tandem-*) gdb_target=st2000 ;; + +m68*-*-aout) gdb_target=m68k-fp ;; +m68*-*-coff) gdb_target=m68k-fp ;; +m68*-*-elf) gdb_target=m68k-fp ;; +m68*-*-os68k) gdb_target=os68k ;; +m68*-*-sunos3*) gdb_target=sun3os3 ;; +m68*-*-sunos4*) gdb_target=sun3os4 ;; +m68*-*-vxworks*) gdb_target=vxworks68 ;; + +m88k-motorola-*) gdb_target=delta88 ;; +m88k-*-*) gdb_target=m88k ;; + +mips-big-*) gdb_target=bigmips ;; +mips-dec-*) gdb_target=decstation ;; +mips-idt-ecoff) gdb_target=idt ;; +mips-little-*) gdb_target=littlemips ;; +mips-sgi-*) gdb_target=irix3 ;; +mips-sony-*) gdb_target=bigmips ;; + +none-*-*) gdb_target=none ;; + +np1-*-*) gdb_target=np1 ;; + +ns32k-utek-sysv) gdb_target=merlin ;; +ns32k-utek-*) gdb_target=umax ;; + +pn-*-*) gdb_target=pn ;; + +pyramid-*-*) gdb_target=pyramid ;; + +rs6000-*-*) gdb_target=rs6000 ;; + +sparc-*-aout) gdb_target=sparc-em ;; +sparc-*-coff) gdb_target=sparc-em ;; +sparc-*-elf) gdb_target=sparc-em ;; +sparc-*-solaris2*) gdb_target=sun4sol2 ;; +sparc-*-sunos4*) gdb_target=sun4os4 ;; +sparc-*-vxworks*) gdb_target=sparc-em ;; +sparc-*-*) gdb_target=sun4os4 ;; +sparclite*-*-*) gdb_target=sparclite ;; + +tahoe-*-*) gdb_target=tahoe ;; +vax-*-*) gdb_target=vax ;; + +z8k-*-sim) gdb_target=z8ksim ;; +esac + +if [ ! -f ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt ]; then + echo '***' "GDB remote does not support target ${target}" 1>&2 + exit 1 +fi + +if [ -z "${removing}" ] ; then + cat ${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh ${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt | awk '$1 == "#msg" { + print substr($0,6)}' +fi + +# We really shouldn't depend on there being a space after TM_FILE= ... +targetfile=`awk '$1 == "TM_FILE=" { print $2 }' <${srcdir}/../config/${gdb_target_cpu}/${gdb_target}.mt` + +if [ "${target}" = "${host}" ] ; then + nativefile=`awk '$1 == "NAT_FILE=" { print $2 }' <${srcdir}/../config/${gdb_host_cpu}/${gdb_host}.mh` +fi + +host_makefile_frag=../config/${gdb_host_cpu}/${gdb_host}.mh +target_makefile_frag=../config/${gdb_target_cpu}/${gdb_target}.mt + +# If hostfile (XM_FILE) and/or targetfile (TM_FILE) and/or nativefile +# (NAT_FILE) is not set in the ?config/* file, we don't make the +# corresponding links. But we have to remove the xm.h files and tm.h +# files anyway, e.g. when switching from "configure host" to +# "configure none". + +files= +links= +rm -f xm.h +rm -f ser-hardwire.c +if [ "${hostfile}" != "" ]; then + if [ -f ${srcdir}/../config/${hostfile} ]; then + files="${files} ../config/${hostfile}" + else + files="${files} ../config/${gdb_host_cpu}/${hostfile}" + fi + links="${links} xm.h" + +# files="${files} ${gdb_serial_driver}" +# links="${links} ser-hardwire.c" +fi +rm -f tm.h +if [ "${targetfile}" != "" ]; then + if [ -f ${srcdir}/../config/${targetfile} ]; then + files="${files} ../config/${targetfile}" + else + files="${files} ../config/${gdb_target_cpu}/${targetfile}" + fi + links="${links} tm.h" +fi +rm -f nm.h +if [ "${nativefile}" != "" ]; then + if [ -f ${srcdir}/../config/${nativefile} ]; then + files="${files} ../config/${nativefile}" + else + files="${files} ../config/${gdb_host_cpu}/${nativefile}" + fi + links="${links} nm.h" +# temporary scaffolding until all hosts have the host/target/native +# split in place. +else + files="${files} ../config/nm-trash.h" + links="${links} nm.h" +fi + +if [ ${target_cpu} = "sparclite" ]; then + configdirs="${configdirs} sparclite" +fi + +# post-target: + +if [ "${nativefile}" = "" ] ; then + sed -e '/^NATDEPFILES= /s//# NATDEPFILES= /' \ + < Makefile > Makefile.tem + mv -f Makefile.tem Makefile +fi diff --git a/gdb/gdbserver/remote-gutils.c b/gdb/gdbserver/remote-gutils.c new file mode 100644 index 00000000000..9db96415b55 --- /dev/null +++ b/gdb/gdbserver/remote-gutils.c @@ -0,0 +1,412 @@ +/* General utility routines for the remote server for GDB. + Copyright (C) 1986, 1989, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include "defs.h" +#include + +void error (); +void fatal (); + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, + rather than waiting until QUIT is executed. */ + +int immediate_quit; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) (); + PTR arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + (*ptr->function) (ptr->arg); + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +PTR +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +PTR +xrealloc (ptr, size) + PTR ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + char *err; + char *combined; + + if (errcode < sys_nerr) + err = sys_errlist[errcode]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + printf ("%s.\n", combined); +} + +void +quit () +{ + fflush (stdout); + ioctl (fileno (stdout), TIOCFLUSH, 0); + error ("Quit"); +} + +/* Control C comes here */ + +void +request_quit (ignored) + int ignored; +{ + quit_flag = 1; + if (immediate_quit) + quit (); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +NORETURN void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + extern jmp_buf toplevel; + + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + longjmp(toplevel, 1); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + const char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + /***********if (!input_from_terminal_p ()) + return 1; *************************/ + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') + clearerr (stdin); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf ("Please answer y or n.\n"); + } +} + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +void +printchar (ch, stream) + unsigned char ch; + FILE *stream; +{ + register int c = ch; + if (c < 040 || c >= 0177) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == '"' || c == '\'') + fputc ('\\', stream); + fputc (c, stream); + } +} diff --git a/gdb/gdbserver/remote-inflow.c b/gdb/gdbserver/remote-inflow.c new file mode 100644 index 00000000000..f093d833f05 --- /dev/null +++ b/gdb/gdbserver/remote-inflow.c @@ -0,0 +1,366 @@ +/* Low level interface to ptrace, for the remote server for GDB. + Copyright (C) 1986, 1987, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +/*************************** +#include "initialize.h" +****************************/ + +#include +#include +#include +/*#include */ +#define LYNXOS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "/usr/include/wait.h" + +/***************Begin MY defs*********************/ +int quit_flag = 0; +char registers[REGISTER_BYTES]; + +/* Index within `registers' of the first byte of the space for + register N. */ + + +char buf2[MAX_REGISTER_RAW_SIZE]; +/***************End MY defs*********************/ + +#include +/*#include */ + +extern char **environ; +extern int errno; +extern int inferior_pid; +void error (), quit (), perror_with_name (); +int query (); + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (allargs, env) + char **allargs; + char **env; +{ + int pid; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char status; + char execbuf[1024]; + + /* exec is said to fail if the executable is open. */ + /****************close_exec_file ();*****************/ + + sprintf (execbuf, "exec %s", allargs); + + pid = fork (); + if (pid < 0) + perror_with_name ("fork"); + + if (pid == 0) + { + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); + + errno = 0; + ptrace (PTRACE_TRACEME); + + execle ("/bin/sh", "sh", "-c", execbuf, 0, env); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + /*************inferior_died ();****VK**************/ +} + +/* Wait for process, returns status */ + +unsigned char +mywait (status) + char *status; +{ + int pid; + union wait w; + + pid = wait (&w); + if (pid != PIDGET(inferior_pid)) + perror_with_name ("wait"); + + inferior_pid = BUILDPID (inferior_pid, w.w_tid); + + if (WIFEXITED (w)) + { + fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); + *status = 'E'; + return ((unsigned char) WEXITSTATUS (w)); + } + else if (!WIFSTOPPED (w)) + { + fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); + *status = 'T'; + return ((unsigned char) WTERMSIG (w)); + } + + fetch_inferior_registers (0); + + *status = 'S'; + return ((unsigned char) WSTOPSIG (w)); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +myresume (step, signal) + int step; + int signal; +{ + errno = 0; + ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) + +static struct econtext * +lynx_registers_addr() +{ + st_t *stblock; + int ecpoff = offsetof(st_t, ecp); + CORE_ADDR ecp; + + errno = 0; + stblock = (st_t *) ptrace (PTRACE_THREADUSER, inferior_pid, + (PTRACE_ARG3_TYPE)0, 0); + if (errno) + perror_with_name ("PTRACE_THREADUSER"); + + ecp = (CORE_ADDR) ptrace (PTRACE_PEEKTHREAD, inferior_pid, + (PTRACE_ARG3_TYPE)ecpoff, 0); + ecp -= (CORE_ADDR)stblock; + if (errno) + perror_with_name ("lynx_registers_addr(PTRACE_PEEKTHREAD)"); + + return (struct econtext *)ecp; +} + +static struct econtext *ecp; + +/* Mapping between GDB register #s and offsets into econtext. Must be + consistent with REGISTER_NAMES macro in tm-i386v.h. */ + +#define X(ENTRY)(offsetof(struct econtext, ENTRY) / 4) +static int regmap[] = { + X(eax), + X(ecx), + X(edx), + X(ebx), + X(esp), + X(ebp), + X(esi), + X(edi), + X(eip), + X(flags), /* ps */ + X(cs), + X(ss), + X(ds), + X(es), + X(ecode), /* Lynx doesn't give us either fs or gs, so */ + X(fault) /* we just substitute these two in the hopes + that they are useful. */ + }; + +/* Fetch one or more registers from the inferior. REGNO == -1 to get + them all. We actually fetch more than requested, when convenient, + marking them as valid so we won't fetch them again. */ + +void +fetch_inferior_registers (ignored) + int ignored; +{ + int regno; + unsigned long reg; + struct econtext *ecp; + + ecp = lynx_registers_addr(); + + for (regno = 0; regno < NUM_REGS; regno++) + { + errno = 0; + reg = ptrace (PTRACE_PEEKTHREAD, inferior_pid, + (PTRACE_ARG3_TYPE) (&ecp->fault + regmap[regno]), 0); + if (errno) + perror_with_name ("fetch_inferior_registers(PTRACE_PEEKTHREAD)"); + + *(unsigned long *)®isters[REGISTER_BYTE (regno)] = reg; + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (ignored) + int ignored; +{ + int regno; + unsigned long reg; + struct econtext *ecp; + + ecp = lynx_registers_addr(); + + for (regno = 0; regno < NUM_REGS; regno++) + { + reg = *(unsigned long *)®isters[REGISTER_BYTE (regno)]; + + errno = 0; + ptrace (PTRACE_POKEUSER, inferior_pid, + (PTRACE_ARG3_TYPE) (&ecp->fault + regmap[regno]), reg); + if (errno) + perror_with_name ("PTRACE_POKEUSER"); + } +} + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +read_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + buffer[i] = ptrace (1, inferior_pid, addr, 0); + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); +} + +/* Copy LEN bytes of data from debugger memory at MYADDR + to inferior's memory at MEMADDR. + On failure (cannot write the inferior) + returns the value of errno. */ + +int +write_inferior_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & -sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + + if (count > 1) + { + buffer[count - 1] + = ptrace (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +void +initialize () +{ + inferior_pid = 0; +} + +int +have_inferior_p () +{ + return inferior_pid != 0; +} diff --git a/gdb/gdbserver/remote-server.c b/gdb/gdbserver/remote-server.c new file mode 100644 index 00000000000..6a53390bb64 --- /dev/null +++ b/gdb/gdbserver/remote-server.c @@ -0,0 +1,151 @@ +/* Main code for remote server for GDB. + Copyright (C) 1989, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include +#include + +void read_inferior_memory (); +unsigned char mywait (); +void myresume(); +void initialize (); +int create_inferior (); + +extern char registers[]; +int inferior_pid; +extern char **environ; + +/* Descriptor for I/O to remote machine. */ +int remote_desc; +int kiodebug = 0; +int remote_debugging; + +void remote_send (); +void putpkt (); +void getpkt (); +void remote_open (); +void write_ok (); +void write_enn (); +void convert_ascii_to_int (); +void convert_int_to_ascii (); +void prepare_resume_reply (); +void decode_m_packet (); +void decode_M_packet (); +jmp_buf toplevel; + +main (argc, argv) + int argc; + char *argv[]; +{ + char ch, status, own_buf[2000], mem_buf[2000]; + int i = 0; + unsigned char signal; + unsigned int mem_addr, len; + char argvec[1024]; + + if (setjmp(toplevel)) + { + fprintf(stderr, "Exiting\n"); + exit(1); + } + + if (argc < 3) + error("Usage: gdbserver tty prog [args ...]"); + + initialize (); + remote_open (argv[1], 0); + + argvec[0] = '\000'; + for (i = 2; i < argc; i++) + strcat(argvec, argv[i]); + + inferior_pid = create_inferior (argvec, environ); + fprintf (stderr, "Process %s created; pid = %d\n", argv[1], inferior_pid); + + signal = mywait (&status); /* Wait till we are at 1st instr in shell */ + if (status != 'S' || signal != SIGTRAP) + error ("Bad status from shell\n"); + myresume (0, 0); /* Start up the shell */ + signal = mywait (&status); /* Wait for program to start */ + + /* We are now stopped at the first instruction of the target process */ + + setjmp(toplevel); + do + { + getpkt (own_buf); + i = 0; + ch = own_buf[i++]; + switch (ch) + { + case '?': + prepare_resume_reply (own_buf, status, signal); + break; + case 'g': + convert_int_to_ascii (registers, own_buf, REGISTER_BYTES); + break; + case 'G': + convert_ascii_to_int (&own_buf[1], registers, REGISTER_BYTES); + store_inferior_registers (-1); + write_ok (own_buf); + break; + case 'm': + decode_m_packet (&own_buf[1], &mem_addr, &len); + read_inferior_memory (mem_addr, mem_buf, len); + convert_int_to_ascii (mem_buf, own_buf, len); + break; + case 'M': + decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf); + if (write_inferior_memory (mem_addr, mem_buf, len) == 0) + write_ok (own_buf); + else + write_enn (own_buf); + break; + case 'c': + myresume (0, 0); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 's': + myresume (1, 0); + signal = mywait (&status); + prepare_resume_reply (own_buf, status, signal); + break; + case 'k': + kill_inferior (); + sprintf (own_buf, "q"); + putpkt (own_buf); + fprintf (stderr, "Obtained kill request...terminating\n"); + close (remote_desc); + exit (0); + default: + printf ("\nUnknown option chosen by master\n"); + write_enn (own_buf); + break; + } + + putpkt (own_buf); + } + while (1); + + close (remote_desc); + /** now get out of here**/ + fprintf (stderr, "Finished reading data from serial link - Bye!\n"); + exit (0); +} diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c new file mode 100644 index 00000000000..2781ac5e35c --- /dev/null +++ b/gdb/gdbserver/remote-utils.c @@ -0,0 +1,339 @@ +/* Remote utility routines for the remote server for GDB. + Copyright (C) 1986, 1989, 1993 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include +#include +#include +#include +#include +#include +#include + +extern int remote_desc; +extern int remote_debugging; +extern int kiodebug; + +void remote_open (); +void remote_send (); +void putpkt (); +void getpkt (); + +void write_ok (); +void write_enn (); +void convert_ascii_to_int (); +void convert_int_to_ascii (); +void prepare_resume_reply (); + +/* Open a connection to a remote debugger. + NAME is the filename used for communication. */ + +void +remote_open (name, from_tty) + char *name; + int from_tty; +{ + struct sgttyb sg; + + remote_debugging = 0; + + remote_desc = open (name, O_RDWR); + if (remote_desc < 0) + perror_with_name ("Could not open remote device"); + + ioctl (remote_desc, TIOCGETP, &sg); + sg.sg_flags = RAW; + ioctl (remote_desc, TIOCSETP, &sg); + + fprintf (stderr, "Remote debugging using %s\n", name); + remote_debugging = 1; +} + +/* Convert hex digit A to a number. */ + +static int +fromhex (a) + int a; +{ + if (a >= '0' && a <= '9') + return a - '0'; + else if (a >= 'a' && a <= 'f') + return a - 'a' + 10; + else + error ("Reply contains invalid hex digit"); +} + +/* Convert number NIB to a hex digit. */ + +static int +tohex (nib) + int nib; +{ + if (nib < 10) + return '0' + nib; + else + return 'a' + nib - 10; +} + +/* Send the command in BUF to the remote machine, + and read the reply into BUF. + Report an error if we get an error reply. */ + +void +remote_send (buf) + char *buf; +{ + putpkt (buf); + getpkt (buf); + + if (buf[0] == 'E') + error ("Remote failure reply: E"); +} + +/* Send a packet to the remote machine, with error checking. + The data of the packet is in BUF. */ + +void +putpkt (buf) + char *buf; +{ + int i; + unsigned char csum = 0; + char buf2[2000]; + char buf3[1]; + int cnt = strlen (buf); + char *p; + + /* Copy the packet into buffer BUF2, encapsulating it + and giving it a checksum. */ + + p = buf2; + *p++ = '$'; + + for (i = 0; i < cnt; i++) + { + csum += buf[i]; + *p++ = buf[i]; + } + *p++ = '#'; + *p++ = tohex ((csum >> 4) & 0xf); + *p++ = tohex (csum & 0xf); + + /* Send it over and over until we get a positive ack. */ + + do + { + write (remote_desc, buf2, p - buf2); + read (remote_desc, buf3, 1); + } + while (buf3[0] != '+'); +} + +static int +readchar () +{ + char buf[1]; + while (read (remote_desc, buf, 1) != 1); + return buf[0] & 0x7f; +} + +/* Read a packet from the remote machine, with error checking, + and store it in BUF. */ + +void +getpkt (buf) + char *buf; +{ + char *bp; + unsigned char csum, c, c1, c2; + extern kiodebug; + + while (1) + { + csum = 0; + while ((c = readchar ()) != '$'); + + bp = buf; + while (1) + { + c = readchar (); + if (c == '#') + break; + *bp++ = c; + csum += c; + } + *bp = 0; + + c1 = fromhex (readchar ()); + c2 = fromhex (readchar ()); + if (csum == (c1 << 4) + c2) + break; + + fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", + (c1 << 4) + c2, csum, buf); + write (remote_desc, "-", 1); + } + + write (remote_desc, "+", 1); +} + +void +write_ok (buf) + char *buf; +{ + buf[0] = 'O'; + buf[1] = 'k'; + buf[2] = '\0'; +} + +void +write_enn (buf) + char *buf; +{ + buf[0] = 'E'; + buf[1] = 'N'; + buf[2] = 'N'; + buf[3] = '\0'; +} + +void +convert_int_to_ascii (from, to, n) + char *from, *to; + int n; +{ + int nib; + char ch; + while (n--) + { + ch = *from++; + nib = ((ch & 0xf0) >> 4) & 0x0f; + *to++ = tohex (nib); + nib = ch & 0x0f; + *to++ = tohex (nib); + } + *to++ = 0; +} + + +void +convert_ascii_to_int (from, to, n) + char *from, *to; + int n; +{ + int nib1, nib2; + while (n--) + { + nib1 = fromhex (*from++); + nib2 = fromhex (*from++); + *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f); + } +} + +static char * +outreg(regno, buf) + int regno; + char *buf; +{ + extern char registers[]; + + *buf++ = tohex (regno >> 4); + *buf++ = tohex (regno & 0xf); + *buf++ = ':'; + convert_int_to_ascii (®isters[REGISTER_BYTE (regno)], buf, 4); + buf += 8; + *buf++ = ';'; + + return buf; +} + +void +prepare_resume_reply (buf, status, signal) + char *buf, status; + unsigned char signal; +{ + int nib; + char ch; + + *buf++ = 'T'; + + nib = ((signal & 0xf0) >> 4); + *buf++ = tohex (nib); + nib = signal & 0x0f; + *buf++ = tohex (nib); + + buf = outreg (PC_REGNUM, buf); + buf = outreg (FP_REGNUM, buf); + buf = outreg (SP_REGNUM, buf); +#ifdef NPC_REGNUM + buf = outreg (NPC_REGNUM, buf); +#endif +#ifdef O7_REGNUM + buf = outreg (O7_REGNUM, buf); +#endif + + *buf++ = 0; +} + +void +decode_m_packet (from, mem_addr_ptr, len_ptr) + char *from; + unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + for (j = 0; j < 4; j++) + { + if ((ch = from[i++]) == 0) + break; + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } +} + +void +decode_M_packet (from, mem_addr_ptr, len_ptr, to) + char *from, *to; + unsigned int *mem_addr_ptr, *len_ptr; +{ + int i = 0, j = 0; + char ch; + *mem_addr_ptr = *len_ptr = 0; + + while ((ch = from[i++]) != ',') + { + *mem_addr_ptr = *mem_addr_ptr << 4; + *mem_addr_ptr |= fromhex (ch) & 0x0f; + } + + while ((ch = from[i++]) != ':') + { + *len_ptr = *len_ptr << 4; + *len_ptr |= fromhex (ch) & 0x0f; + } + + convert_ascii_to_int (&from[i++], to, *len_ptr); +}