kenc@madmax.Viewlogic.COM (Kenstir) (11/06/90)
Here is a patch to get GDB 3.5 running under Ultrix 4.0. For those not familiar with GDB: + You need to run it inside Emacs to really get the full effect. + 10,000x better than dxdb and look-alikes. This patch includes in one shot: + Per Bothner's diffs (alpha version) + Bruce Bauman's (boot@donald.osf.org) post of 27 Sep 90 (gnu.gdb.bug) + Garrett Lau's (lau@efi.com) post of 26 Oct 90 (gnu.gdb.bug), his suggested change to the mipscoff.c:read_type function, and his post of 3 Nov 90 (gnu.gdb.bug) + Mark Reinhold's (mbr@larch.lcs.mit.edu) of 23 Oct 90 (gnu.gdb.bug) -- Kenneth H. Cox Viewlogic Systems, Inc. kenstir@viewlogic.com ...!harvard!cg-atla!viewlog!kenstir --------------------------- cut here ---------------------------- ===================================== = Diffs for GDB 3.5, Ultrix 4.0 ===================================== = IMPORTANT: = Before running patch, you need to create some new files: = touch MIPS-NOTES m-decstatn.h m-mips.h mips-dep.c = touch mips-opcode.h mips-pinsn.c mipscoff.c = After running patch, you need to configure: = config.gdb decstatn = make = enjoy = = This patch includes in one shot: = + Per Bothner's diffs (alpha version) = + Bruce Bauman's (boot@donald.osf.org) post of 27 Sep 90 (gnu.gdb.bug) = + Garrett Lau's (lau@efi.com) post of 26 Oct 90 (gnu.gdb.bug), = his suggested change to the mipscoff.c:read_type function, = and his post of 3 Nov 90 (gnu.gdb.bug) = + Mark Reinhold's (mbr@larch.lcs.mit.edu) of 23 Oct 90 (gnu.gdb.bug) ===================================== *** MIPS-NOTES.orig Mon Nov 5 10:27:49 1990 --- MIPS-NOTES Mon Nov 5 10:28:25 1990 *************** *** 0 **** --- 1,21 ---- + This is the alpha release of the gdb port to MIPS-based machines. + Only the (little-endian) DECstation3100 has been tested. + + Here I will try to list known problems: + + Calling a function in the debugger (as in 'print f(x)') normally + works correctly. One known exception is if you pass a structure + argument whose sizeof > 4. Currently, gdb will align it on + an 8-byte boundary, while the compiler while depend on + the alignment needed by the fields. (Unfortunately, the + distributed varargs.h and stdarg.h are inconsistent with + mips' compiler!) + + Fortran debugging could be made nicer, but a lot of that is a + problem with the implementation-independent gdb. + + Code in include files is handled poorly (missing line numbers). + + Lots of testing is needed. + E.g. is IN_SIGTRAMP (in infrun.c) correct? + *** Makefile.dist.orig Tue Jan 30 21:42:57 1990 --- Makefile.dist Mon Nov 5 10:28:26 1990 *************** *** 328,338 **** cpp -M). It does not include dependencies of .o files on .c files. */ /* All files which depend on config.status also depend on param.h in case someone reconfigures gdb out from under an already compiled gdb. */ blockframe.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h breakpoint.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h ! coffread.o : defs.h param.h config.status command.o : command.h defs.h core.o : defs.h param.h config.status a.out.encap.h dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h a.out.encap.h \ stab.gnu.h environ.o : environ.h --- 328,338 ---- cpp -M). It does not include dependencies of .o files on .c files. */ /* All files which depend on config.status also depend on param.h in case someone reconfigures gdb out from under an already compiled gdb. */ blockframe.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h breakpoint.o : defs.h param.h config.status symtab.h obstack.h symseg.h frame.h ! coffread.o : defs.h param.h mipscoff.c config.status command.o : command.h defs.h core.o : defs.h param.h config.status a.out.encap.h dbxread.o : param.h config.status defs.h symtab.h obstack.h symseg.h a.out.encap.h \ stab.gnu.h environ.o : environ.h *** blockframe.c.orig Sat Jan 6 15:34:14 1990 --- blockframe.c Mon Nov 5 10:28:26 1990 *************** *** 261,279 **** prev->next = next_frame; prev->prev = (struct frame_info *) 0; prev->frame = address; prev->next_frame = prev->next ? prev->next->frame : 0; - #ifdef INIT_EXTRA_FRAME_INFO - INIT_EXTRA_FRAME_INFO(prev); - #endif - /* This entry is in the frame queue now, which is good since FRAME_SAVED_PC may use that queue to figure out it's value (see m-sparc.h). We want the pc saved in the inferior frame. */ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) : next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ()); return prev; } CORE_ADDR --- 261,279 ---- prev->next = next_frame; prev->prev = (struct frame_info *) 0; prev->frame = address; prev->next_frame = prev->next ? prev->next->frame : 0; /* This entry is in the frame queue now, which is good since FRAME_SAVED_PC may use that queue to figure out it's value (see m-sparc.h). We want the pc saved in the inferior frame. */ prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (next_frame) : next_frame ? FRAME_SAVED_PC (next_frame) : read_pc ()); + + #ifdef INIT_EXTRA_FRAME_INFO + INIT_EXTRA_FRAME_INFO(prev); + #endif return prev; } CORE_ADDR *** breakpoint.c.orig Wed Jan 10 18:49:07 1990 --- breakpoint.c Mon Nov 5 10:28:27 1990 *************** *** 438,463 **** last_addr = b->address; if (b->symtab) { sym = find_pc_function (b->address); if (sym) ! printf_filtered (" in %s (%s line %d)", SYMBOL_NAME (sym), b->symtab->filename, b->line_number); else ! printf_filtered ("%s line %d", b->symtab->filename, b->line_number); } else { char *name; int addr; if (find_pc_partial_function (b->address, &name, &addr)) { if (b->address - addr) ! printf_filtered ("<%s+%d>", name, b->address - addr); else ! printf_filtered ("<%s>", name); } } printf_filtered ("\n"); --- 438,464 ---- last_addr = b->address; if (b->symtab) { sym = find_pc_function (b->address); if (sym) ! printf_filtered (" in %.100s (%.100s line %d)", ! SYMBOL_NAME (sym), b->symtab->filename, b->line_number); else ! printf_filtered ("%.100s line %d", b->symtab->filename, b->line_number); } else { char *name; int addr; if (find_pc_partial_function (b->address, &name, &addr)) { if (b->address - addr) ! printf_filtered ("<%.200s+%d>", name, b->address - addr); else ! printf_filtered ("<%.200s>", name); } } printf_filtered ("\n"); *************** *** 472,482 **** printf_filtered ("\n"); } if (l = b->commands) while (l) { ! printf_filtered ("\t%s\n", l->line); l = l->next; } } /* Compare against (CORE_ADDR)-1 in case some compiler decides --- 473,485 ---- printf_filtered ("\n"); } if (l = b->commands) while (l) { ! fputs_filtered (stdout, "\t"); ! fputs_filtered (stdout, l->line); ! fputs_filtered (stdout, "\n"); l = l->next; } } /* Compare against (CORE_ADDR)-1 in case some compiler decides *** coffread.c.orig Wed Jan 10 18:54:43 1990 --- coffread.c Mon Nov 5 10:28:28 1990 *************** *** 22,31 **** --- 22,34 ---- #include <stdio.h> #include "defs.h" #include "param.h" #ifdef COFF_FORMAT + #ifdef THIRD_EYE_FORMAT + #include "mipscoff.c" + #else /* !THIRD_EYE_FORMAT */ #include "symtab.h" #ifdef USG #include <sys/types.h> #include <fcntl.h> *************** *** 2000,2009 **** --- 2003,2014 ---- } /* These will stay zero all the time */ struct psymbol_allocation_list global_psymbols, static_psymbols; + #endif /* !THIRD_EYE_FORMAT */ + _initialize_coff () { symfile = 0; bzero (&global_psymbols, sizeof (global_psymbols)); *************** *** 2011,2018 **** add_com ("symbol-file", class_files, symbol_file_command, "Load symbol table (in coff format) from executable file FILE."); } - #endif /* COFF_FORMAT */ - --- 2016,2021 ---- *** config.gdb.orig Tue Jan 30 15:35:46 1990 --- config.gdb Mon Nov 5 10:28:28 1990 *************** *** 319,328 **** --- 319,341 ---- opcodefile=sparc-opcode.h depfile=sparc-dep.c ;; convex) ;; + iris|mips) + echo "[Big-endian mips-based machines have not been tested]" + paramfile=m-mips.h + pinsnfile=mips-pinsn.c + opcodefile=mips-opcode.h + depfile=mips-dep.c + ;; + dec-3100|decstatn) # DECstation 3100 (alias PMAX) or DECstation 2100 + paramfile=m-decstatn.h + pinsnfile=mips-pinsn.c + opcodefile=mips-opcode.h + depfile=mips-dep.c + ;; test) paramfile=one pinsnfile=three opcodefile=four ;; *** eval.c.orig Sun Nov 5 13:01:52 1989 --- eval.c Mon Nov 5 10:28:29 1990 *************** *** 961,977 **** op = exp->elts[pc].opcode; switch (op) { case OP_VAR_VALUE: ! if (TYPE_CODE (SYMBOL_TYPE (exp->elts[pc + 1].symbol)) == TYPE_CODE_ARRAY) ! { ! (*pos) += 3; ! val = locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0); ! return value_cast (lookup_pointer_type (TYPE_TARGET_TYPE (SYMBOL_TYPE (exp->elts[pc + 1].symbol))), ! val); ! } } return evaluate_subexp (0, exp, pos, noside); } --- 961,988 ---- op = exp->elts[pc].opcode; switch (op) { case OP_VAR_VALUE: ! { ! struct symbol *sym = exp->elts[pc + 1].symbol; ! struct type *sym_type = SYMBOL_TYPE (sym); ! if (TYPE_CODE (sym_type) == TYPE_CODE_ARRAY) ! { ! value val; ! long low_bound= ! TYPE_FIELD_BITPOS(TYPE_FIELD_TYPE (sym_type, 0), 0); ! (*pos) += 3; ! val = locate_var_value (sym, (CORE_ADDR) 0); ! val = value_cast (lookup_pointer_type (TYPE_TARGET_TYPE(sym_type)), ! val); ! if (low_bound) ! val = value_sub (val, ! value_from_long(builtin_type_long, low_bound)); ! return val; ! } ! } } return evaluate_subexp (0, exp, pos, noside); } *** infrun.c.orig Tue Jan 23 18:10:35 1990 --- infrun.c Mon Nov 5 10:28:30 1990 *************** *** 173,183 **** static char signal_print[NSIG]; static char signal_program[NSIG]; /* Nonzero if breakpoints are now inserted in the inferior. */ ! static int breakpoints_inserted; /* Function inferior was in as of last step command. */ static struct symbol *step_start_function; --- 173,183 ---- static char signal_print[NSIG]; static char signal_program[NSIG]; /* Nonzero if breakpoints are now inserted in the inferior. */ ! int breakpoints_inserted; /* Function inferior was in as of last step command. */ static struct symbol *step_start_function; *** m-decstatn.h.orig Mon Nov 5 10:27:50 1990 --- m-decstatn.h Mon Nov 5 10:56:26 1990 *************** *** 0 **** --- 1,3 ---- + #define DECSTATION + #define HAVE_VPRINTF + #include "m-mips.h" *** m-mips.h.orig Mon Nov 5 10:27:50 1990 --- m-mips.h Mon Nov 5 10:28:30 1990 *************** *** 0 **** --- 1,432 ---- + /* Definitions to make GDB run on a MIPS-based machines. + Copyright (C) 1986, 1987, 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. */ + + /* Define the bit, byte, and word ordering of the machine. */ + #ifndef DECSTATION + #define BITS_BIG_ENDIAN + #define BYTES_BIG_ENDIAN + #define WORDS_BIG_ENDIAN + #endif + + #define IEEE_FLOAT + + #define FLOAT_INFO { printf("FPA coprocessor available.\n"); } + + /* Get rid of any system-imposed stack limit if possible. */ + + #define SET_STACK_LIMIT_HUGE + + /* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + + #undef NAMES_HAVE_UNDERSCORE + + /* Debugger information will be a variant of COFF */ + + /*#define READ_DBX_FORMAT*/ + #define COFF_FORMAT + #define THIRD_EYE_FORMAT + + /* We need to remember some procedure-specific values + to do stack traversal. Use the mips_proc_info type. */ + + #define mips_proc_info PDR + #define PROC_LOW_ADDR(proc) ((proc)->lnLow) /* least address */ + #define PROC_HIGH_ADDR(proc) ((proc)->lnHigh) /* upper address bound */ + #define PROC_FRAME_OFFSET(proc) ((proc)->frameoffset) + #define PROC_FRAME_REG(proc) ((proc)->framereg) + #define PROC_REG_MASK(proc) ((proc)->regmask) + #define PROC_FREG_MASK(proc) ((proc)->fregmask) + #define PROC_REG_OFFSET(proc) ((proc)->regoffset) + #define PROC_FREG_OFFSET(proc) ((proc)->fregoffset) + #define PROC_PC_REG(proc) ((proc)->pcreg) + #define PROC_SYMBOL(proc) (*(struct symbol**)&(proc)->isym) + #define _PROC_MAGIC_ 0x0F0F0F0F + #define PROC_DESC_IS_DUMMY(proc) ((proc)->isym == _PROC_MAGIC_) + #define SET_PROC_DESC_IS_DUMMY(proc) ((proc)->isym = _PROC_MAGIC_) + + /* Offset from address of function to start of its code. + Zero on most machines. */ + + #define FUNCTION_START_OFFSET 0 + + /* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + + #define SKIP_PROLOGUE(pc) \ + { register int op = read_memory_integer (pc, 4); \ + if ((op & 0xffff0000) == 0x27bd0000) \ + pc += 4; /* Skip addiu $sp,$sp,offset */ \ + } + + /* Immediately after a function call, return the saved pc. + Can't always go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + + #define SAVED_PC_AFTER_CALL(frame) (CORE_ADDR)read_register(RA_REGNUM) + + /* This is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ + + #define KERNEL_U_ADDR (0x80000000 - (UPAGES * NBPG)) + + /* Address of end of stack space. */ + + #define STACK_END_ADDR 0x7ffff000 + + /* Stack grows downward. */ + + #define INNER_THAN < + + /* Stack has strict alignment. However, use PUSH_ARGUMENTS + to take care of it. */ + /*#define STACK_ALIGN(ADDR) (((ADDR)+7)&-8)*/ + + #define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ + sp = mips_push_arguments(nargs, args, sp, struct_return, struct_addr) + + /* Sequence of bytes for breakpoint instruction. */ + + #ifdef BYTES_BIG_ENDIAN + #define BREAKPOINT {0, 0, 0, 13} + #else + #define BREAKPOINT {13, 0, 0, 0} + #endif + + /* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. */ + + #define DECR_PC_AFTER_BREAK 0 + + /* Nonzero if instruction at PC is a return instruction. */ + /* For Mips, this is jr $ra */ + + #define ABOUT_TO_RETURN(pc) \ + (read_memory_integer (pc, 4) == 0x03e00008) + + /* Return 1 if P points to an invalid floating point value. + LEN is the length in bytes -- not relevant on the Vax. */ + + #define INVALID_FLOAT(p, len) ((*(short *) p & 0xff80) == 0x8000) + + /* Largest integer type */ + #define LONGEST long + + /* Name of the builtin type for the LONGEST type above. */ + #define BUILTIN_TYPE_LONGEST builtin_type_long + + /* Say how long (ordinary) registers are. */ + + #define REGISTER_TYPE long + + /* Number of machine registers */ + + #define NUM_REGS 71 + + /* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + + /* Note that the symbol table parsing of scRegister symbols + * assumes r0=0, ..., r3=31, and f0=32, ... f31=32+31 */ + + #ifdef NUMERIC_REG_NAMES + #define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",\ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",\ + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",\ + "r24", "r25", "r26", "r27", "gp", "sp", "r30", "ra", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\ + "pc", "cause", "hi", "lo", "fcrcs", "fcrir", "fp" }; + #else /* !NUMERIC_REG_NAMES */ + #define REGISTER_NAMES {"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",\ + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",\ + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",\ + "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",\ + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",\ + "pc", "cause", "hi", "lo", "fcrcs", "fcrir", "fp" }; + #endif /* !NUMERIC_REG_NAMES */ + + /* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + + /* Note the FP is a "virtual" register */ + #define SP_REGNUM 29 /* Contains address of top of stack */ + #define RA_REGNUM 31 /* Contains return address value */ + #define FP0_REGNUM 32 /* Floating point register 0 (single float) */ + #define PC_REGNUM 64 /* Contains program counter */ + #define CAUSE_REGNUM 65 + #define HI_REGNUM 66 /* Multiple/divide temp */ + #define LO_REGNUM 67 /* ... */ + #define FCRCS_REGNUM 68 /* FP control/status */ + #define FCRIR_REGNUM 69 /* FP implementation/revision */ + #define FP_REGNUM 70 /* Pseudo register that contains true address of executing stack frame */ + + /* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + + #define DO_REGISTERS_INFO(_regnum) mips_do_registers_info(_regnum) + + /* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ + #define REGISTER_BYTES (4*NUM_REGS) + + /* Index within `registers' of the first byte of the space for + register N. */ + + #define REGISTER_BYTE(N) ((N) * 4) + + /* Number of bytes of storage in the actual machine representation + for register N.*/ + + #define REGISTER_RAW_SIZE(N) 4 + + /* Number of bytes of storage in the program's representation + for register N.*/ + + #define REGISTER_VIRTUAL_SIZE(N) 4 + + /* Largest value REGISTER_RAW_SIZE can have. */ + + #define MAX_REGISTER_RAW_SIZE 4 + + /* Largest value REGISTER_VIRTUAL_SIZE can have. */ + + #define MAX_REGISTER_VIRTUAL_SIZE 4 + + /* Nonzero if register N requires conversion + from raw format to virtual format. */ + + #define REGISTER_CONVERTIBLE(N) 0 + + /* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + + #define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ + { bcopy ((FROM), (TO), REGISTER_RAW_SIZE(REGNUM)); } + + /* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + + #define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ + { bcopy ((FROM), (TO), REGISTER_RAW_SIZE(REGNUM)); } + + /* Return the GDB type object for the "standard" data type + of data in register N. */ + + #define REGISTER_VIRTUAL_TYPE(N) \ + ((N) < FP0_REGNUM ? builtin_type_int : (N) < PC_REGNUM ? \ + builtin_type_float : builtin_type_int) + + /* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + + #define STORE_STRUCT_RETURN(ADDR, SP) SP = push_word(SP, ADDR) + + /* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + + #define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy (REGBUF+REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) + + /* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + + #define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (REGISTER_BYTE (TYPE_CODE (TYPE) == TYPE_CODE_FLT ? FP0_REGNUM : 2), VALBUF, TYPE_LENGTH (TYPE)) + + /* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + + #define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)((REGBUF)+16)) + + /* Compensate for lack of `vprintf' function. */ + #ifndef HAVE_VPRINTF + #define vprintf(format, ap) _doprnt (format, ap, stdout) + #endif /* not HAVE_VPRINTF */ + + /* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + + /* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + + /* In the case of the Vax, the frame's nominal address is the FP value, + and 12 bytes later comes the saved previous FP value as a 4-byte word. */ + + #define EXTRA_FRAME_INFO \ + char *proc_desc; /* actually, a PDR* */\ + int num_args;\ + struct frame_saved_regs *saved_regs; + #define INIT_EXTRA_FRAME_INFO(fci) init_extra_frame_info(fci) + + #define FRAME_CHAIN(thisframe) (FRAME_ADDR)frame_chain(thisframe) + + #define FRAME_CHAIN_VALID(chain, thisframe) (chain != 0) + + #define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + + /* Define other aspects of the stack frame. */ + + /* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ + #define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) {(FRAMELESS) = 0;} + + /* Saved Pc. */ + + #define FRAME_SAVED_PC(FRAME) frame_saved_pc(FRAME) + + /* If the argument is on the stack, it will be here. */ + #define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + + #define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) + + /* Return number of args passed to a frame. + Can return -1, meaning no way to tell. */ + + #define FRAME_NUM_ARGS(numargs, fi) (numargs = (fi)->num_args) + + /* Return number of bytes at start of arglist that are not really args. */ + + #define FRAME_ARGS_SKIP 0 + + /* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + + #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) ( \ + (frame_saved_regs) = *(frame_info)->saved_regs, \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame) + + /* Things needed for making the inferior call functions. */ + + /* Push an empty stack frame, to record the current PC, etc. */ + + #define PUSH_DUMMY_FRAME {push_dummy_frame();} + #if 0 + { register CORE_ADDR sp = read_register (SP_REGNUM);\ + register int regnum; \ + sp = push_word (sp, 0); /* arglist */ \ + for (regnum = 11; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + sp = push_word (sp, 0); \ + write_register (SP_REGNUM, sp); \ + write_register (FP_REGNUM, sp); } + #endif + + /* Discard from the stack the innermost frame, restoring all registers. */ + + #define POP_FRAME {pop_frame();} + + #define MK_OP(op,rs,rt,offset) (((op)<<26)|((rs)<<21)|((rt)<<16)|(offset)) + #define CALL_DUMMY_SIZE 48 + #define Dest_Reg 2 + #define CALL_DUMMY {\ + (017<<26)| (Dest_Reg << 16), /*lui $r31,<target upper 16 bits>*/ \ + MK_OP(13,Dest_Reg,Dest_Reg,0), /*ori $r31,$r31,<lower 16 bits>*/ \ + MK_OP(061,SP_REGNUM,12,0), /* lwc1 $f12,0(sp) */\ + MK_OP(061,SP_REGNUM,13,4), /* lwc1 $f13,4(sp) */\ + MK_OP(061,SP_REGNUM,14,8), /* lwc1 $f14,8(sp) */\ + MK_OP(061,SP_REGNUM,15,12), /* lwc1 $f15,12(sp) */\ + MK_OP(043,SP_REGNUM,4,0), /* lw $r4,0(sp) */\ + MK_OP(043,SP_REGNUM,5,4), /* lw $r5,4(sp) */\ + MK_OP(043,SP_REGNUM,6,8), /* lw $r6,8(sp) */\ + (Dest_Reg<<21) | (31<<11) | 9, /* jalr $r31 */\ + MK_OP(043,SP_REGNUM,7,12), /* lw $r7,12(sp) */\ + 13, /* bpt */\ + } + + #define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */ + + /* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + + #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, type) \ + (*(int *)dummyname |= (((unsigned long)(fun)) >> 16), \ + ((int*)dummyname)[1] |= (unsigned short)(fun)) + + + /* Interface definitions for kernel debugger KDB. */ + + /* Map machine fault codes into signal numbers. + First subtract 0, divide by 4, then index in a table. + Faults for which the entry in this table is 0 + are not handled by KDB; the program's own trap handler + gets to handle then. */ + + #define FAULT_CODE_ORIGIN 0 + #define FAULT_CODE_UNITS 4 + #define FAULT_TABLE \ + { 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ + 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + + /* Start running with a stack stretching from BEG to END. + BEG and END should be symbols meaningful to the assembler. + This is used only for kdb. */ + + #define INIT_STACK(beg, end) \ + { asm (".globl end"); \ + asm ("movl $ end, sp"); \ + asm ("clrl fp"); } + + /* Push the frame pointer register on the stack. */ + #define PUSH_FRAME_PTR \ + asm ("pushl fp"); + + /* Copy the top-of-stack to the frame pointer register. */ + #define POP_FRAME_PTR \ + asm ("movl (sp), fp"); + + /* After KDB is entered by a fault, push all registers + that GDB thinks about (all NUM_REGS of them), + so that they appear in order of ascending GDB register number. + The fault code will be on the stack beyond the last register. */ + + #define PUSH_REGISTERS { abort(); } + + /* Assuming the registers (including processor status) have been + pushed on the stack in order of ascending GDB register number, + restore them and return to the address in the saved PC register. */ + + #define POP_REGISTERS { abort(); } *** mips-dep.c.orig Mon Nov 5 10:27:50 1990 --- mips-dep.c Mon Nov 5 10:28:31 1990 *************** *** 0 **** --- 1,1151 ---- + /* Low level interface to ptrace, for GDB when running under Unix. + 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. */ + + /* + * The port to MIPS-based machines was mostly done + * by Per Bothner, bothner@cs.wisc.edu. + * The inspiration for the heuristics to deal with missing + * symbol tables, as well as many of the specific ideas for doing so, + * comes from Alessando Forin (Alessando.Forin@spice.cs.cmu.edu). + */ + #include "defs.h" + #include "param.h" + #include "frame.h" + #include "inferior.h" + #include "value.h" + + #ifdef USG + #include <sys/types.h> + #endif + + #include <stdio.h> + #include <sys/param.h> + #include <sys/ptrace.h> + #include <sys/dir.h> + #include <signal.h> + #include <sys/ioctl.h> + /* #include <fcntl.h> Can we live without this? */ + + #ifdef COFF_ENCAPSULATE + #include "a.out.encap.h" + #else + #include <a.out.h> + #endif + #ifndef N_SET_MAGIC + #define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) + #endif + #define VM_MIN_ADDRESS (unsigned)0x400000 + #include <sys/user.h> /* After a.out.h */ + #include <sys/file.h> + #include <sys/stat.h> + #include <machine/reg.h> + + #ifdef COFF_FORMAT + #include "symtab.h" + + #ifdef USG + #include <sys/types.h> + #include <fcntl.h> + #endif + + #include <obstack.h> + /*#include <sys/param.h>*/ + /*#include <sys/file.h>*/ + + extern void close (); + + extern PDR *proc_desc_table; + extern long proc_desc_length; + + struct linked_proc_info + { + mips_proc_info info; + struct linked_proc_info *next; + } * linked_proc_desc_table = NULL; + + 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; + { + errno = 0; + if (remote_debugging) + remote_resume (step, signal); + else + { + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + } + } + + static char register_ptrace_map[NUM_REGS] = { + /* general registers */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + /* floating-point registers */ + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + /* special registers */ + PC, /* 96, pc */ + CAUSE, /* 97,cause */ + MMHI, /* 98,mdhi */ + MMLO, /* 99,mdlow */ + FPC_CSR,/* 100,fpc_csr */ + FPC_EIR,/* 101,fpc_eir */ + -1 /* fp */ + }; + + void + fetch_inferior_registers () + { + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + + struct user u; + + for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_ptrace_map[regno]; + if (regaddr < 0) continue; + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0); + regaddr++; + } + supply_register (regno, buf); + } + /* for now, make FP = SP */ + *(long*)buf = read_register(SP_REGNUM); + supply_register(FP_REGNUM, 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]; + extern char registers[]; + unsigned int i; + + if (regno > FP_REGNUM) + return; + if (regno >= 0) + { + regaddr = register_ptrace_map[regno]; + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0 && regno != CAUSE_REGNUM) + { + sprintf (buf, "writing register number %d(ptrace#%d)", + regno, regaddr); + perror_with_name (buf); + } + regaddr++; + } + return; + } + + if (read_register (0) != 0) + { + int zero = 0; + error ("Cannot change register 0."); + supply_register (regno, &zero); + } + for (regno = 1; regno < FP_REGNUM; regno++) + { + regaddr = register_ptrace_map[regno]; + if (regaddr < 0) continue; + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing all regs, number %d(ptrace#%d)", + regno, regaddr); + perror_with_name (buf); + } + regaddr++; + } + } + } + + /* 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 0 + This is now done by read_memory, because when this function did it, + reading a byte or short int hardware port read whole longs, causing + serious side effects + such as bus errors and unexpected hardware operation. This would + also be a problem with ptrace if the inferior process could read + or write hardware registers, but that's not usually the case. + if (remote_debugging) + buffer[i] = remote_fetch_word (addr); + else + #endif + buffer[i] = ptrace (1, 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 (1, 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 (1, inferior_pid, + addr + (count - 1) * sizeof (int), 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + if (remote_debugging) + remote_store_word (addr, buffer[i]); + else + ptrace (4, 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.a_text + #endif /* no N_DATADDR */ + + /* Make COFF and non-COFF names for things a little more compatible + to reduce conditionals later. */ + + #ifdef COFF_FORMAT + #define a_magic magic + #endif + + #ifndef COFF_FORMAT + #ifndef AOUTHDR + #define AOUTHDR struct exec + #endif + #endif + + 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; + + /* 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; + extern char registers[]; + + /* 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 = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* 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); + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { + struct user u; + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = (int) u.u_ar0; + if (reg_offset > NBPG * UPAGES) + reg_offset -= KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + N_SET_MAGIC (core_aouthdr, 0); + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + char buf[MAX_REGISTER_RAW_SIZE]; + + *(long*)buf = 0; + supply_register (regno, buf); + + for (regno = 1; regno < NUM_REGS; regno++) + { + int offset; + + #define PCB_OFFSET(FIELD) ((int)&((struct user*)0)->u_pcb.FIELD) + if (regno < FP0_REGNUM) + offset = UPAGES*NBPG-EF_SIZE+4*((regno)+EF_AT-1); + else if (regno < PC_REGNUM) + offset = PCB_OFFSET(pcb_fpregs[0]) + 4*(regno-FP0_REGNUM); + else if (regno == LO_REGNUM) + offset = UPAGES*NBPG-EF_SIZE+4*EF_MDLO; + else if (regno == HI_REGNUM) + offset = UPAGES*NBPG-EF_SIZE+4*EF_MDHI; + else if (regno == PC_REGNUM) + offset = UPAGES*NBPG-EF_SIZE+4*EF_EPC; + else if (regno == CAUSE_REGNUM) + offset = UPAGES*NBPG-EF_SIZE+4*EF_CAUSE; + else if (regno == FCRIR_REGNUM) + offset = PCB_OFFSET(pcb_fpc_eir); + else if (regno == FCRCS_REGNUM) + offset = PCB_OFFSET(pcb_fpc_csr); + else + continue; + + val = lseek (corechan, offset, 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + + 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); + + { + int aout_hdrsize; + int num_sections; + + if (read_file_hdr (execchan, &file_hdr) < 0) + error ("\"%s\": not in executable format.", execfile); + + aout_hdrsize = file_hdr.f_opthdr; + num_sections = file_hdr.f_nscns; + + if (read_aout_hdr (execchan, &exec_aouthdr, aout_hdrsize) < 0) + error ("\"%s\": can't read optional aouthdr", execfile); + + if (read_section_hdr (execchan, _TEXT, &text_hdr, num_sections) < 0) + error ("\"%s\": can't read text section header", execfile); + + if (read_section_hdr (execchan, _DATA, &data_hdr, num_sections) < 0) + error ("\"%s\": can't read data section header", execfile); + + text_start = exec_aouthdr.text_start; + text_end = text_start + exec_aouthdr.tsize; + text_offset = 0; /* text_hdr.s_scnptr */ + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = exec_aouthdr.tsize; /*data_hdr.s_scnptr;*/ + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } + + 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); + } + + #define READ_FRAME_REG(fi, regno) read_next_frame_reg((fi)->next, regno) + + int + read_next_frame_reg(fi, regno) + FRAME fi; + int regno; + { + for (; fi; fi = fi->next) + if (regno == SP_REGNUM) return fi->frame; + else if (fi->saved_regs->regs[regno]) + return read_memory_integer(fi->saved_regs->regs[regno], 4); + return read_register(regno); + } + + int + frame_saved_pc(frame) + FRAME frame; + { + mips_proc_info *proc_desc = (mips_proc_info*)frame->proc_desc; + int pcreg = proc_desc ? PROC_PC_REG(proc_desc) : RA_REGNUM; + if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + return read_memory_integer(frame->frame - 4, 4); + #if 0 + /* If in the procedure prologue, RA_REGNUM might not have been saved yet. + * Assume non-leaf functions start with: + * addiu $sp,$sp,-frame_size + * sw $ra,ra_offset($sp) + * This if the pc is pointing at either of these instructions, + * then $ra hasn't been trashed. + * If the pc has advanced beyond these two instructions, + * then $ra has been saved. + * critical, and much more complex. Handling $ra is enough to get + * a stack trace, but some register values with be wrong. + */ + if (frame->proc_desc && frame->pc < PROC_LOW_ADDR(proc_desc) + 8) + return read_register(pcreg); + #endif + return read_next_frame_reg(frame, pcreg); + } + + static PDR temp_proc_desc; + static struct frame_saved_regs temp_saved_regs; + + CORE_ADDR heuristic_proc_start(pc) + CORE_ADDR pc; + { + + CORE_ADDR start_pc = pc; + CORE_ADDR fence = start_pc - 10000; + if (fence < VM_MIN_ADDRESS) fence = VM_MIN_ADDRESS; + /* search back for previous return */ + for (start_pc -= 4; ; start_pc -= 4) + if (start_pc < fence) return 0; + else if (ABOUT_TO_RETURN(start_pc)) + break; + + start_pc += 8; /* skip return, and iys delay slot */ + #if 0 + /* skip nops (usually 1) 0 - is this */ + while (start_pc < pc && read_memory_integer (start_pc, 4) == 0) + start_pc += 4; + #endif + return start_pc; + } + + PDR *heuristic_proc_desc(start_pc, limit_pc, next_frame) + CORE_ADDR start_pc, limit_pc; + FRAME next_frame; + { + CORE_ADDR sp = next_frame ? next_frame->frame : read_register (SP_REGNUM); + CORE_ADDR cur_pc; + extern int breakpoints_inserted; + int frame_size; + int has_frame_reg = 0; + int reg30; /* Value of $r30. Used by gcc for frame-pointer */ + unsigned long reg_mask = 0; + if (start_pc == 0) return NULL; + bzero(&temp_proc_desc, sizeof(PDR)); + bzero(&temp_saved_regs, sizeof(struct frame_saved_regs)); + if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200; + remove_breakpoints (); + breakpoints_inserted = 0; + restart: + frame_size = 0; + for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) { + unsigned long word = read_memory_integer(cur_pc, 4); + if ((word & 0xFFFF0000) == 0x27bd0000) /* addiu $sp,$sp,-i */ + frame_size += (-word) & 0xFFFF; + else if ((word & 0xFFFF0000) == 0x23bd0000) /* addu $sp,$sp,-i */ + frame_size += (-word) & 0xFFFF; + else if ((word & 0xFFE00000) == 0xafa00000) { /* sw reg,offset($sp) */ + int reg = (word & 0x001F0000) >> 16; + reg_mask |= 1 << reg; + temp_saved_regs.regs[reg] = sp + (short)word; + } + else if ((word & 0xFFFF0000) == 0x27be0000) { /* addiu $30,$sp,size */ + if ((unsigned short)word != frame_size) + reg30 = sp + (unsigned short)word; + else if (!has_frame_reg) { + int alloca_adjust; + has_frame_reg = 1; + reg30 = read_next_frame_reg(next_frame, 30); + alloca_adjust = reg30 - (sp + (unsigned short)word); + if (alloca_adjust > 0) { + /* FP > SP + frame_size. This may be because + /* of an alloca or somethings similar. + * Fix sp to "pre-alloca" value, and try again. + */ + sp += alloca_adjust; + goto restart; + } + } + } + else if ((word & 0xFFE00000) == 0xafc00000) { /* sw reg,offset($30) */ + int reg = (word & 0x001F0000) >> 16; + reg_mask |= 1 << reg; + temp_saved_regs.regs[reg] = reg30 + (short)word; + } + } + if (has_frame_reg) { + PROC_FRAME_REG(&temp_proc_desc) = 30; + PROC_FRAME_OFFSET(&temp_proc_desc) = 0; + } + else { + PROC_FRAME_REG(&temp_proc_desc) = SP_REGNUM; + PROC_FRAME_OFFSET(&temp_proc_desc) = frame_size; + } + PROC_REG_MASK(&temp_proc_desc) = reg_mask; + PROC_PC_REG(&temp_proc_desc) = RA_REGNUM; + return &temp_proc_desc; + } + + mips_proc_info * + find_proc_desc(pc, next_frame) + CORE_ADDR pc; + FRAME next_frame; + { + mips_proc_info *proc_desc; + + int lo = 0; + int hi = proc_desc_length-1; + if (hi >= 0 && PROC_LOW_ADDR(&proc_desc_table[0]) <= pc + && PROC_HIGH_ADDR(&proc_desc_table[hi]) > pc) + { + for (;;) { + int new = (lo + hi) >> 1; + proc_desc = &proc_desc_table[new]; + if (PROC_LOW_ADDR(proc_desc) > pc) hi = new; + else if (PROC_HIGH_ADDR(proc_desc) <= pc) lo = new; + else { + /* IF this is the topmost frame AND + * (this proc does not have debugging information OR + * the PC is in the procedure prologue) + * THEN create a "hueristic" proc_desc (by analyzing + * the actual code) to replace the "official" proc_desc. + */ + if (next_frame == NULL) { + struct symtab_and_line val; + struct symbol *proc_symbol = PROC_SYMBOL(proc_desc); + if (proc_symbol) { + val = find_pc_line (BLOCK_START + (SYMBOL_BLOCK_VALUE(proc_symbol)), + 0); + val.pc = val.end ? val.end : pc; + } + if (!proc_symbol || pc < val.pc) { + mips_proc_info *found_heuristic = + heuristic_proc_desc(PROC_LOW_ADDR(proc_desc), + pc, next_frame); + if (found_heuristic) proc_desc = found_heuristic; + } + } + break; + } + if (hi-lo <= 1) { proc_desc = 0; break; } + } + } + else + { + register struct linked_proc_info *link; + for (link = linked_proc_desc_table; link; link = link->next) + if (PROC_LOW_ADDR(&link->info) <= pc + && PROC_HIGH_ADDR(&link->info) > pc) + return &link->info; + proc_desc = + heuristic_proc_desc(heuristic_proc_start(pc), pc, next_frame); + } + return proc_desc; + } + + PDR *cached_proc_desc; + + FRAME_ADDR frame_chain(frame) + FRAME frame; + { + extern CORE_ADDR startup_file_start; /* From blockframe.c */ + mips_proc_info *proc_desc; + CORE_ADDR saved_pc = frame_saved_pc(frame); + if (startup_file_start) + { /* has at least the __start symbol */ + if (saved_pc == 0 || !outside_startup_file (saved_pc)) return 0; + } + else + { /* This hack depends on the internals of __start. */ + /* We also assume the breakpoints are *not* inserted */ + if (read_memory_integer (saved_pc + 8, 4) == 0xd) /* break */ + return 0; + } + proc_desc = find_proc_desc(saved_pc, frame); + if (!proc_desc) return 0; + cached_proc_desc = proc_desc; + return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); + } + + void + init_extra_frame_info(fci) + struct frame_info *fci; + { + extern struct obstack frame_cache_obstack; + /* Use proc_desc calculated in frame_chain */ + PDR *proc_desc = fci->next ? cached_proc_desc : + find_proc_desc(fci->pc, fci->next); + fci->saved_regs = (struct frame_saved_regs*) + obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs)); + bzero(fci->saved_regs, sizeof(struct frame_saved_regs)); + fci->proc_desc = + proc_desc == &temp_proc_desc ? (char*)NULL : (char*)proc_desc; + if (proc_desc) + { + int ireg; + CORE_ADDR reg_position; + unsigned long mask; + /* r0 bit means kernel trap */ + int kernel_trap = PROC_REG_MASK(proc_desc) & 1; + + /* Fixup frame-pointer - only needed for top frame */ + /* This may not be quite right, if procedure has a real frame register */ + if (fci->pc == PROC_LOW_ADDR(proc_desc)) + fci->frame = read_register (SP_REGNUM); + else + fci->frame = READ_FRAME_REG(fci, PROC_FRAME_REG(proc_desc)) + + PROC_FRAME_OFFSET(proc_desc); + + if (proc_desc == &temp_proc_desc) + *fci->saved_regs = temp_saved_regs; + else + { + /* find which general-purpose registers were saved */ + reg_position = fci->frame + PROC_REG_OFFSET(proc_desc); + mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK(proc_desc); + for (ireg= 31; mask; --ireg, mask <<= 1) + if (mask & 0x80000000) + { + fci->saved_regs->regs[ireg] = reg_position; + reg_position -= 4; + } + /* find which floating-point registers were saved */ + reg_position = fci->frame + PROC_FREG_OFFSET(proc_desc); + /* The freg_offset points to where the first *double* register is saved. + * So skip to the high-order word. */ + reg_position += 4; + mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK(proc_desc); + for (ireg = 31; mask; --ireg, mask <<= 1) + if (mask & 0x80000000) + { + fci->saved_regs->regs[32+ireg] = reg_position; + reg_position -= 4; + } + } + + /* hack: if argument regs are saved, guess these contain args */ + if ((PROC_REG_MASK(proc_desc) & 0xF0) == 0) fci->num_args = -1; + else if ((PROC_REG_MASK(proc_desc) & 0x80) == 0) fci->num_args = 4; + else if ((PROC_REG_MASK(proc_desc) & 0x40) == 0) fci->num_args = 3; + else if ((PROC_REG_MASK(proc_desc) & 0x20) == 0) fci->num_args = 2; + else if ((PROC_REG_MASK(proc_desc) & 0x10) == 0) fci->num_args = 1; + + fci->saved_regs->regs[PC_REGNUM] = fci->saved_regs->regs[RA_REGNUM]; + } + if (fci->next == 0) + supply_register(FP_REGNUM, &fci->frame); + } + + + CORE_ADDR mips_push_arguments(nargs, args, sp, struct_return, struct_addr) + int nargs; + value *args; + CORE_ADDR sp; + int struct_return; + CORE_ADDR struct_addr; + { + CORE_ADDR buf; + register i; + int accumulate_size = struct_return ? 4 : 0; + struct mips_arg { char *contents; int len; int offset; }; + struct mips_arg *mips_args = + (struct mips_arg*)alloca(nargs * sizeof(struct mips_arg)); + register struct mips_arg *m_arg; + for (i = 0, m_arg = mips_args; i < nargs; i++, m_arg++) { + extern value value_arg_coerce(); + value arg = value_arg_coerce (args[i]); + m_arg->len = TYPE_LENGTH (VALUE_TYPE (arg)); + /* This entire mips-specific routine is because doubles must be aligned + * on 8-byte boundaries. It still isn't quite right, because MIPS decided + * to align 'struct {int a, b}' on 4-byte boundaries (even though this + * breaks their varargs implementation...). A correct solution + * requires an simulation of gcc's 'alignof' (and use of 'alignof' + * in stdarg.h/varargs.h). + */ + if (m_arg->len > 4) accumulate_size = (accumulate_size + 7) & -8; + m_arg->offset = accumulate_size; + accumulate_size = (accumulate_size + m_arg->len + 3) & -4; + m_arg->contents = VALUE_CONTENTS(arg); + } + accumulate_size = (accumulate_size + 7) & (-8); + if (accumulate_size < 16) accumulate_size = 16; + sp -= accumulate_size; + for (i = nargs; m_arg--, --i >= 0; ) + write_memory(sp + m_arg->offset, m_arg->contents, m_arg->len); + if (struct_return) { + buf = struct_addr; + write_memory(sp, &buf, sizeof(CORE_ADDR)); + } + return sp; + } + + /* MASK(i,j) == (1<<i) + (1<<(i+1)) + ... + (1<<j)). Assume i<=j<31. */ + #define MASK(i,j) ((1 << (j)+1)-1 ^ (1 << (i))-1) + + void + push_dummy_frame() + { + int ireg; + struct linked_proc_info *link = (struct linked_proc_info*) + xmalloc(sizeof(struct linked_proc_info)); + mips_proc_info *proc_desc = &link->info; + CORE_ADDR sp = read_register (SP_REGNUM); + CORE_ADDR save_address; + REGISTER_TYPE buffer; + link->next = linked_proc_desc_table; + linked_proc_desc_table = link; + #define PUSH_FP_REGNUM 16 /* must be a register preserved across calls */ + #define GEN_REG_SAVE_MASK MASK(1,16)|MASK(24,28)|(1<<31) + #define GEN_REG_SAVE_COUNT 22 + #define FLOAT_REG_SAVE_MASK MASK(0,19) + #define FLOAT_REG_SAVE_COUNT 20 + #define SPECIAL_REG_SAVE_COUNT 4 + /* + * The registers we must save are all those not preserved across + * procedure calls. Dest_Reg (see m-mips.h) must also be saved. + * In addition, we must save the PC, and PUSH_FP_REGNUM. + * (Ideally, we should also save MDLO/-HI and FP Control/Status reg.) + * + * Dummy frame layout: + * (high memory) + * Saved PC + * Saved MMHI, MMLO, FPC_CSR + * Saved R31 + * Saved R28 + * ... + * Saved R1 + * Saved D18 (i.e. F19, F18) + * ... + * Saved D0 (i.e. F1, F0) + * CALL_DUMMY (subroutine stub; see m-mips.h) + * Parameter build area (not yet implemented) + * (low memory) + */ + PROC_REG_MASK(proc_desc) = GEN_REG_SAVE_MASK; + PROC_FREG_MASK(proc_desc) = FLOAT_REG_SAVE_MASK; + PROC_REG_OFFSET(proc_desc) = /* offset of (Saved R31) from FP */ + -sizeof(long) - 4 * SPECIAL_REG_SAVE_COUNT; + PROC_FREG_OFFSET(proc_desc) = /* offset of (Saved D18) from FP */ + -sizeof(double) - 4 * (SPECIAL_REG_SAVE_COUNT + GEN_REG_SAVE_COUNT); + /* save general registers */ + save_address = sp + PROC_REG_OFFSET(proc_desc); + for (ireg = 32; --ireg >= 0; ) + if (PROC_REG_MASK(proc_desc) & (1 << ireg)) + { + buffer = read_register (ireg); + write_memory (save_address, &buffer, sizeof(REGISTER_TYPE)); + save_address -= 4; + } + /* save floating-points registers */ + save_address = sp + PROC_FREG_OFFSET(proc_desc); + for (ireg = 32; --ireg >= 0; ) + if (PROC_FREG_MASK(proc_desc) & (1 << ireg)) + { + buffer = read_register (ireg); + write_memory (save_address, &buffer, 4); + save_address -= 4; + } + write_register (PUSH_FP_REGNUM, sp); + PROC_FRAME_REG(proc_desc) = PUSH_FP_REGNUM; + PROC_FRAME_OFFSET(proc_desc) = 0; + buffer = read_register (PC_REGNUM); + write_memory (sp - 4, &buffer, sizeof(REGISTER_TYPE)); + buffer = read_register (HI_REGNUM); + write_memory (sp - 8, &buffer, sizeof(REGISTER_TYPE)); + buffer = read_register (LO_REGNUM); + write_memory (sp - 12, &buffer, sizeof(REGISTER_TYPE)); + buffer = read_register (FCRCS_REGNUM); + write_memory (sp - 16, &buffer, sizeof(REGISTER_TYPE)); + sp -= 4 * (GEN_REG_SAVE_COUNT+FLOAT_REG_SAVE_COUNT+SPECIAL_REG_SAVE_COUNT); + write_register (SP_REGNUM, sp); + PROC_HIGH_ADDR(proc_desc) = sp; + PROC_LOW_ADDR(proc_desc) = sp - CALL_DUMMY_SIZE; + SET_PROC_DESC_IS_DUMMY(proc_desc); + PROC_PC_REG(proc_desc) = RA_REGNUM; + } + + void + pop_frame() + { register int regnum; + FRAME frame = get_current_frame (); + CORE_ADDR new_sp = frame->frame; + mips_proc_info *proc_desc = (PDR*)frame->proc_desc; + if (PROC_DESC_IS_DUMMY(proc_desc)) + { + struct linked_proc_info **ptr = &linked_proc_desc_table;; + for (; &ptr[0]->info != proc_desc; ptr = &ptr[0]->next ) + if (ptr[0] == NULL) abort(); + *ptr = ptr[0]->next; + free (ptr[0]); + write_register (HI_REGNUM, read_memory_integer(new_sp - 8, 4)); + write_register (LO_REGNUM, read_memory_integer(new_sp - 12, 4)); + write_register (FCRCS_REGNUM, read_memory_integer(new_sp - 16, 4)); + } + write_register (PC_REGNUM, FRAME_SAVED_PC(frame)); + if (frame->proc_desc) { + for (regnum = 32; --regnum >= 0; ) + if (PROC_REG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum, + read_memory_integer (frame->saved_regs->regs[regnum], 4)); + for (regnum = 64; --regnum >= 32; ) + if (PROC_FREG_MASK(proc_desc) & (1 << regnum)) + write_register (regnum, + read_memory_integer (frame->saved_regs->regs[regnum], 4)); + } + write_register (SP_REGNUM, new_sp); + flush_cached_frames (); + set_current_frame (create_new_frame (new_sp, read_pc ())); + } + + static mips_print_register(regnum, all) + int regnum, all; + { + unsigned char raw_buffer[8]; + REGISTER_TYPE val; + + read_relative_register_raw_bytes (regnum, raw_buffer); + + if (!(regnum & 1) && regnum >= FP0_REGNUM && regnum < FP0_REGNUM+32) { + read_relative_register_raw_bytes (regnum+1, raw_buffer+4); + printf_filtered ("(d%d: ", regnum&31); + val_print (builtin_type_double, raw_buffer, 0, + stdout, 0, 1, 0, Val_pretty_default); + printf_filtered ("); ", regnum&31); + } + fputs_filtered (reg_names[regnum], stdout); + #ifndef NUMERIC_REG_NAMES + if (regnum < 32) + printf_filtered ("(r%d): ", regnum); + else + #endif + printf_filtered (": "); + + /* If virtual format is floating, print it that way. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT + && ! INVALID_FLOAT (raw_buffer, REGISTER_VIRTUAL_SIZE(regnum))) { + val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, + stdout, 0, 1, 0, Val_pretty_default); + } + /* Else print as integer in hex. */ + else + { + long val; + + bcopy (raw_buffer, &val, sizeof (long)); + if (val == 0) + printf_filtered ("0"); + else if (all) + printf_filtered ("0x%x", val); + else + printf_filtered ("0x%x=%d", val, val); + } + } + + mips_do_registers_info(regnum) + int regnum; + { + if (regnum != -1) { + mips_print_register (regnum, 0); + printf_filtered ("\n"); + } + else { + for (regnum = 0; regnum < NUM_REGS; ) { + mips_print_register (regnum, 1); + regnum++; + if ((regnum & 3) == 0 || regnum == NUM_REGS) + printf_filtered (";\n"); + else + printf_filtered ("; "); + } + } + } *** mips-opcode.h.orig Mon Nov 5 10:27:50 1990 --- mips-opcode.h Mon Nov 5 11:12:55 1990 *************** *** 0 **** --- 1,367 ---- + /* Mips opcde list for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.junet) + Made to work for little-endian machines, and debugged + by Per Bothner (bothner@cs.wisc.edu). + Many fixes contributed by Frank Yellin (fy@lucid.com). + + 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. */ + + #ifdef BITS_BIG_ENDIAN + #define BIT_FIELDS_2(a,b) a;b; + #define BIT_FIELDS_4(a,b,c,d) a;b;c;d; + #define BIT_FIELDS_6(a,b,c,d,e,f) a;b;c;d;e;f; + #else + #define BIT_FIELDS_2(a,b) b;a; + #define BIT_FIELDS_4(a,b,c,d) d;c;b;a; + #define BIT_FIELDS_6(a,b,c,d,e,f) f;e;d;c;b;a; + #endif + + struct op_i_fmt + { + BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) + }; + + struct op_j_fmt + { + BIT_FIELDS_2( + unsigned op : 6, + unsigned target : 26) + }; + + struct op_r_fmt + { + BIT_FIELDS_6( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned rd : 5, + unsigned shamt : 5, + unsigned funct : 6) + }; + + + struct fop_i_fmt + { + BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + unsigned immediate : 16) + }; + + struct op_b_fmt + { + BIT_FIELDS_4( + unsigned op : 6, + unsigned rs : 5, + unsigned rt : 5, + short delta : 16) + }; + + struct fop_r_fmt + { + BIT_FIELDS_6( + unsigned op : 6, + unsigned fmt : 5, + unsigned ft : 5, + unsigned fs : 5, + unsigned fd : 5, + unsigned funct : 6) + }; + + struct mips_opcode + { + char *name; + unsigned long opcode; + unsigned long match; + char *args; + }; + + /* args format; + + "s" rs: source register specifier + "t" rt: target register + "i" immediate + "a" target address + "c" branch condition + "d" rd: destination register specifier + "h" shamt: shift amount + "f" funct: function field + + for fpu + "S" fs source 1 register + "T" ft source 2 register + "D" destination register + */ + + #define one(x) (x << 26) + #define op_func(x, y) ((x << 26) | y) + #define op_cond(x, y) ((x << 26) | (y << 16)) + #define op_rs_func(x, y, z) ((x << 26) | (y << 21) | z) + #define op_rs_b11(x, y, z) ((x << 26) | (y << 21) | z) + #define op_o16(x, y) ((x << 26) | (y << 16)) + #define op_bc(x, y, z) ((x << 26) | (y << 21) | (z << 16)) + + struct mips_opcode mips_opcodes[] = + { + /* These first opcodes are special cases of the ones in the comments */ + {"nop", 0, 0xffffffff, /*li*/ ""}, + {"li", op_bc(9,0,0), op_bc(0x3f,31,0), /*addiu*/ "t,j"}, + {"b", one(4), 0xffff0000, /*beq*/ "b"}, + {"move", op_func(0, 33), op_cond(0x3f,31)|0x7ff,/*addu*/ "d,s"}, + + {"sll", op_func(0, 0), op_func(0x3f, 0x3f), "d,t,h"}, + {"srl", op_func(0, 2), op_func(0x3f, 0x3f), "d,t,h"}, + {"sra", op_func(0, 3), op_func(0x3f, 0x3f), "d,t,h"}, + {"sllv", op_func(0, 4), op_func(0x3f, 0x7ff), "d,t,s"}, + {"srlv", op_func(0, 6), op_func(0x3f, 0x7ff), "d,t,s"}, + {"srav", op_func(0, 7), op_func(0x3f, 0x7ff), "d,t,s"}, + {"jr", op_func(0, 8), op_func(0x3f, 0x1fffff), "s"}, + {"jalr", op_func(0, 9), op_func(0x3f, 0x1f07ff), "d,s"}, + {"syscall", op_func(0, 12), op_func(0x3f, 0x3f), ""}, + {"break", op_func(0, 13), op_func(0x3f, 0x3f), ""}, + {"mfhi", op_func(0, 16), op_func(0x3f, 0x03ff07ff), "d"}, + {"mthi", op_func(0, 17), op_func(0x3f, 0x1fffff), "s"}, + {"mflo", op_func(0, 18), op_func(0x3f, 0x03ff07ff), "d"}, + {"mtlo", op_func(0, 19), op_func(0x3f, 0x1fffff), "s"}, + {"mult", op_func(0, 24), op_func(0x3f, 0xffff), "s,t"}, + {"multu", op_func(0, 25), op_func(0x3f, 0xffff), "s,t"}, + {"div", op_func(0, 26), op_func(0x3f, 0xffff), "s,t"}, + {"divu", op_func(0, 27), op_func(0x3f, 0xffff), "s,t"}, + {"add", op_func(0, 32), op_func(0x3f, 0x7ff), "d,s,t"}, + {"addu", op_func(0, 33), op_func(0x3f, 0x7ff), "d,s,t"}, + {"sub", op_func(0, 34), op_func(0x3f, 0x7ff), "d,s,t"}, + {"subu", op_func(0, 35), op_func(0x3f, 0x7ff), "d,s,t"}, + {"and", op_func(0, 36), op_func(0x3f, 0x7ff), "d,s,t"}, + {"or", op_func(0, 37), op_func(0x3f, 0x7ff), "d,s,t"}, + {"xor", op_func(0, 38), op_func(0x3f, 0x7ff), "d,s,t"}, + {"nor", op_func(0, 39), op_func(0x3f, 0x7ff), "d,s,t"}, + {"slt", op_func(0, 42), op_func(0x3f, 0x7ff), "d,s,t"}, + {"sltu", op_func(0, 43), op_func(0x3f, 0x7ff), "d,s,t"}, + + {"bltz", op_cond (1, 0), op_cond(0x3f, 0x1f), "s,b"}, + {"bgez", op_cond (1, 1), op_cond(0x3f, 0x1f), "s,b"}, + {"bltzal", op_cond (1, 16),op_cond(0x3f, 0x1f), "s,b"}, + {"bgezal", op_cond (1, 17),op_cond(0x3f, 0x1f), "s,b"}, + + + {"j", one(2), one(0x3f), "a"}, + {"jal", one(3), one(0x3f), "a"}, + {"beq", one(4), one(0x3f), "s,t,b"}, + {"bne", one(5), one(0x3f), "s,t,b"}, + {"blez", one(6), one(0x3f) | 0x1f0000, "s,b"}, + {"bgtz", one(7), one(0x3f) | 0x1f0000, "s,b"}, + {"addi", one(8), one(0x3f), "t,s,j"}, + {"addiu", one(9), one(0x3f), "t,s,j"}, + {"slti", one(10), one(0x3f), "t,s,j"}, + {"sltiu", one(11), one(0x3f), "t,s,j"}, + {"andi", one(12), one(0x3f), "t,s,i"}, + {"ori", one(13), one(0x3f), "t,s,i"}, + {"xori", one(14), one(0x3f), "t,s,i"}, + /* rs field is don't care field? */ + {"lui", one(15), one(0x3f), "t,i"}, + + /* co processor 0 instruction */ + {"mfc0", op_rs_b11 (16, 0, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"cfc0", op_rs_b11 (16, 2, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"mtc0", op_rs_b11 (16, 4, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"ctc0", op_rs_b11 (16, 6, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + + {"bc0f", op_o16(16, 0x100), op_o16(0x3f, 0x3ff), "b"}, + {"bc0f", op_o16(16, 0x180), op_o16(0x3f, 0x3ff), "b"}, + {"bc0t", op_o16(16, 0x101), op_o16(0x3f, 0x3ff), "b"}, + {"bc0t", op_o16(16, 0x181), op_o16(0x3f, 0x3ff), "b"}, + + {"tlbr", op_rs_func(16, 0x10, 1), + op_rs_func(0x3f, 0x1f, 0x1f), ""}, + {"tlbwi", op_rs_func(16, 0x10, 2), + op_rs_func(0x3f, 0x1f, 0x1f), ""}, + {"tlbwr", op_rs_func(16, 0x10, 6), + op_rs_func(0x3f, 0x1f, 0x1f), ""}, + {"tlbp", op_rs_func(16, 0x10, 8), + op_rs_func(0x3f, 0x1f, 0x1f), ""}, + {"rfe", op_rs_func(16, 0x10, 16), + op_rs_func(0x3f, 0x1f, 0x1f), ""}, + + {"mfc1", op_rs_b11 (17, 0, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,S"}, + {"cfc1", op_rs_b11 (17, 2, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,S"}, + {"mtc1", op_rs_b11 (17, 4, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,S"}, + {"ctc1", op_rs_b11 (17, 6, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,S"}, + + {"bc1f", op_o16(17, 0x100), op_o16(0x3f, 0x3ff), "b"}, + {"bc1f", op_o16(17, 0x180), op_o16(0x3f, 0x3ff), "b"}, + {"bc1t", op_o16(17, 0x101), op_o16(0x3f, 0x3ff), "b"}, + {"bc1t", op_o16(17, 0x181), op_o16(0x3f, 0x3ff), "b"}, + + /* fpu instruction */ + {"add.s", op_rs_func(17, 0x10, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"add.d", op_rs_func(17, 0x11, 0), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"sub.s", op_rs_func(17, 0x10, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"sub.d", op_rs_func(17, 0x11, 1), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"mul.s", op_rs_func(17, 0x10, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"mul.d", op_rs_func(17, 0x11, 2), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"div.s", op_rs_func(17, 0x10, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"div.d", op_rs_func(17, 0x11, 3), + op_rs_func(0x3f, 0x1f, 0x3f), "D,S,T"}, + {"abs.s", op_rs_func(17, 0x10, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"abs.d", op_rs_func(17, 0x11, 5), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"mov.s", op_rs_func(17, 0x10, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"mov.d", op_rs_func(17, 0x11, 6), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"neg.s", op_rs_func(17, 0x10, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"neg.d", op_rs_func(17, 0x11, 7), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.s.s", op_rs_func(17, 0x10, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.s.d", op_rs_func(17, 0x11, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.s.w", op_rs_func(17, 0x14, 32), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.d.s", op_rs_func(17, 0x10, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.d.d", op_rs_func(17, 0x11, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.d.w", op_rs_func(17, 0x14, 33), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.w.s", op_rs_func(17, 0x10, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"cvt.w.d", op_rs_func(17, 0x11, 36), + op_rs_func(0x3f, 0x1f, 0x1f003f), "D,S"}, + {"c.f.s", op_rs_func(17, 0x10, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.f.d", op_rs_func(17, 0x11, 48), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.un.s", op_rs_func(17, 0x10, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.un.d", op_rs_func(17, 0x11, 49), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.eq.s", op_rs_func(17, 0x10, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.eq.d", op_rs_func(17, 0x11, 50), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ueq.s", op_rs_func(17, 0x10, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ueq.d", op_rs_func(17, 0x11, 51), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.olt.s", op_rs_func(17, 0x10, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.olt.d", op_rs_func(17, 0x11, 52), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ult.s", op_rs_func(17, 0x10, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ult.d", op_rs_func(17, 0x11, 53), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ole.s", op_rs_func(17, 0x10, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ole.d", op_rs_func(17, 0x11, 54), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ule.s", op_rs_func(17, 0x10, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ule.d", op_rs_func(17, 0x11, 55), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.sf.s", op_rs_func(17, 0x10, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.sf.d", op_rs_func(17, 0x11, 56), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngle.s", op_rs_func(17, 0x10, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngle.d", op_rs_func(17, 0x11, 57), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.seq.s", op_rs_func(17, 0x10, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.seq.d", op_rs_func(17, 0x11, 58), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngl.s", op_rs_func(17, 0x10, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngl.d", op_rs_func(17, 0x11, 59), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.lt.s", op_rs_func(17, 0x10, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.lt.d", op_rs_func(17, 0x11, 60), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.nge.s", op_rs_func(17, 0x10, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.nge.d", op_rs_func(17, 0x11, 61), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.le.s", op_rs_func(17, 0x10, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.le.d", op_rs_func(17, 0x11, 62), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngt.s", op_rs_func(17, 0x10, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + {"c.ngt.d", op_rs_func(17, 0x11, 63), + op_rs_func(0x3f, 0x1f, 0x7ff), "S,T"}, + + /* co processor 2 instruction */ + {"mfc2", op_rs_b11 (18, 0, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"cfc2", op_rs_b11 (18, 2, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"mtc2", op_rs_b11 (18, 4, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"ctc2", op_rs_b11 (18, 6, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"bc2f", op_o16(18, 0x100), op_o16(0x3f, 0x3ff), "b"}, + {"bc2f", op_o16(18, 0x180), op_o16(0x3f, 0x3ff), "b"}, + {"bc2t", op_o16(18, 0x101), op_o16(0x3f, 0x3ff), "b"}, + {"bc2t", op_o16(18, 0x181), op_o16(0x3f, 0x3ff), "b"}, + + /* co processor 3 instruction */ + {"mtc3", op_rs_b11 (19, 0, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"cfc3", op_rs_b11 (19, 2, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"mtc3", op_rs_b11 (19, 4, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"ctc3", op_rs_b11 (19, 6, 0), op_rs_b11(0x3f, 0x1f, 0x7ff), "t,d"}, + {"bc3f", op_o16(19, 0x100), op_o16(0x3f, 0x3ff), "b"}, + {"bc3f", op_o16(19, 0x180), op_o16(0x3f, 0x3ff), "b"}, + {"bc3t", op_o16(19, 0x101), op_o16(0x3f, 0x3ff), "b"}, + {"bc3t", op_o16(19, 0x181), op_o16(0x3f, 0x3ff), "b"}, + + {"lb", one(32), one(0x3f), "t,j(s)"}, + {"lh", one(33), one(0x3f), "t,j(s)"}, + {"lwl", one(34), one(0x3f), "t,j(s)"}, + {"lw", one(35), one(0x3f), "t,j(s)"}, + {"lbu", one(36), one(0x3f), "t,j(s)"}, + {"lhu", one(37), one(0x3f), "t,j(s)"}, + {"lwr", one(38), one(0x3f), "t,j(s)"}, + {"sb", one(40), one(0x3f), "t,j(s)"}, + {"sh", one(41), one(0x3f), "t,j(s)"}, + {"swl", one(42), one(0x3f), "t,j(s)"}, + {"swr", one(46), one(0x3f), "t,j(s)"}, + {"sw", one(43), one(0x3f), "t,j(s)"}, + {"lwc0", one(48), one(0x3f), "t,j(s)"}, + /* for fpu */ + {"lwc1", one(49), one(0x3f), "T,j(s)"}, + {"lwc2", one(50), one(0x3f), "t,j(s)"}, + {"lwc3", one(51), one(0x3f), "t,j(s)"}, + {"swc0", one(56), one(0x3f), "t,j(s)"}, + /* for fpu */ + {"swc1", one(57), one(0x3f), "T,j(s)"}, + {"swc2", one(58), one(0x3f), "t,j(s)"}, + {"swc3", one(59), one(0x3f), "t,j(s)"}, + }; *** mips-pinsn.c.orig Mon Nov 5 10:27:50 1990 --- mips-pinsn.c Mon Nov 5 10:28:32 1990 *************** *** 0 **** --- 1,149 ---- + /* Print mips instructions for GDB, the GNU debugger. + Copyright (C) 1989 Free Software Foundation, Inc. + Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp) + + 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 "symtab.h" + #include "mips-opcode.h" + + /* Mips instructions are never longer than this many bytes. */ + #define MAXLEN 4 + + /* Number of elements in the opcode table. */ + #define NOPCODES (sizeof mips_opcodes / sizeof mips_opcodes[0]) + + #define MKLONG(p) *(unsigned long*)p + + extern char *reg_names[]; + + + /* subroutine */ + static unsigned char * + print_insn_arg (d, l, stream, pc) + char *d; + register unsigned long int *l; + FILE *stream; + CORE_ADDR pc; + { + switch (*d) + { + case ',': + case '(': + case ')': + fputc (*d, stream); + break; + + case 's': + fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rs]); + break; + + case 't': + fprintf (stream, "$%s", reg_names[((struct op_i_fmt *) l)->rt]); + break; + + case 'i': + fprintf (stream, "%d", ((struct op_i_fmt *) l)->immediate); + break; + + case 'j': /* same as i, but sign-extended */ + fprintf (stream, "%d", ((struct op_b_fmt *) l)->delta); + break; + + case 'a': + print_address ((pc & 0xC0000000) | (((struct op_j_fmt *)l)->target << 2), + stream); + break; + + case 'b': + print_address ((((struct op_b_fmt *) l)->delta << 2) + pc + 4, stream); + break; + + case 'd': + fprintf (stream, "%s", reg_names[((struct op_r_fmt *) l)->rd]); + break; + + case 'h': + fprintf (stream, "0x%x", ((struct op_r_fmt *) l)->shamt); + break; + + case 'S': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fs); + break; + + case 'T': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->ft); + break; + + case 'D': + fprintf (stream, "$f%d", ((struct fop_r_fmt *) l)->fd); + break; + + default: + fprintf (stream, "# internal error, undefined modifier(%c)", *d); + break; + } + } + + /* Print the mips instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes, which + is always 4. */ + + int + print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; + { + unsigned char buffer[MAXLEN]; + register int i; + register char *d; + unsigned long int l; + + read_memory (memaddr, buffer, MAXLEN); + + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = mips_opcodes[i].opcode; + register unsigned int match = mips_opcodes[i].match; + if ((*(unsigned int*)buffer & match) == opcode) + break; + } + + l = MKLONG (buffer); + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0x%x",l); + return 4; + } + + fprintf (stream, "%s", mips_opcodes[i].name); + + if (!(d = mips_opcodes[i].args)) + return 4; + + fputc (' ', stream); + + while (*d) + print_insn_arg (d++, &l, stream, memaddr); + + return 4; + } *** mipscoff.c.orig Mon Nov 5 10:27:50 1990 --- mipscoff.c Mon Nov 5 11:21:44 1990 *************** *** 0 **** --- 1,2044 ---- + /* Read coff symbol tables and convert to internal format, for GDB. + Design and support routines derived from dbxread.c, and UMAX COFF + specific routines written 9/1/87 by David D. Johnson, Brown University. + Revised 11/27/87 ddj@cs.brown.edu + Copyright (C) 1987, 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 <a.out.h> + #include <stdio.h> + #include "symtab.h" + #include <sys/file.h> + + PDR *proc_desc_table = NULL; + long proc_desc_length = 0; + + static void add_symbol_to_list (); + static int read_coff_symtab (); + static void patch_opaque_types (); + static struct type *decode_function_type (); + static struct type *decode_type (); + static struct type *decode_base_type (); + static struct type *read_enum_type (); + static struct type *read_struct_type (); + static struct type *read_type (); + static void finish_block (); + static struct blockvector *make_blockvector (); + static struct symbol *process_coff_symbol (); + static char *getfilename (); + static char *getsymname (); + + extern int fclose (); + extern void close (); + extern void free_all_symtabs (); + extern void free_all_psymtabs (); + + + /* Name of source file whose symbol data we are now processing. + This comes from a symbol named ".file". */ + + static char *last_source_file; + + /* Core address of the end of the first object file. */ + static CORE_ADDR first_object_file_end; + + /* End of the text segment of the executable file, + as found in the symbol _etext. */ + + static CORE_ADDR end_of_text_addr; + + /* The end address of the last seen procedure. */ + + static CORE_ADDR last_end_addr; + + /* The file, a.out and text section headers of the symbol file */ + + static FILHDR file_hdr; + static SCNHDR text_hdr; + static AOUTHDR aout_hdr; + + /* The index in the symbol table of the last coff symbol that was processed. */ + + static int symnum; + + /* Vector of types defined so far, indexed by their coff symnum. */ + + static struct typevector *type_vector; + + /* Number of elements allocated for type_vector currently. */ + + static int type_vector_length; + + /* Chain of typedefs of pointers to empty struct/union types. + They are chained thru the SYMBOL_VALUE. */ + + #define HASHSIZE 127 + static struct symbol *opaque_type_chain[HASHSIZE]; + + /* Record the symbols defined for each context in a list. + We don't create a struct block for the context until we + know how long to make it. */ + + struct pending + { + struct pending *next; + struct symbol *symbol; + }; + + /* Here are the three lists that symbols are put on. */ + + struct pending *file_symbols; /* static at top level, and types */ + + struct pending *global_symbols; /* global functions and variables */ + + struct pending **global_symbols_all, **file_symbols_all; + + struct pending *local_symbols; /* everything local to lexical context */ + + /* List of unclosed lexical contexts + (that will become blocks, eventually). */ + + struct context_stack + { + struct context_stack *next; + struct pending *locals; + struct pending_block *old_blocks; + struct symbol *name; + CORE_ADDR start_addr; + }; + + struct context_stack *context_stack; + + /* Nonzero if within a function (so symbols should be local, + if nothing says specifically). */ + + int within_function; + + /* List of blocks already made (lexical contexts already closed). + This is used at the end to make the blockvector. */ + + struct pending_block + { + struct pending_block *next; + struct block *block; + }; + + struct pending_block *pending_blocks; + + extern CORE_ADDR startup_file_start; /* From blockframe.c */ + extern CORE_ADDR startup_file_end; /* From blockframe.c */ + + /* File name symbols were loaded from. */ + + static char *symfile; + + /* Look up a coff type-number index. Return the address of the slot + where the type for that index is stored. + The type-number is in INDEX. + + This can be used for finding the type associated with that index + or for associating a new type with the index. */ + + static struct type ** + coff_lookup_type (index) + register int index; + { + if (index >= type_vector_length) + { + int old_vector_length = type_vector_length; + + type_vector_length *= 2; + if (type_vector_length < index) { + type_vector_length = index * 2; + } + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[ old_vector_length ], + (type_vector_length - old_vector_length) * sizeof(struct type *)); + } + return &type_vector->type[index]; + } + + /* Make sure there is a type allocated for type number index + and return the type object. + This can create an empty (zeroed) type object. */ + + static struct type * + coff_alloc_type (index) + int index; + { + register struct type **type_addr = coff_lookup_type (index); + register struct type *type = *type_addr; + + /* If we are referring to a type not known at all yet, + allocate an empty type for it. + We will fill it in later if we find out how. */ + if (type == 0) + { + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + *type_addr = type; + } + return type; + } + + /* maintain the lists of symbols and blocks */ + + /* Add a symbol to one of the lists of symbols. */ + static void + add_symbol_to_list (symbol, listhead) + struct symbol *symbol; + struct pending **listhead; + { + register struct pending *link + = (struct pending *) xmalloc (sizeof (struct pending)); + + link->next = *listhead; + link->symbol = symbol; + *listhead = link; + } + + /* Take one of the lists of symbols and make a block from it. + Put the block on the list of pending blocks. */ + + static void + finish_block (symbol, listhead, old_blocks, start, end) + struct symbol *symbol; + struct pending **listhead; + struct pending_block *old_blocks; + CORE_ADDR start, end; + { + register struct pending *next, *next1; + register struct block *block; + register struct pending_block *pblock; + struct pending_block *opblock; + register int i; + + /* Count the length of the list of symbols. */ + + for (next = *listhead, i = 0; next; next = next->next, i++); + + block = (struct block *) + obstack_alloc (symbol_obstack, sizeof (struct block) + (i - 1) * sizeof (struct symbol *)); + + /* Copy the symbols into the block. */ + + BLOCK_NSYMS (block) = i; + for (next = *listhead; next; next = next->next) + BLOCK_SYM (block, --i) = next->symbol; + + BLOCK_START (block) = start; + BLOCK_END (block) = end; + BLOCK_SUPERBLOCK (block) = 0; /* Filled in when containing block is made */ + + /* Put the block in as the value of the symbol that names it. */ + + if (symbol) + { + SYMBOL_BLOCK_VALUE (symbol) = block; + BLOCK_FUNCTION (block) = symbol; + } + else + BLOCK_FUNCTION (block) = 0; + + /* Now free the links of the list, and empty the list. */ + + for (next = *listhead; next; next = next1) + { + next1 = next->next; + free (next); + } + *listhead = 0; + + /* Install this block as the superblock + of all blocks made since the start of this scope + that don't have superblocks yet. */ + + opblock = 0; + for (pblock = pending_blocks; pblock != old_blocks; pblock = pblock->next) + { + if (BLOCK_SUPERBLOCK (pblock->block) == 0) + BLOCK_SUPERBLOCK (pblock->block) = block; + opblock = pblock; + } + + /* Record this block on the list of all blocks in the file. + Put it after opblock, or at the beginning if opblock is 0. + This puts the block in the list after all its subblocks. */ + + pblock = (struct pending_block *) xmalloc (sizeof (struct pending_block)); + pblock->block = block; + if (opblock) + { + pblock->next = opblock->next; + opblock->next = pblock; + } + else + { + pblock->next = pending_blocks; + pending_blocks = pblock; + } + } + + static struct blockvector * + make_blockvector () + { + register struct pending_block *next, *next1; + register struct blockvector *blockvector; + register int i; + + /* Count the length of the list of blocks. */ + + for (next = pending_blocks, i = 0; next; next = next->next, i++); + + blockvector = (struct blockvector *) + obstack_alloc (symbol_obstack, sizeof (struct blockvector) + (i - 1) * sizeof (struct block *)); + + /* Copy the blocks into the blockvector. + This is done in reverse order, which happens to put + the blocks into the proper order (ascending starting address). + finish_block has hair to insert each block into the list + after its subblocks in order to make sure this is true. */ + + BLOCKVECTOR_NBLOCKS (blockvector) = i; + for (next = pending_blocks; next; next = next->next) + BLOCKVECTOR_BLOCK (blockvector, --i) = next->block; + + /* Now free the links of the list, and empty the list. */ + + for (next = pending_blocks; next; next = next1) + { + next1 = next->next; + free (next); + } + pending_blocks = 0; + + return blockvector; + } + + /* Manage the vector of line numbers. */ + + static + record_line (line, pc) + int line; + CORE_ADDR pc; + { + } + + /* Start a new symtab for a new source file. + This is called when a COFF ".file" symbol is seen; + it indicates the start of data for one original source file. */ + + static void + start_symtab () + { + context_stack = 0; + within_function = 0; + last_source_file = 0; + + /* Initialize the source file information for this file. */ + + } + + /* Finish the symbol definitions for one main source file, + close off all the lexical contexts for that file + (creating struct block's for them), then make the + struct symtab for that file and put it in the list of all such. + + END_ADDR is the address of the end of the file's text. */ + + static void + end_symtab (start_addr, end_addr, linetable) + CORE_ADDR start_addr, end_addr; + struct linetable *linetable; + { + register struct symtab *symtab; + register struct context_stack *cstk; + register struct blockvector *blockvector; + struct partial_symtab *psymtab; + + if (aout_hdr.entry < end_addr + && aout_hdr.entry >= start_addr) + { + startup_file_start = start_addr; + startup_file_end = end_addr; + } + + /* Finish the lexical context of the last function in the file. */ + + if (context_stack) + { + cstk = context_stack; + context_stack = 0; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, end_addr); + free (cstk); + } + + /* Create the two top-level blocks for this file. */ + finish_block (0, &file_symbols, 0, start_addr, end_addr); + finish_block (0, &global_symbols, 0, start_addr, end_addr); + + /* Create the blockvector that points to all the file's blocks. */ + blockvector = make_blockvector (); + + /* Now create the symtab object for this source file. */ + symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); + symtab->free_ptr = 0; + + /* Fill in its components. */ + symtab->blockvector = blockvector; + symtab->free_code = free_linetable; + symtab->filename = last_source_file; + symtab->linetable = linetable; + symtab->nlines = 0; + symtab->line_charpos = 0; + + /* Link the new symtab into the list of such. */ + symtab->next = symtab_list; + symtab_list = symtab; + + /* Reinitialize for beginning of new file. */ + last_source_file = 0; + + /* Create a fake partial_symtab, so that find_pc_partial_function + * will do the right thing. */ + psymtab = (struct partial_symtab *) + obstack_alloc (psymbol_obstack, + sizeof (struct partial_symtab)); + bzero (psymtab, sizeof (struct partial_symtab)); + psymtab->next = partial_symtab_list; + partial_symtab_list = psymtab; + psymtab->textlow = start_addr; + psymtab->texthigh = end_addr; + psymtab->filename = symtab->filename ? symtab->filename : ""; + psymtab->readin = 1; + + } + + /* Accumulate the misc functions in bunches of 127. + At the end, copy them all into one newly allocated structure. */ + + #define MISC_BUNCH_SIZE 127 + + struct misc_bunch + { + struct misc_bunch *next; + struct misc_function contents[MISC_BUNCH_SIZE]; + }; + + /* Bunch currently being filled up. + The next field points to chain of filled bunches. */ + + static struct misc_bunch *misc_bunch; + + /* Number of slots filled in current bunch. */ + + static int misc_bunch_index; + + /* Total number of misc functions recorded so far. */ + + static int misc_count; + + static void + init_misc_functions () + { + misc_count = 0; + misc_bunch = 0; + misc_bunch_index = MISC_BUNCH_SIZE; + } + + static void + record_misc_function (name, address) + char *name; + CORE_ADDR address; + { + register struct misc_bunch *new; + + if (misc_bunch_index == MISC_BUNCH_SIZE) + { + new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch)); + misc_bunch_index = 0; + new->next = misc_bunch; + misc_bunch = new; + } + misc_bunch->contents[misc_bunch_index].name = savestring (name, strlen (name)); + misc_bunch->contents[misc_bunch_index].address = address; + misc_bunch->contents[misc_bunch_index].type = (char)mf_unknown; + misc_bunch_index++; + misc_count++; + } + + /* if we see a function symbol, we do record_misc_function. + * however, if it turns out the next symbol is '.bf', then + * we call here to undo the misc definition + */ + static void + unrecord_misc_function () + { + if (misc_bunch_index == 0) + error ("Internal error processing symbol table, at symbol %d.", + symnum); + misc_bunch_index--; + misc_count--; + } + + + 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 void + discard_misc_bunches () + { + register struct misc_bunch *next; + + while (misc_bunch) + { + next = misc_bunch->next; + free (misc_bunch); + misc_bunch = next; + } + } + + static void + condense_misc_bunches () + { + register int i, j; + register struct misc_bunch *bunch; + #ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; + #else + int offset = 0; + #endif + + misc_function_vector + = (struct misc_function *) + xmalloc (misc_count * sizeof (struct misc_function)); + + j = 0; + bunch = misc_bunch; + while (bunch) + { + for (i = 0; i < misc_bunch_index; i++) + { + register char *tmp; + + misc_function_vector[j] = bunch->contents[i]; + tmp = misc_function_vector[j].name; + misc_function_vector[j].name = (tmp[0] == '_' ? tmp + offset : tmp); + j++; + } + bunch = bunch->next; + misc_bunch_index = MISC_BUNCH_SIZE; + } + + misc_function_count = j; + + /* Sort the misc functions by address. */ + + qsort (misc_function_vector, j, sizeof (struct misc_function), + compare_misc_functions); + } + + /* Call sort_syms to sort alphabetically + the symbols of each block of each symtab. */ + + static int + compare_symbols (s1, s2) + struct symbol **s1, **s2; + { + /* Names that are less should come first. */ + register int namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)); + if (namediff != 0) return namediff; + /* For symbols of the same name, registers should come first. */ + return ((SYMBOL_CLASS (*s2) == LOC_REGISTER) + - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); + } + + static void + sort_syms () + { + register struct symtab *s; + register int i, nbl; + register struct blockvector *bv; + register struct block *b; + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + nbl = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < nbl; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + if (BLOCK_SHOULD_SORT (b)) + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); + } + } + } + + /* Call sort_proc_descs to sort the procedure descriptors by address. */ + + static int + compare_proc_descs (p1, p2) + PDR *p1, *p2; + { + unsigned int a1, a2; + + a1 = PROC_LOW_ADDR (p1); + a2 = PROC_LOW_ADDR (p2); + if (a1 < a2) + return -1; + if (a1 > a2) + return 1; + return 0; + } + + static void + sort_proc_descs () + { + qsort (proc_desc_table, proc_desc_length, + sizeof (PDR), compare_proc_descs); + } + + + /* This is the symbol-file command. Read the file, analyze its symbols, + and add a struct symtab to symtab_list. */ + + /* !!! !!! */ + int dump_stuff=0; + + static void free_proc_descs () + { + if (proc_desc_table != NULL) { + free (proc_desc_table); + proc_desc_table = NULL; + proc_desc_length = 0; + } + } + + void + symbol_file_command (name) + char *name; + { + int desc; + int num_symbols; + int num_sections; + int symtab_offset; + register int val; + struct cleanup *old_chain; + + dont_repeat (); + + if (name == 0) + { + if (symtab_list && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + if (symfile) + free (symfile); + symfile = 0; + free_all_symtabs (); + free_proc_descs (); + return; + } + + name = tilde_expand (name); + make_cleanup (free, name); + + if (symtab_list && !query ("Load new symbol table from \"%s\"? ", name)) + error ("Not confirmed."); + + if (symfile) + free (symfile); + symfile = 0; + + { + char *absolute_name; + + desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name); + if (desc < 0) + perror_with_name (name); + else + name = absolute_name; + } + + old_chain = make_cleanup (close, desc); + make_cleanup (free_current_contents, &name); + + if ((num_symbols = read_file_hdr (desc, &file_hdr)) < 0) + error ("File \"%s\" not in executable format.", name); + + /* If an a.out header is present, read it in. If not (e.g. a .o file) + deal with its absence. */ + if (file_hdr.f_opthdr == 0 + || read_aout_hdr (desc, &aout_hdr, file_hdr.f_opthdr) < 0) + { + /* We will not actually be able to run code, since backtraces would + fly off the bottom of the stack (there is no way to reliably + detect bottom of stack), but that's fine since the kernel won't + run something without an a.out header anyway. Passive examination + of .o files is one place this might make sense. */ + /* ~0 will not be in any file. */ + aout_hdr.entry = ~0; + /* set the startup file to be an empty range. */ + startup_file_start = 0; + startup_file_end = 0; + } + + if (num_symbols == 0) + { + free_all_symtabs (); + free_proc_descs (); + printf ("%s does not have a symbol-table.\n", name); + fflush (stdout); + do_cleanups (old_chain); + return; + } + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Throw away the old symbol table. */ + + free_all_symtabs (); + free_proc_descs (); + free_all_psymtabs (); /* Make sure that partial_symtab_list */ + /* is 0 also. */ + + num_sections = file_hdr.f_nscns; + symtab_offset = file_hdr.f_symptr; + + if (read_section_hdr (desc, _TEXT, &text_hdr, num_sections) < 0) + error ("\"%s\": can't read text section header", name); + + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, (long)symtab_offset, 0); + if (val < 0) + perror_with_name (name); + + init_misc_functions (); + make_cleanup (discard_misc_bunches, 0); + + /* Now that the executable file is positioned at symbol table, + process it and define symbols accordingly. */ + + val = read_coff_symtab (desc, num_symbols, symtab_offset); + if (val < 0) error("Bad symbol table format"); + + patch_opaque_types (); + + /* Sort symbols alphabetically within each block. */ + + sort_syms (); + + /* Go over the misc functions and install them in vector. */ + + condense_misc_bunches (); + + /* Sort the procedure descriptor table. */ + + sort_proc_descs (); + + /* Don't allow char * to have a typename (else would get caddr_t.) */ + + TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; + + /* Make a default for file to list. */ + + symfile = savestring (name, strlen (name)); + + do_cleanups (old_chain); + + printf ("done.\n"); + fflush (stdout); + } + + /* Return name of file symbols were loaded from, or 0 if none.. */ + + char * + get_sym_file () + { + return symfile; + } + + /* Simplified internal version of coff symbol table information */ + + struct coff_symbol { + char *c_name; + int c_symnum; /* symbol number of this entry */ + int c_nsyms; /* 1 if syment only, 2 if syment + auxent */ + long c_value; + int c_sclass; + int c_secnum; + unsigned int c_type; + }; + + static char * + read_table(desc, size, offset) + long offset; + { + char *buf; + if (lseek(desc, offset, 0) < 0) + error("Bad symbol table format [seek]"); + buf = xmalloc(size); + if (buf == NULL) error("Not enough memory"); + if (myread (desc, buf, size) != size) + error("Bad symbol table format [read]"); + return buf; + } + + static char * (MapStNames[]) = { /* symbol type names */ + "Nil", "Global", "Static", "Param", "Local", "Label", "Proc", "Block", + "End", "Member", "Typedef", "File", "RegReloc", "Forward", "StaticProc", + "Constant", "BlockPatched" + }; + + long stNameSize = sizeof(MapStNames)/sizeof(MapStNames[0]); + + static char * MapScNames[] = { /* storage class names */ + "Nil", "Text", "Data", "Bss", "Register", "Abs", "Undefined", "CdbLocal", + "Bits", "Dbx", "RegImage", "Info", "UserStruct", "SData", "SBss", "RData", + "Var", "Common", "SCommon", "VarRegister", "Variant", "SUndefined", "Init" + }; + + + long scNameSize = sizeof(MapScNames)/sizeof(MapScNames[0]); + + static char *(MapBtNames[]) = { /* base type names */ + "Nil", "Adr", "Char", "UChar", "Short", "UShort", "Int", "UInt", "Long", + "ULong", "Float", "Double", "Struct", "Union", "Enum", "Typedef", "Range", + "Set", "Complex", "DComplex", "Indirect", "FixedDec", "FloatDec", "String", + "Bit", "Picture" + }; + + long btNameSize = sizeof(MapBtNames)/sizeof(MapBtNames[0]); + + /* Given pointers to a symbol table in coff style exec file, + analyze them and create struct symtab's describing the symbols. + NSYMS is the number of symbols in the symbol table. + We read them one at a time using read_one_sym (). */ + + /* stBlockPatched indicates an stBlock symbol which has been patched + * so that the value points to s struct type */ + + #define stBlockPatched 16 + + static FDR *file_descriptor_table; + static RFDT *rel_file_table; + static SYMR *local_symbol_table; + static char *local_string_table; + static AUXU *aux_symbol_table; + static FDR *cur_file_descriptor; + static int file_descriptor_count; + /* Note that PDR is also used for frame chaining, and is defined above */ + + static int cur_proc_number; /* number of procedure within current file */ + static CORE_ADDR cur_proc_addr; + static int cur_file_number; + static int cur_isymBase; + static int cur_issBase; + + static void + select_file(i) + int i; + { + global_symbols_all[cur_file_number] = global_symbols; + file_symbols_all[cur_file_number] = file_symbols; + global_symbols = global_symbols_all[i]; + file_symbols = file_symbols_all[i]; + cur_file_number = i; + cur_file_descriptor = &file_descriptor_table[i]; + cur_isymBase = cur_file_descriptor->isymBase; + cur_issBase = cur_file_descriptor->issBase; + } + + /* side-effect: changes cur_file_descriptor */ + + static SYMR * + get_type_context(auxp) + AUXU** auxp; + { + SYMR *sym; + FDR *sym_file_desc; + int rfi; + int rfd = (*auxp)->rndx.rfd; + int sym_index = (*auxp)->rndx.index; + (*auxp)++; + if (rfd == ST_RFDESCAPE) { rfd = (*auxp)->isym; (*auxp)++; } + if (rfd == ST_EXTIFD || sym_index == ST_ANONINDEX) return NULL; + rfi = rel_file_table[cur_file_descriptor->rfdBase + rfd]; + if (rfi >= file_descriptor_count) return NULL; + sym_file_desc = &file_descriptor_table[rfi]; + if (sym_index >= sym_file_desc->csym || sym_index == 0) return NULL; + sym = &local_symbol_table[sym_file_desc->isymBase + sym_index]; + if (sym->index == 0) return NULL; + select_file(rfi); + if (dump_stuff) + printf("rfd(%d,%d)->[%s,%x,st%s,sc%s,inx:%d (%x)]\n", + rfi, sym_index, + &local_string_table[cur_issBase+sym->iss], + sym->value, + MapStNames[sym->st], MapScNames[sym->sc], + sym->index, sym); + return sym; + } + + static struct type * + get_struct_type(sym, kind) + SYMR *sym; + int kind; /* either btStruct or btUnion or btNil (unknown) */ + { + struct type *type; + if (sym->st == stBlockPatched) + { + type = (struct type*)sym->value; + /* Patch up possibly-wrong guess about struct vs. union */ + if (kind == btStruct) TYPE_CODE(type) = TYPE_CODE_STRUCT; + else if (kind == btUnion) TYPE_CODE(type) = TYPE_CODE_UNION; + } + else if (sym->st != stBlock) + { + fprintf(stderr,"Bad symbol table: struct/union points to non-stBlock\n"); + type = builtin_type_void; + } + else + { + int nfields = 0; + SYMR *first_field = sym+1; + register struct field *cur_field; + char *sym_name = &local_string_table[cur_issBase+sym->iss]; + int iauxBase = cur_file_descriptor->iauxBase; + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + TYPE_LENGTH (type) = sym->value; + + /* we "remember" the type generated from this block */ + sym->st = stBlockPatched; + sym->value = (long)type; + + /* first count the number of fields */ + for (sym = first_field; sym->st != stEnd; sym++) + if (sym->st == stMember) nfields++; + else if (sym->st == stBlock || sym->st == stBlockPatched) + { + if (sym->sc == scVariant) ; /* UNIMPLEMENTED */ + if (sym->index != 0) + sym = &local_symbol_table[cur_isymBase + sym->index - 1]; + } + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = cur_field = (struct field*) + obstack_alloc (symbol_obstack, nfields * sizeof (struct field)); + for (sym = first_field; sym->st != stEnd; sym++) + if (sym->st == stMember) + { + AUXU *aux = &aux_symbol_table[iauxBase + sym->index]; + char *name = &local_string_table[cur_issBase+sym->iss]; + cur_field->name = + obstack_copy0 (symbol_obstack, name, strlen (name)); + + cur_field->type = read_type(sym->index, &cur_field->bitsize); + cur_field->bitpos = sym->value; + cur_field++; + } + else if (sym->st == stTypedef) ; /* just ignore it */ + else if (sym->st == stBlock || sym->st == stBlockPatched) + { + if (sym->sc == scVariant) ; /* UNIMPLEMENTED */ + if (sym->index != 0) + sym = &local_symbol_table[cur_isymBase + sym->index - 1]; + } + else + fprintf(stderr, "[Bad member in struct/union field list]\n"); + /* + * Heuristic: if 2nd field has offset 0, this is a union, + * otherwise, a struct definition. + * If nfields <= 1, we guess struct. + * If the type is used later, we fix it up. + * (This is done in the stBlockPatched case at the top of this routine). + */ + if (kind == btNil && nfields > 1) + { + if (TYPE_FIELDS(type)[1].bitpos > 0) kind = btStruct; + else kind = btUnion; + } + TYPE_CODE (type) = kind == btUnion ? TYPE_CODE_UNION : TYPE_CODE_STRUCT; + TYPE_NAME (type) = concat ("", + (kind == btUnion ? "union " : "struct "), + sym_name); + } + return type; + } + + static struct type * + read_struct_type(auxp, kind) + AUXU** auxp; + int kind; /* either btStruct or btUnion */ + { + struct type *type; + int save_file_number = cur_file_number; + SYMR *sym = get_type_context(auxp); + if (sym == NULL) { + printf(stderr, "Bad symbol for struct/union definition"); + return builtin_type_void; + } + if (sym->st == stTypedef) + type = read_type(sym->index, NULL); + else + type = get_struct_type(sym, kind); + select_file (save_file_number); + return type; + } + + static struct type * + get_enum_type(sym) + SYMR *sym; + { + struct type *type; + if (sym->st == stBlockPatched) + type = (struct type*)sym->value; + else if (sym->st != stBlock) + { + fprintf(stderr,"Bad symbol table: enum points to non-stBlock\n"); + type = builtin_type_void; + } + else + { + int nfields = 0; + SYMR *first_field = sym+1; + register struct field *cur_field; + type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + bzero (type, sizeof (struct type)); + TYPE_LENGTH (type) = sym->value; + + /* we "remember" the type generated from this block */ + sym->st = stBlockPatched; + sym->value = (long)type; + + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_LENGTH (type) = sizeof (int); + TYPE_NAME (type) = concat ("", "enum ", + &local_string_table[cur_issBase+sym->iss]); + + nfields = &local_symbol_table[cur_isymBase+sym->index] - first_field - 1; + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = cur_field = (struct field*) + obstack_alloc (symbol_obstack, nfields * sizeof (struct field)); + for (sym = first_field; sym->st != stEnd; sym++) + if (sym->st == stMember) + { + char *name = &local_string_table[cur_issBase+sym->iss]; + cur_field->name = + obstack_copy0 (symbol_obstack, name, strlen (name)); + + cur_field->bitpos = sym->value; + cur_field->bitsize = 0; + cur_field++; + } + else + fprintf(stderr, "[Bad member in enum list]\n"); + } + return type; + } + + static struct type * + read_enum_type(auxp) + AUXU** auxp; + { + struct type *type; + int save_file_number = cur_file_number; + SYMR *sym = get_type_context(auxp); + if (sym == NULL) { + printf(stderr, "Bad symbol for enum definition"); + return builtin_type_int; + } + if (sym->st == stTypedef) + type = read_type(sym->index, NULL); + else + type = get_enum_type (sym); + select_file (save_file_number); + return type; + } + + static struct type * + read_range_type(auxp) + AUXU** auxp; + { + struct type *range_type; + int save_file_number = cur_file_number; + SYMR *sym = get_type_context(auxp); + /* sym (if non-NULL) may point at an stBlock/scInfo, but ignore it */ + range_type = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + TYPE_CODE (range_type) = TYPE_CODE_RANGE; + TYPE_TARGET_TYPE (range_type) = builtin_type_int; + TYPE_LENGTH (range_type) = sizeof (int); + TYPE_NFIELDS (range_type) = 2; + TYPE_FIELDS (range_type) = + (struct field *) obstack_alloc (symbol_obstack, + 2 * sizeof (struct field)); + TYPE_FIELD_BITPOS (range_type, 0) = (*auxp)++->dnLow; + TYPE_FIELD_BITPOS (range_type, 1) = (*auxp)++->dnHigh; + + select_file (save_file_number); + return range_type; + } + + static struct type * + modify_type(type, qualifier, auxp) + struct type *type; + int qualifier; + AUXU** auxp; + { + switch (qualifier) { + case tqPtr: return lookup_pointer_type(type); + case tqNil: return type; + case tqArray: + { + struct type *range_type = read_range_type(auxp); + long lower = TYPE_FIELD_BITPOS (range_type, 0); + long upper = TYPE_FIELD_BITPOS (range_type, 1); + int elem_size = (*auxp)++->width; /* not used */ + struct type *atype; + + atype = (struct type *) + obstack_alloc (symbol_obstack, sizeof (struct type)); + bzero (atype, sizeof (struct type)); + + TYPE_CODE (atype) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (atype) = type; + TYPE_LENGTH (atype) = (upper - lower + 1) * TYPE_LENGTH (type); + TYPE_NFIELDS (atype) = 1; + TYPE_FIELDS (atype) = + (struct field *) obstack_alloc (symbol_obstack, + sizeof (struct field)); + TYPE_FIELD_TYPE (atype, 0) = range_type; + return atype; + } + case tqVol: return type; + case tqProc: return lookup_function_type(type); + default: + fprintf(stderr, "[Unimplemented type qualifier: %d]\n", qualifier); + return type; + } + } + + static struct type * + apply_type_modifiers(type, tip, auxp) + struct type *type; + TIR *tip; + AUXU** auxp; + { + for (;;) { + if (tip->tq0 == tqNil) return type; + type = modify_type(type, tip->tq0, auxp); + if (tip->tq1 == tqNil) return type; + type = modify_type(type, tip->tq1, auxp); + if (tip->tq2 == tqNil) return type; + type = modify_type(type, tip->tq2, auxp); + if (tip->tq3 == tqNil) return type; + type = modify_type(type, tip->tq3, auxp); + if (tip->tq4 == tqNil) return type; + type = modify_type(type, tip->tq4, auxp); + if (tip->tq5 == tqNil) return type; + type = modify_type(type, tip->tq5, auxp); + if (!tip->continued) return type; + tip++; + } + } + + static struct type * + read_type(index, widthp) + int index; + int *widthp; /* if non-NULL: set to (if bit field: width, else: 0) */ + { + TIR *tip; + AUXU *aux; + struct type *base_type; + int width; + if (index == 0xfffff) return builtin_type_int; /* no type info */ + /* if (index < 0 || index > ) ...; */ + + aux = &aux_symbol_table[cur_file_descriptor->iauxBase + index]; + tip = &aux->ti; + for ( ; aux->ti.continued; aux++) ; + aux++; /* skip last TIR field */ + + /* sym.h claims that width comes after RNDX, but seems to be wrong */ + width = tip->fBitfield ? (aux++)->width : 0; + if (widthp) *widthp = width; + + switch (tip->bt) { + case btVoid: + case btNil: base_type = builtin_type_void; break; + case btAdr: base_type = lookup_pointer_type(builtin_type_void); break; + case btChar: base_type = builtin_type_char; break; + case btUChar: base_type = builtin_type_unsigned_char; break; + case btShort: base_type = builtin_type_short; break; + case btUShort: base_type = builtin_type_unsigned_short; break; + case btInt: base_type = builtin_type_int; break; + case btUInt: base_type = builtin_type_unsigned_int; break; + case btLong: base_type = builtin_type_long; break; + case btULong: base_type = builtin_type_unsigned_long; break; + case btFloat: base_type = builtin_type_float; break; + case btDouble: base_type = builtin_type_double; break; + case btStruct: case btUnion: + base_type = read_struct_type(&aux, tip->bt); break; + case btEnum: + base_type = read_enum_type(&aux); break; + case btRange: + base_type = read_range_type(&aux); break; + case btTypedef: + case btSet: case btComplex: case btDComplex: + case btIndirect: + case btFixedDec: case btFloatDec: case btString: + case btBit: case btPicture: + default: + fprintf(stderr, "[Unimplemented kind of type: %d]\n", tip->bt); + base_type = builtin_type_void; + } + return apply_type_modifiers(base_type, tip, &aux); + } + + static struct symbol * + alloc_symbol(name, value) + char *name; + int value; + { + register struct symbol *sym; + sym = (struct symbol *)obstack_alloc (symbol_obstack, sizeof(struct symbol)); + #ifdef NAMES_HAVE_UNDERSCORE + if (name[0] == '_') name++; + #endif + + bzero (sym, sizeof (struct symbol)); + SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, name, strlen (name)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_TYPE (sym) = builtin_type_void; + + return sym; + } + + static + read_symbol(csym, name) + SYMR *csym; + char *name; + { + register struct symbol *sym = alloc_symbol(name, csym->value); + + switch (csym->st) + { + case stNil: break; + case stFile: + last_source_file = obstack_copy0 (symbol_obstack, name, strlen (name)); + break; + case stGlobal: + SYMBOL_TYPE (sym) = read_type(csym->index, NULL); + SYMBOL_CLASS (sym) = LOC_STATIC; + add_symbol_to_list (sym, &global_symbols); + break; + case stStatic: + SYMBOL_TYPE (sym) = read_type(csym->index, NULL); + SYMBOL_CLASS (sym) = LOC_STATIC; + if (within_function) { + /* Static symbol of local scope */ + add_symbol_to_list (sym, &local_symbols); + } + else { + /* Static symbol at top level of file */ + add_symbol_to_list (sym, &file_symbols); + } + break; + + case stLocal: + SYMBOL_TYPE (sym) = read_type(csym->index, NULL); + switch (csym->sc) { + case scRegister: SYMBOL_CLASS (sym) = LOC_REGISTER; break; + case scAbs: SYMBOL_CLASS (sym) = LOC_LOCAL; break; + + } + add_symbol_to_list (sym, &local_symbols); + break; + + case stParam: + SYMBOL_TYPE (sym) = read_type(csym->index, NULL); + switch (csym->sc) { + case scAbs: SYMBOL_CLASS (sym) = LOC_ARG; break; + case scRegister: SYMBOL_CLASS (sym) = LOC_REGPARM; break; + case scVar: SYMBOL_CLASS (sym) = LOC_REF_ARG; break; + case scVarRegister: SYMBOL_CLASS (sym) = LOC_REGPARM; break; /*WRONG!*/ + } + add_symbol_to_list (sym, &local_symbols); + break; + + case stTypedef: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_TYPE (sym) = read_type(csym->index, NULL); + if (within_function) { + /* Static symbol of local scope */ + add_symbol_to_list (sym, &local_symbols); + } + else { + /* Static symbol at top level of file */ + add_symbol_to_list (sym, &file_symbols); + } + break; + + case stEnd: + default: break; + } + return 1; + } + + static int + read_tagged_block (index) + { + SYMR *csym = &local_symbol_table[cur_isymBase+index]; + char *name = &local_string_table[cur_issBase+csym->iss]; + struct pending **symlist = within_function ? &local_symbols: &file_symbols; + register struct symbol *sym; + + /* A kludge to decide if this is an enum definition. */ + if ((csym[1].st == stMember + && read_type(csym[1].index, 0) == builtin_type_void) + || (csym->st == stBlockPatched + && TYPE_CODE((struct type*)(csym->value)) == TYPE_CODE_ENUM)) + { + struct type *type = get_enum_type (csym); + if (type && TYPE_CODE(type) == TYPE_CODE_ENUM) + { + int nfields = TYPE_NFIELDS (type); + register int i; + register struct field *cur_field = TYPE_FIELDS(type); + if (name && name[0] && name[0] != '.') + { + sym = alloc_symbol(name, 0); + SYMBOL_TYPE (sym) = type; + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + add_symbol_to_list (sym, symlist); + } + for (i = nfields; --i >= 0; cur_field++) + { + sym = alloc_symbol(cur_field->name, cur_field->bitpos); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_TYPE (sym) = type; + add_symbol_to_list (sym, symlist); + } + return nfields + 2; + } + } + else + { + if (name && name[0] && name[0] != '.') + { + struct type *type = get_struct_type (csym, btNil); + sym = alloc_symbol(name, 0); + SYMBOL_TYPE (sym) = type; + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + add_symbol_to_list (sym, symlist); + } + return read_symbols (index + 1) + 2; + } + } + + /* Read symbols until an stEnd symbol is encountered. Return count. */ + + static int + read_symbols(index) + int index; /* relative to current file */ + { + register struct context_stack *new; + static int blocks_seen = 0; + int index0 = index; + SYMR *start_symbol; + for (;;) + { + SYMR *csym = &local_symbol_table[cur_isymBase+index]; + char *name = &local_string_table[cur_issBase+csym->iss]; + + if (dump_stuff) + printf("[%s,%x,st%s,sc%s,inx:%d (%x)]\n", name, csym->value, + MapStNames[csym->st], MapScNames[csym->sc], + csym->index, csym); + + switch (csym->st) + { + case stFile: + last_source_file = + obstack_copy0 (symbol_obstack, name, strlen (name)); + index++; + index += read_symbols(index) + 1; + return index - index0; + case stBlock: + case stBlockPatched: + if (csym->sc == scText) + { /* lexical block */ + if (!local_symbol_table[cur_isymBase+csym->index-1].value) + { + new = 0; + } + else + { + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + new->next = context_stack; + context_stack = new; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = cur_proc_addr + csym->value; + new->name = 0; + local_symbols = 0; + } + blocks_seen++; + start_symbol=csym; + index++; + index += read_symbols (index); + csym = &local_symbol_table[cur_isymBase+index]; /* stEnd */ + index++; + + if (csym->st != stEnd || + start_symbol != &local_symbol_table[cur_isymBase+csym->index]) + abort(); + if (new) + { + if (local_symbols && context_stack->next) + { + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr, + cur_proc_addr + csym->value); + } + local_symbols = new->locals; + context_stack = new->next; + free (new); + } + } + else if (csym->sc == scInfo) + index += read_tagged_block (index); + break; + case stProc: + case stStaticProc: + { + PDR *proc = &proc_desc_table + [cur_file_descriptor->ipdFirst+cur_proc_number++]; + CORE_ADDR saved_cur_proc_addr = cur_proc_addr; + struct symbol *sym = alloc_symbol(name, csym->value); + struct context_stack *saved_context_stack = context_stack; + int save_blocks_seen = blocks_seen; + SYMBOL_CLASS (sym) = LOC_BLOCK; + /* Add one to csym->index, to the skip the isymMac value + * (which is there only for st*Proc). */ + SYMBOL_TYPE (sym) = + lookup_function_type (read_type(csym->index+1, NULL)); + if (csym->st == stStaticProc) + add_symbol_to_list (sym, &file_symbols); + else + add_symbol_to_list (sym, &global_symbols); + cur_proc_addr = csym->value; + within_function++; + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + new->next = 0; + context_stack = new; + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = csym->value; + new->name = sym; + if (dump_stuff) + printf("[PROC:%s,@%x,framereg:%d,froff:%d,rmsk:%d,fmsk:%d,floff:%d,regof ff:%d,iline:%d,lnLo:%d,lnHi:%d (%x)]\n", + name, proc->adr, + proc->framereg, proc->frameoffset, proc->regmask, + proc->fregmask, proc->fregoffset, + proc->regoffset, + proc->iline,proc->lnLow,proc->lnHigh, proc); + + start_symbol = csym; + index++; + index += read_symbols(index); + + csym = &local_symbol_table[cur_isymBase+index];/*stEnd symbol*/ + + if (csym->st != stEnd || + start_symbol != &local_symbol_table[cur_isymBase+csym->index]) + abort(); + + index++; + PROC_SYMBOL(proc) = + blocks_seen == save_blocks_seen ? NULL : sym; + PROC_LOW_ADDR(proc) = start_symbol->value; + PROC_HIGH_ADDR(proc) = last_end_addr = + start_symbol->value + csym->value; + + finish_block (new->name, &local_symbols, new->old_blocks, + start_symbol->value, last_end_addr); + context_stack = saved_context_stack; + cur_proc_addr = saved_cur_proc_addr; + within_function--; + free (new); + break; + } + + case stEnd: + #if 1 + return index - index0; + #else + start_symbol = &local_symbol_table[cur_isymBase+csym->index]; + switch (start_symbol->st) + { + case stProc: + case stStaticProc: + case stFile: + case stBlock: + case stBlockPatched: + return index - index0; + default: + index++; + } + break; + #endif + default: + read_symbol(csym, name); + index++; + } + } + } + + static int + read_coff_symtab (desc, nsyms, symtab_offset) + int desc; + int nsyms; + int symtab_offset; + { + HDRR hdrr; + struct coff_symbol coff_symbol; + register struct coff_symbol *cs = &coff_symbol; + struct coff_symbol fcn_cs_saved; + + int num_object_files = 0; + int next_file_symnum = -1; + char *filestring; + int fcn_first_line; + int fcn_last_line; + int fcn_start_addr; + long fcn_line_ptr; + struct cleanup *file_chain, *ext_chain, *old_chain; + int isym, ifile; + + char *line_number_table; + EXTR *external_symbol_table; + char *external_string_table; + struct linetable **line_vector_all; + + if (myread (desc, (char *)&hdrr, sizeof hdrr) != sizeof hdrr) + return -1; + + file_descriptor_count = hdrr.ifdMax; + line_vector_all = (struct linetable**) + alloca (file_descriptor_count * sizeof(struct linetable *)); + global_symbols_all = (struct pending**) + alloca (file_descriptor_count * sizeof(struct pending *)); + file_symbols_all = (struct pending**) + alloca (file_descriptor_count * sizeof(struct pending *)); + proc_desc_length = hdrr.ipdMax; + proc_desc_table = (PDR*) + read_table(desc, hdrr.ipdMax * sizeof(PDR), hdrr.cbPdOffset); + old_chain = make_cleanup (free_all_symtabs, 0); + make_cleanup (free_proc_descs, 0); + file_descriptor_table = (FDR*) + read_table(desc, hdrr.ifdMax * sizeof(FDR), hdrr.cbFdOffset); + file_chain = make_cleanup (free, file_descriptor_table); + + line_number_table = read_table(desc, hdrr.cbLine, hdrr.cbLineOffset); + ext_chain = make_cleanup (free, line_number_table); + + for (ifile = 0; ifile < hdrr.ifdMax; ifile++) + { + int iproc, ipdMax; + char *cur_line_entry; + int cur_addr_offset = 0; + int cur_addr; + + /* Vector of line number information. */ + struct linetable *line_vector; + + /* Index of next entry to go in line_vector_index. */ + int line_vector_index; + + /* Number of elements allocated for line_vector currently. */ + int line_vector_length; + + select_file (ifile); + global_symbols_all[ifile] = 0; + file_symbols_all[ifile] = 0; + + /* read line numbers */ + cur_addr = cur_file_descriptor->adr; + iproc = cur_file_descriptor->ipdFirst; + + line_vector_index = 0; + line_vector_length = 1000; + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + + line_vector_length * sizeof (struct linetable_entry)); + + /* we read the line numbers first, since read_symbol over-writes + some of the fields in a proc descriptor */ + ipdMax = iproc + cur_file_descriptor->cpd; + cur_line_entry = line_number_table + cur_file_descriptor->cbLineOffset; + for ( ; iproc < ipdMax; iproc++) { + PDR *proc = &proc_desc_table[iproc]; + int nlines = (iproc+1 < ipdMax ? (proc+1)->iline : cur_file_descriptor->cline) + - proc->iline; + int cur_source_line = proc->lnLow; + if (dump_stuff) + printf( + "[proc:%x,framereg:%d,ofset:%d,rmask:%d,flmask:%d,floff:%d,iline:%d,lnLo o:%d,lnHi:%d,csl:%d]\n", + proc->adr, + proc->framereg, proc->frameoffset, proc->regmask, + proc->fregmask, proc->fregoffset, + proc->iline,proc->lnLow,proc->lnHigh, cur_source_line); + if (proc->iline == -1) continue; + for (isym = proc->iline; nlines > 0; isym++) { + struct linetable_entry *e; + int code = *cur_line_entry++; + int delta = code >> 4; + int count = (code & 15) + 1; + if (dump_stuff & 1) printf("%2x", 0xFF & code); + if (delta == -8) + { + if (dump_stuff & 1) + printf(" %2x%2x", 0xff & cur_line_entry[0], + 0xff & cur_line_entry[1]); + delta = *cur_line_entry++; + delta = (delta << 8) | (unsigned)*cur_line_entry++; + isym += 2; + } + cur_source_line += delta; + if (dump_stuff & 1) + printf("\t%2d.%2d li:%d %X", delta, count, + cur_source_line, + cur_file_descriptor->adr + 4 * cur_addr_offset); + + e = &line_vector->item[line_vector_index]; + if (line_vector_index == 0 || e[-1].line != cur_source_line) + { + + /* Make sure line vector is big enough. */ + if (line_vector_index + 2 >= line_vector_length) + { + line_vector_length *= 2; + line_vector = (struct linetable *) + xrealloc (line_vector, sizeof (struct linetable) + + (line_vector_length + * sizeof (struct linetable_entry))); + e = &line_vector->item[line_vector_index]; + } + + e->line = cur_source_line; + e->pc = cur_file_descriptor->adr + 4 * cur_addr_offset; + line_vector_index++; + } + + if (delta != 0) + { + int save_addr = cur_addr; + if (cur_addr_offset != 0) + { + int toffset = (cur_addr_offset - 1) * 4; + if (dump_stuff & 1) + printf(" [li: %d %x-%x]", + cur_source_line, cur_addr, cur_addr+toffset); + } + cur_addr = save_addr + cur_addr_offset * 4; + } + cur_addr_offset += count; + nlines -= count; + if (dump_stuff & 1) putchar('\n'); + /* if (delta != 0) { } */ + } + } + + line_vector->nitems = line_vector_index; + line_vector_all[ifile] = (struct linetable *) + xrealloc (line_vector, (sizeof (struct linetable) + + line_vector_index * sizeof (struct linetable_entry))); + } + do_cleanups (ext_chain); + + aux_symbol_table = (AUXU*) + read_table(desc, hdrr.iauxMax * sizeof(AUXU), hdrr.cbAuxOffset); + make_cleanup (free, aux_symbol_table); + rel_file_table = (RFDT*) + read_table(desc, hdrr.crfd * sizeof(RFDT), hdrr.cbRfdOffset); + make_cleanup (free, rel_file_table); + local_symbol_table = (SYMR*) + read_table(desc, hdrr.isymMax * sizeof(SYMR), hdrr.cbSymOffset); + make_cleanup (free, local_symbol_table); + local_string_table = read_table(desc, hdrr.issMax, hdrr.cbSsOffset); + make_cleanup (free, local_string_table); + + external_symbol_table = (EXTR*) + read_table(desc, hdrr.iextMax * sizeof(EXTR), hdrr.cbExtOffset); + ext_chain = make_cleanup (free, external_symbol_table); + external_string_table = read_table(desc, hdrr.issExtMax, hdrr.cbSsExtOffset); + make_cleanup (free, external_string_table); + + /* do the external symbols first */ + /* The reason is that each file's end_symtab is done with the locals */ + + for (isym = 0; isym < hdrr.iextMax; isym++) + { + EXTR *ext = &external_symbol_table[isym]; + SYMR *csym = &ext->asym; + char *name = external_string_table+csym->iss; + if ((unsigned)ext->ifd >= hdrr.ifdMax) return -1; + select_file (ext->ifd); + record_misc_function (name, csym->value); + if (csym->st != stProc && csym->st != stStaticProc) + read_symbol(csym, name); + #if 1 + if (dump_stuff) + printf("EXT[%s,%x,st%s,sc%s,inx:%d,ifd:%d]\n", + name, csym->value, MapStNames[csym->st], + MapScNames[csym->sc], csym->index, ext->ifd); + #endif + } + + do_cleanups (ext_chain); + + for (ifile = 0; ifile < hdrr.ifdMax; ifile++) + { + select_file (ifile); + + cur_proc_number = 0; + last_end_addr = cur_file_descriptor->adr; + + start_symtab (); + + if (dump_stuff) + printf("<FILE.adr:%x,ilB:%d,cb:%d,cbLO:%d,cbL:%d,iSB:%d,cS:%d,nProcs:%d, ,first:%d>\n", + cur_file_descriptor->adr, + cur_file_descriptor->ilineBase, cur_file_descriptor->cline, + cur_file_descriptor->cbLineOffset, cur_file_descriptor->cbLine, + cur_isymBase, cur_file_descriptor->csym, + cur_file_descriptor->cpd, + cur_file_descriptor->ipdFirst); + + for (isym = 0; isym < cur_file_descriptor->csym; ) + { + int count = read_symbols(isym); + if (count == 0) + { /* handle un-handled stEnd */ + SYMR *sym = &local_symbol_table[cur_isymBase+isym]; + char *name = &local_string_table[cur_issBase+sym->iss]; + printf("stEnd confusion!"); + read_symbol(sym, name); + count = 1; + } + isym += count; + } + end_symtab (cur_file_descriptor->adr, last_end_addr, + line_vector_all[ifile]); + } + + do_cleanups (file_chain); + + last_source_file = 0; + bzero (opaque_type_chain, sizeof opaque_type_chain); + + type_vector_length = 160; + type_vector = (struct typevector *) + xmalloc (sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (type_vector->type, type_vector_length * sizeof (struct type *)); + + if (last_source_file) + end_symtab (); + discard_cleanups (old_chain); + return 0; + } + + /* Routines for reading headers and symbols from executable. */ + + /* Read COFF file header, check magic number, + and return number of symbols. */ + read_file_hdr (chan, file_hdr) + int chan; + FILHDR *file_hdr; + { + lseek (chan, 0L, 0); + if (myread (chan, (char *)file_hdr, FILHSZ) < 0) + return -1; + + switch (file_hdr->f_magic) + { + #ifdef MIPSEBMAGIC + case MIPSEBMAGIC: + #endif + #ifdef MIPSELMAGIC + case MIPSELMAGIC: + #endif + #ifdef MC68MAGIC + case MC68MAGIC: + #endif + #ifdef NS32GMAGIC + case NS32GMAGIC: + case NS32SMAGIC: + #endif + #ifdef I386MAGIC + case I386MAGIC: + #endif + #ifdef CLIPPERMAGIC + case CLIPPERMAGIC: + #endif + return file_hdr->f_nsyms; + + default: + #ifdef BADMAG + if (BADMAG(file_hdr)) + return -1; + else + return file_hdr->f_nsyms; + #else + return -1; + #endif + } + } + + read_aout_hdr (chan, aout_hdr, size) + int chan; + AOUTHDR *aout_hdr; + int size; + { + lseek (chan, (long)FILHSZ, 0); + if (size != sizeof (AOUTHDR)) + return -1; + if (myread (chan, (char *)aout_hdr, size) != size) + return -1; + return 0; + } + + read_section_hdr (chan, section_name, section_hdr, nsects) + register int chan; + register char *section_name; + SCNHDR *section_hdr; + register int nsects; + { + register int i; + + if (lseek (chan, FILHSZ + sizeof (AOUTHDR), 0) < 0) + return -1; + + for (i = 0; i < nsects; i++) + { + if (myread (chan, (char *)section_hdr, SCNHSZ) < 0) + return -1; + if (strncmp (section_hdr->s_name, section_name, 8) == 0) + return 0; + } + return -1; + } + + + /* Support for string table handling */ + + static char *stringtab = NULL; + + + #if 0 + static char * + getsymname (symbol_entry) + SYMENT *symbol_entry; + { + static char buffer[SYMNMLEN+1]; + char *result; + + if (symbol_entry->n_zeroes == 0) + { + result = stringtab + symbol_entry->n_offset; + } + else + { + strncpy (buffer, symbol_entry->n_name, SYMNMLEN); + buffer[SYMNMLEN] = '\0'; + result = buffer; + } + return result; + } + #endif + + /* Support for line number handling */ + static char *linetab = NULL; + static long linetab_offset; + static int linetab_count; + + static int + hashname (name) + char *name; + { + register char *p = name; + register int total = p[0]; + register int c; + + c = p[1]; + total += c << 2; + if (c) + { + c = p[2]; + total += c << 4; + if (c) + total += p[3] << 6; + } + + return total % HASHSIZE; + } + + static void + patch_type (type, real_type) + struct type *type; + struct type *real_type; + { + register struct type *target = TYPE_TARGET_TYPE (type); + register struct type *real_target = TYPE_TARGET_TYPE (real_type); + int field_size = TYPE_NFIELDS (real_target) * sizeof (struct field); + + TYPE_LENGTH (target) = TYPE_LENGTH (real_target); + TYPE_NFIELDS (target) = TYPE_NFIELDS (real_target); + TYPE_FIELDS (target) = (struct field *) + obstack_alloc (symbol_obstack, field_size); + + bcopy (TYPE_FIELDS (real_target), TYPE_FIELDS (target), field_size); + + if (TYPE_NAME (real_target)) + { + if (TYPE_NAME (target)) + free (TYPE_NAME (target)); + TYPE_NAME (target) = concat (TYPE_NAME (real_target), "", ""); + } + } + + /* Patch up all appropriate typdef symbols in the opaque_type_chains + so that they can be used to print out opaque data structures properly */ + + static void + patch_opaque_types () + { + struct symtab *s; + + /* Look at each symbol in the per-file block of each symtab. */ + for (s = symtab_list; s; s = s->next) + { + register struct block *b; + register int i; + + /* Go through the per-file symbols only */ + b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1); + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + register struct symbol *real_sym; + + /* Find completed typedefs to use to fix opaque ones. + Remove syms from the chain when their types are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ + real_sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF && + SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE && + TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (real_sym))) != 0) + { + register char *name = SYMBOL_NAME (real_sym); + register int hash = hashname (name); + register struct symbol *sym, *prev; + + prev = 0; + for (sym = opaque_type_chain[hash]; sym;) + { + if (name[0] == SYMBOL_NAME (sym)[0] && + !strcmp (name + 1, SYMBOL_NAME (sym) + 1)) + { + if (prev) + SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym); + else + opaque_type_chain[hash] + = (struct symbol *) SYMBOL_VALUE (sym); + + patch_type (SYMBOL_TYPE (sym), SYMBOL_TYPE (real_sym)); + + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = opaque_type_chain[hash]; + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + } + } + } + + /* This function is really horrible, but to avoid it, there would need + to be more filling in of forward references. THIS SHOULD BE MOVED + OUT OF COFFREAD.C AND DBXREAD.C TO SOME PLACE WHERE IT CAN BE SHARED. */ + int + fill_in_vptr_fieldno (type) + struct type *type; + { + if (TYPE_VPTR_FIELDNO (type) < 0) + TYPE_VPTR_FIELDNO (type) = + fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); + return TYPE_VPTR_FIELDNO (type); + } + + /* partial symbol tables are not implemented in coff, therefore + block_for_pc() (and others) will never decide to call this. */ + + extern struct symtab * + psymtab_to_symtab () + { + fatal ("error: Someone called psymtab_to_symtab\n"); + } + + /* These will stay zero all the time */ + struct psymbol_allocation_list global_psymbols, static_psymbols; *** munch.orig Wed Jul 5 15:46:28 1989 --- munch Mon Nov 5 10:28:33 1990 *************** *** 8,17 **** if test "$1" = "-DSYSV" ; then shift; nm $* | egrep '^(.*[^a-zA-Z_]_|_)initialize_' | \ sed -e 's/^.*\(_initialize_[a-zA-Z0-9_]*\)[^a-zA-Z0-9_].*$/ \1 ();/' else ! nm -p $* | egrep 'T *__initialize_' | \ sed -e 's/^.*T *_*\(.*\)/ _\1 ();/' fi echo '}' --- 8,17 ---- if test "$1" = "-DSYSV" ; then shift; nm $* | egrep '^(.*[^a-zA-Z_]_|_)initialize_' | \ sed -e 's/^.*\(_initialize_[a-zA-Z0-9_]*\)[^a-zA-Z0-9_].*$/ \1 ();/' else ! nm -p $* | egrep 'T *_?_initialize_' | \ sed -e 's/^.*T *_*\(.*\)/ _\1 ();/' fi echo '}' *** valops.c.orig Thu Dec 28 16:28:29 1989 --- valops.c Mon Nov 5 10:28:34 1990 *************** *** 653,662 **** --- 653,665 ---- struct_addr = sp; sp += TYPE_LENGTH (value_type); #endif } + #ifdef PUSH_ARGUMENTS + PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr); + #else /* !PUSH_ARGUMENTS */ for (i = nargs - 1; i >= 0; i--) sp = value_arg_push (sp, args[i]); #ifdef CALL_DUMMY_STACK_ADJUST #if 1 INNER_THAN 2 *************** *** 675,684 **** --- 678,688 ---- Also note that on some machines (like the sparc) pcc uses this convention in a slightly twisted way also. */ if (struct_return) STORE_STRUCT_RETURN (struct_addr, sp); + #endif /* !PUSH_ARGUMENTS */ /* Write the stack pointer. This is here because the statement above might fool with it */ write_register (SP_REGNUM, sp); *** valprint.c.orig Thu Feb 1 17:48:29 1990 --- valprint.c Mon Nov 5 10:28:35 1990 *************** *** 530,541 **** } else string[i++] = c; } ! if (i != 0) ! print_string (stream, string, i, force_ellipses); if (out_of_bounds) fprintf_filtered (stream, " <Address 0x%x out of bounds>", (*(int *) valaddr) + i); } --- 530,540 ---- } else string[i++] = c; } ! print_string (stream, string, i, force_ellipses); if (out_of_bounds) fprintf_filtered (stream, " <Address 0x%x out of bounds>", (*(int *) valaddr) + i); }
bush@evax.arl.utexas.edu (Joe Bush) (11/08/90)
Speaking of GNU's gdb and other such tools, does anyone know of a debugger that will run under Ultrix and allows the user to debug across a fork boundry. By that I mean, automatically suspend both the parent and child processes a the fork and allow the user to select, say, a child process and trace its source code. Perhaps stepping back and forth between the parent and child a will. We recently acquired a Sequent Symmetry with a parallel debugger called pdbx that allows this function. It is real handy. GNU's gdb has an "attach" function but it does seem to work under Ultrix 3.1 on a uVAX 3900. Is this a limitation of the debugger, the "ptrace" system call, or the underlying architecture? -- bush@evax.arl.utexas.edu Vax Systems Manager (817) 273 - 3333 CSE Dept. UT-Arlington Office Rm 221 EB2 403 South Cooper P.O. Box 19015 Arlington, Texas 76019