Xref: utzoo alt.sources:1857 comp.unix.xenix:11449 Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!uunet!mcsun!ukc!stl!robobar!root From: Steve.Bleazard@RoboBar.Co.UK Newsgroups: alt.sources,comp.unix.xenix Subject: GDB for Xenix 386 with GCC (part 4 of 4) Message-ID: <1990May8.115539.29630@robobar.co.uk> Date: 8 May 90 11:55:39 GMT Sender: root@robobar.co.uk (Super user) Organization: Robobar Ltd., Perivale, Middx., ENGLAND. Lines: 1791 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 X+ #include X+ #include X+ #include X+ #include X+ #include X+ #include 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 X+ #include "defs.h" X+ #include "param.h" X+ #include "frame.h" X+ #include "inferior.h" X+ X+ #ifdef USG X+ #include X+ #endif X+ X+ #include X+ #include X+ #include X+ #include X+ #ifdef M_XENIX X+ #include X+ #include X+ #endif X+ #include X+ #include X+ #include X+ X+ #ifdef COFF_ENCAPSULATE X+ #include "a.out.encap.h" X+ #else X+ #ifndef M_XENIX /* brain-dead xenix strikes again */ X+ #include 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 X+ #include X+ #include X+ X+ #include 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 $, %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 $, %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 $, %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 */ 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 */ 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