GDB for Xenix 386 with GCC (part 4 of 4)

Steve.Bleazard at RoboBar.Co.UK Steve.Bleazard at RoboBar.Co.UK
Tue May 8 21:55:39 AEST 1990


This is part four of a coordinated set of 4 patches for Xenix GCC, GAS and GDB.
Please collect all parts before you start hacking :-)

This is part 4 which patches GDB, say |patch -p -d /usr/local/src/dist-gdb
or whatever AFTER APPLYING part 3.

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	gdb-x386.02
# This archive created: Tue May  8 09:56:53 1990
export PATH; PATH=/bin:$PATH
echo shar: extracting "'gdb-x386.02'" '(48390 characters)'
if test -f 'gdb-x386.02'
then
	echo shar: will not over-write existing file "'gdb-x386.02'"
else
sed 's/^X//' << \SHAR_EOF > 'gdb-x386.02'
X*** dist-gdb.old/x386dbx.c	Thu Jan  1 00:00:00 1970
X--- x386dbx.c	Sat May  5 14:59:45 1990
X***************
X*** 0 ****
X--- 1,478 ----
X+ #include <stdio.h>
X+ #include <a.out.h>
X+ #include <fcntl.h>
X+ #include <sys/types.h>
X+ #include <sys/relsym.h>
X+ #include <sys/param.h>
X+ #include <sys/file.h>
X+ #include "defs.h"
X+ #include "param.h"
X+ #include "symtab.h"
X+ #include "gas-nlist.h"
X+ 
X+ 
X+ /* XENIX symbol segment shape definitions */
X+ 
X+ struct section2 {			/* File info table shape */
X+ 	short		segment;	/* segment number */
X+ 	CORE_ADDR	address;	/* start address for this file */
X+ 	unsigned short	textsize;	/* size of the text for this file */
X+ 	long		type3off;	/* offset to type3 records, psym tab */
X+ 	long		type4off;	/* offset to type4 records, nlist tab */
X+ 	long		type5off;	/* offset to type5 records, str tab */
X+ 	long		type6off;	/* offset to type6 records */
X+ 	unsigned short	type3sz;	/* size of type3 records */
X+ 	unsigned short	type4sz;	/* size of type4 records */
X+ 	unsigned short	type5sz;	/* size of type5 records */
X+ 	unsigned short	type6sz;	/* size of type6 records */
X+ 	char		filelen;	/* length of filename */
X+ };
X+ 
X+ /* psymtable (attribute 3) symbol segment shape */
X+ 
X+ struct psymbol_seg {
X+ 	long		address;	/* core address */
X+ 	short		segid;		/* segment number */
X+ 	short		typeid;		/* variable's type */
X+ 	char		varlen;		/* variable's length */
X+ /*	char		name[0];	trailing name varlen long */
X+ } record3;
X+ 
X+ /*  Info maintenance structures */
X+ 
X+ struct fileinfo {		/* per file info */
X+ 	CORE_ADDR	address;	/* start address for this file */
X+ 	unsigned short	textsize;	/* size of text for this file */
X+ 	long		psymoff;	/* psyms table */
X+ 	long		strtaboff;	/* string table aka $$TYPES */
X+ 	long		ntaboff;	/* nlist table aka $$SYMBOLS */
X+ 	unsigned short	psymsz;		/* size of psyms table */
X+ 	unsigned short	strtabsz;	/* size of string table */
X+ 	unsigned short	ntabsz;		/* size of nlist table */
X+ 	int		mscdebuginfo;	/* compiled with cc -g not gcc -g */
X+ 	char		*filename;	/* name of this file */
X+ 	struct fileinfo *next;
X+ };
X+ 
X+ static struct fileinfo *fi_table = 0;
X+ struct xseg *seg_table;
X+ long num_seg_table_entries;
X+ 
X+ #ifdef __GNUC__
X+ #define alloca __builtin_alloca
X+ #endif
X+ 
X+ #define IGNORE_ATTR (-1)
X+ 
X+ static read_fileinfo_table(fp, segsize, name)
X+ FILE *fp;
X+ int segsize;
X+ char *name;
X+ {
X+   extern char *strrchr(), *xmalloc();
X+   char *fi_name;
X+   char *filename;
X+   struct section2 fi_entry;
X+   struct fileinfo *fi;
X+ 
X+   fi_table = fi = (struct fileinfo *)xmalloc(sizeof(struct fileinfo));
X+   while (segsize > 0)
X+   {
X+     if ((fread((char *)&fi_entry.segment, sizeof(short), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.address, sizeof(CORE_ADDR), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.textsize, sizeof(unsigned short),1,fp) != 1)
X+       || (fread((char *)&fi_entry.type3off, sizeof(long), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.type4off, sizeof(long), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.type5off, sizeof(long), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.type6off, sizeof(long), 1, fp) != 1)
X+       || (fread((char *)&fi_entry.type3sz, sizeof(unsigned short),1,fp) != 1)
X+       || (fread((char *)&fi_entry.type4sz, sizeof(unsigned short),1,fp) != 1)
X+       || (fread((char *)&fi_entry.type5sz, sizeof(unsigned short),1,fp) != 1)
X+       || (fread((char *)&fi_entry.type6sz, sizeof(unsigned short),1,fp) != 1)
X+       || (fread((char *)&fi_entry.filelen, sizeof(char), 1, fp) != 1))
X+       perror_with_name(name);
X+ 
X+     segsize -= sizeof(short) + sizeof(CORE_ADDR) + 5 * sizeof(unsigned short)
X+ 	       + 4 * sizeof(long) + sizeof(char);
X+ 
X+     fi_name = alloca(fi_entry.filelen + 1);
X+     if (fread(fi_name, fi_entry.filelen, 1, fp) != 1)
X+       perror_with_name(name);
X+     fi_name[fi_entry.filelen] = '\0';
X+     segsize -= fi_entry.filelen;
X+ 
X+     if ((filename = strrchr(fi_name, '/')) != (char *)0)
X+       fi_name = filename + 1;
X+ 
X+     if ((filename = strrchr(fi_name, '(')) != (char *)0)
X+       fi_name = filename + 1;
X+ 
X+     if ((filename = strrchr(fi_name, ')')) != (char *)0)
X+         *filename = '\0';
X+    
X+     {
X+       int len = strlen(fi_name);
X+ 
X+       if (len > 2 && fi_name[len - 1] == 'o' && fi_name[len - 2] == '.')
X+       fi_name[len - 1] = 'c';
X+     }
X+ 
X+     fi_name = savestring(fi_name, strlen(fi_name) + 1);
X+ 
X+     fi->next = (struct fileinfo *)xmalloc(sizeof(struct fileinfo));
X+     fi = fi->next;
X+ 
X+     fi->address = fi_entry.address;
X+     fi->textsize = fi_entry.textsize;
X+     fi->psymoff = fi_entry.type3off;
X+     fi->psymsz = fi_entry.type3sz;
X+     fi->strtaboff = fi_entry.type4off;
X+     fi->strtabsz = fi_entry.type4sz;
X+     fi->ntaboff = fi_entry.type5off;
X+     fi->ntabsz = fi_entry.type5sz;
X+     fi->mscdebuginfo = (fi_entry.type6sz != 0);
X+     fi->filename = fi_name;
X+   }
X+   fi->next = 0;  fi = fi_table;  fi_table = fi_table->next;  free(fi);
X+ 
X+ #ifdef X_DEBUG
X+     printf("\naddress   textsz  symoff   symsz  stroff   strsz  taboff   tabsz  name\n\n");
X+   for (fi = fi_table; fi != 0; fi = fi->next)
X+   {
X+     printf("% 8x  % 6d  % 6d  % 6d  % 6d  % 6d  % 6d  %6d  %s\n", fi->address, fi->textsize, fi->psymoff, fi->psymsz, fi->strtaboff, fi->strtabsz, fi->ntaboff, fi->ntabsz, fi->filename);
X+   }
X+   printf("\n");
X+ #endif /* X_DEBUG */
X+ }
X+ 
X+ static read_seg_table(fp, pos, size, name)
X+ FILE *fp;
X+ long pos, size;
X+ {
X+   seg_table = (struct xseg *) xmalloc(size);
X+   fseek(fp, pos, 0);
X+   if (fread((char *)seg_table, size, 1, fp) != 1)
X+     perror_with_name(name);
X+   num_seg_table_entries = size / sizeof (struct xseg);
X+ }
X+ 
X+ 
X+ struct xseg *find_segment(type, attr)
X+ int type, attr;
X+ {
X+   struct xseg *cseg;
X+ 
X+   for (cseg = seg_table; cseg < seg_table + num_seg_table_entries; ++cseg)
X+   if (cseg->xs_type == type &&
X+     (attr == IGNORE_ATTR || attr == cseg->xs_attr))
X+     return cseg;
X+   return NULL;
X+ }
X+ 
X+ static int compare_misc_functions (fn1, fn2)
X+ struct misc_function *fn1, *fn2;
X+ {
X+   /* Return a signed result based on unsigned comparisons
X+      so that we sort into unsigned numeric order.  */
X+ 
X+   if (fn1->address < fn2->address)
X+     return -1;
X+   if (fn1->address > fn2->address)
X+     return 1;
X+   return 0;
X+ }
X+ 
X+ static int read_misc_functions(fp, segsize, name)
X+ FILE *fp;
X+ int segsize;
X+ char *name;
X+ {
X+   char *symdata, *p, *str_buff;
X+   long sym_count = 0, str_count = 0, i;
X+   struct misc_function *miscp;
X+   struct sym symb;
X+ 
X+   /* grab the symbol table */
X+ 
X+   symdata = alloca(segsize + 1);
X+   if (fread(symdata, segsize, 1, fp) != 1)
X+       perror_with_name(name);
X+ 
X+   /* first pass, work out how many symbols there are and the size of the
X+    * strings
X+    */
X+ 
X+   p = symdata;
X+   while (p < symdata + segsize)
X+   {
X+ 	int len;
X+ 
X+ 	p += sizeof(struct sym);
X+ 	len = strlen(p) + 1;
X+ 	str_count += len;  p += len;  sym_count++;
X+   }
X+ 
X+   /* Now build the misc function vector */
X+ 
X+   str_buff = xmalloc(str_count+1);
X+   misc_function_vector =
X+     (struct misc_function *) xmalloc (sym_count * sizeof(struct misc_function));
X+   misc_function_count = sym_count;
X+ 
X+   p = symdata;  miscp = misc_function_vector;
X+   while (p < symdata + segsize)
X+   {
X+ 	int len;
X+ 
X+ 	symb = *((struct sym *)p);
X+ 	p += sizeof(struct sym);
X+ 
X+ 	if (*p == '_')
X+ 	  strcpy(str_buff, p+1);
X+ 	else
X+ 	  strcpy(str_buff, p);
X+ 
X+ 	/* the following will result in a garbage byte every time a symbol
X+ 	 * starts with a _, I can'y be bothered to fix it.
X+ 	 */
X+ 
X+ 	miscp->name = str_buff;
X+ 	len = strlen(p) + 1;
X+ 	str_buff += len;  p += len;
X+ 	miscp->address = symb.s_value;
X+ 	switch(symb.s_type & S_TYPE)
X+ 	{
X+ 	case S_UNDEF:  miscp->type = mf_unknown;  break;
X+ 	case S_ABS:    miscp->type = mf_abs;  break;
X+ 	case S_TEXT:   miscp->type = mf_text;  break;
X+ 	case S_DATA:   miscp->type = mf_data;  break;
X+ 	case S_BSS:    miscp->type = mf_bss;  break;
X+ 	case S_COMM:   miscp->type = mf_data;  break;
X+ 	case S_REG:    miscp->type = mf_unknown;  break;
X+ 	case S_COMB:   miscp->type = mf_unknown;  break;
X+ 	case S_SEG:    miscp->type = mf_unknown;  break;
X+ 	case S_FN:     miscp->type = mf_unknown;  break;
X+ 	dewfault:      miscp->type = mf_unknown;  break;
X+ 	}
X+ 	miscp++;
X+   }
X+ 
X+   qsort (misc_function_vector, misc_function_count,
X+     sizeof (struct misc_function), compare_misc_functions);
X+ 
X+ #ifdef X_DEBUG
X+   {
X+     struct misc_function *miscp;
X+     int i;
X+ 
X+     printf("type      address  name\n\n");
X+     for (i = 0; i < misc_function_count; i++)
X+     {
X+       miscp = &misc_function_vector[i];
X+       switch (miscp->type)
X+       {
X+       case mf_unknown: printf("%-9s","unknown");  break;
X+       case mf_text:    printf("%-9s","text");  break;
X+       case mf_data:    printf("%-9s","data");  break;
X+       case mf_bss:     printf("%-9s","bss");  break;
X+       case mf_abs:     printf("%-9s","abs");  break;
X+       default:         printf("%-9s","UNKNOWN");  break;
X+       }
X+       printf("% 8x  ", miscp->address);
X+       printf("%s\n", miscp->name);
X+     }
X+   }
X+ #endif /* X_DEBUG */
X+   return misc_function_count;
X+ }
X+ 
X+ process_a_out(desc, name)
X+ int desc;
X+ char *name;
X+ {
X+   struct xexec exec_aouthdr;
X+   struct xext *xext;
X+   struct xseg *cseg;
X+   FILE *fp;
X+ 
X+   lseek(desc, 0L, 0);
X+   if ((fp = fdopen(dup(desc), "r")) == NULL)
X+ 		perror_with_name(name);
X+ 
X+   if (fread((char *)&exec_aouthdr, sizeof(struct xexec), 1, fp) != 1)
X+     perror_with_name(name);
X+   
X+   xext = (struct xext *) alloca(exec_aouthdr.x_ext);
X+   if (fread((char *)xext, exec_aouthdr.x_ext, 1, fp) != 1)
X+     perror_with_name(name);
X+   
X+   read_seg_table(fp, xext->xe_segpos, xext->xe_segsize, name);
X+ 
X+   if (cseg = find_segment(XS_TSYMS, 2))
X+   {
X+     fseek(fp, cseg->xs_filpos, 0);
X+     read_fileinfo_table(fp, cseg->xs_psize, name);
X+   }
X+ 
X+   fclose(fp);
X+ }
X+ 
X+ process_global_symbol_table(desc, name)
X+ int desc;
X+ char *name;
X+ {
X+   struct xseg *cseg;
X+   FILE *fp;
X+ 
X+   if ((fp = fdopen(dup(desc), "r")) == NULL)
X+ 		perror_with_name(name);
X+ 
X+   if (cseg = find_segment(XS_TSYMS, 1))
X+   {
X+     fseek(fp, cseg->xs_filpos, 0);
X+     read_misc_functions(fp, cseg->xs_psize, name);
X+   }
X+   fclose(fp);
X+ }
X+ 
X+ static struct fileinfo *current_fi;
X+ static int first_get_fileinfo_call = 1;
X+ 
X+ init_fileinfo_processing()  /* start processing the list of files */
X+ {
X+   first_get_fileinfo_call = 1;
X+ }
X+ 
X+ long get_next_fileinfo(stroff, nsyms, address, symtaboff)
X+ long *stroff, *nsyms, *address, *symtaboff;
X+ {
X+   struct xseg *cseg;
X+ 
X+   if (first_get_fileinfo_call)
X+   {
X+     current_fi = fi_table;
X+     first_get_fileinfo_call = 0;
X+   }
X+   else
X+     current_fi = current_fi->next;
X+   
X+   if (current_fi == 0)
X+     return 0;
X+ 
X+   if (current_fi->mscdebuginfo)
X+   {
X+     *stroff = 0;
X+     *nsyms = 0;
X+     *address = current_fi->address;
X+   }
X+   else if (cseg = find_segment(XS_TSYMS, 5))
X+   {
X+     *symtaboff = cseg->xs_filpos + current_fi->ntaboff;
X+     *stroff = current_fi->strtaboff;
X+     *nsyms = current_fi->ntabsz / sizeof(struct gas_nlist);
X+     *address = current_fi->address;
X+     return 1;
X+   }
X+   else
X+   {
X+     *symtaboff = 0;
X+     *stroff = 0;
X+     *nsyms = 0;
X+     *address = 0;
X+   }
X+ }
X+ 
X+ #ifdef TEST
X+ 
X+ main()
X+ {
X+ 	char *stab;
X+ 	long str_offset, nsyms, address, ntaboff;
X+  	int desc;
X+ 	struct xseg *cseg;
X+ 
X+ 	process_a_out((desc = open("a.out", O_RDONLY, 0)), "a.out");
X+ 
X+ 	printf("\n");
X+ 
X+      	  if (cseg = find_segment(XS_TSYMS, 4))
X+      	  {
X+ 	    lseek(desc, cseg->xs_filpos, 0);
X+ 	    stab = alloca(cseg->xs_psize);
X+ 	    read(desc, stab, cseg->xs_psize);
X+ 	  }
X+ 	  else
X+ 	    stab = 0;
X+ 
X+           init_fileinfo_processing();
X+ 	  while (get_next_fileinfo(&str_offset,&nsyms,&address,&ntaboff))
X+ 	  {
X+ 	    lseek(desc, ntaboff, 0);
X+ 	    printf("\n  type    desc     value  stroff  string (%#x)\n", address);
X+ 	    while (nsyms--)
X+ 	    {
X+ 	      struct gas_nlist nl;
X+ 
X+ 	      read(desc, &nl, sizeof(nl));
X+ 	      printf("% 6x  % 6x  % 8x  % 6x %s\n",
X+ 		     (unsigned char)nl.n_type,
X+ 		     (unsigned short)nl.n_desc,
X+ 		     (unsigned int)nl.n_value,
X+ 		     nl.n_un.n_strx ? stab + str_offset + nl.n_un.n_strx : "");
X+ 	    }
X+ 	    lseek(desc, 0L, 0);
X+ 	  }
X+ }
X+ 
X+ perror_with_name (string)
X+      char *string;
X+ {
X+   extern int sys_nerr;
X+   extern char *sys_errlist[];
X+   extern int errno;
X+   char *err;
X+   char *combined;
X+ 
X+   if (errno < sys_nerr)
X+     err = sys_errlist[errno];
X+   else
X+     err = "unknown error";
X+ 
X+   combined = (char *) alloca (strlen (err) + strlen (string) + 3);
X+   strcpy (combined, string);
X+   strcat (combined, ": ");
X+   strcat (combined, err);
X+ 
X+   error ("%s.", combined);
X+ }
X+ 
X+ error (string, arg1, arg2, arg3)
X+      char *string;
X+      int arg1, arg2, arg3;
X+ {
X+   fflush (stdout);
X+   fprintf (stderr, string, arg1, arg2, arg3);
X+   fprintf (stderr, "\n");
X+   exit(1);
X+ }
X+ 
X+ char * xmalloc (size)
X+      long size;
X+ {
X+   register char *val = (char *) malloc (size);
X+   if (!val)
X+     error ("virtual memory exhausted.");
X+   return val;
X+ }
X+ 
X+ char *savestring (ptr, size)
X+      char *ptr;
X+      int size;
X+ {
X+   register char *p = (char *) xmalloc (size + 1);
X+   memcpy(p, ptr, size);
X+   p[size] = 0;
X+   return p;
X+ }
X+ 
X+ #endif /* TEST */
X*** dist-gdb.old/xenix386-dep.c	Thu Jan  1 00:00:00 1970
X--- xenix386-dep.c	Mon May  7 15:02:10 1990
X***************
X*** 0 ****
X--- 1,1275 ----
X+ /* Low level interface to ptrace, for GDB when running on the Intel 386.
X+    Copyright (C) 1988, 1989 Free Software Foundation, Inc.
X+ 
X+ This file is part of GDB.
X+ 
X+ GDB is free software; you can redistribute it and/or modify
X+ it under the terms of the GNU General Public License as published by
X+ the Free Software Foundation; either version 1, or (at your option)
X+ any later version.
X+ 
X+ GDB is distributed in the hope that it will be useful,
X+ but WITHOUT ANY WARRANTY; without even the implied warranty of
X+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
X+ GNU General Public License for more details.
X+ 
X+ You should have received a copy of the GNU General Public License
X+ along with GDB; see the file COPYING.  If not, write to
X+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
X+ 
X+ #include <stdio.h>
X+ #include "defs.h"
X+ #include "param.h"
X+ #include "frame.h"
X+ #include "inferior.h"
X+ 
X+ #ifdef USG
X+ #include <sys/types.h>
X+ #endif
X+ 
X+ #include <stdio.h>
X+ #include <sys/param.h>
X+ #include <sys/dir.h>
X+ #include <signal.h>
X+ #ifdef M_XENIX
X+ #include <sys/page.h>
X+ #include <sys/seg.h>
X+ #endif
X+ #include <sys/user.h>
X+ #include <sys/ioctl.h>
X+ #include <fcntl.h>
X+ 
X+ #ifdef COFF_ENCAPSULATE
X+ #include "a.out.encap.h"
X+ #else
X+ #ifndef M_XENIX			/* brain-dead xenix strikes again */
X+ #include <a.out.h>
X+ #endif
X+ #endif
X+ 
X+ #ifndef N_SET_MAGIC
X+ #ifdef COFF_FORMAT
X+ #define N_SET_MAGIC(exec, val) ((exec).magic = (val))
X+ #else
X+ #define N_SET_MAGIC(aexec, val) ((aexec).xa_magic = (val))
X+ #endif
X+ #endif
X+ 
X+ #include <sys/file.h>
X+ #include <sys/stat.h>
X+ #include <sys/proc.h>
X+ 
X+ #include <sys/reg.h>
X+ 
X+ unsigned short text_segid;	/* segment number of text segment */
X+ unsigned short data_segid;	/* segment number of data segment */
X+ extern CORE_ADDR text_end; \
X+ 
X+ #ifdef X_DEBUG
X+ Ptrace(l, a, b, c, d)
X+ int l;
X+ int a, b, c, d;
X+ {
X+ 	printf("at line %d, req = %d, pid = %d, addr = %#x, data = %d\n",
X+ 	       l, a, b, c, d);
X+         return ptrace (a, b, c, d);
X+ }
X+ 
X+ #define ptrace(a,b,c,d) Ptrace(__LINE__, a, b, c, d)
X+ #endif /* X_DEBUG */
X+ 
X+ typedef struct saddr PTRACE;
X+ static PTRACE tmptrace;
X+ extern int errno;
X+ 
X+ /* This function simply calls ptrace with the given arguments.  
X+    It exists so that all calls to ptrace are isolated in this 
X+    machine-dependent file. */
X+ int
X+ call_ptrace (request, pid, arg3, arg4)
X+      int request, pid, arg3, arg4;
X+ {
X+   return ptrace (request, pid, arg3, arg4);
X+ }
X+ 
X+ kill_inferior ()
X+ {
X+   if (remote_debugging)
X+     return;
X+   if (inferior_pid == 0)
X+     return;
X+   ptrace (8, inferior_pid, 0, 0);
X+   wait (0);
X+   inferior_died ();
X+ }
X+ 
X+ /* This is used when GDB is exiting.  It gives less chance of error.*/
X+ 
X+ kill_inferior_fast ()
X+ {
X+   if (remote_debugging)
X+     return;
X+   if (inferior_pid == 0)
X+     return;
X+   ptrace (8, inferior_pid, 0, 0);
X+   wait (0);
X+ }
X+ 
X+ /* Resume execution of the inferior process.
X+    If STEP is nonzero, single-step it.
X+    If SIGNAL is nonzero, give it that signal.  */
X+ 
X+ void
X+ resume (step, signal)
X+      int step;
X+      int signal;
X+ {
X+   PTRACE addr;
X+   addr.sa_seg = 0;
X+   addr.sa_off = 1;
X+   errno = 0;
X+   if (remote_debugging)
X+     remote_resume (step, signal);
X+   else
X+     {
X+       /* ptrace (step ? 9 : 7, inferior_pid, &addr, signal); */
X+       ptrace (step ? 9 : 7, inferior_pid, 1, signal);
X+       if (errno)
X+ 	perror_with_name ("ptrace");
X+     }
X+ }
X+ 
X+ void
X+ fetch_inferior_registers ()
X+ {
X+   register int regno;
X+   register unsigned int regaddr;
X+   char buf[MAX_REGISTER_RAW_SIZE];
X+   register int i;
X+ 
X+   struct user u;
X+   unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
X+   offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
X+ 
X+   for (regno = 0; regno < NUM_REGS; regno++)
X+     {
X+       regaddr = register_addr (regno, offset);
X+       for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
X+  	{
X+  	  *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0);
X+  	  regaddr += sizeof (int);
X+  	}
X+       supply_register (regno, buf);
X+     }
X+ }
X+ 
X+ /* Store our register values back into the inferior.
X+    If REGNO is -1, do this for all registers.
X+    Otherwise, REGNO specifies which register (so we can save time).  */
X+ 
X+ store_inferior_registers (regno)
X+      int regno;
X+ {
X+   register unsigned int regaddr;
X+   char buf[80];
X+ 
X+   struct user u;
X+   unsigned int offset = (char *) &u.u_ar0 - (char *) &u;
X+   offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR;
X+ 
X+   if (regno >= 0)
X+     {
X+       regaddr = register_addr (regno, offset);
X+       errno = 0;
X+       ptrace (6, inferior_pid, regaddr, read_register (regno));
X+       if (errno != 0)
X+ 	{
X+ 	  sprintf (buf, "writing register number %d", regno);
X+ 	  perror_with_name (buf);
X+ 	}
X+     }
X+   else for (regno = 0; regno < NUM_REGS; regno++)
X+     {
X+       regaddr = register_addr (regno, offset);
X+       errno = 0;
X+       ptrace (6, inferior_pid, regaddr, read_register (regno));
X+       if (errno != 0)
X+ 	{
X+ 	  sprintf (buf, "writing register number %d", regno);
X+ 	  perror_with_name (buf);
X+ 	}
X+     }
X+ }
X+ 
X+ /* Copy LEN bytes from inferior's memory starting at MEMADDR
X+    to debugger memory starting at MYADDR. 
X+    On failure (cannot read from inferior, usually because address is out
X+    of bounds) returns the value of errno. */
X+ 
X+ int
X+ read_inferior_memory (memaddr, myaddr, len)
X+      CORE_ADDR memaddr;
X+      char *myaddr;
X+      int len;
X+ {
X+   register int i;
X+   /* Round starting address down to longword boundary.  */
X+   register CORE_ADDR addr = memaddr & - sizeof (int);
X+   /* Round ending address up; get number of longwords that makes.  */
X+   register int count
X+     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
X+   /* Allocate buffer of that many longwords.  */
X+   register int *buffer = (int *) alloca (count * sizeof (int));
X+   extern int errno;
X+ 
X+   /* Read all the longwords */
X+   for (i = 0; i < count; i++, addr += sizeof (int))
X+     {
X+       errno = 0;
X+       if (remote_debugging)
X+ 	buffer[i] = remote_fetch_word (addr);
X+       else
X+ 	buffer[i] = ptrace (addr <= text_end ? 1 : 2, inferior_pid,
X+ 		addr, 0);
X+       if (errno)
X+ 	return errno;
X+     }
X+ 
X+   /* Copy appropriate bytes out of the buffer.  */
X+   bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
X+   return 0;
X+ }
X+ 
X+ /* Copy LEN bytes of data from debugger memory at MYADDR
X+    to inferior's memory at MEMADDR.
X+    On failure (cannot write the inferior)
X+    returns the value of errno.  */
X+ 
X+ int
X+ write_inferior_memory (memaddr, myaddr, len)
X+      CORE_ADDR memaddr;
X+      char *myaddr;
X+      int len;
X+ {
X+   register int i;
X+   /* Round starting address down to longword boundary.  */
X+   register CORE_ADDR addr = memaddr & - sizeof (int);
X+   /* Round ending address up; get number of longwords that makes.  */
X+   register int count
X+     = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
X+   /* Allocate buffer of that many longwords.  */
X+   register int *buffer = (int *) alloca (count * sizeof (int));
X+   extern int errno;
X+ 
X+   /* Fill start and end extra bytes of buffer with existing memory data.  */
X+ 
X+   if (remote_debugging)
X+     buffer[0] = remote_fetch_word (addr);
X+   else
X+     buffer[0] = ptrace (addr <= text_end ? 1 : 2, inferior_pid, addr, 0);
X+ 
X+   if (count > 1)
X+     {
X+       if (remote_debugging)
X+ 	buffer[count - 1]
X+ 	  = remote_fetch_word (addr + (count - 1) * sizeof (int));
X+       else
X+ 	buffer[count - 1]
X+ 	  = ptrace (addr <= text_end ? 1 : 2, inferior_pid,
X+                    (addr + (count - 1) * sizeof(int)) , 0);
X+     }
X+ 
X+   /* Copy data to be written over corresponding part of buffer */
X+ 
X+   bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
X+ 
X+   /* Write the entire buffer.  */
X+ 
X+   for (i = 0; i < count; i++, addr += sizeof (int))
X+     {
X+       errno = 0;
X+       if (remote_debugging)
X+ 	remote_store_word (addr, buffer[i]);
X+       else
X+ 	ptrace (addr <= text_end ? 4 : 5, inferior_pid, addr, buffer[i]);
X+       if (errno)
X+ 	return errno;
X+     }
X+ 
X+   return 0;
X+ }
X+ 
X+ /* Work with core dump and executable files, for GDB. 
X+    This code would be in core.c if it weren't machine-dependent. */
X+ 
X+ #ifndef N_TXTADDR
X+ #define N_TXTADDR(hdr) 0
X+ #endif /* no N_TXTADDR */
X+ 
X+ #ifndef N_DATADDR
X+ #define N_DATADDR(hdr) hdr.xa_text
X+ #endif /* no N_DATADDR */
X+ 
X+ /* Make COFF and non-COFF names for things a little more compatible
X+    to reduce conditionals later.  */
X+ 
X+ #define AOUTHDR struct xexec
X+ 
X+ extern char *sys_siglist[];
X+ 
X+ 
X+ /* Hook for `exec_file_command' command to call.  */
X+ 
X+ extern void (*exec_file_display_hook) ();
X+    
X+ /* File names of core file and executable file.  */
X+ 
X+ extern char *corefile;
X+ extern char *execfile;
X+ 
X+ /* Descriptors on which core file and executable file are open.
X+    Note that the execchan is closed when an inferior is created
X+    and reopened if the inferior dies or is killed.  */
X+ 
X+ extern int corechan;
X+ extern int execchan;
X+ 
X+ /* Last modification time of executable file.
X+    Also used in source.c to compare against mtime of a source file.  */
X+ 
X+ extern int exec_mtime;
X+ 
X+ /* Virtual addresses of bounds of the two areas of memory in the core file.  */
X+ 
X+ extern CORE_ADDR data_start;
X+ extern CORE_ADDR data_end;
X+ extern CORE_ADDR stack_start;
X+ extern CORE_ADDR stack_end;
X+ 
X+ /* Virtual addresses of bounds of two areas of memory in the exec file.
X+    Note that the data area in the exec file is used only when there is no core file.  */
X+ 
X+ extern CORE_ADDR text_start;
X+ extern CORE_ADDR text_end;
X+ 
X+ extern CORE_ADDR exec_data_start;
X+ extern CORE_ADDR exec_data_end;
X+ 
X+ /* Address in executable file of start of text area data.  */
X+ 
X+ extern int text_offset;
X+ 
X+ /* Address in executable file of start of data area data.  */
X+ 
X+ extern int exec_data_offset;
X+ 
X+ /* Address in core file of start of data area data.  */
X+ 
X+ extern int data_offset;
X+ 
X+ /* Address in core file of start of stack area data.  */
X+ 
X+ extern int stack_offset;
X+ 
X+ #ifdef COFF_FORMAT
X+ /* various coff data structures */
X+ 
X+ extern FILHDR file_hdr;
X+ extern SCNHDR text_hdr;
X+ extern SCNHDR data_hdr;
X+ 
X+ #endif /* not COFF_FORMAT */
X+ 
X+ /* a.out header saved in core file.  */
X+   
X+ extern AOUTHDR core_aouthdr;
X+ 
X+ /* a.out header of exec file.  */
X+ 
X+ extern AOUTHDR exec_aouthdr;
X+ 
X+ extern void validate_files ();
X+ 
X+ core_file_command (filename, from_tty)
X+      char *filename;
X+      int from_tty;
X+ {
X+   int val;
X+ 
X+   /* Discard all vestiges of any previous core file
X+      and mark data and stack spaces as empty.  */
X+ 
X+   if (corefile)
X+     free (corefile);
X+   corefile = 0;
X+ 
X+   if (corechan >= 0)
X+     close (corechan);
X+   corechan = -1;
X+ 
X+   data_start = 0;
X+   data_end = 0;
X+   stack_start = 0;
X+   stack_end = 0;
X+ 
X+   /* Now, if a new core file was specified, open it and digest it.  */
X+ 
X+   if (filename)
X+     {
X+       filename = tilde_expand (filename);
X+       make_cleanup (free, filename);
X+       
X+       if (have_inferior_p ())
X+ 	error ("To look at a core file, you must kill the inferior with \"kill\".");
X+       corechan = open (filename, O_RDONLY, 0);
X+       if (corechan < 0)
X+ 	perror_with_name (filename);
X+       /* xenix style core dump */
X+       {
X+ 	struct user u;
X+ 	long user_area_size;
X+ 	int reg_offset;
X+ 
X+ 
X+ 	val = myread (corechan, &u, sizeof u);
X+ 	if (val < 0)
X+ 	  perror_with_name (filename);
X+ 
X+ 	user_area_size = ((sizeof u + (u.u_ldtlimit-1)*sizeof(struct descriptor)
X+ 			 + NBPC - 1) / NBPC) * NBPC;
X+ 
X+ 	data_start = (CORE_ADDR)u.u_sdata;
X+ 	data_end = (CORE_ADDR)u.u_edatau;
X+ 	stack_start = (CORE_ADDR)u.u_stktop;
X+ 	stack_end = (CORE_ADDR)u.u_stkbotu;
X+ 
X+ 	data_offset = lseek(corechan, 0L, 2) - u.u_dsize;
X+ 	stack_offset = user_area_size;
X+ 	reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR;
X+ #ifdef X_DEBUG
X+ 	printf("data_offset = %#x\n", data_offset);
X+ 	printf("stack_offset  = %#x\n", stack_offset );
X+ 	printf("user_area_size = %#x\n", user_area_size);
X+ 	printf("test data_offset = %#x\n", user_area_size + u.u_ssize);
X+ #endif /* X_DEBUG */
X+ 
X+ 	/* I don't know where to find this info.
X+ 	   So, for now, mark it as not available.  */
X+ /*	N_SET_MAGIC (core_aouthdr, 0);  */
X+ 	bzero ((char *) &core_aouthdr, sizeof core_aouthdr);
X+ 
X+ 	/* Read the register values out of the core file and store
X+ 	   them where `read_register' will find them.  */
X+ 
X+ 	{
X+ 	  register int regno;
X+ 
X+ 	  for (regno = 0; regno < NUM_REGS; regno++)
X+ 	    {
X+ 	      char buf[MAX_REGISTER_RAW_SIZE];
X+ 
X+ 	      val = lseek (corechan, register_addr (regno, reg_offset), 0);
X+ 	      if (val < 0)
X+ 		perror_with_name (filename);
X+ 
X+  	      val = myread (corechan, buf, sizeof buf);
X+ 	      if (val < 0)
X+ 		perror_with_name (filename);
X+ 	      supply_register (regno, buf);
X+ 	    }
X+ 	}
X+       }
X+       if (filename[0] == '/')
X+ 	corefile = savestring (filename, strlen (filename));
X+       else
X+ 	{
X+ 	  corefile = concat (current_directory, "/", filename);
X+ 	}
X+ 
X+       set_current_frame ( create_new_frame (read_register (FP_REGNUM),
X+ 					    read_pc ()));
X+       select_frame (get_current_frame (), 0);
X+       validate_files ();
X+     }
X+   else if (from_tty)
X+     printf ("No core file now.\n");
X+ }
X+ 
X+ exec_file_command (filename, from_tty)
X+      char *filename;
X+      int from_tty;
X+ {
X+   int val;
X+ 
X+   /* Eliminate all traces of old exec file.
X+      Mark text segment as empty.  */
X+ 
X+   if (execfile)
X+     free (execfile);
X+   execfile = 0;
X+   data_start = 0;
X+   data_end -= exec_data_start;
X+   text_start = 0;
X+   text_end = 0;
X+   exec_data_start = 0;
X+   exec_data_end = 0;
X+   if (execchan >= 0)
X+     close (execchan);
X+   execchan = -1;
X+ 
X+   /* Now open and digest the file the user requested, if any.  */
X+ 
X+   if (filename)
X+     {
X+       filename = tilde_expand (filename);
X+       make_cleanup (free, filename);
X+       
X+       execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0,
X+ 			&execfile);
X+       if (execchan < 0)
X+ 	perror_with_name (filename);
X+ 
X+       {
X+ 	char *extended_header;
X+ 	struct xext *xext;
X+ 	struct stat st_exec;
X+ 	struct xseg xseg;
X+ 	extern char *malloc();
X+ 	val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR));
X+ 
X+ 	if (val < 0)
X+ 	  perror_with_name (filename);
X+         if (exec_aouthdr.x_magic != X_MAGIC)
X+ 	  error ("\"%s\": not in executable format.", execfile);
X+ 	if ( (exec_aouthdr.x_cpu & XC_CPU) != XC_386 )
X+ 	  error ("\"%s\": not a 386 executable.", execfile);
X+ 	if ( (exec_aouthdr.x_renv & XE_SEG) == 0)
X+ 	  error ("\"%s\": not a segmented executable.", execfile);
X+ 	if ( (exec_aouthdr.x_renv & XE_EXEC) == 0)
X+ 	  error ("\"%s\": not executable.", execfile);
X+ 	extended_header = malloc(exec_aouthdr.x_ext);
X+ 	val = myread (execchan, extended_header, exec_aouthdr.x_ext);
X+ 	if (val < 0)
X+ 	  perror_with_name (filename);
X+ 	xext = (struct xext *)extended_header;
X+ 	lseek(execchan, xext->xe_segpos, 0);
X+ 	if (myread (execchan, (char *)&xseg, sizeof(xseg)) < 0)
X+ 	  perror_with_name (filename);
X+ 	if ( xseg.xs_type != XS_TTEXT )
X+ 	  error ("\"%s\": Text segment isn't first (huh?).", execfile);
X+ 	text_segid = xseg.xs_seg;
X+ 	text_start = xseg.xs_rbase;
X+ 	text_end = text_start + xseg.xs_vsize;
X+ 	text_offset = xseg.xs_filpos;
X+ 
X+ 	if (myread (execchan, (char *)&xseg, sizeof(xseg)) < 0)
X+ 	  perror_with_name (filename);
X+ 	if ( xseg.xs_type != XS_TDATA )
X+ 	  error ("\"%s\": Data segment isn't second (huh?).", execfile);
X+ 	data_segid = xseg.xs_seg;
X+ 	exec_data_start = xseg.xs_rbase;
X+ 	exec_data_end = exec_data_start + xseg.xs_psize;
X+ 	exec_data_offset = xseg.xs_filpos;
X+ 	data_start = exec_data_start;
X+ 	data_end += exec_data_start;
X+ 	
X+ 	fstat (execchan, &st_exec);
X+ 	exec_mtime = st_exec.st_mtime;
X+ 	free(extended_header);
X+       }
X+ 
X+       validate_files ();
X+     }
X+   else if (from_tty)
X+     printf ("No exec file now.\n");
X+ 
X+   /* Tell display code (if any) about the changed file name.  */
X+   if (exec_file_display_hook)
X+     (*exec_file_display_hook) (filename);
X+ }
X+ 
X+ /* helper functions for m-i386.h */
X+ 
X+ /* stdio style buffering to minimize calls to ptrace */
X+ static CORE_ADDR codestream_next_addr;
X+ static CORE_ADDR codestream_addr;
X+ static unsigned char codestream_buf[sizeof (int)];
X+ static int codestream_off;
X+ static int codestream_cnt;
X+ 
X+ #define codestream_tell() (codestream_addr + codestream_off)
X+ #define codestream_peek() (codestream_cnt == 0 ? \
X+ 			   codestream_fill(1): codestream_buf[codestream_off])
X+ #define codestream_get() (codestream_cnt-- == 0 ? \
X+ 			 codestream_fill(0) : codestream_buf[codestream_off++])
X+ 
X+ static unsigned char 
X+ codestream_fill (peek_flag)
X+ {
X+   codestream_addr = codestream_next_addr;
X+   codestream_next_addr += sizeof (int);
X+   codestream_off = 0;
X+   codestream_cnt = sizeof (int);
X+   read_memory (codestream_addr,
X+ 	       (unsigned char *)codestream_buf,
X+ 	       sizeof (int));
X+   
X+   if (peek_flag)
X+     return (codestream_peek());
X+   else
X+     return (codestream_get());
X+ }
X+ 
X+ static void
X+ codestream_seek (place)
X+ {
X+   codestream_next_addr = place & -sizeof (int);
X+   codestream_cnt = 0;
X+   codestream_fill (1);
X+   while (codestream_tell() != place)
X+     codestream_get ();
X+ }
X+ 
X+ static void
X+ codestream_read (buf, count)
X+      unsigned char *buf;
X+ {
X+   unsigned char *p;
X+   int i;
X+   p = buf;
X+   for (i = 0; i < count; i++)
X+     *p++ = codestream_get ();
X+ }
X+ 
X+ /* next instruction is a jump, move to target */
X+ static
X+ i386_follow_jump ()
X+ {
X+   int long_delta;
X+   short short_delta;
X+   char byte_delta;
X+   int data16;
X+   int pos;
X+   
X+   pos = codestream_tell ();
X+   
X+   data16 = 0;
X+   if (codestream_peek () == 0x66)
X+     {
X+       codestream_get ();
X+       data16 = 1;
X+     }
X+   
X+   switch (codestream_get ())
X+     {
X+     case 0xe9:
X+       /* relative jump: if data16 == 0, disp32, else disp16 */
X+       if (data16)
X+ 	{
X+ 	  codestream_read ((unsigned char *)&short_delta, 2);
X+ 	  pos += short_delta + 3; /* include size of jmp inst */
X+ 	}
X+       else
X+ 	{
X+ 	  codestream_read ((unsigned char *)&long_delta, 4);
X+ 	  pos += long_delta + 5;
X+ 	}
X+       break;
X+     case 0xeb:
X+       /* relative jump, disp8 (ignore data16) */
X+       codestream_read ((unsigned char *)&byte_delta, 1);
X+       pos += byte_delta + 2;
X+       break;
X+     }
X+   codestream_seek (pos + data16);
X+ }
X+ 
X+ /*
X+  * find & return amound a local space allocated, and advance codestream to
X+  * first register push (if any)
X+  *
X+  * if entry sequence doesn't make sense, return -1, and leave 
X+  * codestream pointer random
X+  */
X+ static long
X+ i386_get_frame_setup (pc)
X+ {
X+   unsigned char op;
X+   
X+   codestream_seek (pc);
X+   
X+   i386_follow_jump ();
X+   
X+   op = codestream_get ();
X+   
X+   if (op == 0x58)		/* popl %eax */
X+     {
X+       /*
X+        * this function must start with
X+        * 
X+        *    popl %eax		  0x58
X+        *    xchgl %eax, (%esp)  0x87 0x04 0x24
X+        * or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
X+        *
X+        * (the system 5 compiler puts out the second xchg
X+        * inst, and the assembler doesn't try to optimize it,
X+        * so the 'sib' form gets generated)
X+        * 
X+        * this sequence is used to get the address of the return
X+        * buffer for a function that returns a structure
X+        */
X+       int pos;
X+       unsigned char buf[4];
X+       static unsigned char proto1[3] = { 0x87,0x04,0x24 };
X+       static unsigned char proto2[4] = { 0x87,0x44,0x24,0x00 };
X+       pos = codestream_tell ();
X+       codestream_read (buf, 4);
X+       if (bcmp (buf, proto1, 3) == 0)
X+ 	pos += 3;
X+       else if (bcmp (buf, proto2, 4) == 0)
X+ 	pos += 4;
X+       
X+       codestream_seek (pos);
X+       op = codestream_get (); /* update next opcode */
X+     }
X+   
X+   if (op == 0x55)		/* pushl %esp */
X+     {			
X+       /* check for movl %esp, %ebp - can be written two ways */
X+       switch (codestream_get ())
X+ 	{
X+ 	case 0x8b:
X+ 	  if (codestream_get () != 0xec)
X+ 	    return (-1);
X+ 	  break;
X+ 	case 0x89:
X+ 	  if (codestream_get () != 0xe5)
X+ 	    return (-1);
X+ 	  break;
X+ 	default:
X+ 	  return (-1);
X+ 	}
X+       /* check for stack adjustment 
X+        *
X+        *  subl $XXX, %esp
X+        *
X+        * note: you can't subtract a 16 bit immediate
X+        * from a 32 bit reg, so we don't have to worry
X+        * about a data16 prefix 
X+        */
X+       op = codestream_peek ();
X+       if (op == 0x83)
X+ 	{
X+ 	  /* subl with 8 bit immed */
X+ 	  codestream_get ();
X+ 	  if (codestream_get () != 0xec)
X+ 	    return (-1);
X+ 	  /* subl with signed byte immediate 
X+ 	   * (though it wouldn't make sense to be negative)
X+ 	   */
X+ 	  return (codestream_get());
X+ 	}
X+       else if (op == 0x81)
X+ 	{
X+ 	  /* subl with 32 bit immed */
X+ 	  int locals;
X+ 	  codestream_get();
X+ 	  if (codestream_get () != 0xec)
X+ 	    return (-1);
X+ 	  /* subl with 32 bit immediate */
X+ 	  codestream_read ((unsigned char *)&locals, 4);
X+ 	  return (locals);
X+ 	}
X+       else
X+ 	{
X+ 	  return (0);
X+ 	}
X+     }
X+   else if (op == 0xc8)
X+     {
X+       /* enter instruction: arg is 16 bit unsigned immed */
X+       unsigned short slocals;
X+       codestream_read ((unsigned char *)&slocals, 2);
X+       codestream_get (); /* flush final byte of enter instruction */
X+       return (slocals);
X+     }
X+   return (-1);
X+ }
X+ 
X+ /* Return number of args passed to a frame.
X+    Can return -1, meaning no way to tell.  */
X+ 
X+ /* on the 386, the instruction following the call could be:
X+  *  popl %ecx        -  one arg
X+  *  addl $imm, %esp  -  imm/4 args; imm may be 8 or 32 bits
X+  *  anything else    -  zero args
X+  */
X+ 
X+ int
X+ i386_frame_num_args (fi)
X+      struct frame_info fi;
X+ {
X+   int retpc;						
X+   unsigned char op;					
X+   struct frame_info *pfi;
X+ 
X+   pfi = get_prev_frame_info ((fi));			
X+   if (pfi == 0)
X+     {
X+       /* Note:  this can happen if we are looking at the frame for
X+ 	 main, because FRAME_CHAIN_VALID won't let us go into
X+ 	 start.  If we have debugging symbols, that's not really
X+ 	 a big deal; it just means it will only show as many arguments
X+ 	 to main as are declared.  */
X+       return -1;
X+     }
X+   else
X+     {
X+       retpc = pfi->pc;					
X+       op = read_memory_integer (retpc, 1);			
X+       if (op == 0x59)					
X+ 	/* pop %ecx */			       
X+ 	return 1;				
X+       else if (op == 0x83)
X+ 	{
X+ 	  op = read_memory_integer (retpc+1, 1);	
X+ 	  if (op == 0xc4)				
X+ 	    /* addl $<signed imm 8 bits>, %esp */	
X+ 	    return (read_memory_integer (retpc+2,1)&0xff)/4;
X+ 	  else
X+ 	    return 0;
X+ 	}
X+       else if (op == 0x81)
X+ 	{ /* add with 32 bit immediate */
X+ 	  op = read_memory_integer (retpc+1, 1);	
X+ 	  if (op == 0xc4)				
X+ 	    /* addl $<imm 32>, %esp */		
X+ 	    return read_memory_integer (retpc+2, 4) / 4;
X+ 	  else
X+ 	    return 0;
X+ 	}
X+       else
X+ 	{
X+ 	  return 0;
X+ 	}
X+     }
X+ }
X+ 
X+ /*
X+  * parse the first few instructions of the function to see
X+  * what registers were stored.
X+  *
X+  * We handle these cases:
X+  *
X+  * The startup sequence can be at the start of the function,
X+  * or the function can start with a branch to startup code at the end.
X+  *
X+  * %ebp can be set up with either the 'enter' instruction, or 
X+  * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
X+  * but was once used in the sys5 compiler)
X+  *
X+  * Local space is allocated just below the saved %ebp by either the
X+  * 'enter' instruction, or by 'subl $<size>, %esp'.  'enter' has
X+  * a 16 bit unsigned argument for space to allocate, and the
X+  * 'addl' instruction could have either a signed byte, or
X+  * 32 bit immediate.
X+  *
X+  * Next, the registers used by this function are pushed.  In
X+  * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
X+  * (and sometimes a harmless bug causes it to also save but not restore %eax);
X+  * however, the code below is willing to see the pushes in any order,
X+  * and will handle up to 8 of them.
X+  *
X+  * If the setup sequence is at the end of the function, then the
X+  * next instruction will be a branch back to the start.
X+  */
X+ 
X+ i386_frame_find_saved_regs (fip, fsrp)
X+      struct frame_info *fip;
X+      struct frame_saved_regs *fsrp;
X+ {
X+   unsigned long locals;
X+   unsigned char *p;
X+   unsigned char op;
X+   CORE_ADDR dummy_bottom;
X+   CORE_ADDR adr;
X+   int i;
X+   
X+   bzero (fsrp, sizeof *fsrp);
X+   
X+   /* if frame is the end of a dummy, compute where the
X+    * beginning would be
X+    */
X+   dummy_bottom = fip->frame - 4 - NUM_REGS*4 - CALL_DUMMY_LENGTH;
X+   
X+   /* check if the PC is in the stack, in a dummy frame */
X+   if (dummy_bottom <= fip->pc && fip->pc <= fip->frame) 
X+     {
X+       /* all regs were saved by push_call_dummy () */
X+       adr = fip->frame - 4;
X+       for (i = 0; i < NUM_REGS; i++) 
X+ 	{
X+ 	  fsrp->regs[i] = adr;
X+ 	  adr -= 4;
X+ 	}
X+       return;
X+     }
X+   
X+   locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
X+   
X+   if (locals >= 0) 
X+     {
X+       adr = fip->frame - 4 - locals;
X+       for (i = 0; i < 8; i++) 
X+ 	{
X+ 	  op = codestream_get ();
X+ 	  if (op < 0x50 || op > 0x57)
X+ 	    break;
X+ 	  fsrp->regs[op - 0x50] = adr;
X+ 	  adr -= 4;
X+ 	}
X+     }
X+   
X+   fsrp->regs[PC_REGNUM] = fip->frame + 4;
X+   fsrp->regs[FP_REGNUM] = fip->frame;
X+ }
X+ 
X+ /* return pc of first real instruction */
X+ i386_skip_prologue (pc)
X+ {
X+   unsigned char op;
X+   int i;
X+   
X+   if (i386_get_frame_setup (pc) < 0)
X+     return (pc);
X+   
X+   /* found valid frame setup - codestream now points to 
X+    * start of push instructions for saving registers
X+    */
X+   
X+   /* skip over register saves */
X+   for (i = 0; i < 8; i++)
X+     {
X+       op = codestream_peek ();
X+       /* break if not pushl inst */
X+       if (op < 0x50 || op > 0x57) 
X+ 	break;
X+       codestream_get ();
X+     }
X+   
X+   i386_follow_jump ();
X+   
X+   return (codestream_tell ());
X+ }
X+ 
X+ i386_push_dummy_frame ()
X+ {
X+   CORE_ADDR sp = read_register (SP_REGNUM);
X+   int regnum;
X+   
X+   sp = push_word (sp, read_register (PC_REGNUM));
X+   sp = push_word (sp, read_register (FP_REGNUM));
X+   write_register (FP_REGNUM, sp);
X+   for (regnum = 0; regnum < NUM_REGS; regnum++)
X+     sp = push_word (sp, read_register (regnum));
X+   write_register (SP_REGNUM, sp);
X+ }
X+ 
X+ i386_pop_frame ()
X+ {
X+   FRAME frame = get_current_frame ();
X+   CORE_ADDR fp;
X+   int regnum;
X+   struct frame_saved_regs fsr;
X+   struct frame_info *fi;
X+   
X+   fi = get_frame_info (frame);
X+   fp = fi->frame;
X+   get_frame_saved_regs (fi, &fsr);
X+   for (regnum = 0; regnum < NUM_REGS; regnum++) 
X+     {
X+       CORE_ADDR adr;
X+       adr = fsr.regs[regnum];
X+       if (adr)
X+ 	write_register (regnum, read_memory_integer (adr, 4));
X+     }
X+   write_register (FP_REGNUM, read_memory_integer (fp, 4));
X+   write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
X+   write_register (SP_REGNUM, fp + 8);
X+   flush_cached_frames ();
X+   set_current_frame ( create_new_frame (read_register (FP_REGNUM),
X+ 					read_pc ()));
X+ }
X+ 
X+ /* this table must line up with REGISTER_NAMES in m-i386.h */
X+ /* symbols like 'EAX' come from <sys/reg.h> */
X+ static int regmap[] = 
X+ {
X+   REAX, RECX, REDX, REBX,
X+   RESP, REBP, RESI, REDI,
X+   REIP, REFL, RCS, RSS,
X+   RDS, RES, RFS, RGS,
X+ };
X+ 
X+ /* blockend is the value of u.u_ar0, and points to the
X+  * place where GS is stored
X+  */
X+ i386_register_u_addr (blockend, regnum)
X+ {
X+ #if 0
X+   /* this will be needed if fp registers are reinstated */
X+   /* for now, you can look at them with 'info float'
X+    * sys5 wont let you change them with ptrace anyway
X+    */
X+   if (regnum >= FP0_REGNUM && regnum <= FP7_REGNUM) 
X+     {
X+       int ubase, fpstate;
X+       struct user u;
X+       ubase = blockend + 4 * (SS + 1) - KSTKSZ;
X+       fpstate = ubase + ((char *)&u.u_fpstate - (char *)&u);
X+       return (fpstate + 0x1c + 10 * (regnum - FP0_REGNUM));
X+     } 
X+   else
X+ #endif
X+     return (blockend + 4 * regmap[regnum]);
X+   
X+ }
X+ 
X+ i387_to_double (from, to)
X+      char *from;
X+      char *to;
X+ {
X+   long *lp;
X+   /* push extended mode on 387 stack, then pop in double mode
X+    *
X+    * first, set exception masks so no error is generated -
X+    * number will be rounded to inf or 0, if necessary 
X+    */
X+   asm ("pushl %eax"); 		/* grab a stack slot */
X+   asm ("fstcw (%esp)");		/* get 387 control word */
X+   asm ("movl (%esp),%eax");	/* save old value */
X+   asm ("orl $0x3f,%eax");		/* mask all exceptions */
X+   asm ("pushl %eax");
X+   asm ("fldcw (%esp)");		/* load new value into 387 */
X+   
X+   asm ("movl 8(%ebp),%eax");
X+   asm ("fldt (%eax)");		/* push extended number on 387 stack */
X+   asm ("fwait");
X+   asm ("movl 12(%ebp),%eax");
X+   asm ("fstpl (%eax)");		/* pop double */
X+   asm ("fwait");
X+   
X+   asm ("popl %eax");		/* flush modified control word */
X+   asm ("fnclex");			/* clear exceptions */
X+   asm ("fldcw (%esp)");		/* restore original control word */
X+   asm ("popl %eax");		/* flush saved copy */
X+ }
X+ 
X+ double_to_i387 (from, to)
X+      char *from;
X+      char *to;
X+ {
X+   /* push double mode on 387 stack, then pop in extended mode
X+    * no errors are possible because every 64-bit pattern
X+    * can be converted to an extended
X+    */
X+   asm ("movl 8(%ebp),%eax");
X+   asm ("fldl (%eax)");
X+   asm ("fwait");
X+   asm ("movl 12(%ebp),%eax");
X+   asm ("fstpt (%eax)");
X+   asm ("fwait");
X+ }
X+ 
X+ struct env387 
X+ {
X+   unsigned int control;
X+   unsigned int status;
X+   unsigned int tag;
X+   unsigned long eip;
X+   unsigned short code_seg;
X+   unsigned short operand_seg;
X+   unsigned long opcode;
X+   unsigned long operand;
X+   unsigned char regs[8][10];
X+ };
X+ 
X+ static
X+ print_387_control_word (control)
X+ unsigned short control;
X+ {
X+   printf ("control 0x%04x: ", control);
X+   printf ("compute to ");
X+   switch ((control >> 8) & 3) 
X+     {
X+     case 0: printf ("24 bits; "); break;
X+     case 1: printf ("(bad); "); break;
X+     case 2: printf ("53 bits; "); break;
X+     case 3: printf ("64 bits; "); break;
X+     }
X+   printf ("round ");
X+   switch ((control >> 10) & 3) 
X+     {
X+     case 0: printf ("NEAREST; "); break;
X+     case 1: printf ("DOWN; "); break;
X+     case 2: printf ("UP; "); break;
X+     case 3: printf ("CHOP; "); break;
X+     }
X+   if (control & 0x3f) 
X+     {
X+       printf ("mask:");
X+       if (control & 0x0001) printf (" INVALID");
X+       if (control & 0x0002) printf (" DENORM");
X+       if (control & 0x0004) printf (" DIVZ");
X+       if (control & 0x0008) printf (" OVERF");
X+       if (control & 0x0010) printf (" UNDERF");
X+       if (control & 0x0020) printf (" LOS");
X+       printf (";");
X+     }
X+   printf ("\n");
X+   if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n",
X+ 				control & 0xe080);
X+ }
X+ 
X+ static
X+ print_387_status_word (status)
X+      unsigned short status;
X+ {
X+   printf ("status 0x%04x: ", status);
X+   if (status & 0xff) 
X+     {
X+       printf ("exceptions:");
X+       if (status & 0x0001) printf (" INVALID");
X+       if (status & 0x0002) printf (" DENORM");
X+       if (status & 0x0004) printf (" DIVZ");
X+       if (status & 0x0008) printf (" OVERF");
X+       if (status & 0x0010) printf (" UNDERF");
X+       if (status & 0x0020) printf (" LOS");
X+       if (status & 0x0040) printf (" FPSTACK");
X+       printf ("; ");
X+     }
X+   printf ("flags: %d%d%d%d; ",
X+ 	  (status & 0x4000) != 0,
X+ 	  (status & 0x0400) != 0,
X+ 	  (status & 0x0200) != 0,
X+ 	  (status & 0x0100) != 0);
X+   
X+   printf ("top %d\n", (status >> 11) & 7);
X+ }
X+ 
X+ static
X+ print_387_status (ep)
X+      struct env387 *ep;
X+ {
X+   int i;
X+   int top;
X+   int fpreg;
X+   unsigned char *p;
X+   
X+   if (ep->status != 0) 
X+       print_387_status_word (ep->status);
X+   
X+   print_387_control_word (ep->control);
X+   printf ("last exception: ");
X+   printf ("opcode 0x%x; ", ep->opcode);
X+   printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip);
X+   printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand);
X+   
X+   top = (ep->status >> 11) & 7;
X+   
X+   printf ("regno  tag  msb              lsb  value\n");
X+   for (fpreg = 7; fpreg >= 0; fpreg--) 
X+     {
X+       double val;
X+       
X+       printf ("%s %d: ", fpreg == top ? "=>" : "  ", fpreg);
X+       
X+       switch ((ep->tag >> (fpreg * 2)) & 3) 
X+ 	{
X+ 	case 0: printf ("valid "); break;
X+ 	case 1: printf ("zero  "); break;
X+ 	case 2: printf ("trap  "); break;
X+ 	case 3: printf ("empty "); break;
X+ 	}
X+       for (i = 9; i >= 0; i--)
X+ 	printf ("%02x", ep->regs[fpreg][i]);
X+       
X+       i387_to_double (ep->regs[fpreg], (char *)&val);
X+       printf ("  %g\n", val);
X+     }
X+ }
X+ 
X+ #ifndef U_FPSTATE
X+ #define U_FPSTATE(u) u.u_fps
X+ #endif
X+ 
X+ i386_float_info ()
X+ {
X+   struct user u; /* just for address computations */
X+   int i;
X+   /* fpstate defined in <sys/user.h> */
X+   struct u_fps *fpstatep;
X+   char buf[sizeof (struct u_fps) + 2 * sizeof (int)];
X+   unsigned int uaddr;
X+   char fpvalid;
X+   unsigned int rounded_addr;
X+   unsigned int rounded_size;
X+   extern int corechan;
X+   int skip;
X+   
X+   uaddr = (char *)&u.u_fpsaved - (char *)&u;
X+   if (have_inferior_p()) 
X+     {
X+       unsigned int data;
X+       unsigned int mask;
X+       
X+       rounded_addr = uaddr & -sizeof (int);
X+       data = ptrace (3, inferior_pid, rounded_addr, 0);
X+       mask = 0xff << ((uaddr - rounded_addr) * 8);
X+       
X+       fpvalid = ((data & mask) != 0);
X+     } 
X+   else 
X+     {
X+       if (lseek (corechan, uaddr, 0) < 0)
X+ 	perror ("seek on core file");
X+       if (myread (corechan, &fpvalid, 1) < 0) 
X+ 	perror ("read on core file");
X+       
X+     }
X+   
X+   if (fpvalid == 0) 
X+     {
X+       printf ("no floating point status saved\n");
X+       return;
X+     }
X+   
X+   uaddr = (char *)&U_FPSTATE(u) - (char *)&u;
X+   if (have_inferior_p ()) 
X+     {
X+       int *ip;
X+       
X+       rounded_addr = uaddr & -sizeof (int);
X+       rounded_size = (((uaddr + sizeof (struct u_fps)) - uaddr) +
X+ 		      sizeof (int) - 1) / sizeof (int);
X+       skip = uaddr - rounded_addr;
X+       
X+       ip = (int *)buf;
X+       for (i = 0; i < rounded_size; i++) 
X+ 	{
X+ 	  *ip++ = ptrace (3, inferior_pid, rounded_addr, 0);
X+ 	  rounded_addr += sizeof (int);
X+ 	}
X+     } 
X+   else 
X+     {
X+       if (lseek (corechan, uaddr, 0) < 0)
X+ 	perror_with_name ("seek on core file");
X+       if (myread (corechan, buf, sizeof (struct u_fps)) < 0) 
X+ 	perror_with_name ("read from core file");
X+       skip = 0;
X+     }
X+   
X+   fpstatep = (struct u_fps *)(buf + skip);
X+   print_387_status ((struct env387 *)fpstatep);
X+ }
SHAR_EOF
if test 48390 -ne "`wc -c < 'gdb-x386.02'`"
then
	echo shar: error transmitting "'gdb-x386.02'" '(should have been 48390 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Alt.sources mailing list