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