1313 lines
30 KiB
Bash
1313 lines
30 KiB
Bash
#!/bin/sh
|
||
# This is a shell archive.
|
||
# Run the file through sh to extract its contents.
|
||
# shar: Shell Archiver
|
||
# Run the following text with /bin/sh to create:
|
||
# Remote_Makefile
|
||
# remote_gutils.c
|
||
# remote_inflow.c
|
||
# remote_server.c
|
||
# remote_utils.c
|
||
# This archive created: Fri Jun 23 17:06:55 1989
|
||
cat << \SHAR_EOF > Remote_Makefile
|
||
# Makefile for the remote server for GDB, the GNU debugger.
|
||
# Copyright (C) 1986, 1989 Free Software Foundation, Inc.
|
||
#
|
||
# This file is part of GDB.
|
||
#
|
||
# GDB 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 1, or (at your option)
|
||
# any later version.
|
||
#
|
||
# GDB 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 GDB; see the file COPYING. If not, write to
|
||
# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
CFLAGS = -g
|
||
CC = cc
|
||
|
||
SERVER = remote_server.o\
|
||
remote_inflow.o\
|
||
remote_utils.o\
|
||
remote_gutils.o
|
||
|
||
prog : $(SERVER)
|
||
$(CC) -g -o serve $(SERVER)
|
||
SHAR_EOF
|
||
cat << \SHAR_EOF > remote_gutils.c
|
||
/* General utility routines for the remote server for GDB, the GNU debugger.
|
||
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
|
||
|
||
This file is part of GDB.
|
||
|
||
GDB 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 1, or (at your option)
|
||
any later version.
|
||
|
||
GDB 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 GDB; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
#include <stdio.h>
|
||
#include <sys/ioctl.h>
|
||
#include "defs.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) ();
|
||
int 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. */
|
||
|
||
char *
|
||
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. */
|
||
|
||
char *
|
||
xrealloc (ptr, size)
|
||
char *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 ()
|
||
{
|
||
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. */
|
||
|
||
void
|
||
error (string, arg1, arg2, arg3)
|
||
char *string;
|
||
int arg1, arg2, arg3;
|
||
{
|
||
fflush (stdout);
|
||
fprintf (stderr, string, arg1, arg2, arg3);
|
||
fprintf (stderr, "\n");
|
||
/************return_to_top_level ();************/
|
||
}
|
||
|
||
/* 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)
|
||
char *ptr;
|
||
int size;
|
||
{
|
||
register char *p = (char *) xmalloc (size + 1);
|
||
bcopy (ptr, p, size);
|
||
p[size] = 0;
|
||
return p;
|
||
}
|
||
|
||
char *
|
||
concat (s1, s2, s3)
|
||
char *s1, *s2, *s3;
|
||
{
|
||
register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1;
|
||
register char *val = (char *) xmalloc (len);
|
||
strcpy (val, s1);
|
||
strcat (val, s2);
|
||
strcat (val, s3);
|
||
return val;
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
SHAR_EOF
|
||
cat << \SHAR_EOF > remote_inflow.c
|
||
/* Low level interface to ptrace, for GDB when running under Unix.
|
||
Copyright (C) 1986, 1987 Free Software Foundation, Inc.
|
||
*/
|
||
|
||
#include "defs.h"
|
||
#include "param.h"
|
||
#include "wait.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>
|
||
#include <signal.h>
|
||
#include <sys/ioctl.h>
|
||
#include <sgtty.h>
|
||
#include <fcntl.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*********************/
|
||
|
||
#ifdef NEW_SUN_PTRACE
|
||
#include <sys/ptrace.h>
|
||
#include <machine/reg.h>
|
||
#endif
|
||
|
||
extern char **environ;
|
||
extern int errno;
|
||
extern int inferior_pid;
|
||
void error(), quit(), perror_with_name();
|
||
int query();
|
||
void supply_register(), write_register();
|
||
CORE_ADDR read_register();
|
||
|
||
/* Nonzero if we are debugging an attached outside process
|
||
rather than an inferior. */
|
||
|
||
|
||
/* 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;
|
||
|
||
/* exec is said to fail if the executable is open. */
|
||
/****************close_exec_file ();*****************/
|
||
|
||
pid = vfork ();
|
||
if (pid < 0)
|
||
perror_with_name ("vfork");
|
||
|
||
if (pid == 0)
|
||
{
|
||
/* Run inferior in a separate process group. */
|
||
setpgrp (getpid (), getpid ());
|
||
|
||
/* Not needed on Sun, at least, and loses there
|
||
because it clobbers the superior. */
|
||
/*??? signal (SIGQUIT, SIG_DFL);
|
||
signal (SIGINT, SIG_DFL); */
|
||
|
||
errno = 0;
|
||
ptrace (0);
|
||
|
||
execle ("/bin/sh", "sh", "-c", allargs, 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. */
|
||
|
||
kill_inferior ()
|
||
{
|
||
if (inferior_pid == 0)
|
||
return;
|
||
ptrace (8, inferior_pid, 0, 0);
|
||
wait (0);
|
||
/*************inferior_died ();****VK**************/
|
||
}
|
||
|
||
/* Resume execution of the inferior process.
|
||
If STEP is nonzero, single-step it.
|
||
If SIGNAL is nonzero, give it that signal. */
|
||
|
||
unsigned char
|
||
resume (step, signal,status)
|
||
int step;
|
||
int signal;
|
||
char *status;
|
||
{
|
||
int pid ;
|
||
WAITTYPE w;
|
||
|
||
errno = 0;
|
||
ptrace (step ? 9 : 7, inferior_pid, 1, signal);
|
||
if (errno)
|
||
perror_with_name ("ptrace");
|
||
pid = wait(&w);
|
||
if(pid != inferior_pid)
|
||
perror_with_name ("wait");
|
||
|
||
if(WIFEXITED(w))
|
||
{
|
||
printf("\nchild exited with retcode = %x \n",WRETCODE(w));
|
||
*status = 'E';
|
||
return((unsigned char) WRETCODE(w));
|
||
}
|
||
else if(!WIFSTOPPED(w))
|
||
{
|
||
printf("\nchild did terminated with signal = %x \n",WTERMSIG(w));
|
||
*status = 'T';
|
||
return((unsigned char) WTERMSIG(w));
|
||
}
|
||
else
|
||
{
|
||
printf("\nchild stopped with signal = %x \n",WSTOPSIG(w));
|
||
*status = 'S';
|
||
return((unsigned char) WSTOPSIG(w));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
#ifdef NEW_SUN_PTRACE
|
||
|
||
void
|
||
fetch_inferior_registers ()
|
||
{
|
||
struct regs inferior_registers;
|
||
struct fp_status inferior_fp_registers;
|
||
extern char registers[];
|
||
|
||
ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers);
|
||
if (errno)
|
||
perror_with_name ("ptrace");
|
||
/**********debugging begin **********/
|
||
print_some_registers(&inferior_registers);
|
||
/**********debugging end **********/
|
||
ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers);
|
||
if (errno)
|
||
perror_with_name ("ptrace");
|
||
|
||
bcopy (&inferior_registers, registers, 16 * 4);
|
||
bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)],
|
||
sizeof inferior_fp_registers.fps_regs);
|
||
*(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
|
||
*(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
|
||
bcopy (&inferior_fp_registers.fps_control,
|
||
®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
|
||
}
|
||
|
||
/* 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). */
|
||
|
||
store_inferior_registers (regno)
|
||
int regno;
|
||
{
|
||
struct regs inferior_registers;
|
||
struct fp_status inferior_fp_registers;
|
||
extern char registers[];
|
||
|
||
bcopy (registers, &inferior_registers, 16 * 4);
|
||
bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
|
||
sizeof inferior_fp_registers.fps_regs);
|
||
inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)];
|
||
inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)];
|
||
bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)],
|
||
&inferior_fp_registers.fps_control,
|
||
sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs);
|
||
|
||
ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers);
|
||
if (errno)
|
||
perror_with_name ("ptrace");
|
||
ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers);
|
||
if (errno)
|
||
perror_with_name ("ptrace");
|
||
}
|
||
|
||
#endif /* not NEW_SUN_PTRACE */
|
||
|
||
|
||
/* 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
|
||
try_writing_regs_command ()
|
||
{
|
||
register int i;
|
||
register int value;
|
||
extern int errno;
|
||
|
||
if (inferior_pid == 0)
|
||
error ("There is no inferior process now.");
|
||
|
||
fetch_inferior_registers();
|
||
for (i = 0;i<18 ; i ++)
|
||
{
|
||
QUIT;
|
||
errno = 0;
|
||
value = read_register(i);
|
||
write_register ( i, value);
|
||
if (errno == 0)
|
||
{
|
||
printf (" Succeeded with register %d; value 0x%x (%d).\n",
|
||
i, value, value);
|
||
}
|
||
else
|
||
printf (" Failed with register %d.\n", i);
|
||
}
|
||
}
|
||
|
||
void
|
||
initialize ()
|
||
{
|
||
|
||
inferior_pid = 0;
|
||
|
||
|
||
}
|
||
|
||
|
||
/* Return the contents of register REGNO,
|
||
regarding it as an integer. */
|
||
|
||
CORE_ADDR
|
||
read_register (regno)
|
||
int regno;
|
||
{
|
||
/* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
|
||
return *(int *) ®isters[REGISTER_BYTE (regno)];
|
||
}
|
||
|
||
/* Store VALUE in the register number REGNO, regarded as an integer. */
|
||
|
||
void
|
||
write_register (regno, val)
|
||
int regno, val;
|
||
{
|
||
/* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */
|
||
*(int *) ®isters[REGISTER_BYTE (regno)] = val;
|
||
|
||
if (have_inferior_p ())
|
||
store_inferior_registers (regno);
|
||
}
|
||
|
||
|
||
int
|
||
have_inferior_p ()
|
||
{
|
||
return inferior_pid != 0;
|
||
}
|
||
|
||
print_some_registers(regs)
|
||
int regs[];
|
||
{
|
||
register int i;
|
||
for (i = 0; i < 18; i++) {
|
||
printf("reg[%d] = %x\n", i, regs[i]);
|
||
}
|
||
}
|
||
|
||
SHAR_EOF
|
||
cat << \SHAR_EOF > remote_server.c
|
||
/* Main code for remote server for GDB, the GNU Debugger.
|
||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||
|
||
This file is part of GDB.
|
||
|
||
GDB 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 1, or (at your option)
|
||
any later version.
|
||
|
||
GDB 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 GDB; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
#include "param.h"
|
||
#include <stdio.h>
|
||
|
||
void read_inferior_memory(), fetch_inferior_registers();
|
||
unsigned char resume();
|
||
void kill_inferior();
|
||
void initialize(), try_writing_regs_command();
|
||
int create_inferior(), read_register();
|
||
|
||
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();
|
||
|
||
|
||
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;
|
||
|
||
initialize();
|
||
printf("\nwill open serial link\n");
|
||
remote_open("/dev/ttya",0);
|
||
|
||
if(argc < 2)
|
||
{
|
||
printf("Enter name of program to be run with command line args\n");
|
||
gets(own_buf);
|
||
inferior_pid = create_inferior(own_buf,environ);
|
||
printf("\nProcess %s created; pid = %d\n",own_buf,inferior_pid);
|
||
}
|
||
else
|
||
{
|
||
inferior_pid = create_inferior(argv[1],environ);
|
||
printf("\nProcess %s created; pid = %d\n",argv[1],inferior_pid);
|
||
}
|
||
|
||
do {
|
||
getpkt(own_buf);
|
||
printf("\nPacket received is>:%s\n",own_buf);
|
||
i = 0;
|
||
ch = own_buf[i++];
|
||
switch (ch) {
|
||
case 'h': /**********This is only for tweaking the gdb+ program *******/
|
||
signal = resume(1,0,&status);
|
||
prepare_resume_reply(own_buf,status,signal);
|
||
break;
|
||
/*************end tweak*************************************/
|
||
|
||
case 'g': fetch_inferior_registers();
|
||
convert_int_to_ascii(registers,own_buf,REGISTER_BYTES);
|
||
break;
|
||
case 'G': convert_ascii_to_int(&own_buf[1],registers,REGISTER_BYTES);
|
||
if(store_inferior_registers(-1)==0)
|
||
write_ok(own_buf);
|
||
else
|
||
write_enn(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': signal = resume(0,0,&status);
|
||
printf("\nSignal received is >: %0x \n",signal);
|
||
prepare_resume_reply(own_buf,status,signal);
|
||
break;
|
||
case 's': signal = resume(1,0,&status);
|
||
prepare_resume_reply(own_buf,status,signal);
|
||
break;
|
||
case 'k': kill_inferior();
|
||
sprintf(own_buf,"q");
|
||
putpkt(own_buf);
|
||
printf("\nObtained kill request...terminating\n");
|
||
close(remote_desc);
|
||
exit(0);
|
||
case 't': try_writing_regs_command();
|
||
own_buf[0] = '\0';
|
||
break;
|
||
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**/
|
||
printf("\nFinished reading data from serial link - Bye!\n");
|
||
exit(0);
|
||
|
||
}
|
||
|
||
SHAR_EOF
|
||
cat << \SHAR_EOF > remote_utils.c
|
||
/* Remote utility routines for the remote server for GDB, the GNU debugger.
|
||
Copyright (C) 1986, 1989 Free Software Foundation, Inc.
|
||
|
||
This file is part of GDB.
|
||
|
||
GDB 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 1, or (at your option)
|
||
any later version.
|
||
|
||
GDB 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 GDB; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||
|
||
#include "param.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)
|
||
printf("\ncould not open remote device\n");
|
||
|
||
ioctl (remote_desc, TIOCGETP, &sg);
|
||
sg.sg_flags = RAW;
|
||
ioctl (remote_desc, TIOCSETP, &sg);
|
||
|
||
if (from_tty)
|
||
printf ("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
|
||
perror ("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')
|
||
perror ("Remote failure reply: %s", buf);
|
||
}
|
||
|
||
/* 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[500];
|
||
char buf3[1];
|
||
int cnt = strlen (buf);
|
||
char *p;
|
||
|
||
if (kiodebug)
|
||
fprintf (stderr, "Sending packet: %s\n", buf);
|
||
|
||
/* 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;
|
||
|
||
printf ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
|
||
(c1 << 4) + c2, csum, buf);
|
||
write (remote_desc, "-", 1);
|
||
}
|
||
|
||
write (remote_desc, "+", 1);
|
||
|
||
if (kiodebug)
|
||
fprintf (stderr,"Packet received :%s\n", buf);
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
void
|
||
prepare_resume_reply(buf,status,signal)
|
||
char *buf ,status;
|
||
unsigned char signal;
|
||
{
|
||
int nib;
|
||
char ch;
|
||
|
||
*buf++ = 'S';
|
||
*buf++ = status;
|
||
nib = ((signal & 0xf0) >> 4) ;
|
||
*buf++ = tohex(nib);
|
||
nib = signal & 0x0f;
|
||
*buf++ = tohex(nib);
|
||
*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;
|
||
/************debugging begin************/
|
||
printf("\nIn decode_m_packet");
|
||
/************debugging end************/
|
||
|
||
while((ch = from[i++]) != ',')
|
||
{
|
||
*mem_addr_ptr = *mem_addr_ptr << 4;
|
||
*mem_addr_ptr |= fromhex(ch) & 0x0f;
|
||
}
|
||
/************debugging begin************/
|
||
printf("\nFinished mem_addr part");
|
||
/************debugging end************/
|
||
|
||
for(j=0; j < 4; j++)
|
||
{
|
||
if((ch = from[i++]) == 0)
|
||
break;
|
||
*len_ptr = *len_ptr << 4;
|
||
*len_ptr |= fromhex(ch) & 0x0f;
|
||
}
|
||
/************debugging begin************/
|
||
printf("\nFinished len_ptr part");
|
||
/************debugging end************/
|
||
}
|
||
|
||
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;
|
||
/************debugging begin************/
|
||
printf("\nIn decode_M_packet");
|
||
/************debugging end************/
|
||
|
||
while((ch = from[i++]) != ',')
|
||
{
|
||
*mem_addr_ptr = *mem_addr_ptr << 4;
|
||
*mem_addr_ptr |= fromhex(ch) & 0x0f;
|
||
}
|
||
/************debugging begin************/
|
||
printf("\nFinished mem_addr part: memaddr = %x",*mem_addr_ptr);
|
||
/************debugging end************/
|
||
|
||
while((ch = from[i++]) != ':')
|
||
{
|
||
*len_ptr = *len_ptr << 4;
|
||
*len_ptr |= fromhex(ch) & 0x0f;
|
||
}
|
||
/************debugging begin************/
|
||
printf("\nFinished len_ptr part: len = %d",*len_ptr);
|
||
/************debugging end************/
|
||
|
||
convert_ascii_to_int(&from[i++],to,*len_ptr);
|
||
|
||
/************debugging begin************/
|
||
printf("\nmembuf : %x",*(int *)to);
|
||
/************debugging end************/
|
||
}
|
||
|
||
SHAR_EOF
|
||
# End of shell archive
|
||
exit 0
|