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