* 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.
This commit is contained in:
Stu Grossman 1993-05-26 20:49:21 +00:00
parent 185a1705bb
commit e20520b8f9
5 changed files with 1599 additions and 0 deletions

331
gdb/gdbserver/configure.in Normal file
View File

@ -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

View File

@ -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 <stdio.h>
#include <sys/ioctl.h>
#include "defs.h"
#include <setjmp.h>
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);
}
}

View File

@ -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 <stdio.h>
#include <sys/param.h>
#include <sys/dir.h>
/*#include <sys/user.h>*/
#define LYNXOS
#include <sys/mem.h>
#include <sys/signal.h>
#include <sys/file.h>
#include <sys/kernel.h>
#include <sys/itimer.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/proc.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sgtty.h>
#include <fcntl.h>
#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 <sys/ptrace.h>
/*#include <machine/reg.h>*/
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 *)&registers[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 *)&registers[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;
}

View File

@ -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 <setjmp.h>
#include <signal.h>
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);
}

View File

@ -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 <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <a.out.h>
#include <sys/file.h>
#include <sgtty.h>
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 (&registers[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);
}