From: gdb-2.4+.aux.coff Date: Sat, 16 Jan 1988 04:39:57 +0000 (+0000) Subject: gdb-2.4+.aux.coff X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=7b4ac7e1ed2c;p=binutils-gdb.git gdb-2.4+.aux.coff --- 7b4ac7e1ed2c4616bce56d1760807798be87ac9e diff --git a/gdb/=emacs b/gdb/=emacs new file mode 100644 index 00000000000..74097b7ce93 --- /dev/null +++ b/gdb/=emacs @@ -0,0 +1,108 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; gdb code changes +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +/* + * Core Problem: when gdb says something like (../src/file.c 1234), the + * real file might be in any of the active dirs in use by gdb and thus + * emacs can not always find the file at "../src". Emacs cannot just + * scan for GDB dir commands because these might be given in the .gdbinit + * file or other scripts. The only solution is to have gdb be a bit more + * specific when it prints file names. + * + * Remaining defects: + * + * 1. Do I really have to open the file to find out if it exists? + * There should be a faster way. + * + * 2. Should there be a bdb command to toggle between short and absolute + * forms of the file name? + */ + + +/* Add this to ~emacs/gdb/source.c after the openp function */ + +char * +get_absolute_filename(table) +/* Added by Lynn Slater, Silvar-Lisco 10/6/87 + returns the address of the best possible name to use for the file + in the passed symtab. Returns the filename if the path cannot be + resolved. + Please remember to free the absolute name after use.*/ +struct symtab *table; +{ + register int desc; + char *absolute_name; + + desc = openp (source_path, 0, table->filename, O_RDONLY, 0, &absolute_name); + if (desc < 0) + return( savestring(table->filename, strlen(table->filename))); + + close (desc); + return(absolute_name); +} + +/* Replace this fcn in ~emacs/gdb/stack.c */ +void +print_frame_info (fi, level, source, args) + struct frame_info *fi; + register int level; + int source; + int args; +{ + register FRAME frame = fi->frame; + struct symtab_and_line sal; + struct symbol *func; + register char *funname = 0; + int numargs; + + sal = find_pc_line (fi->pc, fi->next_frame); + func = get_frame_function (frame); + if (func) + funname = SYMBOL_NAME (func); + else + { + register int misc_index = find_pc_misc_function (fi->pc); + if (misc_index >= 0) + funname = misc_function_vector[misc_index].name; + } + + if (source >= 0 || !sal.symtab) + { + /* This avoids a bug in cc on the sun. */ + struct frame_info tem; + tem = *fi; + + if (level >= 0) + printf ("#%-2d ", level); + if (fi->pc != sal.pc || !sal.symtab) + printf ("0x%x in ", fi->pc); + printf ("%s (", funname ? funname : "??"); + if (args) + { + FRAME_NUM_ARGS (numargs, tem); + print_frame_args (func, FRAME_ARGS_ADDRESS (tem), numargs, stdout); + } + printf (")"); + if (sal.symtab) + { + char * absolute_filename; + absolute_filename = (char *) get_absolute_filename(sal.symtab); + printf (" (%s line %d)", absolute_filename, sal.line); + free(absolute_filename); + } + printf ("\n"); + } + + if (source != 0 && sal.symtab) + { + if (source < 0 && fi->pc != sal.pc) + printf ("0x%x\t", fi->pc); + print_source_lines (sal.symtab, sal.line, sal.line + 1); + current_source_line = max (sal.line - 5, 1); + } + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + fflush (stdout); +} + diff --git a/gdb/=news b/gdb/=news new file mode 100644 index 00000000000..43de9bc713f --- /dev/null +++ b/gdb/=news @@ -0,0 +1,136 @@ +=================================================================== +RCS file: RCS/printcmd.c,v +retrieving revision 1.1 +diff -c3 -r1.1 printcmd.c +*** /tmp/,RCSt1011248 Tue Jan 12 14:06:06 1988 +--- printcmd.c Mon Sep 21 21:33:39 1987 +*************** +*** 174,179 + VALUE_TYPE (val) = builtin_type_float; + if (TYPE_LENGTH (VALUE_TYPE (val)) == sizeof (double)) + VALUE_TYPE (val) = builtin_type_double; + printf ("%g", value_as_double (val)); + break; + + +--- 174,185 ----- + VALUE_TYPE (val) = builtin_type_float; + if (TYPE_LENGTH (VALUE_TYPE (val)) == sizeof (double)) + VALUE_TYPE (val) = builtin_type_double; ++ #ifdef PRINTF_BUG ++ if (is_nan(value_as_double (val))) ++ printf ("Nan"); ++ else ++ printf ("%g", value_as_double (val)); ++ #else + printf ("%g", value_as_double (val)); + #endif + break; +*************** +*** 175,180 + if (TYPE_LENGTH (VALUE_TYPE (val)) == sizeof (double)) + VALUE_TYPE (val) = builtin_type_double; + printf ("%g", value_as_double (val)); + break; + + case 0: + +--- 181,187 ----- + printf ("%g", value_as_double (val)); + #else + printf ("%g", value_as_double (val)); ++ #endif + break; + + case 0: +=================================================================== +RCS file: RCS/valprint.c,v +retrieving revision 1.1 +diff -c3 -r1.1 valprint.c +*** /tmp/,RCSt1011248 Tue Jan 12 14:06:09 1988 +--- valprint.c Mon Sep 21 21:35:45 1987 +*************** +*** 21,26 + #include + #include "defs.h" + #include "initialize.h" + #include "symtab.h" + #include "value.h" + + +--- 21,27 ----- + #include + #include "defs.h" + #include "initialize.h" ++ #include "param.h" + #include "symtab.h" + #include "value.h" + +*************** +*** 249,255 + break; + + case TYPE_CODE_FLT: +! fprintf (stream, "%g", unpack_double (type, valaddr)); + break; + + case TYPE_CODE_VOID: + +--- 250,265 ----- + break; + + case TYPE_CODE_FLT: +! { double d = unpack_double (type, valaddr); +! #ifdef PRINTF_BUG +! if (is_nan(d)) +! fprintf (stream, "Nan"); +! else +! fprintf (stream, "%g", d); +! #else +! fprintf (stream, "%g", d); +! #endif +! } + break; + + case TYPE_CODE_VOID: +*************** +*** 559,563 + float_type_table[sizeof (float)] = "float"; + float_type_table[sizeof (double)] = "double"; + } + + END_FILE + +--- 569,599 ----- + float_type_table[sizeof (float)] = "float"; + float_type_table[sizeof (double)] = "double"; + } ++ ++ ++ #ifdef PRINTF_BUG ++ ++ struct ieee { /* IEEE floating format */ ++ unsigned int s:1; ++ unsigned int e:11; ++ unsigned int f1:20; ++ unsigned int f2; ++ }; ++ ++ #define ZERO_F(x) ((x.f1 == 0) && (x.f2 == 0)) /* zero fraction ? */ ++ #define ZERO_E(x) (x.e == 0) /* zero exponential ? */ ++ #define MAX_E(x) (x.e == 0x7ff) /* max exponential ? */ ++ #define MINUS_S(x) (x.s == 1) /* minus ? */ ++ ++ int ++ is_nan(arg) /* Not a Number ? */ ++ struct ieee arg; ++ { ++ if (MAX_E(arg) && !ZERO_F(arg)) ++ return (1); ++ else ++ return (0); ++ } ++ #endif + + END_FILE + diff --git a/gdb/=ns32k.msg b/gdb/=ns32k.msg new file mode 100644 index 00000000000..5268fc72ae5 --- /dev/null +++ b/gdb/=ns32k.msg @@ -0,0 +1,1182 @@ +From uwvax!sequent!ogcvax!reed!keith@RUTGERS.EDU Thu Jul 23 21:46:44 1987 +Received: by PREP.AI.MIT.EDU; Thu, 23 Jul 87 21:44:35 EDT +Received: by RUTGERS.EDU (5.54/1.14) with UUCP + id AA04584; Thu, 23 Jul 87 21:42:33 EDT +Received: from sequent.UUCP by spool.WISC.EDU; Thu, 23 Jul 87 20:36:20 CDT +Received: from reed.UUCP by ogcvax.OGC.EDU (5.51/OGC_4.6+) + id AA05332; Thu, 23 Jul 87 13:31:52 PDT +Received: by reed.UUCP (5.51/5.17) + id AA23265; Thu, 23 Jul 87 11:19:20 PDT +From: uwvax!sequent!ogcvax!reed!keith@RUTGERS.EDU (Keith Packard) +Message-Id: <8707231819.AA23265@reed.UUCP> +To: phr@prep.ai.mit.edu (Paul Rubin) +Subject: Re: gdb +In-Reply-To: Your message of Thu, 23 Jul 87 02:06:52 EDT. + <8707230603.AA11722@EDDIE.MIT.EDU> +Date: Thu, 23 Jul 87 11:19:13 PDT +Status: R + + +Thanks much for the address -- the 2.1 sources that I have do not contain +any bug reporting address. The only real bug that I found was in +write_register_bytes in findvar.c: + +was: + + bcopy (myaddr, ®isters[regbyte], len); + if (have_inferior_p ()) + store_inferior_registers (0); + +should be: + + bcopy (myaddr, ®isters[regbyte], len); + if (have_inferior_p ()) + store_inferior_registers (-1); + +Other than that, most of the porting effort to the 32k was in removing +references to alloca - the 32k is adamant about not using alloca -- in fact +someone at tektronix wrote a replacement which accepted another argument +pointing to the function entry instruction so that the stack could be maimed +mercilessly... I just replaced them all with malloc and used free at +judicious times. It's not perfect but it worked fine. + +I would upload gdb 2.3 if I could, however I am not on the arpa net. I'll +probably end up sending GNU a tape. + +It's a great debugger, thanks! + + keith packard + tektronix!reed!keith + +Here are the param files and instruction printer for the 32032: + +#!/bin/sh +# shar: Shell Archiver +# Run the following text with /bin/sh to create: +# m-merlin.h +# n32k-opcode.h +# n32k-pinsn.c +sed 's/^X//' << 'SHAR_EOF' > m-merlin.h +X/* Definitions to make GDB run on a merlin under utek 2.1 +X Copyright (C) 1986, 1987 Free Software Foundation, Inc. +X +XGDB is distributed in the hope that it will be useful, but WITHOUT ANY +XWARRANTY. No author or distributor accepts responsibility to anyone +Xfor the consequences of using it or for whether it serves any +Xparticular purpose or works at all, unless he says so in writing. +XRefer to the GDB General Public License for full details. +X +XEveryone is granted permission to copy, modify and redistribute GDB, +Xbut only under the conditions described in the GDB General Public +XLicense. A copy of this license is supposed to have been given to you +Xalong with GDB so you can know your rights and responsibilities. It +Xshould be in a file named COPYING. Among other things, the copyright +Xnotice and this notice must be preserved on all copies. +X +XIn other words, go ahead and share GDB, but don't try to stop +Xanyone else from sharing it farther. Help stamp out software hoarding! +X*/ +X +X#ifndef ns16000 +X#define ns16000 +X#endif +X +X# include +X +X/* Define this if the C compiler puts an underscore at the front +X of external names before giving them to the linker. */ +X +X#define NAMES_HAVE_UNDERSCORE +X +X/* Offset from address of function to start of its code. +X Zero on most machines. */ +X +X#define FUNCTION_START_OFFSET 0 +X +X/* Advance PC across any function entry prologue instructions +X to reach some "real" code. */ +X +X#define SKIP_PROLOGUE(pc) \ +X{ register int op = read_memory_integer (pc, 1); \ +X if (op == 0x82) { op = read_memory_integer (pc+2,1); \ +X if ((op & 0x80) == 0) pc += 3; \ +X else if ((op & 0xc0) == 0x80) pc += 4; \ +X else pc += 6; \ +X } \ +X} +X +X/* Immediately after a function call, return the saved pc. +X Can't always go through the frames for this because on some machines +X the new frame is not set up until the new function executes +X some instructions. */ +X +X#define SAVED_PC_AFTER_CALL(frame) \ +X read_memory_integer (read_register (SP_REGNUM), 4) +X +X/* This is the amount to subtract from u.u_ar0 +X to get the offset in the core file of the register values. */ +X +X#define KERNEL_U_ADDR (0xfef000) +X +X/* Address of end of stack space. */ +X +X#define STACK_END_ADDR (0x800000) +X +X/* Stack grows downward. */ +X +X#define INNER_THAN < +X +X/* Sequence of bytes for breakpoint instruction. */ +X +X#define BREAKPOINT {0xf2} +X +X/* Amount PC must be decremented by after a breakpoint. +X This is often the number of bytes in BREAKPOINT +X but not always. */ +X +X#define DECR_PC_AFTER_BREAK 0 +X +X/* Nonzero if instruction at PC is a return instruction. */ +X +X#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0x12) +X +X/* Return 1 if P points to an invalid floating point value. */ +X +X#define INVALID_FLOAT(p) (0) +X +X/* Say how long (ordinary) registers are. */ +X +X#define REGISTER_TYPE long +X +X/* Number of machine registers */ +X +X#define NUM_REGS 25 +X +X#define NUM_GENERAL_REGS 8 +X +X/* Initializer for an array of names of registers. +X There should be NUM_REGS strings in this initializer. */ +X +X#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ +X "pc", "sp", "fp", "ps", \ +X "fsr", \ +X "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ +X "l0", "l1", "l2", "l3", "l4", \ +X } +X +X/* Register numbers of various important registers. +X Note that some of these values are "real" register numbers, +X and correspond to the general registers of the machine, +X and some are "phony" register numbers which are too large +X to be actual register numbers as far as the user is concerned +X but do serve to get the desired values when passed to read_register. */ +X +X#define AP_REGNUM FP_REGNUM +X#define FP_REGNUM 10 /* Contains address of executing stack frame */ +X#define SP_REGNUM 9 /* Contains address of top of stack */ +X#define PC_REGNUM 8 /* Contains program counter */ +X#define PS_REGNUM 11 /* Contains processor status */ +X#define FPS_REGNUM 12 /* Floating point status register */ +X#define FP0_REGNUM 13 /* Floating point register 0 */ +X#define LP0_REGNUM 21 /* Double register 0 (same as FP0) */ +X +X#define REGISTER_U_ADDR(addr, blockend, regno) \ +X{ \ +X switch (regno) { \ +X case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: \ +X addr = blockend + (R0 - regno) * sizeof (int); break; \ +X case PC_REGNUM: \ +X addr = blockend + PC * sizeof (int); break; \ +X case SP_REGNUM: \ +X addr = blockend + SP * sizeof (int); break; \ +X case FP_REGNUM: \ +X addr = blockend + FP * sizeof (int); break; \ +X case PS_REGNUM: \ +X addr = blockend + 12 * sizeof (int); break; \ +X case FPS_REGNUM: \ +X addr = 108; break; \ +X case FP0_REGNUM + 0: case FP0_REGNUM + 1: \ +X case FP0_REGNUM + 2: case FP0_REGNUM + 3: \ +X case FP0_REGNUM + 4: case FP0_REGNUM + 5: \ +X case FP0_REGNUM + 6: case FP0_REGNUM + 7: \ +X addr = 76 + (regno - FP0_REGNUM) * sizeof (float); break; \ +X case LP0_REGNUM + 0: case LP0_REGNUM + 1: \ +X case LP0_REGNUM + 2: case LP0_REGNUM + 3: \ +X addr = 76 + (regno - LP0_REGNUM) * sizeof (double); break; \ +X default: \ +X printf ("bad argument to REGISTER_U_ADDR %d\n", regno); \ +X abort (); \ +X } \ +X} +X +X/* Total amount of space needed to store our copies of the machine's +X register state, the array `registers'. */ +X#define REGISTER_BYTES ((NUM_REGS - 4) * sizeof (int) + 4 * sizeof (double)) +X +X/* Index within `registers' of the first byte of the space for +X register N. */ +X +X#define REGISTER_BYTE(N) ((N) >= LP0_REGNUM ? \ +X LP0_REGNUM * 4 + ((N) - LP0_REGNUM) * 8 : (N) * 4) +X +X/* Number of bytes of storage in the actual machine representation +X for register N. On the 32000, all regs are 4 bytes +X except for the doubled floating registers. */ +X +X#define REGISTER_RAW_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) +X +X/* Number of bytes of storage in the program's representation +X for register N. On the 32000, all regs are 4 bytes +X except for the doubled floating registers. */ +X +X#define REGISTER_VIRTUAL_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) +X +X/* Largest value REGISTER_RAW_SIZE can have. */ +X +X#define MAX_REGISTER_RAW_SIZE 8 +X +X/* Largest value REGISTER_VIRTUAL_SIZE can have. */ +X +X#define MAX_REGISTER_VIRTUAL_SIZE 8 +X +X/* Nonzero if register N requires conversion +X from raw format to virtual format. */ +X +X#define REGISTER_CONVERTIBLE(N) 0 +X +X/* Convert data from raw format for register REGNUM +X to virtual format for register REGNUM. */ +X +X#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +X bcopy ((FROM), (TO), REGISTER_VIRTUAL_SIZE(REGNUM)); +X +X/* Convert data from virtual format for register REGNUM +X to raw format for register REGNUM. */ +X +X#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +X bcopy ((FROM), (TO), REGISTER_VIRTUAL_SIZE(REGNUM)); +X +X/* Return the GDB type object for the "standard" data type +X of data in register N. */ +X +X#define REGISTER_VIRTUAL_TYPE(N) \ +X ((N) >= FP0_REGNUM ? \ +X (N) >= LP0_REGNUM ? \ +X builtin_type_double \ +X : builtin_type_float \ +X : builtin_type_int) +X +X/* Describe the pointer in each stack frame to the previous stack frame +X (its caller). */ +X +X/* FRAME_CHAIN takes a frame's nominal address +X and produces the frame's chain-pointer. +X +X FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address +X and produces the nominal address of the caller frame. +X +X However, if FRAME_CHAIN_VALID returns zero, +X it means the given frame is the outermost one and has no caller. +X In that case, FRAME_CHAIN_COMBINE is not used. */ +X +X/* In the case of the Merlin, the frame's nominal address is the FP value, +X and at that address is saved previous FP value as a 4-byte word. */ +X +X#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) +X +X#define FRAME_CHAIN_VALID(chain, thisframe) \ +X (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) +X +X#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) +X +X/* Define other aspects of the stack frame. */ +X +X#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) +X +X/* compute base of arguments */ +X#define FRAME_ARGS_ADDRESS(fi) ((fi).frame) +X +X#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame) +X +X/* Return number of args passed to a frame. +X Can return -1, meaning no way to tell. */ +X +X#define FRAME_NUM_ARGS(numargs, fi) \ +X{ CORE_ADDR pc; \ +X int insn; \ +X int addr_mode; \ +X int width; \ +X \ +X pc = FRAME_SAVED_PC (fi.frame); \ +X insn = read_memory_integer (pc,2); \ +X addr_mode = (insn >> 11) & 0x1f; \ +X insn = insn & 0x7ff; \ +X if ((insn & 0x7fc) == 0x57c && \ +X addr_mode == 0x14) { /* immediate */ \ +X if (insn == 0x57c) /* adjspb */ \ +X width = 1; \ +X else if (insn == 0x57d) /* adjspw */ \ +X width = 2; \ +X else if (insn == 0x57f) /* adjspd */ \ +X width = 4; \ +X numargs = read_memory_integer (pc+2,width); \ +X if (width > 1) \ +X flip_bytes (&numargs, width); \ +X numargs = - sign_extend (numargs, width*8) / 4; \ +X } else { \ +X numargs = -1; \ +X } \ +X} +X +X/* Return number of bytes at start of arglist that are not really args. */ +X +X#define FRAME_ARGS_SKIP 8 +X +X/* Put here the code to store, into a struct frame_saved_regs, +X the addresses of the saved registers of frame described by FRAME_INFO. +X This includes special registers such as pc and fp saved in special +X ways in the stack frame. sp is even more special: +X the address we return for it IS the sp for the next frame. */ +X +X#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +X{ \ +X int regmask,regnum; \ +X int localcount; \ +X CORE_ADDR enter_addr; \ +X CORE_ADDR next_addr; \ +X \ +X enter_addr = get_pc_function_start ((frame_info).pc); \ +X regmask = read_memory_integer (enter_addr+1, 1); \ +X localcount = n32k_localcount (enter_addr); \ +X next_addr = (frame_info).frame + localcount; \ +X for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ +X (frame_saved_regs).regs[regnum] = (regmask & 1) ? \ +X (next_addr -= 4) : 0; \ +X (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4; \ +X (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +X (frame_saved_regs).regs[FP_REGNUM] = (read_memory_integer \ +X ((frame_info).frame, 4)); \ +X} +X +X/* Things needed for making the inferior call functions. */ +X +X/* Push an empty stack frame, to record the current PC, etc. */ +X +X#define PUSH_DUMMY_FRAME \ +X{ register CORE_ADDR sp = read_register (SP_REGNUM);\ +X register int regnum; \ +X sp = push_word (sp, read_register (PC_REGNUM)); \ +X sp = push_word (sp, read_register (FP_REGNUM)); \ +X write_register (FP_REGNUM, sp); \ +X for (regnum = 0; regnum < 8; regnum++) \ +X sp = push_word (sp, read_register (regnum)); \ +X write_register (SP_REGNUM, sp); \ +X} +X +X/* Discard from the stack the innermost frame, restoring all registers. */ +X +X#define POP_FRAME \ +X{ register CORE_ADDR fp = read_register (FP_REGNUM); \ +X register int regnum; \ +X struct frame_saved_regs fsr; \ +X struct frame_info fi; \ +X fi = get_frame_info (fp); \ +X get_frame_saved_regs (&fi, &fsr); \ +X for (regnum = 0; regnum < 8; regnum++) \ +X if (fsr.regs[regnum]) \ +X write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ +X write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ +X write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ +X write_register (SP_REGNUM, fp + 8); \ +X} +X +X/* This sequence of words is the instructions +X enter 0xff,0 82 ff 00 +X jsr @0x00010203 7f ae c0 01 02 03 +X adjspd 0x69696969 7f a5 01 02 03 04 +X bpt f2 +X Note this is 16 bytes. */ +X +X#define CALL_DUMMY { 0x7f00ff82, 0x0201c0ae, 0x01a57f03, 0xf2040302 } +X +X#define CALL_DUMMY_START_OFFSET 3 +X#define CALL_DUMMY_LENGTH 16 +X#define CALL_DUMMY_ADDR 5 +X#define CALL_DUMMY_NARGS 11 +X +X/* Insert the specified number of args and function address +X into a call sequence of the above form stored at DUMMYNAME. */ +X +X#define FIX_CALL_DUMMY(dummyname, fun, nargs) \ +X{ \ +X int flipped; \ +X flipped = fun | 0xc0000000; \ +X flip_bytes (&flipped, 4); \ +X *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ +X flipped = - nargs * 4; \ +X flip_bytes (&flipped, 4); \ +X *((int *) (((char *) dummyname)+CALL_DUMMY_NARGS)) = flipped; \ +X} +X +X#ifdef notdef +X/* Interface definitions for kernel debugger KDB. */ +X +X/* Map machine fault codes into signal numbers. +X First subtract 0, divide by 4, then index in a table. +X Faults for which the entry in this table is 0 +X are not handled by KDB; the program's own trap handler +X gets to handle then. */ +X +X#define FAULT_CODE_ORIGIN 0 +X#define FAULT_CODE_UNITS 4 +X#define FAULT_TABLE \ +X{ 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ +X 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ +X 0, 0, 0, 0, 0, 0, 0, 0} +X +X/* Start running with a stack stretching from BEG to END. +X BEG and END should be symbols meaningful to the assembler. +X This is used only for kdb. */ +X +X#define INIT_STACK(beg, end) \ +X{ asm (".globl end"); \ +X asm ("movl $ end, sp"); \ +X asm ("clrl fp"); } +X +X/* Push the frame pointer register on the stack. */ +X#define PUSH_FRAME_PTR \ +X asm ("pushl fp"); +X +X/* Copy the top-of-stack to the frame pointer register. */ +X#define POP_FRAME_PTR \ +X asm ("movl (sp), fp"); +X +X/* After KDB is entered by a fault, push all registers +X that GDB thinks about (all NUM_REGS of them), +X so that they appear in order of ascending GDB register number. +X The fault code will be on the stack beyond the last register. */ +X +X#define PUSH_REGISTERS \ +X{ asm ("pushl 8(sp)"); \ +X asm ("pushl 8(sp)"); \ +X asm ("pushal 0x14(sp)"); \ +X asm ("pushr $037777"); } +X +X/* Assuming the registers (including processor status) have been +X pushed on the stack in order of ascending GDB register number, +X restore them and return to the address in the saved PC register. */ +X +X#define POP_REGISTERS \ +X{ asm ("popr $037777"); \ +X asm ("subl2 $8,(sp)"); \ +X asm ("movl (sp),sp"); \ +X asm ("rei"); } +X#endif +SHAR_EOF +sed 's/^X//' << 'SHAR_EOF' > n32k-opcode.h +X/* n32k-opcode.h */ +X +X#ifndef n32k_opcodeT +X#define n32k_opcodeT int +X#endif /* no n32k_opcodeT */ +X +Xstruct not_wot /* n32k opcode table: wot to do with this */ +X /* particular opcode */ +X{ +X int obits; /* number of opcode bits */ +X int ibits; /* number of instruction bits */ +X n32k_opcodeT code; /* op-code (may be > 8 bits!) */ +X char *args; /* how to compile said opcode */ +X}; +X +Xstruct not /* n32k opcode text */ +X{ +X char * name; /* opcode name: lowercase string [key] */ +X struct not_wot detail; /* rest of opcode table [datum] */ +X}; +X +X/* F : 32 bit float +X * L : 64 bit float +X * B : byte +X * W : word +X * D : double-word +X * Q : quad-word +X * d : displacement +X * q : quick +X * i : immediate (8 bits) +X * r : register number (3 bits) +X * p : displacement - pc relative addressing +X*/ +Xstatic struct not +Xnotstrs[] = +X{ +X{ "absf", 14,24, 0x35be, "1F2F" }, +X{ "absl", 14,24, 0x34be, "1L2L" }, +X{ "absb", 14,24, 0x304e, "1B2B" }, +X{ "absw", 14,24, 0x314e, "1W2W" }, +X{ "absd", 14,24, 0x334e, "1D2D" }, +X{ "acbb", 7,16, 0x4c, "2B1q3p" }, +X{ "addf", 14,24, 0x01be, "1F2F" }, +X{ "addl", 14,24, 0x00be, "1L2L" }, +X{ "addb", 6,16, 0x00, "1B2B" }, +X{ "addw", 6,16, 0x01, "1W2W" }, +X{ "addd", 6,16, 0x03, "1D2D" }, +X{ "addcb", 6,16, 0x10, "1B2B" }, +X{ "addcw", 6,16, 0x11, "1W2W" }, +X{ "addcd", 6,16, 0x13, "1D2D" }, +X{ "addpb", 14,24, 0x3c4e, "1B2B" }, +X{ "addpw", 14,24, 0x3d4e, "1W2W" }, +X{ "addpd", 14,24, 0x3f4e, "1D2D" }, +X{ "addqb", 7,16, 0x0c, "2B1q" }, +X{ "addqw", 7,16, 0x0d, "2W1q" }, +X{ "addqd", 7,16, 0x0f, "2D1q" }, +X{ "addr", 6,16, 0x27, "1D2D" }, +X{ "adjspb", 11,16, 0x057c, "1B" }, +X{ "adjspw", 11,16, 0x057d, "1W" }, +X{ "adjspd", 11,16, 0x057f, "1D" }, +X{ "andb", 6,16, 0x28, "1B2B" }, +X{ "andw", 6,16, 0x29, "1W2W" }, +X{ "andd", 6,16, 0x2b, "1D2D" }, +X{ "ashb", 14,24, 0x044e, "1B2B" }, +X{ "ashw", 14,24, 0x054e, "1B2W" }, +X{ "ashd", 14,24, 0x074e, "1B2D" }, +X{ "beq", 8,8, 0x0a, "1p" }, +X{ "bne", 8,8, 0x1a, "1p" }, +X{ "bcs", 8,8, 0x2a, "1p" }, +X{ "bcc", 8,8, 0x3a, "1p" }, +X{ "bhi", 8,8, 0x4a, "1p" }, +X{ "bls", 8,8, 0x5a, "1p" }, +X{ "bgt", 8,8, 0x6a, "1p" }, +X{ "ble", 8,8, 0x7a, "1p" }, +X{ "bfs", 8,8, 0x8a, "1p" }, +X{ "bfc", 8,8, 0x9a, "1p" }, +X{ "blo", 8,8, 0xaa, "1p" }, +X{ "bhs", 8,8, 0xba, "1p" }, +X{ "blt", 8,8, 0xca, "1p" }, +X{ "bge", 8,8, 0xda, "1p" }, +X{ "bicb", 6,16, 0x08, "1B2B" }, +X{ "bicw", 6,16, 0x09, "1W2W" }, +X{ "bicd", 6,16, 0x0b, "1D2D" }, +X{ "bicpsrb", 11,16, 0x17c, "1B" }, +X{ "bicpsrw", 11,16, 0x17d, "1W" }, +X{ "bispsrb", 11,16, 0x37c, "1B" }, +X{ "bispsrw", 11,16, 0x37d, "1W" }, +X{ "bpt", 8,8, 0xf2, "" }, +X{ "br", 8,8, 0xea, "1p" }, +X{ "bsr", 8,8, 0x02, "1p" }, +X{ "caseb", 11,16, 0x77c, "1B" }, +X{ "casew", 11,16, 0x77d, "1W" }, +X{ "cased", 11,16, 0x77f, "1D" }, +X{ "cbitb", 14,24, 0x084e, "1B2D" }, +X{ "cbitw", 14,24, 0x094e, "1W2D" }, +X{ "cbitd", 14,24, 0x0b4e, "1D2D" }, +X{ "cbitib", 14,24, 0x0c4e, "1B2D" }, +X{ "cbitiw", 14,24, 0x0d4e, "1W2D" }, +X{ "cbitid", 14,24, 0x0f4e, "1D2D" }, +X{ "checkb", 11,24, 0x0ee, "2A3B1r" }, +X{ "checkw", 11,24, 0x1ee, "2A3B1r" }, +X{ "checkd", 11,24, 0x3ee, "2A3D1r" }, +X{ "cmpf", 14,24, 0x09be, "1F2F" }, +X{ "cmpl", 14,24, 0x08be, "1L2L" }, +X{ "cmpb", 6,16, 0x04, "1B2B" }, +X{ "cmpw", 6,16, 0x05, "1W2W" }, +X{ "cmpd", 6,16, 0x07, "1D2D" }, +X{ "cmpmb", 14,24, 0x04ce, "1D2D3d" }, +X{ "cmpmw", 14,24, 0x05ce, "1D2D3d" }, +X{ "cmpmd", 14,24, 0x07ce, "1D2D3d" }, +X{ "cmpqb", 7,16, 0x1c, "2B1q" }, +X{ "cmpqw", 7,16, 0x1d, "2W1q" }, +X{ "cmpqd", 7,16, 0x1f, "2D1q" }, +X{ "cmpsb", 16,16, 0x040e, "i" }, +X{ "cmpsw", 16,16, 0x050e, "i" }, +X{ "cmpsd", 16,16, 0x070e, "i" }, +X{ "cmpst", 16,16, 0x840e, "i" }, +X{ "comb", 14,24, 0x344e, "1B2B" }, +X{ "comw", 14,24, 0x354e, "1W2W" }, +X{ "comd", 14,24, 0x374e, "1D2D" }, +X{ "cvtp", 11,24, 0x036e, "2D3D1r" }, +X{ "cxp", 8,8, 0x22, "1p" }, +X{ "cxpd", 11,16, 0x07f, "1D" }, +X{ "deib", 14,24, 0x2cce, "1B2W" }, +X{ "deiw", 14,24, 0x2cce, "1W2D" }, +X{ "deid", 14,24, 0x2cce, "1D2Q" }, +X{ "dia", 8,8, 0xc2, "" }, +X{ "divf", 14,24, 0x21be, "1F2F" }, +X{ "divl", 14,24, 0x20be, "1L2L" }, +X{ "divb", 14,24, 0x3cce, "1B2B" }, +X{ "divw", 14,24, 0x3dce, "1W2W" }, +X{ "divd", 14,24, 0x3fce, "1D2D" }, +X{ "enter", 8,8, 0x82, "1i2d" }, +X{ "exit", 8,8, 0x92, "1i" }, +X{ "extb", 11,24, 0x02e, "2D3B1r4d" }, +X{ "extw", 11,24, 0x12e, "2D3W1r4d" }, +X{ "extd", 11,24, 0x32e, "2D3D1r4d" }, +X{ "extsb", 14,24, 0x0cce, "1D2B3i" }, +X{ "extsw", 14,24, 0x0dce, "1D2W3i" }, +X{ "extsd", 14,24, 0x0fce, "1D2D3i" }, +X{ "ffsb", 14,24, 0x046e, "1B2B" }, +X{ "ffsw", 14,24, 0x056e, "1W2B" }, +X{ "ffsd", 14,24, 0x076e, "1D2B" }, +X{ "flag", 8,8, 0xd2, "" }, +X{ "floorfb", 14,24, 0x3c3e, "1F2B" }, +X{ "floorfw", 14,24, 0x3d3e, "1F2W" }, +X{ "floorfd", 14,24, 0x3f3e, "1F2D" }, +X{ "floorlb", 14,24, 0x383e, "1L2B" }, +X{ "floorlw", 14,24, 0x393e, "1L2W" }, +X{ "floorld", 14,24, 0x3b3e, "1L2D" }, +X{ "ibitb", 14,24, 0x384e, "1B2D" }, +X{ "ibitw", 14,24, 0x394e, "1W2D" }, +X{ "ibitd", 14,24, 0x3b4e, "1D2D" }, +X{ "indexb", 11,24, 0x42e, "2B3B1r" }, +X{ "indexw", 11,24, 0x52e, "2W3W1r" }, +X{ "indexd", 11,24, 0x72e, "2D3D1r" }, +X{ "insb", 11,24, 0x0ae, "2B3B1r4d" }, +X{ "insw", 11,24, 0x1ae, "2W3W1r4d" }, +X{ "insd", 11,24, 0x3ae, "2D3D1r4d" }, +X{ "inssb", 14,24, 0x08ce, "1B2D3i" }, +X{ "inssw", 14,24, 0x09ce, "1W2D3i" }, +X{ "inssd", 14,24, 0x0bce, "1D2D3i" }, +X{ "jsr", 11,16, 0x67f, "1A" }, +X{ "jump", 11,16, 0x27f, "1A" }, +X{ "lfsr", 19,24, 0x00f3e,"1D" }, +X{ "lmr", 15,24, 0x0b1e, "2D1q" }, +X{ "lprb", 7,16, 0x6c, "2B1q" }, +X{ "lprw", 7,16, 0x6d, "2W1q" }, +X{ "lprd", 7,16, 0x6f, "2D1q" }, +X{ "lshb", 14,24, 0x144e, "1B2B" }, +X{ "lshw", 14,24, 0x154e, "1B2W" }, +X{ "lshd", 14,24, 0x174e, "1B2D" }, +X{ "meib", 14,24, 0x24ce, "1B2W" }, +X{ "meiw", 14,24, 0x25ce, "1W2D" }, +X{ "meid", 14,24, 0x27ce, "1D2Q" }, +X{ "modb", 14,24, 0x38ce, "1B2B" }, +X{ "modw", 14,24, 0x39ce, "1W2W" }, +X{ "modd", 14,24, 0x3bce, "1D2D" }, +X{ "movf", 14,24, 0x05be, "1F2F" }, +X{ "movl", 14,24, 0x04be, "1L2L" }, +X{ "movb", 6,16, 0x14, "1B2B" }, +X{ "movw", 6,16, 0x15, "1W2W" }, +X{ "movd", 6,16, 0x17, "1D2D" }, +X{ "movbf", 14,24, 0x043e, "1B2F" }, +X{ "movwf", 14,24, 0x053e, "1W2F" }, +X{ "movdf", 14,24, 0x073e, "1D2F" }, +X{ "movbl", 14,24, 0x003e, "1B2L" }, +X{ "movwl", 14,24, 0x013e, "1W2L" }, +X{ "movdl", 14,24, 0x033e, "1D2L" }, +X{ "movfl", 14,24, 0x1b3e, "1F2L" }, +X{ "movlf", 14,24, 0x163e, "1L2F" }, +X{ "movmb", 14,24, 0x00ce, "1D2D3d" }, +X{ "movmw", 14,24, 0x00de, "1D2D3d" }, +X{ "movmd", 14,24, 0x00fe, "1D2D3d" }, +X{ "movqb", 7,16, 0x5c, "2B1q" }, +X{ "movqw", 7,16, 0x5d, "2B1q" }, +X{ "movqd", 7,16, 0x5f, "2B1q" }, +X{ "movsb", 16,16, 0x000e, "i" }, +X{ "movsw", 16,16, 0x010e, "i" }, +X{ "movsd", 16,16, 0x030e, "i" }, +X{ "movst", 16,16, 0x800e, "i" }, +X{ "movsub", 14,24, 0x0cae, "1A1A" }, +X{ "movsuw", 14,24, 0x0dae, "1A1A" }, +X{ "movsud", 14,24, 0x0fae, "1A1A" }, +X{ "movusb", 14,24, 0x1cae, "1A1A" }, +X{ "movusw", 14,24, 0x1dae, "1A1A" }, +X{ "movusd", 14,24, 0x1fae, "1A1A" }, +X{ "movxbd", 14,24, 0x1cce, "1B2D" }, +X{ "movxwd", 14,24, 0x1dce, "1W2D" }, +X{ "movxbw", 14,24, 0x10ce, "1B2W" }, +X{ "movzbd", 14,24, 0x18ce, "1B2D" }, +X{ "movzwd", 14,24, 0x19ce, "1W2D" }, +X{ "movzbw", 14,24, 0x14ce, "1B2W" }, +X{ "mulf", 14,24, 0x31be, "1F2F" }, +X{ "mull", 14,24, 0x30be, "1L2L" }, +X{ "mulb", 14,24, 0x20ce, "1B2B" }, +X{ "mulw", 14,24, 0x21ce, "1W2W" }, +X{ "muld", 14,24, 0x23ce, "1D2D" }, +X{ "negf", 14,24, 0x15be, "1F2F" }, +X{ "negl", 14,24, 0x14be, "1L2L" }, +X{ "negb", 14,24, 0x204e, "1B2B" }, +X{ "negw", 14,24, 0x214e, "1W2W" }, +X{ "negd", 14,24, 0x234e, "1D2D" }, +X{ "nop", 8,8, 0xa2, "" }, +X{ "notb", 14,24, 0x244e, "1B2B" }, +X{ "notw", 14,24, 0x254e, "1W2W" }, +X{ "notd", 14,24, 0x274e, "1D2D" }, +X{ "orb", 6,16, 0x18, "1B1B" }, +X{ "orw", 6,16, 0x19, "1W1W" }, +X{ "ord", 6,16, 0x1b, "1D1D" }, +X{ "quob", 14,24, 0x30ce, "1B2B" }, +X{ "quow", 14,24, 0x31ce, "1W2W" }, +X{ "quod", 14,24, 0x33ce, "1D2D" }, +X{ "rdval", 19,24, 0x0031e,"1A" }, +X{ "remb", 14,24, 0x34ce, "1B2B" }, +X{ "remw", 14,24, 0x35ce, "1W2W" }, +X{ "remd", 14,24, 0x37ce, "1D2D" }, +X{ "restore", 8,8, 0x72, "1i" }, +X{ "ret", 8,8, 0x12, "1d" }, +X{ "reti", 8,8, 0x52, "" }, +X{ "rett", 8,8, 0x42, "" }, +X{ "rotb", 14,24, 0x004e, "1B2B" }, +X{ "rotw", 14,24, 0x014e, "1B2W" }, +X{ "rotd", 14,24, 0x034e, "1B2D" }, +X{ "roundfb", 14,24, 0x243e, "1F2B" }, +X{ "roundfw", 14,24, 0x253e, "1F2W" }, +X{ "roundfd", 14,24, 0x273e, "1F2D" }, +X{ "roundlb", 14,24, 0x203e, "1L2B" }, +X{ "roundlw", 14,24, 0x213e, "1L2W" }, +X{ "roundld", 14,24, 0x233e, "1L2D" }, +X{ "rxp", 8,8, 0x32, "1d" }, +X{ "sCONDb", 7,16, 0x3c, "2B1q" }, +X{ "sCONDw", 7,16, 0x3d, "2D1q" }, +X{ "sCONDd", 7,16, 0x3f, "2D1q" }, +X{ "save", 8,8, 0x62, "1i" }, +X{ "sbitb", 14,24, 0x184e, "1B2A" }, +X{ "sbitw", 14,24, 0x194e, "1W2A" }, +X{ "sbitd", 14,24, 0x1b4e, "1D2A" }, +X{ "sbitib", 14,24, 0x1c4e, "1B2A" }, +X{ "sbitiw", 14,24, 0x1d4e, "1W2A" }, +X{ "sbitid", 14,24, 0x1f4e, "1D2A" }, +X{ "setcfg", 15,24, 0x0b0e, "5D1q" }, +X{ "sfsr", 14,24, 0x673e, "5D1D" }, +X{ "skpsb", 16,16, 0x0c0e, "i" }, +X{ "skpsw", 16,16, 0x0d0e, "i" }, +X{ "skpsd", 16,16, 0x0f0e, "i" }, +X{ "skpst", 16,16, 0x8c0e, "i" }, +X{ "smr", 15,24, 0x0f1e, "2D1q" }, +X{ "sprb", 7,16, 0x2c, "2B1q" }, +X{ "sprw", 7,16, 0x2d, "2W1q" }, +X{ "sprd", 7,16, 0x2f, "2D1q" }, +X{ "subf", 14,24, 0x11be, "1F2F" }, +X{ "subl", 14,24, 0x10be, "1L2L" }, +X{ "subb", 6,16, 0x20, "1B2B" }, +X{ "subw", 6,16, 0x21, "1W2W" }, +X{ "subd", 6,16, 0x23, "1D2D" }, +X{ "subcb", 6,16, 0x30, "1B2B" }, +X{ "subcw", 6,16, 0x31, "1W2W" }, +X{ "subcd", 6,16, 0x33, "1D2D" }, +X{ "subpb", 14,24, 0x2c4e, "1B2B" }, +X{ "subpw", 14,24, 0x2d4e, "1W2W" }, +X{ "subpd", 14,24, 0x2f4e, "1D2D" }, +X{ "svc", 8,8, 0xe2, "2i1i" }, /* not really, but unix uses it */ +X{ "tbitb", 6,16, 0x34, "1B2A" }, +X{ "tbitw", 6,16, 0x35, "1W2A" }, +X{ "tbitd", 6,16, 0x37, "1D2A" }, +X{ "truncfb", 14,24, 0x2c3e, "1F2B" }, +X{ "truncfw", 14,24, 0x2d3e, "1F2W" }, +X{ "truncfd", 14,24, 0x2f3e, "1F2D" }, +X{ "trunclb", 14,24, 0x283e, "1L2B" }, +X{ "trunclw", 14,24, 0x293e, "1L2W" }, +X{ "truncld", 14,24, 0x2b3e, "1L2D" }, +X{ "wait", 8,8, 0xb2, "" }, +X{ "wrval", 19,24, 0x0071e,"1A" }, +X{ "xorb", 6,16, 0x38, "1B2B" }, +X{ "xorw", 6,16, 0x39, "1W2W" }, +X{ "xord", 6,16, 0x3b, "1D2D" }, +X}; /* notstrs */ +X +X/* end: n32k.opcode.h */ +X +X# define MAX_ARGS 4 +X# define ARG_LEN 50 +SHAR_EOF +sed 's/^X//' << 'SHAR_EOF' > n32k-pinsn.c +X/* Print 32000 instructions for GDB, the GNU debugger. +X Copyright (C) 1986 Free Software Foundation, Inc. +X +XGDB is distributed in the hope that it will be useful, but WITHOUT ANY +XWARRANTY. No author or distributor accepts responsibility to anyone +Xfor the consequences of using it or for whether it serves any +Xparticular purpose or works at all, unless he says so in writing. +XRefer to the GDB General Public License for full details. +X +XEveryone is granted permission to copy, modify and redistribute GDB, +Xbut only under the conditions described in the GDB General Public +XLicense. A copy of this license is supposed to have been given to you +Xalong with GDB so you can know your rights and responsibilities. It +Xshould be in a file named COPYING. Among other things, the copyright +Xnotice and this notice must be preserved on all copies. +X +XIn other words, go ahead and share GDB, but don't try to stop +Xanyone else from sharing it farther. Help stamp out software hoarding! +X*/ +X +X#include +X +X#include "defs.h" +X#include "param.h" +X#include "symtab.h" +X#include "n32k-opcode.h" +X +X/* 32000 instructions are never longer than this. */ +X#define MAXLEN 62 +X +X/* Number of elements in the opcode table. */ +X#define NOPCODES (sizeof notstrs / sizeof notstrs[0]) +X +Xextern char *reg_names[]; +X +X#define NEXT_IS_ADDR '|' +X +X/* +X * extract "count" bits starting "offset" bits +X * into buffer +X */ +X +Xint +Xbit_extract (buffer, offset, count) +Xchar *buffer; +Xint offset; +Xint count; +X{ +X int result; +X int mask; +X int bit; +X +X buffer += offset >> 3; +X offset &= 7; +X bit = 1; +X result = 0; +X while (count--) { +X if ((*buffer & (1 << offset))) +X result |= bit; +X if (++offset == 8) { +X offset = 0; +X buffer++; +X } +X bit <<= 1; +X } +X return result; +X} +X +Xdouble +Xdbit_extract (buffer, offset, count) +X{ +X union { +X struct { +X int low, high; +X } ival; +X double dval; +X } foo; +X +X foo.ival.low = bit_extract (buffer, offset, 32); +X foo.ival.high = bit_extract (buffer, offset+32, 32); +X return foo.dval; +X} +X +Xsign_extend (value, bits) +X{ +X value = value & ((1 << bits) - 1); +X return (value & (1 << (bits-1))) ? +X (value | (~((1 << bits) - 1))) +X : value; +X} +X +Xflip_bytes (ptr, count) +Xchar *ptr; +Xint count; +X{ +X char tmp; +X +X while (count > 0) { +X tmp = *ptr; +X ptr[0] = ptr[count-1]; +X ptr[count-1] = tmp; +X ptr++; +X count -= 2; +X } +X} +X +X +X/* Print the 32000 instruction at address MEMADDR in debugged memory, +X on STREAM. Returns length of the instruction, in bytes. */ +X +Xint +Xprint_insn (memaddr, stream) +XCORE_ADDR memaddr; +XFILE *stream; +X{ +X unsigned char buffer[MAXLEN]; +X register int i; +X register unsigned char *p; +X register char *d; +X unsigned short first_word; +X int gen, disp; +X int ioffset; /* bits into instruction */ +X int aoffset; /* bits into arguments */ +X char arg_bufs[MAX_ARGS+1][ARG_LEN]; +X int argnum; +X int maxarg; +X +X read_memory (memaddr, buffer, MAXLEN); +X +X first_word = *(unsigned short *) buffer; +X for (i = 0; i < NOPCODES; i++) { +X if ((first_word & ((1 << notstrs[i].detail.obits) - 1)) == +X notstrs[i].detail.code) +X break; +X } +X +X /* Handle undefined instructions. */ +X if (i == NOPCODES) { +X fprintf (stream, "0%o", buffer[0]); +X return 1; +X } +X +X fprintf (stream, "%s", notstrs[i].name); +X +X ioffset = notstrs[i].detail.ibits; +X aoffset = notstrs[i].detail.ibits; +X d = notstrs[i].detail.args; +X +X if (*d) { +X fputc ('\t', stream); +X +X maxarg = 0; +X while (*d) +X { +X argnum = *d - '1'; +X d++; +X if (argnum > maxarg && argnum < MAX_ARGS) +X maxarg = argnum; +X ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, +X memaddr, arg_bufs[argnum]); +X d++; +X } +X for (argnum = 0; argnum <= maxarg; argnum++) { +X CORE_ADDR addr; +X char *ch, *index (); +X for (ch = arg_bufs[argnum]; *ch;) { +X if (*ch == NEXT_IS_ADDR) { +X ++ch; +X addr = atoi (ch); +X print_address (addr, stream); +X while (*ch && *ch != NEXT_IS_ADDR) +X ++ch; +X if (*ch) +X ++ch; +X } else +X putc (*ch++, stream); +X } +X if (argnum < maxarg) +X fprintf (stream, ", "); +X } +X } +X return aoffset / 8; +X} +X +Xprint_insn_arg (d, ioffset, aoffsetp, buffer, addr, result) +Xchar d; +Xint ioffset, *aoffsetp; +Xchar *buffer; +XCORE_ADDR addr; +Xchar *result; +X{ +X int addr_mode; +X float Fvalue; +X double Lvalue; +X int Ivalue; +X int disp1, disp2; +X int index; +X +X switch (d) { +X case 'F': +X case 'L': +X case 'B': +X case 'W': +X case 'D': +X case 'A': +X addr_mode = bit_extract (buffer, ioffset-5, 5); +X ioffset -= 5; +X switch (addr_mode) { +X case 0x0: case 0x1: case 0x2: case 0x3: +X case 0x4: case 0x5: case 0x6: case 0x7: +X sprintf (result, "r%d", addr_mode); +X break; +X case 0x8: case 0x9: case 0xa: case 0xb: +X case 0xc: case 0xd: case 0xe: case 0xf: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "%d(r%d)", disp1, addr_mode & 7); +X break; +X case 0x10: +X case 0x11: +X case 0x12: +X disp1 = get_displacement (buffer, aoffsetp); +X disp2 = get_displacement (buffer, aoffsetp); +X sprintf (result, "%d(%d(%s))", disp2, disp1, +X addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb"); +X break; +X case 0x13: +X sprintf (result, "reserved"); +X break; +X case 0x14: +X switch (d) { +X case 'B': +X Ivalue = bit_extract (buffer, *aoffsetp, 8); +X Ivalue = sign_extend (Ivalue, 8); +X *aoffsetp += 8; +X sprintf (result, "$%d", Ivalue); +X break; +X case 'W': +X Ivalue = bit_extract (buffer, *aoffsetp, 16); +X flip_bytes (&Ivalue, 2); +X *aoffsetp += 16; +X Ivalue = sign_extend (Ivalue, 16); +X sprintf (result, "$%d", Ivalue); +X break; +X case 'D': +X Ivalue = bit_extract (buffer, *aoffsetp, 32); +X flip_bytes (&Ivalue, 4); +X *aoffsetp += 32; +X sprintf (result, "$%d", Ivalue); +X break; +X case 'A': +X Ivalue = bit_extract (buffer, *aoffsetp, 32); +X flip_bytes (&Ivalue, 4); +X *aoffsetp += 32; +X sprintf (result, "$|%d|", Ivalue); +X break; +X case 'F': +X Fvalue = (float) bit_extract +X (buffer, *aoffsetp, 32); +X flip_bytes (&Fvalue, 4); +X *aoffsetp += 32; +X sprintf (result, "$%g", Fvalue); +X break; +X case 'L': +X Lvalue = dbit_extract +X (buffer, *aoffsetp, 64); +X flip_bytes (&Lvalue, 8); +X *aoffsetp += 64; +X sprintf (result, "$%g", Lvalue); +X break; +X } +X break; +X case 0x15: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "@|%d|", disp1); +X break; +X case 0x16: +X disp1 = get_displacement (buffer, aoffsetp); +X disp2 = get_displacement (buffer, aoffsetp); +X sprintf (result, "EXT(%d) + %d", disp1, disp2); +X break; +X case 0x17: +X sprintf (result, "tos"); +X break; +X case 0x18: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "%d(fp)", disp1); +X break; +X case 0x19: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "%d(sp)", disp1); +X break; +X case 0x1a: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "%d(sb)", disp1); +X break; +X case 0x1b: +X disp1 = get_displacement (buffer, aoffsetp); +X sprintf (result, "|%d|", addr + disp1); +X break; +X case 0x1c: +X case 0x1d: +X case 0x1e: +X case 0x1f: +X index = bit_extract (buffer, *aoffsetp, 8); +X *aoffsetp += 8; +X print_insn_arg (d, *aoffsetp, aoffsetp, buffer, addr, +X result); +X { +X static char *ind[] = {"b", "w", "d", "q"}; +X char *off; +X +X off = result + strlen (result); +X sprintf (off, "[r%d:%s]", index & 7, +X ind[addr_mode & 3]); +X } +X break; +X } +X break; +X case 'q': +X Ivalue = bit_extract (buffer, ioffset-4, 4); +X Ivalue = sign_extend (Ivalue, 4); +X sprintf (result, "%d", Ivalue); +X ioffset -= 4; +X break; +X case 'r': +X Ivalue = bit_extract (buffer, ioffset-3, 3); +X sprintf (result, "r%d", Ivalue&7); +X ioffset -= 3; +X break; +X case 'd': +X sprintf (result, "%d", get_displacement (buffer, aoffsetp)); +X break; +X case 'p': +X sprintf (result, "%c%d%c", NEXT_IS_ADDR, addr + +X get_displacement (buffer, aoffsetp), +X NEXT_IS_ADDR); +X break; +X case 'i': +X Ivalue = bit_extract (buffer, *aoffsetp, 8); +X *aoffsetp += 8; +X sprintf (result, "0x%x", Ivalue); +X break; +X } +X return ioffset; +X} +X +Xget_displacement (buffer, aoffsetp) +Xchar *buffer; +Xint *aoffsetp; +X{ +X int Ivalue; +X +X Ivalue = bit_extract (buffer, *aoffsetp, 8); +X switch (Ivalue & 0xc0) { +X case 0x00: +X case 0x40: +X Ivalue = sign_extend (Ivalue, 7); +X *aoffsetp += 8; +X break; +X case 0x80: +X Ivalue = bit_extract (buffer, *aoffsetp, 16); +X flip_bytes (&Ivalue, 2); +X Ivalue = sign_extend (Ivalue, 14); +X *aoffsetp += 16; +X break; +X case 0xc0: +X Ivalue = bit_extract (buffer, *aoffsetp, 32); +X flip_bytes (&Ivalue, 4); +X Ivalue = sign_extend (Ivalue, 30); +X *aoffsetp += 32; +X break; +X } +X return Ivalue; +X} +X/* +X * return the number of locals in the current frame given a pc +X * pointing to the enter instruction +X */ +Xn32k_localcount (enter_pc) +XCORE_ADDR enter_pc; +X{ +X int localtype, localcount; +X +X localtype = read_memory_integer (enter_pc+2, 1); +X if ((localtype & 0x80) == 0) +X localcount = localtype; +X else if ((localtype & 0xc0) == 0x80) +X localcount = +X ((read_memory_integer (enter_pc+2, 1) & ~0xc0) << 8) | +X ((read_memory_integer (enter_pc+3, 1))); +X else +X localcount = +X ((read_memory_integer (enter_pc+2, 1) & ~0xc0) << 24) | +X ((read_memory_integer (enter_pc+3, 1)) << 16) | +X ((read_memory_integer (enter_pc+4, 1)) << 8 ) | +X ((read_memory_integer (enter_pc+5, 1))); +X return localcount; +X} +SHAR_EOF +exit + diff --git a/gdb/=rt-ans2 b/gdb/=rt-ans2 new file mode 100644 index 00000000000..cd5f9fa6f3a --- /dev/null +++ b/gdb/=rt-ans2 @@ -0,0 +1,103 @@ +BABYL OPTIONS: +Version: 5 +Labels: +Note: This is the header of an rmail file. +Note: If you are seeing it in rmail, +Note: it means the file has no messages in it. + +1,answered,, +Received: by PREP.AI.MIT.EDU; Tue, 26 May 87 14:03:00 EDT +Received: by po2.andrew.cmu.edu (5.54/3.15) id for rms@PREP.AI.MIT.EDU; Tue, 26 May 87 13:12:52 EDT +Received: via switchmail; Tue, 26 May 87 13:12:49 edt +Received: FROM mooncrest VIA qmail + ID ; + Tue, 26 May 87 13:12:08 edt +Received: FROM mooncrest VIA qmail + ID ; + Tue, 26 May 87 13:11:14 edt +Message-Id: <0UiQmky00UkA06w0Ci@andrew.cmu.edu> +X-Trace: MS Version 3.24 on ibm032 host mooncrest, by kazar (71). +Date: Tue, 26 May 87 13:11:12 edt +From: kazar#@andrew.cmu.edu (Mike Kazar) +To: rms@PREP.AI.MIT.EDU (Richard M. Stallman) +Subject: Re: Fwd: RT diffs for gdb version 2.1 +Cc: zs01#@andrew.cmu.edu (Zalman Stern) +In-Reply-To: <4UiN0ly00Vs8Njw0PC@andrew.cmu.edu> + +*** EOOH *** +X-Trace: MS Version 3.24 on ibm032 host mooncrest, by kazar (71). +Date: Tue, 26 May 87 13:11:12 edt +From: kazar#@andrew.cmu.edu (Mike Kazar) +To: rms@PREP.AI.MIT.EDU (Richard M. Stallman) +Subject: Re: Fwd: RT diffs for gdb version 2.1 +Cc: zs01#@andrew.cmu.edu (Zalman Stern) +In-Reply-To: <4UiN0ly00Vs8Njw0PC@andrew.cmu.edu> + +I'm afraid that neither of your proposed simplifications to the gdb RT port +actually work. + +First, the trace table problem. The fundamental problem is that gdb expects +to be able to pass in a frame pointer and get that frame's parent. This is +the purpose of FRAME_CHAIN, a macro whose one parameter is the frame whose +parent is desired. + +This is simply insufficient information with which to compute the preceding +frame's address. In order to truly appreciate how bad things are, let me +describe the procedure involved in going from a set of saved registers +(including the pc), say after a core dump occurs, to the address of the +preceding frame. I assure you that you'll be shocked by its complexity.... + +I start off knowing only one thing: the PC of the guy who pushed the last +stack frame. At the time of a core dump, this is in the saved PC, and for +other stack frames, it is in register R15 (the return address is put in R15 +by the procedure call sequence). My first goal is to compute the frame +register number! Not the contents of the frame register, but the register +number itself, because the RT calling convention lets you change frame +pointers from procedure to procedure! So, I scan for the trace table, based +on the PC, and obtain a structure that gives the frame register number (for +both of our C compilers, this is R13, but it doesn't have to be), the number +of arguments to the procedure, the space used by the locals and the number of +registers saved by the procedure prolog. This enables me to take the frame +pointer, compute the offset of the saved registers off of this frame pointer +and essentially restore the registers to the state they were at the time this +procedure was called. R15 now contains *its* callers PC, and I can redo this +procedure again to back up another frame. + +In essence, in order to compute the preceding frame's address, I need more +than just the current frame's address. I need the full machine state at the +time of the call, including all of the registers since I don't know which one +will even turn out to be the frame pointer for the preceding procedure. + +This is why I put in the frame caching code. Note that even were I to assume +that the frame pointer is always in R13 (and this is almost certainly a +mistake; IBM will surely eventually come up with a compiler where the frame +pointer is NOT r13), I still either need r15 or the PC (depending upon which +frame we're dealing with) in order to compute the preceding frame address. + +As for the _foo v.s. _.foo issue, there are two problems. First, we can not +simply ignore _foo symbols, since an _foo symbol is only "junk" if there is +(possibly later) an _.foo symbol. We might be able to have the processing +for the "_.foo" change the value in the symbol table placed under the name +_foo. I do not know if this will work, since I do not know what processing +is done when a symbol is first encountered, and how much can be done a second +time. The second problem is that sometimes we need to see what is in the +variable named _foo, and we can't if it actually refers to _.foo. I +personally might be willing to live with this loss of functionality, but +other people probably would not. + +As for initialize.h, we simply have no guarantees that IBM won't again change +the junk they stick in front of procedures in the text segment. Already, +depending upon which compiler (and we use both), pcc puts a funny string (and +maybe an integer, too) in front of every procedure, while the metaware hc +compiler puts a funny string in front of the first procedure in a file, but +nothing in front of the others. IBM has made it clear to us that they feel +free to change this at any time, so I feel quite strongly that it would be a +mistake to assume that they've finished playing around with junk at the start +of the text. BTW, for all I know, some of these magic text strings disappear +when you compile with -O. They certainly *should*. + + Mike + + + + \ No newline at end of file diff --git a/gdb/=rt-answers b/gdb/=rt-answers new file mode 100644 index 00000000000..b23cfee9263 --- /dev/null +++ b/gdb/=rt-answers @@ -0,0 +1,147 @@ +X-Trace: MS Version 3.24 on ibm032 host dublin.itc.cmu.edu, by zs01 (623). +Date: Mon, 25 May 87 10:30:10 edt +From: zs01#@andrew.cmu.edu (Zalman Stern) +To: rms@PREP.AI.MIT.EDU (Richard M. Stallman) +Subject: Re: RT diffs for gdb version 2.1 +Cc: kazar#@andrew.cmu.edu (Mike Kazar), zs01#@andrew.cmu.edu (Zalman Stern) +In-Reply-To: <8705250107.AA13256@prep.ai.mit.edu> + +Richard, + +First I will cover the easy questions. + +Either of our fixes to environ.c (i.e. with respect to version 1.9 which was +broken) will work. As I understand it, the intent of init_environ is to fill +in the environment and leave a little extra space for later additions. I do +not understand why you would want to only leave the extra space when the +original size was within 10 elements of the final size. + +add_com returning something is probably left over from a fix I put in which +is superceeded by the "user" class to distinguish command lists from function +pointers. I should have removed it. + +We use csh instead of sh because I got tired of putting up with sh's crapping +out on large environments. + +The change to inferior_args involves putting an explicit initializer of NULL +on it, and testing it for NULL before freeing it. I guess most +implementations of free ignore NULL pointers. The one we have on our Sun-2's +does not. + +I can't remember why the alloca's were moved out of the variable +initializations. It may have been to avoid a compiler problem. In any event, +ignoring this modification shouldn't hurt. + +Now for the hard ones... + +The RT is a very different architecture from either a Sun or a VAX. It does +not use a self-describing stack frame and it does not use the same +conventions for symbols within object modules. There are also certain +subtleties to the way it lays out its address space that cause problems. Many +people at the ITC, including myself, are very impressed with the quality of +the port Mike did in spite of these obstacles. You may feel that these +problems are not worth effort. I have attempted to describe the differences +involved with the RT in case you choose to address them. If not, we are still +quite happy with the debugger we have and thank you for providing us with the +code... + +Both the 68k family and the VAX have a frame pointer and a stack pointer. +Using these to values and the information on the stack, one can do a complete +stack trace. The RT on the other hand has only a stack pointer and a very +loose concept of a frame pointer. The stack pointer will point just below a +section of the stack dedicated to the maximum number of outgoing parameters +minus 4 (the first 4 are in registers). The frame pointer will point +somewhere in the stack where the compiler has deemed it optimal for +addressing locals and parameters. There are variable length fields in the +stack frame, such as the register save areas. In all, the thing looks like +so: + + +Higher Address +----------------- + +a) Incoming args 5 through N <---- Previous sp was here + (part of previous function's stack frame) +b) Four words to save register passed arguments. +c) Four words of linkage area (reserved). +d) 1 word static link. +e) 1 - 16 words of register save area. + (Variable length, return address is at the top of this since it was in +r15) +f) 0 -8 words of floating point reg. save area. (Variable length) +g) Local variables (variable length) +h) Outgoing arguments, words 5 - N <---- Current sp points to bottom of this. + +Lower Address +---------------- + +These and the stack contents are not enough to get back to the previous stack +frame because you do not know how far back it is to the register save area. +The code works because each function has been compiled to know how to pop its +stack frame (i.e. it has embedded constants). In order to facilitate +debugging, there is a trace table at the end of each function containing all +the necessary information. (Namely the offset from the frame pointer to the +top of the stack frame b in the above diagram) The trace table is located by +starting at the beginning of the function and looking for the illegal +instruction sequence 0xdf07df. Since the RT does not have 32bit constants in +the instruction stream, this actually works. In general, the iar and the +stack pointer are needed to do frame manipulations. The cache is necessary +because finding the trace table is very expensive. In short, the machinery +present in gdb was not up to handling this system, so we added what we +thought would work. It is interesting to note that similar calling +conventions are used on other RISC machines, notably the MIPS R2000. If you +wish to take advantage of these high performance machines, you will have to +do something like what we have done. + +The POP_DUMMY_FRAME problem is related to this. The RT stores return address +in r15. We can not use this location to store the current iar since we must +store r15 for later restoration. This rules out using the same function for +popping both kinds of frames. There is also some hassle involved in getting +the stack and frame pointers correct, but I think this might be fixed by +generating an appropriate trace back table for the dummy function. + +The other problem we faced is the non-standard use of symbols within object +modules. The RT defines two symbols for a function foo. There is "_.foo" +which corresponds to the actual code in the text segment (just like "_foo" on +a Sun or VAX), and "_foo" which points to the data area for the function in +the data segment. The first word of the data area contains a pointer to the +code. A function pointer (i.e. int (*foo)()) points to the data area (_foo), +not the code (_.foo). This is what the TYPE_CODE_PTR modification in valops.c +is for. Since both of these symbols are used for certain things, we cannot +simply remove the dots. This is a bogus IBM feature and we do not like it any +better than you do. We have to live with it if we want a working debugger. + +The "fix" to find_pc_misc function handles a special case on the RT where +certain functions are in the high end of the address space. The RT uses the +top 4 bits of an address as a segment number. The text segment is seg. 0, the +data segment is seg. 1, and the kernel is mapped into seg. 14. Certain kernel +functions (i.e. floating point functions) are directly callable by user code +and so occur in the misc_function_vector. I realize this is bogus. + +The initialization code will not run because both the RT compilers (pcc and +hc) output ascii data in the text section preceding the first function. Pcc +outputs the name of each function before the function. Hc outputs the name of +the source file at the beginning of the object module. Coding around this may +be possible, but what is the point? I see no reason for this hackery. I have +had problems getting it to work not only on the RT, but on the Sun-3. It is +guaranteed to be a portability headache on many other machines as well. If +you intend for gdb to only work when compiled with gcc, I suppose you may be +able to use this method. + +I strongly agree with your statements that cleaner solutions are better in +every way. Unfortunately, we did not write gdb, nor is the system we are +working with particularly supportive of symbolic debugging. We were faced +with the task of both figuring out gdb, and hacking our way around a +contorted system (featuring among other things, a plethora of compiler bugs). +The fact that our version of gdb is the only working symbolic debugger on the +IBM RT (despite much effort by IBM) is proof that we have done something +right. I am willing to discuss what would make this port better. However, it +is not our intent to maintain or rewrite gdb. We merely wish to use it, and +if not a terrible hassle, let other people use it too. Mike and I would +prefer a copyright assignment. I would appreciate it if you would send me +info on what we need to do. + +-Z- + + + diff --git a/gdb/=rt-changes b/gdb/=rt-changes new file mode 100644 index 00000000000..1eda81c8df4 --- /dev/null +++ b/gdb/=rt-changes @@ -0,0 +1,3338 @@ +From: zs01#@andrew.cmu.edu (Zalman Stern) +Date: Sun, 24 May 87 03:20:57 edt +To: rms@prep.ai.mit.edu +Subject: RT diffs for gdb version 2.1 + +Here are the new files, followed by the diffs to old files. The first file below +is ITCMODS which is my attempt to document some of our changes. Unfortunately, +it has not been maintained particularly well and notably does not include info +about our changes to support the HIGH-C compiler. One big change we put in was +to use a number of initialize routines instead of the "linked list of object +modules" that is used on other machines. The RT object file format appears to +have a variable size header before the code, making it very difficult +(impossible?) to get the initialization stuff to work. If you have any +questions, don't hesitate to send me mail. + +-Z- + +Only in .: ITCMODS + +blockframe.c: + set_current_frame now takes an extra argument. + RT specific code for interpreting and caching of trace table entries. + Added initialize routine. + +breakpoint.c: + Added new_breakpoint_commands flag to prevent incorrect interpretation of command lists containing a continue statement. + Modified do_breakpoint_commands to know about new_breakpoint_commands. + Modified clear_breakpoint_commands to set new_breakpoint_commands. + Added initialize routine. + +core.c: + RT specific code to find the uarea. + RT specific code to indicate the start of the data segment. + set_current_frame now takes an extra argument. + Added initialize routine. + +dbxread.c: + Added support for the Camphor dynamic loading system. (All under #ifdef CAMPHOR). + Fix for multiple declarations of register variables (i.e. they are declared twice). The fix munges the incorrect declaration (i.e. the one which is not register). + set_rel_command to set relocation offset for camphor loaded files. (Under #ifdef CAMPHOR). + add_file_command to append a file's symbols to the current symbol table instead of replacing it. (Under #ifdef CAMPHOR). + RT specific code to deal with function names being _.foo instead of _foo. + Added initialize routine. + + Feb 8, 1987 Zalman Stern. + Added test in symbol_file_command to see if file was compiled with debugging. If not print an error message instead of dumping core. + Added same test in add_file_command and made it run through BZPATH, CLASSPATH, and PATH in that order (Under #ifdef CAMPHOR). + +environ.c: + Fixed error in calculating new size of a reallocated environment. + +eval.c: + Added initialize routine. + +expread.y: + Moved alloca call out of variable initializations. + +findvar.c: + Added initialize routine. + +firstfile.c: + Added main initialization driver routine. + +frame.h: + Added RT specific declarations to hold frame information, and to deal with trace table caching. + +ibm032-pinsn.c: + New file, contains RT disassembler. + +ibm032-opcode.h: + New file, contains RT opcode definitions. + +infcmd.c + Changed code to use csh instead of sh to avoid the anoyance of the environment bug. + Added initialize routine. + +inflow.c: + Added initialize routine. + +infrun.c: + set_current_frame now takes an extra argument. + Added some code to deal with stopping in the middle of a camphor link. (Under #ifdef CAMPHOR). + Added RT specific code to get the return values from the right registers. Replaces code that was there for RT. + RT specific code to do a "POP_DUMMY_FRAME." Dummy frames are to store more complete state than a normal frame. Makes calling a function in inferior more reliable. Perhaps this should be expanded to other machine types. + Added initialize routine. + + Feb 9, 1987 Zalman Stern. + Added call to select_frame after popping a stack dummy frame in normal_stop. This fixes the bug where you could not print variables without doing a "frame 0" after printing an expression with a function call in it. + +iniitialize.h: + Changed file to use #ifdef's for machine type. Allows one to use same sources for different machines. + +m-ibm032.h: + New file, contains RT specific macros and variables. + +param.h: + Changed file to use #ifdef's for machine type. Allows one to use same sources for different machines. + +pinsn.c: + Changed file to use #ifdef's for machine type. Allows one to use same sources for different machines. + +printcmd.c: + Moved alloca calls out of variable initialization. + Added initialize routine. + +source.c: + Added initialize routine. + +stack.c: + Added initialize routine. + +symmisc.c: + Added initialize routine. + +symtab.c: + RT specific code to deal with function names being _.foo instead of _foo. + Added initialize routine. + +utils.c: + Added comment. + +valarith.c: + Added initialize routine. + +valops.c: + Added initialize routine. + +valprint.c: + Added initialize routine. + +values.c: + Added initialize routine. + +Only in .: ibm032-opcode.h + +/* The opcode table consists of a 256 element array containing an + * instruction mnemonic and an instruction type field. This can be + * indexed directly by the first eight bits of an RT instruction. + * The instruction type consists of a type field and some flags. + * In addition to this, there is an ifdef'd out "instruction" table + * at the end of the file. This is an alphabetical listing of the instructions + * containing mnemonic, opcode, and type. This is useful for modification + * purposes. There is also some code in the ifdef to convert the + * instruction table into an opcode table. + */ + +/* Various useful bit masks. */ +#define ibm032_typeMask 0x0f /* Mask to get actual type info out of instruction type. */ +#define LOW4 0x0f +#define HIGH4 0xf0 +#define LOW16 0x0000ffff +#define HIGH16 0xffff0000 +#define LOW20 0x000fffff +#define LOW24 0x00ffffff + +/* Instruction types consist of a type id in the low 4 bits and flags above that. */ + +/* Flags. */ +#define ibm032_conditional 0x10 +#define ibm032_negative 0x20 + +/* Format types. */ +#define ibm032_JI 0x0 /* Jump immediate. */ +#define ibm032_X 0x1 /* ??? */ + +/* These next ones are in a special bit position. Do not change their defines. */ +#define ibm032_DS0 0x2 /* Data short with no shift for immediate value. */ +#define ibm032_DS1 0x3 /* Data short with 1 bit shift for immediate value. */ +#define ibm032_DS2 0x4 /* Data short with 2 bit shift for immediate value */ +#define ibm032_DSShiftOffset ibm032_DS0 /* Offset to get shift value from ibm032_DS? types. */ + +#define ibm032_RR 0x5 /* R format where second argument is a register */ +#define ibm032_RI 0x6 /* R format where second argument is 4 bit immediate. */ +#define ibm032_BI 0x7 /* Branch immediate. */ +#define ibm032_BA 0x8 /* Branch absolute. */ +#define ibm032_D 0x9 /* Data. */ + +/* What an instruction looks like. */ +struct ibm032_opcode { + char *mnemonic; /* the name. NULL indicates illegal instruction. */ + int type; /* See above. */ +}; + +#define MAXOPCODES 256 /* Pretty well hardwired. */ + +#ifndef BUILDTABLE +/* The actual data. */ +struct ibm032_opcode ibm032_opcodes[] = { + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional | ibm032_negative}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"j%s", ibm032_JI | ibm032_conditional}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"stcs", ibm032_DS0}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sths", ibm032_DS1}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"sts", ibm032_DS2}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lcs", ibm032_DS0}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"lhas", ibm032_DS1}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"cas", ibm032_X}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {"ls", ibm032_DS2}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {"b%s", ibm032_BI | ibm032_conditional | ibm032_negative}, + {"b%sx", ibm032_BI | ibm032_conditional | ibm032_negative}, + {"bala", ibm032_BA}, + {"balax", ibm032_BA}, + {"bali", ibm032_BI}, + {"balix", ibm032_BI}, + {"b%s", ibm032_BI | ibm032_conditional}, + {"b%sx", ibm032_BI | ibm032_conditional}, + {"ais", ibm032_RI}, + {"inc", ibm032_RI}, + {"sis", ibm032_RI}, + {"dec", ibm032_RI}, + {"cis", ibm032_RI}, + {"clrsb", ibm032_RI}, + {"mfs", ibm032_RR}, + {"setsb", ibm032_RI}, + {"clrbu", ibm032_RI}, + {"clrbl", ibm032_RI}, + {"setbu", ibm032_RI}, + {"setbl", ibm032_RI}, + {"mftbiu", ibm032_RI}, + {"mftbil", ibm032_RI}, + {"mttbiu", ibm032_RI}, + {"mttbil", ibm032_RI}, + {"sari", ibm032_RI}, + {"sari16", ibm032_RI}, + {0, 0}, + {0, 0}, + {"lis", ibm032_RI}, + {0, 0}, + {0, 0}, + {0, 0}, + {"sri", ibm032_RI}, + {"sri16", ibm032_RI}, + {"sli", ibm032_RI}, + {"sli16", ibm032_RI}, + {"srpi", ibm032_RI}, + {"srpi16", ibm032_RI}, + {"slpi", ibm032_RI}, + {"slpi16", ibm032_RI}, + {"sar", ibm032_RR}, + {"exts", ibm032_RR}, + {"sf", ibm032_RR}, + {"cl", ibm032_RR}, + {"c", ibm032_RR}, + {"mts", ibm032_RR}, + {"d", ibm032_RR}, + {0, 0}, + {"sr", ibm032_RR}, + {"srp", ibm032_RR}, + {"sl", ibm032_RR}, + {"slp", ibm032_RR}, + {"mftb", ibm032_RR}, + {"tgte", ibm032_RR}, + {"tlt", ibm032_RR}, + {"mttb", ibm032_RR}, + {"svc", ibm032_D}, + {"ai", ibm032_D}, + {"cal16", ibm032_D}, + {"oiu", ibm032_D}, + {"oil", ibm032_D}, + {"nilz", ibm032_D}, + {"nilo", ibm032_D}, + {"xil", ibm032_D}, + {"cal", ibm032_D}, + {"lm", ibm032_D}, + {"lha", ibm032_D}, + {"ior", ibm032_D}, + {"ti", ibm032_D}, + {"l", ibm032_D}, + {"lc", ibm032_D}, + {"tsh", ibm032_D}, + {"lps", ibm032_D}, + {"aei", ibm032_D}, + {"sfi", ibm032_D}, + {"cli", ibm032_D}, + {"ci", ibm032_D}, + {"niuz", ibm032_D}, + {"niuo", ibm032_D}, + {"xiu", ibm032_D}, + {"cau", ibm032_D}, + {"stm", ibm032_D}, + {"lh", ibm032_D}, + {"iow", ibm032_D}, + {"sth", ibm032_D}, + {"st", ibm032_D}, + {"stc", ibm032_D}, + {0, 0}, + {"abs", ibm032_RR}, + {"a", ibm032_RR}, + {"s", ibm032_RR}, + {"o", ibm032_RR}, + {"twoc", ibm032_RR}, + {"n", ibm032_RR}, + {"m", ibm032_RR}, + {"x", ibm032_RR}, + {"b%sr", ibm032_RR | ibm032_conditional | ibm032_negative}, + {"b%srx", ibm032_RR | ibm032_conditional | ibm032_negative}, + {0, 0}, + {"lhs", ibm032_RR}, + {"balr", ibm032_RR}, + {"balrx", ibm032_RR}, + {"b%sr", ibm032_RR | ibm032_conditional}, + {"b%srx", ibm032_RR | ibm032_conditional}, + {"wait", ibm032_RR}, + {"ae", ibm032_RR}, + {"se", ibm032_RR}, + {"ca16", ibm032_RR}, + {"onec", ibm032_RR}, + {"clz", ibm032_RR}, + {0, 0}, + {0, 0}, + {0, 0}, + {"mc03", ibm032_RR}, + {"mc13", ibm032_RR}, + {"mc23", ibm032_RR}, + {"mc33", ibm032_RR}, + {"mc30", ibm032_RR}, + {"mc31", ibm032_RR}, + {"mc32", ibm032_RR}, +}; + +#else +struct ibm032_opcode ibm032_opcodes[MAXOPCODES]; + +struct ibm032_instruction { + char *mnemonic; /* Mnemonic for this instruction */ + char opcode; /* Numerical value of opcode. */ + int type; /* This instructions format. */ +}; + +struct ibm032_instruction ibm032_instructions[] = +{ + {"a", 0xe1, ibm032_RR}, + {"abs", 0xe0, ibm032_RR}, + {"ae", 0xf1, ibm032_RR}, + {"aei", 0xd1, ibm032_D}, + {"ai", 0xc1, ibm032_D}, + {"ais", 0x90, ibm032_RI}, + {"bala", 0x8a, ibm032_BA}, + {"balax", 0x8b, ibm032_BA}, + {"bali", 0x8c, ibm032_BI}, + {"balix", 0x8d, ibm032_BI}, + {"balr", 0xec, ibm032_RR}, + {"balrx", 0xed, ibm032_RR}, + {"b%s", 0x8e, ibm032_BI | ibm032_conditional}, + {"b%sr", 0xee, ibm032_RR | ibm032_conditional}, + {"b%srx", 0xef, ibm032_RR | ibm032_conditional}, + {"b%sx", 0x8f, ibm032_BI | ibm032_conditional}, + {"b%s", 0x88, ibm032_BI | ibm032_conditional | ibm032_negative}, + {"b%sr", 0xe8, ibm032_RR | ibm032_conditional | ibm032_negative}, + {"b%srx", 0xe9, ibm032_RR | ibm032_conditional | ibm032_negative}, + {"b%sx", 0x89, ibm032_BI | ibm032_conditional | ibm032_negative}, + {"c", 0xb4, ibm032_RR}, + {"cal", 0xc8, ibm032_D}, + {"cal16", 0xc2, ibm032_D}, + {"cas", 0x60, ibm032_X}, + {"cau", 0xd8, ibm032_D}, + {"ca16", 0xf3, ibm032_RR}, + {"ci", 0xd4, ibm032_D}, + {"cis", 0x94, ibm032_RI}, + {"cl", 0xb3, ibm032_RR}, + {"cli", 0xd3, ibm032_D}, + {"clrbl", 0x99, ibm032_RI}, + {"clrbu", 0x98, ibm032_RI}, + {"clrsb", 0x95, ibm032_RI}, + {"clz", 0xf5, ibm032_RR}, + {"d", 0xb6, ibm032_RR}, + {"dec", 0x93, ibm032_RI}, + {"exts", 0xb1, ibm032_RR}, + {"inc", 0x91, ibm032_RI}, + {"ior", 0xcb, ibm032_D}, + {"iow", 0xdb, ibm032_D}, + + {"j%s", 0x08, ibm032_JI | ibm032_conditional}, + {"j%s", 0x00, ibm032_JI | ibm032_conditional | ibm032_negative}, + + {"l", 0xcd, ibm032_D}, + {"lc", 0xce, ibm032_D}, + {"lcs", 0x40, ibm032_DS0}, + {"lh", 0xda, ibm032_D}, + {"lha", 0xca, ibm032_D}, + {"lhas", 0x50, ibm032_DS1}, + {"lhs", 0xeb, ibm032_RR}, + {"lis", 0xa4, ibm032_RI}, + {"lm", 0xc9, ibm032_D}, + {"lps", 0xd0, ibm032_D}, + {"ls", 0x70, ibm032_DS2}, + {"m", 0xe6, ibm032_RR}, + {"mc03", 0xf9, ibm032_RR}, + {"mc13", 0xfa, ibm032_RR}, + {"mc23", 0xfb, ibm032_RR}, + {"mc33", 0xfc, ibm032_RR}, + {"mc30", 0xfd, ibm032_RR}, + {"mc31", 0xfe, ibm032_RR}, + {"mc32", 0xff, ibm032_RR}, + {"mfs", 0x96, ibm032_RR}, + {"mftb", 0xbc, ibm032_RR}, + {"mftbil", 0x9d, ibm032_RI}, + {"mftbiu", 0x9c, ibm032_RI}, + {"mts", 0xb5, ibm032_RR}, + {"mttb", 0xbf, ibm032_RR}, + {"mttbil", 0x9f, ibm032_RI}, + {"mttbiu", 0x9e, ibm032_RI}, + {"n", 0xe5, ibm032_RR}, + + {"nilo", 0xc6, ibm032_D}, + {"nilz", 0xc5, ibm032_D}, + {"niuo", 0xd6, ibm032_D}, + {"niuz", 0xd5, ibm032_D}, + {"o", 0xe3, ibm032_RR}, + {"oil", 0xc4, ibm032_D}, + {"oiu", 0xc3, ibm032_D}, + {"onec", 0xf4, ibm032_RR}, + {"s", 0xe2, ibm032_RR}, + {"sar", 0xb0, ibm032_RR}, + {"sari", 0xa0, ibm032_RI}, + {"sari16", 0xa1, ibm032_RI}, + {"se", 0xf2, ibm032_RR}, + {"setbl", 0x9b, ibm032_RI}, + {"setbu", 0x9a, ibm032_RI}, + {"setsb", 0x97, ibm032_RI}, + {"sf", 0xb2, ibm032_RR}, + + {"sfi", 0xd2, ibm032_D}, + + {"sis", 0x92, ibm032_RI}, + {"sl", 0xba, ibm032_RR}, + {"sli", 0xaa, ibm032_RI}, + {"sli16", 0xab, ibm032_RI}, + {"slp", 0xbb, ibm032_RR}, + {"slpi", 0xae, ibm032_RI}, + {"slpi16", 0xaf, ibm032_RI}, + {"sr", 0xb8, ibm032_RR}, + {"sri", 0xa8, ibm032_RI}, + {"sri16", 0xa9, ibm032_RI}, + {"srp", 0xb9, ibm032_RR}, + {"srpi", 0xac, ibm032_RI}, + {"srpi16", 0xad, ibm032_RI}, + + {"st", 0xdd, ibm032_D}, + + {"stc", 0xde, ibm032_D}, + {"stcs", 0x10, ibm032_DS0}, + {"sth", 0xdc, ibm032_D}, + {"sths", 0x20, ibm032_DS1}, + {"stm", 0xd9, ibm032_D}, + {"sts", 0x30, ibm032_DS2}, + {"svc", 0xc0, ibm032_D}, + {"tgte", 0xbd, ibm032_RR}, + {"ti", 0xcc, ibm032_D}, + {"tlt", 0xbe, ibm032_RR}, + {"tsh", 0xcf, ibm032_D}, + {"twoc", 0xe4, ibm032_RR}, + {"wait", 0xf0, ibm032_RR}, + {"x", 0xe7, ibm032_RR}, + {"xil", 0xc7, ibm032_D}, + {"xiu", 0xd7, ibm032_D} +}; + +/* Code to generate the packed opcode table from the instructions table. */ + +#include + +char *typeNames[] = { + "ibm032_JI", + "ibm032_X", + "ibm032_DS0", + "ibm032_DS1", + "ibm032_DS2", + "ibm032_RR", + "ibm032_RI", + "ibm032_BI", + "ibm032_BA", + "ibm032_D" +}; + +main() +{ + + int i, j, opcode, type; + + for (j = (sizeof(ibm032_instructions) / sizeof(struct ibm032_instruction)); j >= 0; j--) { + opcode = ibm032_instructions[j].opcode; + switch (ibm032_instructions[j].type & ibm032_typeMask) { + case ibm032_JI: + i = 7; + break; + case ibm032_X: + case ibm032_DS0: + case ibm032_DS1: + case ibm032_DS2: + i = 15; + break; + case ibm032_RR: + case ibm032_RI: + default: + i = 0; + break; + } + for (;i >= 0; i--) { + ibm032_opcodes[opcode + i].mnemonic = ibm032_instructions[j].mnemonic; + ibm032_opcodes[opcode + i].type = ibm032_instructions[j].type; + } + } + + printf("struct ibm032_opcode ibm032_opcodes[] = {\n"); + for ( j = 0; j < 256; j++) { + type = ibm032_opcodes[j].type; + if (ibm032_opcodes[j].mnemonic != NULL) + printf(" {\"%s\",\t\t%s%s%s},\n", ibm032_opcodes[j].mnemonic, + typeNames[type & ibm032_typeMask], + (type & ibm032_conditional) ? " | ibm032_conditional" : "", + (type & ibm032_negative) ? " | ibm032_negative" : ""); + else + printf(" {0,\t\t\t0},\n"); + } + printf("};\n"); +} +#endif /* BUILDTABLE */ + +Only in .: ibm032-pinsn.c + +/* Print ibm032 instructions for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "ibm032-opcode.h" + +/* ibm032 instructions are never longer than this many bytes. */ +#define MAXLEN 4 + +extern char *reg_names[]; + +static char *mapCondition(); + + +/* Print the ibm032 instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + int opcodeIndex, instructionBits, type; + char *mnemonic; + + read_memory (memaddr, buffer, MAXLEN); + instructionBits = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]; /* Get it into an int for easy use. */ + + if ((mnemonic = ibm032_opcodes[opcodeIndex = buffer[0]].mnemonic) == NULL) + { + fprintf (stream, "0%o", (instructionBits & HIGH16) >> 16); + return 2; + } + type = ibm032_opcodes[opcodeIndex].type; + if (!(type & ibm032_conditional)) { + fprintf (stream, "%s", mnemonic); + + switch (type) { + + int displacement; /* Used for sign extensions. */ + char *sign; + + case ibm032_X: + fprintf(stream, "\t%s, %s(%s)", reg_names[buffer[0] & LOW4], (buffer[1] & HIGH4) ? (reg_names[(buffer[1] & HIGH4) >> 4]) : "", reg_names[buffer[1] & LOW4]); + return 2; + case ibm032_DS0: + case ibm032_DS1: + case ibm032_DS2: + fprintf(stream, "\t%s, %x", reg_names[(buffer[1] & HIGH4) >> 4], (buffer[0] & LOW4) << (ibm032_opcodes[opcodeIndex].type - ibm032_DSShiftOffset)); /* Hacked to shift imediate field. */ + if (buffer[1] & LOW4) + fprintf(stream, "(%s)", reg_names[buffer[1] & LOW4]); + return 2; + case ibm032_RR: + fprintf(stream, "\t%s, %s", reg_names[(buffer[1] & HIGH4) >> 4], reg_names[buffer[1] & 0x0f]); + return 2; + case ibm032_RI: + fprintf(stream, "\t%s, %x", reg_names[(buffer[1] & HIGH4) >> 4], buffer[1] & LOW4); + return 2; + case ibm032_BI: + fprintf(stream, "\t%s, ", reg_names[(buffer[1] & HIGH4) >> 4]); + displacement = (instructionBits & LOW20); + if ((displacement & (1 << 19)) != 0) /* Cover sign extension. */ + displacement |= 0xfff00000; + print_address(memaddr + (displacement * 2), stream); /* Need sign extension. */ + return 4; + case ibm032_BA: + print_address((instructionBits & LOW24) & ~1, stream); + return 4; + case ibm032_D: + displacement = (instructionBits & LOW16); + if ((displacement & (1 << 15)) != 0) { /* Cover sign extension. */ + displacement = - (displacement | 0xffff0000); + sign = "-"; + } + else + sign = ""; + fprintf(stream, "\t%s, %s, %s%x", reg_names[(buffer[1] & HIGH4) >> 4], reg_names[buffer[1] & LOW4], sign, displacement); + return 4; + } + } + else { /* Conditional branches are hacked. */ + switch (type & 0x0f) { + + int displacement; + + case ibm032_JI: + fprintf(stream, ibm032_opcodes[opcodeIndex].mnemonic, mapCondition(type & ibm032_negative, buffer[0] & LOW4)); + putc('\t', stream); + print_address((buffer[1] << 1) + memaddr, stream); + return 2; + case ibm032_BI: + fprintf(stream, ibm032_opcodes[opcodeIndex].mnemonic, mapCondition(type & ibm032_negative, (buffer[1] & HIGH4) >> 4)); + putc('\t', stream); + displacement = (instructionBits & LOW20); + if ((displacement & (1 << 19)) != 0) /* Cover sign extension. */ + displacement |= 0xfff00000; + print_address((displacement * 2) + memaddr, stream); + return 4; + case ibm032_RR: + fprintf(stream, ibm032_opcodes[opcodeIndex].mnemonic, mapCondition(type & ibm032_negative, (buffer[1] & HIGH4) >> 4)); + fprintf(stream, "\t%s", reg_names[buffer[1] & LOW4]); + return 2; + } + } +} + +/* Converts a 4 bit "conditional specifier" into a semi-meaningful name. */ +static char *mapCondition(negative, conditionBits) + int conditionBits; +{ + + char *condition; + + if (negative) + switch (conditionBits) { + case 0x8: + condition = ""; + break; + case 0x9: + condition = "ge"; + break; + case 0xa: + condition = "ne"; + break; + case 0xb: + condition = "le"; + break; + case 0xc: + condition = "nc"; + break; + case 0xd: /* Reserved. */ + condition = "notbogus"; + break; + case 0xe: + condition = "no"; + break; + case 0xf: + condition = "ntb"; + break; + default: + condition = "notbogus"; + break; + } + else + switch (conditionBits) { + case 0x8: + condition = "nop"; + break; + case 0x9: + condition = "lt"; + break; + case 0xa: + condition = "eq"; + break; + case 0xb: + condition = "gt"; + break; + case 0xc: + condition = "c"; + break; + case 0xd: /* Reserved. */ + condition = "bogus"; + break; + case 0xe: + condition = "o"; + break; + case 0xf: + condition = "tb"; + break; + default: + condition = "bogus"; + break; + } + return condition; +} + +Only in .: m-ibm032.h + +/* Parameters for execution on an IBM RT, for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* 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, 1) & 0x00ff; \ + if (op == 0xd9) { \ + pc += 4; \ + op = read_memory_integer (pc, 2); \ + if ((op & 0xff00) == 0xc100) { /* pcc prolog add r1, number */ \ + pc += 4; \ + op = read_memory_integer (pc, 1) & 0x00ff; \ + if (op == 0x6e) { /* cas r14, 0 */ \ + pc += 2; \ + op = read_memory_integer (pc, 2) & 0xffff; \ + if (op == 0xc8d1) pc += 4; /* cal r13, junk(r1) */ \ + } \ + } \ + else if ((op & 0xffff) == 0x6e00) { /* hc prolog cas r14, 0 */ \ + pc += 4; \ + op = read_memory_integer(pc, 1) & 0xff; \ + if (op == 0x6d) { /* cas r13 junk, probably */ \ + pc += 2; \ + op = read_memory_integer(pc, 2) & 0xffff; \ + if (op == 0xc811) pc += 4; /* cal r1, foo(r1) */ \ + } \ + } \ + } \ + while (1) { \ + /* now watch for st, sth, stc, and short versions thereof, cas instructions and exts */ \ + /* which are all used to store the parameters from r2-r5 onto the stack or into reg vars */ \ + op = read_memory_integer (pc, 2); \ + if ((op & 0xff00) == 0x3000 && (op & 0xf0) >= 0x20 && (op & 0xf0) <= 0x50) pc += 2; \ + else if ((op & 0xff00) == 0x2300 && (op & 0xf0) >= 0x20 && (op & 0xf0) <= 0x50) pc += 2; \ + else if ((op & 0xff00) == 0x1b00 && (op & 0xf0) >= 0x20 && (op & 0xf0) <= 0x50) pc += 2; \ + else if ((op & 0xff00) == 0x6c00 && (op & 0xf0) >= 0x20 && (op & 0xf0) <= 0x50) pc += 2; \ + else if ((op & 0xff00) == 0xb100) pc += 2; /* extend sign */ \ + else if ((op & 0xff00) == 0xdd00 && (op & 0xf0) >= 0x20 && (op & 0xf0) <= 0x50) pc += 4; \ + else break; \ + } \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) \ +read_register (15) + +/* 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 (0x20000000 - NBPG * (UPAGES)) + +/* Address of end of stack space. */ + +/* extra page is for the "red zone" */ +#define STACK_END_ADDR (0x20000000 - NBPG * (UPAGES+1)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xbd, 0x00} + +/* 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. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) & 0x00ff == 0xc9) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 18 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "iar", "mq"} + +/* 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. */ + +#define FP_REGNUM 13 /* Contains address of executing stack frame */ +#define SP_REGNUM 1 /* Contains address of top of stack */ +#define PS_REGNUM 17 /* Contains processor status */ +#define PC_REGNUM 16 /* Contains program counter */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = blockend + regno * 4; } + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (NUM_REGS*4) + +/* 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. On the vax, all regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) 4 + +/* Number of bytes of storage in the program's representation + for register N. On the vax, all regs are 4 bytes. */ + +#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), 4); + +/* 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), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +/* 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 Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (rt_prev_frame(thisframe)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain >= 0x10000000 && chain < 0x20000000) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (rt_frame_reg(frame, 15)) + +#define FRAME_ARGS_ADDRESS(fi) (rt_frame_args(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(val, fi) \ +{register struct rt_frame *tf; \ + tf = get_cached_frame(fi.frame); \ + val = -1; \ + if (tf) val = tf->nParms;\ +} + +/* 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) \ +{ register int regnum; \ + register struct rt_frame *tf; \ + register CORE_ADDR next_addr; \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + tf = get_cached_frame((frame_info).frame); \ + if (tf) { \ + for(regnum = tf->firstReg; regnum < 16; regnum++) { \ + (frame_saved_regs).regs[regnum] = tf->firstRLoc+ 4*(regnum - tf->firstReg); \ + } \ + } \ +} + + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM);\ + register int regnum; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + for (regnum = 15; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (FP_REGNUM, sp+64); \ + write_register (SP_REGNUM, sp); } + +/* discard special frame pushed by PUSH_DUMMY_FRAME */ +#define POP_DUMMY_FRAME \ + {register CORE_ADDR sp; \ + register int regnum; \ + sp = read_register(FP_REGNUM)-64; \ + for(regnum = 0; regnum < 16;regnum++) { \ + write_register(regnum, read_memory_integer(sp, 4)); \ + sp += 4; \ + } \ + /* now get the pc */ \ + write_register(PC_REGNUM, read_memory_integer(sp, 4)); \ + sp += 4; \ + } + +/* Discard from the stack the innermost frame, restoring all registers. */ +/* THIS ROUTINE DOES NOT SET R1 (SP_REGNUM) CORRECTLY */ +/* REALLY MUST CONSULT TRACE TBL TO FIND OUT FRAME SIZE */ +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + register struct rt_frame *tf; \ + tf = (struct rt_frame *) get_cached_frame(fp); \ + if (tf) { \ + for(regnum = tf->firstReg; regnum < 16; regnum++) { \ + write_register(regnum, \ + read_memory_integer (tf->firstRLoc + 4*(regnum-tf->firstReg), 4) \ + ); \ + } \ + write_register(PC_REGNUM, read_register(15)); \ + write_register(SP_REGNUM, tf->firstRLoc + 4*(16-tf->firstReg) + 36); \ + } \ +} + +/* This sequence of words is the instructions + ls r2,0(r1) 2 bytes pick up args + ls r3,4(r1) 2 bytes pick up args + ls r4,8(r1) 2 bytes pick up args + ls r5,c(r1) 2 bytes pick up args + cal r1,16(r1) 4 bytes fix up ap (==sp) + cal16 r15, 4 bytes do call + oiu r15,(r15) 4 + lr r0,r15 2 + ls r15,0(r15) 2 + balr r15 2 + bpt 2 get back to gdb + <4 byte trace table> 4 + +This is 16 bytes. +*/ + +#define CALL_DUMMY {0x70217131, 0x72417351, 0xc8110010, 0xc2f06969, \ + 0xc3ff6969, 0x60f070ff, 0xecffbd00, 0xdf7fdf00} + +#define CALL_DUMMY_LENGTH 32 + +#define CALL_DUMMY_START_OFFSET 0 + +/* 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, fun, nargs) \ +{ *((short *)(((char *)dummyname)+14)) = fun&0xffff; \ +*((short *)(((char *)dummyname)+18)) = (fun>>16)&0xffff; \ +} + +/* 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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, which we do not support. */ + +#define INIT_STACK(beg, end) \ +{ } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ +{ } + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ +{ } + +/* 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 \ +{ } + +/* 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 \ +{ } + +Only in .: m-ibm032init.h + +/* This is how the size of an individual .o file's text segment + is rounded on a sun. */ + +#define FILEADDR_ROUND(addr) ((addr + 3) & -4) + +diff -c ../../gnu/gdb/blockframe.c ./blockframe.c +*** ../../gnu/gdb/blockframe.c Sat Apr 4 22:06:18 1987 +--- ./blockframe.c Mon Apr 27 01:06:06 1987 +*************** +*** 53,62 **** + } + + void +! set_current_frame (frame) + FRAME frame; + { + current_frame = frame; + } + + /* Return the frame that called FRAME. +--- 53,67 ---- + } + + void +! set_current_frame (frame, validp) + FRAME frame; ++ int validp; + { + current_frame = frame; ++ #ifdef ibm032 ++ if (validp) ++ recache_frames(); ++ #endif + } + + /* Return the frame that called FRAME. +*************** +*** 291,301 **** + CORE_ADDR pc; + { + register int i; + + /* Note that the last thing in the vector is always _etext. */ + for (i = 0; i < misc_function_count; i++) + { +! if (pc < misc_function_vector[i].address) + return i - 1; + } + return -1; +--- 296,309 ---- + CORE_ADDR pc; + { + register int i; ++ register long j; + + /* Note that the last thing in the vector is always _etext. */ + for (i = 0; i < misc_function_count; i++) + { +! if ((j = misc_function_vector[i].address) < 0) +! continue; +! if (pc < j) + return i - 1; + } + return -1; +*************** +*** 325,333 **** +--- 333,610 ---- + } + } + ++ #ifdef ibm032 ++ /* RT frame format: ++ arg 3 these are not really here, but are in regs ++ arg 2 ++ arg 1 ++ arg 0 ++ resvd 20 bytes ++ rn to r15 saved regs ++ floating regs (at first assume 0 bytes, fix later) ++ locals ++ ++ N.B. r13 points 64 bytes below the end of the locals. ++ */ ++ ++ /* ++ * Routine for ibm032 stack trace. Called after a new frame has been set. Do an entire stack ++ * trace, and squirrel away the information. We need to do this since the ibm032 (rt) does ++ * not have enough info in a known place off of the frame ptr (r13) to do anything useful. ++ * Instead, one also requires the pc, and can then perform various operations to find ++ * out how that procedure built its frame, and thus, to decode it. However, since this is ++ * fairly slow, we only do it after a set_current_frame operation has been performed. ++ */ ++ ++ #define rtTTSize 50 ++ static struct rtTTCache { ++ CORE_ADDR lbound; /* lowest address so far known as using this trace table */ ++ CORE_ADDR ttaddr; /* address of the last '0xdf' in the trace table */ ++ char ttype; /* type of the trace table -- 0 == unused */ ++ } ttcache[rtTTSize]; ++ short ttptr = 0; ++ ++ #define rtSize 50 ++ static struct rt_frame rtFrames[rtSize]; ++ static int rtCount; ++ static CORE_ADDR rt_next_frame, rt_next_pc; ++ ++ static struct rtTTCache *ttfind (addr) ++ CORE_ADDR addr; { ++ register int i; ++ register struct rtTTCache *tp; ++ for(i=0,tp=ttcache;i= tp->lbound && addr <= tp->ttaddr) return tp; ++ } ++ return 0; ++ } ++ ++ static ttadd(lowaddr, ttaddr, type) ++ register CORE_ADDR lowaddr, ttaddr; ++ char type; { ++ register struct rtTTCache *tp; ++ if (tp = ttfind(ttaddr)) { ++ /* possibly increase the bound on this cache element */ ++ if (lowaddr < tp->lbound) tp->lbound = lowaddr; ++ } ++ else { ++ /* add a new element */ ++ tp = &ttcache[ttptr++]; ++ tp->lbound = lowaddr; ++ tp->ttaddr = ttaddr; ++ tp->ttype = type; ++ if (ttptr >= rtTTSize) ttptr = 0; /* keep it in bounds */ ++ } ++ } ++ ++ /* this routine scans for a trace table, and returns 4 bytes: 0 0 */ ++ rt_num_regs (pc, tf) ++ register struct rt_frame *tf; ++ CORE_ADDR pc; { ++ register state = 0; ++ register long newpc = pc; ++ register int tc; ++ short nparms, firstreg; ++ short ttype; ++ short optx; ++ long offset; ++ char offtype; ++ struct rtTTCache *tp; ++ CORE_ADDR frame; ++ ++ frame = tf->frame; ++ /* first see if it is in our ttcache */ ++ if (tp = ttfind(pc)) { ++ state = 3; ++ ttype = tp->ttype; ++ newpc = tp->ttaddr; ++ } ++ else { ++ /* state machine to look for 'df' 'xx' 'df' */ ++ while (1) { ++ tc = read_memory_integer(newpc, 2); ++ if (state == 0 && (tc&0xff00) == 0xdf00) { ++ state = 1; ++ ttype = tc & 0xff; ++ } ++ else if (state == 1 && (tc & 0xff00) == 0xdf00) { ++ state = 3; ++ break; ++ } ++ else state = 0; ++ if (newpc - pc > 20000) break; ++ newpc += 2; ++ } ++ if (state == 3) ttadd(pc, newpc, ttype); /* add to cache */ ++ } ++ if (state != 3) { ++ printf("No trace table for pc %x, making one up.\n", pc); ++ tf->nParms = 0; ++ tf->firstReg = 12; ++ tf->firstRLoc = frame+64; ++ rt_next_pc = read_memory_integer(frame+64+12, 4); ++ rt_next_frame = read_memory_integer(frame+64+4, 4); ++ return 0; ++ } ++ /* otherwise newpc is pointing at the last 'df' in the trace table */ ++ else if (ttype == 3) { ++ /* funny trace table found by OBSERVATION (not doc) to be in program prolog */ ++ return -1; /* special value checked by recache_frames */ ++ } ++ else if (ttype == 2) { ++ /* assembly: no registers were saved */ ++ tf->nParms = 0; ++ tf->firstReg = 16; ++ tf->firstRLoc = 0; ++ rt_next_pc = read_register(15); /* where we go back to */ ++ rt_next_frame = frame; ++ tf->frame -= 100; /* hack to eliminate duplicate tags */ ++ return 0; ++ } ++ else if (ttype == 0x7f) { ++ /* special machine state frame saved by STACK_DUMMY */ ++ tf->nParms = 0; ++ tf->firstReg = 16; ++ tf->firstRLoc = 0; ++ rt_next_pc = read_memory_integer(frame + 64 - 64, 4); ++ rt_next_frame = read_memory_integer(frame -64 + 13*4, 4); ++ return 0; ++ } ++ else { ++ /* C program, I hope */ ++ nparms = (read_memory_integer(newpc+2, 1) >> 4) & 0x0f; ++ firstreg = ((tc=read_memory_integer(newpc+1, 1)) >> 4) & 0x0f; ++ optx = ((tc&4)? 1 : 0); /* flags says if floating registers described */ ++ offtype = read_memory_integer(newpc+optx+3, 1) & 0xff; ++ if ((offtype & 0xc0) == 0) { ++ /* 6 bits of local offset */ ++ offset = offtype & 0x3f; ++ } ++ else if ((offtype & 0xc0) == 0x40) { ++ /* 14 bits of local offset */ ++ offset = (offtype & 0x3f) << 8; ++ offset += (read_memory_integer(newpc+optx+4, 1) & 0xff); ++ } ++ else if ((offtype & 0xc0) == 0x80) { ++ /* 22 bits of local offset */ ++ offset = (offtype & 0x3f) << 8; ++ offset += (read_memory_integer(newpc+optx+4, 1) & 0xff); ++ offset <<= 8; ++ offset += (read_memory_integer(newpc+optx+5, 1) & 0xff); ++ } ++ else if ((offtype & 0xc0) == 0xc0) { ++ /* 30 bits of local offset */ ++ offset = (offtype & 0x3f) << 8; ++ offset += (read_memory_integer(newpc+optx+4, 1) & 0xff); ++ offset <<= 8; ++ offset += (read_memory_integer(newpc+optx+5, 1) & 0xff); ++ offset <<= 8; ++ offset += (read_memory_integer(newpc+optx+6, 1) & 0xff); ++ } ++ offset <<= 2; ++ tf->nParms = nparms; ++ tf->firstReg = firstreg; ++ tf->firstRLoc = frame /* initial frame location */ ++ + offset /* to top of frame */ ++ - 36 /* pascal static link, incomings args and linkage */ ++ - (4*(16-firstreg)); /* space used by general regs */ ++ rt_next_pc = read_memory_integer(tf->firstRLoc + 4*(15-firstreg), 4); ++ rt_next_frame = read_memory_integer(tf->firstRLoc + 4*(13-firstreg), 4); ++ return 0; ++ } ++ } ++ ++ recache_frames() { ++ register long i, j; ++ long pc; ++ CORE_ADDR curfp; ++ struct rt_frame *tf; ++ ++ pc = read_pc(); ++ curfp = current_frame; ++ rtCount = 0; ++ /* these next special cases can only occur with frame #0; others can't make calls ++ in these intermediate states. ++ */ ++ /* if pc points at br or brx, we're doing a return, so set the pc to the target */ ++ i=read_memory_integer(pc, 2); ++ if ((i & 0xfe00) == 0xe800) { ++ /* we're looking at a br or brx instruction */ ++ pc = read_register(i&0x0f); ++ } ++ /* also, if pc points at d9xx or c111 we're in the middle of a frame push, and should ++ use r15 for the pc. ++ */ ++ if ((i & 0xff00) == 0xd900 || (i & 0xffff) == 0xc111) { ++ pc = read_register(15); ++ } ++ while (1) { ++ if (curfp <= 0x10000000 || curfp >= 0x20000000) break; ++ if (pc > 0x20000000) break; ++ /* otherwise try to add a new frame structure */ ++ if (rtCount >= rtTTSize) break; ++ tf = &rtFrames[rtCount++]; ++ tf->frame = curfp; ++ tf->pc = pc; ++ i = rt_num_regs(pc, tf); ++ if (i<0) { /* exceptional values */ ++ rtCount--; /* last frame was bogus */ ++ break; ++ } ++ /* now setup for next iteration */ ++ pc = rt_next_pc; ++ curfp = rt_next_frame; ++ } ++ } ++ ++ struct rt_frame *get_cached_frame(aframe) ++ CORE_ADDR aframe; { ++ register int i; ++ for(i=0;ifirstReg > reg) return 0; /* didn't save this one! */ ++ return read_memory_integer(tf->firstRLoc + 4 * (reg - tf->firstReg), 4); ++ } ++ ++ long rt_frame_args(frame) ++ CORE_ADDR frame; { ++ register struct rt_frame *tf; ++ tf = get_cached_frame(frame); ++ if (!tf) return 0; ++ return tf->firstRLoc + 20 + 4*(16 - tf->firstReg); ++ } ++ #endif ++ ++ blockinitialize() {initialize();} ++ + static + initialize () + { ++ #ifdef ibm032 ++ #ifdef CAMPHOR ++ add_com ("recache-frames", class_stack, recache_frames, ++ "Tell debugger to recompute PC/RT stack frame cache\n"); ++ #endif ++ #endif + } + + END_FILE +diff -c ../../gnu/gdb/breakpoint.c ./breakpoint.c +*** ../../gnu/gdb/breakpoint.c Sat Apr 4 22:22:44 1987 +--- ./breakpoint.c Sun Apr 26 23:02:20 1987 +*************** +*** 94,99 **** +--- 94,100 ---- + of last breakpoint hit. */ + + struct command_line *breakpoint_commands; ++ char new_breakpoint_commands = 0; /* Zalman Stern, ITC 1/12/1987 */ + + START_FILE + +*************** +*** 203,210 **** + { + execute_command (breakpoint_commands->line, 0); + /* If command was "cont", breakpoint_commands is 0 now. */ +! if (breakpoint_commands) + breakpoint_commands = breakpoint_commands->next; + } + clear_momentary_breakpoints (); + } +--- 204,213 ---- + { + execute_command (breakpoint_commands->line, 0); + /* If command was "cont", breakpoint_commands is 0 now. */ +! if (breakpoint_commands && !new_breakpoint_commands) /* Zalman Stern, ITC 1/12/1987 */ + breakpoint_commands = breakpoint_commands->next; ++ else /* Zalman Stern, ITC 1/12/1987 */ ++ new_breakpoint_commands = 0; /* Zalman Stern, ITC 1/12/1987 */ + } + clear_momentary_breakpoints (); + } +*************** +*** 215,220 **** +--- 218,225 ---- + void + clear_breakpoint_commands () + { ++ if (breakpoint_commands != 0) /* Zalman Stern, ITC 1/12/1987 */ ++ new_breakpoint_commands = 1; /* Zalman Stern, ITC 1/12/1987 */ + breakpoint_commands = 0; + breakpoint_auto_delete (0); + } +*************** +*** 921,926 **** +--- 926,933 ---- + struct cmd_list_element *enablelist; + + extern struct cmd_list_element *cmdlist; ++ ++ breakinitialize() {initialize();} + + static + initialize () +diff -c ../../gnu/gdb/command.c ./command.c +*** ../../gnu/gdb/command.c Sat Apr 4 22:24:07 1987 +--- ./command.c Sat Apr 25 17:18:15 1987 +*************** +*** 94,100 **** + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! */ + +- + #include "command.h" + #include + +--- 94,99 ---- +*************** +*** 388,394 **** + { + if (nfound > 1 && allow_unknown >= 0) + { +! *p = 0; + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (*line, c->name, p - *line)) +--- 387,393 ---- + { + if (nfound > 1 && allow_unknown >= 0) + { +! *p = 0; + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (*line, c->name, p - *line)) +diff -c ../../gnu/gdb/core.c ./core.c +*** ../../gnu/gdb/core.c Sat Apr 4 22:27:23 1987 +--- ./core.c Mon Apr 27 13:20:47 1987 +*************** +*** 163,172 **** + int reg_offset; + + /* 4.2bsd-style core dump */ + val = myread (corechan, &u, sizeof u); + if (val < 0) +! perror_with_name (filename); + 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; +--- 163,180 ---- + int reg_offset; + + /* 4.2bsd-style core dump */ ++ #ifdef ibm032 ++ /* on ibm032, uarea is at the far end of the u pages */ ++ lseek(corechan, UPAGES*NBPG - sizeof(u), 0); ++ #endif + val = myread (corechan, &u, sizeof u); + if (val < 0) +! perror_with_name (execfile); +! #ifdef ibm032 +! data_start = 0x10000000; +! #else + data_start = exec_data_start; ++ #endif + data_end = data_start + NBPG * u.u_dsize; + stack_start = stack_end - NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; +*************** +*** 208,214 **** + corefile = concat (dirname, "/", filename); + } + +! set_current_frame (read_register (FP_REGNUM)); + select_frame (get_current_frame (), 0); + validate_files (); + } +--- 216,222 ---- + corefile = concat (dirname, "/", filename); + } + +! set_current_frame (read_register (FP_REGNUM), 1); + select_frame (get_current_frame (), 0); + validate_files (); + } +*************** +*** 523,528 **** +--- 531,539 ---- + + #endif /* not NEW_SUN_CORE */ + ++ ++ coreinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/dbxread.c ./dbxread.c +*** ../../gnu/gdb/dbxread.c Sat Apr 4 22:29:54 1987 +--- ./dbxread.c Fri May 15 15:52:24 1987 +*************** +*** 28,33 **** +--- 28,36 ---- + #include "initialize.h" + #include "symtab.h" + #include "param.h" ++ #ifdef CAMPHOR ++ #include "value.h" ++ #endif + + static void add_symbol_to_list (); + static void read_dbx_symtab (); +*************** +*** 89,94 **** +--- 92,109 ---- + int prev_line_number; + }; + ++ /* When dealing with dynamically loaded objects, the symbol table in the sym file ++ does not match where we actually load the files. Thus, gdb has to relocate those ++ symbols during dbxread. This is only used by the camphor support code, and ++ probably should be under an ifdef camphor. */ ++ ++ struct dlreloc ++ { ++ long text; ++ long data; ++ long bss; ++ } dlreloc; ++ + static struct subfile *subfiles; + + static struct subfile *current_subfile; +*************** +*** 1015,1020 **** +--- 1030,1037 ---- + register int i, nbl; + register struct blockvector *bv; + register struct block *b; ++ int j; ++ struct symbol *ts1, *ts2; + + for (s = symtab_list; s; s = s->next) + { +*************** +*** 1025,1034 **** +--- 1042,1238 ---- + b = BLOCKVECTOR_BLOCK (bv, i); + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); ++ /* Register parms have two decls, but the register one is the only one of interest */ ++ /* So, trash the name of the bad one, since binary srch could get either. Yucko. */ ++ /* doing name this way enables symbol freeing code to keep working */ ++ for(j=1;jnext; ++ free (symseg_chain); ++ symseg_chain = s; ++ } ++ ++ if (in_this_dir && name[0] != '/') ++ { ++ char dirname[MAXPATHLEN]; ++ ++ getwd (dirname); ++ symfile = concat (dirname, "/", ++ savestring (name, strlen (name))); ++ } ++ else ++ symfile = savestring (name, strlen (name)); ++ ++ printf ("done.\n"); ++ fflush (stdout); ++ } ++ #endif ++ + /* This is the symbol-file command. Read the file, analyze its symbols, + and add a struct symtab to symtab_list. */ + +*************** +*** 1047,1052 **** +--- 1251,1263 ---- + + dont_repeat (); + ++ #ifdef CAMPHOR ++ /* this command does not deal with automatically relocated stuff */ ++ dlreloc.text = 0; ++ dlreloc.data = 0; ++ dlreloc.bss = 0; ++ #endif ++ + if (name == 0) + error_no_arg ("file to read symbols from"); + +*************** +*** 1130,1151 **** + + read_dbx_symtab (desc, stringtab, hdr.a_syms / sizeof (struct nlist)); + + /* Sort symbols alphabetically within each block. */ + +! sort_syms (); + + /* Go over the misc functions and install them in vector. */ + +! condense_misc_bunches (); + + /* 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. */ + +! select_source_symtab (symtab_list); + + symfile = savestring (name, strlen (name)); + + do_cleanups (old_chain); +--- 1341,1372 ---- + + read_dbx_symtab (desc, stringtab, hdr.a_syms / sizeof (struct nlist)); + ++ /* Check to make sure file was compiled with -g. */ ++ ++ if (symtab_list == NULL) { ++ printf("\n%s not compiled with -g, debugging posibilities are limited.\n", name); ++ fflush(stdout); ++ } ++ else { ++ + /* Sort symbols alphabetically within each block. */ + +! sort_syms (); + + /* Go over the misc functions and install them in vector. */ + +! condense_misc_bunches (); + + /* 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. */ + +! select_source_symtab (symtab_list); + ++ } ++ + symfile = savestring (name, strlen (name)); + + do_cleanups (old_chain); +*************** +*** 1204,1209 **** +--- 1425,1440 ---- + { + fread (&buf, sizeof buf, 1, stream); + namestring = buf.n_un.n_strx ? buf.n_un.n_strx + stringtab : 0; ++ #ifdef CAMPHOR ++ if ((buf.n_type & N_TYPE) == N_UNDF) { ++ /* don't screw around with undefined symbols */ ++ } ++ else { ++ if ((buf.n_type & N_TYPE) == N_TEXT) buf.n_value += dlreloc.text; ++ else if ((buf.n_type & N_TYPE) == N_DATA) buf.n_value += dlreloc.data; ++ else if ((buf.n_type & N_TYPE) == N_BSS) buf.n_value += dlreloc.bss; ++ } ++ #endif + if (buf.n_type & N_STAB) + process_one_symbol (buf.n_type, buf.n_desc, + buf.n_value, namestring); +*************** +*** 1356,1361 **** +--- 1587,1596 ---- + } + } + ++ #ifdef ibm032 ++ static char hcState; /* two different, incompatible compilers for the RT */ ++ #endif ++ + static void + process_one_symbol (type, desc, value, name) + int type, desc; +*************** +*** 1363,1369 **** + char *name; + { + register struct context_stack *new; +! + /* Something is wrong if we see real data before + seeing a source file name. */ + +--- 1598,1633 ---- + char *name; + { + register struct context_stack *new; +! char tname[256]; +! /* Now, there are two compilers for the RT, and they are seriously incompatible. +! pcc is just like normal c compilers: stabs for a block occur before the LBRAC +! stab for that same block. Thus this code squirrels them away in the context +! and when the RBRAC is hit, restores local_symbols as of the time the LBRAC +! was encountered, and adds these symbosl to the block that just ended. +! +! However, with the HC compiler, those symbols occur *after* the LBRAC symbol +! declaring the block's start. Totally incompatible, of course. One expects no +! less from IBM. For hc compiled programs, we use the symbols in local_symbols +! *before* the RBRAC command pops the context stack. +! +! Amazingly enough, when we complained to IBM/Palo Alto about this incompatibility, +! they claimed that Mark Linton (original author of dbx) liked the new way better, and +! that he didn't even know that pcc used a different order. Sorta explains some things +! about dbx, n'est-ce pas? Furthermore, of course, IBM doesn't want to change +! either pcc or hc. +! +! Anyway, hc and pcc compiled .o files often co-exist in programs. How do we +! tell which is which? Stupid heuristic which doesn't work with programs +! with no top-level locals or parameters: after seeing a function's start, if we see +! an LBRAC before seeing a variable, then we are using hc, otherwise it is pcc. +! Stupid heuristics are better than none, so we use it. +! +! The variable hcState is used to keep track of this crap. +! 0 ==> saw function symbol +! 1 ==> saw lbrac in state 0, this is hc. +! 2 ==> saw symbol in state 0, this is pcc. +! */ +! + /* Something is wrong if we see real data before + seeing a source file name. */ + +*************** +*** 1384,1389 **** +--- 1648,1656 ---- + also the end of the lexical context for the previous function. */ + new = context_stack; + within_function = 1; ++ #ifdef ibm032 ++ hcState = 0; ++ #endif + if (new) + { + /* Make a block for the local symbols within. */ +*************** +*** 1400,1406 **** +--- 1667,1679 ---- + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = value; ++ #ifdef ibm032 ++ strcpy(tname, "."); ++ strcat(tname, name); ++ new->name = define_symbol(value, tname); ++ #else + new->name = define_symbol (value, name); ++ #endif + local_symbols = 0; + break; + +*************** +*** 1407,1412 **** +--- 1680,1688 ---- + case N_LBRAC: + /* This "symbol" just indicates the start of an inner lexical + context within a function. */ ++ #ifdef ibm032 ++ if (hcState == 0) hcState = 1; ++ #endif + new = (struct context_stack *) xmalloc (sizeof (struct context_stack)); + new->depth = desc; + new->next = context_stack; +*************** +*** 1422,1430 **** + /* This "symbol" just indicates the end of an inner lexical + context that was started with N_RBRAC. */ + new = context_stack; + if (new == 0 || desc != new->depth) + error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum); +- local_symbols = new->locals; + context_stack = new->next; + /* If this is not the outermost LBRAC...RBRAC pair in the + function, its local symbols preceded it, and are the ones +--- 1698,1711 ---- + /* This "symbol" just indicates the end of an inner lexical + context that was started with N_RBRAC. */ + new = context_stack; ++ #ifdef ibm032 ++ if (hcState == 2) /* pcc */ ++ local_symbols = new->locals; ++ #else ++ local_symbols = new->locals; ++ #endif + if (new == 0 || desc != new->depth) + error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum); + context_stack = new->next; + /* If this is not the outermost LBRAC...RBRAC pair in the + function, its local symbols preceded it, and are the ones +*************** +*** 1443,1448 **** +--- 1724,1733 ---- + new->start_addr + last_source_start_addr, + value + last_source_start_addr); + } ++ #ifdef ibm032 ++ if (hcState == 1 && context_stack->next) /* hc */ ++ local_symbols = new->locals; /* now we get them */ ++ #endif + free (new); + break; + +*************** +*** 1493,1498 **** +--- 1778,1786 ---- + break; + + default: ++ #ifdef ibm032 ++ if (hcState == 0) hcState = 2; ++ #endif + if (name) + define_symbol (value, name); + } +*************** +*** 1553,1558 **** +--- 1841,1849 ---- + Dbx data never actually contains 'l'. */ + case 'l': + SYMBOL_CLASS (sym) = LOC_LOCAL; ++ #ifdef ibm032 ++ if (hcState == 1) value += 1000000; /* temporary hack until rel 3 pcc matches hc */ ++ #endif + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); +*************** +*** 1572,1577 **** +--- 1863,1875 ---- + add_symbol_to_list (sym, &local_symbols); + break; + ++ case 'R': ++ SYMBOL_CLASS (sym) = LOC_REGISTER; ++ SYMBOL_VALUE (sym) = value; ++ SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; ++ add_symbol_to_list (sym, &local_symbols); ++ break; ++ + case 'S': + /* Static symbol at top level of file */ + SYMBOL_CLASS (sym) = LOC_STATIC; +*************** +*** 1616,1622 **** + break; + + default: +! error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum); + } + return sym; + } +--- 1914,1928 ---- + break; + + default: +! printf ("Unknown symbol-type code '%c' in dbx symbol table, assuming local.\n", deftype); +! SYMBOL_CLASS (sym) = LOC_LOCAL; +! #ifdef ibm032 +! if (hcState == 1) value += 1000000; /* temporary hack until rel 3 pcc matches hc */ +! #endif +! SYMBOL_VALUE (sym) = value; +! SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; +! add_symbol_to_list (sym, &local_symbols); +! break; + } + return sym; + } +*************** +*** 1741,1746 **** +--- 2047,2056 ---- + (*pp) += 5; + else if (!strncmp (*pp, "r(0,1);0;", 9)) + (*pp) += 9; ++ #if 1 ++ else if ((**pp == 'r') && (!strncmp(*pp + 2, ";0;", 3))) ++ (*pp) += 5; ++ #endif + else break; + + TYPE_CODE (type) = TYPE_CODE_ARRAY; +*************** +*** 1980,1986 **** + rather than -128 which is what I would like. + So use n1 != 0 to prevent char from being taken as unsigned. */ + +! else if (n2 == 0 && n1 == 1) + { + /* an unsigned type */ + if (n3 == (1 << (8 * sizeof (int)))) +--- 2290,2296 ---- + rather than -128 which is what I would like. + So use n1 != 0 to prevent char from being taken as unsigned. */ + +! if (n2 == 0) + { + /* an unsigned type */ + if (n3 == (1 << (8 * sizeof (int)))) +*************** +*** 1989,1994 **** +--- 2299,2306 ---- + return builtin_type_unsigned_short; + if (n3 == (1 << (8 * sizeof (char)))) + return builtin_type_unsigned_char; ++ if (n3 == (1 << (8 * sizeof (char) - 1))) ++ return builtin_type_char; + } + else + { +*************** +*** 2002,2007 **** +--- 2314,2321 ---- + if (n3 == (1 << (8 * sizeof (char) - 1))) + return builtin_type_char; + } ++ if (n2 == 0 && n3 == 1) ++ return builtin_type_void; + error ("Invalid symbol data: range type spec %s at symtab pos %d.", + errp - 1, symnum); + } +*************** +*** 2033,2040 **** +--- 2347,2364 ---- + + /* Read the digits, as far as they go. */ + ++ #if 0 /* Yet another "Compiler sucks" fix. */ + while ((c = *p++) >= '0' && c <= '9') ++ #else ++ while (((c = *p++) >= '0' && c <= '9') || ((end != '\n') && (c == '\n'))) ++ #endif + { ++ #if 1 ++ if (c == '\n') { ++ printf("Ignoring bogus newline in stabs entry. Your compiler should be fixed.\n"); ++ continue; ++ } ++ #endif + n *= 10; + n += c - '0'; + } +*************** +*** 2050,2060 **** +--- 2374,2392 ---- + return n * sign; + } + ++ dbxinitialize() {initialize();} ++ + static + initialize () + { + symfile = 0; + ++ #ifdef CAMPHOR ++ add_com ("add-file", class_files, add_file_command, ++ "Add a new symbol table (in dbx format) from file FILE."); ++ add_com("set-rel", class_files, set_rel_command, ++ "Set relocation for add-file command to NUMBER."); ++ #endif + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table (in dbx format) from executable file FILE."); + } +diff -c ../../gnu/gdb/environ.c ./environ.c +*** ../../gnu/gdb/environ.c Sat Apr 4 22:31:16 1987 +--- ./environ.c Sun Apr 26 23:48:05 1987 +*************** +*** 129,135 **** + + if (e->allocated < i) + { +! e->allocated = max (i, e->allocated + 10); + e->vector = (char **) xrealloc (e->vector, + (e->allocated + 1) * sizeof (char *)); + } +--- 129,136 ---- + + if (e->allocated < i) + { +! e->allocated = i + 10; + e->vector = (char **) xrealloc (e->vector, + (e->allocated + 1) * sizeof (char *)); + } +diff -c ../../gnu/gdb/eval.c ./eval.c +*** ../../gnu/gdb/eval.c Sat Apr 4 22:32:36 1987 +--- ./eval.c Mon Apr 27 00:01:27 1987 +*************** +*** 546,551 **** +--- 546,553 ---- + } + } + ++ evalinitialize() {initialize();} ++ + static + initialize () + { } +diff -c ../../gnu/gdb/expread.y ./expread.y +*** ../../gnu/gdb/expread.y Sat Apr 4 22:35:27 1987 +--- ./expread.y Sun Apr 26 23:56:51 1987 +*************** +*** 650,655 **** +--- 650,656 ---- + ; + else + { ++ /*N.B. error does a longjmp, so we do not have to worry about storage */ + err_copy = (char *) alloca (olen + 1); + bcopy (lexptr, err_copy, olen); + err_copy[olen] = 0; +*************** +*** 945,953 **** + { + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); +! register struct expression *temp +! = (struct expression *) alloca (len); + register int inpos = expr->nelts, outpos = 0; + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); +--- 946,955 ---- + { + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); +! register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; ++ ++ temp = (struct expression *) alloca(len); + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); +diff -c ../../gnu/gdb/findvar.c ./findvar.c +*** ../../gnu/gdb/findvar.c Sat Apr 4 22:36:38 1987 +--- ./findvar.c Mon Apr 27 00:01:44 1987 +*************** +*** 359,364 **** +--- 359,366 ---- + return value_cast (lookup_pointer_type (SYMBOL_TYPE (var)), + value_from_long (builtin_type_long, addr)); + } ++ ++ findinitialize() {initialize();} + + static + initialize () +diff -c ../../gnu/gdb/firstfile.c ./firstfile.c +*** ../../gnu/gdb/firstfile.c Sat Apr 4 22:37:06 1987 +--- ./firstfile.c Mon Apr 27 00:02:06 1987 +*************** +*** 125,130 **** +--- 125,152 ---- + static initialize_dummy_1 (); + static initialize_dummy_2 (); + ++ initialize_all_files() { ++ blockinitialize(); ++ breakinitialize(); ++ coreinitialize(); ++ dbxinitialize(); ++ evalinitialize(); ++ findinitialize(); ++ infcmdinitialize(); ++ inflowinitialize(); ++ infruninitialize(); ++ symmiscinitialize(); ++ symtabinitialize(); ++ valarithinitialize(); ++ valopsinitialize(); ++ valprintinitialize(); ++ valuesinitialize(); ++ printcmdinitialize(); ++ sourceinitialize(); ++ stackinitialize(); ++ } ++ ++ #if 0 + initialize_all_files () + { + initialize_next_file ((char *) initialize_dummy_2 +*************** +*** 148,153 **** +--- 170,176 ---- + initialize_dummy_2 () + { + } ++ #endif + + /* This makes the function initialize_next_file. */ + +diff -c ../../gnu/gdb/frame.h ./frame.h +*** ../../gnu/gdb/frame.h Sat Apr 4 22:37:22 1987 +--- ./frame.h Mon Apr 27 00:02:14 1987 +*************** +*** 20,25 **** +--- 20,35 ---- + + /* Note that frame.h requires param.h! */ + ++ #ifdef ibm032 ++ struct rt_frame { ++ CORE_ADDR frame; /* frame address */ ++ CORE_ADDR pc; /* pc we called from */ ++ CORE_ADDR firstRLoc; /* loc'n of first saved general reg */ ++ short nParms; /* number of parameters to this frame */ ++ short firstReg; /* the reg stored at 64(fp) */ ++ }; ++ #endif ++ + #define FRAME CORE_ADDR + + struct frame_info +*************** +*** 62,64 **** +--- 72,77 ---- + extern struct block *get_selected_block (); + extern struct symbol *get_frame_function (); + extern struct symbol *get_pc_function (); ++ #ifdef ibm032 ++ extern struct rt_frame *get_cached_frame(); ++ #endif +diff -c ../../gnu/gdb/infcmd.c ./infcmd.c +*** ../../gnu/gdb/infcmd.c Sat Apr 4 22:47:22 1987 +--- ./infcmd.c Mon Apr 27 00:07:53 1987 +*************** +*** 39,45 **** + /* String containing arguments to give to the program, + with a space added at the front. Just a space means no args. */ + +! static char *inferior_args; + + /* Pid of our debugged inferior, or 0 if no inferior now. */ + +--- 39,45 ---- + /* String containing arguments to give to the program, + with a space added at the front. Just a space means no args. */ + +! static char *inferior_args = NULL; + + /* Pid of our debugged inferior, or 0 if no inferior now. */ + +*************** +*** 112,119 **** + set_args_command (args) + char *args; + { +! free (inferior_args); +! if (!args) args = ""; + inferior_args = concat (" ", args, ""); + } + +--- 112,121 ---- + set_args_command (args) + char *args; + { +! if (inferior_args != NULL) +! free (inferior_args); +! if (!args) +! args = ""; + inferior_args = concat (" ", args, ""); + } + +*************** +*** 171,177 **** + signal (SIGINT, SIG_DFL); */ + + ptrace (0); +! execle ("/bin/sh", "sh", "-c", allargs, 0, + environ_vector (inferior_environ)); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", +--- 173,180 ---- + signal (SIGINT, SIG_DFL); */ + + ptrace (0); +! +! execle ("/bin/csh", "csh", "-f", "-c", allargs, 0, + environ_vector (inferior_environ)); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", +*************** +*** 473,478 **** +--- 476,482 ---- + + retbuf[0] = stop_r0; + retbuf[1] = stop_r1; ++ + val = value_being_returned (value_type, retbuf); + printf ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, stdout); +*************** +*** 705,710 **** +--- 709,716 ---- + printf ("Contents are relative to selected stack frame.\n"); + } + ++ infcmdinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/inflow.c ./inflow.c +*** ../../gnu/gdb/inflow.c Sat Apr 4 22:56:34 1987 +--- ./inflow.c Mon Apr 27 00:12:10 1987 +*************** +*** 188,194 **** + inferior_pid = 0; + mark_breakpoints_out (); + if (have_core_file_p ()) +! set_current_frame (read_register (FP_REGNUM)); + } + + /* Resume execution of the inferior process. +--- 188,194 ---- + inferior_pid = 0; + mark_breakpoints_out (); + if (have_core_file_p ()) +! set_current_frame (read_register (FP_REGNUM), 1); + } + + /* Resume execution of the inferior process. +*************** +*** 266,271 **** +--- 266,274 ---- + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + ++ #ifdef ibm032 ++ offset += UPAGES*NBPG - sizeof(u); /* ibm032: ustruct at end of uarea */ ++ #endif + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + for (regno = 0; regno < NUM_REGS; regno++) + { +*************** +*** 291,296 **** +--- 294,303 ---- + register unsigned int regaddr; + char buf[80]; + ++ #ifdef ibm032 ++ offset += UPAGES*NBPG - sizeof(u); /* ibm032: ustruct at end of uarea */ ++ #endif ++ + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; + + if (regno >= 0) +*************** +*** 340,347 **** + 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)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + buffer[i] = ptrace (1, inferior_pid, addr, 0); +--- 347,355 ---- + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ +! register int *buffer; + ++ buffer = (int *) alloca(count * sizeof(int)); + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + buffer[i] = ptrace (1, inferior_pid, addr, 0); +*************** +*** 367,377 **** + 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. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + if (count > 1) + buffer[count - 1] +--- 375,386 ---- + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ +! register int *buffer; + extern int errno; + + /* Fill start and end extra bytes of buffer with existing memory data. */ + ++ buffer = (int *) alloca (count * sizeof (int)); + buffer[0] = ptrace (1, inferior_pid, addr, 0); + if (count > 1) + buffer[count - 1] +*************** +*** 388,397 **** + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); +! if (errno) + return 1; + } +- + return 0; + } + +--- 397,406 ---- + { + errno = 0; + ptrace (4, inferior_pid, addr, buffer[i]); +! if (errno) { + return 1; ++ } + } + return 0; + } + +*************** +*** 421,426 **** +--- 430,437 ---- + } + } + ++ inflowinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/infrun.c ./infrun.c +*** ../../gnu/gdb/infrun.c Sat Apr 4 22:57:15 1987 +--- ./infrun.c Mon Apr 27 00:17:40 1987 +*************** +*** 257,263 **** + pc_changed = 0; + fetch_inferior_registers (); + stop_pc = read_pc (); +! set_current_frame (read_register (FP_REGNUM)); + stop_frame = get_current_frame (); + stop_sp = read_register (SP_REGNUM); + another_trap = 0; +--- 257,271 ---- + pc_changed = 0; + fetch_inferior_registers (); + stop_pc = read_pc (); +! #ifdef CAMPHOR +! /* if we're not going to stop, don't bother with a stack trace */ +! if (WIFSTOPPED(w) && !signal_stop[WSTOPSIG(w)]) +! set_current_frame(read_register(FP_REGNUM), 0); +! else +! set_current_frame(read_register(FP_REGNUM), 1); +! #else +! set_current_frame (read_register (FP_REGNUM), 1); +! #endif + stop_frame = get_current_frame (); + stop_sp = read_register (SP_REGNUM); + another_trap = 0; +*************** +*** 688,700 **** + + /* Save the function value return registers + We might be about to restore their previous contents. */ +! stop_r0 = read_register (0); +! stop_r1 = read_register (1); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. */ + POP_FRAME; + select_frame (read_register (FP_REGNUM), 0); + } + } +--- 696,717 ---- + + /* Save the function value return registers + We might be about to restore their previous contents. */ +! #ifdef ibm032 +! stop_r0 = read_register (2); +! stop_r1 = read_register (3); +! #else +! stop_r0 = read_register (0); +! stop_r1 = read_register (1); +! #endif + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. */ ++ #ifdef ibm032 ++ POP_DUMMY_FRAME; ++ #else + POP_FRAME; ++ #endif + select_frame (read_register (FP_REGNUM), 0); + } + } +*************** +*** 841,846 **** +--- 858,865 ---- + printf ("\nUse the \"handle\" command to change these tables.\n"); + } + ++ infruninitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/initialize.h ./initialize.h +*** ../../gnu/gdb/initialize.h Sat Apr 4 22:58:27 1987 +--- ./initialize.h Sun May 24 00:19:21 1987 +*************** +*** 103,109 **** +--- 103,120 ---- + of the end of one object file's text to the start of the next + object file's text. */ + ++ /* Changed to use ifdefs on the machine type. David Nichols, 11/28/86 */ ++ #ifdef ibm032 ++ #include "m-ibm032init.h" ++ #endif ++ ++ #ifdef vax + #include "m-vaxinit.h" ++ #endif ++ ++ #ifdef sun ++ #include "m-suninit.h" ++ #endif + + /* This is used to make a file's initialization function. + It calls another function named `initialize', which must +diff -c ../../gnu/gdb/main.c ./main.c +*** ../../gnu/gdb/main.c Sat Apr 4 23:11:59 1987 +--- ./main.c Mon Apr 27 00:27:21 1987 +*************** +*** 236,241 **** +--- 236,243 ---- + if (*p) + { + c = lookup_cmd (&p, cmdlist, "", 0); ++ if (c->function == 0) ++ error ("That is not a command, just a help topic."); + if (c->class == (int) class_user) + { + if (*p) +*************** +*** 457,463 **** + + /* Add an element to the list of commands. */ + +! void + add_com (name, class, fun, doc) + char *name; + int class; +--- 459,465 ---- + + /* Add an element to the list of commands. */ + +! struct cmd_list_element * + add_com (name, class, fun, doc) + char *name; + int class; +*************** +*** 464,470 **** + void (*fun) (); + char *doc; + { +! add_cmd (name, class, fun, doc, &cmdlist); + } + + /* Add an alias or abbreviation command to the list of commands. */ +--- 466,473 ---- + void (*fun) (); + char *doc; + { +! +! return add_cmd (name, class, fun, doc, &cmdlist); + } + + /* Add an alias or abbreviation command to the list of commands. */ +*************** +*** 547,552 **** +--- 550,556 ---- + + if (c && c->class == (int) class_user) + free_command_lines (&c->function); ++ + + add_com (comname, class_user, cmds, + (c && c->class == (int) class_user) +diff -c ../../gnu/gdb/param.h ./param.h +*** ../../gnu/gdb/param.h Sat Apr 4 23:15:44 1987 +--- ./param.h Mon Apr 27 00:28:17 1987 +*************** +*** 1 **** +--- 1,19 ---- ++ /* Changed to use ifdefs so we don't have to edit it all the time. ++ David Nichols ++ 28 November 1986 */ ++ ++ #ifdef vax + #include "m-vax.h" ++ #endif ++ ++ #ifdef ibm032 ++ #include "m-ibm032.h" ++ #endif ++ ++ #ifdef sun ++ #ifdef mc68020 ++ #include "m-sun3.h" ++ #else ++ #include "m-sun2.h" ++ #endif ++ #endif +diff -c ../../gnu/gdb/pinsn.c ./pinsn.c +*** ../../gnu/gdb/pinsn.c Sat Apr 4 23:15:58 1987 +--- ./pinsn.c Mon Apr 27 00:28:36 1987 +*************** +*** 1 **** +--- 1,15 ---- ++ /* Changed to use ifdefs so we don't have to edit this. ++ David Nichols ++ 28 Nov 1986 */ ++ ++ #ifdef ibm032 ++ #include "ibm032-pinsn.c" ++ #endif ++ ++ #ifdef vax + #include "vax-pinsn.c" ++ #endif ++ ++ #ifdef sun ++ #include "m68k-pinsn.c" ++ #endif +diff -c ../../gnu/gdb/printcmd.c ./printcmd.c +*** ../../gnu/gdb/printcmd.c Sat Apr 4 23:17:03 1987 +--- ./printcmd.c Mon Apr 27 00:30:52 1987 +*************** +*** 797,804 **** + CORE_ADDR frame; + FILE *stream; + { +! char *space = (char *) alloca (TYPE_LENGTH (SYMBOL_TYPE (var))); + value val = read_var_value (var, frame); + value_print (val, stream); + } + +--- 797,805 ---- + CORE_ADDR frame; + FILE *stream; + { +! char *space; + value val = read_var_value (var, frame); ++ space = (char *) alloca (TYPE_LENGTH (SYMBOL_TYPE (var))); + value_print (val, stream); + } + +*************** +*** 883,888 **** +--- 884,891 ---- + } + } + ++ printcmdinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/source.c ./source.c +*** ../../gnu/gdb/source.c Sat Apr 4 23:17:55 1987 +--- ./source.c Mon Apr 27 00:31:25 1987 +*************** +*** 276,282 **** + if (get_exec_file () != 0 && exec_mtime < st.st_mtime) + printf ("Source file is more recent than executable.\n"); + +! data = (char *) alloca (st.st_size); + myread (desc, data, st.st_size, s->filename); + end = data + st.st_size; + p = data; +--- 276,283 ---- + if (get_exec_file () != 0 && exec_mtime < st.st_mtime) + printf ("Source file is more recent than executable.\n"); + +! data = (char *) alloca(st.st_size); +! + myread (desc, data, st.st_size, s->filename); + end = data + st.st_size; + p = data; +*************** +*** 530,535 **** +--- 531,538 ---- + printf ("Line number %d is out of range for \"%s\".\n", + sal.line, sal.symtab->filename); + } ++ ++ sourceinitialize() {initialize();} + + static + initialize () +diff -c ../../gnu/gdb/stack.c ./stack.c +*** ../../gnu/gdb/stack.c Sun Apr 5 00:28:05 1987 +--- ./stack.c Mon Apr 27 00:31:50 1987 +*************** +*** 511,516 **** +--- 511,517 ---- + + print_stack_frame (selected_frame, selected_frame_level, 1); + } ++ + + static void + return_command (retval_exp) +*************** +*** 538,543 **** +--- 539,546 ---- + frame_command ("0", 1); + } + ++ stackinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/symmisc.c ./symmisc.c +*** ../../gnu/gdb/symmisc.c Sun Apr 5 00:33:16 1987 +--- ./symmisc.c Mon Apr 27 00:37:46 1987 +*************** +*** 504,509 **** +--- 504,511 ---- + return i; + } + ++ symmiscinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/symtab.c ./symtab.c +*** ../../gnu/gdb/symtab.c Sun Apr 5 00:35:45 1987 +--- ./symtab.c Mon Apr 27 00:38:19 1987 +*************** +*** 71,78 **** + strcpy (copy, name); + strcat (copy, ".c"); + for (s = symtab_list; s; s = s->next) +! if (!strcmp (copy, s->filename)) + return s; + + return 0; + } +--- 71,79 ---- + strcpy (copy, name); + strcat (copy, ".c"); + for (s = symtab_list; s; s = s->next) +! if (!strcmp (copy, s->filename)) { + return s; ++ } + + return 0; + } +*************** +*** 703,709 **** + register struct symbol *sym; + register CORE_ADDR pc; + register int i; +! char *copy; + + /* Defaults have defaults. */ + +--- 704,710 ---- + register struct symbol *sym; + register CORE_ADDR pc; + register int i; +! char *copy, *dotcopy; + + /* Defaults have defaults. */ + +*************** +*** 818,825 **** +--- 819,847 ---- + /* Look up that token as a function. + If file specified, use that file's per-file block to start with. */ + ++ #ifdef ibm032 ++ /* RT has stupid dots in front of function names (_.foo), and worse, has bogus _foo ++ symbol to confuse us, too. ++ */ ++ if (*copy != '.') { ++ dotcopy = (char *) alloca (strlen(copy)+2); /* one for the null and one for the dot */ ++ dotcopy[0] = '.'; ++ strcpy(dotcopy+1, copy); ++ sym = lookup_symbol (dotcopy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, ++ VAR_NAMESPACE); ++ } ++ else { ++ sym = 0; ++ dotcopy = 0; ++ } ++ if (!sym || SYMBOL_CLASS(sym) != LOC_BLOCK) { ++ sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, ++ VAR_NAMESPACE); ++ } ++ #else + sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, + VAR_NAMESPACE); ++ #endif + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + { +*************** +*** 835,840 **** +--- 857,875 ---- + if (sym) + error ("%s is not a function.", copy); + ++ #ifdef ibm032 ++ /* try the dot version first */ ++ if (dotcopy) for (i = 0; i < misc_function_count; i++) ++ if (!strcmp (misc_function_vector[i].name, dotcopy)) ++ { ++ value.symtab = 0; ++ value.line = 0; ++ value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET; ++ if (funfirstline) ++ SKIP_PROLOGUE (value.pc); ++ return value; ++ } ++ #endif + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, copy)) + { +*************** +*** 1027,1032 **** +--- 1062,1069 ---- + + return type; + } ++ ++ symtabinitialize() {initialize();} + + static + initialize () +diff -c ../../gnu/gdb/utils.c ./utils.c +*** ../../gnu/gdb/utils.c Sun Apr 5 00:40:01 1987 +--- ./utils.c Mon Apr 27 00:40:01 1987 +*************** +*** 151,156 **** +--- 151,157 ---- + else + err = "unknown error"; + ++ /* ibm032: no core leak or other problems 'cause we alway call error -> longjmps away */ + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); +diff -c ../../gnu/gdb/valarith.c ./valarith.c +*** ../../gnu/gdb/valarith.c Sun Apr 5 00:40:44 1987 +--- ./valarith.c Fri May 22 20:18:46 1987 +*************** +*** 239,245 **** + COERCE_ARRAY (arg1); + + len = TYPE_LENGTH (VALUE_TYPE (arg1)); +! p = VALUE_CONTENTS (arg1); + + while (--len >= 0) + { +--- 239,245 ---- + COERCE_ARRAY (arg1); + + len = TYPE_LENGTH (VALUE_TYPE (arg1)); +! p = (char *) VALUE_CONTENTS (arg1); + + while (--len >= 0) + { +*************** +*** 281,288 **** + && ((len = TYPE_LENGTH (VALUE_TYPE (arg1))) + == TYPE_LENGTH (VALUE_TYPE (arg2)))) + { +! p1 = VALUE_CONTENTS (arg1); +! p2 = VALUE_CONTENTS (arg2); + while (--len >= 0) + { + if (*p1++ != *p2++) +--- 281,288 ---- + && ((len = TYPE_LENGTH (VALUE_TYPE (arg1))) + == TYPE_LENGTH (VALUE_TYPE (arg2)))) + { +! p1 = (char *) VALUE_CONTENTS (arg1); +! p2 = (char *) VALUE_CONTENTS (arg2); + while (--len >= 0) + { + if (*p1++ != *p2++) +*************** +*** 348,353 **** +--- 348,355 ---- + return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1)); + } + ++ valarithinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/valops.c ./valops.c +*** ../../gnu/gdb/valops.c Sun Apr 5 00:41:32 1987 +--- ./valops.c Fri May 22 20:13:02 1987 +*************** +*** 174,180 **** + /* Return a value just like TOVAL except with the contents of FROMVAL. */ + + val = allocate_value (type); +! bcopy (toval, val, VALUE_CONTENTS (val) - (char *) val); + bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS (val), TYPE_LENGTH (type)); + + return val; +--- 174,180 ---- + /* Return a value just like TOVAL except with the contents of FROMVAL. */ + + val = allocate_value (type); +! bcopy (toval, val, (char *) VALUE_CONTENTS (val) - (char *) val); + bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS (val), TYPE_LENGTH (type)); + + return val; +*************** +*** 413,419 **** +--- 413,427 ---- + } + else if (code == TYPE_CODE_PTR) + { ++ #ifdef ibm032 ++ /* apparently '_a' pseudoprocedure has lval_memory as its lval type */ ++ if (VALUE_LVAL(function) == lval_memory) ++ funaddr = VALUE_ADDRESS(function); ++ else ++ funaddr = value_as_long (function); ++ #else + funaddr = value_as_long (function); ++ #endif + if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) + == TYPE_CODE_FUNC) + value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)); +*************** +*** 429,439 **** + else + /* Handle integer used as address of a function. */ + funaddr = value_as_long (function); +- + value_type = builtin_type_int; + } +! else + error ("Invalid data type for function to be called."); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ +--- 437,447 ---- + else + /* Handle integer used as address of a function. */ + funaddr = value_as_long (function); + value_type = builtin_type_int; + } +! else { + error ("Invalid data type for function to be called."); ++ } + + /* Create a call sequence customized for this function + and the number of arguments for it. */ +*************** +*** 590,595 **** +--- 598,605 ---- + return value_field (arg1, i); + } + ++ valopsinitialize() {initialize();} ++ + static + initialize () + { } +diff -c ../../gnu/gdb/valprint.c ./valprint.c +*** ../../gnu/gdb/valprint.c Sun Apr 5 00:42:28 1987 +--- ./valprint.c Mon Apr 27 00:40:56 1987 +*************** +*** 529,534 **** +--- 529,536 ---- + print_max = atoi (arg); + } + ++ valprintinitialize() {initialize();} ++ + static + initialize () + { +diff -c ../../gnu/gdb/value.h ./value.h +*** ../../gnu/gdb/value.h Sun Apr 5 00:43:44 1987 +--- ./value.h Fri May 22 20:03:32 1987 +*************** +*** 37,43 **** + short repeated; + short repetitions; + short regno; +! char contents[1]; + }; + + typedef struct value *value; +--- 37,43 ---- + short repeated; + short repetitions; + short regno; +! long contents[1]; /* Forces alignment... */ + }; + + typedef struct value *value; +diff -c ../../gnu/gdb/values.c ./values.c +*** ../../gnu/gdb/values.c Sun Apr 5 00:45:14 1987 +--- ./values.c Fri May 22 20:12:40 1987 +*************** +*** 338,344 **** + int offset, bitpos, bitsize; + value newval; + { +! register char *addr = VALUE_CONTENTS (var->value) + offset; + if (bitsize) + modify_field (addr, value_as_long (newval), + bitpos, bitsize); +--- 338,344 ---- + int offset, bitpos, bitsize; + value newval; + { +! register char *addr = (char *) VALUE_CONTENTS (var->value) + offset; + if (bitsize) + modify_field (addr, value_as_long (newval), + bitpos, bitsize); +*************** +*** 733,738 **** +--- 733,740 ---- + write_register (1, retbuf[1]); + } + ++ valuesinitialize() {initialize();} ++ + static + initialize () + { + diff --git a/gdb/=rt-extra b/gdb/=rt-extra new file mode 100644 index 00000000000..827e1a1e629 --- /dev/null +++ b/gdb/=rt-extra @@ -0,0 +1,84 @@ +BABYL OPTIONS: +Version: 5 +Labels: +Note: This is the header of an rmail file. +Note: If you are seeing it in rmail, +Note: it means the file has no messages in it. + +1,, +Received: by PREP.AI.MIT.EDU; Mon, 25 May 87 04:03:20 EDT +Message-Id: <8705250803.AA14993@prep.ai.mit.edu> +Received: by po2.andrew.cmu.edu (5.54/3.15) id for rms@prep.ai.mit.edu; Mon, 25 May 87 04:02:41 EDT +Received: via switchmail; Mon, 25 May 87 04:02:29 edt +Received: FROM z.itc.cmu.edu VIA qmail + ID ; + Mon, 25 May 87 04:01:27 edt +Received: FROM z.itc.cmu.edu VIA qmail + ID ; + Mon, 25 May 87 04:01:15 edt +From: zs01#@andrew.cmu.edu (Zalman Stern) +Date: Mon, 25 May 87 04:01:13 edt +To: rms@prep.ai.mit.edu +Subject: Small diff to yesterdays gdb diffs. + +*** EOOH *** +From: zs01#@andrew.cmu.edu (Zalman Stern) +Date: Mon, 25 May 87 04:01:13 edt +To: rms@prep.ai.mit.edu +Subject: Small diff to yesterdays gdb diffs. + +Richard, + +Here is another minor diff to the diassembler to get certain conditional +branches instructions correct... + +Also, I noticed that gcc.tar.Z is out of date with respect to gcc.tar . +When I go to get these files, should I go ahead and replace the compressed +version with a newer one or should I leave it alone? Likewise, should I try and +make a split version on prep? + +-Z- + +*** ibm032-pinsn.c.old Mon May 25 03:31:04 1987 +--- ibm032-pinsn.c Mon May 25 03:47:12 1987 +*************** +*** 101,112 **** + } + } + else { /* Conditional branches are hacked. */ +! switch (type & 0x0f) { + + int displacement; + + case ibm032_JI: +! fprintf(stream, ibm032_opcodes[opcodeIndex].mnemonic, mapCondition(type & ibm032_negative, buffer[0] & LOW4)); + putc('\t', stream); + print_address((buffer[1] << 1) + memaddr, stream); + return 2; +--- 101,112 ---- + } + } + else { /* Conditional branches are hacked. */ +! switch (type & LOW4) { + + int displacement; + + case ibm032_JI: +! fprintf(stream, ibm032_opcodes[opcodeIndex].mnemonic, mapCondition(type & ibm032_negative, (buffer[0] & LOW3) + 8)); + putc('\t', stream); + print_address((buffer[1] << 1) + memaddr, stream); + return 2; +*** ibm032-opcode.h.old Mon May 25 03:33:19 1987 +--- ibm032-opcode.h Mon May 25 03:33:24 1987 +*************** +*** 11,16 **** +--- 11,17 ---- + + /* Various useful bit masks. */ + #define ibm032_typeMask 0x0f /* Mask to get actual type info out of instruction type. */ ++ #define LOW3 0x07 + #define LOW4 0x0f + #define HIGH4 0xf0 + #define LOW16 0x0000ffff + + \ No newline at end of file diff --git a/gdb/=xgdb.msg b/gdb/=xgdb.msg new file mode 100644 index 00000000000..ac32300163f --- /dev/null +++ b/gdb/=xgdb.msg @@ -0,0 +1,997 @@ +From beatty@unh.cs.cmu.edu Sat Jul 4 12:04:01 1987 +Received: by PREP.AI.MIT.EDU; Sat, 4 Jul 87 12:03:37 EDT +Message-Id: <8707041603.AA08600@prep.ai.mit.edu> +To: phr@prep.ai.mit.edu (Paul Rubin) +Date: Sat, 4 Jul 87 12:03:01 EDT +From: Derek Beatty +Subject: Re: gdb and X (msg 1 of 3) +Status: R + +This is part 1 of 3 parts. It consists of the cursor I used, and a message +I sent to Zalman Stern at Andrew regarding what I did, and why. The +code and context diffs will follow in other messages. + +#define gdb_width 16 +#define gdb_height 16 +#define gdb_x_hot 7 +#define gdb_y_hot 0 +static short gdb_bits[] = { + 0x0000, 0x0140, 0x0220, 0x0220, + 0x23e2, 0x13e4, 0x09c8, 0x0ff8, + 0x0220, 0x3ffe, 0x0630, 0x03e0, + 0x0220, 0x1ffc, 0x2632, 0x01c0}; + +#define gdb_mask_width 16 +#define gdb_mask_height 16 +#define gdb_mask_x_hot 7 +#define gdb_mask_y_hot 0 +static short gdb_mask_bits[] = { + 0x0360, 0x07f0, 0x07f0, 0x77f7, + 0x7fff, 0x7fff, 0x1ffc, 0x1ffc, + 0x7fff, 0x7fff, 0x7fff, 0x0ff8, + 0x3ffe, 0x7fff, 0x7fff, 0x7fff}; + +> +> The X support I added is minimal; it was inspired by Suntools' dbxtool, +> together with the availability of the V10 implementation of the X V11 +> toolkit specification. Design was guided by simplicity and the facilities +> of the toolkit. The debugger window provides a view into the code +> corresponding to the current stack frame, and several buttons for the +> breakpoint, print, step, next, continue, finish, up, and down commands. +> The standard gdb command interface remains available in the tty window from +> which gdb was started. The breakpoint and print buttons make use of the +> current selection, so you can do simple things like click at text in the +> source window, then click the "Go 'til" button to continue until that +> point. +> +> Such an interface is simple to program ( ~ 20 hours, about 700 lines), +> but it has some drawbacks. First, I didn't take the time to understand +> the longjmp's in gdb, and I'm not exactly happy with the idea of them +> jumping out of my callback procedures that were invoked by toolkit routines. +> There's one core dump bug (it shows up when gdb can't find a source +> file) that I haven't tracked down, and it may be related to this. Second, +> selection in the text window is not particularly graceful: double-clicking +> highlights one word of text, as the toolkit defines a word. It would +> be much more graceful were double-clicking to highlight a C identifier. +> Finally, and most seriously, most buttons operate by building textual +> command lines and passing them to gdb's execute_command function. This +> means that all selected expressions are evaluated and printed in the +> lexical scope corresponding to the current stack frame, although the +> selected text may be in a different lexical scope. This serious bug would +> require work to fix. +> +> I wrote the X support out of frustration at not having dbxtool available +> when I work on a vax. The hope of portability to V11 via the toolkit +> also helped motivate me to write V10 code at this late date. Finally, +> I'd never written any nontrivial code that ran on a windowing system +> (although that turns out still to be the case). Were I to make a more +> serious effort at this project, I would probably add a general "define-button" +> command akin to gdb's "define" command. +> +> Look in /usr/beatty/gnu/gdb on vlsi.cs.cmu.edu. All files I have modified +> are marked, and also have associated backups (.B extensions). Bennet +> Yee has a copy of the toolkit library; see /usr/bsy/Xtlib on f.gp.cs.cmu.edu. +> +> -- Derek +> + + -- Derek Beatty + +From beatty@unh.cs.cmu.edu Sat Jul 4 12:12:47 1987 +Received: by PREP.AI.MIT.EDU; Sat, 4 Jul 87 12:09:20 EDT +Message-Id: <8707041609.AA08643@prep.ai.mit.edu> +To: phr@PREP.AI.MIT.EDU (Paul Rubin) +Date: Sat, 4 Jul 87 12:07:25 EDT +From: Derek Beatty +Subject: Re: gdb and X (msg 2 of 3) +In-Reply-To: Message from "Paul Rubin" of Jul 4, 87 at 1:22 am +Status: R + +The following is "tool.c". I hereby grant permission to do anything you +like with it. + + -- Derek Beatty + +[nosave] +/* + * gdb tool for X V10R4 (using V11-compatible toolkit). + * Derek Beatty 30 June 87. + */ +#include +#include +#include + +#include "defs.h" +#include "symtab.h" + +#include "gdb.cursor" +#include "gdb_mask.cursor" + + + +/* forward refs */ + +static Window createFileText(); +/* + * Windows manipulated by this package. + */ + +static Window + icon, + frame, + srcLabelStrip, + srcText, + ctlPanel, + execLabelStrip; + +static Cursor curse; + +/* + * Source text display. + */ + +static struct symtab *displayedSymtab= 0; + +extern struct symtab *current_source_symtab; +extern int current_source_line; + +toolDisplaySource() +{ + char *fullName; + static Arg labelArgs[1]; + int linenumbers_changed= 0; + static int newWidget= 1; + + struct symtab_and_line get_selected_frame_sal(); + struct symtab_and_line sal; + + /* we could be called before we are initialized */ + if (!frame) return; + + sal= get_selected_frame_sal(); + + /* strictly this is wrong, but better than a blank display */ + if (sal.symtab==NULL) { + sal.symtab= current_source_symtab; + /* current_source_line may be off by a small number like 4 */ + sal.line= current_source_line; + } + + /* + * Switch to a new file if necessary. + */ + + if (sal.symtab) + linenumbers_changed= get_filename_and_charpos(sal.symtab, + sal.line, + &fullName); + if (!fullName) sal.symtab= NULL; + /* if the display may be wrong, destroy it */ + if (linenumbers_changed || displayedSymtab != sal.symtab) { + XtVPanedWindowDeletePane( srcText); + XtSendDestroyNotify( srcText); + XDestroyWindow( srcText); + srcText= 0; + } + /* if there's no display, create one */ + if (!srcText) { + newWidget= 1; + /* if there's no valid display, create a dummy display */ + if (!sal.symtab ) { + displayedSymtab= NULL; + srcText= createFileText(frame, "/dev/null"); + XtVPanedWindowAddPane(frame, srcText, 1, 20, 1000, 1); + /* create /dev/null text widget */ + XtSetArg(labelArgs[0], XtNlabel, "No source displayed."); + XtLabelSetValues(srcLabelStrip, labelArgs, XtNumber(labelArgs)); + } else { + displayedSymtab= sal.symtab; + srcText= createFileText(frame, fullName); + XtVPanedWindowAddPane(frame, srcText, 1, 20, 1000, 1); + XtSetArg(labelArgs[0], XtNlabel, fullName); + XtLabelSetValues(srcLabelStrip, labelArgs, XtNumber(labelArgs)); + /* free filename (maybe: check gdb code!) */ + } + } + + /* + * Update display and cursor positions as necessary. + * Cursor should be placed on line sal.line. + */ + + { + static int prevTop= 0, highWaterMark= 0; + int currentTop; + Arg textArgs[1]; + + /* get positions of start of display, and caret */ + XtSetArg(textArgs[0], XtNdisplayPosition, NULL); + XtTextGetValues(srcText, textArgs, XtNumber(textArgs)); + currentTop= cvtCharToLine(displayedSymtab, + (int) textArgs[0].value); + + highWaterMark += currentTop - prevTop; + + if ( sal.line < currentTop + || sal.line > highWaterMark + || newWidget) { + + /* warp the display */ + + newWidget= 0; + + /* yes, these magic numbers are ugly, but I don't know how + * to get the height of a text widget in a V11-portable way + */ + currentTop= (sal.line > 15) ? sal.line - 15 : 0; + highWaterMark= currentTop + 35; + + XtSetArg(textArgs[0], XtNdisplayPosition, + cvtLineToChar(displayedSymtab, currentTop)); + XtTextSetValues(srcText, textArgs, XtNumber(textArgs)); + } + XtSetArg(textArgs[0], XtNinsertPosition, + cvtLineToChar(displayedSymtab, sal.line)); + XtTextSetValues(srcText, textArgs, XtNumber(textArgs)); + + prevTop= currentTop; + } +} + +/* return the character position of a line */ +int +cvtLineToChar( s, line) + struct symtab *s; + int line; +{ + if (!s) return 0; + if (!s->line_charpos) return 0; + if (line < 0) line= 0; + if (line > s->nlines) line= s->nlines; + return *(s->line_charpos + line-1); +} + +/* return the line position of a character */ +int +cvtCharToLine( s, chr) + register struct symtab *s; + register int chr; +{ + register int lineNumber= 0; + register int *lnp; + + if (!s) return 0; + lnp= s->line_charpos; + /* files are usually short, so sequential search is Ok */ + while ( lineNumber < s->nlines && *lnp <= chr) { + lineNumber++; + lnp++; + } + if (lineNumber >= s->nlines) + lineNumber= s->nlines; + return lineNumber; +} + +/* + * title bar at bottom + */ + +static char *execFileName; + +toolSetExecFile(s) + char *s; +{ + execFileName= s; + if (execLabelStrip) { + static Arg labelArgs[1]; + + XtSetArg(labelArgs[0], XtNlabel, execFileName); + XtLabelSetValues(execLabelStrip, labelArgs, XtNumber(labelArgs)); + } +} + +/* + * Command line into which command are placed for execution. + * There's some ugly interaction between this and readline in main.c. + */ +extern char *line; +extern int linesize; + +/* + * Do any necessary prompting, etc. + */ +static char *gdbPrompt; + +static void +printPrompt() +{ + if (gdbPrompt) { + printf("%s", gdbPrompt); + fflush(stdout); + } +} + +/* + * Callback procedures for control panel. + */ + +/* used by "print" and "print*" buttons */ +static void printButnProc_1( starflag) + int starflag; +{ + int selnLen; + char *seln; + + char *cmd= starflag ? "print * " : "print "; + register int cmdlen= strlen(cmd); + + seln= XFetchBytes(&selnLen); + if (selnLen) { + if (selnLen+cmdlen >= linesize-1) { + linesize= (selnLen+cmdlen > linesize*2-1) ? selnLen+cmdlen+1 : linesize*2; + line= (char *) xrealloc(line, linesize); + } + strcpy(line, cmd); + strncpy(line+cmdlen, seln, selnLen); + *(line+cmdlen+selnLen)= '\0'; + execute_command(line, 0); + free(seln); + } + printPrompt(); +} + +static void printButnProc() +{ + printButnProc_1( 0); +} + +static void printStarButnProc() +{ + printButnProc_1( 1); +} + +static void nextButnProc() +{ + strcpy(line, "next"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +static void stepButnProc() +{ + strcpy(line, "step"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +static void contButnProc() +{ + strcpy(line, "cont"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +static void finButnProc() +{ + strcpy(line, "finish"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +/* used by "stop at" and "go till" buttons */ +static void stopAtButnProc_1( gotillFlag) + int gotillFlag; +{ + XtTextPosition start, finish; + static int lineNumber; + + XtTextGetSelectionPos(srcText, &start, &finish); + if (!displayedSymtab) + printf("No source file displayed.\n"); + else { + break_command_for_tool( displayedSymtab, + cvtCharToLine(displayedSymtab, start), + gotillFlag); + if (gotillFlag) { + strcpy(line, "cont"); + execute_command(line, 0); + toolDisplaySource(); + } + } + printPrompt(); +} + +static void stopAtButnProc() +{ + stopAtButnProc_1( 0); +} + +static void untilButnProc() +{ + stopAtButnProc_1( 1); +} + +/* decide if a character is trash */ +static int +garbage(c) + char c; +{ + if ('a' <= c && c <= 'z') return 0; + if ('A' <= c && c <= 'Z') return 0; + if ('0' <= c && c <= '9') return 0; + if (c == '_') return 0; + return 1; +} + +static void stopInButnProc() +{ + static int selnLen; + static char *seln; + char *sp, *selnp; + + seln= XFetchBytes(&selnLen); + if (selnLen) { + if (selnLen+6 >= linesize-1) { + linesize= (selnLen+6 > linesize*2-1) ? selnLen+7 : linesize*2; + line= (char *) xrealloc(line, linesize); + } + strcpy(line, "break "); + /* copy selection but not garbage */ + selnp= seln; + sp= line+strlen(line); + while (garbage(*selnp) && selnLen) selnp++, selnLen--; + while (!garbage(*selnp) && selnLen) { + *sp++= *selnp++; + selnLen--; + } + *sp= '\0'; + execute_command(line, 0); + free(seln); + } + printPrompt(); +} + +static void deIconifyButnProc() +{ + XUnmapWindow(icon); + XMapWindow(frame); +} + +static void iconifyButnProc() +{ + static Arg iconArgs[1]; + XtSetArg(iconArgs[0], XtNlabel, gdbPrompt); + XtCommandSetValues(icon, iconArgs, XtNumber(iconArgs)); + XUnmapWindow(frame); + XMapWindow(icon); +} + +static void upButnProc() +{ + strcpy(line, "up"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +static void downButnProc() +{ + strcpy(line, "down"); + execute_command(line, 0); + toolDisplaySource(); + printPrompt(); +} + +#define addbutton(w) XtSetArg(buttons[buttoncount], XtNwindow, w); \ + buttoncount++; +static Arg buttons[20]; +static int buttoncount= 0; + +/* + * Create control panel buttons. + */ +static createButtons(parent) + Window parent; +{ + static Window button; + static Arg commandArgs[2]; + +#define crButn(label,fn) \ + XtSetArg(commandArgs[0], XtNlabel, label);\ + XtSetArg(commandArgs[1], XtNfunction, fn);\ + button= XtCommandCreate(parent, commandArgs, XtNumber(commandArgs));\ + addbutton(button); + + crButn("Brk At", stopAtButnProc); + crButn("Brk In", stopInButnProc); + crButn("Go 'til", untilButnProc); + + crButn("Print", printButnProc); + crButn("Print*", printStarButnProc); + + crButn("Next", nextButnProc); + crButn("Step", stepButnProc); + crButn("Cont", contButnProc); + crButn("Finish", finButnProc); + + crButn("Up", upButnProc); + crButn("Down", downButnProc); + + crButn("Iconify", iconifyButnProc); +#undef crButn +} + +static Window createLabel(parent, name, label) + Window parent; + char *name, *label; +{ + static Arg labelArgs[2]; + + XtSetArg(labelArgs[0], XtNname, name); + XtSetArg(labelArgs[1], XtNlabel, label); + return XtLabelCreate(frame, labelArgs, XtNumber(labelArgs)); +} + +static Window createFileText( parent, filename) + Window parent; + char *filename; +{ + static Arg fileArgs[2]; + + XtSetArg(fileArgs[0], XtNfile, filename); + XtSetArg(fileArgs[1], XtNtextOptions, scrollVertical); + return XtTextDiskCreate(parent, fileArgs, XtNumber(fileArgs)); +} + +/***************** Externally referenced routine **************/ +int createTool() +{ + static Arg frameArgs[]= { + {XtNwidth, (XtArgVal) 600}, + {XtNheight, (XtArgVal) 700}, + }; + + ResourceDataBase db; + FILE *rdbFile; + + /* + * init and database stuff... this is wrong but what the heck + */ + if (XOpenDisplay("") == NULL) + return 0; + printf("Initializing tool..."); fflush(stdout); + XtInitialize(); + /* should be checking .Xdefaults in $HOME */ + if ((rdbFile= fopen(".Xresources", "r")) != NULL) { + XtGetDataBase(rdbFile, &db); + XtSetCurrentDataBase(db); + fclose(rdbFile); + } + + /* + * create the frame + */ + frame= XtVPanedWindowCreate(RootWindow, frameArgs, XtNumber(frameArgs)); + + /* create source label strip and add to frame */ + srcLabelStrip= createLabel(frame, "Source File", "No source file yet."); + XtVPanedWindowAddPane(frame, srcLabelStrip, 0, 15, 15, 0); + + /* create text widget and add to frame */ + srcText= createFileText(frame, "/dev/null"); + XtVPanedWindowAddPane(frame, srcText, 1, 20, 1000, 1); + + /* create button box */ + ctlPanel= XtButtonBoxCreate(frame, NULL, 0); + createButtons( ctlPanel); + XtButtonBoxAddButton(ctlPanel, buttons, buttoncount); + XtVPanedWindowAddPane(frame, ctlPanel, 2, 30, 30, 0); + + /* create exec label strip and add */ + execLabelStrip= createLabel(frame, "Executable", + execFileName ? execFileName : "No executable specified."); + XtVPanedWindowAddPane(frame, execLabelStrip, 3, 15, 15, 0); + + + /* create icon */ + { + static Arg iconArgs[2]; + XtSetArg(iconArgs[0], XtNlabel, "(gdb)"); + XtSetArg(iconArgs[1], XtNfunction, deIconifyButnProc); + icon= XtCommandCreate(RootWindow, iconArgs, XtNumber(iconArgs)); + XMoveWindow(icon, 100, 100); /* HACK */ + XSetIconWindow(frame, icon); + } + + /* throw it onto the display */ + curse= XCreateCursor(gdb_width, gdb_height, gdb_bits, gdb_mask_bits, + gdb_x_hot, gdb_y_hot, + BlackPixel, WhitePixel, GXcopy); + XDefineCursor(frame, curse); + XDefineCursor(icon, curse); + XMapWindow(frame); + XMapSubwindows(frame); + XFlush(); + printf("done\n"); + return 1; +} + +/**************** Externally referenced routine. ***********/ +/* toolDispatcher -- dispatch events until data is available on fp */ +toolDispatcher(fp, prompt) + FILE *fp; + char *prompt; +{ + int inMask= 1 << fileno(fp); + int xMask= 1 << dpyno(); + int rfds= 0; + int nfds; + XEvent ev; + int pend; + + gdbPrompt= prompt; + + while (! (rfds & inMask)) { + pend= XPending(); + if (!pend) { + rfds= inMask | xMask; + /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */ + nfds= select( 32, &rfds, 0, 0, (struct timeval *) 0); + } + if (pend || rfds & xMask) { + XNextEvent(&ev); + XtDispatchEvent(&ev); + } + } +} + +From beatty@unh.cs.cmu.edu Sat Jul 4 12:17:44 1987 +Received: by PREP.AI.MIT.EDU; Sat, 4 Jul 87 12:15:18 EDT +Message-Id: <8707041615.AA08691@prep.ai.mit.edu> +To: phr@PREP.AI.MIT.EDU (Paul Rubin) +Date: Sat, 4 Jul 87 12:14:08 EDT +From: Derek Beatty +Subject: Re: gdb and X (msg 3 of 3) +In-Reply-To: Message from "Paul Rubin" of Jul 4, 87 at 1:22 am +Status: R + +Context diffs follow. The original files are from GDB 2.1 (emacs distribution +18.40). + + -- Derek Beatty +[nosave] +*** /usr/misc/.gdb/src/core.c Fri Mar 27 12:20:14 1987 +--- core.c Sat Jul 4 11:12:16 1987 +*************** +*** 1,3 + /* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + + +--- 1,5 ----- ++ /* modified by Beatty 1 Jul 87 for gdb tool. */ ++ + /* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +*************** +*** 257,262 + } + else if (from_tty) + printf ("No exec file now.\n"); + } + + /* If we have both a core file and an exec file, + +--- 259,267 ----- + } + else if (from_tty) + printf ("No exec file now.\n"); ++ #ifdef TOOL ++ toolSetExecFile( filename ? filename : "No executable specified.\n"); ++ #endif /* def TOOL */ + } + + /* If we have both a core file and an exec file, +*** /usr/misc/.gdb/src/breakpoint.c Fri Mar 27 12:20:11 1987 +--- breakpoint.c Wed Jul 1 11:27:31 1987 +*************** +*** 1,3 + /* Everything about breakpoints, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + + +--- 1,5 ----- ++ /* modified by Beatty 1 Jul 87 for gdbtool */ ++ + /* Everything about breakpoints, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +*************** +*** 513,518 + break; + } + } + + /* Set a breakpoint according to ARG (function, linenum or *address) + and make it temporary if TEMPFLAG is nonzero. */ + +--- 515,571 ----- + break; + } + } ++ ++ #ifdef TOOL ++ /* set a breakpoint from a symtab and line */ ++ void break_command_for_tool( s, line, tempflag) ++ struct symtab *s; ++ int line; ++ int tempflag; ++ { ++ register struct breakpoint *b; ++ struct symtab_and_line sal; ++ ++ sal.symtab= s; ++ sal.line= line; ++ sal.pc= find_line_pc( sal.symtab, sal.line); ++ if (sal.pc==0) { ++ error("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename); ++ } else { ++ b= set_raw_breakpoint( sal); ++ b->number= ++breakpoint_count; ++ b->cond= 0; ++ if (tempflag) ++ b->enable= temporary; ++ ++ printf ("Breakpoint %d at 0x%x", b->number, b->address); ++ if (b->symtab) ++ printf (": file %s, line %d.", b->symtab->filename, b->line_number); ++ printf ("\n"); ++ ++ { ++ int others = 0; ++ ALL_BREAKPOINTS (b) ++ if (b->address == sal.pc && b->number != breakpoint_count) ++ others++; ++ if (others > 0) ++ { ++ printf ("Note: breakpoint%s ", (others > 1) ? "s" : ""); ++ ALL_BREAKPOINTS (b) ++ if (b->address == sal.pc && b->number != breakpoint_count) ++ { ++ others--; ++ printf ("%d%s%s ", ++ b->number, ++ (b->enable == disabled) ? " (disabled)" : "", ++ (others > 1) ? "," : ((others == 1) ? " and" : "")); ++ } ++ printf (" also set at pc 0x%x\n", sal.pc); ++ } ++ } ++ } ++ } ++ #endif /* def TOOL */ + + /* Set a breakpoint according to ARG (function, linenum or *address) + and make it temporary if TEMPFLAG is nonzero. */ +*** /usr/misc/.gdb/src/main.c Fri Mar 27 12:20:45 1987 +--- main.c Sat Jul 4 11:13:32 1987 +*************** +*** 1,3 + /* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + + +--- 1,5 ----- ++ /* modified by Beatty 30 june 87 for gdb tool */ ++ + /* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +*************** +*** 42,47 + + FILE *instream; + + void free_command_lines (); + char *read_line (); + static void initialize_main (); + +--- 44,54 ----- + + FILE *instream; + ++ #ifdef TOOL ++ /* flag indicating whether we are running in a window system */ ++ int isaTool= 0; ++ #endif /* def TOOL */ ++ + void free_command_lines (); + char *read_line (); + static void initialize_main (); +*************** +*** 214,219 + + while (1) + { + if (!setjmp (to_top_level)) + command_loop (); + clearerr (stdin); /* Don't get hung if C-d is typed. */ + +--- 221,232 ----- + + while (1) + { ++ ++ #ifdef TOOL ++ if (!isaTool) ++ isaTool= createTool(); ++ #endif /* def TOOL */ ++ + if (!setjmp (to_top_level)) + command_loop (); + clearerr (stdin); /* Don't get hung if C-d is typed. */ +*************** +*** 270,275 + printf ("%s", prompt); + fflush (stdout); + + quit_flag = 0; + execute_command (read_line (instream == stdin), instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + +--- 283,294 ----- + printf ("%s", prompt); + fflush (stdout); + ++ #ifdef TOOL ++ toolDisplaySource(); ++ if (isaTool) toolDispatcher(instream, ++ instream==stdin ? prompt : NULL); ++ #endif /* def TOOL */ ++ + quit_flag = 0; + execute_command (read_line (instream == stdin), instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ +*************** +*** 320,325 + + while (1) + { + c = fgetc (instream); + if (c == -1 || c == '\n') + break; + +--- 339,345 ----- + + while (1) + { ++ + c = fgetc (instream); + if (c == -1 || c == '\n') + break; +*************** +*** 765,770 + GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"info copying\" to see the conditions.\n", + version); + } + + static void + +--- 785,793 ----- + GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"info copying\" to see the conditions.\n", + version); ++ #ifdef TOOL ++ printf( "(CMU X support is available in this version.)\n"); ++ #endif + } + + static void +*** /usr/misc/.gdb/src/source.c Fri Mar 27 12:20:50 1987 +--- source.c Wed Jul 1 17:56:58 1987 +*************** +*** 1,3 + /* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + + +--- 1,5 ----- ++ /* modified 1 July 87 by Beatty for gdbtool */ ++ + /* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +*************** +*** 295,300 + s->nlines = nlines; + s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int)); + } + + /* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ + +--- 297,328 ----- + s->nlines = nlines; + s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int)); + } ++ ++ #ifdef TOOL ++ /* Get full pathname and line number positions for a symtab ++ * return nonzero if line numbers may have changed ++ * set full pathname to NULL if no file found ++ */ ++ int ++ get_filename_and_charpos(s, line, fullname) ++ struct symtab *s; ++ int line; ++ char **fullname; ++ { ++ register int desc, linenums_changed= 0; ++ ++ desc= openp(source_path, 0, s->filename, O_RDONLY, 0, fullname); ++ if (desc < 0) { ++ *fullname= NULL; ++ return 0; ++ } ++ if (s->line_charpos==0) linenums_changed= 1; ++ if (linenums_changed) find_source_lines(s, desc); ++ close(desc); ++ return linenums_changed; ++ } ++ #endif /* def TOOL */ ++ + + /* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ +*** /usr/misc/.gdb/src/stack.c Fri Mar 27 12:20:51 1987 +--- stack.c Wed Jul 1 17:27:34 1987 +*************** +*** 1,3 + /* Print and select stack frames for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + + +--- 1,5 ----- ++ /* modified by Beatty 1 Jul 87 for gdbtool */ ++ + /* Print and select stack frames for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +*************** +*** 42,47 + static void select_calling_frame (); + + void print_frame_info (); + + /* Print a stack frame briefly. FRAME should be the frame address + and LEVEL should be its level in the stack (or -1 for level not defined). + +--- 44,62 ----- + static void select_calling_frame (); + + void print_frame_info (); ++ ++ #ifdef TOOL ++ /* get symtab and line of selected frame, for tool display */ ++ struct symtab_and_line ++ get_selected_frame_sal() ++ { ++ struct frame_info fi; ++ ++ fi= get_frame_info( selected_frame); ++ return find_pc_line(fi.pc, fi.next_frame); ++ } ++ ++ #endif /* TOOL */ + + /* Print a stack frame briefly. FRAME should be the frame address + and LEVEL should be its level in the stack (or -1 for level not defined). +End of context diffs. The presence of this line verifies that this message +has not been truncated. + diff --git a/gdb/COPYING b/gdb/COPYING new file mode 100644 index 00000000000..9f3a6dcf2e8 --- /dev/null +++ b/gdb/COPYING @@ -0,0 +1,138 @@ + + GDB GENERAL PUBLIC LICENSE + (Clarified 20 March 1987) + + Copyright (C) 1986 Richard M. Stallman + Everyone is permitted to copy and distribute verbatim copies + of this license, but changing it is not allowed. + + The license agreements of most software companies keep you at the +mercy of those companies. By contrast, our general public license is +intended to give everyone the right to share GDB. To make sure that +you get the rights we want you to have, we need to make restrictions +that forbid anyone to deny you these rights or to ask you to surrender +the rights. Hence this license agreement. + + Specifically, we want to make sure that you have the right to give +away copies of GDB, that you receive source code or else can get it +if you want it, that you can change GDB or use pieces of it in new +free programs, and that you know you can do these things. + + To make sure that everyone has such rights, we have to forbid you to +deprive anyone else of these rights. For example, if you distribute +copies of GDB, you must give the recipients all the rights that you +have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + Also, for our own protection, we must make certain that everyone +finds out that there is no warranty for GDB. If GDB is modified by +someone else and passed on, we want its recipients to know that what +they have is not what we distributed, so that any problems introduced +by others will not reflect on our reputation. + + Therefore we (Richard Stallman and the Free Software Foundation, +Inc.) make the following terms which say what you must do to be +allowed to distribute or change GDB. + + + COPYING POLICIES + + 1. You may copy and distribute verbatim copies of GDB source code as +you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc." (or with the year updated if +that is appropriate); keep intact the notices on all files that refer +to this License Agreement and to the absence of any warranty; and give +any other recipients of the GDB program a copy of this License +Agreement along with the program. You may charge a distribution fee +for the physical act of transferring a copy. + + 2. You may modify your copy or copies of GDB or any portion of it, +and copy and distribute such modifications under the terms of +Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of GDB or any + part thereof, to be licensed at no charge to all third parties on + terms identical to those contained in this License Agreement + (except that you may choose to grant more extensive warranty + protection to third parties, at your option). + + c) if the modified program serves as a debugger, cause it + when started running in the simplest and usual way, to print + an announcement including a valid copyright notice + "Copyright (C) 1986 Free Software Foundation, Inc." (or with + the year updated if appropriate), saying that there + is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of + this License Agreement. + + d) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute GDB or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of GDB in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer GDB +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer GDB is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of GDB into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse +of software. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! + + NO WARRANTY + + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO +WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE GDB AS PERMITTED ABOVE, BE LIABLE TO +YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN +IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR +ANY CLAIM BY ANY OTHER PARTY. diff --git a/gdb/ChangeLog b/gdb/ChangeLog new file mode 100644 index 00000000000..301bdac93a1 --- /dev/null +++ b/gdb/ChangeLog @@ -0,0 +1,1025 @@ +Fri Jan 15 05:09:18 1988 Richard Stallman (rms at frosted-flakes) + + * valprint.c [IEEE_FLOAT]: New function `is_nan' checks + whether a double is a nan. + + * printcmd.c (print_formatted) [IEEE_FLOAT]: + Detect nans and print specially. + * valprint.c (val_print) [IEEE_FLOAT]: Same thing. + + * m68k-pinsn.c (convert_{to,from}_68881): Hand-assemble + all the assembler code. + + * m-newsinit.h, m-news800.h: Two new files. + +Thu Jan 7 22:25:16 1988 Richard Stallman (rms at frosted-flakes) + + * valops.c (value_assign): Don't coerce the arg being stored in. + Coercion is not right either for an array or for an enum. + +Tue Jan 5 00:59:29 1988 Richard Stallman (rms at frosted-flakes) + + * symtab.c (decode_line_1): Don't complain about no symtabs loaded + until after trying the misc function table. + +Sat Jan 2 13:16:08 1988 Richard Stallman (rms at frosted-flakes) + + * stack.c (record_selected_frame): New fn to access + the selected frame and its level. + * infcmd.c (run_stack_dummy): Save and restore the selected + frame and its level. + +Wed Dec 30 18:44:41 1987 Richard Stallman (rms at frosted-flakes) + + * valprint.c (type_print_varspec_prefix): + Treat arrays just like functions. + * valprint.c (type_print_varspec_{prefix,suffix}): + When passed_a_ptr is handled, pass 0 for it in the recursive call. + +Fri Dec 18 10:24:14 1987 Richard Stallman (rms at frosted-flakes) + + * findvar.c (read_var_value): Share code between values really + in registers and values in saved registers. + Register short on a big-endian machine needs a VALUE_OFFSET. + + * findvar.c (locate_var_value): Offset the address of a + saved register variable that's shorter than the register. + +Thu Dec 17 08:26:31 1987 Richard Stallman (rms at lucky-charms) + + * valprint.c (type_print_base): Print nameless bit fields + to indicate gaps before bit fields. + + * source.c (select_source_symtab): Ignore .h files. + Also, if a function `main' exists, make the default listing line + the beginning of `main'. + + * breakpoint.c ({get,set}_breakpoint_commands): + Commands to examine or set the pending breakpoint-commands. + + * infcmd.c (run_stack_dummy): Save and restore the breakpoint + commands around the function call. + + * stack.c (return_command): Don't query or print if not interactive. + + * value.h (COERCE_ENUM): New macro: if arg is enum, convert to int. + * value.h (COERCE_ARRAY): Do that, as well as old job. + + * valarith.c (value_binop, value_neg, value_lognot): + Use COERCE_ENUM on the arguments. + * valops.c (value_arg_coerce): Likewise. + * valops.c (value_cast): AVOID coercing enums when arrays are. + + * eval.c (evaluate_subexp): In the BINOP_SUB case, + use evaluate_subexp_with_coercion. + + * inflow.c (terminal_ours_1, terminal_inferior): + Ignore inferior_thisrun_terminal since our terminal + is the inferior's controlling terminal regardless. + + * m-sun3.h: Fix assembler syntax for kdb macros. + + * infcmd.c ({attach,detach}_command): New functions from Dave Taylor. + * inflow.c (attach, detach): New functions from Dave Taylor. + * infrun.c (attach_process): New function, middle-level. + Does all the work of attaching a process, assuming there is no + inferior yet, except for printing and querying. + + * infrun.c (clear_proceed_status): Clear `stop_after_attach'. + * infrun.c (wait_for_inferior): Handle `stop_after_attach'. + +Sat Dec 12 04:36:39 1987 Richard Stallman (rms at corn-chex) + + * dbxread.c (end_symtab): The free_code for a symseg got + from a file should be free_linetable. + + * dbxread.c: Allocate blockvector, blocks, symbols and symbol names + from the symbol-obstack, and use free_linetable for all files. + The typevector is still malloc'd, so put it in the free_ptr + to get it freed. + + * symmisc.c (free_symtab): Always free the `free_ptr' if nonzero. + `free_explicit' therefore now the same as `free_nothing'. + + * dbxread.c (define_symbol): Handle defn code 'c', used by + fortran, which defines integer and real constant symbols. + + * symseg.h: Define LOC_CONST_BYTES for constants longer than a + word. New `bytes' alternative for the value of a symbol. + + * symtab.h (SYMBOL_VALUE_BYTES): Macro to access `bytes'. + + * findvar.c ({read,locate}_var_value): Handle LOC_CONST_BYTES. + * printcmd.c (address_info): Handle LOC_CONST_BYTES. + * symmisc.c (print_symbol): Handle LOC_CONST_BYTES. + +Tue Dec 8 20:26:37 1987 Richard Stallman (rms at frosted-flakes) + + * symtab.c (find_line_pc_range): Detection of last line in file + was erroneous. + +Fri Dec 4 21:52:52 1987 Richard Stallman (rms at frosted-flakes) + + * dbxread.c (read_range_type): Accept the typenums as argument. + Use read_type_number to read the subrange-of type. + A type defined as a subrange of itself is void. + +Thu Dec 3 12:45:10 1987 Richard Stallman (rms at frosted-flakes) + + * inflow.c ({fetch,store}_inferior_registers): Support UMAX_PTRACE. + + * m-umax.h: New file, for Encore machines. + + * core.c (exec_file_command, etc): Decode COFF files. + * core.c (core_file_command): Support UMAX_CORE format. + * core.c (validate_files, exec_file_command): + Set exec_mtime in exec_file_command so that COFF vs non-COFF + differences appear all in one place. + + * coffread.c: New file from Dave Johnson. + + * core.c (specify_exec_file_hook): New function to specify + a hook to be called by exec_file_command. Last #ifdef X_WINDOWS gone. + * xgdb.c (initialize): Specify a hook. + + * infrun.c, inferior.h: Replace stop_r0 and stop_r1 with an array + `stop_registers' that will hold ALL the registers. + * infcmd.c (run_stack_dummy): Get the value from `stop_registers' + and copy all of that into BUFFER. + * infcmd.c (finish_command): Specify `stop_registers' + to `value_being_returned'. + * values.c (value_being_returned): Use the new EXTRACT... macros. + * values.c (set_return_value): Use new STORE_RETURN_VALUE macro. + * valops.c (call_function): Allocate retbuf long enough for all regs. + * m-*.h: New macros EXTRACT_RETURN_VALUE, STORE_RETURN_VALUE and + EXTRACT_STRUCT_VALUE_ADDRESS that express machine-dependencies + in where return values are stored. + + * valops.c (call_function): Flush default for CALL_DUMMY_START_OFFSET. + Assume it is defined. + * m-vax.h: Define CALL_DUMMY_START_OFFSET. + + * ns32k-pinsn.c (ns32k-localcount): Fix decoding of `enter' insn. + * ns32k-pinsn.c (n32k_get_enter_addr): New fn used from m-umax.h. + + * m-*.h: Change INVALID_FLOAT to accept 2nd arg which is length + of the float. + * values.c (unpack_double): Pass the 2nd arg. + * vax-pinsn.c (print_insn_arg): Pass the 2nd arg. + * infcmd.c (registers_info): Pass the 2nd arg. + +Wed Nov 25 15:06:55 1987 Richard Stallman (rms at frosted-flakes) + + * Bug fixes by David Johnson (ddj%cs.brown.edu@relay.cs.net). + + * symtab.c (list_symbols): Print typedef names, and don't call + them `static'. + + * symmisc.c (print_symtabs): Allow immediate quit, and close the + output file if that happens. + + * stack.c (frame_command): Declare args `unsigned' so a negative + number is a frame address, not a level number. + + * source.c: Check for error-return from calls to `getwd'. + + * printcmd.c (address_info): Fix error in case of a function name. + + * inflow.c (create_inferior): Return the inferior pid properly. + + * inferior.h: Define `inferior_io_terminal'. + * infrun.c (tty_command): New command to specify inferior_io_terminal. + * inflow.c (new_tty): Open specified terminal for the inferior. + * inflow.c (terminal_{ours,inferior}): Do nothing if inferior was + started with its own terminal. + * main.c (main): -t switch calls `tty_command'. + + * expread.y (rule for `block'): `copy_name' was called in wrong + place and with wrong args. + + * dbxread.c: Entire file #ifdef READ_DBX_FORMAT. + * m-*.h: Define READ_DBX_FORMAT. + + * breakpoint.c (initialize): Error in doc string of `info breakpoints'. + +Wed Nov 11 12:57:28 1987 Richard Stallman (rms at frosted-flakes) + + * ns32k-opcode.h, ns32k-pinsn.c: Two new files. + * m-merlin.h: New file, for one 32000 box. + +Mon Nov 9 10:31:42 1987 Brian Fox (bfox at sugar-smacks) + + * eval.c (evaluate_subexp): Made the case of OP_FUNCALL use + evaluate_subexp_with_coercion, so that array references would + get converted into pointer references. + +Mon Nov 9 05:50:24 1987 Richard Stallman (rms at sugar-smacks) + + * breakpoint.c (ignore_command): Error if no arg. + +Sat Nov 7 13:57:40 1987 Richard Stallman (rms at frosted-flakes) + + * main.c (quit_command): Get rid of execfile before the kill_inferior. + + * xgdb.c: New file, interface to X windows. + + * main.c (main): Look for flag arguments before + calling the initialization functions. -nw switch sets + `inhibit_windows' which xgdb.c looks at. + * main.c (command_loop): Call the window hook function, if any. + + * source.c (get_filename_and_charpos): New function + that interfaces to find_source_lines. + * source.c (source_line_charpos, source_charpos_line): + New functions translate source line number to char pos and vice versa. + + * breakpoint.c (describe_other_breakpoints): New subroutine + to list all breakpoints at PC in a message about "other + breakpoints". + * breakpoint.c (break_command_1): Use describe_other_breakpoints. + * breakpoint.c (set_breakpoint): Like break_command_1 + but takes arg predecoded into symtab and line. + + * core.c (exec_file_command): Call xgdb_display_exec_file. + + * valprint.c (type_print_base): For struct bitfields, + print the bit size. + +Thu Aug 20 02:46:47 1987 Richard M. Stallman (rms at prep) + + * Version 2.4. + + * m68k-pinsn.c (print_insn_arg): Implement place = '3'. + + * findvar.c (write_register_bytes): Arg to + store_inferior_registers should be -1: write all registers. + + * dbxread.c (symbol_file_command): If no arg, + just discard all symbols. + + * core.c (myread): Flush the 4th arg (filename). + * source.c (find_source_lines): Don't pass 4th arg. + * symmisc.c (read_symsegs): Ditto. + + * dbxread.c (process_one_symbol): One call to `define_symbol' + lacked 3rd arg. + + * inflow.c (write_inferior_memory): On failure, return the errno value. + * core.c (write_memory): ditto. + * breakpoint.c ({insert,remove}_breakpoints): ditto. + * utils.c (print_sys_errmsg): Like perror_with_name but don't + signal an error; also, the error code is an arg instead of from + `errno'. + * infrun.c : Save the value from insert_breakpoints and pass it to + print_sys_errmsg. + + * main.c (input_from_terminal_p): Put in omitted `return'. + + * Makefile (expread.o): Use $(CC). + +Sun Jun 7 04:42:51 1987 Richard M. Stallman (rms at prep) + + * version.c: Version 2.3. + + * inflow.c (terminal_ours): Save fcntl flags correctly. + * inflow.c (term_status_command): + Print the tchars and ltchars structures, byte by byte. + +Mon May 25 14:37:14 1987 Richard M. Stallman (rms at prep) + + * version.c: Version 2.2. + + * breakpoint.c (do_breakpoint_commands): + Advance breakpoint_commands before executing the command, + in case command is `cont' and it hits another bpt with commands. + +Sun May 24 20:45:04 1987 Richard M. Stallman (rms at prep) + + * value.h: Declare `contents' long and cast its address to char *. + + * expread.y (prefixify_expression): Don't call alloca among the decls. + + * printcmd.c (print_variable_value): Flush unused local `space'. + + * main.c (execute_command): Barf on "user" like other class names. + +Fri May 22 01:34:37 1987 Richard M. Stallman (rms at prep) + + * m68k-pinsn.c (fetch_arg): New arg position 'j', for movec. + (print_insn_arg): New arg syntax 'J', for movec. + * m68k-opcode.h: movec uses 'Jj'. Everything reformatted. + bf... and cas... insns were corrected. + + * inflow.c (create_inferior): Fork and exec with given args and env. + Call close_exec_file. + (inferior_died): Record the fact that the inferior no longer exists. + Call reopen_exec_file. + + * core.c (close_exec_file): New fn: Close the execchan if it's open. + (reopen_exec_file): New fn: Reopen execchan if not currently open. + + * infrun.c (wait_for_inferior): Call inferior_died if it exits. + + * infcmd.c (run_command): Don't fork and exec; call create_inferior. + + * findvar.c (read_var_value): For reg var in a convertable reg, + fetch reg in its own virtual type and then cast to variable's type. + + * symtab.h: Declare xmalloc to return char *. + + * dbxread.c (read_dbx_symtab): Record static text syms as + misc-functions. But if an assembler symbol supplies the address + for a debugger symbol, don't record it as a misc-function. + + * utils.c (query): Do clearerr (stdin) frequently in case of C-d. + + * dbxread.c (process_one_symbol, define_symbol): + Pass the stab's DESC down to define_symbol. + DESC = 0 means GCC output: if type is "short", believe it. + + * dbxread.c (read_enum_type): Don't allocate the type here; + take it as an argument. (Like read_struct_type.) + (read_type)): Before call to read_enum_type, allocate the type + or get the one already allocated. + + * printcmd.c (print_frame_args): Print a comma before + every arg except the first. + +Wed May 13 00:36:00 1987 Richard M. Stallman (rms at prep) + + * m68k-pinsn.c (convert_{to,from}_68881): + Hand-assemble the fmoved and fmovex insns. + + * dbxread.c (define_symbol): For case 'p', a parameter, + if specified type is short or char, change it to int. + This is for how PCC handles arguments. + Define new case 'P' that does what 'p' used to do. + Maybe GCC will use this. + +Mon May 4 21:52:44 1987 Richard M. Stallman (rms at prep) + + * main.c (main): If SET_STACK_LIMIT_HUGE, set the + run-time stack limit as high as it can go. + * m-sun3.h, m-vax.h: define SET_STACK_LIMIT_HUGE. + +Sun May 3 08:46:23 1987 Richard Mlynarik (mly at prep) + + * command.c, expread.y, findvar.c, infcmd.c, inflow.c, utils.c, + values.c, defs.h: Various ANSI C compatibility changes + (fouts@wilbur.arpa <8705010117.AA13112@wilbur.arpa>) + + * core.c, inflow.c: Fix calls to supply_register. + * findvar.c (supply_register): Instead of register value as int, + pass address of buffer in core containing contents in raw form. + +Sat Apr 18 17:09:42 1987 Richard Mlynarik (mly at prep) + + * main.c (command_loop): + Do any cleanups made by a executing a command each time around. + + * source.c (directory_command): + make_cleanup (free, dirname), not + make_cleanup (free_current_contents, &dirname) + (rlk <8704180416.AA29572@PARIS.MIT.EDU>) + +Mon Apr 13 20:28:26 1987 Leonard H. Tower Jr. (tower at prep) + + * gdb.1: fixed typo and italicization errors. + ( id AA16470;Sun,12 Apr 87 14:30:07 EST) + +Sat Apr 11 15:41:01 1987 Richard Mlynarik (mly at prep) + + * dbxread.c (read_dbx_symtab): + No name for symbol => "" not 0 (avoid referencing memory 0) + (tower <8704081854.AA00135@buit3.bu.edu>) + +Mon Mar 30 22:24:07 1987 Leonard H. Tower Jr. (tower at prep) + + * gdb.1: Unix style manual page pointing at internal gdb + documentation, and info sub-system in GNU Emacs. + +Fri Mar 20 12:07:15 1987 Richard M. Stallman (rms at prep) + + * COPYING: Clarifications about distribution fees and mixing. + * main.c (copying_info): Same changes. + +Tue Mar 17 17:40:14 1987 Richard M. Stallman (rms at prep) + + * values.c (unpack_field_as_long): Avoid >>= operator + since ISI compiler has a bug. + +Sat Mar 7 12:19:35 1987 Richard M. Stallman (rms at prep) + + * GDB version 2.1. + + * values.c (unpack-field-as-long): Tests for endianness were broken. + * findvar.c (read_var_value): + Now we initialize the union as an int and test it as a char. + +Sun Mar 1 16:16:20 1987 Richard M. Stallman (rms at prep) + + * main.c (define_command): Command class symbols + must be cast to int. + +Mon Feb 23 02:47:44 1987 Richard M. Stallman (rms at prep) + + * source.c (list_command): Reword error messages. + New message for case of first arg not just a line-number + and no symtab specified by it. + +Sun Feb 22 21:15:19 1987 Richard M. Stallman (rms at prep) + + * dbxread.c (compare_misc_functions): + Compare the addresses as unsigned numbers. + +Sun Feb 22 13:11:45 1987 Richard Mlynarik (mly at prep) + + * main.c (define_command, document_command): + Stuff was being unnecessarily malloced (-and- not freed!) + + * main.c (execute_command): + User-defined commands don't take args. + Don't confuse empty user command with no command. + Replace bogus `etext' test with a comparison against + class_user. + + * main.c (define_command): + If the command of the specified name is built-in, note that when + asking whether to redefine it (this is suppressed for class_alias + -- should it not be?) + + * main.c (define_command): + If command was previously built-in, don't preserve its + documentation (otherwise could get error later when trying to free + the non-malloced text of built-in documentation strings) + +Tue Feb 17 16:23:57 1987 Richard Mlynarik (mly at prep) + + * main.c (echo_command): Don't die if not given any arg. + * main.c (cd_command): Echo new cwd if interactive. + +Thu Feb 12 11:22:56 1987 Richard M. Stallman (rms at prep) + + * stack.c (initialize): "bt" now appears in help aliases. + + * Version 2.0 released. + +Wed Feb 11 17:45:45 1987 Richard M. Stallman (rms at prep) + + * m68k-opcode.h: Errors corrected in several instructions + and reordering done for assembler's sake. + + * m-vax.h (POP_FRAME): End with call to set_current_frame. + +Tue Feb 10 15:06:07 1987 Richard M. Stallman (rms at prep) + + * infrun.c (wait_for_inferior): Set stop_print_frame to 1 + after checking breakpoint condition. + + * infcmd.c (run_stack_dummy): Save many flags. + +Thu Feb 5 07:12:20 1987 Richard Mlynarik (mly at prep) + + * source.c (directory_command): + Step over `:' + +Mon Feb 2 23:40:32 1987 Richard M. Stallman (rms at prep) + + * infcmd.c (set_environment_command): Fix stupid error + for case where no "=" appears in the string. + +Mon Jan 26 13:46:52 1987 Richard M. Stallman (rms at prep) + + * printcmd.c (print_frame_args): Round end-of-arg offset + up rather than down to multiple of int. + +Fri Jan 23 15:11:50 1987 Richard M. Stallman (rms at prep) + + * source.c (directory_command): If dir is not added cause already + present, print explanation. + + * infrun.c (proceed): Use read_pc (), not stop_pc, + to get current pc to think about. stop_pc could have been + clobbered by call_function. + +Fri Jan 23 15:00:55 1987 Richard Mlynarik (mly at prep) + + * source.c (directory_command): + If dir is already in source_path, don't append another copy of it. + +Thu Jan 22 00:31:03 1987 Richard M. Stallman (rms at prep) + + * Version 2.0. + + * blockframe.c (get_pc_function_start): + Understand misc functions. + + * core.c (core_file_command): + Copy all register contents into the array `registers' + Save a.out header of executable file in core_aouthdr. + Print name of executable file that was running, if we know + where to find it. + + * core.c (exec_file_command): + Save a.out header in exec_aouthdr and file's mtime + in exec_mtime. + + * core.c (validate_files): Check that core file's a.out hdr + matches exec file's. + + * New handling of registers: + Now all registers are fetched once when the program stops or + when a core file is selected. Their contents are kept in + `registers', an array of bytes. This is done by + `fetch_inferior_registers'. `read_register', etc., just look + there. Writing a register works through + `store_inferior_registers' which writes one or all registers + from `registers' back to the inferior. + + A register now can have a "raw" data format and a "virtual" + data format, which may require conversion or even be different sizes. + The conversion can be different for different registers. + For example, the 68000 cpu registers need no conversion + and both raw and virtual size is 4, but the 68881 floating point + registers have raw size 12 (for extended fmt) and virtual size 8 + (for double). Macros in the m- file such as REGISTER_BYTES, + REGISTER_BYTE, REGISTER_{RAW,VIRTUAL}_SIZE, and + REGISTER_CONVERT_TO_{RAW,VIRTUAL} control these things. + + `read_register' and `write_register' are usable only on registers + which hold an int and need no conversion (raw fmt = virtual fmt). + For other registers, `read_register_bytes' is used, or + `read_relative_register_raw_bytes'. + + * m-sun3.h: Define the 68881 fp registers. + Know how to recognize insns that save them. + Make dummy frames save them. + + * core.c (read_register, write_registers): Functions deleted. + * findvar.c (read_register, write_registers): New functions, + not the same as the old ones of the same name. + + * findvar.c (supply_register): Function used by + fetch_inferior_registers, etc., to install the register + values fetched from the inferior. + + * findvar.c (read_register_bytes, write_register_bytes): + Read spec'd number of bytes from the byte-array `registers'. + + * findvar.c (read_relative_register_raw_bytes): + Replaces old function `read_relative_register'; accepts + address of where to store the contents; # bytes stored is size + of the specified register in raw format. + + * findvar.c (value_of_register, read_var_value): + Convert register values and values of register variables + from raw format to virtual format. + + * findvar.c (locate_var_value): Like `read_var_value' but + returns value for variable's address. + + * value.h: Add new field VALUE_REGNO to each value. It holds + register number to control virtual-to-raw conversion + for assignments to the value. + + * valops.c (value_assign): Convert data from virtual to raw format + if value came from a register variable. + Use read_register_bytes and write_register_bytes. + + + * infcmd.c (continue_command): Subtract 1 from arg + before setting breakpoint's ignore-count. + + * infcmd.c (jump_command): Query if spec'd line is outside + of the current function. + + * infcmd.c (finish_command): Now finish the selected frame, + and no arg required. + + * infcmd.c (set_environment_command): Allow space to separate + varname and value. + + * infcmd.c (registers_info): Print both raw and virtual data + format if they differ. Allow register name as arg. + Ask for a Newline each 16 registers. + + * inflow.c (kill_inferior): call mark_breakpoints_out. + * inflow.c ({fetch,store}_inferior_registers for Sun): + Get the fp registers and store them in right places in + `registers'. + * inflow.c ({read,write}_inferior_register): Deleted. + + * infrun.c (wait_for_inferior): Single-stepping is not considered + to have hit a breakpoint unless the pc before the step matches the + address of the breakpoint. Necessary on machines where + breakpoints leave the pc incremented. + + If shell gets SIGSEGV, pass the signal silently to it. + + * m68k-pinsn.c, m68k-opcode.h: + Add the 68881 instructions. New operand codes `F', `I', `s' + and `k' are needed for them. New place codes `78tcik'. + NEXTBYTE now skips a word but fetches just a byte. + Explicit sign-extension removed from NEXTBYTE and NEXTWORD. + NEXTSINGLE, NEXTDOUBLE, NEXTEXTEND and NEXTPACKED defined. + Various changes to implement the new operand and place codes. + print_index changed because displacement-size codes for + word and long displacement were interchanged. + + * m68k-pinsn.c (convert_{from,to}_68881): Functions added + to support REGISTER_CONVERT_TO_{RAW,VIRTUAL} on 68000. + + * main.c (main): Move around calls to setjmp. + * main.c (define_command, document_command): + Accept a from_tty argument instead of calling input_from_terminal_p. + + * printcmd.c (address_info): Print info on class and address + of a specified symbol. For register symbols, gives name of register. + + * printcmd.c (print_command): Remember explicitly whether + `make_cleanup' was called. + + * printcmd.c (print_frame_args): Know how arg-addresses vary with + data type on big-endian machines. + + * source.c (directory_command): Detect `:' in arg and reject it. + Free the old directory-path. Simplify things like `/.' in + dirname. + + * source.c (openp): Simplify `./' in specified name. + + * source.c (find_source_lines): Compare source mtime against + `exec_mtime' and warn if source is newer. + + * source.c (line_info): No arg means use last line listed + or line following last one this command was used on. + If from tty, clear out argument so Return is like `i li' without + arg. + + * stack.c (frame_info): Print addresses registers are saved at. + + * stack.c (return_command): When asking for confirmation, give + name of function that will be made to return. + + * valops.c (call_function): If function type is + pointer-to-function, dereference it to compute return type. + If pointer-to-object, assume function returns int. + If char, assume that the value's address is the function address + (because it's a misc functon). If int, the value itself is the + function address. + + * dbxread.c (compare_symbols): Sort register symbols + before all others. + + * eval.c (evaluate_subexp_for_address): New function like + `evaluate_subexp' but returns a value for the address where + the subexpression's value would be located. + + * eval.c (evaluate_subexp_for_sizeof): New function like + `evaluate_subexp' but returns a value for the size of the subexp. + + * eval.c (evaluate_subexp_with_coercion): Like `evaluate_subexp' + but coerces arrays to pointers (without taking the time to + read the array contents). + + * eval.c (evaluate_subexp): Use the three new functions above + when appropriate instead of calling self recursively. + +Wed Jan 14 17:00:03 1987 Richard Mlynarik (mly at prep) + + * core.c (core_file_command): + Use correct file in calls to perror_with_name + +Mon Jan 12 03:34:35 1987 Richard Mlynarik (mly at prep) + + * breakpoint.c (map_breakpoint_numbers): + Err if no args not supplied, otherwise would get mpv. + + * main.c (main): + Command-line arg "-d dir" adds dir to source-file directory + search-list. + +Sun Jan 11 19:19:52 1987 Richard Mlynarik (mly at prep) + + * symmisc.c (free_all_symtabs): + Don't call free on 0. + + * core.c (exec_file_command): + Use correct name in call to perror_with_name. + Record absolute pathname. + Don't savestring an arg to concat. + + * dbxread.c (symbol_file_command): + Record absolute name of pathname opened. + Print a message if file doesn't have a symbol-table. + Don't savestring an arg to concat. + + * source.c (openp): + Add new arg filename_opened, which if non-zero will be set to a + malloced string of the absolute name of the actual filename opened. + + * breakpoint.c (clear_command): + If from_tty or cleared more than one breakpoint at location, + print which bpts were deleted. + + * breakpoint.c (break_command_1, break_command, tbreak_command): + If from_tty, mention any other breakpoints set at same location. + + * symtab.c (decode_line_1): + If no symtabs, err mentioning `symbol-file' command rather than + saying "function foo not defined" + +Fri Jan 9 01:25:19 1987 Richard Mlynarik (mly at prep) + + * main.c (set_prompt_command): + Add support command "set-prompt" + + * printcmd.c (undisplay_command): + Fix paren error to make "undisplay " work. + +Wed Jan 7 12:06:09 1987 Richard Mlynarik (mly at prep) + + * main.c (print_gdb_version, gdb_version_info): + Add command "info version" to report the version + of gdb for use in bug reports. + + * infcmd.c: + Ensure inferior_args always points to string starting with a space + and is never 0. + + * printcmd.c: (clear_displays, undisplay_command): + Fix bug in clear_displays which led to looping. + Make undisplay_command call it instead of wrong-looking code which + looked at (display->number == 0) instead of (display == 0) to + determine if it were at the end of the chain. + +Mon Dec 15 20:57:06 1986 Richard M. Stallman (rms at prep) + + * utils.c (query): Don't ignore a second line if given a null line. + + * infrun.c (normal_stop): Print "bug in shell" message + only for a segmentation fault. + + * main.c (main): Read init file from home directory if any, + before init file from current directory. + +Thu Dec 4 09:05:35 1986 Richard M. Stallman (rms at prep) + + * source.c (select_source_symtab): Don't ref thru arg if null. + + * m68k.opcode.h: For trap instruction code, use type T. + * m68k-pinsn.c (print_insn_arg): Recognize new arg-code T + and print the trap vector properly. + + * m-sun[23].h (FRAME_FIND_SAVED_REGS): Recognize a movl REG,-(sp) + as a way to save one register. Recognize clrw -(sp); movw -(sp) + after saving regs as a way to save the PS register. Adjust the + way to find the starting pc of a stack dummy frame for the fact + that these frames now save the PS. + + * m-sun[23].h (POP_FRAME): Restore PS register if frame saved it. + + * m-sun[23].h (PUSH_DUMMY_FRAME): Push the old PS register. + + * m-sun[23].h (CALL_DUMMY, etc.): Fix erroneous binary code for + the addl #nnn,sp instruction. Insert clrw -(sp); movw -(sp) + to indicate that the PS has been saved. + + * infrun.c (wait_for_inferior): If inferior exits, call + mark_breakpoints_out so it works to delete breakpoints afterward. + + * infrun.c (normal_stop): After popping a stack dummy frame, + select the frame that we get to. + + * dbxread.c (process_one_symbol): Store new `depth' field + in all context_stack elements created. For N_RBRAC, test + that depth matches that in the context_stack; if not, error. + + * dbxread.c (all callers of error): Make all error messages + start "Invalid symbol data: " and end with value of symnum. + Also change a few aborts to errors. + +Mon Dec 1 20:20:37 1986 Richard M. Stallman (rms at prep) + + * version.c: Version 1.11. + + * breakpoint.c (condition_command): If no condition spec'd, + print "breakpoint N now unconditional". + + * breakpoint.c (commands_command): Give different error messages + for cases of args not containing a breakpoint number + and args containing anything after the breakpoint number. + + * commands.c (lookup_command): Don't store a zero in *p + if have an undefined subcommand that is not an error. + + * commands.c (lookup_command): For recursive call, + pass subcommand list properly. Was passing the address + of the word containing the list. + + * core.c ({core,exec}_file_name): If no arg, tell user + what the effect is. + + * dbxread.c (define_symbol): Accept class code 'v' + for static variable within a function. + + * dbxread.c (read_type): Now allow any plain number or + pair of numbers in parens, with no code letter. This means + define new type same as type with specified number, or define + it as void if specified number's type is not yet mentioned. + + * m68k-pinsn.c (print_insn_arg): Case of general operand + in byte insn that happened to be immediate used wrong arg-size. + + * printcmd.c (set_next_address): Set next_address from arg + and also set value of `$_' from it. + + * printcmd.c (do_examine): Save address in last_examine_address + and value fetched to examine in last_examine_value. + + * printcmd.c (x_command): Copy last_examine_{address,value} + into values of `$_' and `$__'. Change `x' documentation string. + + * source.c (directory_command): Query when no args now says + what new value it wants use for the path. + + * source.c (list_command): Don't die in cases like `list ,+30'. + + * source.c (line_info): Call `set_next_address' to make `x' + display the text of the line. Change `info list' doc string. + +Sat Nov 29 07:59:29 1986 Richard M. Stallman (rms at prep) + + * printcmd.c (undisplay_command): If get no arg, + rather than crashing, query and then delete undisplay everything. + +Fri Nov 28 15:43:52 1986 Richard M. Stallman (rms at prep) + + * dbxread.c (process_one_symbol): If N_LBRAC sym + has a greater value that N_RBRAC, ignore the + N_LBRAC value and give the block zero length. + +Tue Nov 25 03:10:12 1986 Richard M. Stallman (rms at prep) + + * dbxread.c (process_one_symbol): Ignore N_NSYMS symbols + that appear in Ultrix. + +Sat Nov 22 22:49:06 1986 Richard M. Stallman (rms at prep) + + * version.c: version 1.10. + + * valprint.c (type_print*): + SHOW < 0 now means abbreviate struct/union members + or enum values with `...'. SHOW now decremented on + each recursion in type_print_base. Several places + that used to check !show now check show <= 0. + + * valprint.c (val_print): Pass -1 for SHOW to type_print + when printing typename inside parens or braces. + + * printcmd.c (print_command): If no value specified to print, + print the value of $. + + * expression.h, expread.y, eval.c, expprint.c: + OP_MEMVAL renamed UNOP_MEMVAL + and now allows any expression, not just an integer address. + It now has same format as UNOP_CAST and works almost like it. + Each place that referred to it has been rewritten + starting with a copy of the code that handles UNOP_CAST. + Doc for `print' command changed for this. + + * source.c (init_source_path): + Free and zero out any line_charpos's saved in source symtabs. + + * breakpoint.c (condition_command): + Parse the condition in the environment of the code where the + breakpoint is set. This requires finding the breakpoint + before parsing, so code is rearranged. + + * dbxread.c (dbx_alloc_type): + New function given typenums returns the type for those typenums + or allocates a new, empty type for those typenums and returns it. + + * symtab.c (smash_type_to_{pointer,function}): + New functions modify an already-allocated type object + to be a pointer to or function returning some given type. + + * dbxread.c (read_type): Uses dbx_alloc_type in many cases. + Reading a pointer or function type now works by doing that, + then reading the value type or type pointed to, then smashing + it into the type already allocated. This makes some fwd refs win. + Likewise for structs and unions. + + * dbxread.c (read_struct_type): Now receives the type object + as args. Used to get typenums as args and look up the type + itself. + + * dbxread.c (symbol_file_command): + At very end, clear out any type name that `char *' has received. + +Thu Nov 20 16:43:53 1986 Richard M. Stallman (rms at prep) + + * m-sun2.h, m-sun3.h (FIND_FRAME_SAVED_REGS): + Was incrementing address even for regs not saved. + +Sun Nov 16 14:59:07 1986 Richard M. Stallman (rms at prep) + + * values.c (value_field): Was adding in byte offset + before calling unpack_field_as_long, which itself + adds in the offset. Now pass addr of start of structure. + + * infrun.c (normal_stop): Clean up inferior_pid conditionals: + just return early if no inferior. + +Thu Nov 13 15:45:50 1986 Richard M. Stallman (rms at prep) + + * dbxread.c (struct header_file): add new field .instance + to distinguish the various entries for one header file. + + * dbxread.c (process_one_symbol): Use the `value' of + a N_BINCL or N_EXCL as the instance code for the header file. + + * dbxread.c (add_{new,old}_header_file): + Accept an instance code as arg and treat it as if it were + part of the file name for distinguishing and finding entries. + + * dbxread.c (add_new_header_file, read_type): + Turn off the header_file_prev_index feature with #if 0. + + * values.c (unpack_field_as_long, modify_field): + Run-time test to distinguish big and little endian machines + and do shifting accordingly. + +Tue Nov 11 00:31:18 1986 Richard M. Stallman (rms at prep) + + * version.c: version 1.9. + + * breakpoint.c (delete_command): + Don't query if 2nd arg is zero. + + * breakpoint.c (clear_breakpoints): + Pass 2nd arg of zero to delete_command. + +Sat Nov 8 23:29:19 1986 Richard M. Stallman (rms at prep) + + * breakpoint.c (delete_command): + Ask for confirmation when used with no arg (delete all). + +Fri Nov 7 11:23:09 1986 Richard M. Stallman (rms at prep) + + * infrun.c (start_inferior, wait_for_inferior): + Eliminate `stop_in_shell' which was not being maintained right. + New variable `running_in_shell' is set to 1 or 0 when the + expected SIGTRAPs happen, and is simply examined at other times. + + * infrun.c (wait_for_inferior): + If get SIGSEGV with running_in_shell == 1, it is sh + allocating memory. Pass the signal silently to the shell. + + * core.c (exec_file_command): + data_{start,end} are adjusted unconditionally when an + exec file is opened, so closing counter-adjustment is + now unconditional as well. + + * printcmd.c (x_command): + Don't erase the expression from the calling args + if cllaed noninteractively (used to be clobbering + definitions of user-defined commands). + + * source.c (list_command): likewise. + +Wed Nov 5 09:41:00 1986 Richard M. Stallman (rms at prep) + + * Makefile: New variable OBSTACK1 that people can use + to make obstack.o a dependency of gdb. + + * breakpoint.c (initialize): + Define new aliases "br", "bre" and "brea" for "break". + +Sun Nov 2 21:16:06 1986 Richard Mlynarik (mly at prep) + + * symmisc.c (read_symsegs): + Add an extra protection against invalid symbol-file + + * m-vax.h: + Set KERNEL_U_ADDR and STACK_END_ADDR non-4.2-specifically + +Tue Oct 21 13:34:14 1986 Richard Mlynarik (mly at prep) + + * breakpoints.c (initialize): + Delet reference to non-existent command "tenable" from doc of "enable" + +Tue Oct 14 19:58:27 1986 Richard Mlynarik (mly at prep) + + * printcmd.c (display_command, undisplay_command): + * infcmd.c (run_command): + Call dont_repeat. + + +Local Variables: +mode: indented-text +eval: (auto-fill-mode 1) +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/gdb/Makefile b/gdb/Makefile new file mode 100644 index 00000000000..c1fd60cb307 --- /dev/null +++ b/gdb/Makefile @@ -0,0 +1,85 @@ +# -I. for "#include " +CFLAGS = -g -I. -Dvfork=fork -DDEBUG +# NOTE!!! -O may FAIL TO WORK! See initialize.h for some weird hacks. + +# define this to be "obstack.o" if you don't have the obstack library installed +# you must at the same time define OBSTACK1 as "obstack.o" +# so that the dependencies work right. +OBSTACK = obstack.o alloca.o -lPW +OBSTACK1 = obstack.o alloca.o + +STARTOBS = main.o firstfile.o + +OBS = blockframe.o breakpoint.o findvar.o stack.o source.o \ + values.o eval.o valops.o valarith.o valprint.o printcmd.o \ + symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o + +TSOBS = core.o inflow.o + +NTSOBS = standalone.o + +ENDOBS = lastfile.o command.o utils.o expread.o expprint.o pinsn.o \ + environ.o version.o + +TSSTART = /lib/crt0.o + +NTSSTART = kdb-start.o + +gdb : $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(OBSTACK1) + $(CC) -o gdb $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) -lg $(OBSTACK) + +xgdb : $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) $(OBSTACK1) + $(CC) -o xgdb $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) \ + -lXtk11 -lXrm -lX11 -lg $(OBSTACK) + +kdb : $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) $(OBSTACK1) + ld -o kdb $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) -lc -lg $(OBSTACK) + +clean: + rm -f $(STARTOBS) $(OBS) $(TSOBS) $(OBSTACK1) $(NTSSTART) $(NTSOBS) + rm -f xgdb.o gdb xgdb kdb tags errs expread.tab.c + +blockframe.o : blockframe.c defs.h initialize.h param.h symtab.h frame.h +breakpoint.o : breakpoint.c defs.h initialize.h param.h symtab.h frame.h +command.o : command.c command.h +coffread.o : coffread.c defs.h initialize.h param.h symtab.h +core.o : core.c defs.h initialize.h param.h +dbxread.o : dbxread.c defs.h initialize.h param.h symtab.h +environ.o : environ.c environ.h +expprint.o : expprint.c defs.h symtab.h expression.h +expread.tab.c : expread.y + @echo 'Expect 96 shift/reduce conflicts.' + yacc expread.y + mv y.tab.c expread.tab.c +expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h + $(CC) -c ${CFLAGS} expread.tab.c + mv expread.tab.o expread.o +eval.o : eval.c defs.h initialize.h symtab.h value.h expression.h +findvar.o : findvar.c defs.h initialize.h param.h symtab.h frame.h value.h +firstfile.o : firstfile.c initialize.h +infcmd.o : infcmd.c defs.h initialize.h param.h symtab.h frame.h inferior.h environ.h value.h +inflow.o : inflow.c defs.h initialize.h param.h frame.h inferior.h +infrun.o : infrun.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h +kdb-start.o : kdb-start.c defs.h param.h +lastfile.o : lastfile.c +main.o : main.c defs.h command.h +# pinsn.o depends on ALL the opcode printers +# since we don't know which one is really being used. +pinsn.o : pinsn.c defs.h param.h symtab.h \ + vax-opcode.h vax-pinsn.c m68k-opcode.h m68k-pinsn.c +printcmd.o : printcmd.c defs.h initialize.h param.h symtab.h value.h expression.h +source.o : source.c defs.h initialize.h symtab.h +stack.o : stack.c defs.h initialize.h param.h symtab.h frame.h +standalone.o : standalone.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h +symmisc.o : symmisc.c defs.h initialize.h symtab.h +symtab.o : symtab.c defs.h initialize.h param.h symtab.h +utils.o : utils.c defs.h +valarith.o : valarith.c defs.h initialize.h param.h symtab.h value.h expression.h +valops.o : valops.c defs.h initialize.h param.h symtab.h value.h +valprint.o : valprint.c defs.h initialize.h symtab.h value.h +values.o : values.c defs.h initialize.h param.h symtab.h value.h +version.o : version.c +xgdb.o : xgdb.c defs.h initialize.h param.h symtab.h frame.h + $(CC) -c $(CFLAGS) xgdb.c -o $@ + +obstack.o : obstack.c diff --git a/gdb/RCS/Makefile,v b/gdb/RCS/Makefile,v new file mode 100644 index 00000000000..d942be05e6a --- /dev/null +++ b/gdb/RCS/Makefile,v @@ -0,0 +1,160 @@ +head 1.4; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @# @; + + +1.4 +date 88.06.08.23.14.28; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 88.02.28.03.38.17; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 88.01.26.05.14.43; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.05.14.07; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS's wheaties devl dirs +@ + + +1.4 +log +@Add -DEBUG +@ +text +@# -I. for "#include " +CFLAGS = -g -I. -Dvfork=fork -DDEBUG +# NOTE!!! -O may FAIL TO WORK! See initialize.h for some weird hacks. + +# define this to be "obstack.o" if you don't have the obstack library installed +# you must at the same time define OBSTACK1 as "obstack.o" +# so that the dependencies work right. +OBSTACK = obstack.o alloca.o -lPW +OBSTACK1 = obstack.o alloca.o + +STARTOBS = main.o firstfile.o + +OBS = blockframe.o breakpoint.o findvar.o stack.o source.o \ + values.o eval.o valops.o valarith.o valprint.o printcmd.o \ + symtab.o symmisc.o coffread.o dbxread.o infcmd.o infrun.o + +TSOBS = core.o inflow.o + +NTSOBS = standalone.o + +ENDOBS = lastfile.o command.o utils.o expread.o expprint.o pinsn.o \ + environ.o version.o + +TSSTART = /lib/crt0.o + +NTSSTART = kdb-start.o + +gdb : $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) $(OBSTACK1) + $(CC) -o gdb $(STARTOBS) $(OBS) $(TSOBS) $(ENDOBS) -lg $(OBSTACK) + +xgdb : $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) $(OBSTACK1) + $(CC) -o xgdb $(STARTOBS) $(OBS) xgdb.o $(TSOBS) $(ENDOBS) \ + -lXtk11 -lXrm -lX11 -lg $(OBSTACK) + +kdb : $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) $(OBSTACK1) + ld -o kdb $(NTSSTART) $(STARTOBS) $(OBS) $(NTSOBS) $(ENDOBS) -lc -lg $(OBSTACK) + +clean: + rm -f $(STARTOBS) $(OBS) $(TSOBS) $(OBSTACK1) $(NTSSTART) $(NTSOBS) + rm -f xgdb.o gdb xgdb kdb tags errs expread.tab.c + +blockframe.o : blockframe.c defs.h initialize.h param.h symtab.h frame.h +breakpoint.o : breakpoint.c defs.h initialize.h param.h symtab.h frame.h +command.o : command.c command.h +coffread.o : coffread.c defs.h initialize.h param.h symtab.h +core.o : core.c defs.h initialize.h param.h +dbxread.o : dbxread.c defs.h initialize.h param.h symtab.h +environ.o : environ.c environ.h +expprint.o : expprint.c defs.h symtab.h expression.h +expread.tab.c : expread.y + @@echo 'Expect 96 shift/reduce conflicts.' + yacc expread.y + mv y.tab.c expread.tab.c +expread.o : expread.tab.c defs.h param.h symtab.h frame.h expression.h + $(CC) -c ${CFLAGS} expread.tab.c + mv expread.tab.o expread.o +eval.o : eval.c defs.h initialize.h symtab.h value.h expression.h +findvar.o : findvar.c defs.h initialize.h param.h symtab.h frame.h value.h +firstfile.o : firstfile.c initialize.h +infcmd.o : infcmd.c defs.h initialize.h param.h symtab.h frame.h inferior.h environ.h value.h +inflow.o : inflow.c defs.h initialize.h param.h frame.h inferior.h +infrun.o : infrun.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h +kdb-start.o : kdb-start.c defs.h param.h +lastfile.o : lastfile.c +main.o : main.c defs.h command.h +# pinsn.o depends on ALL the opcode printers +# since we don't know which one is really being used. +pinsn.o : pinsn.c defs.h param.h symtab.h \ + vax-opcode.h vax-pinsn.c m68k-opcode.h m68k-pinsn.c +printcmd.o : printcmd.c defs.h initialize.h param.h symtab.h value.h expression.h +source.o : source.c defs.h initialize.h symtab.h +stack.o : stack.c defs.h initialize.h param.h symtab.h frame.h +standalone.o : standalone.c defs.h initialize.h param.h symtab.h frame.h inferior.h wait.h +symmisc.o : symmisc.c defs.h initialize.h symtab.h +symtab.o : symtab.c defs.h initialize.h param.h symtab.h +utils.o : utils.c defs.h +valarith.o : valarith.c defs.h initialize.h param.h symtab.h value.h expression.h +valops.o : valops.c defs.h initialize.h param.h symtab.h value.h +valprint.o : valprint.c defs.h initialize.h symtab.h value.h +values.o : values.c defs.h initialize.h param.h symtab.h value.h +version.o : version.c +xgdb.o : xgdb.c defs.h initialize.h param.h symtab.h frame.h + $(CC) -c $(CFLAGS) xgdb.c -o $@@ + +obstack.o : obstack.c +@ + + +1.3 +log +@Make clean +@ +text +@d2 1 +a2 1 +CFLAGS = -g -I. -Dvfork=fork +@ + + +1.2 +log +@We don't have vfork or alloca, and regexp routines are in libPW.a for +no good reason. +@ +text +@d38 4 +@ + + +1.1 +log +@Initial revision +@ +text +@d2 1 +a2 1 +CFLAGS = -g -I. +d8 2 +a9 2 +OBSTACK = obstack.o +OBSTACK1 = obstack.o +@ diff --git a/gdb/RCS/coffread.c,v b/gdb/RCS/coffread.c,v new file mode 100644 index 00000000000..7542030f9a1 --- /dev/null +++ b/gdb/RCS/coffread.c,v @@ -0,0 +1,304 @@ +head 1.4; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.4 +date 88.06.08.23.13.40; author gnu; state Exp; +branches ; +next 1.3; + +1.3 +date 88.02.28.03.37.53; author gnu; state Exp; +branches ; +next 1.2; + +1.2 +date 88.01.26.05.02.32; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.00.38.04; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS's work dirs on Wheaties +@ + + +1.4 +log +@Half reasonable reading of coff files. Problem was that it assumed +that a .text would show up sometime, and it never did. We have to close +out each source file's symtab as we hit the next one. +@ +text +@/* 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 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "param.h" +#ifdef COFF_FORMAT +#include "initialize.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include + +static void add_symbol_to_list (); +static void 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 void finish_block (); +static struct blockvector *make_blockvector (); +static struct symbol *process_coff_symbol (); +static int init_stringtab (); +static void free_stringtab (); +static char *getfilename (); +static char *getsymname (); +static int init_lineno (); +static void enter_linenos (); + +START_FILE + +/* 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 start and end of text of current source file. + This comes from a ".text" symbol where x_nlinno > 0. */ + +static CORE_ADDR cur_src_start_addr; +static CORE_ADDR cur_src_end_addr; + +/* End of the text segment of the executable file, + as found in the symbol _etext. */ + +static CORE_ADDR end_of_text_addr; + +/* The addresses of the symbol table stream and number of symbols + of the object file we are reading (as copied into core). */ + +static FILE *nlist_stream_global; +static int nlist_nsyms_global; + +/* The file and text section headers of the symbol file */ + +static FILHDR file_hdr; +static SCNHDR text_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; + +/* Vector of line number information. */ + +static struct linetable *line_vector; + +/* Index of next entry to go in line_vector_index. */ + +static int line_vector_index; + +/* Last line number recorded in the line vector. */ + +static int prev_line_number; + +/* Number of elements allocated for line_vector currently. */ + +static int line_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 *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; + int depth; +}; + +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 first_object_file_end; /* From blockframe.c */ + +/* File name symbols were loaded from. */ + +static char *symfile; + +int debug = 1; + + +/* 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) + { + type_vector_length *= 2; + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[type_vector_length / 2], + type_vector_length * sizeof (struct type *) / 2); + } + 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 *) xmalloc (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 \ No newline at end of file diff --git a/gdb/RCS/core.c,v b/gdb/RCS/core.c,v new file mode 100644 index 00000000000..99547f8c0a7 --- /dev/null +++ b/gdb/RCS/core.c,v @@ -0,0 +1,763 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.04.52; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.05.04.03; author gnu; state Exp; +branches ; +next ; + + +desc +@From RMS's development version on wheaties, 20Jan88 +@ + + +1.2 +log +@Hacks to get it to compile on a/ux. Needs work at finding the registers +in a core file. +@ +text +@/* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "initialize.h" +#include "defs.h" +#include "param.h" + +#include +#include +#include +#include +#include +#include +#include + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#endif + +#ifdef NEW_SUN_CORE +#include +#else /* not NEW_SUN_CORE */ +#ifdef UMAX_CORE +#include +#else /* not UMAX_CORE */ +#ifdef mac_aux +#include +#include +#include +#include +#include +#else +#include +#endif /* mac_aux */ +#endif /* UMAX_CORE */ +#endif /* NEW_SUN_CORE */ + +#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 +#define AOUTHDR struct exec +#endif + +START_FILE + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +static char *corefile; +static 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. */ + +static int corechan; +static int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +static CORE_ADDR data_start; +static CORE_ADDR data_end; +static CORE_ADDR stack_start; +static 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. */ + +static CORE_ADDR text_start; +static CORE_ADDR text_end; +static CORE_ADDR exec_data_start; +static CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +static int text_offset; + +/* Address in executable file of start of data area data. */ + +static int exec_data_offset; + +/* Address in core file of start of data area data. */ + +static int data_offset; + +/* Address in core file of start of stack area data. */ + +static int stack_offset; + +#ifdef COFF_FORMAT +/* various coff data structures */ + +static FILHDR file_hdr; +static SCNHDR text_hdr; +static SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +static AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +static AOUTHDR exec_aouthdr; + +static void validate_files (); +unsigned int register_addr (); + +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) + { + 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); +#ifdef NEW_SUN_CORE + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + data_start = exec_data_start; + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + bcopy (&corestr.c_regs, registers, 16 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; + bcopy (corestr.c_fpstatus.fps_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpstatus.fps_regs); + bcopy (&corestr.c_fpstatus.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs); + + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + } +#else /* not NEW_SUN_CORE */ + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { +#ifdef UMAX_CORE + struct ptrace_user u; +#else + struct user u; +#endif + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + +#ifdef UMAX_CORE + data_end = data_start + u.pt_dsize; + stack_start = stack_end - u.pt_ssize; + data_offset = sizeof u; + stack_offset = data_offset + u.pt_dsize; + reg_offset = 0; + + bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR)); + +#else /* not UMAX_CORE */ +#ifdef mac_aux + /* This may well not work for 0407 (nonshared text) a.out's */ + data_end = data_start + u.u_dsize << PAGESHIFT; + stack_start = stack_end - u.u_ssize << PAGESHIFT; + data_offset = USIZE; + stack_offset = USIZE + u.u_dsize << PAGESHIFT; + reg_offset = (int) &u.u_ar0[0] - (int) &u; + + core_aouthdr.a_magic = u.u_exdata.ux_mag; +#else + 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); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + core_aouthdr.a_magic = 0; +#endif /* not mac_aux */ +#endif /* not UMAX_CORE */ + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } +#endif /* not NEW_SUN_CORE */ + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + char dirname[MAXPATHLEN]; + + getwd (dirname); + corefile = concat (dirname, "/", filename); + } + + set_current_frame (read_register (FP_REGNUM)); + 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) + { + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + 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 = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_TXTADDR (exec_aouthdr); + text_end = text_start + exec_aouthdr.a_text; + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + exec_data_end = exec_data_start + exec_aouthdr.a_data; + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + data_start = exec_data_start; + data_end += exec_data_start; + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } +#endif /* not COFF_FORMAT */ + + 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 ? filename : "No executable specified.\n"); +} + +/* Call this to specify the hook for exec_file_command to call back. + This is called from the x-window display code. */ + +specify_exec_file_hook (hook) + void (*hook) (); +{ + exec_file_display_hook = hook; +} + +/* The exec file must be closed before running an inferior. + If it is needed again after the inferior dies, it must + be reopened. */ + +close_exec_file () +{ + if (execchan >= 0) + close (execchan); + execchan = -1; +} + +reopen_exec_file () +{ + if (execchan < 0 && execfile != 0) + { + char *filename = concat (execfile, "", ""); + exec_file_command (filename, 0); + free (filename); + } +} + +/* If we have both a core file and an exec file, + print a warning if they don't go together. + This should really check that the core file came + from that exec file, but I don't know how to do it. */ + +static void +validate_files () +{ + if (execfile != 0 && corefile != 0) + { + struct stat st_core; + + fstat (corechan, &st_core); + + if (core_aouthdr.a_magic != 0 + && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr)) + printf ("Warning: core file does not match specified executable file.\n"); + else if (exec_mtime > st_core.st_mtime) + printf ("Warning: exec file is newer than core file.\n"); + } +} + +char * +get_exec_file () +{ + if (execfile == 0) + error ("No executable file specified.\n\ +Use the \"exec-file\" and \"symbol-file\" commands."); + return execfile; +} + +int +have_core_file_p () +{ + return corefile != 0; +} + +static void +files_info () +{ + char *symfile; + extern char *get_sym_file (); + + if (execfile) + printf ("Executable file \"%s\".\n", execfile); + else + printf ("No executable file\n"); + if (corefile == 0) + printf ("No core dump file\n"); + else + printf ("Core dump file \"%s\".\n", corefile); + + if (have_inferior_p ()) + printf ("Using the running image of the program, rather than these files.\n"); + + symfile = get_sym_file (); + if (symfile != 0) + printf ("Symbols loaded from \"%s\".\n", symfile); + + if (! have_inferior_p ()) + { + if (execfile) + { + printf ("Text segment from 0x%x to 0x%x.\n", + text_start, text_end); + } + if (corefile) + { + printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n", + data_start, data_end, stack_start, stack_end); + } + else + { + printf ("Data segment in executable from 0x%x to 0x%x.\n", + exec_data_start, exec_data_end); + } + } +} + +/* Read "memory data" from core file and/or executable file */ + +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (have_inferior_p ()) + read_inferior_memory (memaddr, myaddr, len); + else + xfer_core_file (memaddr, myaddr, len, 0); +} + +/* Write LEN bytes of data starting at address MYADDR + into debugged program memory at address MEMADDR. + Returns zero if successful, or an errno value if ptrace failed. */ + +int +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (have_inferior_p ()) + return write_inferior_memory (memaddr, myaddr, len); + else + error ("Can write memory only when program being debugged is running."); +} + +xfer_core_file (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + register int val; + int xferchan; + char **xferfile; + int fileptr; + + while (len > 0) + { + xferfile = 0; + xferchan = 0; + + /* Determine which file the next bunch of addresses reside in, + and where in the file. Set the file's read/write pointer + to point at the proper place for the desired address + and set xferfile and xferchan for the correct file. + If desired address is nonexistent, leave them zero. + i is set to the number of bytes that can be handled + along with the next address. */ + + if (memaddr < text_start) + { + i = min (len, text_start - memaddr); + } + else if (memaddr >= text_end && memaddr < data_start) + { + i = min (len, data_start - memaddr); + } + else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end) + && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } + /* Note that if there is no core file + data_start and data_end are equal. */ + else if (memaddr >= data_start && memaddr < data_end) + { + i = min (len, data_end - memaddr); + fileptr = memaddr - data_start + data_offset; + xferfile = &corefile; + xferchan = corechan; + } + /* Note that if there is no core file + stack_start and stack_end are equal. */ + else if (memaddr >= stack_start && memaddr < stack_end) + { + i = min (len, stack_end - memaddr); + fileptr = memaddr - stack_start + stack_offset; + xferfile = &corefile; + xferchan = corechan; + } + else if (corechan < 0 + && memaddr >= exec_data_start && memaddr < exec_data_end) + { + i = min (len, exec_data_end - memaddr); + fileptr = memaddr - exec_data_start + exec_data_offset; + xferfile = &execfile; + xferchan = execchan; + } + else if (memaddr >= text_start && memaddr < text_end) + { + i = min (len, text_end - memaddr); + fileptr = memaddr - text_start + text_offset; + xferfile = &execfile; + xferchan = execchan; + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. */ + else + bzero (myaddr, i); + + memaddr += i; + myaddr += i; + len -= i; + } +} + +/* My replacement for the read system call. + Used like `read' but keeps going if `read' returns too soon. */ + +myread (desc, addr, len) + int desc; + char *addr; + int len; +{ + register int val; + int orglen = len; + + while (len > 0) + { + val = read (desc, addr, len); + if (val < 0) + return val; + if (val == 0) + return orglen - len; + len -= val; + addr += val; + } +} + +#ifndef NEW_SUN_CORE + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + +#ifdef mac_aux +/* FIXME, we don't know where the regs are. Maybe the test command + * that tests what parts of the upage are writeable will find 'em for us. + */ +#define REGISTER_U_ADDR(addr, foo, bar) addr = 0; +#endif + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* not NEW_SUN_CORE */ + +static +initialize () +{ + corechan = -1; + execchan = -1; + corefile = 0; + execfile = 0; + exec_file_display_hook = 0; + + text_start = 0; + text_end = 0; + data_start = 0; + data_end = 0; + exec_data_start = 0; + exec_data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + add_com ("core-file", class_files, core_file_command, + "Use FILE as core dump for examining memory and registers.\n\ +No arg means have no core file."); + add_com ("exec-file", class_files, exec_file_command, + "Use FILE as program for getting contents of pure memory.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +is searched for a command of that name.\n\ +No arg means have no executable file."); + add_info ("files", files_info, "Names of files being debugged."); +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d27 1 +d44 5 +d50 4 +a53 1 +#endif +d240 10 +d259 1 +d675 6 +@ diff --git a/gdb/RCS/infcmd.c,v b/gdb/RCS/infcmd.c,v new file mode 100644 index 00000000000..cc30fe4d6bc --- /dev/null +++ b/gdb/RCS/infcmd.c,v @@ -0,0 +1,966 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.06.19; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.01.19.05; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS's wheaties devl sources +@ + + +1.2 +log +@Add local sys_siglist for a/ux because they don't provide one, sigh. +@ +text +@/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" + +#include +#include +#include + +#ifdef mac_aux +/* Warning! This table is positional and highly dependent on the local + system. Check it closely against when porting. */ +char *sys_siglist[] = { + "Signal 0", + "Hangup", + "Interrupt", + "Quit", + "Invalid instruction", + "Trace/breakpoint trap", + "IOT trap", + "EMT trap", + "Floating point exception", + "Killed", + "Bus error", + "Segmentation fault", + "Bad system call", + "Broken pipe", + "Alarm clock", + "Terminated", + "User signal 1", + "User signal 2", + "Child exited", + "Power-fail restart", + "Stopped", + "Stopped (tty input)", + "Stopped (tty output)", + "Stopped (signal)", + "Cputime limit exceeded", + "File size limit exceeded", + "Virtual timer expired", + "Profiling timer expired", + "Window changed", + "Continued", + "Urgent I/O condition", + "I/O possible", +}; +#else +/* More portable systems do it for you */ +extern char *sys_siglist[]; +#endif + +#define ERROR_NO_INFERIOR \ + if (inferior_pid == 0) error ("The program is not being run."); + +/* String containing arguments to give to the program, + with a space added at the front. Just a space means no args. */ + +static char *inferior_args; + +/* File name for default use for standard in/out in the inferior. */ + +char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +int inferior_pid; + +/* Last signal that the inferior received (why it stopped). */ + +int stop_signal; + +/* Address at which inferior stopped. */ + +CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +FRAME stop_frame; + +/* Number of breakpoint it stopped at, or 0 if none. */ + +int stop_breakpoint; + +/* Nonzero if stopped due to a step command. */ + +int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +int stop_stack_dummy; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +CORE_ADDR step_range_start; /* Inclusive */ +CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +CORE_ADDR step_frame; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +int step_multi; + +/* Environment to use for running inferior, + in format described in environ.h. */ + +struct environ *inferior_environ; + +CORE_ADDR read_pc (); +struct command_line *get_breakpoint_commands (); + +START_FILE + +int +have_inferior_p () +{ + return inferior_pid != 0; +} + +static void +set_args_command (args) + char *args; +{ + free (inferior_args); + if (!args) args = ""; + inferior_args = concat (" ", args, ""); +} + +void +tty_command (file) + char *file; +{ + if (file == 0) + error_no_arg ("terminal name for running target process"); + + inferior_io_terminal = savestring (file, strlen (file)); +} + +static void +run_command (args, from_tty) + char *args; + int from_tty; +{ + extern char **environ; + register int i; + char *exec_file; + char *allargs; + + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + dont_repeat (); + + if (inferior_pid) + { + if (query ("The program being debugged has been started already.\n\ +Start it from the beginning? ")) + kill_inferior (); + else + error ("Program already started."); + } + + if (args) + set_args_command (args); + + exec_file = (char *) get_exec_file (); + if (from_tty) + { + printf ("Starting program: %s%s\n", + exec_file, inferior_args); + fflush (stdout); + } + + allargs = concat ("exec ", exec_file, inferior_args); + inferior_pid = create_inferior (allargs, environ_vector (inferior_environ)); + + clear_proceed_status (); + + start_inferior (); +} + +void +cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + ERROR_NO_INFERIOR; + + clear_proceed_status (); + + /* If have argument, set proceed count of breakpoint we stopped at. */ + + if (stop_breakpoint && proc_count_exp) + { + set_ignore_count (stop_breakpoint, + parse_and_eval_address (proc_count_exp) - 1, + from_tty); + if (from_tty) + printf (" "); + } + + if (from_tty) + printf ("Continuing.\n"); + + proceed (-1, -1, 0); +} + +/* Step until outside of current statement. */ +static void step_1 (); + +static void +step_command (count_string) +{ + step_1 (0, 0, count_string); +} + +/* Likewise, but skip over subroutine calls as if single instructions. */ + +static void +next_command (count_string) +{ + step_1 (1, 0, count_string); +} + +/* Likewise, but step only one instruction. */ + +static void +stepi_command (count_string) +{ + step_1 (0, 1, count_string); +} + +static void +nexti_command (count_string) +{ + step_1 (1, 1, count_string); +} + +static void +step_1 (skip_subroutines, single_inst, count_string) + int skip_subroutines; + int single_inst; + char *count_string; +{ + register int count = 1; + + ERROR_NO_INFERIOR; + count = count_string ? parse_and_eval_address (count_string) : 1; + + for (; count > 0; count--) + { + clear_proceed_status (); + + step_frame = get_current_frame (); + + if (! single_inst) + { + find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end); + if (step_range_end == 0) + { + terminal_ours (); + error ("Current function has no line number information."); + } + } + else + { + /* Say we are stepping, but stop after one insn whatever it does. + Don't step through subroutine calls even to undebuggable functions. */ + step_range_start = step_range_end = 1; + if (!skip_subroutines) + step_over_calls = 0; + } + + if (skip_subroutines) + step_over_calls = 1; + + step_multi = (count > 1); + proceed (-1, -1, 1); + if (! stop_step) + break; + } +} + +/* Continue program at specified address. */ + +static void +jump_command (arg, from_tty) + char *arg; + int from_tty; +{ + register CORE_ADDR addr; + struct symtab_and_line sal; + + ERROR_NO_INFERIOR; + + if (!arg) + error_no_arg ("starting address"); + + sal = decode_line_spec (arg, 1); + + if (sal.symtab == 0 && sal.pc == 0) + error ("No source file has been specified."); + + if (sal.pc == 0) + sal.pc = find_line_pc (sal.symtab, sal.line); + + { + struct symbol *fn = get_frame_function (get_current_frame ()); + struct symbol *sfn = find_pc_function (sal.pc); + if (fn != 0 && sfn != fn + && ! query ("That is not in function %s. Continue there? ", + sal.line, SYMBOL_NAME (fn))) + error ("Not confirmed."); + } + + if (sal.pc == 0) + error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename); + + addr = sal.pc; + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing at 0x%x.\n", addr); + + proceed (addr, 0, 0); +} + +/* Continue program giving it specified signal. */ + +static void +signal_command (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + register int signum; + + dont_repeat (); /* Too dangerous. */ + ERROR_NO_INFERIOR; + + if (!signum_exp) + error_no_arg ("signal number"); + + signum = parse_and_eval_address (signum_exp); + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing with signal %d.\n", signum); + + proceed (stop_pc, signum, 0); +} + +/* Execute a "stack dummy", a piece of code stored in the stack + by the debugger to be executed in the inferior. + + To call: first, do PUSH_DUMMY_FRAME. + Then push the contents of the dummy. It should end with a breakpoint insn. + Then call here, passing address at which to start the dummy. + + The contents of all registers are saved before the dummy frame is popped + and copied into the buffer BUFFER. + + The dummy's frame is automatically popped whenever that break is hit. + If that is the first time the program stops, run_stack_dummy + returns to its caller with that frame already gone. + Otherwise, the caller never gets returned to. */ + +/* 4 => return instead of letting the stack dummy run. */ + +static int stack_dummy_testing = 0; + +void +run_stack_dummy (addr, buffer) + CORE_ADDR addr; + REGISTER_TYPE *buffer; +{ + int saved_pc_changed = pc_changed; + int saved_stop_signal = stop_signal; + int saved_stop_pc = stop_pc; + int saved_stop_frame = stop_frame; + int saved_stop_breakpoint = stop_breakpoint; + int saved_stop_step = stop_step; + int saved_stop_stack_dummy = stop_stack_dummy; + FRAME saved_selected_frame; + int saved_selected_level; + struct command_line *saved_breakpoint_commands + = get_breakpoint_commands (); + + record_selected_frame (&saved_selected_frame, &saved_selected_level); + + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); + if (stack_dummy_testing & 4) + { + POP_FRAME; + return; + } + proceed (addr, 0, 0); + + if (!stop_stack_dummy) + error ("Cannot continue previously requested operation."); + + set_breakpoint_commands (saved_breakpoint_commands); + select_frame (saved_selected_frame, saved_selected_level); + stop_signal = saved_stop_signal; + stop_pc = saved_stop_pc; + stop_frame = saved_stop_frame; + stop_breakpoint = saved_stop_breakpoint; + stop_step = saved_stop_step; + stop_stack_dummy = saved_stop_stack_dummy; + pc_changed = saved_pc_changed; + + /* On return, the stack dummy has been popped already. */ + + bcopy (stop_registers, buffer, sizeof stop_registers); +} + +/* "finish": Set a temporary breakpoint at the place + the selected frame will return to, then continue. */ + +static void +finish_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + register FRAME frame; + struct frame_info fi; + + register struct symbol *function; + + if (!have_inferior_p ()) + error ("The program is not being run."); + if (arg) + error ("The \"finish\" command does not take any arguments."); + + frame = get_prev_frame (selected_frame); + if (frame == 0) + error ("\"finish\" not meaningful in the outermost frame."); + + clear_proceed_status (); + + fi = get_frame_info (frame); + sal = find_pc_line (fi.pc, 0); + sal.pc = fi.pc; + set_momentary_breakpoint (sal, frame); + + /* Find the function we will return from. */ + + fi = get_frame_info (fi.next_frame); + function = find_pc_function (fi.pc); + + if (from_tty) + { + printf ("Run till exit from "); + print_selected_frame (); + } + + proceed (-1, -1, 0); + + if (stop_breakpoint == -3 && function != 0) + { + struct type *value_type; + register value val; + + if (TYPE_CODE (SYMBOL_TYPE (function)) != TYPE_CODE_VOID) + value_type = SYMBOL_TYPE (function); + else + return; + + val = value_being_returned (value_type, stop_registers); + printf ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, stdout); + putchar ('\n'); + } +} + +static void +program_info () +{ + if (inferior_pid == 0) + { + printf ("The program being debugged is not being run.\n"); + return; + } + + printf ("Program being debugged is in process %d, stopped at 0x%x.\n", + inferior_pid, stop_pc); + if (stop_step) + printf ("It stopped after being stepped.\n"); + else if (stop_breakpoint) + printf ("It stopped at breakpoint %d.\n", stop_breakpoint); + else if (stop_signal) + printf ("It stopped with signal %d (%s).\n", + stop_signal, sys_siglist[stop_signal]); + + printf ("\nType \"info stack\" or \"info reg\" for more information.\n"); +} + +static void +environment_info (var) + char *var; +{ + if (var) + { + register char *val = get_in_environ (inferior_environ, var); + if (val) + printf ("%s = %s\n", var, val); + else + printf ("Environment variable \"%s\" not defined.\n", var); + } + else + { + register char **vector = environ_vector (inferior_environ); + while (*vector) + printf ("%s\n", *vector++); + } +} + +static void +set_environment_command (arg) + char *arg; +{ + register char *p, *val, *var; + + if (arg == 0) + error_no_arg ("environment variable and value"); + + p = (char *) index (arg, '='); + val = (char *) index (arg, ' '); + if (p != 0 && val != 0) + p = arg + min (p - arg, val - arg); + else if (val != 0 && p == 0) + p = val; + + if (p == 0) + error ("Space or \"=\" must separate variable name and its value"); + if (p[1] == 0) + error_no_arg ("value for the variable"); + if (p == arg) + error_no_arg ("environment variable to set"); + + val = p + 1; + while (*val == ' ' || *val == '\t') val++; + while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--; + + var = savestring (arg, p - arg); + set_in_environ (inferior_environ, var, val); + free (var); +} + +static void +unset_environment_command (var) + char *var; +{ + if (var == 0) + error_no_arg ("environment variable"); + + unset_in_environ (inferior_environ, var); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char cbuf; + short sbuf; + int ibuf; + long lbuf; + + if (len == sizeof (char)) + { + read_memory (memaddr, &cbuf, len); + return cbuf; + } + if (len == sizeof (short)) + { + read_memory (memaddr, &sbuf, len); + return sbuf; + } + if (len == sizeof (int)) + { + read_memory (memaddr, &ibuf, len); + return ibuf; + } + if (len == sizeof (lbuf)) + { + read_memory (memaddr, &lbuf, len); + return lbuf; + } + error ("Cannot handle integers of %d bytes.", len); +} + +CORE_ADDR +read_pc () +{ + return (CORE_ADDR) read_register (PC_REGNUM); +} + +write_pc (val) + CORE_ADDR val; +{ + write_register (PC_REGNUM, (long) val); +} + +char *reg_names[] = REGISTER_NAMES; + +static void +registers_info (addr_exp) + char *addr_exp; +{ + register int i; + int regnum; + + if (addr_exp) + { + if (*addr_exp >= '0' && *addr_exp <= '9') + regnum = atoi (addr_exp); + else + { + register char *p = addr_exp; + if (p[0] == '$') + p++; + for (regnum = 0; regnum < NUM_REGS; regnum++) + if (!strcmp (p, reg_names[regnum])) + break; + if (regnum == NUM_REGS) + error ("%s: invalid register name.", addr_exp); + } + } + else + printf ("Reg\tContents\n\n"); + + for (i = 0; i < NUM_REGS; i++) + { + unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + REGISTER_TYPE val; + + if (addr_exp != 0 && i != regnum) + continue; + + /* On machines with lots of registers, pause every 16 lines + so user can read the output. */ + if (addr_exp == 0 && i > 0 && i % 16 == 0) + { + printf ("--Type Return to print more--"); + fflush (stdout); + read_line (); + } + + /* Get the data in raw format, then convert also to virtual format. */ + read_relative_register_raw_bytes (i, raw_buffer); + REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); + + printf ("%s\t", reg_names[i]); + + /* If virtual format is floating, print it that way. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT + && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i))) + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout); + /* Else if virtual format is too long for printf, + print in hex a byte at a time. */ + else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long)) + { + register int j; + printf ("0x"); + for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++) + printf ("%02x", virtual_buffer[j]); + } + /* Else print as integer in hex and in decimal. */ + else + { + long val; + + bcopy (virtual_buffer, &val, sizeof (long)); + if (val == 0) + printf ("0"); + else + printf ("0x%08x %d", val, val); + } + + /* If register has different raw and virtual formats, + print the raw format in hex now. */ + + if (REGISTER_CONVERTIBLE (i)) + { + register int j; + + printf (" (raw 0x"); + for (j = 0; j < REGISTER_RAW_SIZE (i); j++) + printf ("%02x", raw_buffer[j]); + printf (")"); + } + printf ("\n"); + } + + printf ("Contents are relative to selected stack frame.\n"); +} + +#ifdef ATTACH_DETACH +/* + * TODO: + * Should save/restore the tty state since it might be that the + * program to be debugged was started on this tty and it wants + * the tty in some state other than what we want. If it's running + * on another terminal or without a terminal, then saving and + * restoring the tty state is a harmless no-op. + */ + +/* + * attach_command -- + * takes a program started up outside of gdb and ``attaches'' to it. + * This stops it cold in it's tracks and allows us to start tracing + * it. For this to work, we must be able to send the process a + * signal and we must have the same effective uid as the program. + */ +static void +attach_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + dont_repeat(); + + if (!args) + error_no_arg ("process-id to attach"); + else + pid = atoi (args); + + if (inferior_pid) + { + if (query ("A program is being debugged already. Kill it? ")) + kill_inferior (); + else + error ("Inferior not killed."); + } + + exec_file = (char *) get_exec_file (); + + if (from_tty) + { + printf ("Attaching program: %s pid %d\n", + exec_file, pid); + fflush (stdout); + } + + attach_program (pid); +} + +/* + * detach_command -- + * takes a program previously attached to and detaches it. + * The program resumes execution and will no longer stop + * on signals, etc. We better not have left any breakpoints + * in the program or it'll die when it hits one. For this + * to work, it may be necessary for the process to have been + * previously attached. It *might* work if the program was + * started via the normal ptrace (PTRACE_TRACEME). + */ + +static void +detach_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file = (char *)get_exec_file (); + int signal = 0; + + if (!inferior_pid) + error ("Not currently tracing a program\n"); + if (from_tty) + { + printf ("Detaching program: %s pid %d\n", + exec_file, inferior_pid); + fflush (stdout); + } + if (args) + signal = atoi (args); + + detach (signal); + inferior_pid = 0; +} +#endif /* ATTACH_DETACH */ + +static +initialize () +{ + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_com ("set-args", class_run, set_args_command, + "Specify arguments to give program being debugged when it is started.\n\ +Follow this command with any number of args, to be passed to the program."); + + add_info ("environment", environment_info, + "The environment to give the program, or one variable's value.\n\ +With an argument VAR, prints the value of environment variable VAR to\n\ +give the program being debugged. With no arguments, prints the entire\n\ +environment to be given to the program."); + + add_com ("unset-environment", class_run, unset_environment_command, + "Cancel environment variable VAR for the program.\n\ +This does not affect the program until the next \"run\" command."); + add_com ("set-environment", class_run, set_environment_command, + "Set environment variable value to give the program.\n\ +Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\ +VALUES of environment variables are uninterpreted strings.\n\ +This does not affect the program until the next \"run\" command."); + +#ifdef ATTACH_DETACH + add_com ("attach", class_run, attach_command, + "Attach to a process that was started up outside of GDB.\n\ +To do this, you must have permission to send the process a signal.\n\ +And it must have the same effective uid as the debugger.\n\n\ +Before using \"attach\", you must use the \"exec-file\" command\n\ +to specify the program running in the process,\n\ +and the \"symbol-file\" command to load its symbol table."); + add_com ("detach", class_run, detach_command, + "Detach the process previously attached.\n\ +The process is no longer traced and continues its execution."); +#endif /* ATTACH_DETACH */ + + add_com ("signal", class_run, signal_command, + "Continue program giving it signal number SIGNUMBER."); + + add_com ("stepi", class_run, stepi_command, + "Step one instruction exactly.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("si", "stepi", class_alias, 0); + + add_com ("nexti", class_run, nexti_command, + "Step one instruction, but proceed through subroutine calls.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("ni", "nexti", class_alias, 0); + + add_com ("finish", class_run, finish_command, + "Execute until selected stack frame returns.\n\ +Upon return, the value returned is printed and put in the value history."); + + add_com ("next", class_run, next_command, + "Step program, proceeding through subroutine calls.\n\ +Like the \"step\" command as long as subroutine calls do not happen;\n\ +when they do, the call is treated as one instruction.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("n", "next", class_run, 1); + + add_com ("step", class_run, step_command, + "Step program until it reaches a different source line.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("s", "step", class_run, 1); + + add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ +Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ +for an address to start at."); + + add_com ("cont", class_run, cont_command, + "Continue program being debugged, after signal or breakpoint.\n\ +If proceeding from breakpoint, a number N may be used as an argument:\n\ +then the same breakpoint won't break until the Nth time it is reached."); + add_com_alias ("c", "cont", class_run, 1); + + add_com ("run", class_run, run_command, + "Start debugged program. You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ +Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\ +With no arguments, uses arguments last specified (with \"run\" or \"set-args\".\n\ +To cancel previous arguments and run with no arguments,\n\ +use \"set-args\" without arguments."); + add_com_alias ("r", "run", class_run, 1); + + add_info ("registers", registers_info, + "List of registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("program", program_info, + "Execution status of the program."); + + inferior_args = savestring (" ", 1); /* By default, no args. */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d34 39 +d74 1 +@ diff --git a/gdb/RCS/inflow.c,v b/gdb/RCS/inflow.c,v new file mode 100644 index 00000000000..83f44d94dad --- /dev/null +++ b/gdb/RCS/inflow.c,v @@ -0,0 +1,731 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.07.38; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.05.04.57; author gnu; state Exp; +branches ; +next ; + + +desc +@From RMS's development sources on wheaties, 20Jan88 +@ + + +1.2 +log +@Major Sys V tty changes, and a few changes to try to find the registers +in the upage (untested yet). +@ +text +@/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef mac_aux +#include +#include +#include +#include +#include +#else +#include +#endif /* mac_aux */ + + +#ifdef UMAX_PTRACE +#include +#endif + +#ifdef NEW_SUN_PTRACE +#include +#include +#endif + +#ifdef SYSV_TTYS +#include +#endif + +extern int errno; + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +static int attach_flag; + +#define UPAGE_MASK 0x00003FFF + +START_FILE + +/* Record terminal status separately for debugger and inferior. */ + +#ifdef SYSV_TTYS +static struct termio ti_inferior; +#else +static struct sgttyb sg_inferior; +static struct tchars tc_inferior; +static struct ltchars ltc_inferior; +static int lmode_inferior; +#endif +static int tflags_inferior; +static int pgrp_inferior; + +#ifdef SYSV_TTYS +static struct termio ti_ours; +#else +static struct sgttyb sg_ours; +static struct tchars tc_ours; +static struct ltchars ltc_ours; +static int lmode_ours; +#endif +static int tflags_ours; +static int pgrp_ours; + +/* Copy of inferior_io_terminal when inferior was last started. */ +static char *inferior_thisrun_terminal; + +static void terminal_ours_1 (); + +/* Nonzero if our terminal settings are in effect. + Zero if the inferior's settings are in effect. */ +static int terminal_is_ours; + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +void +terminal_init_inferior () +{ + +#ifdef SYSV_TTYS + ti_inferior = ti_ours; +#else + sg_inferior = sg_ours; + tc_inferior = tc_ours; + ltc_inferior = ltc_ours; + lmode_inferior = lmode_ours; +#endif + tflags_inferior = tflags_ours; + pgrp_inferior = inferior_pid; + + terminal_is_ours = 1; +} + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +void +terminal_inferior () +{ + if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ + { + fcntl (0, F_SETFL, tflags_inferior); + fcntl (0, F_SETFL, tflags_inferior); +#ifdef SYSV_TTYS + ioctl (0, TCSETA, &ti_inferior); +#else + ioctl (0, TIOCSETN, &sg_inferior); + ioctl (0, TIOCSETC, &tc_inferior); + ioctl (0, TIOCSLTC, <c_inferior); + ioctl (0, TIOCLSET, &lmode_inferior); +#endif + ioctl (0, TIOCSPGRP, &pgrp_inferior); + } + terminal_is_ours = 0; +} + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +void +terminal_ours_for_output () +{ + terminal_ours_1 (1); +} + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +void +terminal_ours () +{ + terminal_ours_1 (0); +} + +static void +terminal_ours_1 (output_only) + int output_only; +{ + /* Ignore this signal since it will happen when we try to set the pgrp. */ + int (*osigttou) (); + + if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ + { + terminal_is_ours = 1; + + osigttou = signal (SIGTTOU, SIG_IGN); + + ioctl (0, TIOCGPGRP, &pgrp_inferior); + ioctl (0, TIOCSPGRP, &pgrp_ours); + + signal (SIGTTOU, osigttou); + + tflags_inferior = fcntl (0, F_GETFL, 0); +#ifdef SYSV_TTYS + ioctl (0, TCGETA, &ti_inferior); +#else + ioctl (0, TIOCGETP, &sg_inferior); + ioctl (0, TIOCGETC, &tc_inferior); + ioctl (0, TIOCGLTC, <c_inferior); + ioctl (0, TIOCLGET, &lmode_inferior); +#endif + } + + fcntl (0, F_SETFL, tflags_ours); + fcntl (0, F_SETFL, tflags_ours); + + +#ifdef SYSV_TTYS + ti_ours.c_lflag |= ICANON | ISIG; + if (output_only) + ti_ours.c_lflag &= ~((ICANON|ISIG)&ti_inferior.c_lflag); + ioctl (0, TCSETA, &ti_ours); + ti_ours.c_lflag |= ICANON | ISIG; +#else + sg_ours.sg_flags &= ~RAW & ~CBREAK; + if (output_only) + sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags; + ioctl (0, TIOCSETN, &sg_ours); + ioctl (0, TIOCSETC, &tc_ours); + ioctl (0, TIOCSLTC, <c_ours); + ioctl (0, TIOCLSET, &lmode_ours); + sg_ours.sg_flags &= ~RAW & ~CBREAK; +#endif +} + +static void +term_status_command () +{ + register int i; + printf ("Inferior's terminal status (currently saved by GDB):\n"); +#ifdef SYSV_TTYS + printf ("fcntl flags = 0x%x, owner pid = %d.\n", + tflags_inferior, pgrp_inferior); + printf ("iflag = 0x%04x, oflag = 0x%04x, cflag = 0x%04x, lflag = 0x%04x\n", + ti_inferior.c_iflag, ti_inferior.c_oflag, + ti_inferior.c_cflag, ti_inferior.c_lflag); + printf ("line discipline = %d\n", ti_inferior.c_line); + printf ("control chars: "); + for (i = 0; i < NCC; i++) + printf ("0x%x ", ti_inferior.c_cc[i]); + printf ("\n"); +#else + printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n", + tflags_inferior, lmode_inferior, + sg_inferior.sg_flags, pgrp_inferior); + printf ("tchars: "); + for (i = 0; i < sizeof (struct tchars); i++) + printf ("0x%x ", ((char *)&tc_inferior)[i]); + printf ("\n"); + printf ("ltchars: "); + for (i = 0; i < sizeof (struct ltchars); i++) + printf ("0x%x ", ((char *)<c_inferior)[i]); + printf ("\n"); +#endif +} + +static void +new_tty (ttyname) + char *ttyname; +{ + register int tty; + register int fd; + +#if 0 + /* I think it is better not to do this. Then C-z on the GDB terminal + will still stop the program, while C-z on the data terminal + will be input. */ + + /* Disconnect the child process from our controlling terminal. */ + tty = open("/dev/tty", O_RDWR); + if (tty > 0) + { + ioctl(tty, TIOCNOTTY, 0); + close(tty); + } +#endif + /* Now open the specified new terminal. */ + + tty = open(ttyname, O_RDWR); + if (tty == -1) + _exit(1); + + dup2(tty, 0); + dup2(tty, 1); + dup2(tty, 2); + close(tty); +} + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (allargs, env) + char **allargs; + char **env; +{ + int pid; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + + pid = vfork (); + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); + + inferior_thisrun_terminal = inferior_io_terminal; + if (inferior_io_terminal != 0) + new_tty (inferior_io_terminal); + +/* Not needed on Sun, at least, and loses there + because it clobbers the superior. */ +/*??? signal (SIGQUIT, SIG_DFL); + signal (SIGINT, SIG_DFL); */ + + ptrace (0); + execle ("/bin/sh", "sh", "-c", allargs, 0, env); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +static void +kill_command () +{ + if (inferior_pid == 0) + error ("The program is not being run."); + if (!query ("Kill the inferior process? ")) + error ("Not confirmed."); + kill_inferior (); +} + +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + inferior_died (); +} + +inferior_died () +{ + inferior_pid = 0; + attach_flag = 0; + mark_breakpoints_out (); + reopen_exec_file (); + if (have_core_file_p ()) + set_current_frame (read_register (FP_REGNUM)); +} + +/* 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; + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef NEW_SUN_PTRACE + +/* Start debugging the process whose number is PID. */ + +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_ATTACH, pid, 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif + +#ifdef NEW_SUN_PTRACE + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + bcopy (&inferior_registers, registers, 16 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +} + +/* 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; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bcopy (registers, &inferior_registers, 16 * 4); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); +} + +#else + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + +#ifdef UMAX_PTRACE + unsigned int offset = 0; +#else + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) & UPAGE_MASK; +#endif + + for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + +#ifdef UMAX_PTRACE + unsigned int offset = 0; +#else + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) & UPAGE_MASK; +#endif + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } +} + +#endif /* not NEW_SUN_PTRACE */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +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)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + buffer[i] = ptrace (1, inferior_pid, addr, 0); + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); +} + +/* Copy LEN bytes of data from debugger memnory 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. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + if (count > 1) + 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; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +static void +try_writing_regs_command () +{ + register int i; + register int value; + extern int errno; + + if (inferior_pid == 0) + error ("The program is not being run."); + + for (i = 0; ; i += 2) + { + QUIT; + errno = 0; + value = ptrace (3, inferior_pid, i, 0); + ptrace (6, inferior_pid, i, value); + if (errno == 0) + { + printf (" Succeeded with address 0x%x; value 0x%x (%d).\n", + i, value, value); + } + else if ((i & 0377) == 0) + printf (" Failed at 0x%x.\n", i); + } +} + +static +initialize () +{ + add_com ("term-status", class_obscure, term_status_command, + "Print info on inferior's saved terminal status."); + + add_com ("try-writing-regs", class_obscure, try_writing_regs_command, + "Try writing all locations in inferior's system block.\n\ +Report which ones can be written."); + + add_com ("kill", class_run, kill_command, + "Kill execution of program being debugged."); + + inferior_pid = 0; + +#ifdef SYSV_TTYS + ioctl (0, TCGETA, &ti_ours); +#else + ioctl (0, TIOCGETP, &sg_ours); + ioctl (0, TIOCGETC, &tc_ours); + ioctl (0, TIOCGLTC, <c_ours); + ioctl (0, TIOCLGET, &lmode_ours); +#endif + fcntl (0, F_GETFL, tflags_ours); + ioctl (0, TIOCGPGRP, &pgrp_ours); + + terminal_is_ours = 1; +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d28 1 +a30 1 +#include +d36 11 +d56 4 +d67 2 +d73 3 +d80 1 +d84 3 +d91 1 +d110 4 +d118 1 +d135 3 +d142 1 +d191 3 +d198 1 +d201 11 +a214 3 + + fcntl (0, F_SETFL, tflags_ours); + fcntl (0, F_SETFL, tflags_ours); +d220 1 +d228 12 +d251 1 +d470 1 +a470 1 + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; +d500 1 +a500 1 + offset = ptrace (3, inferior_pid, offset, 0) - KERNEL_U_ADDR; +d647 3 +d654 1 +@ diff --git a/gdb/RCS/m-mac-aux.h,v b/gdb/RCS/m-mac-aux.h,v new file mode 100644 index 00000000000..eaac3dd5bcc --- /dev/null +++ b/gdb/RCS/m-mac-aux.h,v @@ -0,0 +1,523 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.16.06; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.05.15.44; author gnu; state Exp; +branches ; +next ; + + +desc +@Originally nonexistent, I create it. +@ + + +1.2 +log +@Original new config file for Mac-II running A/UX. +@ +text +@/* Parameters for execution on Macintosh under A/UX, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef mac_aux +#define mac_aux +#endif + +/* Get rid of any system-imposed stack limit if possible. */ + +#undef 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 + +/* COFF format object files */ + +#define COFF_FORMAT + +/* System eVil ttys */ + +#define SYSV_TTYS + +/* Debugger information will not be in DBX format. */ + +#undef READ_DBX_FORMAT + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x20000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 31 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags" } + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* 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, 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 (0, 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)) + +/* Enable use of alternate code to read and write registers. */ + +#undef NEW_SUN_PTRACE + +/* Enable use of alternate code for Sun's format of core dump file. */ + +#undef NEW_SUN_CORE + +/* Do implement the attach and detach commands. */ + +#undef ATTACH_DETACH + +/* It is safe to look for symsegs on a Sun, because Sun's ld + does not screw up with random garbage at end of file. */ + +#define READ_GDB_SYMSEGS + +/* 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 Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) (fi.frame) + +#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + int nextinsn; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + /* But before that can come an fmovem. Check for it. */ \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf227 == nextinsn \ + && (regmask & 0xff00) == 0xe000) \ + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 12); \ + regmask = read_memory_integer (pc + 2, 2); } \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* fmovemx to index of sp may follow. */ \ + regmask = read_memory_integer (pc + 2, 2); \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf236 == nextinsn \ + && (regmask & 0xff00) == 0xf000) \ + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \ + regmask = read_memory_integer (pc + 2, 2); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + set_current_frame (read_register (FP_REGNUM)); } + +/* This sequence of words is the instructions + fmovem 0xff,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @@#32323232 + addl #69696969,sp + bpt + nop +Note this is 28 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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 ("movel #end, sp"); \ + asm ("movel #0,a6"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel a6,sp@@-"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl sp@@,a6"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea sp@@(10)"); \ + asm ("movem #0xfffe,sp@@-"); } + +/* 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 \ +{ asm ("subil #8,sp@@(28)"); \ + asm ("movem sp@@,#0xffff"); \ + asm ("rte"); } +@ + + +1.1 +log +@Initial revision +@ +text +@d1 485 +@ diff --git a/gdb/RCS/m-mac-auxinit.h,v b/gdb/RCS/m-mac-auxinit.h,v new file mode 100644 index 00000000000..796bc8d3549 --- /dev/null +++ b/gdb/RCS/m-mac-auxinit.h,v @@ -0,0 +1,43 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.19.09; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.05.18.45; author gnu; state Exp; +branches ; +next ; + + +desc +@Originally nonexistent. +@ + + +1.2 +log +@Created by John Gilmore for Mac A/UX +@ +text +@ +/* This is how the size of an individual .o file's text segment + is rounded on a mac under a/ux. */ + +#define FILEADDR_ROUND(addr) (addr) +@ + + +1.1 +log +@Initial revision +@ +text +@d1 5 +@ diff --git a/gdb/RCS/m68k-pinsn.c,v b/gdb/RCS/m68k-pinsn.c,v new file mode 100644 index 00000000000..dedc0e7fc3f --- /dev/null +++ b/gdb/RCS/m68k-pinsn.c,v @@ -0,0 +1,828 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.08.29; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.22.04.55; author gnu; state Exp; +branches ; +next ; + + +desc +@From RMS's development sources on wheaties, 20Jan88 +@ + + +1.2 +log +@Avoid the so-called "portable" preassembled instructions; call a macro +to generate them, since a/ux assembler uses a different syntax (grumble) +@ +text +@/* Print m68k instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "m68k-opcode.h" + +/* 68k instructions are never longer than this many bytes. */ +#define MAXLEN 22 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) + +extern char *reg_names[]; +char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", + "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"}; + +static unsigned char *print_insn_arg (); +static unsigned char *print_indexed (); +static void print_base (); +static int fetch_arg (); + +#define NEXTBYTE(p) (p += 2, ((char *)p)[-1]) + +#define NEXTWORD(p) \ + (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + +#define NEXTSINGLE(p) \ + (p += 4, *((float *)(p - 4))) + +#define NEXTDOUBLE(p) \ + (p += 8, *((double *)(p - 8))) + +#define NEXTEXTEND(p) \ + (p += 12, 0.0) /* Need a function to convert from extended to double + precision... */ + +#define NEXTPACKED(p) \ + (p += 12, 0.0) /* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register unsigned char *p; + register char *d; + register int bestmask; + int best; + + read_memory (memaddr, buffer, MAXLEN); + + bestmask = 0; + best = -1; + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = m68k_opcodes[i].opcode; + register unsigned int match = m68k_opcodes[i].match; + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == 0) + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 't') + break; + + if (*d == 0 && match > bestmask) + { + best = i; + bestmask = match; + } + } + } + + /* Handle undefined instructions. */ + if (best < 0) + { + fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; + } + + fprintf (stream, "%s", m68k_opcodes[best].name); + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Why do this this way? -MelloN */ + for (d = m68k_opcodes[best].args; *d; d += 2) + { + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) + p = buffer + 4; + } + if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) + p = buffer + 4; + if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) + p = buffer + 6; + } + + d = m68k_opcodes[best].args; + + if (*d) + fputc (' ', stream); + + while (*d) + { + p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream); + d += 2; + if (*d && *(d - 2) != 'I' && *d != 'k') + fprintf (stream, ","); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, buffer, p, addr, stream) + char *d; + unsigned char *buffer; + register unsigned char *p; + CORE_ADDR addr; /* PC for this arg to be relative to */ + FILE *stream; +{ + register int val; + register int place = d[1]; + int regno; + register char *regname; + register unsigned char *p1; + register double flval; + int flt_p; + + switch (*d) + { + case 'C': + fprintf (stream, "ccr"); + break; + + case 'S': + fprintf (stream, "sr"); + break; + + case 'U': + fprintf (stream, "usp"); + break; + + case 'J': + { + static struct { char *name; int value; } names[] + = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, + {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, + {"msp", 0x803}, {"isp", 0x804}}; + + val = fetch_arg (buffer, place, 12); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + fprintf (stream, names[regno].name); + break; + } + if (regno < 0) + fprintf (stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3); + if (val == 0) val = 8; + fprintf (stream, "#%d", val); + break; + + case 'M': + val = fetch_arg (buffer, place, 8); + if (val & 0x80) + val = val - 0x100; + fprintf (stream, "#%d", val); + break; + + case 'T': + val = fetch_arg (buffer, place, 4); + fprintf (stream, "#%d", val); + break; + + case 'D': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 'A': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]); + break; + + case 'R': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'F': + fprintf (stream, "fp%d", fetch_arg (buffer, place, 3)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6); + if (val & 0x20) + fprintf (stream, "%s", reg_names [val & 7]); + else + fprintf (stream, "%d", val); + break; + + case '+': + fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case '-': + fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case 'k': + if (place == 'k') + fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7); + if ( val > 63 ) /* This is a signed constant. */ + val -= 128; + fprintf (stream, "{#%d}", val); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + break; + + case '#': + p1 = buffer + 2; + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == '3') + val = fetch_arg (buffer, place, 8); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case '^': + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else if (place == 'g') + { + val = ((char *)buffer)[1]; + if (val == 0) + val = NEXTWORD (p); + else if (val == -1) + val = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset */ + val = NEXTLONG (p); + else + val = NEXTWORD (p); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + + print_address (addr + val, stream); + break; + + case 'd': + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, fetch_arg (buffer, place, 3)); + break; + + case 's': + fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]); + break; + + case 'I': + val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ + if (val != 1) /* Unusual coprocessor ID? */ + fprintf (stream, "(cpid=%d) ", val); + if (place == 'i') + p += 2; /* Skip coprocessor extended operands */ + break; + + case '*': + case '~': + case '%': + case ';': + case '@@': + case '!': + case '$': + case '?': + case '/': + case '&': + + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6); + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + fprintf (stream, "%s", reg_names[val]); + break; + + case 1: + fprintf (stream, "%s", regname); + break; + + case 2: + fprintf (stream, "(%s)", regname); + break; + + case 3: + fprintf (stream, "(%s)+", regname); + break; + + case 4: + fprintf (stream, "-(%s)", regname); + break; + + case 5: + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, regname); + break; + + case 6: + p = print_indexed (regno, p, addr, stream); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + fprintf (stream, "@@#"); + print_address (val, stream); + break; + + case 1: + val = NEXTLONG (p); + fprintf (stream, "@@#"); + print_address (val, stream); + break; + + case 2: + val = NEXTWORD (p); + print_address (addr + val, stream); + break; + + case 3: + p = print_indexed (-1, p, addr, stream); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch( place ) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + flval = NEXTSINGLE(p); + break; + + case 'F': + flval = NEXTDOUBLE(p); + break; + + case 'x': + flval = NEXTEXTEND(p); + break; + + case 'p': + flval = NEXTPACKED(p); + break; + + default: + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + } + if ( flt_p ) /* Print a float? */ + fprintf (stream, "#%g", flval); + else + fprintf (stream, "#%d", val); + break; + + default: + fprintf (stream, "", val); + } + } + break; + + default: + error ("Invalid arg format in opcode table: \"%c\".", *d); + } + + return (unsigned char *) p; +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (buffer, code, bits) + unsigned char *buffer; + char code; + int bits; +{ + register int val; + switch (code) + { + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + val = (buffer[3] >> 4); + break; + + case 'C': + val = buffer[3]; + break; + + case '1': + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + default: + abort (); + } + + switch (bits) + { + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (basereg, p, addr, stream) + int basereg; + unsigned char *p; + FILE *stream; + CORE_ADDR addr; +{ + register int word; + static char *scales[] = {"", "*2", "*4", "*8"}; + register int base_disp; + register int outer_disp; + char buf[40]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "[%s.%c%s]", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + print_base (basereg, + ((word & 0x80) ? word | 0xff00 : word & 0xff) + + ((basereg == -1) ? addr : 0), + stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + + if (word & 0200) + basereg = -2; + if (word & 0100) + buf[0] = 0; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect) */ + + if ((word & 7) == 0) + { + print_base (basereg, base_disp, stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + fprintf (stream, "%d(", outer_disp); + print_base (basereg, base_disp, stream); + + /* If postindexed, print the closeparen before the index. */ + if (word & 4) + fprintf (stream, ")%s", buf); + /* If preindexed, print the closeparen after the index. */ + else + fprintf (stream, "%s)", buf); + + return p; +} + +/* Print a base register REGNO and displacement DISP, on STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (regno, disp, stream) + int regno; + int disp; + FILE *stream; +{ + if (regno == -2) + fprintf (stream, "%d", disp); + else if (regno == -1) + fprintf (stream, "0x%x", disp); + else + fprintf (stream, "%d(%s)", disp, reg_names[regno]); +} + +/* This is not part of insn printing, but it is machine-specific, + so this is a convenient place to put it. + + Convert a 68881 extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +#ifdef mac_aux +#ifdef __STDC__ +#define asm16(str) asm ("short " str#) +#else +#define asm16(str) asm ("short str") +#endif +#else +#ifdef __STDC__ +#define asm16(str) asm (".word " str#) +#else +#define asm16(str) asm (".word str") +#endif +#endif + +convert_from_68881 (from, to) + char *from; + double *to; +{ +#if 0 + asm ("movl a6@@(8),a0"); + asm ("movl a6@@(12),a1"); + asm ("fmovex a0@@,fp0"); + asm ("fmoved fp0,a1@@"); +#else + /* Hand-assemble those insns since some assemblers lose + and some have different syntax. */ + asm16 (020156); + asm16 (8); + asm16 (021156); + asm16 (12); + asm16 (0xf210); + asm16 (0x4800); + asm16 (0xf211); + asm16 (0x7400); +#endif +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +convert_to_68881 (from, to) + double *from; + char *to; +{ +#if 0 + asm ("movl a6@@(8),a0"); + asm ("movl a6@@(12),a1"); + asm ("fmoved a0@@,fp0"); + asm ("fmovex fp0,a1@@"); +#else + /* Hand-assemble those insns since some assemblers lose. */ + asm16 (020156); + asm16 (8); + asm16 (021156); + asm16 (12); + asm16 (0xf210); + asm16 (0x5400); + asm16 (0xf211); + asm16 (0x6800); +#endif +} +@ + + +1.1 +log +@Initial revision +@ +text +@d713 14 +d739 8 +a746 6 + asm (".word 020156"); + asm (".word 8"); + asm (".word 021156"); + asm (".word 12"); + asm (".long 0xf2104800"); + asm (".long 0xf2117400"); +d764 8 +a771 6 + asm (".word 020156"); + asm (".word 8"); + asm (".word 021156"); + asm (".word 12"); + asm (".long 0xf2105400"); + asm (".long 0xf2116800"); +@ diff --git a/gdb/RCS/main.c,v b/gdb/RCS/main.c,v new file mode 100644 index 00000000000..ae6615f7318 --- /dev/null +++ b/gdb/RCS/main.c,v @@ -0,0 +1,1110 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.09.12; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.04.23.16; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS development on wheaties, 20Jan88 +@ + + +1.2 +log +@Add +@ +text +@/* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "command.h" +#include "param.h" + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include +#endif + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* Chain containing all defined commands. */ + +struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +struct cmd_list_element *infolist; + +/* stdio stream that command input is being read from. */ + +FILE *instream; + +/* Nonzero if we should refrain from using an X window. */ + +int inhibit_windows = 0; + +/* Function to call before reading a command, if nonzero. + The function receives two args: an input stream, + and a prompt string. */ + +void (*window_hook) (); + +void free_command_lines (); +char *read_line (); +static void initialize_main (); +void command_loop (); +static void source_command (); +void print_gdb_version (); + +/* gdb prints this when reading a command interactively */ +static char *prompt; + +/* Buffer used for reading command lines, and the size + allocated for it so far. */ + +char *line; +int linesize; + +/* This is how `error' returns to command level. */ + +jmp_buf to_top_level; + +return_to_top_level () +{ + quit_flag = 0; + immediate_quit = 0; + clear_breakpoint_commands (); + clear_momentary_breakpoints (); + do_cleanups (0); + longjmp (to_top_level, 1); +} + +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + extern void request_quit (); + int count; + int inhibit_gdbinit = 0; + int quiet = 0; + int batch = 0; + register int i; + + quit_flag = 0; + linesize = 100; + line = (char *) xmalloc (linesize); + instream = stdin; + +#ifdef SET_STACK_LIMIT_HUGE + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca (particularly stringtab + * in dbxread.c) does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* SET_STACK_LIMIT_HUGE */ + + /* Look for flag arguments. */ + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet")) + quiet = 1; + else if (!strcmp (argv[i], "-nx")) + inhibit_gdbinit = 1; + else if (!strcmp (argv[i], "-nw")) + inhibit_windows = 1; + else if (!strcmp (argv[i], "-batch")) + batch = 1, quiet = 1; + else if (argv[i][0] == '-') + i++; + } + + /* Run the init function of each source file */ + + initialize_all_files (); + initialize_main (); /* But that omits this file! Do it now */ + + signal (SIGINT, request_quit); + signal (SIGQUIT, SIG_IGN); + + if (!quiet) + print_gdb_version (); + + /* Process the command line arguments. */ + + count = 0; + for (i = 1; i < argc; i++) + { + register char *arg = argv[i]; + /* Args starting with - say what to do with the following arg + as a filename. */ + if (arg[0] == '-') + { + extern void exec_file_command (), symbol_file_command (); + extern void core_file_command (), directory_command (); + extern void tty_command (); + + if (!strcmp (arg, "-q") || !strcmp (arg, "-nx") + || !strcmp (arg, "quiet") || !strcmp (arg, "-batch")) + /* Already processed above */ + continue; + + if (++i == argc) + fprintf (stderr, "No argument follows \"%s\".\n", arg); + if (!setjmp (to_top_level)) + { + /* -s foo: get syms from foo. -e foo: execute foo. + -se foo: do both with foo. -c foo: use foo as core dump. */ + if (!strcmp (arg, "-se")) + { + exec_file_command (argv[i], !batch); + symbol_file_command (argv[i], !batch); + } + else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols")) + symbol_file_command (argv[i], !batch); + else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec")) + exec_file_command (argv[i], !batch); + else if (!strcmp (arg, "-c") || !strcmp (arg, "-core")) + core_file_command (argv[i], !batch); + /* -x foo: execute commands from foo. */ + else if (!strcmp (arg, "-x") || !strcmp (arg, "-command") + || !strcmp (arg, "-commands")) + source_command (argv[i]); + /* -d foo: add directory `foo' to source-file directory + search-list */ + else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir") + || !strcmp (arg, "-directory")) + directory_command (argv[i], 0); + /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */ + else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty")) + tty_command (argv[i], 0); + else + error ("Unknown command-line switch: \"%s\"\n", arg); + } + } + else + { + /* Args not thus accounted for + are treated as, first, the symbol/executable file + and, second, the core dump file. */ + count++; + if (!setjmp (to_top_level)) + switch (count) + { + case 1: + exec_file_command (arg, !batch); + symbol_file_command (arg, !batch); + break; + + case 2: + core_file_command (arg, !batch); + break; + + case 3: + fprintf (stderr, "Excess command line args ignored. (%s%s)\n", + arg, (i == argc - 1) ? "" : " ..."); + } + } + } + + /* Read init file, if it exists in home directory */ + if (getenv ("HOME")) + { + char *s; + s = (char *) xmalloc (strlen (getenv ("HOME")) + 10); + strcpy (s, getenv ("HOME")); + strcat (s, "/.gdbinit"); + if (!inhibit_gdbinit && access (s, R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (s); + } + + /* Read init file, if it exists in current directory. */ + if (!inhibit_gdbinit && access (".gdbinit", R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (".gdbinit"); + + if (batch) + fatal ("Attempt to read commands from stdin in batch mode."); + + if (!quiet) + printf ("Type \"help\" for a list of commands.\n"); + + /* The command loop. */ + + while (1) + { + if (!setjmp (to_top_level)) + command_loop (); + clearerr (stdin); /* Don't get hung if C-d is typed. */ + } +} + +/* Execute the line P as a command. + Pass FROM_TTY as second argument to the defining function. */ + +void +execute_command (p, from_tty) + char *p; + int from_tty; +{ + register struct cmd_list_element *c; + register struct command_line *cmdlines; + + free_all_values (); + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + c = lookup_cmd (&p, cmdlist, "", 0); + if (c->function == 0) + error ("That is not a command, just a help topic."); + else if (c->class == (int) class_user) + { + if (*p) + error ("User-defined commands cannot take command-line arguments: \"%s\"", + p); + cmdlines = (struct command_line *) c->function; + if (cmdlines == (struct command_line *) 0) + /* Null command */ + return; + while (cmdlines) + { + execute_command (cmdlines->line, 0); + cmdlines = cmdlines->next; + } + } + else + /* Pass null arg rather than an empty one. */ + (*c->function) (*p ? p : 0, from_tty); + } +} + +static void +do_nothing () +{ +} + +/* Read commands from `instream' and execute them + until end of file. */ +void +command_loop () +{ + struct cleanup *old_chain; + while (!feof (instream)) + { + if (instream == stdin) + printf ("%s", prompt); + fflush (stdout); + + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + old_chain = make_cleanup (do_nothing, 0); + execute_command (read_line (instream == stdin), instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + do_breakpoint_commands (); + do_cleanups (old_chain); + } +} + +static void +stop_sig () +{ + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); + printf ("%s", prompt); + fflush (stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + *line = 0; +} + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + *line = 0; +} + +/* Read one line from the command input stream `instream' + into the buffer `line' (whose current length is `linesize'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. */ + +char * +read_line (repeat) + int repeat; +{ + register char *p = line; + register char *p1; + register int c; + char *nline; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; + signal (SIGTSTP, stop_sig); + + while (1) + { + c = fgetc (instream); + if (c == -1 || c == '\n') + break; + if (p - line == linesize - 1) + { + linesize *= 2; + nline = (char *) xrealloc (line, linesize); + p += nline - line; + line = nline; + } + *p++ = c; + } + + signal (SIGTSTP, SIG_DFL); + immediate_quit--; + + /* If we just got an empty line, and that is supposed + to repeat the previous command, leave the last input unchanged. */ + if (p == line && repeat) + return line; + + /* If line is a comment, clear it out. */ + p1 = line; + while ((c = *p1) == ' ' || c == '\t') p1++; + if (c == '#') + p = line; + + *p = 0; + + return line; +} + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *first = 0; + register struct command_line *next, *tail = 0; + register char *p, *p1; + struct cleanup *old_chain = 0; + + while (1) + { + dont_repeat (); + p = read_line (1); + /* Remove leading and trailing blanks. */ + while (*p == ' ' || *p == '\t') p++; + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--; + + /* Is this "end"? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + break; + + /* No => add this line to the chain of command lines. */ + next = (struct command_line *) xmalloc (sizeof (struct command_line)); + next->line = savestring (p, p1 - p); + next->next = 0; + if (tail) + { + tail->next = next; + } + else + { + /* We just read the first line. + From now on, arrange to throw away the lines we have + if we quit or get an error while inside this function. */ + first = next; + old_chain = make_cleanup (free_command_lines, &first); + } + tail = next; + } + + dont_repeat (); + + /* Now we are about to return the chain to our caller, + so freeing it becomes his responsibility. */ + if (first) + discard_cleanups (old_chain); + return first; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + + while (l) + { + next = l->next; + free (l->line); + free (l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) (); + char *doc; +{ + add_cmd (name, 0, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +static void +info_command () +{ + printf ("\"info\" must be followed by the name of an info command.\n"); + help_cmd (0, infolist, "info ", -1, stdout); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + int class; + void (*fun) (); + char *doc; +{ + add_cmd (name, class, fun, doc, &cmdlist); +} + +/* Add an alias or abbreviation command to the list of commands. */ + +void +add_com_alias (name, oldname, class, abbrev_flag) + char *name; + char *oldname; + int class; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); +} + +void +error_no_arg (why) + char *why; +{ + error ("Argument required (%s).", why); +} + +static void +help_command (command, from_tty) + char *command; + int from_tty; /* Ignored */ +{ + help_cmd (command, cmdlist, "", -2, stdout); +} + +static void +validate_comname (comname) + char *comname; +{ + register char *p; + + if (comname == 0) + error_no_arg ("name of command to define"); + + p = comname; + while (*p) + { + if (!(*p >= 'A' && *p <= 'Z') + && !(*p >= 'a' && *p <= 'z') + && !(*p >= '1' && *p <= '9') + && *p != '-') + error ("Junk in argument list: \"%s\"", p); + p++; + } +} + +static void +define_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct command_line *cmds; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", -1); + if (c) + { + if (c->class == (int) class_user || c->class == (int) class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, comname)) + error ("Command \"%s\" not redefined.", comname); + } + + if (from_tty) + printf ("Type commands for definition of \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + comname = savestring (comname, strlen (comname)); + + cmds = read_command_lines (); + + if (c && c->class == (int) class_user) + free_command_lines (&c->function); + + add_com (comname, class_user, cmds, + (c && c->class == (int) class_user) + ? c->doc : savestring ("User-defined.", 13)); +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0); + + if (c->class != (int) class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +static void +copying_info () +{ + immediate_quit++; + printf (" GDB GENERAL PUBLIC LICENSE\n\ +\n\ + Copyright (C) 1986 Richard M. Stallman\n\ + Everyone is permitted to copy and distribute verbatim copies\n\ + of this license, but changing it is not allowed.\n\ +\n\ + The license agreements of most software companies keep you at the\n\ +mercy of those companies. By contrast, our general public license is\n\ +intended to give everyone the right to share GDB. To make sure that\n\ +you get the rights we want you to have, we need to make restrictions\n\ +that forbid anyone to deny you these rights or to ask you to surrender\n\ +the rights. Hence this license agreement.\n\ +\n\ + Specifically, we want to make sure that you have the right to give\n\ +away copies of GDB, that you receive source code or else can get it\n\ +if you want it, that you can change GDB or use pieces of it in new\n\ +free programs, and that you know you can do these things.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + To make sure that everyone has such rights, we have to forbid you to\n\ +deprive anyone else of these rights. For example, if you distribute\n\ +copies of GDB, you must give the recipients all the rights that you\n\ +have. You must make sure that they, too, receive or can get the\n\ +source code. And you must tell them their rights.\n\ +\n\ + Also, for our own protection, we must make certain that everyone\n\ +finds out that there is no warranty for GDB. If GDB is modified by\n\ +someone else and passed on, we want its recipients to know that what\n\ +they have is not what we distributed, so that any problems introduced\n\ +by others will not reflect on our reputation.\n\ +\n\ + Therefore we (Richard Stallman and the Free Software Foundation,\n\ +Inc.) make the following terms which say what you must do to be\n\ +allowed to distribute or change GDB.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + COPYING POLICIES\n\ +\n\ + 1. You may copy and distribute verbatim copies of GDB source code as\n\ +you receive it, in any medium, provided that you conspicuously and\n\ +appropriately publish on each copy a valid copyright notice \"Copyright\n\ +\(C) 1987 Free Software Foundation, Inc.\" (or with the year updated if\n\ +that is appropriate); keep intact the notices on all files that refer\n\ +to this License Agreement and to the absence of any warranty; and give\n\ +any other recipients of the GDB program a copy of this License\n\ +Agreement along with the program. You may charge a distribution fee\n\ +for the physical act of transferring a copy.\n\ +\n\ + 2. You may modify your copy or copies of GDB or any portion of it,\n\ +and copy and distribute such modifications under the terms of\n\ +Paragraph 1 above, provided that you also do the following:\n\ +\n\ + a) cause the modified files to carry prominent notices stating\n\ + that you changed the files and the date of any change; and\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + b) cause the whole of any work that you distribute or publish,\n\ + that in whole or in part contains or is a derivative of GDB\n\ + or any part thereof, to be licensed to all third parties on terms\n\ + identical to those contained in this License Agreement (except that\n\ + you may choose to grant more extensive warranty protection to third\n\ + parties, at your option).\n\ +\n"); + printf ("\ + c) if the modified program serves as a debugger, cause it\n\ + when started running in the simplest and usual way, to print\n\ + an announcement including a valid copyright notice\n\ + \"Copyright (C) 1987 Free Software Foundation, Inc.\" (or with\n\ + the year updated if appropriate), saying that there\n\ + is no warranty (or else, saying that you provide\n\ + a warranty) and that users may redistribute the program under\n\ + these conditions, and telling the user how to view a copy of\n\ + this License Agreement.\n\ +\n\ + d) You may charge a distribution fee for the physical act of\n\ + transferring a copy, and you may at your option offer warranty\n\ + protection in exchange for a fee.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + 3. You may copy and distribute GDB or any portion of it in\n\ +compiled, executable or object code form under the terms of Paragraphs\n\ +1 and 2 above provided that you do the following:\n\ +\n\ + a) cause each such copy to be accompanied by the\n\ + corresponding machine-readable source code, which must\n\ + be distributed under the terms of Paragraphs 1 and 2 above; or,\n\ +\n\ + b) cause each such copy to be accompanied by a\n\ + written offer, with no time limit, to give any third party\n\ + free (except for a nominal shipping charge) a machine readable\n\ + copy of the corresponding source code, to be distributed\n\ + under the terms of Paragraphs 1 and 2 above; or,\n\n"); + + printf ("\ + c) in the case of a recipient of GDB in compiled, executable\n\ + or object code form (without the corresponding source code) you\n\ + shall cause copies you distribute to be accompanied by a copy\n\ + of the written offer of source code which you received along\n\ + with the copy you received.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + 4. You may not copy, sublicense, distribute or transfer GDB\n\ +except as expressly provided under this License Agreement. Any attempt\n\ +otherwise to copy, sublicense, distribute or transfer GDB is void and\n\ +your rights to use the program under this License agreement shall be\n\ +automatically terminated. However, parties who have received computer\n\ +software programs from you with this License Agreement will not have\n\ +their licenses terminated so long as such parties remain in full compliance.\n\ +\n\ + 5. If you wish to incorporate parts of GDB into other free\n\ +programs whose distribution conditions are different, write to the Free\n\ +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\ +worked out a simple rule that can be stated here, but we will often permit\n\ +this. We will be guided by the two goals of preserving the free status of\n\ +all derivatives of our free software and of promoting the sharing and reuse\n\ +of software.\n\ +\n\ +In other words, go ahead and share GDB, but don't try to stop\n\ +anyone else from sharing it farther. Help stamp out software hoarding!\n\ +"); + immediate_quit--; +} + +static void +warranty_info () +{ + immediate_quit++; + printf (" NO WARRANTY\n\ +\n\ + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO\n\ +WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT\n\ +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,\n\ +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB \"AS IS\" WITHOUT\n\ +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\n\ +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\ +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\n\ +PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU\n\ +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n"); + + printf ("\ + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.\n\ +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY\n\ +WHO MAY MODIFY AND REDISTRIBUTE GDB, BE LIABLE TO\n\ +YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER\n\ +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\n\ +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\n\ +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A\n\ +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN\n\ +IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR\n\ +ANY CLAIM BY ANY OTHER PARTY.\n"); + immediate_quit--; +} + +static void +print_gdb_version () +{ + printf ("GDB %s, Copyright (C) 1987 Free Software Foundation, Inc.\n\ +There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"info copying\" to see the conditions.\n", + version); +} + +static void +version_info () +{ + immediate_quit++; + print_gdb_version (); + immediate_quit--; +} + +static void +set_prompt_command (text) + char *text; +{ + char *p, *q; + register int c; + char *new; + + if (text == 0) + error_no_arg ("string to which to set prompt"); + + new = (char *) xmalloc (strlen (text) + 2); + p = text; q = new; + while (c = *p++) + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + break; + c = parse_escape (&p); + if (c == 0) + break; /* C loses */ + else if (c > 0) + *q++ = c; + } + else + *q++ = c; + } + if (*(p - 1) != '\\') + *q++ = ' '; + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + free (prompt); + prompt = new; +} + +static void +quit_command () +{ + if (have_inferior_p ()) + { + if (query ("The program is running. Quit anyway? ")) + { + /* Prevent any warning message from reopen_exec_file, in case + we have a core file that's inconsistent with the exec file. */ + exec_file_command (0, 0); + kill_inferior (); + } + else + error ("Not confirmed."); + } + exit (0); +} + +int +input_from_terminal_p () +{ + return instream == stdin; +} + +static void +pwd_command (arg, from_tty) + char *arg; + int from_tty; +{ + char buf[MAXPATHLEN]; + if (arg) error ("The \"pwd\" command does not take an argument: %s", arg); + printf ("Working directory %s.\n", getwd (buf)); +} + +static void +cd_command (dir, from_tty) + char *dir; + int from_tty; +{ + if (dir == 0) + error_no_arg ("new working directory"); + + if (chdir (dir) < 0) + perror_with_name (dir); + if (from_tty) + pwd_command ((char *) 0, 1); +} + + +/* Clean up on error during a "source" command. + Close the file opened by the command + and restore the previous input stream. */ + +static void +source_cleanup (stream) + FILE *stream; +{ + fclose (instream); + instream = stream; +} + +static void +source_command (file) + char *file; +{ + FILE *stream; + struct cleanup *cleanups; + + if (file == 0) + error_no_arg ("file to read commands from"); + + stream = fopen (file, "r"); + if (stream == 0) + perror_with_name (file); + + cleanups = make_cleanup (source_cleanup, instream); + + instream = stream; + + command_loop (); + + do_cleanups (cleanups); +} + +static void +echo_command (text) + char *text; +{ + char *p = text; + register int c; + + if (text) + while (c = *p++) + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + return; + + c = parse_escape (&p); + if (c >= 0) + fputc (c, stdout); + } + else + fputc (c, stdout); + } +} + +static void +dump_me_command () +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + + +static void +initialize_main () +{ + prompt = savestring ("(gdb) ", 6); + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist); + add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist); + add_cmd ("user", class_user, 0, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, 0, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, 0, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, 0, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + add_com ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started."); + + add_com ("set-prompt", class_support, set_prompt_command, + "Change gdb's prompt from the default of \"(gdb)\""); + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +use \"\\n\" if you want a newline to be printed.\n\ +Since leading and trailing whitespace are ignored in command arguments,\n\ +if you want to print some you must use \"\\\" before leading whitespace\n\ +to be printed or after trailing whitespace."); + add_com ("document", class_support, document_command, + "Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\"."); + add_com ("define", class_support, define_command, + "Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way do not take arguments."); + + add_com ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started."); + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + add_com ("dump-me", class_obscure, dump_me_command, + "Get fatal error; make debugger dump its core."); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for printing status.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_info ("copying", copying_info, "Conditions for redistributing copies of GDB."); + add_info ("warranty", warranty_info, "Various kinds of warranty you do not have."); + add_info ("version", version_info, "Report what version of GDB this is."); +} +@ + + +1.1 +log +@Initial revision +@ +text +@d21 1 +@ diff --git a/gdb/RCS/source.c,v b/gdb/RCS/source.c,v new file mode 100644 index 00000000000..bd3218b509c --- /dev/null +++ b/gdb/RCS/source.c,v @@ -0,0 +1,705 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.09.34; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.04.30.11; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS development sources on wheaties, 20Jan88 +@ + + +1.2 +log +@Add +@ +text +@/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include +#include +#include +#include "defs.h" +#include "initialize.h" +#include "symtab.h" + +/* Path of directories to search for source files. + Same format as the PATH environment variable's value. */ + +static char *source_path; + +/* Symtab of default file for listing lines of. */ + +struct symtab *current_source_symtab; + +/* Default next line to list. */ + +int current_source_line; + +/* Line for "info line" to work on if no line specified. */ + +static int line_info_default_line; + +/* First line number listed by last listing command. */ + +static int first_line_listed; + +START_FILE + +/* Set the source file default for the "list" command, + specifying a symtab. */ + +void +select_source_symtab (s) + register struct symtab *s; +{ + if (s) + { + struct symtab_and_line sal; + + /* Make the default place to list be the function `main' + if one exists. */ + if (lookup_symbol ("main", 0, VAR_NAMESPACE)) + { + sal = decode_line_spec ("main", 1); + current_source_symtab = sal.symtab; + current_source_line = sal.line - 9; + return; + } + + /* If there is no `main', use the last symtab in the list, + which is actually the first found in the file's symbol table. + But ignore .h files. */ + do + { + char *name = s->filename; + int len = strlen (name); + if (! (len > 2 && !strcmp (&name[len - 2], ".h"))) + current_source_symtab = s; + s = s->next; + } + while (s); + current_source_line = 1; + } +} + +static void +directories_info () +{ + printf ("Source directories searched: %s\n", source_path); +} + +static void +init_source_path () +{ + register struct symtab *s; + char wd[MAXPATHLEN]; + if (getwd (wd) == NULL) + perror_with_name ("getwd"); + + source_path = savestring (wd, strlen (wd)); + + /* Forget what we learned about line positions in source files; + must check again now since files may be found in + a different directory now. */ + for (s = symtab_list; s; s = s->next) + if (s->line_charpos != 0) + { + free (s->line_charpos); + s->line_charpos = 0; + } +} + +void +directory_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + char *old = source_path; + + char wd[MAXPATHLEN]; + if (getwd (wd) == NULL) + perror_with_name ("getwd"); + + if (dirname == 0) + { + if (query ("Reinitialize source path to %s? ", wd)) + { + init_source_path (); + free (old); + } + } + else + { + struct stat st; + register int len = strlen (dirname); + register char *tem; + extern char *index (); + + if (index (dirname, ':')) + error ("Please add one directory at a time to the source path."); + if (dirname[len - 1] == '/') + /* Sigh. "foo/" => "foo" */ + dirname[--len] == '\0'; + + while (dirname[len - 1] == '.') + { + if (len == 1) + { + /* "." => getwd () */ + dirname = wd; + goto append; + } + else if (dirname[len - 2] == '/') + { + if (len == 2) + { + /* "/." => "/" */ + dirname[--len] = '\0'; + goto append; + } + else + { + /* "...foo/." => "...foo" */ + dirname[len -= 2] = '\0'; + continue; + } + } + break; + } + + if (dirname[0] != '/') + dirname = concat (wd, "/", dirname); + else + dirname = savestring (dirname, len); + make_cleanup (free, dirname); + + if (stat (dirname, &st) < 0) + perror_with_name (dirname); + if ((st.st_mode & S_IFMT) != S_IFDIR) + error ("%s is not a directory.", dirname); + + append: + len = strlen (dirname); + tem = source_path; + while (1) + { + if (!strncmp (tem, dirname, len) + && (tem[len] == '\0' || tem[len] == ':')) + { + printf ("\"%s\" is already in the source path.\n", + dirname); + break; + } + tem = index (tem, ':'); + if (tem) + tem++; + else + { + source_path = concat (old, ":", dirname); + free (old); + break; + } + } + if (from_tty) + directories_info (); + } +} + +/* Open a file named STRING, searching path PATH (dir names sep by colons) + using mode MODE and protection bits PROT in the calls to open. + If TRY_CWD_FIRST, try to open ./STRING before searching PATH. + (ie pretend the first element of PATH is ".") + If FILENAMED_OPENED is non-null, set it to a newly allocated string naming + the actual file opened (this string will always start with a "/" + + If a file is found, return the descriptor. + Otherwise, return -1, with errno set for the last name we tried to open. */ + +/* >>>> This should only allow files of certain types, + >>>> eg executable, non-directory */ +int +openp (path, try_cwd_first, string, mode, prot, filename_opened) + char *path; + int try_cwd_first; + char *string; + int mode; + int prot; + char **filename_opened; +{ + register int fd; + register char *filename; + register char *p, *p1; + register int len; + + /* ./foo => foo */ + while (string[0] == '.' && string[1] == '/') + string += 2; + + if (try_cwd_first || string[0] == '/') + { + filename = string; + fd = open (filename, mode, prot); + if (fd >= 0 || string[0] == '/') + goto done; + } + + filename = (char *) alloca (strlen (path) + strlen (string) + 2); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = (char *) index (p, ':'); + if (p1) + len = p1 - p; + else + len = strlen (p); + + strncpy (filename, p, len); + filename[len] = 0; + strcat (filename, "/"); + strcat (filename, string); + + fd = open (filename, mode, prot); + if (fd >= 0) break; + } + + done: + if (filename_opened) + if (fd < 0) + *filename_opened = (char *) 0; + else if (filename[0] == '/') + *filename_opened = savestring (filename, strlen (filename)); + else + { + char dirname[MAXPATHLEN]; + if (getwd (dirname) == NULL) + perror_with_name ("getwd"); + *filename_opened = concat (dirname, "/", filename); + } + + return fd; +} + +/* Create and initialize the table S->line_charpos that records + the positions of the lines in the source file, which is assumed + to be open on descriptor DESC. + All set S->nlines to the number of such lines. */ + +static void +find_source_lines (s, desc) + struct symtab *s; + int desc; +{ + struct stat st; + register char *data, *p, *end; + int nlines = 0; + int lines_allocated = 1000; + int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int)); + extern int exec_mtime; + + fstat (desc, &st); + if (get_exec_file () != 0 && exec_mtime < st.st_mtime) + printf ("Source file is more recent than executable.\n"); + + data = (char *) alloca (st.st_size); + myread (desc, data, st.st_size); + end = data + st.st_size; + p = data; + line_charpos[0] = 0; + nlines = 1; + while (p != end) + { + if (*p++ == '\n') + { + if (nlines == lines_allocated) + line_charpos = (int *) xrealloc (line_charpos, + sizeof (int) * (lines_allocated *= 2)); + line_charpos[nlines++] = p - data; + } + } + s->nlines = nlines; + s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int)); +} + +/* Return the character position of a line LINE in symtab S. + Return 0 if anything is invalid. */ + +int +source_line_charpos (s, line) + struct symtab *s; + int line; +{ + if (!s) return 0; + if (!s->line_charpos || line <= 0) return 0; + if (line > s->nlines) + line = s->nlines; + return s->line_charpos[line - 1]; +} + +/* Return the line number of character position POS in symtab S. */ + +int +source_charpos_line (s, chr) + register struct symtab *s; + register int chr; +{ + register int line = 0; + register int *lnp; + + if (s == 0 || s->line_charpos == 0) return 0; + lnp = s->line_charpos; + /* Files are usually short, so sequential search is Ok */ + while (line < s->nlines && *lnp <= chr) + { + line++; + lnp++; + } + if (line >= s->nlines) + line = s->nlines; + return line; +} + +/* Get full pathname and line number positions for a symtab. + Return nonzero if line numbers may have changed. + Set *FULLNAME to actual name of the file as found by `openp', + or to 0 if the file is not found. */ + +int +get_filename_and_charpos (s, line, fullname) + struct symtab *s; + int line; + char **fullname; +{ + register int desc, linenums_changed = 0; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, fullname); + if (desc < 0) + { + *fullname = NULL; + return 0; + } + if (s->line_charpos == 0) linenums_changed = 1; + if (linenums_changed) find_source_lines (s, desc); + close (desc); + return linenums_changed; +} + +/* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ + +void +print_source_lines (s, line, stopline) + struct symtab *s; + int line, stopline; +{ + register int c; + register int desc; + register FILE *stream; + int nlines = stopline - line; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, (char **) 0); + if (desc < 0) + perror_with_name (s->filename); + + if (s->line_charpos == 0) + find_source_lines (s, desc); + + if (line < 1 || line >= s->nlines) + { + close (desc); + error ("Line number out of range; %s has %d lines.", + s->filename, s->nlines); + } + + if (lseek (desc, s->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (s->filename); + } + + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + + stream = fdopen (desc, "r"); + clearerr (stream); + + while (nlines-- > 0) + { + c = fgetc (stream); + if (c == EOF) break; + line_info_default_line = current_source_line; + printf ("%d\t", current_source_line++); + do + { + if (c < 040 && c != '\t' && c != '\n') + { + fputc ('^', stdout); + fputc (c + 0100, stdout); + } + else if (c == 0177) + printf ("^?"); + else + fputc (c, stdout); + } while (c != '\n' && (c = fgetc (stream)) >= 0); + } + + fclose (stream); +} + +static void +list_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal, sal_end; + struct symbol *sym; + char *arg1; + int no_end = 1; + int dummy_end = 0; + int dummy_beg = 0; + int linenum_beg = 0; + char *p; + + if (symtab_list == 0) + error ("Listing source lines requires symbols."); + + /* "l" or "l +" lists next ten lines. */ + + if (arg == 0 || !strcmp (arg, "+")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, current_source_line, + current_source_line + 10); + return; + } + + /* "l -" lists previous ten lines, the ones before the ten just listed. */ + if (!strcmp (arg, "-")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, + max (first_line_listed - 10, 1), + first_line_listed); + return; + } + + /* Now if there is only one argument, decode it in SAL + and set NO_END. + If there are two arguments, decode them in SAL and SAL_END + and clear NO_END; however, if one of the arguments is blank, + set DUMMY_BEG or DUMMY_END to record that fact. */ + + arg1 = arg; + if (*arg1 == ',') + dummy_beg = 1; + else + sal = decode_line_1 (&arg1, 0, 0, 0); + + /* Record whether the BEG arg is all digits. */ + + for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); + linenum_beg = (p == arg1); + + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == ',') + { + no_end = 0; + arg1++; + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == 0) + dummy_end = 1; + else if (dummy_beg) + sal_end = decode_line_1 (&arg1, 0, 0, 0); + else + sal_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line); + } + + if (*arg1) + error ("Junk at end of line specification."); + + if (!no_end && !dummy_beg && !dummy_end + && sal.symtab != sal_end.symtab) + error ("Specified start and end are in different files."); + if (dummy_beg && dummy_end) + error ("Two empty args do not say what lines to list."); + + /* if line was specified by address, + first print exactly which line, and which file. + In this case, sal.symtab == 0 means address is outside + of all known source files, not that user failed to give a filename. */ + if (*arg == '*') + { + if (sal.symtab == 0) + error ("No source file for address 0x%x.", sal.pc); + sym = find_pc_function (sal.pc); + if (sym) + printf ("0x%x is in %s (%s, line %d).\n", + sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line); + else + printf ("0x%x is in %s, line %d.\n", + sal.pc, sal.symtab->filename, sal.line); + } + + /* If line was not specified by just a line number, + and it does not imply a symtab, it must be an undebuggable symbol + which means no source code. */ + + if (! linenum_beg && sal.symtab == 0) + error ("No line number known for %s.", arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + + if (dummy_beg && sal_end.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + if (dummy_beg) + print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1), + sal_end.line + 1); + else if (sal.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + else if (no_end) + print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5); + else + print_source_lines (sal.symtab, sal.line, + dummy_end ? sal.line + 10 : sal_end.line + 1); +} + +/* Print info on range of pc's in a specified line. */ + +static void +line_info (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + int start_pc, end_pc; + + if (arg == 0) + { + sal.symtab = current_source_symtab; + sal.line = line_info_default_line; + } + else + { + sal = decode_line_spec (arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + } + + if (sal.symtab == 0) + error ("No source file specified."); + if (sal.line > 0 + && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc)) + { + if (start_pc == end_pc) + printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n", + sal.line, sal.symtab->filename, start_pc); + else + printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n", + sal.line, sal.symtab->filename, start_pc, end_pc); + /* x/i should display this line's code. */ + set_next_address (start_pc); + /* Repeating "info line" should do the following line. */ + line_info_default_line = sal.line + 1; + } + else + printf ("Line number %d is out of range for \"%s\".\n", + sal.line, sal.symtab->filename); +} + +static +initialize () +{ + current_source_symtab = 0; + init_source_path (); + + add_com ("directory", class_files, directory_command, + "Add directory DIR to end of search path for source files.\n\ +With no argument, reset the search path to just the working directory\n\ +and forget cached info on line positions in source files."); + + add_info ("directories", directories_info, + "Current search path for finding source files."); + + add_info ("line", line_info, + "Core addresses of the code for a source line.\n\ +Line can be specified as\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ +Default is to describe the last source line that was listed.\n\n\ +This sets the default address for \"x\" to the line's first instruction\n\ +so that \"x/i\" suffices to start examining the machine code.\n\ +The address is also stored as the value of \"$_\"."); + + add_com ("list", class_files, list_command, + "List specified function or line.\n\ +With no argument, lists ten more lines after or around previous listing.\n\ +\"list -\" lists the ten lines before a previous ten-line listing.\n\ +One argument specifies a line, and ten lines are listed around that line.\n\ +Two arguments with comma between specify starting and ending lines to list.\n\ +Lines can be specified in these ways:\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to list around the line containing that address.\n\ +With two args if one is empty it stands for ten lines away from the other arg."); +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d22 1 +@ diff --git a/gdb/RCS/symmisc.c,v b/gdb/RCS/symmisc.c,v new file mode 100644 index 00000000000..42653dfba97 --- /dev/null +++ b/gdb/RCS/symmisc.c,v @@ -0,0 +1,575 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.09.53; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.04.25.22; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS's devl sources on wheaties +@ + + +1.2 +log +@Check for null pointer passed to free()... +@ +text +@/* Do various things to symbol tables (other than lookup)), for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" + +#include +#include + +static void free_symtab (); + +START_FILE + +/* Free all the symtabs that are currently installed, + and all storage associated with them. + Leaves us in a consistent state with no symtabs installed. */ + +void +free_all_symtabs () +{ + register struct symtab *s, *snext; + + /* All values will be invalid because their types will be! */ + + clear_value_history (); + clear_displays (); + clear_internalvars (); + clear_breakpoints (); + set_default_breakpoint (0, 0, 0, 0); + + current_source_symtab = 0; + + for (s = symtab_list; s; s = snext) + { + snext = s->next; + free_symtab (s); + } + symtab_list = 0; + obstack_free (symbol_obstack, 0); + obstack_init (symbol_obstack); + + if (misc_function_vector) + free (misc_function_vector); + misc_function_count = 0; + misc_function_vector = 0; +} + +/* Free a struct block <- B and all the symbols defined in that block. */ + +static void +free_symtab_block (b) + struct block *b; +{ + register int i, n; + n = BLOCK_NSYMS (b); + for (i = 0; i < n; i++) + { + free (SYMBOL_NAME (BLOCK_SYM (b, i))); + free (BLOCK_SYM (b, i)); + } + free (b); +} + +/* Free all the storage associated with the struct symtab <- S. + Note that some symtabs have contents malloc'ed structure by structure, + while some have contents that all live inside one big block of memory, + and some share the contents of another symbol table and so you should + not free the contents on their behalf (except sometimes the linetable, + which maybe per symtab even when the rest is not). + It is s->free_code that says which alternative to use. */ + +static void +free_symtab (s) + register struct symtab *s; +{ + register int i, n; + register struct blockvector *bv; + register struct type *type; + register struct typevector *tv; + + switch (s->free_code) + { + case free_nothing: + /* All the contents are part of a big block of memory + and some other symtab is in charge of freeing that block. + Therefore, do nothing. */ + break; + + case free_explicit: + /* All the contents are part of a big block of memory + and that is our `free_ptr' and will be freed below. */ + break; + + case free_contents: + /* Here all the contents were malloc'ed structure by structure + and must be freed that way. */ + /* First free the blocks (and their symbols. */ + bv = BLOCKVECTOR (s); + n = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < n; i++) + free_symtab_block (BLOCKVECTOR_BLOCK (bv, i)); + /* Free the blockvector itself. */ + free (bv); + /* Free the type vector. */ + tv = TYPEVECTOR (s); + if (tv) /* FIXME, should this happen? It does... */ + free (tv); + /* Also free the linetable. */ + + case free_linetable: + /* Everything will be freed either by our `free_ptr' + or by some other symbatb, except for our linetable. + Free that now. */ + free (LINETABLE (s)); + break; + } + + /* If there is a single block of memory to free, free it. */ + if (s->free_ptr) + free (s->free_ptr); + + if (s->line_charpos) + free (s->line_charpos); + free (s->filename); + free (s); +} + +/* Convert a raw symbol-segment to a struct symtab, + and relocate its internal pointers so that it is valid. */ + +/* This is how to relocate one pointer, given a name for it. + Works independent of the type of object pointed to. */ +#define RELOCATE(slot) (slot ? (* (char **) &slot += relocation) : 0) + +/* This is the inverse of RELOCATE. We use it when storing + a core address into a slot that has yet to be relocated. */ +#define UNRELOCATE(slot) (slot ? (* (char **) &slot -= relocation) : 0) + +/* During the process of relocation, this holds the amount to relocate by + (the address of the file's symtab data, in core in the debugger). */ +static int relocation; + +#define CORE_RELOCATE(slot) \ + ((slot) += (((slot) < data_start) ? text_relocation \ + : ((slot) < bss_start) ? data_relocation : bss_relocation)) + +#define TEXT_RELOCATE(slot) ((slot) += text_relocation) + +/* Relocation amounts for addresses in the program's core image. */ +static int text_relocation, data_relocation, bss_relocation; + +/* Boundaries that divide program core addresses into text, data and bss; + used to determine which relocation amount to use. */ +static int data_start, bss_start; + +static void relocate_typevector (); +static void relocate_blockvector (); +static void relocate_type (); +static void relocate_block (); +static void relocate_symbol (); + +/* Relocate a file symbol table so that all the pointers + are valid C pointers. Pass the struct symtab for the file + and the amount to relocate by. */ + +static struct symtab * +relocate_symtab (root) + struct symbol_root *root; +{ + struct symtab *sp = (struct symtab *) xmalloc (sizeof (struct symtab)); + bzero (sp, sizeof (struct symtab)); + + relocation = (int) root; + text_relocation = root->textrel; + data_relocation = root->datarel; + bss_relocation = root->bssrel; + data_start = root->databeg; + bss_start = root->bssbeg; + + sp->filename = root->filename; + sp->ldsymoff = root->ldsymoff; + sp->language = root->language; + sp->compilation = root->compilation; + sp->version = root->version; + sp->blockvector = root->blockvector; + sp->typevector = root->typevector; + sp->free_code = free_explicit; + sp->free_ptr = (char *) root; + + RELOCATE (TYPEVECTOR (sp)); + RELOCATE (BLOCKVECTOR (sp)); + RELOCATE (sp->version); + RELOCATE (sp->compilation); + RELOCATE (sp->filename); + + relocate_typevector (TYPEVECTOR (sp)); + relocate_blockvector (BLOCKVECTOR (sp)); + + return sp; +} + +static void +relocate_typevector (tv) + struct typevector *tv; +{ + register int ntypes = TYPEVECTOR_NTYPES (tv); + register int i; + + for (i = 0; i < ntypes; i++) + RELOCATE (TYPEVECTOR_TYPE (tv, i)); + for (i = 0; i < ntypes; i++) + relocate_type (TYPEVECTOR_TYPE (tv, i)); +} + +static void +relocate_blockvector (blp) + register struct blockvector *blp; +{ + register int nblocks = BLOCKVECTOR_NBLOCKS (blp); + register int i; + for (i = 0; i < nblocks; i++) + RELOCATE (BLOCKVECTOR_BLOCK (blp, i)); + for (i = 0; i < nblocks; i++) + relocate_block (BLOCKVECTOR_BLOCK (blp, i)); +} + +static void +relocate_block (bp) + register struct block *bp; +{ + register int nsyms = BLOCK_NSYMS (bp); + register int i; + + TEXT_RELOCATE (BLOCK_START (bp)); + TEXT_RELOCATE (BLOCK_END (bp)); + + /* These two should not be recursively processed. + The superblock need not be because all blocks are + processed from relocate_blockvector. + The function need not be because it will be processed + under the block which is its scope. */ + RELOCATE (BLOCK_SUPERBLOCK (bp)); + RELOCATE (BLOCK_FUNCTION (bp)); + + for (i = 0; i < nsyms; i++) + RELOCATE (BLOCK_SYM (bp, i)); + + for (i = 0; i < nsyms; i++) + relocate_symbol (BLOCK_SYM (bp, i)); +} + +static void +relocate_symbol (sp) + register struct symbol *sp; +{ + RELOCATE (SYMBOL_NAME (sp)); + if (SYMBOL_CLASS (sp) == LOC_BLOCK) + { + RELOCATE (SYMBOL_BLOCK_VALUE (sp)); + /* We can assume the block that belongs to this symbol + is not relocated yet, since it comes after + the block that contains this symbol. */ + BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)) = sp; + UNRELOCATE (BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp))); + } + else if (SYMBOL_CLASS (sp) == LOC_STATIC) + CORE_RELOCATE (SYMBOL_VALUE (sp)); + else if (SYMBOL_CLASS (sp) == LOC_LABEL) + TEXT_RELOCATE (SYMBOL_VALUE (sp)); + RELOCATE (SYMBOL_TYPE (sp)); +} + +/* We cannot come up with an a priori spanning tree + for the network of types, since types can be used + for many symbols and also as components of other types. + Therefore, we need to be able to mark types that we + already have relocated (or are already in the middle of relocating) + as in a garbage collector. */ + +static void +relocate_type (tp) + register struct type *tp; +{ + register int nfields = TYPE_NFIELDS (tp); + register int i; + + RELOCATE (TYPE_NAME (tp)); + RELOCATE (TYPE_TARGET_TYPE (tp)); + RELOCATE (TYPE_FIELDS (tp)); + RELOCATE (TYPE_POINTER_TYPE (tp)); + + for (i = 0; i < nfields; i++) + { + RELOCATE (TYPE_FIELD_TYPE (tp, i)); + RELOCATE (TYPE_FIELD_NAME (tp, i)); + } +} + +/* Read symsegs from file named NAME open on DESC, + make symtabs from them, and return a chain of them. + Assumes DESC is prepositioned at the end of the string table, + just before the symsegs if there are any. */ + +struct symtab * +read_symsegs (desc, name) + int desc; + char *name; +{ + struct symbol_root root; + register char *data; + register struct symtab *sp, *chain = 0; + register int len; + + while (1) + { + len = myread (desc, &root, sizeof root); + if (len == 0 || root.format == 0) + break; + if (root.format != 1 || + root.length < sizeof root) + error ("Invalid symbol segment format code"); + data = (char *) xmalloc (root.length); + bcopy (&root, data, sizeof root); + len = myread (desc, data + sizeof root, + root.length - sizeof root); + sp = relocate_symtab (data); + sp->next = chain; + chain = sp; + } + + return chain; +} + +static int block_depth (); +static void print_spaces (); +static void print_symbol (); + +print_symtabs (filename) + char *filename; +{ + FILE *outfile; + register struct symtab *s; + register int i, j; + int len, line, blen; + register struct linetable *l; + struct blockvector *bv; + register struct block *b; + int depth; + struct cleanup *cleanups; + extern int fclose(); + + if (filename == 0) + error_no_arg ("file to write symbol data in"); + outfile = fopen (filename, "w"); + + cleanups = make_cleanup (fclose, outfile); + immediate_quit++; + + for (s = symtab_list; s; s = s->next) + { + /* First print the line table. */ + fprintf (outfile, "Symtab for file %s\n\n", s->filename); + fprintf (outfile, "Line table:\n\n"); + l = LINETABLE (s); + len = l->nitems; + for (i = 0; i < len; i++) + { + if (l->item[i] < 0) + line = - l->item[i] - 1; + else + fprintf (outfile, " line %d at %x\n", ++line, l->item[i]); + } + /* Now print the block info. */ + fprintf (outfile, "\nBlockvector:\n\n"); + bv = BLOCKVECTOR (s); + len = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < len; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + depth = block_depth (b) * 2; + print_spaces (depth, outfile); + fprintf (outfile, "block #%03d (object 0x%x) ", i, b); + fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b)); + if (BLOCK_SUPERBLOCK (b)) + fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b)); + if (BLOCK_FUNCTION (b)) + fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b))); + fputc ('\n', outfile); + blen = BLOCK_NSYMS (b); + for (j = 0; j < blen; j++) + { + print_symbol (BLOCK_SYM (b, j), depth + 1, outfile); + } + } + + fprintf (outfile, "\n\n"); + } + + immediate_quit--; + do_cleanups (cleanups); +} + +static void +print_symbol (symbol, depth, outfile) + struct symbol *symbol; + int depth; + FILE *outfile; +{ + print_spaces (depth, outfile); + if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE) + { + fprintf (outfile, "label %s at 0x%x", SYMBOL_NAME (symbol), + SYMBOL_VALUE (symbol)); + return; + } + if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE) + { + if (TYPE_NAME (SYMBOL_TYPE (symbol))) + { + type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + else + { + fprintf (outfile, "%s %s = ", + (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM + ? "enum" + : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT + ? "struct" : "union")), + SYMBOL_NAME (symbol)); + type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + fprintf (outfile, ";\n"); + } + else + { + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + fprintf (outfile, "typedef "); + if (SYMBOL_TYPE (symbol)) + { + type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol), + outfile, 1, depth); + fprintf (outfile, "; "); + } + else + fprintf (outfile, "%s ", SYMBOL_NAME (symbol)); + + switch (SYMBOL_CLASS (symbol)) + { + case LOC_CONST: + fprintf (outfile, "const %d (0x%x),", + SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + fprintf (outfile, "const %d hex bytes:", + TYPE_LENGTH (SYMBOL_TYPE (symbol))); + { + int i; + for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++) + fprintf (outfile, " %2x", SYMBOL_VALUE_BYTES (symbol) [i]); + fprintf (outfile, ","); + } + break; + + case LOC_STATIC: + fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGISTER: + fprintf (outfile, "register %d,", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf (outfile, "arg at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf (outfile, "local at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf (outfile, "label at 0x%x", SYMBOL_VALUE (symbol)); + break; + + case LOC_BLOCK: + fprintf (outfile, "block (object 0x%x) starting at 0x%x,", + SYMBOL_VALUE (symbol), + BLOCK_START (SYMBOL_BLOCK_VALUE (symbol))); + break; + } + } + fprintf (outfile, "\n"); +} + +/* Return the nexting depth of a block within other blocks in its symtab. */ + +static int +block_depth (block) + struct block *block; +{ + register int i = 0; + while (block = BLOCK_SUPERBLOCK (block)) i++; + return i; +} + +static +initialize () +{ + add_com ("printsyms", class_obscure, print_symtabs, + "Print dump of current symbol definitions to file OUTFILE."); +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d125 2 +a126 1 + free (tv); +@ diff --git a/gdb/RCS/symtab.c,v b/gdb/RCS/symtab.c,v new file mode 100644 index 00000000000..7ccdaacac54 --- /dev/null +++ b/gdb/RCS/symtab.c,v @@ -0,0 +1,1153 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.10.33; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.26.02.18.56; author gnu; state Exp; +branches ; +next ; + + +desc +@Original from RMS's wheaties devel sources +@ + + +1.2 +log +@Permit SYS V regular expression library as well as real Unix one. +@ +text +@/* Symbol table lookup for the GNU debugger, GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "param.h" + +#include +#include + +#ifdef mac_aux +#define REGCMP +#endif + +START_FILE + +/* Allocate an obstack to hold objects that should be freed + when we load a new symbol table. + This includes the symbols made by dbxread + and the types that are not permanent. */ + +struct obstack obstack1; + +struct obstack *symbol_obstack = &obstack1; + +/* These variables point to the objects + representing the predefined C data types. */ + +struct type *builtin_type_void; +struct type *builtin_type_char; +struct type *builtin_type_short; +struct type *builtin_type_int; +struct type *builtin_type_long; +struct type *builtin_type_unsigned_char; +struct type *builtin_type_unsigned_short; +struct type *builtin_type_unsigned_int; +struct type *builtin_type_unsigned_long; +struct type *builtin_type_float; +struct type *builtin_type_double; + +/* Lookup the symbol table of a source file named NAME. */ + +struct symtab * +lookup_symtab (name) + char *name; +{ + register struct symtab *s; + register char *copy; + + for (s = symtab_list; s; s = s->next) + if (!strcmp (name, s->filename)) + return s; + + /* If name not found as specified, see if adding ".c" helps. */ + + copy = (char *) alloca (strlen (name) + 3); + strcpy (copy, name); + strcat (copy, ".c"); + for (s = symtab_list; s; s = s->next) + if (!strcmp (copy, s->filename)) + return s; + + return 0; +} + +/* Lookup a typedef or primitive type named NAME, + visible in lexical block BLOCK. + If NOERR is nonzero, return zero if NAME is not suitably defined. */ + +struct type * +lookup_typename (name, block, noerr) + char *name; + struct block *block; + int noerr; +{ + register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE); + if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + { + if (!strcmp (name, "int")) + return builtin_type_int; + if (!strcmp (name, "long")) + return builtin_type_long; + if (!strcmp (name, "short")) + return builtin_type_short; + if (!strcmp (name, "char")) + return builtin_type_char; + if (!strcmp (name, "float")) + return builtin_type_float; + if (!strcmp (name, "double")) + return builtin_type_double; + if (!strcmp (name, "void")) + return builtin_type_void; + + if (noerr) + return 0; + error ("No type named %s.", name); + } + return SYMBOL_TYPE (sym); +} + +struct type * +lookup_unsigned_typename (name) + char *name; +{ + if (!strcmp (name, "int")) + return builtin_type_unsigned_int; + if (!strcmp (name, "long")) + return builtin_type_unsigned_long; + if (!strcmp (name, "short")) + return builtin_type_unsigned_short; + if (!strcmp (name, "char")) + return builtin_type_unsigned_char; + error ("No type named unsigned %s.", name); +} + +/* Lookup a structure type named "struct NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_struct (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No struct type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + error ("This context has union or enum %s, not a struct.", name); + return SYMBOL_TYPE (sym); +} + +/* Lookup a union type named "union NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_union (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No union type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION) + error ("This context has struct or enum %s, not a union.", name); + return SYMBOL_TYPE (sym); +} + +/* Lookup an enum type named "enum NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_enum (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No enum type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM) + error ("This context has struct or union %s, not an enum.", name); + return SYMBOL_TYPE (sym); +} + +/* Given a type TYPE, return a type of pointers to that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_pointer_type (type) + struct type *type; +{ + register struct type *ptype = TYPE_POINTER_TYPE (type); + if (ptype) return ptype; + + /* This is the first time anyone wanted a pointer to a TYPE. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + ptype = (struct type *) xmalloc (sizeof (struct type)); + else + ptype = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + + bzero (ptype, sizeof (struct type)); + TYPE_TARGET_TYPE (ptype) = type; + TYPE_POINTER_TYPE (type) = ptype; + /* New type is permanent if type pointed to is permanent. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (ptype) = sizeof (char *); + TYPE_CODE (ptype) = TYPE_CODE_PTR; + return ptype; +} + +/* Given a type TYPE, return a type of functions that return that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_function_type (type) + struct type *type; +{ + register struct type *ptype = TYPE_FUNCTION_TYPE (type); + if (ptype) return ptype; + + /* This is the first time anyone wanted a function returning a TYPE. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + ptype = (struct type *) xmalloc (sizeof (struct type)); + else + ptype = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + + bzero (ptype, sizeof (struct type)); + TYPE_TARGET_TYPE (ptype) = type; + TYPE_FUNCTION_TYPE (type) = ptype; + /* New type is permanent if type returned is permanent. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM; + TYPE_LENGTH (ptype) = 1; + TYPE_CODE (ptype) = TYPE_CODE_FUNC; + TYPE_NFIELDS (ptype) = 0; + return ptype; +} + +/* Smash TYPE to be a type of pointers to TO_TYPE. + If TO_TYPE is not permanent and has no pointer-type yet, + record TYPE as its pointer-type. */ + +void +smash_to_pointer_type (type, to_type) + struct type *type, *to_type; +{ + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (type) = sizeof (char *); + TYPE_CODE (type) = TYPE_CODE_PTR; + + if (TYPE_POINTER_TYPE (to_type) == 0 + && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM)) + { + TYPE_POINTER_TYPE (to_type) = type; + } +} + +/* Smash TYPE to be a type of functions returning TO_TYPE. + If TO_TYPE is not permanent and has no function-type yet, + record TYPE as its function-type. */ + +void +smash_to_function_type (type, to_type) + struct type *type, *to_type; +{ + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_FUNC; + TYPE_NFIELDS (type) = 0; + + if (TYPE_FUNCTION_TYPE (to_type) == 0 + && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM)) + { + TYPE_FUNCTION_TYPE (to_type) = type; + } +} + +static struct symbol *lookup_block_symbol (); + +/* Find the definition for a specified symbol name NAME + in namespace NAMESPACE, visible from lexical block BLOCK. + Returns the struct symbol pointer, or zero if no symbol is found. */ + +struct symbol * +lookup_symbol (name, block, namespace) + char *name; + register struct block *block; + enum namespace namespace; +{ + register int i, n; + register struct symbol *sym; + register struct symtab *s; + struct blockvector *bv; + + /* Search specified block and its superiors. */ + + while (block != 0) + { + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + block = BLOCK_SUPERBLOCK (block); + } + + /* Now search all symtabs' global blocks. */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 0); + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + } + + /* Now search all symtabs' per-file blocks. + Not strictly correct, but more useful than an error. */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 1); + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + } + return 0; +} + +/* Look for a symbol in block BLOCK using binary search. */ + +static struct symbol * +lookup_block_symbol (block, name, namespace) + register struct block *block; + char *name; + enum namespace namespace; +{ + register int bot, top, inc; + register struct symbol *sym; + + top = BLOCK_NSYMS (block); + bot = 0; + + /* First, advance BOT to not far before + the first symbol whose name is NAME. */ + + while (1) + { + inc = (top - bot + 1); + /* No need to keep binary searching for the last few bits worth. */ + if (inc < 7) + break; + inc >>= 1; + sym = BLOCK_SYM (block, bot + inc); + if (strcmp (SYMBOL_NAME (sym), name) < 0) + bot += inc; + else + top = bot + inc; + } + + /* Now scan forward until we run out of symbols, + find one whose name is greater than NAME, + or find one we want. + If there is more than one symbol with the right name and namespace, + we return the first one. dbxread.c is careful to make sure + that if one is a register then it comes first. */ + + top = BLOCK_NSYMS (block); + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + inc = strcmp (SYMBOL_NAME (sym), name); + if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace) + return sym; + if (inc > 0) + return 0; + bot++; + } + return 0; +} + +/* Return the symbol for the function which contains a specified + lexical block, described by a struct block BL. */ + +struct symbol * +block_function (bl) + struct block *bl; +{ + while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) + bl = BLOCK_SUPERBLOCK (bl); + + return BLOCK_FUNCTION (bl); +} + +/* Subroutine of find_pc_line */ + +static struct symtab * +find_pc_symtab (pc) + register CORE_ADDR pc; +{ + register struct block *b; + struct blockvector *bv; + register struct symtab *s; + + /* Search all symtabs for one whose file contains our pc */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, 0); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc) + break; + } + + return s; +} + +/* Find the source file and line number for a given PC value. + Return a structure containing a symtab pointer, a line number, + and a pc range for the entire source line. + The value's .pc field is NOT the specified pc. + NOTCURRENT nonzero means, if specified pc is on a line boundary, + use the line that ends there. Otherwise, in that case, the line + that begins there is used. */ + +struct symtab_and_line +find_pc_line (pc, notcurrent) + CORE_ADDR pc; + int notcurrent; +{ + struct symtab *s; + register struct linetable *l; + register int len; + register int i, item; + int line; + struct symtab_and_line value; + struct blockvector *bv; + + /* Info on best line seen so far, and where it starts, and its file. */ + + int best_line = 0; + CORE_ADDR best_pc = 0; + CORE_ADDR best_end = 0; + struct symtab *best_symtab = 0; + + /* Store here the first line number + of a file which contains the line at the smallest pc after PC. + If we don't find a line whose range contains PC, + we will use a line one less than this, + with a range from the start of that file to the first line's pc. */ + int alt_line = 0; + CORE_ADDR alt_pc = 0; + struct symtab *alt_symtab = 0; + + /* Info on best line seen in this file. */ + + int prev_line; + CORE_ADDR prev_pc; + + /* Info on first line of this file. */ + + int first_line; + CORE_ADDR first_pc; + + /* If this pc is not from the current frame, + it is the address of the end of a call instruction. + Quite likely that is the start of the following statement. + But what we want is the statement containing the instruction. + Fudge the pc to make sure we get that. */ + + if (notcurrent) pc -= 1; + + s = find_pc_symtab (pc); + if (s == 0) + { + value.symtab = 0; + value.line = 0; + value.pc = pc; + return value; + } + + bv = BLOCKVECTOR (s); + + /* Look at all the symtabs that share this blockvector. + They all have the same apriori range, that we found was right; + but they have different line tables. */ + + for (; s && BLOCKVECTOR (s) == bv; s = s->next) + { + /* Find the best line in this symtab. */ + l = LINETABLE (s); + len = l->nitems; + prev_line = -1; + first_line = -1; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + line = - item - 1; + else + { + line++; + if (first_line < 0) + { + first_line = line; + first_pc = item; + } + /* Return the last line that did not start after PC. */ + if (pc >= item) + { + prev_line = line; + prev_pc = item; + } + else + break; + } + } + + /* Is this file's best line closer than the best in the other files? + If so, record this file, and its best line, as best so far. */ + if (prev_line >= 0 && prev_pc > best_pc) + { + best_pc = prev_pc; + best_line = prev_line; + best_symtab = s; + if (i < len) + best_end = item; + else + best_end = 0; + } + /* Is this file's first line closer than the first lines of other files? + If so, record this file, and its first line, as best alternate. */ + if (first_line >= 0 && first_pc > pc + && (alt_pc == 0 || first_pc < alt_pc)) + { + alt_pc = first_pc; + alt_line = first_line; + alt_symtab = s; + } + } + if (best_symtab == 0) + { + value.symtab = alt_symtab; + value.line = alt_line - 1; + value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)); + value.end = alt_pc; + } + else + { + value.symtab = best_symtab; + value.line = best_line; + value.pc = best_pc; + value.end = (best_end ? best_end + : (alt_pc ? alt_pc + : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)))); + } + return value; +} + +/* Find the range of pc values in a line. + Store the starting pc of the line into *STARTPTR + and the ending pc (start of next line) into *ENDPTR. + Returns 1 to indicate success. + Returns 0 if could not find the specified line. */ + +int +find_line_pc_range (symtab, thisline, startptr, endptr) + struct symtab *symtab; + int thisline; + CORE_ADDR *startptr, *endptr; +{ + register struct linetable *l; + register int i, line, item; + int len; + register CORE_ADDR prev_pc; + CORE_ADDR last_pc; + + if (symtab == 0) + return 0; + + l = LINETABLE (symtab); + len = l->nitems; + prev_pc = -1; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + line = - item - 1; + else + { + line++; + /* As soon as we find a line following the specified one + we know the end pc and can return. */ + if (line > thisline) + { + /* If we have not seen an entry for the specified line, + assume that means the specified line has zero bytes. */ + *startptr = prev_pc == -1 ? item : prev_pc; + *endptr = item; + return 1; + } + /* If we see an entry for the specified line, + it gives the beginning. */ + if (line == thisline) + prev_pc = item; + last_pc = item; + } + } + if (prev_pc != -1) + { + /* If we found the specified line but no later line, it's file's last. + Its range is from line's pc to file's end pc. */ + *startptr = last_pc; + *endptr = BLOCK_END (BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), 0)); + return 1; + } + + return 0; +} + +/* Find the PC value for a given source file and line number. + Returns zero for invalid line number. + The source file is specified with a struct symtab. */ + +CORE_ADDR +find_line_pc (symtab, line) + struct symtab *symtab; + int line; +{ + register struct linetable *l; + register int len; + register int i; + register int item; + register int nextline = -1; + + if (line <= 0) + return 0; + + l = LINETABLE (symtab); + len = l->nitems; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + nextline = - item - 1; + else + { + nextline++; + if (line <= nextline) + return item; + } + } + return 0; +} + +int +find_pc_line_pc_range (pc, startptr, endptr) + CORE_ADDR pc; + CORE_ADDR *startptr, *endptr; +{ + struct symtab_and_line sal; + sal = find_pc_line (pc, 0); + *startptr = sal.pc; + *endptr = sal.end; + return sal.symtab != 0; +} + +/* Parse a string that specifies a line number. + Pass the address of a char * variable; that variable will be + advanced over the characters actually parsed. + + The string can be: + + LINENUM -- that line number in current file. PC returned is 0. + FILE:LINENUM -- that line in that file. PC returned is 0. + FUNCTION -- line number of openbrace of that function. + PC returned is the start of the function. + FILE:FUNCTION -- likewise, but prefer functions in that file. + *EXPR -- line in which address EXPR appears. + + FUNCTION may be an undebuggable function found in misc_function_vector. + + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside a function when a function is specified. + + DEFAULT_SYMTAB specifies the file to use if none is specified. + It defaults to current_source_symtab. + DEFAULT_LINE specifies the line number to use for relative + line numbers (that start with signs). Defaults to current_source_line. + + Note that it is possible to return zero for the symtab + if no file is validly specified. Callers must check that. + Also, the line number returned may be invalid. */ + +struct symtab_and_line +decode_line_1 (argptr, funfirstline, default_symtab, default_line) + char **argptr; + int funfirstline; + struct symtab *default_symtab; + int default_line; +{ + struct symtab_and_line value; + register char *p, *p1; + register struct symtab *s; + register struct symbol *sym; + register CORE_ADDR pc; + register int i; + char *copy; + + /* Defaults have defaults. */ + + if (default_symtab == 0) + { + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + /* See if arg is *PC */ + + if (**argptr == '*') + { + (*argptr)++; + pc = parse_and_eval_address_1 (argptr); + value = find_pc_line (pc, 0); + value.pc = pc; + return value; + } + + /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ + + s = 0; + + for (p = *argptr; *p; p++) + { + if (p[0] == ':' || p[0] == ' ' || p[0] == '\t') + break; + } + while (p[0] == ' ' || p[0] == '\t') p++; + + if (p[0] == ':') + { + /* Extract the file name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + bcopy (*argptr, copy, p - *argptr); + copy[p - *argptr] = 0; + + /* Find that file's data. */ + s = lookup_symtab (copy); + if (s == 0) + { + if (symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + error ("No source file named %s.", copy); + } + + /* Discard the file name from the arg. */ + p = p1 + 1; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + } + + /* S is specified file's symtab, or 0 if no file specified. + arg no longer contains the file name. */ + + /* Check whether arg is all digits (and sign) */ + + p = *argptr; + if (*p == '-' || *p == '+') p++; + while (*p >= '0' && *p <= '9') + p++; + + if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ',')) + { + /* We found a token consisting of all digits -- at least one digit. */ + enum sign {none, plus, minus} sign = none; + + if (**argptr == '+') + sign = plus, (*argptr)++; + else if (**argptr == '-') + sign = minus, (*argptr)++; + value.line = atoi (*argptr); + switch (sign) + { + case plus: + if (p == *argptr) + value.line = 5; + if (s == 0) + value.line = default_line + value.line; + break; + case minus: + if (p == *argptr) + value.line = 15; + if (s == 0) + value.line = default_line - value.line; + else + value.line = 1; + break; + } + + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + if (s == 0) + s = default_symtab; + value.symtab = s; + value.pc = 0; + return value; + } + + /* Arg token is not digits => try it as a function name + Find the next token (everything up to end or next whitespace). */ + p = *argptr; + while (*p && *p != ' ' && *p != '\t' && *p != ',') p++; + copy = (char *) alloca (p - *argptr + 1); + bcopy (*argptr, copy, p - *argptr); + copy[p - *argptr] = 0; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + /* Look up that token as a function. + If file specified, use that file's per-file block to start with. */ + + sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, + VAR_NAMESPACE); + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* Arg is the name of a function */ + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (pc); + value = find_pc_line (pc, 0); + value.pc = (value.end && value.pc != pc) ? value.end : pc; + return value; + } + + if (sym) + error ("%s is not a function.", copy); + + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, copy)) + { + value.symtab = 0; + value.line = 0; + value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (value.pc); + return value; + } + + if (symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + error ("Function %s not defined.", copy); +} + +struct symtab_and_line +decode_line_spec (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtab_and_line sal; + if (string == 0) + error ("Empty line specification."); + sal = decode_line_1 (&string, funfirstline, + current_source_symtab, current_source_line); + if (*string) + error ("Junk at end of line specification: %s", string); + return sal; +} + +static void +sources_info () +{ + register struct symtab *s; + register int column = 0; + + if (symtab_list == 0) + { + printf ("No symbol table is loaded.\n"); + return; + } + printf ("Source files for which symbol table is known:\n"); + for (s = symtab_list; s; s = s->next) + { + if (column != 0 && column + strlen (s->filename) >= 70) + { + printf ("\n"); + column = 0; + } + else if (column != 0) + { + printf (" "); + column++; + } + printf ("%s", s->filename); + column += strlen (s->filename); + if (s->next) + { + printf (","); + column++; + } + } + printf ("\n"); +} + +/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP. + If CLASS is zero, list all symbols except functions and type names. + If CLASS is 1, list only functions. + If CLASS is 2, list only type names. */ + +#define MORE \ +{ print_count++; \ + if (print_count >= 21) \ + { printf ("--Type Return to print more--"); \ + print_count = 0; \ + fflush (stdout); \ + read_line (); } } + +static void +list_symbols (regexp, class) + char *regexp; + int class; +{ + register struct symtab *s; + register struct blockvector *bv; + struct blockvector *prev_bv = 0; + register struct block *b; + register int i, j; + register struct symbol *sym; + char *val = 0; + int found_in_file; + static char *classnames[] + = {"variable", "function", "type"}; + int print_count = 0; +#ifdef REGCMP + extern char *regcmp(), *regex(), *loc1; +#endif + + if (regexp) { +#ifdef REGCMP + val = regcmp(regexp, (char *)0); + if (val == 0) + error ("Invalid regexp: %s", regexp); +#else + if (val = (char *) re_comp (regexp)) + error ("Invalid regexp: %s", val); +#endif + } + + printf (regexp + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[class], + regexp); + + for (s = symtab_list; s; s = s->next) + { + found_in_file = 0; + bv = BLOCKVECTOR (s); + /* Often many files share a blockvector. + Scan each blockvector only once so that + we don't get every symbol many times. + It happens that the first symtab in the list + for any given blockvector is the main file. */ + if (bv != prev_bv) + for (i = 0; i < 2; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + for (j = 0; j < BLOCK_NSYMS (b); j++) + { + QUIT; + sym = BLOCK_SYM (b, j); + if (regexp) { +#ifdef REGCMP + if (!regex(val, SYMBOL_NAME (sym))) + continue; +#else + if (!re_exec (SYMBOL_NAME (sym))) + continue; +#endif + } + if ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK) + || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)) + { + if (!found_in_file) + { + printf ("\nFile %s:\n", s->filename); + print_count += 2; + } + found_in_file = 1; + MORE; + if (class != 2 && i == 1) + printf ("static "); + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE) + printf ("typedef "); + + type_print (SYMBOL_TYPE (sym), + (SYMBOL_CLASS (sym) == LOC_TYPEDEF + ? "" : SYMBOL_NAME (sym)), + stdout, 0); + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE + && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0 + || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))), + SYMBOL_NAME (sym)))) + printf (" %s", SYMBOL_NAME (sym)); + printf (";\n"); + } + } + } + prev_bv = bv; + } +#ifdef REGCMP + if (val) + (void)free(val); +#endif +} + +static void +variables_info (regexp) + char *regexp; +{ + list_symbols (regexp, 0); +} + +static void +functions_info (regexp) + char *regexp; +{ + list_symbols (regexp, 1); +} + +static void +types_info (regexp) + char *regexp; +{ + list_symbols (regexp, 2); +} + +/* Initialize the standard C scalar types. */ + +static +struct type * +init_type (code, length, uns, name) + enum type_code code; + int length, uns; + char *name; +{ + register struct type *type; + + type = (struct type *) xmalloc (sizeof (struct type)); + bzero (type, sizeof *type); + TYPE_CODE (type) = code; + TYPE_LENGTH (type) = length; + TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0; + TYPE_FLAGS (type) |= TYPE_FLAG_PERM; + TYPE_NFIELDS (type) = 0; + TYPE_NAME (type) = name; + + return type; +} + +static +initialize () +{ + add_info ("variables", variables_info, + "All global and static variable names, or those matching REGEXP."); + add_info ("functions", functions_info, + "All function names, or those matching REGEXP."); + add_info ("types", types_info, + "All types names, or those matching REGEXP."); + add_info ("sources", sources_info, + "Source files in the program."); + + obstack_init (symbol_obstack); + + builtin_type_void = init_type (TYPE_CODE_VOID, 0, 0, "void"); + + builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float"); + builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double"); + + builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char"); + builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short"); + builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long"); + builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int"); + + builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char"); + builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short"); + builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long"); + builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int"); +} + +END_FILE +@ + + +1.1 +log +@Initial revision +@ +text +@d29 4 +d933 1 +a933 1 + char *val; +d938 3 +d942 6 +a947 1 + if (regexp) +d950 2 +d976 10 +a985 2 + if ((regexp == 0 || re_exec (SYMBOL_NAME (sym))) + && ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF +d988 1 +a988 1 + || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF))) +d1019 4 +@ diff --git a/gdb/RCS/utils.c,v b/gdb/RCS/utils.c,v new file mode 100644 index 00000000000..3f7a836e6a4 --- /dev/null +++ b/gdb/RCS/utils.c,v @@ -0,0 +1,461 @@ +head 1.2; +access ; +symbols RMS-has:1.2; +locks ; strict; +comment @ * @; + + +1.2 +date 88.01.26.05.11.12; author gnu; state Exp; +branches ; +next 1.1; + +1.1 +date 88.01.21.05.11.11; author gnu; state Exp; +branches ; +next ; + + +desc +@From RMS's development sources on wheaties, 20Jan88 +@ + + +1.2 +log +@Avoid using TIOCFLUSH if it is not defined. +@ +text +@/* General utility routines for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include "defs.h" + +void error (); +void fatal (); + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, + rather than waiting until QUIT is executed. */ + +int immediate_quit; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) (); + int arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + (*ptr->function) (ptr->arg); + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +xrealloc (ptr, size) + char *ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + char *err; + char *combined; + + if (errcode < sys_nerr) + err = sys_errlist[errcode]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + printf ("%s.\n", combined); +} + +void +quit () +{ + fflush (stdout); +#ifdef TIOCFLUSH + ioctl (fileno (stdout), TIOCFLUSH, 0); +#endif + error ("Quit"); +} + +/* Control C comes here */ + +void +request_quit () +{ + quit_flag = 1; + if (immediate_quit) + quit (); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + return_to_top_level (); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) xmalloc (len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + if (!input_from_terminal_p ()) + return 1; + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') clearerr (stdin); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf ("Please answer y or n.\n"); + } +} + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +void +printchar (ch, stream) + unsigned char ch; + FILE *stream; +{ + register int c = ch; + if (c < 040 || c >= 0177) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == '"' || c == '\'') + fputc ('\\', stream); + fputc (c, stream); + } +} +@ + + +1.1 +log +@Initial revision +@ +text +@d194 1 +d196 1 +@ diff --git a/gdb/README b/gdb/README new file mode 100644 index 00000000000..6e985de1572 --- /dev/null +++ b/gdb/README @@ -0,0 +1,29 @@ +This is GDB, a source-level debugger intended for GNU, +presently running under un*x. + +Before compiling GDB, you must set three files according to +the kind of machine you are running on. + +param.h must be set up to #include an m- file for the machine. +The m- files written so far are m-vax.h, m-sun2.h and m-sun3.h. +(I believe that it is the operating system version and not +the cpu type which determines which of the two is right on a Sun.) +This file contains macro definitions that express information +about the machine's registers, stack frame format and instructions. + +initialize.h must be set up to #include an m-...init.h file. +There are two of them written: m-vaxinit.h and m-suninit.h. +This file defines one macro, which says how to round up from the +address of the end of the text of one .o file to the beginning of +the text of the next .o file. + +pinsn.c must be set up to include the instruction printer for +your cpu type. The two printers that exist are vax-pinsn.c +and m68k-pinsn.c. + +`Makefile' must be changed to say `OBSTACK = obstack.o' instead of +`OBSTACK=-lobstack' (unless you want to install obstack.o as +/lib/libobstack.a). + +Once these files are set up, just `make' will do everything, +producing an executable `gdb' in this directory. diff --git a/gdb/TAGS b/gdb/TAGS new file mode 100644 index 00000000000..e01cba939ef --- /dev/null +++ b/gdb/TAGS @@ -0,0 +1,852 @@ + +blockframe.c,436 +block_for_pc 221,5337 +block_innermost_frame 308,7200 +find_pc_function 276,6473 +find_pc_misc_function 290,6806 +get_current_block 182,4485 +get_current_frame 47,1553 +get_frame_block 172,4336 +get_frame_function 208,5053 +get_frame_info 90,2661 +get_frame_pc 150,3800 +get_frame_saved_regs 161,3986 +get_pc_function_start 188,4557 +get_prev_frame 66,1893 +get_prev_frame_info 128,3455 +initialize 329,7603 +set_current_frame 56,1705 + +breakpoint.c,1102 +#define ALL_BREAKPOINTS(71,2545 +break_command 604,14937 +break_command_1 528,13121 +breakpoint_1 360,9438 +breakpoint_auto_delete 687,16916 +breakpoint_here_p 288,7887 +breakpoint_stop_status 308,8410 +breakpoints_info 409,10520 +check_duplicates 443,11290 +clear_breakpoint_commands 218,6186 +clear_breakpoints 757,18298 +clear_command 620,15179 +clear_momentary_breakpoints 513,12821 +commands_command 154,4443 +condition_command 109,3533 +delete_breakpoint 704,17221 +delete_command 733,17741 +disable_breakpoint 873,20658 +disable_command 882,20791 +do_breakpoint_commands 200,5626 +enable_breakpoint 857,20419 +enable_command 866,20550 +enable_delete_breakpoint 910,21276 +enable_delete_command 919,21413 +enable_once_breakpoint 894,21020 +enable_once_command 903,21158 +ignore_command 797,19190 +initialize 933,21666 +insert_breakpoints 230,6503 +map_breakpoint_numbers 822,19738 +mark_breakpoints_out 275,7576 +remove_breakpoints 251,7042 +set_default_breakpoint 426,10820 +set_ignore_count 767,18523 +set_momentary_breakpoint 501,12597 +set_raw_breakpoint 464,11810 +tbreak_command 612,15057 + +command.c,151 +add_alias_cmd 141,6077 +add_cmd 116,5529 +add_prefix_cmd 177,7140 +delete_cmd 198,7681 +help_cmd 230,8515 +lookup_cmd 336,11651 +savestring 446,13891 + +core.c,397 +#define N_DATADDR(41,1348 +#define N_TXTADDR(37,1278 +close_exec_file 268,7417 +core_file_command 104,2838 +exec_file_command 221,6183 +files_info 330,8673 +get_exec_file 315,8446 +have_core_file_p 324,8612 +initialize 548,13957 +myread 505,13219 +read_memory 373,9666 +register_addr 531,13685 +reopen_exec_file 275,7501 +validate_files 291,7907 +write_memory 389,10073 +xfer_core_file 400,10338 + +dbxread.c,1108 +add_new_header_file 346,10622 +add_old_header_file 317,9604 +add_symbol_to_list 496,14905 +add_this_object_header_file 297,8977 +compare_misc_functions 931,26566 +compare_symbols 1000,28016 +condense_misc_bunches 957,27070 +dbx_alloc_type 454,13833 +dbx_lookup_type 404,12394 +define_symbol 1516,42011 +discard_misc_bunches 944,26878 +end_symtab 756,22240 +explicit_lookup_type 475,14373 +finish_block 512,15299 +free_header_files 273,8395 +get_sym_file 1174,32423 +hash_symsegs 1343,36983 +hashname 1318,36533 +init_header_files 260,8046 +init_misc_functions 903,25961 +initialize 2078,57588 +make_blockvector 590,17428 +new_object_header_files 286,8705 +next_symbol_text 1309,36368 +pop_subfile 861,25120 +process_one_symbol 1374,37801 +push_subfile 847,24770 +read_dbx_symtab 1186,32790 +read_enum_type 1892,52804 +read_number 2041,57023 +read_range_type 1962,54881 +read_struct_type 1809,50421 +read_type 1685,47313 +read_type_number 1658,46658 +record_line 627,18511 +record_misc_function 911,26075 +sort_syms 1012,28407 +start_subfile 699,20484 +start_symtab 662,19485 +symbol_file_command 1036,28951 + +environ.c,213 +environ_vector 164,6337 +free_environ 118,5334 +get_in_environ 173,6472 +init_environ 134,5661 +make_environ 103,5036 +#define max(96,4912 +#define min(95,4870 +set_in_environ 192,6807 +unset_in_environ 232,7561 + +eval.c,309 +evaluate_expression 95,2716 +evaluate_subexp 114,3104 +evaluate_subexp_for_address 440,13032 +evaluate_subexp_for_sizeof 509,14789 +evaluate_subexp_with_coercion 477,13979 +evaluate_type 106,2961 +initialize 550,15888 +parse_and_eval 64,1977 +parse_and_eval_address 33,1188 +parse_and_eval_address_1 50,1650 + +expprint.c,49 +print_expression 88,3265 +print_subexp 102,3660 + +expread.tab.c,358 +copy_name 538,12121 +end_arglist 125,2565 +free_funcalls 139,2867 +length_of_subexp 572,13025 +parse_c_1 751,17140 +parse_c_expression 790,18194 +parse_number 217,5038 +prefixify_expression 552,12457 +prefixify_subexp 644,14362 +start_arglist 111,2206 +write_exp_elt 156,3206 +write_exp_string 173,3660 +yyerror 529,11966 +yylex 315,7081 +yyparse(985,25972 + +findvar.c,309 +find_saved_register 38,1432 +initialize 386,10456 +locate_var_value 334,9235 +read_register 165,4621 +read_register_bytes 140,4050 +read_relative_register_raw_bytes 68,2095 +read_var_value 202,5600 +supply_register 190,5277 +value_of_register 102,2842 +write_register 175,4862 +write_register_bytes 151,4328 + +firstfile.c,89 +initialize_all_files 128,6009 +initialize_dummy_1 140,6338 +initialize_dummy_2 148,6497 + +infcmd.c,550 +cont_command 165,3979 +environment_info 479,11280 +finish_command 397,9291 +have_inferior_p 106,2907 +initialize 682,15823 +jump_command 269,6035 +next_command 202,4695 +nexti_command 216,4897 +program_info 457,10675 +read_memory_integer 542,12697 +read_pc 575,13293 +registers_info 589,13488 +run_command 121,3120 +run_stack_dummy 355,8179 +set_args_command 112,2972 +set_environment_command 499,11682 +signal_command 314,7007 +step_1 222,4974 +step_command 194,4543 +stepi_command 210,4820 +unset_environment_command 531,12458 +write_pc 580,13357 + +inflow.c,551 +create_inferior 187,5073 +fetch_inferior_registers 271,6793 +fetch_inferior_registers 317,8482 +inferior_died 244,6286 +initialize 483,13062 +kill_command 226,5974 +kill_inferior 235,6161 +read_inferior_memory 388,10475 +resume 258,6596 +store_inferior_registers 294,7707 +store_inferior_registers 343,9249 +term_status_command 165,4365 +terminal_inferior 87,2428 +terminal_init_inferior 71,2074 +terminal_ours 121,3326 +terminal_ours_1 127,3383 +terminal_ours_for_output 111,3126 +try_writing_regs_command 457,12556 +write_inferior_memory 416,11420 + +infrun.c,286 +clear_proceed_status 111,3347 +handle_command 728,21384 +initialize 848,24793 +insert_step_breakpoint 706,20807 +normal_stop 618,18254 +proceed 138,4172 +remove_step_breakpoint 718,21109 +signals_info 810,23832 +start_inferior 214,6079 +wait_for_inferior 242,7039 +writing_pc 202,5763 + +kdb-start.c,14 +start 10,140 + +lastfile.c,28 +initialize_last_file 4,144 + +m68k-pinsn.c,361 +#define NEXTBYTE(43,1554 +#define NEXTDOUBLE(54,1819 +#define NEXTEXTEND(57,1877 +#define NEXTLONG(48,1671 +#define NEXTPACKED(61,1995 +#define NEXTSINGLE(51,1762 +#define NEXTWORD(45,1602 +convert_from_68881 713,16392 +convert_to_68881 732,16806 +fetch_arg 504,12082 +print_base 693,15890 +print_indexed 603,13871 +print_insn 71,2389 +print_insn_arg 163,4738 + +main.c,841 +add_com 487,11896 +add_com_alias 499,12123 +add_info 455,11186 +add_info_alias 466,11372 +cd_command 885,24375 +command_loop 288,7462 +copying_info 628,14816 +define_command 545,12933 +do_nothing 281,7362 +document_command 583,13895 +dont_repeat 323,8255 +dump_me_command 961,25608 +echo_command 935,25224 +error_no_arg 509,12321 +execute_command 245,6496 +free_command_lines 437,10877 +help_command 516,12415 +info_command 478,11700 +initialize_main 972,25764 +input_from_terminal_p 869,24072 +main 81,2147 +print_gdb_version 800,22767 +pwd_command 875,24143 +quit_command 856,23880 +read_command_lines 386,9603 +read_line 334,8514 +return_to_top_level 71,1965 +set_prompt_command 818,23215 +source_cleanup 904,24752 +source_command 912,24854 +stop_sig 307,7915 +validate_comname 524,12566 +version_info 810,23117 +warranty_info 770,21356 + +obstack.c,77 +_obstack_begin 101,4993 +_obstack_free 148,6461 +_obstack_newchunk 121,5631 + +pinsn.c,0 + +printcmd.c,585 +address_info 385,9015 +clear_displays 661,15183 +decode_format 70,2061 +display_command 606,14214 +display_info 769,17310 +do_displays 731,16450 +do_examine 231,5522 +free_display 649,14965 +initialize 888,20497 +output_command 346,8219 +print_address 208,4990 +print_command 306,7398 +print_formatted 109,2860 +print_frame_args 810,18392 +print_frame_nameless_args 870,20125 +print_variable_value 795,17951 +ptype_command 525,12189 +set_command 374,8765 +set_next_address 193,4626 +undisplay_command 677,15445 +validate_format 291,6959 +whatis_command 500,11716 +x_command 452,10410 + +source.c,249 +directories_info 53,1637 +directory_command 79,2168 +find_source_lines 264,6263 +init_source_path 59,1735 +initialize 535,13376 +line_info 490,12220 +list_command 363,8569 +openp 186,4596 +print_source_lines 303,7291 +select_source_symtab 250,5960 + +stack.c,502 +args_info 350,8833 +backtrace_command 232,6280 +down_command 498,12939 +find_relative_frame 391,10010 +frame_command 444,11623 +frame_info 149,4137 +get_selected_block 371,9306 +initialize 542,13968 +locals_info 312,8132 +print_block_frame_locals 257,6820 +print_frame_arg_vars 318,8214 +print_frame_info 70,2167 +print_frame_local_vars 291,7614 +print_sel_frame 131,3689 +print_selected_frame 140,3894 +print_stack_frame 57,1964 +return_command 516,13439 +select_frame 359,9033 +up_command 477,12347 + +standalone.c,1165 +_exit 436,8533 +_flsbuf 326,6852 +access 76,1743 +chdir 62,1588 +close 164,4224 +core_file_command 340,7028 +exec_file_command 337,7003 +execle 433,8519 +exit 81,1771 +fault 514,9963 +fclose 189,4597 +fdopen 183,4539 +fflush 331,6910 +fgetc 247,5466 +fopen 175,4414 +fprintf 298,6263 +fputc 314,6593 +fread 229,5154 +fstat 195,4647 +fwrite 305,6422 +get_exec_file 344,7060 +getpid 54,1543 +getrlimit 474,9005 +getwd 66,1608 +have_core_file_p 350,7176 +initialize 585,11686 +ioctl 45,1478 +kill 51,1531 +kill_command 355,7213 +lseek 266,5714 +malloc_warning 441,8575 +myread 208,4831 +open 129,3606 +printf 291,6110 +ptrace 427,8490 +read_inferior_register 372,7361 +read_memory 375,7391 +read_register 397,7764 +restore_gdb 528,10282 +resume 490,9429 +save_frame_pointer 502,9633 +save_registers 540,10627 +sbrk 451,8691 +setpgrp 430,8504 +int (* signal 48,1506 +sigsetmask 59,1570 +int kdb_stack_beg[STACK_SIZE / sizeof 581,11613 +terminal_inferior 360,7254 +terminal_init_inferior 366,7300 +terminal_ours 363,7279 +ulimit 463,8913 +vfork 417,8200 +vlimit 469,8955 +wait 554,10975 +write_inferior_register 369,7330 +write_memory 385,7564 +write_register 406,7933 + +stuff.c,70 +err 162,5253 +find_symbol 141,4686 +get_offset 97,3038 +main 32,1184 + +symmisc.c,473 +#define CORE_RELOCATE(158,4817 +#define RELOCATE(148,4378 +#define TEXT_RELOCATE(162,4972 +#define UNRELOCATE(152,4573 +block_depth 499,13854 +free_all_symtabs 38,1310 +free_symtab 92,2701 +free_symtab_block 70,1994 +initialize 508,13995 +print_symbol 413,11786 +print_symtabs 353,10199 +read_symsegs 320,9451 +relocate_block 243,7195 +relocate_blockvector 231,6886 +relocate_symbol 268,7855 +relocate_symtab 182,5675 +relocate_type 296,8833 +relocate_typevector 218,6602 + +symtab.c,716 +block_function 383,10928 +decode_line_1 694,18782 +decode_line_spec 853,22739 +find_line_pc 624,16888 +find_line_pc_range 565,15457 +find_pc_line 425,11975 +find_pc_line_pc_range 655,17363 +find_pc_symtab 395,11161 +functions_info 995,26000 +init_type 1012,26230 +initialize 1032,26680 +list_symbols 916,24143 +lookup_block_symbol 330,9572 +lookup_enum 166,4758 +lookup_function_type 211,6260 +lookup_pointer_type 182,5269 +lookup_struct 134,3824 +lookup_symbol 285,8458 +lookup_symtab 58,1929 +lookup_typename 85,2559 +lookup_union 150,4293 +lookup_unsigned_typename 116,3346 +smash_to_function_type 262,7816 +smash_to_pointer_type 241,7206 +sources_info 868,23119 +types_info 1002,26088 +variables_info 988,25912 + +test2.c,11 +main 6,86 + +test3.c,25 +bar 12,123 +newfun 5,51 + +testbit.c,11 +main 7,58 + +testfun.c,44 +do_add 7,62 +do_float_add 13,104 +main 1,0 + +testkill.c,11 + main(2,1 + +testrec.c,20 +foo 6,24 +main 1,0 + +testreg.c,22 +foo 19,341 +main 1,0 + +testregs.c,23 +foo 2,11 +main 15,321 + +utils.c,382 +concat 254,5912 +discard_cleanups 84,2483 +do_cleanups 68,2104 +error 213,5038 +fatal 228,5397 +free_current_contents 104,2893 +make_cleanup 48,1636 +parse_escape 323,7736 +perror_with_name 142,3676 +print_spaces 266,6154 +print_sys_errmsg 168,4235 +printchar 390,8781 +query 280,6518 +quit 191,4675 +request_quit 201,4799 +savestring 243,5745 +xmalloc 115,3106 +xrealloc 127,3326 + +valarith.c,215 +initialize 352,8246 +value_add 31,1128 +value_binop 116,3276 +value_equal 257,5535 +value_less 301,6746 +value_lognot 342,7998 +value_neg 328,7619 +value_sub 70,2102 +value_subscript 105,2971 +value_zerop 233,5184 + +valops.c,395 +call_function 388,10791 +initialize 594,16295 +push_bytes 314,9135 +push_word 294,8769 +value_addr 247,7400 +value_arg_coerce 354,9928 +value_arg_push 373,10344 +value_assign 85,2697 +value_at 68,2289 +value_cast 34,1302 +value_coerce_array 219,6610 +value_ind 274,8155 +value_of_variable 209,6404 +value_push 333,9476 +value_repeat 186,5819 +value_string 485,13581 +value_struct_elt 555,15503 + +valprint.c,237 +initialize 533,13661 +set_maximum_command 525,13515 +type_print 272,7365 +type_print_1 283,7591 +type_print_base 403,10889 +type_print_varspec_prefix 316,8617 +type_print_varspec_suffix 352,9476 +val_print 113,3308 +value_print 46,1539 + +values.c,762 +access_value_history 212,5551 +allocate_repeat_value 83,2505 +allocate_value 59,1948 +clear_internalvars 371,9239 +clear_value_history 251,6511 +convenience_info 386,9475 +free_all_values 108,3143 +history_info 270,6920 +initialize 737,18259 +internalvar_name 361,9048 +lookup_internalvar 308,7852 +modify_field 602,14750 +record_latest_value 178,4634 +release_value 125,3410 +set_internalvar 351,8879 +set_internalvar_component 336,8485 +set_return_value 709,17666 +unpack_double 486,11851 +unpack_field_as_long 578,14176 +unpack_long 430,10615 +value_as_double 418,10252 +value_as_long 411,10132 +value_being_returned 688,17121 +value_copy 151,3834 +value_field 542,13135 +value_from_double 654,16089 +value_from_long 626,15329 +value_of_internalvar 327,8298 + +vax-pinsn.c,44 +print_insn 42,1456 +print_insn_arg 86,2396 + +version.c,0 + +command.h,0 + +defs.h,42 +#define max(24,1043 +#define min(23,1001 + +environ.h,0 + +expression.h,0 + +frame.h,0 + +inferior.h,0 + +initialize.h,0 + +m-isi-ov.h,852 +#define ABOUT_TO_RETURN(136,4974 +#define FIX_CALL_DUMMY(447,17543 +#define FRAME_ARGS_ADDRESS(275,9997 +#define FRAME_CHAIN(264,9636 +#define FRAME_CHAIN_COMBINE(269,9825 +#define FRAME_CHAIN_VALID(266,9706 +#define FRAME_FIND_SAVED_REGS(305,11191 +#define FRAME_LOCALS_ADDRESS(277,10040 +#define FRAME_NUM_ARGS(282,10176 +#define FRAME_SAVED_PC(273,9929 +#define INIT_STACK(471,18339 +#define INVALID_FLOAT(140,5108 +#define N_DATADDR(120,4437 +#define N_TXTADDR(125,4616 +#define REGISTER_BYTE(194,7220 +#define REGISTER_CONVERTIBLE(222,8151 +#define REGISTER_CONVERT_TO_RAW(236,8614 +#define REGISTER_CONVERT_TO_VIRTUAL(227,8318 +#define REGISTER_RAW_SIZE(203,7555 +#define REGISTER_U_ADDR(174,6379 +#define REGISTER_VIRTUAL_SIZE(209,7811 +#define REGISTER_VIRTUAL_TYPE(245,8895 +#define SAVED_PC_AFTER_CALL(97,3881 +#define SKIP_PROLOGUE(77,3210 + +m-sun2.h,824 +#define ABOUT_TO_RETURN(79,2505 +#define FIX_CALL_DUMMY(344,12862 +#define FRAME_ARGS_ADDRESS(196,6448 +#define FRAME_CHAIN(185,6087 +#define FRAME_CHAIN_COMBINE(190,6276 +#define FRAME_CHAIN_VALID(187,6157 +#define FRAME_FIND_SAVED_REGS(232,7817 +#define FRAME_LOCALS_ADDRESS(198,6491 +#define FRAME_NUM_ARGS(205,6746 +#define FRAME_NUM_ARGS(208,6795 +#define FRAME_SAVED_PC(194,6380 +#define INIT_STACK(368,13658 +#define INVALID_FLOAT(83,2639 +#define REGISTER_BYTE(121,3997 +#define REGISTER_CONVERTIBLE(144,4615 +#define REGISTER_CONVERT_TO_RAW(154,4927 +#define REGISTER_CONVERT_TO_VIRTUAL(149,4749 +#define REGISTER_RAW_SIZE(126,4162 +#define REGISTER_U_ADDR(166,5375 +#define REGISTER_VIRTUAL_SIZE(131,4317 +#define REGISTER_VIRTUAL_TYPE(159,5092 +#define SAVED_PC_AFTER_CALL(51,1836 +#define SKIP_PROLOGUE(38,1400 + +m-sun3.h,790 +#define ABOUT_TO_RETURN(78,2454 +#define FIX_CALL_DUMMY(392,15189 +#define FRAME_ARGS_ADDRESS(213,7102 +#define FRAME_CHAIN(202,6741 +#define FRAME_CHAIN_COMBINE(207,6930 +#define FRAME_CHAIN_VALID(204,6811 +#define FRAME_FIND_SAVED_REGS(249,8471 +#define FRAME_LOCALS_ADDRESS(215,7145 +#define FRAME_NUM_ARGS(222,7400 +#define FRAME_NUM_ARGS(225,7449 +#define FRAME_SAVED_PC(211,7034 +#define INIT_STACK(416,15985 +#define INVALID_FLOAT(82,2588 +#define REGISTER_BYTE(123,4130 +#define REGISTER_CONVERTIBLE(151,5061 +#define REGISTER_CONVERT_TO_RAW(165,5524 +#define REGISTER_CONVERT_TO_VIRTUAL(156,5228 +#define REGISTER_RAW_SIZE(132,4465 +#define REGISTER_VIRTUAL_SIZE(138,4721 +#define REGISTER_VIRTUAL_TYPE(174,5805 +#define SAVED_PC_AFTER_CALL(55,1929 +#define SKIP_PROLOGUE(42,1493 + +m-suninit.h,29 +#define FILEADDR_ROUND(5,94 + +m-vax.h,791 +#define ABOUT_TO_RETURN(80,2551 +#define FIX_CALL_DUMMY(294,10681 +#define FRAME_ARGS_ADDRESS(199,6661 +#define FRAME_CHAIN(185,6120 +#define FRAME_CHAIN_COMBINE(190,6314 +#define FRAME_CHAIN_VALID(187,6195 +#define FRAME_FIND_SAVED_REGS(222,7517 +#define FRAME_LOCALS_ADDRESS(204,6836 +#define FRAME_NUM_ARGS(209,6972 +#define FRAME_SAVED_PC(194,6418 +#define INIT_STACK(317,11455 +#define INVALID_FLOAT(84,2681 +#define REGISTER_BYTE(127,4329 +#define REGISTER_CONVERTIBLE(150,4942 +#define REGISTER_CONVERT_TO_RAW(161,5257 +#define REGISTER_CONVERT_TO_VIRTUAL(155,5076 +#define REGISTER_RAW_SIZE(132,4491 +#define REGISTER_U_ADDR(112,3753 +#define REGISTER_VIRTUAL_SIZE(137,4644 +#define REGISTER_VIRTUAL_TYPE(167,5425 +#define SAVED_PC_AFTER_CALL(53,1877 +#define SKIP_PROLOGUE(42,1480 + +m-vaxinit.h,29 +#define FILEADDR_ROUND(5,94 + +m68k-opcode.h,138 +#define one(130,5680 +int numopcodes=sizeof(1270,68164 +struct m68k_opcode *endop = m68k_opcodes+sizeof(1272,68226 +#define two(131,5707 + +obstack.h,618 +#define obstack_1grow(252,11387 +#define obstack_1grow_fast(275,12190 +#define obstack_alignment_mask(228,10489 +#define obstack_alloc(263,11796 +#define obstack_base(216,10145 +#define obstack_begin(232,10606 +#define obstack_blank(257,11569 +#define obstack_blank_fast(277,12257 +#define obstack_copy(266,11889 +#define obstack_copy0(269,11994 +#define obstack_finish(279,12314 +#define obstack_free(290,12730 +#define obstack_grow(237,10784 +#define obstack_grow0(244,11064 +#define obstack_init(230,10547 +#define obstack_next_free(220,10254 +#define obstack_object_size(224,10341 +#define obstack_room(272,12101 + +param.h,0 + +symseg.h,0 + +symtab.h,1291 +#define BLOCKLIST(108,3923 +#define BLOCKLIST_BLOCK(137,4911 +#define BLOCKLIST_NBLOCKS(136,4853 +#define BLOCKVECTOR(109,3971 +#define BLOCKVECTOR_BLOCK(139,5030 +#define BLOCKVECTOR_NBLOCKS(138,4970 +#define BLOCK_END(145,5244 +#define BLOCK_FUNCTION(148,5354 +#define BLOCK_NSYMS(146,5280 +#define BLOCK_START(144,5204 +#define BLOCK_SUPERBLOCK(149,5396 +#define BLOCK_SYM(147,5316 +#define LINELIST(113,4071 +#define LINETABLE(114,4116 +#define SYMBOL_BLOCK_VALUE(155,5635 +#define SYMBOL_CLASS(153,5539 +#define SYMBOL_NAME(151,5443 +#define SYMBOL_NAMESPACE(152,5486 +#define SYMBOL_TYPE(156,5692 +#define SYMBOL_VALUE(154,5584 +#define TYPEVECTOR(111,4022 +#define TYPEVECTOR_NTYPES(141,5092 +#define TYPEVECTOR_TYPE(142,5147 +#define TYPE_CODE(170,6307 +#define TYPE_FIELD(174,6453 +#define TYPE_FIELDS(172,6403 +#define TYPE_FIELD_BITPOS(178,6712 +#define TYPE_FIELD_BITSIZE(179,6780 +#define TYPE_FIELD_NAME(176,6571 +#define TYPE_FIELD_PACKED(180,6850 +#define TYPE_FIELD_TYPE(175,6507 +#define TYPE_FIELD_VALUE(177,6635 +#define TYPE_FLAGS(168,6187 +#define TYPE_FUNCTION_TYPE(166,6075 +#define TYPE_LENGTH(167,6138 +#define TYPE_NAME(163,5910 +#define TYPE_NFIELDS(171,6352 +#define TYPE_POINTER_TYPE(165,6014 +#define TYPE_TARGET_TYPE(164,5955 +#define TYPE_UNSIGNED(169,6234 + +value.h,399 +#define COERCE_ARRAY(58,1961 +#define VALUE_ADDRESS(48,1560 +#define VALUE_BITPOS(52,1752 +#define VALUE_BITSIZE(51,1710 +#define VALUE_CONTENTS(46,1469 +#define VALUE_INTERNALVAR(49,1611 +#define VALUE_LVAL(47,1524 +#define VALUE_NEXT(53,1792 +#define VALUE_OFFSET(50,1670 +#define VALUE_REGNO(56,1922 +#define VALUE_REPEATED(54,1828 +#define VALUE_REPETITIONS(55,1872 +#define VALUE_TYPE(45,1433 + +vax-opcode.h,0 + +wait.h,331 +#define WCOREDUMP(13,439 +#define WCOREDUMP(21,690 +#define WIFEXITED(10,338 +#define WIFSIGNALED(9,274 +#define WIFSTOPPED(8,231 +#define WRETCODE(11,377 +#define WRETCODE(19,622 +#define WSETSTOP(15,511 +#define WSETSTOP(23,760 +#define WSTOPSIG(12,408 +#define WSTOPSIG(20,656 +#define WTERMSIG(14,478 +#define WTERMSIG(22,726 + +expread.y,349 +copy_name 929,20955 +end_arglist 516,11399 +free_funcalls 530,11701 +length_of_subexp 963,21859 +parse_c_1 1142,25974 +parse_c_expression 1181,27028 +parse_number 608,13872 +prefixify_expression 943,21291 +prefixify_subexp 1035,23196 +start_arglist 502,11040 +write_exp_elt 547,12040 +write_exp_string 564,12494 +yyerror 920,20800 +yylex 706,15915 diff --git a/gdb/alloca.c b/gdb/alloca.c new file mode 100644 index 00000000000..cfe98f92d2a --- /dev/null +++ b/gdb/alloca.c @@ -0,0 +1,191 @@ +/* + alloca -- (mostly) portable public-domain implementation -- D A Gwyn + + last edit: 86/05/30 rms + include config.h, since on VMS it renames some symbols. + Use xmalloc instead of malloc. + + This implementation of the PWB library alloca() function, + which is used to allocate space off the run-time stack so + that it is automatically reclaimed upon procedure exit, + was inspired by discussions with J. Q. Johnson of Cornell. + + It should work under any C implementation that uses an + actual procedure stack (as opposed to a linked list of + frames). There are some preprocessor constants that can + be defined when compiling for your specific system, for + improved efficiency; however, the defaults should be okay. + + The general concept of this implementation is to keep + track of all alloca()-allocated blocks, and reclaim any + that are found to be deeper in the stack than the current + invocation. This heuristic does not reclaim storage as + soon as it becomes invalid, but it will do so eventually. + + As a special case, alloca(0) reclaims storage without + allocating any. It is a good idea to use alloca(0) in + your main control loop, etc. to force garbage collection. +*/ +#ifndef lint +static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ +#endif + +#ifdef emacs +#include "config.h" +#ifdef static +/* actually, only want this if static is defined as "" + -- this is for usg, in which emacs must undefine static + in order to make unexec workable + */ +#ifndef STACK_DIRECTION +you +lose +-- must know STACK_DIRECTION at compile-time +#endif /* STACK_DIRECTION undefined */ +#endif static +#endif emacs + +#ifdef X3J11 +typedef void *pointer; /* generic pointer type */ +#else +typedef char *pointer; /* generic pointer type */ +#endif + +#define NULL 0 /* null pointer constant */ + +extern void free(); +extern pointer xmalloc(); + +/* + Define STACK_DIRECTION if you know the direction of stack + growth for your system; otherwise it will be automatically + deduced at run-time. + + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown +*/ + +#ifndef STACK_DIRECTION +#define STACK_DIRECTION 0 /* direction unknown */ +#endif + +#if STACK_DIRECTION != 0 + +#define STACK_DIR STACK_DIRECTION /* known at compile-time */ + +#else /* STACK_DIRECTION == 0; need run-time code */ + +static int stack_dir; /* 1 or -1 once known */ +#define STACK_DIR stack_dir + +static void +find_stack_direction (/* void */) +{ + static char *addr = NULL; /* address of first + `dummy', once known */ + auto char dummy; /* to get stack address */ + + if (addr == NULL) + { /* initial entry */ + addr = &dummy; + + find_stack_direction (); /* recurse once */ + } + else /* second entry */ + if (&dummy > addr) + stack_dir = 1; /* stack grew upward */ + else + stack_dir = -1; /* stack grew downward */ +} + +#endif /* STACK_DIRECTION == 0 */ + +/* + An "alloca header" is used to: + (a) chain together all alloca()ed blocks; + (b) keep track of stack depth. + + It is very important that sizeof(header) agree with malloc() + alignment chunk size. The following default should work okay. +*/ + +#ifndef ALIGN_SIZE +#define ALIGN_SIZE sizeof(double) +#endif + +typedef union hdr +{ + char align[ALIGN_SIZE]; /* to force sizeof(header) */ + struct + { + union hdr *next; /* for chaining headers */ + char *deep; /* for stack depth measure */ + } h; +} header; + +/* + alloca( size ) returns a pointer to at least `size' bytes of + storage which will be automatically reclaimed upon exit from + the procedure that called alloca(). Originally, this space + was supposed to be taken from the current stack frame of the + caller, but that method cannot be made to work for some + implementations of C, for example under Gould's UTX/32. +*/ + +static header *last_alloca_header = NULL; /* -> last alloca header */ + +pointer +alloca (size) /* returns pointer to storage */ + unsigned size; /* # bytes to allocate */ +{ + auto char probe; /* probes stack depth: */ + register char *depth = &probe; + +#if STACK_DIRECTION == 0 + if (STACK_DIR == 0) /* unknown growth direction */ + find_stack_direction (); +#endif + + /* Reclaim garbage, defined as all alloca()ed storage that + was allocated from deeper in the stack than currently. */ + + { + register header *hp; /* traverses linked list */ + + for (hp = last_alloca_header; hp != NULL;) + if (STACK_DIR > 0 && hp->h.deep > depth + || STACK_DIR < 0 && hp->h.deep < depth) + { + register header *np = hp->h.next; + + free ((pointer) hp); /* collect garbage */ + + hp = np; /* -> next header */ + } + else + break; /* rest are not deeper */ + + last_alloca_header = hp; /* -> last valid storage */ + } + + if (size == 0) + return NULL; /* no allocation required */ + + /* Allocate combined header + user data storage. */ + + { + register pointer new = xmalloc (sizeof (header) + size); + /* address of header */ + + ((header *)new)->h.next = last_alloca_header; + ((header *)new)->h.deep = depth; + + last_alloca_header = (header *)new; + + /* User storage begins just after header. */ + + return (pointer)((char *)new + sizeof(header)); + } +} + diff --git a/gdb/bar.c b/gdb/bar.c new file mode 100644 index 00000000000..59e559f1532 --- /dev/null +++ b/gdb/bar.c @@ -0,0 +1,13 @@ +main() { + int i; + + for (i = 0; i >= 0; i++) + bar(); +} + +bar() +{ + int i; + + i = 10; +} diff --git a/gdb/bar.nm b/gdb/bar.nm new file mode 100644 index 00000000000..6f2df5ce9bc --- /dev/null +++ b/gdb/bar.nm @@ -0,0 +1,65 @@ +0000003e - 00 0002 RBRAC +000020de - 00 000d SLINE +000020d6 - 00 000c SLINE +000020c8 - 00 0009 SLINE +000020c4 - 00 0006 SLINE +00000024 - 00 0002 RBRAC +000020be - 00 0004 SLINE +000020b8 - 00 0005 SLINE +000020ae - 00 0004 SLINE +0000000e - 00 0002 LBRAC +000020d6 - 00 0009 SLINE +000020e4 - 00 ffff SLINE +000020ae - 00 0001 SLINE +000020a0 - 00 0001 SLINE +00000036 - 00 0002 LBRAC +000020e4 t -lg +00000000 - 00 0000 LSYM ???:t(0,12)=(0,1) +00002098 t Fcrt1.o +0002001c D _Fmode +00020020 D _Fstatus +0000215c T __cleanup +00002164 T __exit +00020052 D __exit_nhandlers +00020056 D __exit_tnames +00020018 D __skybase +000020c8 T _bar +00020000 D _environ +00020118 D _errno +00002110 T _exit +00002164 t _exit.o +000020e4 T _finitfp_ +00020010 D _fp_state_mc68881 +0002000c D _fp_state_skyffp +00020008 D _fp_state_software +00020014 D _fp_state_sunfpa +00020004 D _fp_switch +000020a0 T _main +000020a0 - 00 0000 SO bar.c +000020a0 t bar.o +000020c8 - 00 0004 FUN bar:F(0,1) +0000216c T cerror +0000216c t cerror.o +00000000 - 00 0000 LSYM char:t(0,2)=r(0,2);0;127; +00002020 t crt0.o +00000000 - 00 0000 LSYM double:t(0,10)=r(0,1);8;0; +00002110 t exit.o +0000215c t fakcu.o +000020e4 t finitfp.o +00000000 - 00 0000 LSYM float:t(0,9)=r(0,1);4;0; +00002110 t fp_globals.o +00002098 T fsoft_used +fffffffc - 00 0004 LSYM i:(0,1) +fffffffc - 00 0004 LSYM i:(0,1) +00000000 - 00 0000 LSYM int:t(0,1)=r(0,1);-2147483648;2147483647; +000020e4 - 00 0000 SO libg.s +00000000 - 00 0000 LSYM long:t(0,3)=r(0,1);-2147483648;2147483647; +000020a0 - 00 0004 FUN main:F(0,1) +00000000 - 00 0000 LSYM short:t(0,4)=r(0,1);-32768;32767; +00002020 T start +00002098 T start_float +00000000 - 00 0000 LSYM unsigned char:t(0,5)=r(0,1);0;255; +00000000 - 00 0000 LSYM unsigned int:t(0,8)=r(0,1);0;-1; +00000000 - 00 0000 LSYM unsigned long:t(0,7)=r(0,1);0;-1; +00000000 - 00 0000 LSYM unsigned short:t(0,6)=r(0,1);0;65535; +00000000 - 00 0000 LSYM void:t(0,11)=(0,11) diff --git a/gdb/bar.s b/gdb/bar.s new file mode 100644 index 00000000000..96b4c073a94 --- /dev/null +++ b/gdb/bar.s @@ -0,0 +1,93 @@ + .stabs "bar.c",0144,0,0,LL0 +LL0: + .data + .stabs "int:t(0,1)=r(0,1);-2147483648;2147483647;",0x80,0,0,0 + .stabs "char:t(0,2)=r(0,2);0;127;",0x80,0,0,0 + .stabs "long:t(0,3)=r(0,1);-2147483648;2147483647;",0x80,0,0,0 + .stabs "short:t(0,4)=r(0,1);-32768;32767;",0x80,0,0,0 + .stabs "unsigned char:t(0,5)=r(0,1);0;255;",0x80,0,0,0 + .stabs "unsigned short:t(0,6)=r(0,1);0;65535;",0x80,0,0,0 + .stabs "unsigned long:t(0,7)=r(0,1);0;-1;",0x80,0,0,0 + .stabs "unsigned int:t(0,8)=r(0,1);0;-1;",0x80,0,0,0 + .stabs "float:t(0,9)=r(0,1);4;0;",0x80,0,0,0 + .stabs "double:t(0,10)=r(0,1);8;0;",0x80,0,0,0 + .stabs "void:t(0,11)=(0,11)",0x80,0,0,0 + .stabs "???:t(0,12)=(0,1)",0x80,0,0,0 + .stabs "main:F(0,1)",0x24,0,4,_main + .text + .stabn 0104,0,1,LL1 +LL1: +|#PROC# 04 + .globl _main +_main: +|#PROLOGUE# 0 + link a6,#0 + addl #-LF12,sp + moveml #LS12,sp@ +|#PROLOGUE# 1 + .stabn 0104,0,1,LL2 +LL2: + .stabs "i:(0,1)",0x80,0,4,-4 + .stabn 0300,0,2,LL3 +LL3: + .stabn 0104,0,4,LL4 +LL4: + clrl a6@(-0x4) +L16: + tstl a6@(-0x4) + jlt L15 + .stabn 0104,0,5,LL5 +LL5: + jbsr _bar +L14: + .stabn 0104,0,4,LL6 +LL6: + addql #0x1,a6@(-0x4) + jra L16 +L15: + .stabn 0340,0,2,LL7 +LL7: + .stabn 0104,0,6,LL8 +LL8: +LE12: + unlk a6 + rts + LF12 = 4 + LS12 = 0x0 + LFF12 = 4 + LSS12 = 0x0 + LP12 = 0x8 + .data + .stabs "bar:F(0,1)",0x24,0,4,_bar + .text + .stabn 0104,0,9,LL9 +LL9: +|#PROC# 04 + .globl _bar +_bar: +|#PROLOGUE# 0 + link a6,#0 + addl #-LF18,sp + moveml #LS18,sp@ +|#PROLOGUE# 1 + .stabn 0104,0,9,LL10 +LL10: + .stabs "i:(0,1)",0x80,0,4,-4 + .stabn 0300,0,2,LL11 +LL11: + .stabn 0104,0,12,LL12 +LL12: + movl #0xa,a6@(-0x4) + .stabn 0340,0,2,LL13 +LL13: + .stabn 0104,0,13,LL14 +LL14: +LE18: + unlk a6 + rts + LF18 = 4 + LS18 = 0x0 + LFF18 = 4 + LSS18 = 0x0 + LP18 = 0x8 + .data diff --git a/gdb/bar.sym b/gdb/bar.sym new file mode 100644 index 00000000000..a3f41315bb3 --- /dev/null +++ b/gdb/bar.sym @@ -0,0 +1,51 @@ +Symtab for file libg.s + +Line table: + + line 2 at 20e4 + +Blockvector: + +block #000 (object 0x56f90) [0x20e4..0x20e4] + block #001 (object 0x56f7c) [0x20e4..0x20e4] (under 0x56f90) + + +Symtab for file bar.c + +Line table: + + line 1 at 20a0 + line 1 at 20ae + line 4 at 20ae + line 5 at 20b8 + line 4 at 20be + line 6 at 20c4 + line 9 at 20c8 + line 9 at 20d6 + line 12 at 20d6 + line 13 at 20de + +Blockvector: + +block #000 (object 0x56f4c) [0x20a0..0x20e4] + int bar; block (object 0x56ef0) starting at 0x20c8, + int main; block (object 0x56ea8) starting at 0x20a0, + block #001 (object 0x56f08) [0x20a0..0x20e4] (under 0x56f4c) + typedef int ???; + typedef char char; + typedef double double; + typedef float float; + typedef int int; + typedef int long; + typedef short short; + typedef unsigned char unsigned char; + typedef unsigned int unsigned int; + typedef unsigned int unsigned long; + typedef unsigned short unsigned short; + typedef void void; + block #002 (object 0x56ea8) [0x20a0..0x20c8] (under 0x56f08) main + int i; local at 0xfffffffc, + block #003 (object 0x56ef0) [0x20c8..0x20e4] (under 0x56f08) bar + int i; local at 0xfffffffc, + + diff --git a/gdb/blockframe.c b/gdb/blockframe.c new file mode 100644 index 00000000000..5ed025c423e --- /dev/null +++ b/gdb/blockframe.c @@ -0,0 +1,333 @@ +/* Get info from stack frames; + convert between frames, blocks, functions and pc values. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +/* Address of end of first object file. + This file is assumed to be a startup file + and frames with pc's inside it + are treated as nonexistent. */ + +CORE_ADDR first_object_file_end; + +/* Address of innermost stack frame (contents of FP register) */ + +static FRAME current_frame; + +struct block *block_for_pc (); +CORE_ADDR get_pc_function_start (); + +START_FILE + +/* Return the innermost (currently executing) stack frame. */ + +FRAME +get_current_frame () +{ + /* We assume its address is kept in a general register; + param.h says which register. */ + + return current_frame; +} + +void +set_current_frame (frame) + FRAME frame; +{ + current_frame = frame; +} + +/* Return the frame that called FRAME. + If FRAME is the original frame (it has no caller), return 0. */ + +FRAME +get_prev_frame (frame) + FRAME frame; +{ + CORE_ADDR pointer; + /* The caller of "no frame" is the innermost frame. */ + if (frame == 0) + return get_current_frame (); + + /* Two macros defined in param.h specify the machine-dependent + actions to be performed here. */ + /* First, get the frame's chain-pointer. + If that is zero, the frame is the outermost frame. */ + pointer = FRAME_CHAIN (frame); + if (!FRAME_CHAIN_VALID (pointer, frame)) + return 0; + /* If frame has a caller, combine the chain pointer and the frame's own + address to get the address of the caller. */ + return FRAME_CHAIN_COMBINE (pointer, frame); +} + +/* Return a structure containing various interesting information + about a specified stack frame. */ + +struct frame_info +get_frame_info (frame) + FRAME frame; +{ + struct frame_info val; + FRAME current = get_current_frame (); + register FRAME frame1; + + val.frame = frame; + + if (frame == current) + { + val.pc = read_pc (); + val.next_frame = 0; + } + else + { + for (frame1 = current; frame1; frame1 = get_prev_frame (frame1)) + { + QUIT; + if (frame1 == frame) + break; + + val.pc = FRAME_SAVED_PC (frame1); + val.next_frame = frame1; + } + } + + return val; +} + +/* Return a structure containing various interesting information + about the frame that called FRAME. + + This is much faster than get_frame_info (get_prev_frame (FRAME)) + because it does not need to search the entire stack + to find the frame called by the one being described -- that is FRAME. */ + +struct frame_info +get_prev_frame_info (next_frame) + FRAME next_frame; +{ + struct frame_info val; + register FRAME frame = get_prev_frame (next_frame); + + val.frame = frame; + val.next_frame = next_frame; + + if (next_frame == 0) + { + val.pc = read_pc (); + } + else + { + val.pc = FRAME_SAVED_PC (next_frame); + } + + return val; +} + +CORE_ADDR +get_frame_pc (frame) + FRAME frame; +{ + struct frame_info fi; + fi = get_frame_info (frame); + return fi.pc; +} + +/* Find the addresses in which registers are saved in FRAME. */ + +void +get_frame_saved_regs (frame_info_addr, saved_regs_addr) + struct frame_info *frame_info_addr; + struct frame_saved_regs *saved_regs_addr; +{ + FRAME_FIND_SAVED_REGS (*frame_info_addr, *saved_regs_addr); +} + +/* Return the innermost lexical block in execution + in a specified stack frame. The frame address is assumed valid. */ + +struct block * +get_frame_block (frame) + FRAME frame; +{ + struct frame_info fi; + + fi = get_frame_info (frame); + return block_for_pc (fi.pc); +} + +struct block * +get_current_block () +{ + return block_for_pc (read_pc ()); +} + +CORE_ADDR +get_pc_function_start (pc) + CORE_ADDR pc; +{ + register struct block *bl = block_for_pc (pc); + register struct symbol *symbol; + if (bl == 0) + { + register int misc_index = find_pc_misc_function (pc); + if (misc_index >= 0) + return misc_function_vector[misc_index].address; + return 0; + } + symbol = block_function (bl); + bl = SYMBOL_BLOCK_VALUE (symbol); + return BLOCK_START (bl); +} + +/* Return the symbol for the function executing in frame FRAME. */ + +struct symbol * +get_frame_function (frame) + FRAME frame; +{ + register struct block *bl = get_frame_block (frame); + if (bl == 0) + return 0; + return block_function (bl); +} + +/* Return the innermost lexical block containing the specified pc value, + or 0 if there is none. */ + +struct block * +block_for_pc (pc) + register CORE_ADDR pc; +{ + register struct block *b; + register int bot, top, half; + register struct symtab *s; + struct blockvector *bl; + + /* First search all symtabs for one whose file contains our pc */ + + for (s = symtab_list; s; s = s->next) + { + bl = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bl, 0); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc) + break; + } + + if (s == 0) + return 0; + + /* Then search that symtab for the smallest block that wins. */ + /* Use binary search to find the last block that starts before PC. */ + + bot = 0; + top = BLOCKVECTOR_NBLOCKS (bl); + + while (top - bot > 1) + { + half = (top - bot + 1) >> 1; + b = BLOCKVECTOR_BLOCK (bl, bot + half); + if (BLOCK_START (b) <= pc) + bot += half; + else + top = bot + half; + } + + /* Now search backward for a block that ends after PC. */ + + while (bot >= 0) + { + b = BLOCKVECTOR_BLOCK (bl, bot); + if (BLOCK_END (b) > pc) + return b; + bot--; + } + + return 0; +} + +/* Return the function containing pc value PC. + Returns 0 if function is not known. */ + +struct symbol * +find_pc_function (pc) + CORE_ADDR pc; +{ + register struct block *b = block_for_pc (pc); + if (b == 0) + return 0; + return block_function (b); +} + +/* Find the misc function whose address is the largest + while being less than PC. Return its index in misc_function_vector. + Returns -1 if PC is not in suitable range. */ + +int +find_pc_misc_function (pc) + CORE_ADDR pc; +{ + register int i; + + /* Note that the last thing in the vector is always _etext. */ + for (i = 0; i < misc_function_count; i++) + { + if (pc < misc_function_vector[i].address) + return i - 1; + } + return -1; +} + +/* Return the innermost stack frame executing inside of the specified block, + or zero if there is no such frame. */ + +FRAME +block_innermost_frame (block) + struct block *block; +{ + struct frame_info fi; + register FRAME frame; + register CORE_ADDR start = BLOCK_START (block); + register CORE_ADDR end = BLOCK_END (block); + + frame = 0; + while (1) + { + fi = get_prev_frame_info (frame); + frame = fi.frame; + if (frame == 0) + return 0; + if (fi.pc >= start && fi.pc < end) + return frame; + } +} + +static +initialize () +{ +} + +END_FILE diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c new file mode 100644 index 00000000000..82e40757d47 --- /dev/null +++ b/gdb/breakpoint.c @@ -0,0 +1,1096 @@ +/* Everything about breakpoints, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +#include + +/* This is the sequence of bytes we insert for a breakpoint. */ + +static char break_insn[] = BREAKPOINT; + +/* States of enablement of breakpoint. + `temporary' means disable when hit. + `once' means delete when hit. */ + +enum enable { disabled, enabled, temporary, delete}; + +struct breakpoint +{ + struct breakpoint *next; + /* Number assigned to distinguish breakpoints. */ + int number; + /* Address to break at. */ + CORE_ADDR address; + /* Line number of this address. Redundant. */ + int line_number; + /* Symtab of file of this address. Redundant. */ + struct symtab *symtab; + /* Zero means disabled; remember the info but don't break here. */ + enum enable enable; + /* Number of stops at this breakpoint that should + be continued automatically before really stopping. */ + int ignore_count; + /* "Real" contents of byte where breakpoint has been inserted. + Valid only when breakpoints are in the program. */ + char shadow_contents[sizeof break_insn]; + /* Nonzero if this breakpoint is now inserted. */ + char inserted; + /* Nonzero if this is not the first breakpoint in the list + for the given address. */ + char duplicate; + /* Chain of command lines to execute when this breakpoint is hit. */ + struct command_line *commands; + /* Stack depth (frame). If nonzero, break only if fp equals this. */ + FRAME frame; + /* Conditional. Break only if this expression's value is nonzero. */ + struct expression *cond; +}; + +#define ALL_BREAKPOINTS(b) for (b = breakpoint_chain; b; b = b->next) + +/* Chain of all breakpoints defined. */ + +struct breakpoint *breakpoint_chain; + +/* Number of last breakpoint made. */ + +static int breakpoint_count; + +/* Default address, symtab and line to put a breakpoint at + for "break" command with no arg. + if default_breakpoint_valid is zero, the other three are + not valid, and "break" with no arg is an error. + + This set by print_stack_frame, which calls set_default_breakpoint. */ + +int default_breakpoint_valid; +CORE_ADDR default_breakpoint_address; +struct symtab *default_breakpoint_symtab; +int default_breakpoint_line; + +/* Remaining commands (not yet executed) + of last breakpoint hit. */ + +struct command_line *breakpoint_commands; + +START_FILE + +extern char *read_line (); + +static void delete_breakpoint (); +void clear_momentary_breakpoints (); +void breakpoint_auto_delete (); + +/* condition N EXP -- set break condition of breakpoint N to EXP. */ + +static void +condition_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b; + register char *p; + register int bnum; + register struct expression *expr; + + if (arg == 0) + error_no_arg ("breakpoint number"); + + p = arg; + while (*p >= '0' && *p <= '9') p++; + bnum = atoi (arg); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->cond) + free (b->cond); + if (*p == 0) + { + b->cond = 0; + if (from_tty) + printf ("Breakpoint %d now unconditional.\n", bnum); + } + else + { + if (*p != ' ' && *p != '\t') + error ("Arguments must be an integer (breakpoint number) and an expression."); + + /* Find start of expression */ + while (*p == ' ' || *p == '\t') p++; + + arg = p; + b->cond = (struct expression *) parse_c_1 (&arg, block_for_pc (b->address)); + } + return; + } + + error ("No breakpoint number %d.", bnum); +} + +static void +commands_command (arg) + char *arg; +{ + register struct breakpoint *b; + register char *p, *p1; + register int bnum; + struct command_line *l; + + if (arg == 0) + error_no_arg ("breakpoint number"); + + /* If we allowed this, we would have problems with when to + free the storage, if we change the commands currently + being read from. */ + + if (breakpoint_commands) + error ("Can't use the \"commands\" command among a breakpoint's commands."); + + p = arg; + if (! (*p >= '0' && *p <= '9')) + error ("Argument must be integer (a breakpoint number)."); + + while (*p >= '0' && *p <= '9') p++; + if (*p) + error ("Unexpected extra arguments following breakpoint number."); + + bnum = atoi (arg); + + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (input_from_terminal_p ()) + printf ("Type commands for when breakpoint %d is hit, one per line.\n\ +End with a line saying just \"end\".\n", bnum); + l = read_command_lines (); + free_command_lines (&b->commands); + b->commands = l; + return; + } + error ("No breakpoint number %d.", bnum); +} + +/* Called from command loop to execute the commands + associated with the breakpoint we just stopped at. */ + +void +do_breakpoint_commands () +{ + while (breakpoint_commands) + { + char *line = breakpoint_commands->line; + breakpoint_commands = breakpoint_commands->next; + execute_command (line, 0); + /* If command was "cont", breakpoint_commands is now 0, + of if we stopped at yet another breakpoint which has commands, + it is now the commands for the new breakpoint. */ + } + clear_momentary_breakpoints (); +} + +/* Used when the program is proceeded, to eliminate any remaining + commands attached to the previous breakpoint we stopped at. */ + +void +clear_breakpoint_commands () +{ + breakpoint_commands = 0; + breakpoint_auto_delete (0); +} + +/* Functions to get and set the current list of pending + breakpoint commands. These are used by run_stack_dummy + to preserve the commands around a function call. */ + +struct command_line * +get_breakpoint_commands () +{ + return breakpoint_commands; +} + +void +set_breakpoint_commands (cmds) + struct command_line *cmds; +{ + breakpoint_commands = cmds; +} + +/* insert_breakpoints is used when starting or continuing the program. + remove_breakpoints is used when the program stops. + Both return zero if successful, + or an `errno' value if could not write the inferior. */ + +int +insert_breakpoints () +{ + register struct breakpoint *b; + int val; + +/* printf ("Inserting breakpoints.\n"); */ + ALL_BREAKPOINTS (b) + if (b->enable != disabled && ! b->inserted && ! b->duplicate) + { + read_memory (b->address, b->shadow_contents, sizeof break_insn); + val = write_memory (b->address, break_insn, sizeof break_insn); + if (val) + return val; +/* printf ("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", + b->address, b->shadow_contents[0], b->shadow_contents[1]); */ + b->inserted = 1; + } + return 0; +} + +int +remove_breakpoints () +{ + register struct breakpoint *b; + int val; + +/* printf ("Removing breakpoints.\n"); */ + ALL_BREAKPOINTS (b) + if (b->inserted) + { + val = write_memory (b->address, b->shadow_contents, sizeof break_insn); + if (val) + return val; + b->inserted = 0; +/* printf ("Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", + b->address, b->shadow_contents[0], b->shadow_contents[1]); */ + } + + return 0; +} + +/* Clear the "inserted" flag in all breakpoints. + This is done when the inferior is loaded. */ + +int +mark_breakpoints_out () +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + b->inserted = 0; +} + +/* breakpoint_here_p (PC) returns 1 if an enabled breakpoint exists at PC. + When continuing from a location with a breakpoint, + we actually single step once before calling insert_breakpoints. */ + +int +breakpoint_here_p (pc) + CORE_ADDR pc; +{ + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == pc) + return 1; + + return 0; +} + +/* Return 0 if PC is not the address just after a breakpoint, + or -1 if breakpoint says do not stop now, + or -2 if breakpoint says it has deleted itself and don't stop, + or -3 if hit a breakpoint number -3 (delete when program stops), + or else the number of the breakpoint, + with 0x1000000 added for a silent breakpoint. */ + +int +breakpoint_stop_status (pc, frame) + CORE_ADDR pc; + FRAME frame; +{ + register struct breakpoint *b; + register int cont = 0; + + /* Get the address where the breakpoint would have been. */ + pc -= DECR_PC_AFTER_BREAK; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == pc) + { + if (b->frame && b->frame != frame) + cont = -1; + else + { + int value_zero; + if (b->cond) + { + value_zero = value_zerop (evaluate_expression (b->cond)); + free_all_values (); + } + if (b->cond && value_zero) + { + cont = -1; + } + else if (b->ignore_count > 0) + { + b->ignore_count--; + cont = -1; + } + else + { + if (b->enable == temporary) + b->enable = disabled; + breakpoint_commands = b->commands; + if (breakpoint_commands + && !strcmp ("silent", breakpoint_commands->line)) + { + breakpoint_commands = breakpoint_commands->next; + return 0x1000000 + b->number; + } + return b->number; + } + } + } + + return cont; +} + +static void +breakpoint_1 (bnum) + int bnum; +{ + register struct breakpoint *b; + register struct command_line *l; + register struct symbol *sym; + CORE_ADDR last_addr = -1; + + ALL_BREAKPOINTS (b) + if (bnum == -1 || bnum == b->number) + { + printf ("#%-3d %c 0x%08x ", b->number, + "nyod"[(int) b->enable], + b->address); + last_addr = b->address; + if (b->symtab) + { + sym = find_pc_function (b->address); + if (sym) + printf (" in %s (%s line %d)", SYMBOL_NAME (sym), + b->symtab->filename, b->line_number); + else + printf ("%s line %d", b->symtab->filename, b->line_number); + } + printf ("\n"); + + if (b->ignore_count) + printf ("\tignore next %d hits\n", b->ignore_count); + if (b->frame) + printf ("\tstop only in stack frame at 0x%x\n", b->frame); + if (b->cond) + { + printf ("\tbreak only if "); + print_expression (b->cond, stdout); + printf ("\n"); + } + if (l = b->commands) + while (l) + { + printf ("\t%s\n", l->line); + l = l->next; + } + } + + if (last_addr != -1) + set_next_address (last_addr); +} + +static void +breakpoints_info (bnum_exp) + char *bnum_exp; +{ + int bnum = -1; + + if (bnum_exp) + bnum = parse_and_eval_address (bnum_exp); + else if (breakpoint_chain == 0) + printf ("No breakpoints.\n"); + else + printf ("Breakpoints:\n\ +Num Enb Address Where\n"); + + breakpoint_1 (bnum); +} + +/* Print a message describing any breakpoints set at PC. */ + +static void +describe_other_breakpoints (pc) + register CORE_ADDR pc; +{ + register int others = 0; + register struct breakpoint *b; + + ALL_BREAKPOINTS (b) + if (b->address == pc) + others++; + if (others > 0) + { + printf ("Note: breakpoint%s ", (others > 1) ? "s" : ""); + ALL_BREAKPOINTS (b) + if (b->address == pc) + { + others--; + printf ("%d%s%s ", + b->number, + (b->enable == disabled) ? " (disabled)" : "", + (others > 1) ? "," : ((others == 1) ? " and" : "")); + } + printf (" also set at pc 0x%x\n", pc); + } +} + +/* Set the default place to put a breakpoint + for the `break' command with no arguments. */ + +void +set_default_breakpoint (valid, addr, symtab, line) + int valid; + CORE_ADDR addr; + struct symtab *symtab; + int line; +{ + default_breakpoint_valid = valid; + default_breakpoint_address = addr; + default_breakpoint_symtab = symtab; + default_breakpoint_line = line; +} + +/* Rescan breakpoints at address ADDRESS, + marking the first one as "first" and any others as "duplicates". + This is so that the bpt instruction is only inserted once. */ + +static void +check_duplicates (address) + CORE_ADDR address; +{ + register struct breakpoint *b; + register int count = 0; + + ALL_BREAKPOINTS (b) + if (b->enable != disabled && b->address == address) + { + count++; + b->duplicate = count > 1; + } +} + +/* Low level routine to set a breakpoint. + Takes as args the three things that every breakpoint must have. + Returns the breakpoint object so caller can set other things. + Does not set the breakpoint number! + Does not print anything. */ + +static struct breakpoint * +set_raw_breakpoint (sal) + struct symtab_and_line sal; +{ + register struct breakpoint *b, *b1; + + b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint)); + bzero (b, sizeof *b); + b->address = sal.pc; + b->symtab = sal.symtab; + b->line_number = sal.line; + b->enable = enabled; + b->next = 0; + + /* Add this breakpoint to the end of the chain + so that a list of breakpoints will come out in order + of increasing numbers. */ + + b1 = breakpoint_chain; + if (b1 == 0) + breakpoint_chain = b; + else + { + while (b1->next) + b1 = b1->next; + b1->next = b; + } + + check_duplicates (sal.pc); + + return b; +} + +/* Set a breakpoint that will evaporate an end of command + at address specified by SAL. + Restrict it to frame FRAME if FRAME is nonzero. */ + +void +set_momentary_breakpoint (sal, frame) + struct symtab_and_line sal; + FRAME frame; +{ + register struct breakpoint *b; + b = set_raw_breakpoint (sal); + b->number = -3; + b->enable = delete; + b->frame = frame; +} + +void +clear_momentary_breakpoints () +{ + register struct breakpoint *b; + ALL_BREAKPOINTS (b) + if (b->number == -3) + { + delete_breakpoint (b); + break; + } +} + +/* Set a breakpoint from a symtab and line. + If TEMPFLAG is nonzero, it is a temporary breakpoint. + Print the same confirmation messages that the breakpoint command prints. */ + +void +set_breakpoint (s, line, tempflag) + struct symtab *s; + int line; + int tempflag; +{ + register struct breakpoint *b; + struct symtab_and_line sal; + + sal.symtab = s; + sal.line = line; + sal.pc = find_line_pc (sal.symtab, sal.line); + if (sal.pc == 0) + error ("No line %d in file \"%s\".\n", sal.line, sal.symtab->filename); + else + { + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + b->number = ++breakpoint_count; + b->cond = 0; + if (tempflag) + b->enable = temporary; + + printf ("Breakpoint %d at 0x%x", b->number, b->address); + if (b->symtab) + printf (": file %s, line %d.", b->symtab->filename, b->line_number); + printf ("\n"); + } +} + +/* Set a breakpoint according to ARG (function, linenum or *address) + and make it temporary if TEMPFLAG is nonzero. */ + +static void +break_command_1 (arg, tempflag, from_tty) + char *arg; + int tempflag, from_tty; +{ + struct symtab_and_line sal; + register struct expression *cond = 0; + register struct breakpoint *b; + + sal.pc = 0; + + if (arg) + { + sal = decode_line_1 (&arg, 1, 0, 0); + + if (sal.pc == 0 && sal.symtab != 0) + { + sal.pc = find_line_pc (sal.symtab, sal.line); + if (sal.pc == 0) + error ("No line %d in file \"%s\".", + sal.line, sal.symtab->filename); + } + + while (*arg) + { + if (arg[0] == 'i' && arg[1] == 'f' + && (arg[2] == ' ' || arg[2] == '\t')) + cond = (struct expression *) parse_c_1 ((arg += 2, &arg), + block_for_pc (sal.pc)); + else + error ("Junk at end of arguments."); + } + } + else if (default_breakpoint_valid) + { + sal.pc = default_breakpoint_address; + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + } + else + error ("No default breakpoint address now."); + + if (from_tty) + describe_other_breakpoints (sal.pc); + + b = set_raw_breakpoint (sal); + b->number = ++breakpoint_count; + b->cond = cond; + if (tempflag) + b->enable = temporary; + + printf ("Breakpoint %d at 0x%x", b->number, b->address); + if (b->symtab) + printf (": file %s, line %d.", b->symtab->filename, b->line_number); + printf ("\n"); +} + +static void +break_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, 0, from_tty); +} + +static void +tbreak_command (arg, from_tty) + char *arg; + int from_tty; +{ + break_command_1 (arg, 1, from_tty); +} + +static void +clear_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b, *b1; + struct symtab_and_line sal; + register struct breakpoint *found; + + if (arg) + sal = decode_line_spec (arg, 1); + else + { + sal.line = default_breakpoint_line; + sal.symtab = default_breakpoint_symtab; + sal.pc = 0; + if (sal.symtab == 0) + error ("No source file specified."); + } + + /* If exact pc given, clear bpts at that pc. + But if sal.pc is zero, clear all bpts on specified line. */ + + found = (struct breakpoint *) 0; + while (breakpoint_chain + && (sal.pc ? breakpoint_chain->address == sal.pc + : (breakpoint_chain->symtab == sal.symtab + && breakpoint_chain->line_number == sal.line))) + { + b1 = breakpoint_chain; + breakpoint_chain = b1->next; + b1->next = found; + found = b1; + } + + ALL_BREAKPOINTS (b) + while (b->next + && (sal.pc ? b->next->address == sal.pc + : (b->next->symtab == sal.symtab + && b->next->line_number == sal.line))) + { + b1 = b->next; + b->next = b1->next; + b1->next = found; + found = b1; + } + + if (found == 0) + error ("No breakpoint at %s.", arg); + + if (found->next) from_tty = 1; /* Alwats report if deleted more than one */ + if (from_tty) printf ("Deleted breakpoint%s ", found->next ? "s" : ""); + while (found) + { + if (from_tty) printf ("%d ", found->number); + b1 = found->next; + delete_breakpoint (found); + found = b1; + } + if (from_tty) putchar ('\n'); +} + +/* Delete breakpoint number BNUM if it is a `delete' breakpoint. + This is called after breakpoint BNUM has been hit. + Also delete any breakpoint numbered -3 unless there are breakpoint + commands to be executed. */ + +void +breakpoint_auto_delete (bnum) + int bnum; +{ + register struct breakpoint *b; + if (bnum != 0) + ALL_BREAKPOINTS (b) + if (b->number == bnum) + { + if (b->enable == delete) + delete_breakpoint (b); + break; + } + if (breakpoint_commands == 0) + clear_momentary_breakpoints (); +} + +static void +delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + register struct breakpoint *b; + + if (bpt->inserted) + write_memory (bpt->address, bpt->shadow_contents, sizeof break_insn); + + if (breakpoint_chain == bpt) + breakpoint_chain = bpt->next; + + ALL_BREAKPOINTS (b) + if (b->next == bpt) + { + b->next = bpt->next; + break; + } + + check_duplicates (bpt->address); + + free_command_lines (&bpt->commands); + if (bpt->cond) + free (bpt->cond); + free (bpt); +} + +void map_breakpoint_numbers (); + +static void +delete_command (arg, from_tty) + char *arg; + int from_tty; +{ + register struct breakpoint *b, *b1; + + if (arg == 0) + { + if (!from_tty || query ("Delete all breakpoints? ")) + { + /* No arg; clear all breakpoints. */ + while (breakpoint_chain) + delete_breakpoint (breakpoint_chain); + } + } + else + map_breakpoint_numbers (arg, delete_breakpoint); +} + +/* Delete all breakpoints. + Done when new symtabs are loaded, since the break condition expressions + may become invalid, and the breakpoints are probably wrong anyway. */ + +void +clear_breakpoints () +{ + delete_command (0, 0); +} + +/* Set ignore-count of breakpoint number BPTNUM to COUNT. + If from_tty is nonzero, it prints a message to that effect, + which ends with a period (no newline). */ + +void +set_ignore_count (bptnum, count, from_tty) + int bptnum, count, from_tty; +{ + register struct breakpoint *b; + + if (count < 0) + count = 0; + + ALL_BREAKPOINTS (b) + if (b->number == bptnum) + { + b->ignore_count = count; + if (!from_tty) + return; + else if (count == 0) + printf ("Will stop next time breakpoint %d is reached.", bptnum); + else if (count == 1) + printf ("Will ignore next crossing of breakpoint %d.", bptnum); + else + printf ("Will ignore next %d crossings of breakpoint %d.", + count, bptnum); + return; + } + + error ("No breakpoint number %d.", bptnum); +} + +/* Command to set ignore-count of breakpoint N to COUNT. */ + +static void +ignore_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p; + register int num; + + if (p == 0) + error_no_arg ("a breakpoint number"); + + p = args; + while (*p >= '0' && *p <= '9') p++; + if (*p && *p != ' ' && *p != '\t') + error ("First argument must be a breakpoint number."); + + num = atoi (args); + + if (*p == 0) + error ("Second argument (specified ignore-count) is missing."); + + set_ignore_count (num, parse_and_eval_address (p), from_tty); + printf ("\n"); +} + +/* Call FUNCTION on each of the breakpoints + whose numbers are given in ARGS. */ + +static void +map_breakpoint_numbers (args, function) + char *args; + void (*function) (); +{ + register char *p = args; + register char *p1; + register int num; + register struct breakpoint *b; + + if (p == 0) + error_no_arg ("one or more breakpoint numbers"); + + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be breakpoint numbers."); + + num = atoi (p); + + ALL_BREAKPOINTS (b) + if (b->number == num) + { + function (b); + goto win; + } + printf ("No breakpoint number %d.\n", num); + win: + p = p1; + while (*p == ' ' || *p == '\t') p++; + } +} + +static void +enable_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = enabled; + + check_duplicates (bpt->address); +} + +static void +enable_command (args) + char *args; +{ + map_breakpoint_numbers (args, enable_breakpoint); +} + +static void +disable_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = disabled; + + check_duplicates (bpt->address); +} + +static void +disable_command (args) + char *args; +{ + register struct breakpoint *bpt; + if (args == 0) + ALL_BREAKPOINTS (bpt) + disable_breakpoint (bpt); + else + map_breakpoint_numbers (args, disable_breakpoint); +} + +static void +enable_once_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = temporary; + + check_duplicates (bpt->address); +} + +static void +enable_once_command (args) + char *args; +{ + map_breakpoint_numbers (args, enable_once_breakpoint); +} + +static void +enable_delete_breakpoint (bpt) + struct breakpoint *bpt; +{ + bpt->enable = delete; + + check_duplicates (bpt->address); +} + +static void +enable_delete_command (args) + char *args; +{ + map_breakpoint_numbers (args, enable_delete_breakpoint); +} + + +/* Chain containing all defined enable commands. */ + +struct cmd_list_element *enablelist; + +extern struct cmd_list_element *cmdlist; + +static +initialize () +{ + breakpoint_chain = 0; + breakpoint_count = 0; + enablelist = 0; + + add_com ("ignore", class_breakpoint, ignore_command, + "Set ignore-count of breakpoint number N to COUNT."); + + add_com ("commands", class_breakpoint, commands_command, + "Set commands to be executed when a breakpoint is hit.\n\ +Give breakpoint number as argument after \"commands\".\n\ +The commands themselves follow starting on the next line.\n\ +Type a line containing \"end\" to indicate the end of them.\n\ +Give \"silent\" as the first line to make the breakpoint silent;\n\ +then no output is printed when it is hit, except what the commands print."); + + add_com ("condition", class_breakpoint, condition_command, + "Specify breakpoint number N to break only if COND is true.\n\ +N is an integer; COND is a C expression to be evaluated whenever\n\ +breakpoint N is reached. Actually break only when COND is nonzero."); + + add_com ("tbreak", class_breakpoint, tbreak_command, + "Set a temporary breakpoint. Args like \"break\" command.\n\ +Like \"break\" except the breakpoint is only enabled temporarily,\n\ +so it will be disabled when hit. Equivalent to \"break\" followed\n\ +by using \"enable once\" on the breakpoint number."); + + add_prefix_cmd ("enable", class_breakpoint, enable_command, + "Enable some breakpoints. Give breakpoint numbers as arguments.\n\ +With no subcommand, breakpoints are enabled until you command otherwise.\n\ +This is used to cancel the effect of the \"disable\" command.\n\ +With a subcommand you can enable temporarily.", + &enablelist, "enable ", 1, &cmdlist); + + add_cmd ("delete", 0, enable_delete_command, + "Enable breakpoints and delete when hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it is deleted.", + &enablelist); + + add_cmd ("once", 0, enable_once_command, + "Enable breakpoints for one hit. Give breakpoint numbers.\n\ +If a breakpoint is hit while enabled in this fashion, it becomes disabled.\n\ +See the \"tbreak\" command which sets a breakpoint and enables it once.", + &enablelist); + + add_com ("disable", class_breakpoint, disable_command, + "Disable some breakpoints. Give breakpoint numbers as arguments.\n\ +With no arguments, disable all breakpoints.\n\ +A disabled breakpoint is not forgotten,\n\ +but it has no effect until enabled again."); + add_com_alias ("dis", "disable", class_breakpoint, 1); + + add_com ("delete", class_breakpoint, delete_command, + "Delete breakpoints, specifying breakpoint numbers; or all breakpoints.\n\ +Arguments are breakpoint numbers with spaces in between.\n\ +To delete all breakpoints, give no argument."); + add_com_alias ("d", "delete", class_breakpoint, 1); + + add_com ("clear", class_breakpoint, clear_command, + "Clear breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, all breakpoints in that line are cleared.\n\ +If function is specified, breakpoints at beginning of function are cleared.\n\ +If an address is specified, breakpoints at that address are cleared.\n\n\ +With no argument, clears all breakpoints in the line that the selected frame\n\ +is executing in.\n\ +\n\ +See also the \"delete\" command which clears breakpoints by number."); + + add_com ("break", class_breakpoint, break_command, + "Set breakpoint at specified line or function.\n\ +Argument may be line number, function name, or \"*\" and an address.\n\ +If line number is specified, break at start of code for that line.\n\ +If function is specified, break at start of code for that function.\n\ +If an address is specified, break at that exact address.\n\ +With no arg, uses current execution address of selected stack frame.\n\ +This is useful for breaking on return to a stack frame.\n\ +\n\ +Multiple breakpoints at one place are permitted, and useful if conditional.\n\ +\n\ +Do \"help breakpoints\" for info on other commands dealing with breakpoints."); + add_com_alias ("b", "break", class_run, 1); + add_com_alias ("br", "break", class_run, 1); + add_com_alias ("bre", "break", class_run, 1); + add_com_alias ("brea", "break", class_run, 1); + + add_info ("breakpoints", breakpoints_info, + "Status of all breakpoints, or breakpoint number NUMBER.\n\ +Second column is \"y\" for enabled breakpoint, \"n\" for disabled,\n\ +\"o\" for enabled once (disable when hit), \"d\" for enable but delete when hit.\n\ +Then come the address and the file/line number.\n\n\ +Convenience variable \"$_\" and default examine address for \"x\"\n\ +are set to the address of the last breakpoint listed."); +} + +END_FILE diff --git a/gdb/coffread.c b/gdb/coffread.c new file mode 100644 index 00000000000..626b16f41df --- /dev/null +++ b/gdb/coffread.c @@ -0,0 +1,1860 @@ +/* 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 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "param.h" +#ifdef COFF_FORMAT +#include "initialize.h" +#include "symtab.h" + +#include +#include +#include +#include +#include +#include + +static void add_symbol_to_list (); +static void 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 void finish_block (); +static struct blockvector *make_blockvector (); +static struct symbol *process_coff_symbol (); +static int init_stringtab (); +static void free_stringtab (); +static char *getfilename (); +static char *getsymname (); +static int init_lineno (); +static void enter_linenos (); + +START_FILE + +/* 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 start and end of text of current source file. + This comes from a ".text" symbol where x_nlinno > 0. */ + +static CORE_ADDR cur_src_start_addr; +static CORE_ADDR cur_src_end_addr; + +/* End of the text segment of the executable file, + as found in the symbol _etext. */ + +static CORE_ADDR end_of_text_addr; + +/* The addresses of the symbol table stream and number of symbols + of the object file we are reading (as copied into core). */ + +static FILE *nlist_stream_global; +static int nlist_nsyms_global; + +/* The file and text section headers of the symbol file */ + +static FILHDR file_hdr; +static SCNHDR text_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; + +/* Vector of line number information. */ + +static struct linetable *line_vector; + +/* Index of next entry to go in line_vector_index. */ + +static int line_vector_index; + +/* Last line number recorded in the line vector. */ + +static int prev_line_number; + +/* Number of elements allocated for line_vector currently. */ + +static int line_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 *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; + int depth; +}; + +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 first_object_file_end; /* From blockframe.c */ + +/* File name symbols were loaded from. */ + +static char *symfile; + +int debug = 1; + + +/* 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) + { + type_vector_length *= 2; + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[type_vector_length / 2], + type_vector_length * sizeof (struct type *) / 2); + } + 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 *) xmalloc (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 *) xmalloc (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; +{ + /* 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 (int)); + } + + /* If this line is not continguous with previous one recorded, + all lines between subsequent line and current one are same pc. + Add one item to line vector, and if more than one line skipped, + record a line-number entry for it. */ + if (prev_line_number > 0 && line != prev_line_number + 1) + line_vector->item[line_vector_index++] = pc; + if (prev_line_number < 0 || line > prev_line_number + 2) + line_vector->item[line_vector_index++] = - line; + prev_line_number = line; + + /* Record the core address of the line. */ + line_vector->item[line_vector_index++] = 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 () +{ + file_symbols = 0; + global_symbols = 0; + context_stack = 0; + within_function = 0; + last_source_file = 0; + + /* Initialize the source file information for this file. */ + + line_vector_index = 0; + line_vector_length = 1000; + prev_line_number = -2; /* Force first line number to be explicit */ + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + line_vector_length * sizeof (int)); +} + +/* Save the vital information for use when closing off the current file. + NAME is the file name the symbols came from, START_ADDR is the first + text address for the file, and SIZE is the number of bytes of text. */ + +static void +complete_symtab (name, start_addr, size) + char *name; + CORE_ADDR start_addr; + unsigned int size; +{ + last_source_file = savestring (name, strlen (name)); + cur_src_start_addr = start_addr; + cur_src_end_addr = start_addr + size; +} + +/* 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. */ + +static void +end_symtab () +{ + register struct symtab *symtab; + register struct context_stack *cstk; + register struct blockvector *blockvector; + register struct linetable *lv; + + /* Finish the lexical context of the last function in the file. */ + + if (context_stack) + { + cstk = context_stack; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, cur_src_end_addr); + free (cstk); + } + + finish_block (0, &file_symbols, 0, cur_src_start_addr, cur_src_end_addr); + finish_block (0, &global_symbols, 0, cur_src_start_addr, cur_src_end_addr); + blockvector = make_blockvector (); + + /* Now create the symtab objects proper this source file. */ + + symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); + /* Fill in its components. */ + symtab->blockvector = blockvector; + symtab->free_code = free_contents; + symtab->free_ptr = 0; + symtab->filename = last_source_file; + lv = line_vector; + lv->nitems = line_vector_index; + symtab->linetable = (struct linetable *) + xrealloc (lv, sizeof (struct linetable) + lv->nitems * sizeof (int)); + symtab->nlines = 0; + symtab->line_charpos = 0; + + /* Link the new symtab into the list of such. */ + symtab->next = symtab_list; + symtab_list = symtab; + + line_vector = 0; + line_vector_length = -1; + last_source_file = 0; +} + +/* 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_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); + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); + } + } +} + +/* This is the symbol-file command. Read the file, analyze its symbols, + and add a struct symtab to symtab_list. */ + +void +symbol_file_command (name) + char *name; +{ + int desc; + int num_symbols; + int num_sections; + int symtab_offset; + extern void close (); + register int val; + struct cleanup *old_chain; + + dont_repeat (); + + if (name == 0) + { + if (symtab_list && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + free_all_symtabs (); + return; + } + + 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 (num_symbols == 0) + { + free_all_symtabs (); + printf ("%s does not have a symbol-table.\n", name); + fflush (stdout); + return; + } + + 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); + + /* Read the line number table, all at once. */ + + val = init_lineno (desc, text_hdr.s_lnnoptr, text_hdr.s_nlnno); + if (val < 0) + error ("\"%s\": error reading line numbers\n", name); + + /* Now read the string table, all at once. */ + + val = init_stringtab (desc, symtab_offset + num_symbols * SYMESZ); + if (val < 0) + error ("\"%s\": can't get string table", name); + make_cleanup (free_stringtab, 0); + + /* 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); + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Throw away the old symbol table. */ + + free_all_symtabs (); + + 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. */ + + read_coff_symtab (desc, num_symbols); + + patch_opaque_types (); + + /* Sort symbols alphabetically within each block. */ + + sort_syms (); + + /* Go over the misc functions and install them in vector. */ + + condense_misc_bunches (); + + /* 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. */ + + select_source_symtab (symtab_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; +}; + +/* 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 (). */ + +static void +read_coff_symtab (desc, nsyms) + int desc; + int nsyms; +{ + FILE *stream = fdopen (desc, "r"); + register struct context_stack *new; + struct coff_symbol coff_symbol; + register struct coff_symbol *cs = &coff_symbol; + static SYMENT main_sym; + static AUXENT main_aux; + + int num_object_files = 0; + int next_file_symnum = 0; + char *filestring; + int depth; + int fcn_first_line; + int fcn_last_line; + long fcn_line_ptr; + + nlist_stream_global = stream; + nlist_nsyms_global = nsyms; + 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 *)); + + start_symtab (); + + symnum = 0; + while (symnum < nsyms) + { + read_one_sym (cs, &main_sym, &main_aux); + + /* + * If we are finished with the previous file's symbols, and the + * next thing is not a C_FILE, then we have hit the global symbols. + */ + if (cs->c_symnum == next_file_symnum && cs->c_sclass != C_FILE) + { + CORE_ADDR last_file_end = cur_src_end_addr; + + if (last_source_file) + end_symtab (); + + start_symtab (); + complete_symtab ("_globals_", 0, first_object_file_end); + /* done with all files, everything from here on out is globals */ + } + + if (ISFCN (cs->c_type)) + { + /* + * gdb expects all functions to also be in misc_function + * list -- why not... + */ + record_misc_function (cs->c_name, cs->c_value); + + fcn_line_ptr = main_aux.x_sym.x_fcnary.x_fcn.x_lnnoptr; + within_function = 1; + + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + new->depth = depth = 0; + new->next = 0; + context_stack = new; + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = cs->c_value; + new->name = process_coff_symbol (cs, &main_aux); + continue; + } + + switch (cs->c_sclass) + { + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + printf ("Bad n_sclass = %d\n", cs->c_sclass); + break; + + case C_FILE: + /* + * c_value field contains symnum of next .file entry in table + * or symnum of first global after last .file. + */ + next_file_symnum = cs->c_value; + filestring = getfilename (&main_aux); + /* + * Complete symbol table for last object file + * containing debugging information. + */ + if (last_source_file) + { + end_symtab (); + start_symtab (); + } + complete_symtab (filestring, 0, 0); /* FIXME, 0 0 is wrong */ + num_object_files++; + break; + + case C_EXT: + if (cs->c_secnum == N_ABS && strcmp (cs->c_name, _ETEXT) == 0) + { + end_of_text_addr = cs->c_value; + } + if (cs->c_type == T_NULL) + { + if (cs->c_secnum <= 1) /* text or abs */ + { + record_misc_function (cs->c_name, cs->c_value); + break; + } + else + cs->c_type = T_INT; + } + (void) process_coff_symbol (cs, &main_aux); + break; + + case C_STAT: + if (cs->c_type == T_NULL && cs->c_secnum > N_UNDEF) + { + /* These ".text", ".data", ".bss" entries don't seem to + * appear in A/UX COFF output. -- gnu@toad.com 4Apr88 + */ + if (strcmp (cs->c_name, _TEXT) == 0) + { + /* We have a ".text" symbol */ + if (num_object_files == 1) + { + /* Record end address of first file, crt0.s */ + first_object_file_end = + cs->c_value + main_aux.x_scn.x_scnlen; + } + /* + * Fill in missing information for debugged + * object file only if we have line number info. + */ + if (main_aux.x_scn.x_nlinno > 0) + { + complete_symtab (filestring, cs->c_value, + main_aux.x_scn.x_scnlen); + } + break; + } + else if (strcmp (cs->c_name, _DATA) == 0) + break; + else if (strcmp (cs->c_name, _BSS) == 0) + break; + + /* get rid of assembly labels here */ + /* record_misc_function (cs->c_name, cs->c_value); */ + break; + } + (void) process_coff_symbol (cs, &main_aux); + break; + + case C_FCN: + if (strcmp (cs->c_name, ".bf") == 0) + { + /* value contains address of first non-init type code */ + /* main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains line number of '{' } */ + fcn_first_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + } + else if (strcmp (cs->c_name, ".ef") == 0) + { + /* value contains address of exit/return from function */ + /* round it up to next multiple of 16 */ + cs->c_value = (cs->c_value + 15) & -16; + /* { main_aux.x_sym.x_misc.x_lnsz.x_lnno + contains number of lines to '}' */ + fcn_last_line = main_aux.x_sym.x_misc.x_lnsz.x_lnno; + enter_linenos (fcn_line_ptr, fcn_first_line, fcn_last_line); + + new = context_stack; + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, cs->c_value); + context_stack = 0; + within_function = 0; + free (new); + } + break; + + case C_BLOCK: + if (strcmp (cs->c_name, ".bb") == 0) + { + new = (struct context_stack *) + xmalloc (sizeof (struct context_stack)); + depth++; + new->depth = depth; + new->next = context_stack; + context_stack = new; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = cs->c_value; + new->name = 0; + local_symbols = 0; + } + else if (strcmp (cs->c_name, ".eb") == 0) + { + new = context_stack; + if (new == 0 || depth != new->depth) + error ("Invalid symbol data: .bb/.eb symbol mismatch."); + 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, cs->c_value); + } + depth--; + local_symbols = new->locals; + context_stack = new->next; + free (new); + } + break; + + default: + (void) process_coff_symbol (cs, &main_aux); + break; + } + } + + if (last_source_file) + end_symtab (); + fclose (stream); +} + +/* 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; + + if (BADMAG(file_hdr)) + return -1; /* Non understood file */ + return file_hdr->f_nsyms; /* OK magic number, return # syms */ +} + +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; +} + +read_one_sym (cs, sym, aux) + register struct coff_symbol *cs; + register SYMENT *sym; + register AUXENT *aux; +{ + cs->c_symnum = symnum; + fread ((char *)sym, SYMESZ, 1, nlist_stream_global); + cs->c_nsyms = (sym->n_numaux & 0xff) + 1; + if (cs->c_nsyms == 2) + { + /* doc for coff says there is either no aux entry or just one */ + fread ((char *)aux, AUXESZ, 1, nlist_stream_global); + } + else if (cs->c_nsyms > 2) + error ("more than one aux symbol table entry at symnum=%d\n", symnum); + + cs->c_name = getsymname (sym); + cs->c_value = sym->n_value; + cs->c_sclass = (sym->n_sclass & 0xff); + cs->c_secnum = sym->n_scnum; + cs->c_type = (unsigned) sym->n_type; + +#ifdef DEBUG + if (debug) { + fprintf(stderr, "sym %3x: %2x %s %x %x %x", cs->c_symnum, + cs->c_sclass, cs->c_name, cs->c_value, cs->c_secnum, cs->c_type); + if (cs->c_nsyms > 1) + fprintf(stderr, " +aux %s\n", (char *)aux); + else + fprintf(stderr, "\n"); + } +#endif + + symnum += cs->c_nsyms; +} + +/* Support for string table handling */ + +static char *stringtab = NULL; + +static int +init_stringtab (chan, offset) + int chan; + long offset; +{ + long buffer; + int val; + + if (lseek (chan, offset, 0) < 0) + return -1; + + val = myread (chan, (char *)&buffer, sizeof buffer); + + /* If no string table, we get 0 bytes back from the read. That's OK. */ + if (val == 0) { + free_stringtab(); + return 0; + } + + if (val != sizeof buffer) + return -1; + + if (stringtab) + free (stringtab); + stringtab = (char *) xmalloc (buffer); + bcopy (&buffer, stringtab, sizeof buffer); + + val = myread (chan, stringtab + sizeof buffer, buffer - sizeof buffer); + if (val != buffer - sizeof buffer || stringtab[buffer - 1] != '\0') + return -1; + + return 0; +} + +static void +free_stringtab () +{ + if (stringtab) + free (stringtab); + stringtab = NULL; +} + +static char * +getsymname (symbol_entry) + SYMENT *symbol_entry; +{ + static char buffer[SYMNMLEN+1]; + char *result; + + if (symbol_entry->n_zeroes == 0) + { + if (!stringtab) + error("Symbol entry references nonexistent string table"); + result = stringtab + symbol_entry->n_offset; + } + else + { + strncpy (buffer, symbol_entry->n_name, SYMNMLEN); + buffer[SYMNMLEN] = '\0'; + result = buffer; + } + return result; +} + +static char * +getfilename (aux_entry) + AUXENT *aux_entry; +{ + static char buffer[BUFSIZ]; + register char *temp; + char *result; + extern char *rindex (); + +#ifndef mac_aux + if (aux_entry->x_file.x_foff != 0) + strcpy (buffer, stringtab + aux_entry->x_file.x_foff); + else +#endif + { + strncpy (buffer, aux_entry->x_file.x_fname, FILNMLEN); + buffer[FILNMLEN] = '\0'; + } + result = buffer; + if ((temp = rindex (result, '/')) != NULL) + result = temp + 1; + return (result); +} + +/* Support for line number handling */ +static char *linetab = NULL; +static long linetab_offset; +static int linetab_count; + +static int +init_lineno (chan, offset, count) + int chan; + long offset; + int count; +{ + int val; + + if (lseek (chan, offset, 0) < 0) + return -1; + + if (linetab) + free (linetab); + linetab = (char *) xmalloc (count * LINESZ); + + val = myread (chan, linetab, count * LINESZ); + if (val != count * LINESZ) + return -1; + + linetab_offset = offset; + linetab_count = count; + return 0; +} + +static void +enter_linenos (file_offset, first_line, last_line) + long file_offset; + register int first_line; + register int last_line; +{ + register char *rawptr = &linetab[file_offset - linetab_offset]; + register struct lineno *lptr; + + /* skip first line entry for each function */ + rawptr += LINESZ; + /* line numbers start at one for the first line of the function */ + first_line--; + + for (lptr = (struct lineno *)rawptr; + lptr->l_lnno && lptr->l_lnno <= last_line; + rawptr += LINESZ, lptr = (struct lineno *)rawptr) + { + record_line (first_line + lptr->l_lnno, lptr->l_addr.l_paddr); + } +} + +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); + } + } + } + } + } +} + +static struct symbol * +process_coff_symbol (cs, aux) + register struct coff_symbol *cs; + register AUXENT *aux; +{ + register struct symbol *sym = (struct symbol *) + xmalloc (sizeof (struct symbol)); + char *name; + char *dot; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + bzero (sym, sizeof (struct symbol)); + name = cs->c_name; + name = (name[0] == '_' ? name + offset : name); + SYMBOL_NAME (sym) = savestring (name, strlen (name)); + + /* default assumptions */ + SYMBOL_VALUE (sym) = cs->c_value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + if (ISFCN (cs->c_type)) + { + SYMBOL_TYPE (sym) = decode_function_type (cs, cs->c_type, aux); + SYMBOL_CLASS (sym) = LOC_BLOCK; + if (cs->c_sclass == C_STAT) + add_symbol_to_list (sym, &file_symbols); + else if (cs->c_sclass == C_EXT) + add_symbol_to_list (sym, &global_symbols); + } + else + { + SYMBOL_TYPE (sym) = decode_type (cs, cs->c_type, aux); + switch (cs->c_sclass) + { + case C_NULL: + break; + + case C_AUTO: + SYMBOL_CLASS (sym) = LOC_LOCAL; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_EXT: + SYMBOL_CLASS (sym) = LOC_STATIC; + add_symbol_to_list (sym, &global_symbols); + break; + + case C_STAT: + 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 C_REG: + case C_REGPARM: + SYMBOL_CLASS (sym) = LOC_REGISTER; + add_symbol_to_list (sym, &local_symbols); + break; + + case C_LABEL: + break; + + case C_ARG: + SYMBOL_CLASS (sym) = LOC_ARG; + add_symbol_to_list (sym, &local_symbols); + /* If PCC says a parameter is a short or a char, + it is really an int. */ + if (SYMBOL_TYPE (sym) == builtin_type_char + || SYMBOL_TYPE (sym) == builtin_type_short) + SYMBOL_TYPE (sym) = builtin_type_int; + else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char + || SYMBOL_TYPE (sym) == builtin_type_unsigned_short) + SYMBOL_TYPE (sym) = builtin_type_unsigned_int; + break; + + case C_TPDEF: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + + /* If type has no name, give it one */ + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = concat (SYMBOL_NAME (sym), "", ""); + + /* Keep track of any type which points to empty structured type, + so it can be filled from a definition from another file */ + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_PTR && + TYPE_LENGTH (TYPE_TARGET_TYPE (SYMBOL_TYPE (sym))) == 0) + { + register int i = hashname (SYMBOL_NAME (sym)); + + SYMBOL_VALUE (sym) = (int) opaque_type_chain[i]; + opaque_type_chain[i] = sym; + } + add_symbol_to_list (sym, &file_symbols); + break; + + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = concat ("", + (cs->c_sclass == C_ENTAG + ? "enum " + : (cs->c_sclass == C_STRTAG + ? "struct " : "union ")), + SYMBOL_NAME (sym)); + add_symbol_to_list (sym, &file_symbols); + break; + + default: + break; + } + } + return sym; +} + +/* Decode a coff type specifier; + return the type that is meant. */ + +static +struct type * +decode_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + register struct type *type = 0; + register int n; + unsigned int new_c_type; + + if (c_type & ~N_BTMASK) + { + new_c_type = DECREF (c_type); + if (ISPTR (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_pointer_type (type); + } + else if (ISFCN (c_type)) + { + type = decode_type (cs, new_c_type, aux); + type = lookup_function_type (type); + } + else if (ISARY (c_type)) + { + int i, n; + register unsigned short *dim; + struct type *base_type; + + /* Define an array type. */ + /* auxent refers to array, not base type */ + if (aux->x_sym.x_tagndx == 0) + cs->c_nsyms = 1; + + /* shift the indices down */ + dim = &aux->x_sym.x_fcnary.x_ary.x_dimen[0]; + i = 1; + n = dim[0]; + for (i = 0; *dim && i < DIMNUM - 1; i++, dim++) + *dim = *(dim + 1); + *dim = 0; + + type = (struct type *) + obstack_alloc (symbol_obstack, sizeof (struct type)); + bzero (type, sizeof (struct type)); + + base_type = decode_type (cs, new_c_type, aux); + + TYPE_CODE (type) = TYPE_CODE_ARRAY; + TYPE_TARGET_TYPE (type) = base_type; + TYPE_LENGTH (type) = n * TYPE_LENGTH (base_type); + } + return type; + } + + /* Reference to existing type */ + if (cs->c_nsyms > 1 && aux->x_sym.x_tagndx != 0) + { + type = coff_alloc_type (aux->x_sym.x_tagndx); + return type; + } + + return decode_base_type (cs, BTYPE (c_type), aux); +} + +/* Decode a coff type specifier for function definition; + return the type that the function returns. */ + +static +struct type * +decode_function_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + if (aux->x_sym.x_tagndx == 0) + cs->c_nsyms = 1; /* auxent refers to function, not base type */ + + return decode_type (cs, DECREF (cs->c_type), aux); +} + +/* basic C types */ + +static +struct type * +decode_base_type (cs, c_type, aux) + register struct coff_symbol *cs; + unsigned int c_type; + register AUXENT *aux; +{ + struct type *type; + + switch (c_type) + { + case T_NULL: + /* NULL seems to be used as the basic type of void functions */ + return builtin_type_void; + break; + + case T_ARG: + /* shouldn't show up here */ + break; + + case T_CHAR: + return builtin_type_char; + + case T_SHORT: + return builtin_type_short; + + case T_INT: + return builtin_type_int; + + case T_LONG: + return builtin_type_long; + + case T_FLOAT: + return builtin_type_float; + + case T_DOUBLE: + return builtin_type_double; + + case T_STRUCT: + if (cs->c_nsyms != 2) + { + /* anonymous structure type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_NAME (type) = concat ("struct ", "", ""); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + } + return type; + + case T_UNION: + if (cs->c_nsyms != 2) + { + /* anonymous union type */ + type = coff_alloc_type (cs->c_symnum); + TYPE_NAME (type) = concat ("union ", "", ""); + TYPE_LENGTH (type) = 0; + TYPE_FIELDS (type) = 0; + TYPE_NFIELDS (type) = 0; + } + else + { + type = read_struct_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + } + TYPE_CODE (type) = TYPE_CODE_UNION; + return type; + + case T_ENUM: + return read_enum_type (cs->c_symnum, + aux->x_sym.x_misc.x_lnsz.x_size, + aux->x_sym.x_fcnary.x_fcn.x_endndx); + + case T_MOE: + /* shouldn't show up here */ + break; + + case T_UCHAR: + return builtin_type_unsigned_char; + + case T_USHORT: + return builtin_type_unsigned_short; + + case T_UINT: + return builtin_type_unsigned_int; + + case T_ULONG: + return builtin_type_unsigned_long; + } + printf ("unexpected type %d at symnum %d, name %s\n", c_type, cs->c_symnum, + cs->c_name); + return builtin_type_void; +} + +/* This page contains subroutines of read_type. */ + +/* Read the description of a structure (or union type) + and return an object describing the type. */ + +static struct type * +read_struct_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + struct nextfield + { + struct nextfield *next; + struct field field; + }; + + register struct type *type; + register struct nextfield *list = 0; + struct nextfield *new; + int nfields = 0; + register int n; + char *name; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + SYMENT sub_sym; + AUXENT sub_aux; + + type = coff_alloc_type (index); + TYPE_CODE (type) = TYPE_CODE_STRUCT; + TYPE_LENGTH (type) = length; + + while (symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = (name[0] == '_' ? name + offset : name); + + switch (ms->c_sclass) + { + case C_MOS: + case C_MOU: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = 8 * ms->c_value; + list->field.bitsize = 0; + nfields++; + break; + + case C_FIELD: + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Save the data. */ + list->field.name = savestring (name, strlen (name)); + list->field.type = decode_type (ms, ms->c_type, &sub_aux); + list->field.bitpos = ms->c_value; + list->field.bitsize = sub_aux.x_sym.x_misc.x_lnsz.x_size; + nfields++; + break; + + case C_EOS: + break; + } + } + /* Now create the vector of fields, and record how big it is. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (symbol_obstack, sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + TYPE_FIELD (type, --n) = list->field; + + return type; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (index, length, lastsym) + int index; + int length; + int lastsym; +{ + register struct symbol *sym; + register struct type *type; + int nsyms = 0; + struct pending **symlist; + struct coff_symbol member_sym; + register struct coff_symbol *ms = &member_sym; + SYMENT sub_sym; + AUXENT sub_aux; + struct pending *osyms, *syms; + register int n; + char *name; +#ifdef NAMES_HAVE_UNDERSCORE + int offset = 1; +#else + int offset = 0; +#endif + + type = coff_alloc_type (index); + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + + while (symnum < lastsym && symnum < nlist_nsyms_global) + { + read_one_sym (ms, &sub_sym, &sub_aux); + name = ms->c_name; + name = (name[0] == '_' ? name + offset : name); + + switch (ms->c_sclass) + { + case C_MOE: + sym = (struct symbol *) xmalloc (sizeof (struct symbol)); + bzero (sym, sizeof (struct symbol)); + + SYMBOL_NAME (sym) = savestring (name, strlen (name)); + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = ms->c_value; + add_symbol_to_list (sym, symlist); + nsyms++; + break; + + case C_EOS: + break; + } + } + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = sizeof (int); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) + obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + + for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next) + { + SYMBOL_TYPE (syms->symbol) = type; + TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol); + TYPE_FIELD_VALUE (type, n) = SYMBOL_VALUE (syms->symbol); + TYPE_FIELD_BITPOS (type, n) = 0; + TYPE_FIELD_BITSIZE (type, n) = 0; + } + return type; +} + +static +initialize () +{ + symfile = 0; + + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table (in coff format) from executable file FILE."); +} + +END_FILE + +#endif /* COFF_FORMAT */ + diff --git a/gdb/command.c b/gdb/command.c new file mode 100644 index 00000000000..fed5ff91f0e --- /dev/null +++ b/gdb/command.c @@ -0,0 +1,454 @@ +/* Library for reading command lines and decoding commands. + Copyright (C) 1986 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more + extensive warranty protection to third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of this program in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +#include "command.h" +#include + +extern char *xmalloc (); + +static char *savestring (); + +/* Add element named NAME to command list *LIST. + FUN should be the function to execute the command; + it will get a character string as argument, with leading + and trailing blanks already eliminated. + + DOC is a documentation string for the command. + Its first line should be a complete sentence. + It should start with ? for a command that is an abbreviation + or with * for a command that most users don't need to know about. */ + +struct cmd_list_element * +add_cmd (name, class, fun, doc, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c + = (struct cmd_list_element *) xmalloc (sizeof (struct cmd_list_element)); + + delete_cmd (name, list); + c->next = *list; + c->name = savestring (name, strlen (name)); + c->class = class; + c->function = fun; + c->doc = doc; + c->prefixlist = 0; + c->allow_unknown = 0; + c->abbrev_flag = 0; + c->aux = 0; + *list = c; + return c; +} + +struct cmd_list_element * +add_alias_cmd (name, oldname, class, abbrev_flag, list) + char *name; + char *oldname; + int class; + int abbrev_flag; + struct cmd_list_element **list; +{ + /* Must do this since lookup_cmd tries to side-effect its first arg */ + char *copied_name; + register struct cmd_list_element *old; + register struct cmd_list_element *c; + copied_name = (char *) alloca (strlen (oldname) + 1); + strcpy (copied_name, oldname); + old = lookup_cmd (&copied_name, *list, 0, 1); + + if (old == 0) + { + delete_cmd (name, list); + return 0; + } + + c = add_cmd (name, class, old->function, old->doc, list); + c->prefixlist = old->prefixlist; + c->prefixname = old->prefixname; + c->allow_unknown = old->allow_unknown; + c->abbrev_flag = abbrev_flag; + c->aux = old->aux; + return c; +} + +/* Like add_prefix_cmd but adds an element for a command prefix: + a name that should be followed by a subcommand to be looked up + in another command list. PREFIXLIST should be the address + of the variable containing that list. */ + +struct cmd_list_element * +add_prefix_cmd (name, class, fun, doc, prefixlist, prefixname, + allow_unknown, list) + char *name; + int class; + void (*fun) (); + char *doc; + struct cmd_list_element **prefixlist; + char *prefixname; + int allow_unknown; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c = add_cmd (name, class, fun, doc, list); + c->prefixlist = prefixlist; + c->prefixname = prefixname; + c->allow_unknown = allow_unknown; + return c; +} + +/* Remove the command named NAME from the command list. */ + +void +delete_cmd (name, list) + char *name; + struct cmd_list_element **list; +{ + register struct cmd_list_element *c; + + while (*list && !strcmp ((*list)->name, name)) + { + *list = (*list)->next; + } + + if (*list) + for (c = *list; c->next;) + { + if (!strcmp (c->next->name, name)) + c->next = c->next->next; + else + c = c->next; + } +} + +/* Implement a help command on command list LIST. + COMMAND is the argument given (a command from the list to document) + or zero for no arg (describe briefly all the commands in the list). + CMDTYPE is a string to use in the error message if command COMMAND + is not found in the list. */ + +/* CLASS should be -1 to list all commands in LIST, + or a nonnegative class number value to list just commands in that class, + or -2 to list the classes themselves. */ + +void +help_cmd (command, list, cmdtype, class, stream) + char *command; + struct cmd_list_element *list; + char *cmdtype; + int class; + FILE *stream; +{ + register struct cmd_list_element *c; + register char *p; + register int ncmds; + struct cmdvec { struct cmd_list_element *cmd; int class; }; + register struct cmdvec *cmdvec; + char *cmdtype1, *cmdtype2; + int len; + + if (command) + { + c = lookup_cmd (&command, list, cmdtype, 0); + if (c == 0) + return; + + /* There are three cases here. + If c->prefixlist is nonzer, we have a prefix command. + Print its documentation, then list its subcommands. + + If c->function is nonzero, we really have a command. + Print its documentation and return. + + If c->function is zero, we have a class name. + Print its documentation (as if it were a command) + and then set class to he number of this class + so that the commands in the class will be listed. */ + + p = c->doc; + fprintf (stream, "%s\n", p); + if (c->function != 0 && c->prefixlist == 0) + return; + fputc ('\n', stream); + if (c->prefixlist) + { + list = *c->prefixlist; + class = 0; + cmdtype = c->prefixname; + } + else + class = c->class; + } + + /* If CMDTYPE is "foo ", CMDTYPE1 gets " foo" and CMDTYPE2 gets "foo sub" */ + len = strlen (cmdtype); + cmdtype1 = (char *) alloca (len + 1); + cmdtype1[0] = 0; + cmdtype2 = (char *) alloca (len + 4); + cmdtype2[0] = 0; + if (len) + { + cmdtype1[0] = ' '; + strncpy (cmdtype1 + 1, cmdtype, len - 1); + cmdtype1[len] = 0; + strncpy (cmdtype2, cmdtype, len - 1); + strcpy (cmdtype2 + len - 1, " sub"); + } + + if (class == -2) + fprintf (stream, "List of classes of %scommands:\n\n", cmdtype2); + else + fprintf (stream, "List of %scommands:\n\n", cmdtype2); + + for (c = list; c; c = c->next) + { + if (c->abbrev_flag == 0 + && (class == -1 /* Listing all */ + || (c->class == class && c->function != 0) /* Listing one class */ + || (class == -2 && c->function == 0))) /* Listing the classes */ + { + fprintf (stream, "%s -- ", c->name); + /* Print just first line of documentation. */ + p = c->doc; + while (*p && *p != '\n') p++; + fwrite (c->doc, 1, p - c->doc, stream); + fputc ('\n', stream); + } + } + + if (class == -2) + fprintf (stream, "\n\ +Type \"help%s\" followed by a class name for a list of commands in that class.", + cmdtype1); + + fprintf (stream, "\n\ +Type \"help%s\" followed by %scommand name for full documentation.\n\ +Command name abbreviations are allowed if unambiguous.\n", + cmdtype1, cmdtype2); +} + +/* Look up the contents of *LINE as a command in the command list LIST. + LIST is a chain of struct cmd_list_element's. + If it is found, return the struct cmd_list_element for that command + and update *LINE to point after the command name, at the first argument. + If not found, call error if ALLOW_UNKNOWN is zero + otherwise (or if error returns) return zero. + Call error if specified command is ambiguous, + unless ALLOW_UNKNOWN is negative. + CMDTYPE precedes the word "command" in the error message. */ + +struct cmd_list_element * +lookup_cmd (line, list, cmdtype, allow_unknown) + char **line; + struct cmd_list_element *list; + char *cmdtype; + int allow_unknown; +{ + register char *p; + register struct cmd_list_element *c, *found; + int nfound; + char ambbuf[100]; + + /* Skip leading whitespace. */ + + while (**line == ' ' || **line == '\t') + (*line)++; + + /* Clear out trailing whitespace. */ + + p = *line + strlen (*line); + while (p != *line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = 0; + + /* Find end of command name. */ + + p = *line; + while (*p == '-' + || (*p >= 'a' && *p <= 'z') + || (*p >= 'A' && *p <= 'Z') + || (*p >= '1' && *p <= '9')) + { + if (*p >= 'A' && *p <= 'Z') + *p += 'a' - 'A'; + p++; + } + + /* Look up the command name. + If exact match, keep that. + Otherwise, take command abbreviated, if unique. */ + + found = 0; + nfound = 0; + for (c = list; c; c = c->next) + { + if (!strncmp (*line, c->name, p - *line)) + { + found = c; + nfound++; + if (c->name[p - *line] == 0) + { + nfound = 1; + break; + } + } + } + + /* Report error for undefined command name. */ + + if (nfound != 1) + { + if (nfound > 1 && allow_unknown >= 0) + { + *p = 0; + ambbuf[0] = 0; + for (c = list; c; c = c->next) + if (!strncmp (*line, c->name, p - *line)) + { + if (strlen (ambbuf) + strlen (c->name) + 6 < sizeof ambbuf) + { + if (strlen (ambbuf)) + strcat (ambbuf, ", "); + strcat (ambbuf, c->name); + } + else + { + strcat (ambbuf, ".."); + break; + } + } + error ("Ambiguous %scommand \"%s\": %s.", cmdtype, *line, ambbuf); + } + else if (!allow_unknown) + { + *p = 0; + error ("Undefined %scommand: \"%s\".", cmdtype, *line); + } + return 0; + } + + /* Skip whitespace before the argument. */ + + while (*p == ' ' || *p == '\t') p++; + *line = p; + + if (found->prefixlist && *p) + { + c = lookup_cmd (line, *found->prefixlist, found->prefixname, + found->allow_unknown); + if (c) + return c; + } + + return found; +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +static char * +savestring (ptr, size) + char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} diff --git a/gdb/command.h b/gdb/command.h new file mode 100644 index 00000000000..687741cce0e --- /dev/null +++ b/gdb/command.h @@ -0,0 +1,154 @@ +/* Header file for command-reading library command.c. + Copyright (C) 1986 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more + extensive warranty protection to third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of this program in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* This structure records one command'd definition. */ + +struct cmd_list_element + { + /* Points to next command in this list. */ + struct cmd_list_element *next; + + /* Name of this command. */ + char *name; + + /* Command class; class values are chosen by application program. */ + int class; + + /* Function definition of this command. + Zero for command class names and for help topics that + are not really commands. */ + void (*function) (); + + /* Documentation of this command (or help topic). + First line is brief documentation; remaining lines form, with it, + the full documentation. First line should end with a period. + Entire string should also end with a period, not a newline. */ + char *doc; + + /* Auxiliary information. + It is up to the calling program to decide what this means. */ + char *aux; + + /* Nonzero identifies a prefix command. For them, the address + of the variable containing the list of subcommands. */ + struct cmd_list_element **prefixlist; + + /* For prefix commands only: + String containing prefix commands to get here: this one + plus any others needed to get to it. Should end in a space. + It is used before the word "command" in describing the + commands reached through this prefix. */ + char *prefixname; + + /* For prefix commands only: + nonzero means do not get an error if subcommand is not + recognized; call the prefix's own function in that case. */ + char allow_unknown; + + /* Nonzero says this is an abbreviation, and should not + be mentioned in lists of commands. */ + char abbrev_flag; + }; + +/* Forward-declarations of the entry-points of command.c. */ + +extern struct cmd_list_element *add_cmd (); +extern struct cmd_list_element *add_alias_cmd (); +extern struct cmd_list_element *add_prefix_cmd (); +extern struct cmd_list_element *lookup_cmd (); +extern void delete_cmd (); +extern void help_cmd (); diff --git a/gdb/core.c b/gdb/core.c new file mode 100644 index 00000000000..7d3c68c869d --- /dev/null +++ b/gdb/core.c @@ -0,0 +1,717 @@ +/* Work with core dump and executable files, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "initialize.h" +#include "defs.h" +#include "param.h" + +#include +#include +#include +#include +#include +#include +#include + +/* Recognize COFF format systems because a.out.h defines AOUTHDR. */ +#ifdef AOUTHDR +#define COFF_FORMAT +#endif + +#ifdef NEW_SUN_CORE +#include +#else /* not NEW_SUN_CORE */ +#ifdef UMAX_CORE +#include +#else /* not UMAX_CORE */ +#ifdef mac_aux +#include +#include +#include +#include +#include +#else +#include +#endif /* mac_aux */ +#endif /* UMAX_CORE */ +#endif /* NEW_SUN_CORE */ + +#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 +#define AOUTHDR struct exec +#endif + +START_FILE + +/* Hook for `exec_file_command' command to call. */ + +void (*exec_file_display_hook) (); + +/* File names of core file and executable file. */ + +static char *corefile; +static 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. */ + +static int corechan; +static int execchan; + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +static CORE_ADDR data_start; +static CORE_ADDR data_end; +static CORE_ADDR stack_start; +static 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. */ + +static CORE_ADDR text_start; +static CORE_ADDR text_end; +static CORE_ADDR exec_data_start; +static CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +static int text_offset; + +/* Address in executable file of start of data area data. */ + +static int exec_data_offset; + +/* Address in core file of start of data area data. */ + +static int data_offset; + +/* Address in core file of start of stack area data. */ + +static int stack_offset; + +#ifdef COFF_FORMAT +/* various coff data structures */ + +static FILHDR file_hdr; +static SCNHDR text_hdr; +static SCNHDR data_hdr; + +#endif /* not COFF_FORMAT */ + +/* a.out header saved in core file. */ + +static AOUTHDR core_aouthdr; + +/* a.out header of exec file. */ + +static AOUTHDR exec_aouthdr; + +static void validate_files (); +unsigned int register_addr (); + +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) + { + 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); +#ifdef NEW_SUN_CORE + { + struct core corestr; + + val = myread (corechan, &corestr, sizeof corestr); + if (val < 0) + perror_with_name (filename); + if (corestr.c_magic != CORE_MAGIC) + error ("\"%s\" does not appear to be a core dump file (magic 0x%x, expected 0x%x)", + filename, corestr.c_magic, (int) CORE_MAGIC); + else if (sizeof (struct core) != corestr.c_len) + error ("\"%s\" has an invalid struct core length (%d, expected %d)", + filename, corestr.c_len, (int) sizeof (struct core)); + + data_start = exec_data_start; + data_end = data_start + corestr.c_dsize; + stack_start = stack_end - corestr.c_ssize; + data_offset = sizeof corestr; + stack_offset = sizeof corestr + corestr.c_dsize; + + bcopy (&corestr.c_regs, registers, 16 * 4); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc; + bcopy (corestr.c_fpstatus.fps_regs, + ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof corestr.c_fpstatus.fps_regs); + bcopy (&corestr.c_fpstatus.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof corestr.c_fpstatus - sizeof corestr.c_fpstatus.fps_regs); + + bcopy (&corestr.c_aouthdr, &core_aouthdr, sizeof (struct exec)); + + printf ("Core file is from \"%s\".\n", corestr.c_cmdname); + } +#else /* not NEW_SUN_CORE */ + /* 4.2-style (and perhaps also sysV-style) core dump file. */ + { +#ifdef UMAX_CORE + struct ptrace_user u; +#else + struct user u; +#endif + int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name (filename); + data_start = exec_data_start; + +#ifdef UMAX_CORE + data_end = data_start + u.pt_dsize; + stack_start = stack_end - u.pt_ssize; + data_offset = sizeof u; + stack_offset = data_offset + u.pt_dsize; + reg_offset = 0; + + bcopy (&u.pt_aouthdr, &core_aouthdr, sizeof (AOUTHDR)); + +#else /* not UMAX_CORE */ +#ifdef mac_aux + /* This may well not work for 0407 (nonshared text) a.out's */ + data_end = data_start + u.u_dsize << PAGESHIFT; + stack_start = stack_end - u.u_ssize << PAGESHIFT; + data_offset = USIZE; + stack_offset = USIZE + u.u_dsize << PAGESHIFT; + reg_offset = (int) &u.u_ar0[0] - (int) &u; + + core_aouthdr.a_magic = u.u_exdata.ux_mag; +#else + 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); + reg_offset = (int) u.u_ar0 - KERNEL_U_ADDR; + + /* I don't know where to find this info. + So, for now, mark it as not available. */ + core_aouthdr.a_magic = 0; +#endif /* not mac_aux */ +#endif /* not UMAX_CORE */ + + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0) + perror_with_name (filename); + + val = myread (corechan, buf, sizeof buf); + if (val < 0) + perror_with_name (filename); + supply_register (regno, buf); + } + } + } +#endif /* not NEW_SUN_CORE */ + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + char dirname[MAXPATHLEN]; + + getwd (dirname); + corefile = concat (dirname, "/", filename); + } + + set_current_frame (read_register (FP_REGNUM)); + 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) + { + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + +#ifdef COFF_FORMAT + { + 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 = text_hdr.s_scnptr; + exec_data_start = exec_aouthdr.data_start; + exec_data_end = exec_data_start + exec_aouthdr.dsize; + exec_data_offset = data_hdr.s_scnptr; + data_start = exec_data_start; + data_end += exec_data_start; + exec_mtime = file_hdr.f_timdat; + } +#else /* not COFF_FORMAT */ + { + struct stat st_exec; + + val = myread (execchan, &exec_aouthdr, sizeof (AOUTHDR)); + + if (val < 0) + perror_with_name (filename); + + text_start = N_TXTADDR (exec_aouthdr); + text_end = text_start + exec_aouthdr.a_text; + text_offset = N_TXTOFF (exec_aouthdr); + exec_data_start = N_DATADDR (exec_aouthdr); + exec_data_end = exec_data_start + exec_aouthdr.a_data; + exec_data_offset = N_TXTOFF (exec_aouthdr) + exec_aouthdr.a_text; + data_start = exec_data_start; + data_end += exec_data_start; + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + } +#endif /* not COFF_FORMAT */ + + 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 ? filename : "No executable specified.\n"); +} + +/* Call this to specify the hook for exec_file_command to call back. + This is called from the x-window display code. */ + +specify_exec_file_hook (hook) + void (*hook) (); +{ + exec_file_display_hook = hook; +} + +/* The exec file must be closed before running an inferior. + If it is needed again after the inferior dies, it must + be reopened. */ + +close_exec_file () +{ + if (execchan >= 0) + close (execchan); + execchan = -1; +} + +reopen_exec_file () +{ + if (execchan < 0 && execfile != 0) + { + char *filename = concat (execfile, "", ""); + exec_file_command (filename, 0); + free (filename); + } +} + +/* If we have both a core file and an exec file, + print a warning if they don't go together. + This should really check that the core file came + from that exec file, but I don't know how to do it. */ + +static void +validate_files () +{ + if (execfile != 0 && corefile != 0) + { + struct stat st_core; + + fstat (corechan, &st_core); + + if (core_aouthdr.a_magic != 0 + && bcmp (&core_aouthdr, &exec_aouthdr, sizeof core_aouthdr)) + printf ("Warning: core file does not match specified executable file.\n"); + else if (exec_mtime > st_core.st_mtime) + printf ("Warning: exec file is newer than core file.\n"); + } +} + +char * +get_exec_file () +{ + if (execfile == 0) + error ("No executable file specified.\n\ +Use the \"exec-file\" and \"symbol-file\" commands."); + return execfile; +} + +int +have_core_file_p () +{ + return corefile != 0; +} + +static void +files_info () +{ + char *symfile; + extern char *get_sym_file (); + + if (execfile) + printf ("Executable file \"%s\".\n", execfile); + else + printf ("No executable file\n"); + if (corefile == 0) + printf ("No core dump file\n"); + else + printf ("Core dump file \"%s\".\n", corefile); + + if (have_inferior_p ()) + printf ("Using the running image of the program, rather than these files.\n"); + + symfile = get_sym_file (); + if (symfile != 0) + printf ("Symbols loaded from \"%s\".\n", symfile); + + if (! have_inferior_p ()) + { + if (execfile) + { + printf ("Text segment from 0x%x to 0x%x.\n", + text_start, text_end); + } + if (corefile) + { + printf ("Data segment from 0x%x to 0x%x.\nStack segment from 0x%x to 0x%x.\n", + data_start, data_end, stack_start, stack_end); + } + else + { + printf ("Data segment in executable from 0x%x to 0x%x.\n", + exec_data_start, exec_data_end); + } + } +} + +/* Read "memory data" from core file and/or executable file */ + +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (have_inferior_p ()) + read_inferior_memory (memaddr, myaddr, len); + else + xfer_core_file (memaddr, myaddr, len, 0); +} + +/* Write LEN bytes of data starting at address MYADDR + into debugged program memory at address MEMADDR. + Returns zero if successful, or an errno value if ptrace failed. */ + +int +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + if (have_inferior_p ()) + return write_inferior_memory (memaddr, myaddr, len); + else + error ("Can write memory only when program being debugged is running."); +} + +xfer_core_file (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + register int val; + int xferchan; + char **xferfile; + int fileptr; + + while (len > 0) + { + xferfile = 0; + xferchan = 0; + + /* Determine which file the next bunch of addresses reside in, + and where in the file. Set the file's read/write pointer + to point at the proper place for the desired address + and set xferfile and xferchan for the correct file. + If desired address is nonexistent, leave them zero. + i is set to the number of bytes that can be handled + along with the next address. */ + + if (memaddr < text_start) + { + i = min (len, text_start - memaddr); + } + else if (memaddr >= text_end && memaddr < data_start) + { + i = min (len, data_start - memaddr); + } + else if (memaddr >= (corechan >= 0 ? data_end : exec_data_end) + && memaddr < stack_start) + { + i = min (len, stack_start - memaddr); + } + else if (memaddr >= stack_end && stack_end != 0) + { + i = min (len, - memaddr); + } + /* Note that if there is no core file + data_start and data_end are equal. */ + else if (memaddr >= data_start && memaddr < data_end) + { + i = min (len, data_end - memaddr); + fileptr = memaddr - data_start + data_offset; + xferfile = &corefile; + xferchan = corechan; + } + /* Note that if there is no core file + stack_start and stack_end are equal. */ + else if (memaddr >= stack_start && memaddr < stack_end) + { + i = min (len, stack_end - memaddr); + fileptr = memaddr - stack_start + stack_offset; + xferfile = &corefile; + xferchan = corechan; + } + else if (corechan < 0 + && memaddr >= exec_data_start && memaddr < exec_data_end) + { + i = min (len, exec_data_end - memaddr); + fileptr = memaddr - exec_data_start + exec_data_offset; + xferfile = &execfile; + xferchan = execchan; + } + else if (memaddr >= text_start && memaddr < text_end) + { + i = min (len, text_end - memaddr); + fileptr = memaddr - text_start + text_offset; + xferfile = &execfile; + xferchan = execchan; + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. */ + else + bzero (myaddr, i); + + memaddr += i; + myaddr += i; + len -= i; + } +} + +/* My replacement for the read system call. + Used like `read' but keeps going if `read' returns too soon. */ + +myread (desc, addr, len) + int desc; + char *addr; + int len; +{ + register int val; + int orglen = len; + + while (len > 0) + { + val = read (desc, addr, len); + if (val < 0) + return val; + if (val == 0) + return orglen - len; + len -= val; + addr += val; + } +} + +#ifndef NEW_SUN_CORE + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + +#ifdef mac_aux +/* FIXME, we don't know where the regs are. Maybe the test command + * that tests what parts of the upage are writeable will find 'em for us. + */ +#define REGISTER_U_ADDR(addr, foo, bar) addr = 0; +#endif + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* not NEW_SUN_CORE */ + +static +initialize () +{ + corechan = -1; + execchan = -1; + corefile = 0; + execfile = 0; + exec_file_display_hook = 0; + + text_start = 0; + text_end = 0; + data_start = 0; + data_end = 0; + exec_data_start = 0; + exec_data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + add_com ("core-file", class_files, core_file_command, + "Use FILE as core dump for examining memory and registers.\n\ +No arg means have no core file."); + add_com ("exec-file", class_files, exec_file_command, + "Use FILE as program for getting contents of pure memory.\n\ +If FILE cannot be found as specified, your execution directory path\n\ +is searched for a command of that name.\n\ +No arg means have no executable file."); + add_info ("files", files_info, "Names of files being debugged."); +} + +END_FILE diff --git a/gdb/dbxread.c b/gdb/dbxread.c new file mode 100644 index 00000000000..007e7682e09 --- /dev/null +++ b/gdb/dbxread.c @@ -0,0 +1,2183 @@ +/* Read dbx symbol tables and convert to internal format, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "param.h" + +#ifdef READ_DBX_FORMAT + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "initialize.h" +#include "symtab.h" + +static void add_symbol_to_list (); +static void read_dbx_symtab (); +static void process_one_symbol (); +static struct type *read_type (); +static struct type *read_range_type (); +static struct type *read_enum_type (); +static struct type *read_struct_type (); +static long read_number (); +static void finish_block (); +static struct blockvector *make_blockvector (); +static struct symbol *define_symbol (); +static void start_subfile (); +static int hashname (); +static void hash_symsegs (); +extern struct symtab *read_symsegs (); + +START_FILE + +/* Chain of symtabs made from reading the file's symsegs. + These symtabs do not go into symtab_list themselves, + but the information is copied from them when appropriate + to make the symtabs that will exist permanently. */ + +static struct symtab *symseg_chain; + +/* Symseg symbol table for the file whose data we are now processing. + It is one of those in symseg_chain. Or 0, for a compilation that + has no symseg. */ + +static struct symtab *current_symseg; + +/* Name of source file whose symbol data we are now processing. + This comes from a symbol of type N_SO. */ + +static char *last_source_file; + +/* Core address of start of text of current source file. + This too comes from the N_SO symbol. */ + +static CORE_ADDR last_source_start_addr; + +/* End of the text segment of the executable file, + as found in the symbol _etext. */ + +static CORE_ADDR end_of_text_addr; + +/* The list of sub-source-files within the current individual compilation. + Each file gets its own symtab with its own linetable and associated info, + but they all share one blockvector. */ + +struct subfile +{ + struct subfile *next; + char *name; + struct linetable *line_vector; + int line_vector_length; + int line_vector_index; + int prev_line_number; +}; + +static struct subfile *subfiles; + +static struct subfile *current_subfile; + +/* The addresses of the symbol table stream and the string table + of the object file we are reading (as copied into core). */ + +static FILE *nlist_stream_global; +static int nlist_size_global; +static char *stringtab_global; + +/* The index in nlist_global of the last dbx symbol to be processed. */ + +static int symnum; + +/* Vector of types defined so far, indexed by their dbx type numbers. + (In newer sun systems, dbx uses a pair of numbers in parens, + as in "(SUBFILENUM,NUMWITHINSUBFILE)". Then these numbers must be + translated through the type_translations hash table to get + the index into the type vector.) */ + +static struct typevector *type_vector; + +/* Number of elements allocated for type_vector currently. */ + +static int type_vector_length; + +/* Vector of line number information. */ + +static struct linetable *line_vector; + +/* Index of next entry to go in line_vector_index. */ + +static int line_vector_index; + +/* Last line number recorded in the line vector. */ + +static int prev_line_number; + +/* Number of elements allocated for line_vector currently. */ + +static int line_vector_length; + +/* Chain of global symbols whose values are not known yet. + They are chained thru the SYMBOL_VALUE, since we don't + have the correct data for that slot yet. */ + +#define HASHSIZE 127 +static struct symbol *global_sym_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 *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; + int depth; +}; + +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 first_object_file_end; /* From blockframe.c */ + +/* File name symbols were loaded from. */ + +static char *symfile; + +/* Support for Sun changes to dbx symbol format */ + +/* For each identified header file, we have a table of types defined + in that header file. + + header_files maps header file names to their type tables. + It is a vector of n_header_files elements. + Each element describes one header file. + It contains a vector of types. + + Sometimes it can happen that the same header file produces + different results when included in different places. + This can result from conditionals or from different + things done before including the file. + When this happens, there are multiple entries for the file in this table, + one entry for each distinct set of results. + The entries are distinguished by the INSTANCE field. + The INSTANCE field appears in the N_BINCL and N_EXCL symbol table and is + used to match header-file references to their corresponding data. */ + +struct header_file +{ + char *name; /* Name of header file */ + int instance; /* Numeric code distinguishing instances + of one header file that produced + different results when included. + It comes from the N_BINCL or N_EXCL. */ + struct type **vector; /* Pointer to vector of types */ + int length; /* Allocated length (# elts) of that vector */ +}; + +static struct header_file *header_files; + +static int n_header_files; + +static int n_allocated_header_files; + +/* Within each object file, various header files are assigned numbers. + A type is defined or referred to with a pair of numbers + (FILENUM,TYPENUM) where FILENUM is the number of the header file + and TYPENUM is the number within that header file. + TYPENUM is the index within the vector of types for that header file. + + FILENUM == 1 is special; it refers to the main source of the object file, + and not to any header file. FILENUM != 1 is interpreted by looking it up + in the following table, which contains indices in header_files. */ + +static int *this_object_header_files; + +static int n_this_object_header_files; + +static int n_allocated_this_object_header_files; + +/* When a header file is getting special overriding definitions + for one source file, record here the header_files index + of its normal definition vector. + At other times, this is -1. */ + +static int header_file_prev_index; + +/* At the start of reading dbx symbols, allocate our tables. */ + +static void +init_header_files () +{ + n_allocated_header_files = 10; + header_files = (struct header_file *) xmalloc (10 * sizeof (struct header_file)); + n_header_files = 0; + + n_allocated_this_object_header_files = 10; + this_object_header_files = (int *) xmalloc (10 * sizeof (int)); +} + +/* At the end of reading dbx symbols, free our tables. */ + +static void +free_header_files () +{ + register int i; + for (i = 0; i < n_header_files; i++) + free (header_files[i].name); + free (header_files); + free (this_object_header_files); +} + +/* Called at the start of each object file's symbols. + Clear out the mapping of header file numbers to header files. */ + +static void +new_object_header_files () +{ + /* Leave FILENUM of 0 free for builtin types and this file's types. */ + n_this_object_header_files = 1; + header_file_prev_index = -1; +} + +/* Add header file number I for this object file + at the next successive FILENUM. */ + +static void +add_this_object_header_file (i) + int i; +{ + if (n_this_object_header_files == n_allocated_this_object_header_files) + { + n_allocated_this_object_header_files *= 2; + this_object_header_files + = (int *) xrealloc (this_object_header_files, + n_allocated_this_object_header_files * sizeof (int)); + } + + this_object_header_files[n_this_object_header_files++] = i; +} + +/* Add to this file an "old" header file, one already seen in + a previous object file. NAME is the header file's name. + INSTANCE is its instance code, to select among multiple + symbol tables for the same header file. */ + +static void +add_old_header_file (name, instance) + char *name; + int instance; +{ + register struct header_file *p = header_files; + register int i; + + for (i = 0; i < n_header_files; i++) + if (!strcmp (p[i].name, name) && instance == p[i].instance) + { + add_this_object_header_file (i); + return; + } + error ("Invalid symbol data: \"repeated\" header file that hasn't been seen before, at symtab pos %d.", + symnum); +} + +/* Add to this file a "new" header file: definitions for its types follow. + NAME is the header file's name. + Most often this happens only once for each distinct header file, + but not necessarily. If it happens more than once, INSTANCE has + a different value each time, and references to the header file + use INSTANCE values to select among them. + + dbx output contains "begin" and "end" markers for each new header file, + but at this level we just need to know which files there have been; + so we record the file when its "begin" is seen and ignore the "end". */ + +static void +add_new_header_file (name, instance) + char *name; + int instance; +{ + register int i; + register struct header_file *p = header_files; + header_file_prev_index = -1; + +#if 0 + /* This code was used before I knew about the instance codes. + My first hypothesis is that it is not necessary now + that instance codes are handled. */ + + /* Has this header file a previous definition? + If so, make a new entry anyway so that this use in this source file + gets a separate entry. Later source files get the old entry. + Record here the index of the old entry, so that any type indices + not previously defined can get defined in the old entry as + well as in the new one. */ + + for (i = 0; i < n_header_files; i++) + if (!strcmp (p[i].name, name)) + { + header_file_prev_index = i; + } + +#endif + + /* Make sure there is room for one more header file. */ + + if (n_header_files == n_allocated_header_files) + { + n_allocated_header_files *= 2; + header_files + = (struct header_file *) xrealloc (header_files, n_allocated_header_files * sizeof (struct header_file)); + } + + /* Create an entry for this header file. */ + + i = n_header_files++; + header_files[i].name = name; + header_files[i].instance = instance; + header_files[i].length = 10; + header_files[i].vector + = (struct type **) xmalloc (10 * sizeof (struct type *)); + bzero (header_files[i].vector, 10 * sizeof (struct type *)); + + add_this_object_header_file (i); +} + +/* Look up a dbx type-number pair. Return the address of the slot + where the type for that number-pair is stored. + The number-pair is in TYPENUMS. + + This can be used for finding the type associated with that pair + or for associating a new type with the pair. */ + +static struct type ** +dbx_lookup_type (typenums) + int typenums[2]; +{ + register int filenum = typenums[0], index = typenums[1]; + + if (filenum < 0 || filenum >= n_this_object_header_files) + error ("Invalid symbol data: type number (%d,%d) out of range at symtab pos %d.", + filenum, index, symnum); + + if (filenum == 0) + { + /* Type is defined outside of header files. + Find it in this object file's type vector. */ + if (index >= type_vector_length) + { + type_vector_length *= 2; + type_vector = (struct typevector *) + xrealloc (type_vector, sizeof (struct typevector) + type_vector_length * sizeof (struct type *)); + bzero (&type_vector->type[type_vector_length / 2], + type_vector_length * sizeof (struct type *) / 2); + } + return &type_vector->type[index]; + } + else + { + register int real_filenum = this_object_header_files[filenum]; + register struct header_file *f; + + if (real_filenum >= n_header_files) + abort (); + + f = &header_files[real_filenum]; + + if (index >= f->length) + { + f->length *= 2; + f->vector = (struct type **) + xrealloc (f->vector, f->length * sizeof (struct type *)); + bzero (&f->vector[f->length / 2], + f->length * sizeof (struct type *) / 2); + } + return &f->vector[index]; + } +} + +/* Make sure there is a type allocated for type numbers TYPENUMS + and return the type object. + This can create an empty (zeroed) type object. */ + +static struct type * +dbx_alloc_type (typenums) + int typenums[2]; +{ + register struct type **type_addr = dbx_lookup_type (typenums); + 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; +} + +#if 0 +static struct type ** +explicit_lookup_type (real_filenum, index) + int real_filenum, index; +{ + register struct header_file *f = &header_files[real_filenum]; + + if (index >= f->length) + { + f->length *= 2; + f->vector = (struct type **) + xrealloc (f->vector, f->length * sizeof (struct type *)); + bzero (&f->vector[f->length / 2], + f->length * sizeof (struct type *) / 2); + } + return &f->vector[index]; +} +#endif + +/* 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; +{ + /* Ignore the dummy line number in libg.o */ + + if (line == 0xffff) + return; + + /* Make sure line vector is big enough. */ + + if (line_vector_index + 1 >= line_vector_length) + { + line_vector_length *= 2; + line_vector = (struct linetable *) + xrealloc (line_vector, + sizeof (struct linetable) + line_vector_length * sizeof (int)); + current_subfile->line_vector = line_vector; + } + + /* If this line is not continguous with previous one recorded, + record a line-number entry for it. */ + if (line != prev_line_number + 1) + line_vector->item[line_vector_index++] = - line; + prev_line_number = line; + + /* Record the core address of the line. */ + line_vector->item[line_vector_index++] = pc; +} + +/* Start a new symtab for a new source file. + This is called when a dbx symbol of type N_SO is seen; + it indicates the start of data for one original source file. */ + +static void +start_symtab (name, start_addr) + char *name; + CORE_ADDR start_addr; +{ + register struct symtab *s; + + last_source_file = name; + last_source_start_addr = start_addr; + file_symbols = 0; + global_symbols = 0; + context_stack = 0; + within_function = 0; + + new_object_header_files (); + + for (s = symseg_chain; s; s = s->next) + if (s->ldsymoff == symnum * sizeof (struct nlist)) + break; + current_symseg = s; + + 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 *)); + + /* Initialize the list of sub source files with one entry + for this file (the top-level source file). */ + + subfiles = 0; + current_subfile = 0; + start_subfile (name); +} + +/* Handle an N_SOL symbol, which indicates the start of + code that came from an included (or otherwise merged-in) + source file with a different name. */ + +static void +start_subfile (name) + char *name; +{ + register struct subfile *subfile; + + /* Save the current subfile's line vector data. */ + + if (current_subfile) + { + current_subfile->line_vector_index = line_vector_index; + current_subfile->line_vector_length = line_vector_length; + current_subfile->prev_line_number = prev_line_number; + } + + /* See if this subfile is already known as a subfile of the + current main source file. */ + + for (subfile = subfiles; subfile; subfile = subfile->next) + { + if (!strcmp (subfile->name, name)) + { + line_vector = subfile->line_vector; + line_vector_index = subfile->line_vector_index; + line_vector_length = subfile->line_vector_length; + prev_line_number = subfile->prev_line_number; + current_subfile = subfile; + return; + } + } + + /* This subfile is not known. Add an entry for it. */ + + line_vector_index = 0; + line_vector_length = 1000; + prev_line_number = -2; /* Force first line number to be explicit */ + line_vector = (struct linetable *) + xmalloc (sizeof (struct linetable) + line_vector_length * sizeof (int)); + + /* Make an entry for this subfile in the list of all subfiles + of the current main source file. */ + + subfile = (struct subfile *) xmalloc (sizeof (struct subfile)); + subfile->next = subfiles; + subfile->name = savestring (name, strlen (name)); + subfile->line_vector = line_vector; + subfiles = subfile; + current_subfile = subfile; +} + +/* 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 (end_addr) + CORE_ADDR end_addr; +{ + register struct symtab *symtab; + register struct context_stack *cstk; + register struct blockvector *blockvector; + register struct subfile *subfile; + register struct linetable *lv; + struct subfile *nextsub; + + /* Finish the lexical context of the last function in the file. */ + + if (context_stack) + { + cstk = context_stack; + /* Make a block for the local symbols within. */ + finish_block (cstk->name, &local_symbols, cstk->old_blocks, + cstk->start_addr, end_addr); + free (cstk); + } + + /* Finish defining all the blocks of this symtab. */ + if (current_symseg == 0) + { + finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr); + finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr); + blockvector = make_blockvector (); + } + current_subfile->line_vector_index = line_vector_index; + + /* Now create the symtab objects proper, one for each subfile. */ + /* (The main file is one of them.) */ + + for (subfile = subfiles; subfile; subfile = nextsub) + { + symtab = (struct symtab *) xmalloc (sizeof (struct symtab)); + /* Fill in its components. */ + if (current_symseg) + { + bcopy (current_symseg, symtab, sizeof (struct symtab)); + symtab->free_code = free_linetable; + symtab->free_ptr = 0; + } + else + { + symtab->blockvector = blockvector; + type_vector->length = type_vector_length; + symtab->typevector = type_vector; + symtab->free_code = free_linetable; + if (subfile->next == 0) + symtab->free_ptr = (char *) type_vector; + } + symtab->filename = subfile->name; + lv = subfile->line_vector; + lv->nitems = subfile->line_vector_index; + symtab->linetable = (struct linetable *) + xrealloc (lv, sizeof (struct linetable) + lv->nitems * sizeof (int)); + symtab->nlines = 0; + symtab->line_charpos = 0; + + /* Link the new symtab into the list of such. */ + symtab->next = symtab_list; + symtab_list = symtab; + + nextsub = subfile->next; + free (subfile); + } + + type_vector = 0; + type_vector_length = -1; + line_vector = 0; + line_vector_length = -1; + last_source_file = 0; +} + +#ifdef N_BINCL + +/* Handle the N_BINCL and N_EINCL symbol types + that act like N_SOL for switching source files + (different subfiles, as we call them) within one object file, + but using a stack rather than in an arbitrary order. */ + +struct subfile_stack +{ + struct subfile_stack *next; + char *name; + int prev_index; +}; + +struct subfile_stack *subfile_stack; + +static void +push_subfile () +{ + register struct subfile_stack *tem + = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack)); + + tem->next = subfile_stack; + subfile_stack = tem; + if (current_subfile == 0 || current_subfile->name == 0) + abort (); + tem->name = current_subfile->name; + tem->prev_index = header_file_prev_index; +} + +static char * +pop_subfile () +{ + register char *name; + register struct subfile_stack *link = subfile_stack; + + if (link == 0) + abort (); + + name = link->name; + subfile_stack = link->next; + header_file_prev_index = link->prev_index; + free (link); + + return name; +} +#endif /* Have N_BINCL */ + +/* 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 = name; + misc_bunch->contents[misc_bunch_index].address = address; + 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++) + { + misc_function_vector[j] = bunch->contents[i]; + misc_function_vector[j].name + = concat (misc_function_vector[j].name + + (misc_function_vector[j].name[0] == '_' ? offset : 0), + "", ""); + 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); + qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), + sizeof (struct symbol *), compare_symbols); + } + } +} + +/* This is the symbol-file command. Read the file, analyze its symbols, + and add a struct symtab to symtab_list. */ + +void +symbol_file_command (name) + char *name; +{ + register int desc; + struct exec hdr; + struct nlist *nlist; + char *stringtab; + long buffer; + register int val; + extern void close (); + struct cleanup *old_chain; + + dont_repeat (); + + if (name == 0) + { + if (symtab_list && !query ("Discard symbol table? ", 0)) + error ("Not confirmed."); + free_all_symtabs (); + return; + } + + 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); + + val = myread (desc, &hdr, sizeof hdr); + if (val < 0) + perror_with_name (name); + + if (N_BADMAG (hdr)) + error ("File \"%s\" not in executable format.", name); + + if (hdr.a_syms == 0) + { + free_all_symtabs (); + printf ("%s does not have a symbol-table.\n", name); + fflush (stdout); + return; + } + + /* Now read the string table, all at once. */ + val = lseek (desc, N_SYMOFF (hdr) + hdr.a_syms, 0); + if (val < 0) + perror_with_name (name); + val = myread (desc, &buffer, sizeof buffer); + if (val < 0) + perror_with_name (name); + stringtab = (char *) alloca (buffer); + bcopy (&buffer, stringtab, sizeof buffer); + val = myread (desc, stringtab + sizeof buffer, buffer - sizeof buffer); + if (val < 0) + perror_with_name (name); + +#ifdef READ_GDB_SYMSEGS + /* That puts us at the symsegs. Read them. */ + symseg_chain = read_symsegs (desc, name); + hash_symsegs (); +#else + /* Where people are using the 4.2 ld program, must not check for + symsegs, because that ld puts randonm garbage at the end of + the output file and that would trigger an error message. */ + symseg_chain = 0; +#endif + + /* Position to read the symbol table. Do not read it all at once. */ + val = lseek (desc, N_SYMOFF (hdr), 0); + if (val < 0) + perror_with_name (name); + + printf ("Reading symbol data from %s...", name); + fflush (stdout); + + /* Throw away the old symbol table. */ + + free_all_symtabs (); + + init_misc_functions (); + make_cleanup (discard_misc_bunches, 0); + init_header_files (); + make_cleanup (free_header_files, 0); + + /* Now that the symbol table data of the executable file are all in core, + process them and define symbols accordingly. Closes desc. */ + + read_dbx_symtab (desc, stringtab, hdr.a_syms / sizeof (struct nlist)); + + /* Sort symbols alphabetically within each block. */ + + sort_syms (); + + /* Go over the misc functions and install them in vector. */ + + condense_misc_bunches (); + + /* 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. */ + + select_source_symtab (symtab_list); + + symfile = savestring (name, strlen (name)); + + do_cleanups (old_chain); + + /* Free the symtabs made by read_symsegs, but not their contents, + which have been copied into symtabs on symtab_list. */ + while (symseg_chain) + { + register struct symtab *s = symseg_chain->next; + free (symseg_chain); + symseg_chain = s; + } + + printf ("done.\n"); + fflush (stdout); +} + +/* Return name of file symbols were loaded from, or 0 if none.. */ + +char * +get_sym_file () +{ + return symfile; +} + +/* Given pointers to a a.out symbol table in core containing dbx style data, + analyze them and create struct symtab's describing the symbols. + NLISTLEN is the number of symbols in the symbol table. + We read them one at a time using stdio. + All symbol names are given as offsets relative to STRINGTAB. */ + +static void +read_dbx_symtab (desc, stringtab, nlistlen) + int desc; + register char *stringtab; + register int nlistlen; +{ + FILE *stream = fdopen (desc, "r"); + struct nlist buf; + register char *namestring; + register struct symbol *sym, *prev; + int hash; + int num_object_files = 0; + +#ifdef N_BINCL + subfile_stack = 0; +#endif + + nlist_stream_global = stream; + nlist_size_global = nlistlen; + stringtab_global = stringtab; + last_source_file = 0; + bzero (global_sym_chain, sizeof global_sym_chain); + + for (symnum = 0; symnum < nlistlen; symnum++) + { + fread (&buf, sizeof buf, 1, stream); + namestring = buf.n_un.n_strx ? buf.n_un.n_strx + stringtab : ""; + if (buf.n_type & N_STAB) + process_one_symbol (buf.n_type, buf.n_desc, + buf.n_value, namestring); + /* A static text symbol whose name ends in ".o" + can only mean the start of another object file. + So end the symtab of the source file we have been processing. + This is how we avoid counting the libraries as part + or the last source file. + Also this way we find end of first object file (crt0). */ + else if (buf.n_type == N_TEXT + && !strcmp (namestring + strlen (namestring) - 2, ".o")) + { + if (num_object_files++ == 1) + first_object_file_end = buf.n_value; + if (last_source_file) + end_symtab (buf.n_value); + } + else if (buf.n_type & N_EXT || buf.n_type == N_TEXT) + { + int used_up = 0; + + /* Record the location of _etext. */ + if (buf.n_type == (N_TEXT | N_EXT) + && !strcmp (namestring, "_etext")) + end_of_text_addr = buf.n_value; + + /* Global symbol: see if we came across a dbx definition + for a corresponding symbol. If so, store the value. + Remove syms from the chain when their values are stored, + but search the whole chain, as there may be several syms + from different files with the same name. */ + if (buf.n_type & N_EXT) + { + prev = 0; +#ifdef NAMES_HAVE_UNDERSCORE + hash = hashname (namestring + 1); +#else /* not NAMES_HAVE_UNDERSCORE */ + hash = hashname (namestring); +#endif /* not NAMES_HAVE_UNDERSCORE */ + for (sym = global_sym_chain[hash]; + sym;) + { + if ( +#ifdef NAMES_HAVE_UNDERSCORE + *namestring == '_' + && namestring[1] == SYMBOL_NAME (sym)[0] + && + !strcmp (namestring + 2, SYMBOL_NAME (sym) + 1) +#else /* NAMES_HAVE_UNDERSCORE */ + namestring[0] == SYMBOL_NAME (sym)[0] + && + !strcmp (namestring + 1, SYMBOL_NAME (sym) + 1) +#endif /* NAMES_HAVE_UNDERSCORE */ + ) + { + if (prev) + SYMBOL_VALUE (prev) = SYMBOL_VALUE (sym); + else + global_sym_chain[hash] + = (struct symbol *) SYMBOL_VALUE (sym); + SYMBOL_VALUE (sym) = buf.n_value; + if (prev) + sym = (struct symbol *) SYMBOL_VALUE (prev); + else + sym = global_sym_chain[hash]; + + used_up = 1; + } + else + { + prev = sym; + sym = (struct symbol *) SYMBOL_VALUE (sym); + } + } + } + + /* Defined global or text symbol: record as a misc function + if it didn't give its address to a debugger symbol above. */ + if (buf.n_type <= (N_TYPE | N_EXT) + && buf.n_type != N_EXT + && ! used_up) + record_misc_function (namestring, buf.n_value); + } + } + + if (last_source_file) + end_symtab (end_of_text_addr); + + fclose (stream); +} + +/* dbx allows the text of a symbol name to be continued into the + next symbol name! When such a continuation is encountered + (a \ at the end of the text of a name) + call this function to get the continuation. */ + +static char * +next_symbol_text () +{ + struct nlist buf; + fread (&buf, sizeof buf, 1, nlist_stream_global); + symnum++; + return buf.n_un.n_strx + stringtab_global; +} + +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; +} + +/* Put all appropriate global symbols in the symseg data + onto the hash chains so that their addresses will be stored + when seen later in loader global symbols. */ + +static void +hash_symsegs () +{ + /* Look at each symbol in each block in each symseg symtab. */ + struct symtab *s; + for (s = symseg_chain; s; s = s->next) + { + register int n; + for (n = BLOCKVECTOR_NBLOCKS (BLOCKVECTOR (s)) - 1; n >= 0; n--) + { + register struct block *b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), n); + register int i; + for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--) + { + register struct symbol *sym = BLOCK_SYM (b, i); + + /* Put the symbol on a chain if its value is an address + that is figured out by the loader. */ + + if (SYMBOL_CLASS (sym) == LOC_EXTERNAL) + { + register int hash = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE (sym) = (int) global_sym_chain[hash]; + global_sym_chain[hash] = sym; + SYMBOL_CLASS (sym) = LOC_STATIC; + } + } + } + } +} + +static void +process_one_symbol (type, desc, value, name) + int type, desc; + CORE_ADDR value; + char *name; +{ + register struct context_stack *new; + + /* Something is wrong if we see real data before + seeing a source file name. */ + +#ifdef N_NSYMS + if (type == N_NSYMS) return; +#endif + + if (type != N_SO && last_source_file == 0) + error ("Invalid symbol data: does not start by identifying a source file."); + + switch (type) + { + case N_FUN: + case N_FNAME: + /* Either of these types of symbols indicates the start of + a new function. We must process its "name" normally for dbx, + but also record the start of a new lexical context, and possibly + also the end of the lexical context for the previous function. */ + new = context_stack; + within_function = 1; + if (new) + { + /* Make a block for the local symbols within. */ + finish_block (new->name, &local_symbols, new->old_blocks, + new->start_addr, value); + } + else + { + new = (struct context_stack *) xmalloc (sizeof (struct context_stack)); + new->next = 0; + new->depth = -1; + context_stack = new; + } + new->locals = 0; + new->old_blocks = pending_blocks; + new->start_addr = value; + new->name = define_symbol (value, name, desc); + local_symbols = 0; + break; + + case N_LBRAC: + /* This "symbol" just indicates the start of an inner lexical + context within a function. */ + new = (struct context_stack *) xmalloc (sizeof (struct context_stack)); + new->depth = desc; + new->next = context_stack; + context_stack = new; + new->locals = local_symbols; + new->old_blocks = pending_blocks; + new->start_addr = value; + new->name = 0; + local_symbols = 0; + break; + + case N_RBRAC: + /* This "symbol" just indicates the end of an inner lexical + context that was started with N_RBRAC. */ + new = context_stack; + if (new == 0 || desc != new->depth) + error ("Invalid symbol data: N_LBRAC/N_RBRAC symbol mismatch, symtab pos %d.", symnum); + local_symbols = new->locals; + context_stack = new->next; + /* If this is not the outermost LBRAC...RBRAC pair in the + function, its local symbols preceded it, and are the ones + just recovered from the context stack. Defined the block for them. + + If this is the outermost LBRAC...RBRAC pair, there is no + need to do anything; leave the symbols that preceded it + to be attached to the function's own block. */ + if (local_symbols && context_stack->next) + { + /* Muzzle a compiler bug that makes end > start. */ + if (new->start_addr > value) + new->start_addr = value; + /* Make a block for the local symbols within. */ + finish_block (0, &local_symbols, new->old_blocks, + new->start_addr + last_source_start_addr, + value + last_source_start_addr); + } + free (new); + break; + + case N_FN: + /* This kind of symbol supposedly indicates the start + of an object file. In fact this type does not appear. */ + break; + + case N_SO: + /* This type of symbol indicates the start of data + for one source file. + Finish the symbol table of the previous source file + (if any) and start accumulating a new symbol table. */ + if (last_source_file) + end_symtab (value); + start_symtab (name, value); + break; + + case N_SOL: + /* This type of symbol indicates the start of data for + a sub-source-file, one whose contents were copied or + included in the compilation of the main source file + (whose name was given in the N_SO symbol.) */ + start_subfile (name); + break; + +#ifdef N_BINCL + case N_BINCL: + push_subfile (); + add_new_header_file (name, value); + start_subfile (name); + break; + + case N_EINCL: + start_subfile (pop_subfile ()); + break; + + case N_EXCL: + add_old_header_file (name, value); + break; +#endif /* have N_BINCL */ + + case N_SLINE: + /* This type of "symbol" really just records + one line-number -- core-address correspondence. + Enter it in the line list for this symbol table. */ + record_line (desc, value); + break; + + default: + if (name) + define_symbol (value, name, desc); + } +} + +static struct symbol * +define_symbol (value, string, desc) + int value; + char *string; + int desc; +{ + register struct symbol *sym + = (struct symbol *) obstack_alloc (symbol_obstack, sizeof (struct symbol)); + char *p = (char *) index (string, ':'); + int deftype; + register int i; + + bzero (sym, sizeof (struct symbol)); + SYMBOL_NAME (sym) = obstack_copy0 (symbol_obstack, string, p - string); + p++; + /* Determine the type of name being defined. */ + if ((*p >= '0' && *p <= '9') || *p == '(') + deftype = 'l'; + else + deftype = *p++; + + /* c is a special case, not followed by a type-number. + SYMBOL:c=iVALUE for an integer constant symbol. + SYMBOL:c=rVALUE for a floating constant symbol. */ + if (deftype == 'c') + { + if (*p++ != '=') + error ("Invalid symbol data at symtab pos %d.", symnum); + switch (*p++) + { + case 'r': + { + double d = atof (p); + char *value; + + SYMBOL_TYPE (sym) = builtin_type_double; + value = (char *) obstack_alloc (symbol_obstack, sizeof (double)); + bcopy (&d, value, sizeof (double)); + SYMBOL_VALUE_BYTES (sym) = value; + SYMBOL_CLASS (sym) = LOC_CONST; + } + break; + case 'i': + { + SYMBOL_TYPE (sym) = builtin_type_int; + SYMBOL_VALUE (sym) = atoi (p); + SYMBOL_CLASS (sym) = LOC_CONST_BYTES; + } + break; + default: + error ("Invalid symbol data at symtab pos %d.", symnum); + } + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + return sym; + } + + /* Now usually comes a number that says which data type, + and possibly more stuff to define the type + (all of which is handled by read_type) */ + + if (deftype == 'p' && *p == 'F') + /* pF is a two-letter code that means a function parameter in Fortran. + The type-number specifies the type of the return value. + Translate it into a pointer-to-function type. */ + { + p++; + SYMBOL_TYPE (sym) + = lookup_pointer_type (lookup_function_type (read_type (&p))); + } + else + SYMBOL_TYPE (sym) = read_type (&p); + + switch (deftype) + { + case 'f': + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + + case 'F': + SYMBOL_CLASS (sym) = LOC_BLOCK; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + break; + + case 'G': + /* For a class G (global) symbol, it appears that the + value is not correct. It is necessary to search for the + corresponding linker definition to find the value. + These definitions appear at the end of the namelist. */ + i = hashname (SYMBOL_NAME (sym)); + SYMBOL_VALUE (sym) = (int) global_sym_chain[i]; + global_sym_chain[i] = sym; + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &global_symbols); + break; + + /* This case is faked by a conditional above, + when there is no code letter in the dbx data. + Dbx data never actually contains 'l'. */ + case 'l': + SYMBOL_CLASS (sym) = LOC_LOCAL; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'p': + SYMBOL_CLASS (sym) = LOC_ARG; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + /* DESC == 0 implies compiled with GCC. + In this case, if it says `short', believe it. */ + if (desc == 0) + break; + /* If PCC says a parameter is a short or a char, + it is really an int. */ + if (SYMBOL_TYPE (sym) == builtin_type_char + || SYMBOL_TYPE (sym) == builtin_type_short) + SYMBOL_TYPE (sym) = builtin_type_int; + else if (SYMBOL_TYPE (sym) == builtin_type_unsigned_char + || SYMBOL_TYPE (sym) == builtin_type_unsigned_short) + SYMBOL_TYPE (sym) = builtin_type_unsigned_int; + break; + + case 'r': + SYMBOL_CLASS (sym) = LOC_REGISTER; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + case 'S': + /* Static symbol at top level of file */ + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &file_symbols); + break; + + case 't': + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) = concat (SYMBOL_NAME (sym), "", ""); + add_symbol_to_list (sym, &file_symbols); + break; + + case 'T': + SYMBOL_CLASS (sym) = LOC_TYPEDEF; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE; + if (TYPE_NAME (SYMBOL_TYPE (sym)) == 0 + && (TYPE_FLAGS (SYMBOL_TYPE (sym)) & TYPE_FLAG_PERM) == 0) + TYPE_NAME (SYMBOL_TYPE (sym)) + = concat ("", + (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM + ? "enum " + : (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_STRUCT + ? "struct " : "union ")), + SYMBOL_NAME (sym)); + add_symbol_to_list (sym, &file_symbols); + break; + + case 'V': + case 'v': + /* Static symbol of local scope */ + SYMBOL_CLASS (sym) = LOC_STATIC; + SYMBOL_VALUE (sym) = value; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + add_symbol_to_list (sym, &local_symbols); + break; + + default: + error ("Invalid symbol data: unknown symbol-type code `%c' at symtab pos %d.", deftype, symnum); + } + return sym; +} + +/* Read a number by which a type is referred to in dbx data, + or perhaps read a pair (FILENUM, TYPENUM) in parentheses. + Just a single number N is equivalent to (0,N). + Return the two numbers by storing them in the vector TYPENUMS. + TYPENUMS will then be used as an argument to dbx_lookup_type. */ + +static void +read_type_number (pp, typenums) + register char **pp; + register int *typenums; +{ + if (**pp == '(') + { + (*pp)++; + typenums[0] = read_number (pp, ','); + typenums[1] = read_number (pp, ')'); + } + else + { + typenums[0] = 0; + typenums[1] = read_number (pp, 0); + } +} + +/* Read a dbx type reference or definition; + return the type that is meant. + This can be just a number, in which case it references + a type already defined and placed in type_vector. + Or the number can be followed by an =, in which case + it means to define a new type according to the text that + follows the =. */ + +static +struct type * +read_type (pp) + register char **pp; +{ + register struct type *type = 0; + register int n; + struct type *type1; + int typenums[2]; + int xtypenums[2]; + + read_type_number (pp, typenums); + + /* Detect random reference to type not yet defined. + Allocate a type object but leave it zeroed. */ + if (**pp != '=') + return dbx_alloc_type (typenums); + + *pp += 2; + switch ((*pp)[-1]) + { + case 'x': + type = dbx_alloc_type (typenums); + /* Set the type code according to the following letter. */ + switch ((*pp)[0]) + { + case 's': + TYPE_CODE (type) = TYPE_CODE_STRUCT; + break; + case 'u': + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + case 'e': + TYPE_CODE (type) = TYPE_CODE_ENUM; + break; + } + /* Skip the name the cross-ref points to. */ + *pp = (char *) index (*pp, ','); + /* Just allocate the type and leave it zero if nothing known */ + return dbx_alloc_type (typenums); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '(': + (*pp)--; + read_type_number (pp, xtypenums); + type = *dbx_lookup_type (xtypenums); + if (type == 0) + type = builtin_type_void; + *dbx_lookup_type (typenums) = type; + break; + + case '*': + type = dbx_alloc_type (typenums); + smash_to_pointer_type (type, read_type (pp)); + break; + + case 'f': + type = dbx_alloc_type (typenums); + smash_to_function_type (type, read_type (pp)); + break; + + case 'r': + type = read_range_type (pp, typenums); + *dbx_lookup_type (typenums) = type; + break; + + case 'e': + type = dbx_alloc_type (typenums); + type = read_enum_type (pp, type); + *dbx_lookup_type (typenums) = type; + break; + + case 's': + type = dbx_alloc_type (typenums); + type = read_struct_type (pp, type); + break; + + case 'u': + type = dbx_alloc_type (typenums); + type = read_struct_type (pp, type); + TYPE_CODE (type) = TYPE_CODE_UNION; + break; + + case 'a': + /* Define an array type. */ + type = dbx_alloc_type (typenums); + + /* dbx expresses array types in terms of a range type for the index, + and that range type is specified right inside the array type spec + making ar1;MIN;MAX;VALTYPE */ + if (!strncmp (*pp, "r1;0;", 5)) + (*pp) += 5; + else if (!strncmp (*pp, "r(0,1);0;", 9)) + (*pp) += 9; + else break; + + TYPE_CODE (type) = TYPE_CODE_ARRAY; + /* In Fortran, an upper bound may be T... meaning a parameter specifies + the length of the data. In this case, just pretend the bound is 1. + This happens only for array parameters, which are really passed + as pointers anyway, and we will translate them into such. */ + if (**pp == 'T') + { + n = 1; + while (**pp != ';') + (*pp)++; + } + else + n = read_number (pp, ';') + 1; + TYPE_TARGET_TYPE (type) = read_type (pp); + TYPE_LENGTH (type) = TYPE_LENGTH (TYPE_TARGET_TYPE (type)) * n; + break; + + default: + error ("Invalid symbol data: unrecognized type-code `%c' at symtab pos %d.", + (*pp)[-1], symnum); + } + + if (type == 0) + abort (); + +#if 0 + /* If this is an overriding temporary alteration for a header file's + contents, and this type number is unknown in the global definition, + put this type into the global definition at this type number. */ + if (header_file_prev_index >= 0) + { + register struct type **tp + = explicit_lookup_type (header_file_prev_index, typenums[1]); + if (*tp == 0) + *tp = type; + } +#endif + return type; +} + +/* This page contains subroutines of read_type. */ + +/* Read the description of a structure (or union type) + and return an object describing the type. */ + +static struct type * +read_struct_type (pp, type) + char **pp; + register struct type *type; +{ + struct nextfield + { + struct nextfield *next; + struct field field; + }; + + register struct nextfield *list = 0; + struct nextfield *new; + int totalsize; + char *name; + register char *p; + int nfields = 0; + register int n; + + TYPE_CODE (type) = TYPE_CODE_STRUCT; + + /* First comes the total size in bytes. */ + + TYPE_LENGTH (type) = read_number (pp, 0); + + /* Now come the fields, as NAME:TYPENUM,BITPOS,BITSIZE; for each one. + At the end, we see a semicolon instead of a field. */ + + while (**pp != ';') + { + /* Check for and handle cretinous dbx symbol name continuation! */ + if (**pp == '\\') + *pp = next_symbol_text (); + + /* Get space to record the next field's data. */ + new = (struct nextfield *) alloca (sizeof (struct nextfield)); + new->next = list; + list = new; + + /* Read the data. */ + p = *pp; + while (*p != ':') p++; + list->field.name = savestring (*pp, p - *pp); + *pp = p + 1; + list->field.type = read_type (pp); + if (**pp != ',') + error ("Invalid symbol data: bad structure-type format at symtab pos %d.", + symnum); + (*pp)++; /* Skip the comma. */ + list->field.bitpos = read_number (pp, ','); + list->field.bitsize = read_number (pp, ';'); + /* Detect an unpacked field and mark it as such. + dbx gives a bit size for all fields. + Also detect forward refs to structures and unions, + and treat enums as if they had the width of ints. */ + if ((list->field.bitsize == 8 * TYPE_LENGTH (list->field.type) + || TYPE_CODE (list->field.type) == TYPE_CODE_STRUCT + || TYPE_CODE (list->field.type) == TYPE_CODE_UNION + || (TYPE_CODE (list->field.type) == TYPE_CODE_ENUM + && list->field.bitsize == 8 * TYPE_LENGTH (builtin_type_int))) + && + list->field.bitpos % 8 == 0) + list->field.bitsize = 0; + nfields++; + } + + (*pp)++; /* Skip the terminating ';'. */ + + /* Now create the vector of fields, and record how big it is. */ + + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, + sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + + for (n = nfields; list; list = list->next) + TYPE_FIELD (type, --n) = list->field; + + return type; +} + +/* Read a definition of an enumeration type, + and create and return a suitable type object. + Also defines the symbols that represent the values of the type. */ + +static struct type * +read_enum_type (pp, type) + register char **pp; + register struct type *type; +{ + register char *p; + char *name; + register long n; + register struct symbol *sym; + int nsyms = 0; + struct pending **symlist; + struct pending *osyms, *syms; + + if (within_function) + symlist = &local_symbols; + else + symlist = &file_symbols; + osyms = *symlist; + + /* Read the value-names and their values. + The input syntax is NAME:VALUE,NAME:VALUE, and so on. + A semicolon instead of a NAME means the end. */ + while (**pp && **pp != ';') + { + /* Check for and handle cretinous dbx symbol name continuation! */ + if (**pp == '\\') + *pp = next_symbol_text (); + + p = *pp; + while (*p != ':') p++; + name = savestring (*pp, p - *pp); + *pp = p + 1; + n = read_number (pp, ','); + + sym = (struct symbol *) xmalloc (sizeof (struct symbol)); + bzero (sym, sizeof (struct symbol)); + SYMBOL_NAME (sym) = name; + SYMBOL_CLASS (sym) = LOC_CONST; + SYMBOL_NAMESPACE (sym) = VAR_NAMESPACE; + SYMBOL_VALUE (sym) = n; + add_symbol_to_list (sym, symlist); + nsyms++; + } + + (*pp)++; /* Skip the semicolon. */ + + /* Now fill in the fields of the type-structure. */ + + TYPE_LENGTH (type) = sizeof (int); + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_NFIELDS (type) = nsyms; + TYPE_FIELDS (type) = (struct field *) obstack_alloc (symbol_obstack, sizeof (struct field) * nsyms); + + /* Find the symbols for the values and put them into the type. + The symbols can be found in the symlist that we put them on + to cause them to be defined. osyms contains the old value + of that symlist; everything up to there was defined by us. */ + + for (syms = *symlist, n = nsyms; syms != osyms; syms = syms->next) + { + SYMBOL_TYPE (syms->symbol) = type; + TYPE_FIELD_NAME (type, --n) = SYMBOL_NAME (syms->symbol); + TYPE_FIELD_VALUE (type, n) = SYMBOL_VALUE (syms->symbol); + TYPE_FIELD_BITPOS (type, n) = 0; + TYPE_FIELD_BITSIZE (type, n) = 0; + } + + return type; +} + +static struct type * +read_range_type (pp, typenums) + char **pp; + int typenums[2]; +{ + char *errp = *pp; + int rangenums[2]; + int n1, n2, n3; + + /* First comes a type we are a subrange of. + In practice it is usually 0, 1 or the type being defined. */ + read_type_number (pp, rangenums); + n1 = rangenums[1]; + + /* A semicolon should now follow; skip it. */ + if (**pp == ';') + (*pp)++; + + /* The remaining two operands are usually lower and upper bounds + of the range. But in some special cases they mean something else. */ + n2 = read_number (pp, ';'); + n3 = read_number (pp, ';'); + + /* A type defined as a subrange of itself, with bounds both 0, is void. */ + if (rangenums[0] == typenums[0] && rangenums[1] == typenums[1] + && n2 == 0 && n3 == 0) + return builtin_type_void; + + /* If n3 is zero and n2 is not, we want a floating type, + and n2 is the width in bytes. + + Fortran programs appear to use this for complex types also, + and they give no way to distinguish between double and single-complex! + We don't have complex types, so we would lose on all fortran files! + So return type `double' for all of those. It won't work right + for the complex values, but at least it makes the file loadable. */ + + if (n3 == 0 && n2 > 0) + { + if (n2 == sizeof (float)) + return builtin_type_float; + return builtin_type_double; + } + + /* If the upper bound is -1, it must really be an unsigned int. */ + + else if (n2 == 0 && n3 == -1) + { + if (sizeof (int) == sizeof (long)) + return builtin_type_unsigned_int; + else + return builtin_type_unsigned_long; + } + + /* Detect unsigned subranges of int. Int is normally 1. + Note that `char' is usually given bounds of 0 to 127, + and would therefore appear unsigned; but it is described + as a subrange of itself, so we reject it here. */ + + else if (n2 == 0 && n1 == 1) + { + /* an unsigned type */ + if (n3 == (1 << (8 * sizeof (int))) - 1) + return builtin_type_unsigned_int; + if (n3 == (1 << (8 * sizeof (short))) - 1) + return builtin_type_unsigned_short; + if (n3 == (1 << (8 * sizeof (char))) - 1) + return builtin_type_unsigned_char; + } + else + { + /* a signed type */ + if (n3 == (1 << (8 * sizeof (int) - 1)) - 1) + return builtin_type_int; + if (n3 == (1 << (8 * sizeof (long) - 1)) - 1) + return builtin_type_long; + if (n3 == (1 << (8 * sizeof (short) - 1)) - 1) + return builtin_type_short; + if (n3 == (1 << (8 * sizeof (char) - 1)) - 1) + return builtin_type_char; + } + error ("Invalid symbol data: range type spec %s at symtab pos %d.", + errp - 1, symnum); +} + +/* Read a number from the string pointed to by *PP. + The value of *PP is advanced over the number. + If END is nonzero, the character that ends the + number must match END, or an error happens; + and that character is skipped if it does match. + If END is zero, *PP is left pointing to that character. */ + +static long +read_number (pp, end) + char **pp; + int end; +{ + register char *p = *pp; + register long n = 0; + register int c; + int sign = 1; + + /* Handle an optional leading minus sign. */ + + if (*p == '-') + { + sign = -1; + p++; + } + + /* Read the digits, as far as they go. */ + + while ((c = *p++) >= '0' && c <= '9') + { + n *= 10; + n += c - '0'; + } + if (end) + { + if (c != end) + error ("Invalid symbol data: invalid character \\%03o at symbol pos %d.", c, symnum); + } + else + --p; + + *pp = p; + return n * sign; +} + +static +initialize () +{ + symfile = 0; + + add_com ("symbol-file", class_files, symbol_file_command, + "Load symbol table (in dbx format) from executable file FILE."); +} + +END_FILE + +#endif /* READ_DBX_FORMAT */ diff --git a/gdb/defs.h b/gdb/defs.h new file mode 100644 index 00000000000..b23297216f0 --- /dev/null +++ b/gdb/defs.h @@ -0,0 +1,75 @@ +/* Basic definitions for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#define CORE_ADDR unsigned int + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +extern char *savestring (); +extern char *concat (); +extern char *xmalloc (), *xrealloc (); +extern int parse_escape (); +extern char *reg_names[]; + +extern int quit_flag; + +extern int immediate_quit; + +#define QUIT { if (quit_flag) quit (); } + +enum command_class +{ + class_run, class_vars, class_stack, class_files, class_support, class_info, + class_breakpoint, class_alias, class_obscure, class_user, +}; + +/* the cleanup list records things that have to be undone + if an error happens (descriptors to be closed, memory to be freed, etc.) + Each link in the chain records a function to call and an + argument to give it. + + Use make_cleanup to add an element to the cleanup chain. + Use do_cleanups to do all cleanup actions back to a given + point in the chain. Use discard_cleanups to remove cleanups + from the chain back to a given point, not doing them. */ + +struct cleanup +{ + struct cleanup *next; + void (*function) (); + int arg; +}; + +extern void do_cleanups (); +extern void discard_cleanups (); +extern struct cleanup *make_cleanup (); +extern void free_current_contents (); + +/* Structure for saved commands lines + (for breakpoints, defined commands, etc). */ + +struct command_line +{ + struct command_line *next; + char *line; +}; + +struct command_line *read_command_lines (); diff --git a/gdb/environ.c b/gdb/environ.c new file mode 100644 index 00000000000..0b9f913ca17 --- /dev/null +++ b/gdb/environ.c @@ -0,0 +1,250 @@ +/* environ.c -- library for manipulating environments for GNU. + Copyright (C) 1986 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more + extensive warranty protection to third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of this program in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + +In other words, feel free to share this program, but don't try to +stop anyone else from sharing it. */ + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) + +#include "environ.h" + +/* Return a new environment object. */ + +struct environ * +make_environ () +{ + register struct environ *e; + + e = (struct environ *) xmalloc (sizeof (struct environ)); + + e->allocated = 10; + e->vector = (char **) xmalloc ((e->allocated + 1) * sizeof (char *)); + e->vector[0] = 0; + return e; +} + +/* Free an environment and all the strings in it. */ + +void +free_environ (e) + register struct environ *e; +{ + register char **vector = e->vector; + + while (*vector) + free (*vector++); + + free (e); +} + +/* Copy the environment given to this process into E. + Also copies all the strings in it, so we can be sure + that all strings in these environments are safe to free. */ + +void +init_environ (e) + register struct environ *e; +{ + extern char **environ; + register int i; + + for (i = 0; environ[i]; i++); + + if (e->allocated < i) + { + e->allocated = max (i, e->allocated + 10); + e->vector = (char **) xrealloc (e->vector, + (e->allocated + 1) * sizeof (char *)); + } + + bcopy (environ, e->vector, (i + 1) * sizeof (char *)); + + while (--i >= 0) + { + register int len = strlen (e->vector[i]); + register char *new = (char *) xmalloc (len + 1); + bcopy (e->vector[i], new, len); + e->vector[i] = new; + } +} + +/* Return the vector of environment E. + This is used to get something to pass to execve. */ + +char ** +environ_vector (e) + struct environ *e; +{ + return e->vector; +} + +/* Return the value in environment E of variable VAR. */ + +char * +get_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; s = *vector; vector++) + if (!strncmp (s, var, len) + && s[len] == '=') + return &s[len + 1]; + + return 0; +} + +/* Store the value in E of VAR as VALUE. */ + +void +set_in_environ (e, var, value) + struct environ *e; + char *var; + char *value; +{ + register int i; + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (i = 0; s = vector[i]; i++) + if (!strncmp (s, var, len) + && s[len] == '=') + break; + + if (s == 0) + { + if (i == e->allocated) + { + e->allocated += 10; + vector = (char **) xrealloc (vector, + (e->allocated + 1) * sizeof (char *)); + e->vector = vector; + } + vector[i + 1] = 0; + } + else + free (s); + + s = (char *) xmalloc (len + strlen (value) + 2); + strcpy (s, var); + strcat (s, "="); + strcat (s, value); + vector[i] = s; + return; +} + +/* Remove the setting for variable VAR from environment E. */ + +void +unset_in_environ (e, var) + struct environ *e; + char *var; +{ + register int len = strlen (var); + register char **vector = e->vector; + register char *s; + + for (; s = *vector; vector++) + if (!strncmp (s, var, len) + && s[len] == '=') + { + free (s); + bcopy (vector + 1, vector, + (e->allocated - (vector - e->vector)) * sizeof (char *)); + e->vector[e->allocated - 1] = 0; + return; + } +} diff --git a/gdb/environ.h b/gdb/environ.h new file mode 100644 index 00000000000..5ebeaa26653 --- /dev/null +++ b/gdb/environ.h @@ -0,0 +1,23 @@ + +/* We manipulate environments represented as these structures. */ + +struct environ +{ + /* Number of usable slots allocated in VECTOR. + VECTOR always has one slot not counted here, + to hold the terminating zero. */ + int allocated; + /* A vector of slots, ALLOCATED + 1 of them. + The first few slots contain strings "VAR=VALUE" + and the next one contains zero. + Then come some unused slots. */ + char **vector; +}; + +struct environ *make_environ (); +void free_environ (); +void init_environ (); +char *get_in_environ (); +void set_in_environ (); +void unset_in_environ (); +char **environ_vector (); diff --git a/gdb/eval.c b/gdb/eval.c new file mode 100644 index 00000000000..97f39c3b832 --- /dev/null +++ b/gdb/eval.c @@ -0,0 +1,556 @@ +/* Evaluate expressions for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "value.h" +#include "expression.h" + +START_FILE + +/* Parse the string EXP as a C expression, evaluate it, + and return the result as a number. */ + +CORE_ADDR +parse_and_eval_address (exp) + char *exp; +{ + struct expression *expr = parse_c_expression (exp); + register CORE_ADDR addr; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + addr = value_as_long (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +/* Like parse_and_eval_address but takes a pointer to a char * variable + and advanced that variable across the characters parsed. */ + +CORE_ADDR +parse_and_eval_address_1 (expptr) + char **expptr; +{ + struct expression *expr = parse_c_1 (expptr, 0); + register CORE_ADDR addr; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + addr = value_as_long (evaluate_expression (expr)); + do_cleanups (old_chain); + return addr; +} + +value +parse_and_eval (exp) + char *exp; +{ + struct expression *expr = parse_c_expression (exp); + register value val; + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + do_cleanups (old_chain); + return val; +} + +/* Evaluate an expression in internal prefix form + such as is constructed by expread.y. + + See expression.h for info on the format of an expression. */ + +static value evaluate_subexp (); +static value evaluate_subexp_for_address (); +static value evaluate_subexp_for_sizeof (); +static value evaluate_subexp_with_coercion (); + +/* Values of NOSIDE argument to eval_subexp. */ +enum noside +{ EVAL_NORMAL, + EVAL_SKIP, + EVAL_AVOID_SIDE_EFFECTS, +}; + +value +evaluate_expression (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (exp, &pc, EVAL_NORMAL); +} + +/* Evaluate an expression, avoiding all memory references + and getting a value whose type alone is correct. */ + +value +evaluate_type (exp) + struct expression *exp; +{ + int pc = 0; + return evaluate_subexp (exp, &pc, EVAL_AVOID_SIDE_EFFECTS); +} + +static value +evaluate_subexp (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + int tem; + register int pc; + register value arg1, arg2; + int nargs; + value *argvec; + + pc = (*pos)++; + op = exp->elts[pc].opcode; + + switch (op) + { + case OP_LONG: + (*pos) += 3; + return value_from_long (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst); + + case OP_DOUBLE: + (*pos) += 3; + return value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst); + + case OP_VAR_VALUE: + (*pos) += 2; + if (noside == EVAL_SKIP) + goto nosideret; + return value_of_variable (exp->elts[pc + 1].symbol); + + case OP_LAST: + (*pos) += 2; + return access_value_history (exp->elts[pc + 1].longconst); + + case OP_REGISTER: + (*pos) += 2; + return value_of_register (exp->elts[pc + 1].longconst); + + case OP_INTERNALVAR: + (*pos) += 2; + return value_of_internalvar (exp->elts[pc + 1].internalvar); + + case OP_FUNCALL: + (*pos) += 2; + nargs = exp->elts[pc + 1].longconst; + argvec = (value *) alloca (sizeof (value) * (nargs + 1)); + for (tem = 0; tem <= nargs; tem++) + + /* Ensure that array expressions are coerced into pointer objects. */ + argvec[tem] = evaluate_subexp_with_coercion (exp, pos, noside); + + if (noside == EVAL_SKIP) + goto nosideret; + if (noside == EVAL_AVOID_SIDE_EFFECTS) + return allocate_value (TYPE_TARGET_TYPE (VALUE_TYPE (argvec[0]))); + return call_function (argvec[0], nargs, argvec + 1); + + case OP_STRING: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + if (noside == EVAL_SKIP) + goto nosideret; + return value_string (&exp->elts[pc + 1].string, tem); + + case TERNOP_COND: + /* Skip third and second args to evaluate the first one. */ + arg1 = evaluate_subexp (exp, pos, noside); + if (value_zerop (arg1)) + { + evaluate_subexp (exp, pos, EVAL_SKIP); + return evaluate_subexp (exp, pos, noside); + } + else + { + arg2 = evaluate_subexp (exp, pos, noside); + evaluate_subexp (exp, pos, EVAL_SKIP); + return arg2; + } + + case STRUCTOP_STRUCT: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_struct_elt (arg1, &exp->elts[pc + 1].string, + "structure"); + + case STRUCTOP_PTR: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_struct_elt (arg1, &exp->elts[pc + 1].string, + "structure pointer"); + + case BINOP_ASSIGN: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + return value_assign (arg1, arg2); + + case BINOP_ASSIGN_MODIFY: + (*pos) += 2; + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + op = exp->elts[pc + 1].opcode; + if (op == BINOP_ADD) + arg2 = value_add (arg1, arg2); + else if (op == BINOP_SUB) + arg2 = value_sub (arg1, arg2); + else + arg2 = value_binop (arg1, arg2, op); + return value_assign (arg1, arg2); + + case BINOP_ADD: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_add (arg1, arg2); + + case BINOP_SUB: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_sub (arg1, arg2); + + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_LSH: + case BINOP_RSH: + case BINOP_LOGAND: + case BINOP_LOGIOR: + case BINOP_LOGXOR: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_binop (arg1, arg2, op); + + case BINOP_SUBSCRIPT: + arg1 = evaluate_subexp_with_coercion (exp, pos, noside); + arg2 = evaluate_subexp_with_coercion (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_subscript (arg1, arg2, op); + + case BINOP_AND: + arg1 = evaluate_subexp (exp, pos, noside); + tem = value_zerop (arg1); + arg2 = evaluate_subexp (exp, pos, + (tem ? EVAL_SKIP : noside)); + return value_from_long (builtin_type_int, + !tem && !value_zerop (arg2)); + + case BINOP_OR: + arg1 = evaluate_subexp (exp, pos, noside); + tem = value_zerop (arg1); + arg2 = evaluate_subexp (exp, pos, + (!tem ? EVAL_SKIP : noside)); + return value_from_long (builtin_type_int, + !tem || !value_zerop (arg2)); + + case BINOP_EQUAL: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_equal (arg1, arg2); + return value_from_long (builtin_type_int, tem); + + case BINOP_NOTEQUAL: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_equal (arg1, arg2); + return value_from_long (builtin_type_int, ! tem); + + case BINOP_LESS: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_less (arg1, arg2); + return value_from_long (builtin_type_int, tem); + + case BINOP_GTR: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_less (arg2, arg1); + return value_from_long (builtin_type_int, tem); + + case BINOP_GEQ: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_less (arg1, arg2); + return value_from_long (builtin_type_int, ! tem); + + case BINOP_LEQ: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + tem = value_less (arg2, arg1); + return value_from_long (builtin_type_int, ! tem); + + case BINOP_REPEAT: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_repeat (arg1, value_as_long (arg2)); + + case BINOP_COMMA: + evaluate_subexp (exp, pos, noside); + return evaluate_subexp (exp, pos, noside); + + case UNOP_NEG: + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_neg (arg1); + + case UNOP_LOGNOT: + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_lognot (arg1); + + case UNOP_ZEROP: + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_from_long (builtin_type_int, value_zerop (arg1)); + + case UNOP_IND: + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_ind (arg1); + + case UNOP_ADDR: + if (noside == EVAL_SKIP) + { + evaluate_subexp (exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_address (exp, pos, noside); + + case UNOP_SIZEOF: + if (noside == EVAL_SKIP) + { + evaluate_subexp (exp, pos, EVAL_SKIP); + goto nosideret; + } + return evaluate_subexp_for_sizeof (exp, pos); + + case UNOP_CAST: + (*pos) += 2; + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_cast (exp->elts[pc + 1].type, arg1); + + case UNOP_MEMVAL: + (*pos) += 2; + arg1 = evaluate_subexp (exp, pos, noside); + if (noside == EVAL_SKIP) + goto nosideret; + return value_at (exp->elts[pc + 1].type, value_as_long (arg1)); + + case UNOP_PREINCREMENT: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = value_add (arg1, value_from_long (builtin_type_char, 1)); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + return value_assign (arg1, arg2); + + case UNOP_PREDECREMENT: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1)); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + return value_assign (arg1, arg2); + + case UNOP_POSTINCREMENT: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = value_add (arg1, value_from_long (builtin_type_char, 1)); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + value_assign (arg1, arg2); + return arg1; + + case UNOP_POSTDECREMENT: + arg1 = evaluate_subexp (exp, pos, noside); + arg2 = value_sub (arg1, value_from_long (builtin_type_char, 1)); + if (noside == EVAL_SKIP || noside == EVAL_AVOID_SIDE_EFFECTS) + return arg1; + value_assign (arg1, arg2); + return arg1; + } + + nosideret: + return value_from_long (builtin_type_long, 1); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return the address of that subexpression. + Advance *POS over the subexpression. + If the subexpression isn't an lvalue, get an error. + NOSIDE may be EVAL_AVOID_SIDE_EFFECTS; + then only the type of the result need be correct. */ + +static value +evaluate_subexp_for_address (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + enum exp_opcode op; + register int pc; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + case UNOP_IND: + (*pos)++; + return evaluate_subexp (exp, pos, noside); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_cast (lookup_pointer_type (exp->elts[pc + 1].type), + evaluate_subexp (exp, pos, noside)); + + case OP_VAR_VALUE: + (*pos) += 3; + return locate_var_value (exp->elts[pc + 1].symbol, (CORE_ADDR) 0); + + default: + return value_addr (evaluate_subexp (exp, pos, noside)); + } +} + +/* Evaluate like `evaluate_subexp' except coercing arrays to pointers. + When used in contexts where arrays will be coerced anyway, + this is equivalent to `evaluate_subexp' + but much faster because it avoids actually fetching array contents. */ + +static value +evaluate_subexp_with_coercion (exp, pos, noside) + register struct expression *exp; + register int *pos; + enum noside noside; +{ + register enum exp_opcode op; + register int pc; + register value val; + + pc = (*pos); + 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 (exp, pos, noside); +} + +/* Evaluate a subexpression of EXP, at index *POS, + and return a value for the size of that subexpression. + Advance *POS over the subexpression. */ + +static value +evaluate_subexp_for_sizeof (exp, pos) + register struct expression *exp; + register int *pos; +{ + enum exp_opcode op; + register int pc; + value val; + + pc = (*pos); + op = exp->elts[pc].opcode; + + switch (op) + { + /* This case is handled specially + so that we avoid creating a value for the result type. + If the result type is very big, it's desirable not to + create a value unnecessarily. */ + case UNOP_IND: + (*pos)++; + val = evaluate_subexp (exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_long (builtin_type_int, + TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (val)))); + + case UNOP_MEMVAL: + (*pos) += 3; + return value_from_long (builtin_type_int, + TYPE_LENGTH (exp->elts[pc + 1].type)); + + case OP_VAR_VALUE: + (*pos) += 3; + return value_from_long (builtin_type_int, + TYPE_LENGTH (SYMBOL_TYPE (exp->elts[pc + 1].symbol))); + + default: + val = evaluate_subexp (exp, pos, EVAL_AVOID_SIDE_EFFECTS); + return value_from_long (builtin_type_int, + TYPE_LENGTH (VALUE_TYPE (val))); + } +} + +static +initialize () +{ } + +END_FILE diff --git a/gdb/expprint.c b/gdb/expprint.c new file mode 100644 index 00000000000..36b31c6fa8c --- /dev/null +++ b/gdb/expprint.c @@ -0,0 +1,304 @@ +/* Print in infix form a struct expression. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "symtab.h" +#include "expression.h" + +#include + +/* These codes indicate operator precedences, least tightly binding first. */ +/* Adding 1 to a precedence value is done for binary operators, + on the operand which is more tightly bound, so that operators + of equal precedence within that operand will get parentheses. */ +/* PREC_HYPER and PREC_ABOVE_COMMA are not the precedence of any operator; + they are used as the "surrounding precedence" to force + various kinds of things to be parenthesized. */ +enum precedence +{ PREC_NULL, PREC_COMMA, PREC_ABOVE_COMMA, PREC_ASSIGN, PREC_OR, PREC_AND, + PREC_LOGIOR, PREC_LOGAND, PREC_LOGXOR, PREC_EQUAL, PREC_ORDER, + PREC_SHIFT, PREC_ADD, PREC_MUL, PREC_REPEAT, + PREC_HYPER, PREC_PREFIX, PREC_SUFFIX }; + +/* Table mapping opcodes into strings for printing operators + and precedences of the operators. */ + +struct op_print +{ + char *string; + enum exp_opcode opcode; + /* Precedence of operator. These values are used only by comparisons. */ + enum precedence precedence; + int right_assoc; +}; + +static struct op_print op_print_tab[] = + { + {",", BINOP_COMMA, PREC_COMMA, 0}, + {"=", BINOP_ASSIGN, PREC_ASSIGN, 1}, + {"||", BINOP_OR, PREC_OR, 0}, + {"&&", BINOP_AND, PREC_AND, 0}, + {"|", BINOP_LOGIOR, PREC_LOGIOR, 0}, + {"&", BINOP_LOGAND, PREC_LOGAND, 0}, + {"^", BINOP_LOGXOR, PREC_LOGXOR, 0}, + {"==", BINOP_EQUAL, PREC_EQUAL, 0}, + {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0}, + {"<=", BINOP_LEQ, PREC_ORDER, 0}, + {">=", BINOP_GEQ, PREC_ORDER, 0}, + {">", BINOP_GTR, PREC_ORDER, 0}, + {"<", BINOP_LESS, PREC_ORDER, 0}, + {">>", BINOP_RSH, PREC_SHIFT, 0}, + {"<<", BINOP_LSH, PREC_SHIFT, 0}, + {"+", BINOP_ADD, PREC_ADD, 0}, + {"-", BINOP_SUB, PREC_ADD, 0}, + {"*", BINOP_MUL, PREC_MUL, 0}, + {"/", BINOP_DIV, PREC_MUL, 0}, + {"%", BINOP_REM, PREC_MUL, 0}, + {"@", BINOP_REPEAT, PREC_REPEAT, 0}, + {"-", UNOP_NEG, PREC_PREFIX, 0}, + {"!", UNOP_ZEROP, PREC_PREFIX, 0}, + {"~", UNOP_LOGNOT, PREC_PREFIX, 0}, + {"*", UNOP_IND, PREC_PREFIX, 0}, + {"&", UNOP_ADDR, PREC_PREFIX, 0}, + {"sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0}, + {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0}, + {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0} + }; + +static void print_subexp (); + +void +print_expression (exp, stream) + struct expression *exp; + FILE *stream; +{ + int pc = 0; + print_subexp (exp, &pc, stream, PREC_NULL); +} + +/* Print the subexpression of EXP that starts in position POS, on STREAM. + PREC is the precedence of the surrounding operator; + if the precedence of the main operator of this subexpression is less, + parentheses are needed here. */ + +static void +print_subexp (exp, pos, stream, prec) + register struct expression *exp; + register int *pos; + FILE *stream; + enum precedence prec; +{ + register int tem; + register int pc; + int nargs; + register char *op_str; + int assign_modify = 0; + enum exp_opcode opcode; + enum precedence myprec; + /* Set to 1 for a right-associative operator. */ + int assoc; + + pc = (*pos)++; + opcode = exp->elts[pc].opcode; + switch (opcode) + { + case OP_LONG: + (*pos) += 3; + value_print (value_from_long (exp->elts[pc + 1].type, + exp->elts[pc + 2].longconst), + stream); + return; + + case OP_DOUBLE: + (*pos) += 3; + value_print (value_from_double (exp->elts[pc + 1].type, + exp->elts[pc + 2].doubleconst), + stream); + return; + + case OP_VAR_VALUE: + (*pos) += 2; + fprintf (stream, "%s", SYMBOL_NAME (exp->elts[pc + 1].symbol)); + return; + + case OP_LAST: + (*pos) += 2; + fprintf (stream, "$%d", exp->elts[pc + 1].longconst); + return; + + case OP_REGISTER: + (*pos) += 2; + fprintf (stream, "$%s", reg_names[exp->elts[pc + 1].longconst]); + return; + + case OP_INTERNALVAR: + (*pos) += 2; + fprintf (stream, "$%s", + internalvar_name (exp->elts[pc + 1].internalvar)); + return; + + case OP_FUNCALL: + (*pos) += 2; + nargs = exp->elts[pc + 1].longconst; + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, " ("); + for (tem = 0; tem < nargs; tem++) + { + if (tem > 0) + fprintf (stream, ", "); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + } + fprintf (stream, ")"); + return; + + case OP_STRING: + nargs = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (nargs + sizeof (union exp_element)) / sizeof (union exp_element); + fprintf (stream, "\""); + for (tem = 0; tem < nargs; tem++) + printchar ((&exp->elts[pc + 1].string)[tem], stream); + fprintf (stream, "\""); + return; + + case TERNOP_COND: + if ((int) prec > (int) PREC_COMMA) + fprintf (stream, "("); + /* Print the subexpressions, forcing parentheses + around any binary operations within them. + This is more parentheses than are strictly necessary, + but it looks clearer. */ + print_subexp (exp, pos, stream, PREC_HYPER); + fprintf (stream, " ? "); + print_subexp (exp, pos, stream, PREC_HYPER); + fprintf (stream, " : "); + print_subexp (exp, pos, stream, PREC_HYPER); + if ((int) prec > (int) PREC_COMMA) + fprintf (stream, ")"); + return; + + case STRUCTOP_STRUCT: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, ".%s", &exp->elts[pc + 1].string); + return; + + case STRUCTOP_PTR: + tem = strlen (&exp->elts[pc + 1].string); + (*pos) += 2 + (tem + sizeof (union exp_element)) / sizeof (union exp_element); + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "->%s", &exp->elts[pc + 1].string); + return; + + case BINOP_SUBSCRIPT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "["); + print_subexp (exp, pos, stream, PREC_ABOVE_COMMA); + fprintf (stream, "]"); + return; + + case UNOP_POSTINCREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "++"); + return; + + case UNOP_POSTDECREMENT: + print_subexp (exp, pos, stream, PREC_SUFFIX); + fprintf (stream, "--"); + return; + + case UNOP_CAST: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, "("); + fprintf (stream, "("); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fprintf (stream, ") "); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, ")"); + return; + + case UNOP_MEMVAL: + (*pos) += 2; + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, "("); + fprintf (stream, "{"); + type_print (exp->elts[pc + 1].type, "", stream, 0); + fprintf (stream, "} "); + print_subexp (exp, pos, stream, PREC_PREFIX); + if ((int) prec > (int) PREC_PREFIX) + fprintf (stream, ")"); + return; + + case BINOP_ASSIGN_MODIFY: + opcode = exp->elts[pc + 1].opcode; + (*pos) += 2; + myprec = PREC_ASSIGN; + assoc = 1; + assign_modify = 1; + for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + break; + } + + default: + for (tem = 0; tem < sizeof op_print_tab / sizeof op_print_tab[0]; tem++) + if (op_print_tab[tem].opcode == opcode) + { + op_str = op_print_tab[tem].string; + myprec = op_print_tab[tem].precedence; + assoc = op_print_tab[tem].right_assoc; + break; + } + } + + if ((int) myprec < (int) prec) + fprintf (stream, "("); + if ((int) opcode > (int) BINOP_END) + { + /* Unary prefix operator. */ + fprintf (stream, "%s", op_str); + print_subexp (exp, pos, stream, PREC_PREFIX); + } + else + { + /* Binary operator. */ + /* Print left operand. + If operator is right-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, (int) myprec + assoc); + /* Print the operator itself. */ + if (assign_modify) + fprintf (stream, " %s= ", op_str); + else if (op_str[0] == ',') + fprintf (stream, "%s ", op_str); + else + fprintf (stream, " %s ", op_str); + /* Print right operand. + If operator is left-associative, + increment precedence for this operand. */ + print_subexp (exp, pos, stream, (int) myprec + !assoc); + } + if ((int) myprec < (int) prec) + fprintf (stream, ")"); +} diff --git a/gdb/expread.y b/gdb/expread.y new file mode 100644 index 00000000000..468d409a7d8 --- /dev/null +++ b/gdb/expread.y @@ -0,0 +1,1189 @@ +/* Parse C expressions for GDB. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Parse a C expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. */ + +%{ +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "expression.h" + +#include + +static struct expression *expout; +static int expout_size; +static int expout_ptr; + +static int yylex (); +static yyerror (); +static void write_exp_elt (); +static void write_exp_string (); +static void start_arglist (); +static int end_arglist (); +static void free_funcalls (); +static char *copy_name (); + +/* If this is nonzero, this block is used as the lexical context + for symbol names. */ + +static struct block *expression_context_block; + +/* Number of arguments seen so far in innermost function call. */ +static int arglist_len; + +/* Data structure for saving values of arglist_len + for function calls whose arguments contain other function calls. */ + +struct funcall + { + struct funcall *next; + int arglist_len; + }; + +struct funcall *funcall_chain; + +/* This kind of datum is used to represent the name + of a symbol token. */ + +struct stoken + { + char *ptr; + int length; + }; +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + long lval; + double dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + } + +%type exp exp1 start variable +%type type typebase +%type block + +%token INT CHAR +%token FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token NAME TYPENAME STRING +%type name + +%token STRUCT UNION ENUM SIZEOF UNSIGNED COLONCOLON + +%token LAST REGNAME + +%token VARIABLE + +%token ASSIGN_MODIFY + +%left ',' +%left ABOVE_COMMA +%right '=' ASSIGN_MODIFY +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOTEQUAL +%left '<' '>' LEQ GEQ +%left LSH RSH +%left '+' '-' +%left '*' '/' '%' +%left '@' +%right UNARY INCREMENT DECREMENT +%right ARROW '.' '[' +%left COLONCOLON + +%% + +start : exp1 + ; + +/* Expressions, including the comma operator. */ +exp1 : exp + | exp1 ',' exp + { write_exp_elt (BINOP_COMMA); } + ; + +/* Expressions, not including the comma operator. */ +exp : '*' exp %prec UNARY + { write_exp_elt (UNOP_IND); } + +exp : '&' exp %prec UNARY + { write_exp_elt (UNOP_ADDR); } + +exp : '-' exp %prec UNARY + { write_exp_elt (UNOP_NEG); } + ; + +exp : '!' exp %prec UNARY + { write_exp_elt (UNOP_ZEROP); } + ; + +exp : '~' exp %prec UNARY + { write_exp_elt (UNOP_LOGNOT); } + ; + +exp : INCREMENT exp %prec UNARY + { write_exp_elt (UNOP_PREINCREMENT); } + ; + +exp : DECREMENT exp %prec UNARY + { write_exp_elt (UNOP_PREDECREMENT); } + ; + +exp : exp INCREMENT %prec UNARY + { write_exp_elt (UNOP_POSTINCREMENT); } + ; + +exp : exp DECREMENT %prec UNARY + { write_exp_elt (UNOP_POSTDECREMENT); } + ; + +exp : SIZEOF exp %prec UNARY + { write_exp_elt (UNOP_SIZEOF); } + ; + +exp : exp ARROW name + { write_exp_elt (STRUCTOP_PTR); + write_exp_string ($3); + write_exp_elt (STRUCTOP_PTR); } + ; + +exp : exp '.' name + { write_exp_elt (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt (STRUCTOP_STRUCT); } + ; + +exp : exp '[' exp1 ']' + { write_exp_elt (BINOP_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' + { write_exp_elt (OP_FUNCALL); + write_exp_elt (end_arglist ()); + write_exp_elt (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +exp : '{' type '}' exp %prec UNARY + { write_exp_elt (UNOP_MEMVAL); + write_exp_elt ($2); + write_exp_elt (UNOP_MEMVAL); } + ; + +exp : '(' type ')' exp %prec UNARY + { write_exp_elt (UNOP_CAST); + write_exp_elt ($2); + write_exp_elt (UNOP_CAST); } + ; + +exp : '(' exp1 ')' + { } + ; + +/* Binary operators in order of decreasing precedence. */ + +exp : exp '@' exp + { write_exp_elt (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt (BINOP_DIV); } + ; + +exp : exp '%' exp + { write_exp_elt (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt (BINOP_SUB); } + ; + +exp : exp LSH exp + { write_exp_elt (BINOP_LSH); } + ; + +exp : exp RSH exp + { write_exp_elt (BINOP_RSH); } + ; + +exp : exp EQUAL exp + { write_exp_elt (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt (BINOP_GTR); } + ; + +exp : exp '&' exp + { write_exp_elt (BINOP_LOGAND); } + ; + +exp : exp '^' exp + { write_exp_elt (BINOP_LOGXOR); } + ; + +exp : exp '|' exp + { write_exp_elt (BINOP_LOGIOR); } + ; + +exp : exp AND exp + { write_exp_elt (BINOP_AND); } + ; + +exp : exp OR exp + { write_exp_elt (BINOP_OR); } + ; + +exp : exp '?' exp ':' exp + { write_exp_elt (TERNOP_COND); } + ; + +exp : exp '=' exp + { write_exp_elt (BINOP_ASSIGN); } + ; + +exp : exp ASSIGN_MODIFY exp + { write_exp_elt (BINOP_ASSIGN_MODIFY); + write_exp_elt ($2); + write_exp_elt (BINOP_ASSIGN_MODIFY); } + ; + +exp : INT + { write_exp_elt (OP_LONG); + write_exp_elt (builtin_type_long); + write_exp_elt ($1); + write_exp_elt (OP_LONG); } + ; + +exp : CHAR + { write_exp_elt (OP_LONG); + write_exp_elt (builtin_type_char); + write_exp_elt ($1); + write_exp_elt (OP_LONG); } + ; + +exp : FLOAT + { write_exp_elt (OP_DOUBLE); + write_exp_elt (builtin_type_double); + write_exp_elt ($1); + write_exp_elt (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : LAST + { write_exp_elt (OP_LAST); + write_exp_elt ($1); + write_exp_elt (OP_LAST); } + ; + +exp : REGNAME + { write_exp_elt (OP_REGISTER); + write_exp_elt ($1); + write_exp_elt (OP_REGISTER); } + ; + +exp : VARIABLE + { write_exp_elt (OP_INTERNALVAR); + write_exp_elt ($1); + write_exp_elt (OP_INTERNALVAR); } + ; + +exp : SIZEOF '(' type ')' + { write_exp_elt (OP_LONG); + write_exp_elt (builtin_type_int); + write_exp_elt ((long) TYPE_LENGTH ($3)); + write_exp_elt (OP_LONG); } + ; + +exp : STRING + { write_exp_elt (OP_STRING); + write_exp_string ($1); + write_exp_elt (OP_STRING); } + ; + +block : name + { struct symtab *tem = lookup_symtab (copy_name ($1)); + struct symbol *sym; + + if (tem) + $$ = BLOCKVECTOR_BLOCK (BLOCKVECTOR (tem), 1); + else + { + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + $$ = SYMBOL_BLOCK_VALUE (sym); + else + error ("No file or function \"%s\".", + copy_name ($1)); + }} + ; + +block : block COLONCOLON name + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, VAR_NAMESPACE); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = SYMBOL_BLOCK_VALUE (tem); } + ; + +variable: block COLONCOLON name + { struct symbol *sym; + sym = lookup_symbol ($3, copy_name ($1), VAR_NAMESPACE); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + write_exp_elt (OP_VAR_VALUE); + write_exp_elt (sym); + write_exp_elt (OP_VAR_VALUE); } + ; + +variable: NAME + { struct symbol *sym; + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE); + if (sym) + { + write_exp_elt (OP_VAR_VALUE); + write_exp_elt (sym); + write_exp_elt (OP_VAR_VALUE); + } + else + { + register char *arg = copy_name ($1); + register int i; + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, arg)) + break; + + if (i < misc_function_count) + { + write_exp_elt (OP_LONG); + write_exp_elt (builtin_type_int); + write_exp_elt (misc_function_vector[i].address); + write_exp_elt (OP_LONG); + write_exp_elt (UNOP_MEMVAL); + write_exp_elt (builtin_type_char); + write_exp_elt (UNOP_MEMVAL); + } + else + if (symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1)); + } + } + ; + +type : typebase + | type '*' + { $$ = lookup_pointer_type ($1); } + ; + +typebase + : TYPENAME + { $$ = lookup_typename (copy_name ($1), + expression_context_block, 0); } + | STRUCT name + { $$ = lookup_struct (copy_name ($2), + expression_context_block); } + | UNION name + { $$ = lookup_union (copy_name ($2), + expression_context_block); } + | ENUM name + { $$ = lookup_enum (copy_name ($2), + expression_context_block); } + | UNSIGNED name + { $$ = lookup_unsigned_typename (copy_name ($2)); } + ; + +name : NAME + | TYPENAME + ; +%% + +/* Begin counting arguments for a function call, + saving the data about any containing call. */ + +static void +start_arglist () +{ + register struct funcall *new = (struct funcall *) xmalloc (sizeof (struct funcall)); + + new->next = funcall_chain; + new->arglist_len = arglist_len; + arglist_len = 0; + funcall_chain = new; +} + +/* Return the number of arguments in a function call just terminated, + and restore the data for the containing function call. */ + +static int +end_arglist () +{ + register int val = arglist_len; + register struct funcall *call = funcall_chain; + funcall_chain = call->next; + arglist_len = call->arglist_len; + free (call); + return val; +} + +/* Free everything in the funcall chain. + Used when there is an error inside parsing. */ + +static void +free_funcalls () +{ + register struct funcall *call, *next; + + for (call = funcall_chain; call; call = next) + { + next = call->next; + free (call); + } +} + +/* This page contains the functions for adding data to the struct expression + being constructed. */ + +/* Add one element to the end of the expression. */ + +static void +write_exp_elt (expelt) + union exp_element expelt; +{ + if (expout_ptr >= expout_size) + { + expout_size *= 2; + expout = (struct expression *) xrealloc (expout, + sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + } + expout->elts[expout_ptr++] = expelt; +} + +/* Add a string constant to the end of the expression. + Follow it by its length in bytes, as a separate exp_element. */ + +static void +write_exp_string (str) + struct stoken str; +{ + register int len = str.length; + register int lenelt + = (len + sizeof (union exp_element)) / sizeof (union exp_element); + + expout_ptr += lenelt; + + if (expout_ptr >= expout_size) + { + expout_size = max (expout_size * 2, expout_ptr + 10); + expout = (struct expression *) xrealloc (expout, + sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + } + bcopy (str.ptr, (char *) &expout->elts[expout_ptr - lenelt], len); + ((char *) &expout->elts[expout_ptr - lenelt])[len] = 0; + write_exp_elt (len); +} + +/* During parsing of a C expression, the pointer to the next character + is in this variable. */ + +static char *lexptr; + +/* Tokens that refer to names do so with explicit pointer and length, + so they can share the storage that lexptr is parsing. + + When it is necessary to pass a name to a function that expects + a null-terminated string, the substring is copied out + into a block of storage that namecopy points to. + + namecopy is allocated once, guaranteed big enough, for each parsing. */ + +static char *namecopy; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register long n = 0; + register int c; + register int base = 10; + register int len = olen; + char *err_copy; + + extern double atof (); + + for (c = 0; c < len; c++) + if (p[c] == '.') + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + + if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) + { + p += 2; + base = 16; + len -= 2; + } + else if (*p == '0') + base = 8; + + while (len-- > 0) + { + c = *p++; + n *= base; + if (c >= '0' && c <= '9') + n += c - '0'; + else + { + if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; + if (base == 16 && c >= 'a' && c <= 'f') + n += c - 'a' + 10; + else if (len == 0 && c == 'l') + ; + else + { + err_copy = (char *) alloca (olen + 1); + bcopy (lexptr, err_copy, olen); + err_copy[olen] = 0; + error ("Invalid number \"%s\".", err_copy); + } + } + } + + lexptr = p; + yylval.lval = n; + return INT; +} + +struct token +{ + char *operator; + int token; + enum exp_opcode opcode; +}; + +static struct token tokentab3[] = + { + {">>=", ASSIGN_MODIFY, BINOP_RSH}, + {"<<=", ASSIGN_MODIFY, BINOP_LSH} + }; + +static struct token tokentab2[] = + { + {"+=", ASSIGN_MODIFY, BINOP_ADD}, + {"-=", ASSIGN_MODIFY, BINOP_SUB}, + {"*=", ASSIGN_MODIFY, BINOP_MUL}, + {"/=", ASSIGN_MODIFY, BINOP_DIV}, + {"%=", ASSIGN_MODIFY, BINOP_REM}, + {"|=", ASSIGN_MODIFY, BINOP_LOGIOR}, + {"&=", ASSIGN_MODIFY, BINOP_LOGAND}, + {"^=", ASSIGN_MODIFY, BINOP_LOGXOR}, + {"++", INCREMENT, BINOP_END}, + {"--", DECREMENT, BINOP_END}, + {"->", ARROW, BINOP_END}, + {"&&", AND, BINOP_END}, + {"||", OR, BINOP_END}, + {"::", COLONCOLON, BINOP_END}, + {"<<", LSH, BINOP_END}, + {">>", RSH, BINOP_END}, + {"==", EQUAL, BINOP_END}, + {"!=", NOTEQUAL, BINOP_END}, + {"<=", LEQ, BINOP_END}, + {">=", GEQ, BINOP_END} + }; + +/* Read one token, getting characters through lexptr. */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + + retry: + + tokstart = lexptr; + /* See if it is a special token of length 3. */ + for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++) + if (!strncmp (tokstart, tokentab3[i].operator, 3)) + { + lexptr += 3; + yylval.opcode = tokentab3[i].opcode; + return tokentab3[i].token; + } + + /* See if it is a special token of length 2. */ + for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++) + if (!strncmp (tokstart, tokentab2[i].operator, 2)) + { + lexptr += 2; + yylval.opcode = tokentab2[i].opcode; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '\'': + lexptr++; + c = *lexptr++; + if (c == '\\') + c = parse_escape (&lexptr); + yylval.lval = c; + c = *lexptr++; + if (c != '\'') + error ("Invalid character constant."); + return CHAR; + + case '+': + case '-': + case '*': + case '/': + case '%': + case '|': + case '&': + case '^': + case '~': + case '!': + case '@': + case '<': + case '>': + case '(': + case ')': + case '[': + case ']': + case '.': + case '?': + case ':': + case '=': + case '{': + case '}': + case ',': + lexptr++; + return c; + + case '"': + for (namelen = 1; (c = tokstart[namelen]) != '"'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + return STRING; + } + if (c >= '0' && c <= '9') + { + /* It's a number */ + for (namelen = 0; + c = tokstart[namelen], + (c == '_' || c == '$' || c == '.' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + namelen++) + ; + return parse_number (namelen); + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + error ("Invalid token in expression."); + + /* It is a name. See how long it is. */ + + for (namelen = 0; + c = tokstart[namelen], + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + namelen++) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Handle the tokens $digits; also $ (short for $0) and $$ (short for $$1) + and $$digits (equivalent to $<-digits> if you could type that). + Make token type LAST, and put the number (the digits) in yylval. */ + + if (*tokstart == '$') + { + register int negate = 0; + c = 1; + /* Double dollar means negate the number and add -1 as well. + Thus $$ alone means -1. */ + if (namelen >= 2 && tokstart[1] == '$') + { + negate = 1; + c = 2; + } + if (c == namelen) + { + /* Just dollars (one or two) */ + yylval.lval = - negate; + return LAST; + } + /* Is the rest of the token digits? */ + for (; c < namelen; c++) + if (!(tokstart[c] >= '0' && tokstart[c] <= '9')) + break; + if (c == namelen) + { + yylval.lval = atoi (tokstart + 1 + negate); + if (negate) + yylval.lval = - yylval.lval; + return LAST; + } + } + + /* Handle tokens that refer to machine registers: + $ followed by a register name. */ + + if (*tokstart == '$') + for (c = 0; c < NUM_REGS; c++) + if (namelen - 1 == strlen (reg_names[c]) + && !strncmp (tokstart + 1, reg_names[c], namelen - 1)) + { + yylval.lval = c; + return REGNAME; + } + + if (namelen == 6 && !strncmp (tokstart, "struct", 6)) + { + return STRUCT; + } + if (namelen == 5 && !strncmp (tokstart, "union", 5)) + { + return UNION; + } + if (namelen == 4 && !strncmp (tokstart, "enum", 4)) + { + return ENUM; + } + if (namelen == 6 && !strncmp (tokstart, "sizeof", 6)) + { + return SIZEOF; + } + if (namelen == 8 && !strncmp (tokstart, "unsigned", 6)) + { + return UNSIGNED; + } + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + /* Any other names starting in $ are debugger internal variables. */ + + if (*tokstart == '$') + { + yylval.ivar = (struct internalvar *) lookup_internalvar (copy_name (yylval.sval) + 1); + return VARIABLE; + } + + /* Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + return NAME; +} + +static +yyerror () +{ + error ("Invalid syntax in expression."); +} + +/* Return a null-terminated temporary copy of the name + of a string token. */ + +static char * +copy_name (token) + struct stoken token; +{ + bcopy (token.ptr, namecopy, token.length); + namecopy[token.length] = 0; + return namecopy; +} + +/* Reverse an expression from suffix form (in which it is constructed) + to prefix form (in which we can conveniently print or execute it). */ + +static void prefixify_subexp (); + +static void +prefixify_expression (expr) + register struct expression *expr; +{ + register int len = sizeof (struct expression) + + expr->nelts * sizeof (union exp_element); + register struct expression *temp; + register int inpos = expr->nelts, outpos = 0; + + temp = (struct expression *) alloca (len); + + /* Copy the original expression into temp. */ + bcopy (expr, temp, len); + + prefixify_subexp (temp, expr, inpos, outpos); +} + +/* Return the number of exp_elements in the subexpression of EXPR + whose last exp_element is at index ENDPOS - 1 in EXPR. */ + +static int +length_of_subexp (expr, endpos) + register struct expression *expr; + register int endpos; +{ + register int oplen = 1; + register int args = 0; + register int i; + + i = (int) expr->elts[endpos - 1].opcode; + + switch (i) + { + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + expr->elts[endpos - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((expr->elts[endpos - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + default: + args = 1 + (i < (int) BINOP_END); + } + + while (args > 0) + { + oplen += length_of_subexp (expr, endpos - oplen); + args--; + } + + return oplen; +} + +/* Copy the subexpression ending just before index INEND in INEXPR + into OUTEXPR, starting at index OUTBEG. + In the process, convert it from suffix to prefix form. */ + +static void +prefixify_subexp (inexpr, outexpr, inend, outbeg) + register struct expression *inexpr; + struct expression *outexpr; + register int inend; + int outbeg; +{ + register int oplen = 1; + register int args = 0; + register int i; + int *arglens; + enum exp_opcode opcode; + + /* Compute how long the last operation is (in OPLEN), + and also how many preceding subexpressions serve as + arguments for it (in ARGS). */ + + opcode = inexpr->elts[inend - 1].opcode; + switch (opcode) + { + case OP_LONG: + case OP_DOUBLE: + oplen = 4; + break; + + case OP_VAR_VALUE: + case OP_LAST: + case OP_REGISTER: + case OP_INTERNALVAR: + oplen = 3; + break; + + case OP_FUNCALL: + oplen = 3; + args = 1 + inexpr->elts[inend - 2].longconst; + break; + + case UNOP_CAST: + case UNOP_MEMVAL: + oplen = 3; + args = 1; + break; + + case STRUCTOP_STRUCT: + case STRUCTOP_PTR: + args = 1; + case OP_STRING: + oplen = 3 + ((inexpr->elts[inend - 2].longconst + + sizeof (union exp_element)) + / sizeof (union exp_element)); + + break; + + case TERNOP_COND: + args = 3; + break; + + case BINOP_ASSIGN_MODIFY: + oplen = 3; + args = 2; + break; + + default: + args = 1 + ((int) opcode < (int) BINOP_END); + } + + /* Copy the final operator itself, from the end of the input + to the beginning of the output. */ + inend -= oplen; + bcopy (&inexpr->elts[inend], &outexpr->elts[outbeg], + oplen * sizeof (union exp_element)); + outbeg += oplen; + + /* Find the lengths of the arg subexpressions. */ + arglens = (int *) alloca (args * sizeof (int)); + for (i = args - 1; i >= 0; i--) + { + oplen = length_of_subexp (inexpr, inend); + arglens[i] = oplen; + inend -= oplen; + } + + /* Now copy each subexpression, preserving the order of + the subexpressions, but prefixifying each one. + In this loop, inend starts at the beginning of + the expression this level is working on + and marches forward over the arguments. + outbeg does similarly in the output. */ + for (i = 0; i < args; i++) + { + oplen = arglens[i]; + inend += oplen; + prefixify_subexp (inexpr, outexpr, inend, outbeg); + outbeg += oplen; + } +} + +/* This page contains the two entry points to this file. */ + +/* Read a C expression from the string *STRINGPTR points to, + parse it, and return a pointer to a struct expression that we malloc. + Use block BLOCK as the lexical context for variable names; + if BLOCK is zero, use the block of the selected stack frame. + Meanwhile, advance *STRINGPTR to point after the expression, + at the first nonwhite character that is not part of the expression + (possibly a null character). */ + +struct expression * +parse_c_1 (stringptr, block) + char **stringptr; + struct block *block; +{ + struct cleanup *old_chain; + + lexptr = *stringptr; + + if (lexptr == 0 || *lexptr == 0) + error_no_arg ("expression to compute"); + + old_chain = make_cleanup (free_funcalls, 0); + funcall_chain = 0; + + expression_context_block = block ? block : get_selected_block (); + + namecopy = (char *) alloca (strlen (lexptr) + 1); + expout_size = 10; + expout_ptr = 0; + expout = (struct expression *) xmalloc (sizeof (struct expression) + + expout_size * sizeof (union exp_element)); + make_cleanup (free_current_contents, &expout); + if (yyparse ()) + yyerror (); + discard_cleanups (old_chain); + expout->nelts = expout_ptr; + expout = (struct expression *) + xrealloc (expout, + sizeof (struct expression) + + expout_ptr * sizeof (union exp_element)); + prefixify_expression (expout); + *stringptr = lexptr; + return expout; +} + +/* Parse STRING as an expression, and complain if this fails + to use up all of the contents of STRING. */ + +struct expression * +parse_c_expression (string) + char *string; +{ + register struct expression *exp; + exp = parse_c_1 (&string, 0); + if (*string) + error ("Junk after end of expression."); + return exp; +} diff --git a/gdb/expression.h b/gdb/expression.h new file mode 100644 index 00000000000..7a7bd83f47d --- /dev/null +++ b/gdb/expression.h @@ -0,0 +1,167 @@ +/* Definitions for expressions stored in reversed prefix form, for GDB. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Definitions for saved C expressions. */ + +/* An expression is represented as a vector of union exp_element's. + Each exp_element is an opcode, except that some opcodes cause + the following exp_element to be treated as a long or double constant + or as a variable. The opcodes are obeyed, using a stack for temporaries. + The value is left on the temporary stack at the end. */ + +/* When it is necessary to include a string, + it can occupy as many exp_elements as it needs. + We find the length of the string using strlen, + divide to find out how many exp_elements are used up, + and skip that many. Strings, like numbers, are indicated + by the preceding opcode. */ + +enum exp_opcode +{ +/* BINOP_... operate on two values computed by following subexpressions, + replacing them by one result value. They take no immediate arguments. */ + BINOP_ADD, /* + */ + BINOP_SUB, /* - */ + BINOP_MUL, /* * */ + BINOP_DIV, /* / */ + BINOP_REM, /* % */ + BINOP_LSH, /* << */ + BINOP_RSH, /* >> */ + BINOP_AND, /* && */ + BINOP_OR, /* || */ + BINOP_LOGAND, /* & */ + BINOP_LOGIOR, /* | */ + BINOP_LOGXOR, /* ^ */ + BINOP_EQUAL, /* == */ + BINOP_NOTEQUAL, /* != */ + BINOP_LESS, /* < */ + BINOP_GTR, /* > */ + BINOP_LEQ, /* <= */ + BINOP_GEQ, /* >= */ + BINOP_REPEAT, /* @ */ + BINOP_ASSIGN, /* = */ + BINOP_COMMA, /* , */ + BINOP_SUBSCRIPT, /* x[y] */ + BINOP_EXP, /* Exponentiation */ + BINOP_END, + + BINOP_ASSIGN_MODIFY, /* +=, -=, *=, and so on. + The following exp_element is another opcode, + a BINOP_, saying how to modify. + Then comes another BINOP_ASSIGN_MODIFY, + making three exp_elements in total. */ + +/* Operates on three values computed by following subexpressions. */ + TERNOP_COND, /* ?: */ + +/* The OP_... series take immediate following arguments. + After the arguments come another OP_... (the same one) + so that the grouping can be recognized from the end. */ + +/* OP_LONG is followed by a type pointer in the next exp_element + and the long constant value in the following exp_element. + Then comes another OP_LONG. + Thus, the operation occupies four exp_elements. */ + + OP_LONG, +/* OP_DOUBLE is similar but takes a double constant instead of a long one. */ + OP_DOUBLE, +/* OP_VAR_VALUE takes one struct symbol * in the following exp_element, + followed by another OP_VAR_VALUE, making three exp_elements. */ + OP_VAR_VALUE, +/* OP_LAST is followed by an integer in the next exp_element. + The integer is zero for the last value printed, + or it is the absolute number of a history element. + With another OP_LAST at the end, this makes three exp_elements. */ + OP_LAST, +/* OP_REGISTER is followed by an integer in the next exp_element. + This is the number of a register to fetch (as an int). + With another OP_REGISTER at the end, this makes three exp_elements. */ + OP_REGISTER, +/* OP_INTERNALVAR is followed by an internalvar ptr in the next exp_element. + With another OP_INTERNALVAR at the end, this makes three exp_elements. */ + OP_INTERNALVAR, +/* OP_FUNCALL is followed by an integer in the next exp_element. + The integer is the number of args to the function call. + That many plus one values from following subexpressions + are used, the first one being the function. + The integer is followed by a repeat of OP_FUNCALL, + making three exp_elements. */ + OP_FUNCALL, +/* OP_STRING represents a string constant. + Its format is the same as that of a STRUCTOP, but the string + data is just made into a string constant when the operation + is executed. */ + OP_STRING, + +/* UNOP_CAST is followed by a type pointer in the next exp_element. + With another UNOP_CAST at the end, this makes three exp_elements. + It casts the value of the following subexpression. */ + UNOP_CAST, +/* UNOP_MEMVAL is followed by a type pointer in the next exp_element + With another UNOP_MEMVAL at the end, this makes three exp_elements. + It casts the contents of the word addressed by the value of the + following subexpression. */ + UNOP_MEMVAL, +/* UNOP_... operate on one value from a following subexpression + and replace it with a result. They take no immediate arguments. */ + UNOP_NEG, /* Unary - */ + UNOP_ZEROP, /* Unary ! */ + UNOP_LOGNOT, /* Unary ~ */ + UNOP_IND, /* Unary * */ + UNOP_ADDR, /* Unary & */ + UNOP_PREINCREMENT, /* ++ before an expression */ + UNOP_POSTINCREMENT, /* ++ after an expression */ + UNOP_PREDECREMENT, /* -- before an expression */ + UNOP_POSTDECREMENT, /* -- after an expression */ + UNOP_SIZEOF, /* Unary sizeof (followed by expression) */ + +/* STRUCTOP_... operate on a value from a following subexpression + by extracting a structure component specified by a string + that appears in the following exp_elements (as many as needed). + STRUCTOP_STRUCT is used for "." and STRUCTOP_PTR for "->". + They differ only in the error message given in case the value is + not suitable or the structure component specified is not found. + + The length of the string follows in the next exp_element, + (after the string), followed by another STRUCTOP_... code. */ + STRUCTOP_STRUCT, + STRUCTOP_PTR, +}; + +union exp_element +{ + enum exp_opcode opcode; + struct symbol *symbol; + long longconst; + double doubleconst; + char string; + struct type *type; + struct internalvar *internalvar; +}; + +struct expression +{ + int nelts; + union exp_element elts[1]; +}; + +struct expression *parse_c_expression (); +struct expression *parse_c_1 (); diff --git a/gdb/findvar.c b/gdb/findvar.c new file mode 100644 index 00000000000..1f92b1625eb --- /dev/null +++ b/gdb/findvar.c @@ -0,0 +1,409 @@ +/* Find a variable's value in memory, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "value.h" + +CORE_ADDR read_register (); + +START_FILE + +/* Return the address in which frame FRAME's value of register REGNUM + has been saved in memory. Or return zero if it has not been saved. + If REGNUM specifies the SP, the value we return is actually + the SP value, not an address where it was saved. */ + +static CORE_ADDR +find_saved_register (frame, regnum) + FRAME frame; + int regnum; +{ + struct frame_info fi; + struct frame_saved_regs saved_regs; + + register FRAME frame1 = 0; + register CORE_ADDR addr = 0; + + while (1) + { + QUIT; + fi = get_prev_frame_info (frame1); + if (fi.frame == 0 || fi.frame == frame) + break; + get_frame_saved_regs (&fi, &saved_regs); + if (saved_regs.regs[regnum]) + addr = saved_regs.regs[regnum]; + frame1 = fi.frame; + } + + return addr; +} + +/* Copy the bytes of register REGNUM, relative to the current stack frame, + into our memory at MYADDR. + The number of bytes copied is REGISTER_RAW_SIZE (REGNUM). */ + +void +read_relative_register_raw_bytes (regnum, myaddr) + int regnum; + char *myaddr; +{ + register CORE_ADDR addr; + + if (regnum == FP_REGNUM) + { + bcopy (&selected_frame, myaddr, sizeof (CORE_ADDR)); + return; + } + + addr = find_saved_register (selected_frame, regnum); + + if (addr) + { + if (regnum == SP_REGNUM) + { + CORE_ADDR buffer = addr; + bcopy (&buffer, myaddr, sizeof (CORE_ADDR)); + } + else + read_memory (addr, myaddr, REGISTER_RAW_SIZE (regnum)); + return; + } + read_register_bytes (REGISTER_BYTE (regnum), + myaddr, REGISTER_RAW_SIZE (regnum)); +} + +/* Return a `value' with the contents of register REGNUM + in its virtual format, with the type specified by + REGISTER_VIRTUAL_TYPE. */ + +value +value_of_register (regnum) + int regnum; +{ + register CORE_ADDR addr = find_saved_register (selected_frame, regnum); + register value val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + + if (addr) + { + if (regnum == SP_REGNUM) + return value_from_long (builtin_type_int, addr); + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum)); + } + else + read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, + REGISTER_RAW_SIZE (regnum)); + + REGISTER_CONVERT_TO_VIRTUAL (regnum, raw_buffer, virtual_buffer); + val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum)); + bcopy (virtual_buffer, VALUE_CONTENTS (val), REGISTER_VIRTUAL_SIZE (regnum)); + VALUE_LVAL (val) = addr ? lval_memory : lval_register; + VALUE_ADDRESS (val) = addr ? addr : REGISTER_BYTE (regnum); + VALUE_REGNO (val) = regnum; + return val; +} + +/* Low level examining and depositing of registers. + + Note that you must call `fetch_registers' once + before examining or depositing any registers. */ + +char registers[REGISTER_BYTES]; + +/* Copy LEN bytes of consecutive data from registers + starting with the REGBYTE'th byte of register data + into memory at MYADDR. */ + +read_register_bytes (regbyte, myaddr, len) + int regbyte; + char *myaddr; + int len; +{ + bcopy (®isters[regbyte], myaddr, len); +} + +/* Copy LEN bytes of consecutive data from memory at MYADDR + into registers starting with the REGBYTE'th byte of register data. */ + +write_register_bytes (regbyte, myaddr, len) + int regbyte; + char *myaddr; + int len; +{ + bcopy (myaddr, ®isters[regbyte], len); + if (have_inferior_p ()) + store_inferior_registers (-1); +} + +/* Return the contents of register REGNO, + regarding it as an integer. */ + +CORE_ADDR +read_register (regno) + int regno; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + return *(int *) ®isters[REGISTER_BYTE (regno)]; +} + +/* Store VALUE in the register number REGNO, regarded as an integer. */ + +void +write_register (regno, val) + int regno, val; +{ + /* This loses when REGISTER_RAW_SIZE (regno) != sizeof (int) */ + *(int *) ®isters[REGISTER_BYTE (regno)] = val; + + if (have_inferior_p ()) + store_inferior_registers (regno); +} + +/* Record that register REGNO contains VAL. + This is used when the value is obtained from the inferior or core dump, + so there is no need to store the value there. */ + +void +supply_register (regno, val) + int regno; + char *val; +{ + bcopy (val, ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno)); +} + +/* Given a struct symbol for a variable, + and a stack frame address, read the value of the variable + and return a (pointer to a) struct value containing the value. */ + +value +read_var_value (var, frame) + register struct symbol *var; + FRAME frame; +{ + register value v; + + struct frame_info fi; + + struct type *type = SYMBOL_TYPE (var); + register CORE_ADDR addr = 0; + int val = SYMBOL_VALUE (var); + register int len; + + if (SYMBOL_CLASS (var) == LOC_BLOCK) + type = lookup_function_type (type); + + v = allocate_value (type); + VALUE_LVAL (v) = lval_memory; /* The most likely possibility. */ + len = TYPE_LENGTH (type); + + if (frame == 0) frame = selected_frame; + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + case LOC_LABEL: + bcopy (&val, VALUE_CONTENTS (v), len); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_CONST_BYTES: + bcopy (val, VALUE_CONTENTS (v), len); + VALUE_LVAL (v) = not_lval; + return v; + + case LOC_STATIC: + addr = val; + break; + + case LOC_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + break; + + case LOC_LOCAL: + fi = get_frame_info (frame); + addr = val + FRAME_LOCALS_ADDRESS (fi); + break; + + case LOC_TYPEDEF: + error ("Cannot look up value of a typedef"); + + case LOC_BLOCK: + VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + return v; + + case LOC_REGISTER: + { + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + + VALUE_REGNO (v) = val; + + /* Locate the register's contents in a real register or in core; + read the data in raw format. */ + + addr = find_saved_register (frame, val); + if (addr == 0) + { + /* Value is really in a register. */ + + VALUE_LVAL (v) = lval_register; + VALUE_ADDRESS (v) = REGISTER_BYTE (val); + + read_register_bytes (REGISTER_BYTE (val), + raw_buffer, REGISTER_RAW_SIZE (val)); + } + else + { + /* Value was in a register that has been saved in memory. */ + + read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (val)); + VALUE_ADDRESS (v) = addr; + } + + /* Convert the raw contents to virtual contents. + (Just copy them if the formats are the same.) */ + + REGISTER_CONVERT_TO_VIRTUAL (val, raw_buffer, virtual_buffer); + + if (REGISTER_CONVERTIBLE (val)) + { + /* When the raw and virtual formats differ, the virtual format + corresponds to a specific data type. If we want that type, + copy the data into the value. + Otherwise, do a type-conversion. */ + + if (type != REGISTER_VIRTUAL_TYPE (val)) + { + /* eg a variable of type `float' in a 68881 register + with raw type `extended' and virtual type `double'. + Fetch it as a `double' and then convert to `float'. */ + v = allocate_value (REGISTER_VIRTUAL_TYPE (val)); + bcopy (virtual_buffer, VALUE_CONTENTS (v), len); + v = value_cast (type, v); + } + else + bcopy (virtual_buffer, VALUE_CONTENTS (v), len); + } + else + { + /* Raw and virtual formats are the same for this register. */ + + union { int i; char c; } test; + /* If we want less than the full size, we need to + test for a big-endian or little-endian machine. */ + test.i = 1; + if (test.c != 1 && len < REGISTER_RAW_SIZE (val)) + { + /* Big-endian, and we want less than full size. */ + VALUE_OFFSET (v) = REGISTER_RAW_SIZE (val) - len; + } + + bcopy (virtual_buffer + VALUE_OFFSET (v), + VALUE_CONTENTS (v), len); + } + + return v; + } + } + + read_memory (addr, VALUE_CONTENTS (v), len); + VALUE_ADDRESS (v) = addr; + return v; +} + +/* Given a struct symbol for a variable, + and a stack frame address, + return a (pointer to a) struct value containing the variable's address. */ + +value +locate_var_value (var, frame) + register struct symbol *var; + FRAME frame; +{ + register CORE_ADDR addr = 0; + int val = SYMBOL_VALUE (var); + struct frame_info fi; + + if (frame == 0) frame = selected_frame; + + switch (SYMBOL_CLASS (var)) + { + case LOC_CONST: + case LOC_CONST_BYTES: + error ("Address requested for identifier \"%s\" which is a constant.", + SYMBOL_NAME (var)); + + case LOC_REGISTER: + addr = find_saved_register (frame, val); + if (addr != 0) + { + union { int i; char c; } test; + int len = TYPE_LENGTH (SYMBOL_TYPE (var)); + /* If var is less than the full size of register, we need to + test for a big-endian or little-endian machine. */ + test.i = 1; + if (test.c != 1 && len < REGISTER_RAW_SIZE (val)) + /* Big-endian, and we want less than full size. */ + addr+ = REGISTER_RAW_SIZE (val) - len; + break; + } + error ("Address requested for identifier \"%s\" which is in a register.", + SYMBOL_NAME (var)); + + case LOC_STATIC: + case LOC_LABEL: + addr = val; + break; + + case LOC_ARG: + fi = get_frame_info (frame); + addr = val + FRAME_ARGS_ADDRESS (fi); + break; + + case LOC_LOCAL: + fi = get_frame_info (frame); + addr = val + FRAME_LOCALS_ADDRESS (fi); + break; + + case LOC_TYPEDEF: + error ("Address requested for identifier \"%s\" which is a typedef.", + SYMBOL_NAME (var)); + + case LOC_BLOCK: + addr = BLOCK_START (SYMBOL_BLOCK_VALUE (var)); + break; + } + + return value_cast (lookup_pointer_type (SYMBOL_TYPE (var)), + value_from_long (builtin_type_long, addr)); +} + +static +initialize () +{} + +END_FILE diff --git a/gdb/firstfile.c b/gdb/firstfile.c new file mode 100644 index 00000000000..60d6bf867bd --- /dev/null +++ b/gdb/firstfile.c @@ -0,0 +1,154 @@ +/* Find the initialization functions of following files. + This goes with initialize.h and lastfile.c. + + Copyright (C) 1986 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more + extensive warranty protection to third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of this program in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + + +/* This is a magical hack for finding, automatically, + all the files that are linked together + and calling an initialization function in each one + without requiring the main file to know which other + files there are. + + Call initialize_all_files to run the initialization functions + of all the files. Each initialization function can enter + the commands of its file into a global data base so that the + contents of the file can be used. + + The files to be found must follow this file. Each of them + must start START_FILE, before any other functions, + and end with END_FILE, after any other functions. + These macros are defined in initialize.h. + In addition, each file must contain a function named + `initialize', which will be called with no arguments. + + After the files to be found must come the file `lastfile' + which ends the chain of calls. */ + +#include "initialize.h" + +static initialize_next_file (); +static initialize_dummy_1 (); +static initialize_dummy_2 (); + +initialize_all_files () +{ + initialize_next_file ((char *) initialize_dummy_2 + - (char *) initialize_dummy_1); +} + +/* The next two functions exist just so we can find + out how long the first of them is. + That tells us how long initialize_next_file is, + since that function has the same definition as this one. */ + +static +initialize_dummy_1 (offset) + int offset; +{ + long addr = FILEADDR_ROUND ((int) initialize_next_file + offset); + (*(void (*) ()) addr) (offset); +} + +static +initialize_dummy_2 () +{ +} + +/* This makes the function initialize_next_file. */ + +END_FILE diff --git a/gdb/foo.c b/gdb/foo.c new file mode 100644 index 00000000000..59e559f1532 --- /dev/null +++ b/gdb/foo.c @@ -0,0 +1,13 @@ +main() { + int i; + + for (i = 0; i >= 0; i++) + bar(); +} + +bar() +{ + int i; + + i = 10; +} diff --git a/gdb/foo.nm b/gdb/foo.nm new file mode 100644 index 00000000000..7a14364dec1 --- /dev/null +++ b/gdb/foo.nm @@ -0,0 +1,39 @@ + + +Symbols from foo: + +Name Value Class Type Size Line Section + +crt0.s | | file | | | | +foo.c | | file | | | | +main | 228|extern| int( )| 66| |.text +.bf | 228|fcn | | | 1|.text +i | -4|auto | int| | | +.ef | 274|fcn | | | 6|.text +bar | 294|extern| int( )| 50| |.text +.bf | 294|fcn | | | 9|.text +i | -4|auto | int| | | +.ef | 324|fcn | | | 5|.text +dbxxx.s | | file | | | | +initfpu.s | | file | | | | +cuexit.s | | file | | | | +fakcu.c | | file | | | | +_cleanup | 404|extern| ( )| 42| |.text +.bf | 404|fcn | | | 23|.text +.ef | 426|fcn | | | 2|.text +_ac_r | 4194760|static| *char| | |.data +copyright.c | | file | | | | +_ac_r | 4194764|static| *char| | |.data +_start | 168|extern| | | |.text +_dbargs | 4195016|extern| | | |.bss +exit | 388|extern| | | |.text +initfpu | 380|extern| | | |.text +environ | 4194756|extern| | | |.data +splimit% | 4194752|extern| | | |.data +_dbsubc | 344|extern| | | |.text +_dbsubn | 376|extern| | | |.text +_ac_s | 4194768|extern| char[0]| | |.data +etext | 448|extern| | | | +edata | 4195016|extern| | | | +end | 4195528|extern| | | | +_sorigin | 4195528|extern| | | | diff --git a/gdb/foo.od b/gdb/foo.od new file mode 100644 index 00000000000..ce2a1861d7e --- /dev/null +++ b/gdb/foo.od @@ -0,0 +1,213 @@ +0000000 0150 0003 21fc 7629 0000 0310 0000 0032 + 001 P \0 003 ! 374 v ) \0 \0 003 020 \0 \0 \0 2 +0000020 001c 0103 010b 0000 0000 0118 0000 0108 + \0 034 001 003 001 013 \0 \0 \0 \0 001 030 \0 \0 001 \b +0000040 0000 0200 0000 00a8 0000 00a8 0040 01c0 + \0 \0 002 \0 \0 \0 \0 250 \0 \0 \0 250 \0 @ 001 300 +0000060 2e74 6578 7400 0000 0000 00a8 0000 00a8 + . t e x t \0 \0 \0 \0 \0 \0 250 \0 \0 \0 250 +0000100 0000 0118 0000 00a8 0000 0000 0000 02c8 + \0 \0 001 030 \0 \0 \0 250 \0 \0 \0 \0 \0 \0 002 310 +0000120 0000 000c 0000 0020 2e64 6174 6100 0000 + \0 \0 \0 \f \0 \0 \0 . d a t a \0 \0 \0 +0000140 0040 01c0 0040 01c0 0000 0108 0000 01c0 + \0 @ 001 300 \0 @ 001 300 \0 \0 001 \b \0 \0 001 300 +0000160 0000 0000 0000 0000 0000 0000 0000 0040 + \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 @ +0000200 2e62 7373 0000 0000 0040 02c8 0040 02c8 + . b s s \0 \0 \0 \0 \0 @ 002 310 \0 @ 002 310 +0000220 0000 0200 0000 0000 0000 0000 0000 0000 + \0 \0 002 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 +0000240 0000 0000 0000 0080 23c0 0040 01c0 518f + \0 \0 \0 \0 \0 \0 \0 200 # 300 \0 @ 001 300 Q 217 +0000260 2eaf 0008 41ef 000c 2f48 0004 2248 4a98 + . 257 \0 \b A 357 \0 \f / H \0 004 " H J 230 +0000300 66fc 2f48 0008 23c8 0040 01c4 4eb9 0000 + f 374 / H \0 \b # 310 \0 @ 001 304 N 271 \0 \0 +0000320 017c 4eb9 0000 00e4 2e80 4eb9 0000 0184 + 001 | N 271 \0 \0 \0 344 . 200 N 271 \0 \0 001 204 +0000340 7001 4e40 480e ffff fff8 48ef 0000 0004 + p 001 N @ H 016 377 377 377 370 H 357 \0 \0 \0 004 +0000360 f237 f000 0170 0000 0004 42ae fffc 4aae + 362 7 360 \0 001 p \0 \0 \0 004 B 256 377 374 J 256 +0000400 fffc 6d00 000e 4eba 001e 52ae fffc 6000 + 377 374 m \0 \0 016 N 272 \0 036 R 256 377 374 ` \0 +0000420 ffee 4cef 0000 0004 f237 d000 0170 0000 + 377 356 L 357 \0 \0 \0 004 362 7 320 \0 001 p \0 \0 +0000440 0004 4e5e 4e75 480e ffff fff8 48ef 0000 + \0 004 N ^ N u H 016 377 377 377 370 H 357 \0 \0 +0000460 0004 f237 f000 0170 0000 0004 2d7c 0000 + \0 004 362 7 360 \0 001 p \0 \0 \0 004 - | \0 \0 +0000500 000a fffc 4cef 0000 0004 f237 d000 0170 + \0 \n 377 374 L 357 \0 \0 \0 004 362 7 320 \0 001 p +0000520 0000 0004 4e5e 4e75 4e56 0000 207c 0040 + \0 \0 \0 004 N ^ N u N V \0 \0 | \0 @ +0000540 02c8 2258 2018 2200 e581 d1c1 6002 2f20 + 002 310 " X 030 " \0 345 201 321 301 ` 002 / +0000560 51c8 fffc 4e91 4e5e 4e41 4e71 4e56 fffc + Q 310 377 374 N 221 N ^ N A N q N V 377 374 +0000600 4e5e 4e75 4eb9 0000 0194 7001 4e40 4e72 + N ^ N u N 271 \0 \0 001 224 p 001 N @ N r +0000620 0000 4e71 480e ffff fffc 48ef 0000 0004 + \0 \0 N q H 016 377 377 377 374 H 357 \0 \0 \0 004 +0000640 f237 f000 0170 0000 0004 4cef 0000 0004 + 362 7 360 \0 001 p \0 \0 \0 004 L 357 \0 \0 \0 004 +0000660 f237 d000 0170 0000 0004 4e5e 4e75 4e71 + 362 7 320 \0 001 p \0 \0 \0 004 N ^ N u N q +0000700 0000 0000 0000 0000 0040 01d0 0040 01d0 + \0 \0 \0 \0 \0 \0 \0 \0 \0 @ 001 320 \0 @ 001 320 +0000720 436f 7079 7269 6768 7420 2863 2920 3139 + C o p y r i g h t ( c ) 1 9 +0000740 3837 2041 7070 6c65 2043 6f6d 7075 7465 + 8 7 A p p l e C o m p u t e +0000760 722c 2049 6e63 2e2c 2031 3938 3520 4164 + r , I n c . , 1 9 8 5 A d +0001000 6f62 6520 5379 7374 656d 7320 496e 636f + o b e S y s t e m s I n c o +0001020 7270 6f72 6174 6564 2c20 3139 3833 2d38 + r p o r a t e d , 1 9 8 3 - 8 +0001040 3720 4154 2654 2d49 532c 2031 3938 352d + 7 A T & T - I S , 1 9 8 5 - +0001060 3837 204d 6f74 6f72 6f6c 6120 496e 632e + 8 7 M o t o r o l a I n c . +0001100 2c20 3139 3830 2d38 3720 5375 6e20 4d69 + , 1 9 8 0 - 8 7 S u n M i +0001120 6372 6f73 7973 7465 6d73 2049 6e63 2e2c + c r o s y s t e m s I n c . , +0001140 2031 3938 302d 3837 2054 6865 2052 6567 + 1 9 8 0 - 8 7 T h e R e g +0001160 656e 7473 206f 6620 7468 6520 556e 6976 + e n t s o f t h e U n i v +0001200 6572 7369 7479 206f 6620 4361 6c69 666f + e r s i t y o f C a l i f o +0001220 726e 6961 2c20 3139 3835 2d38 3720 556e + r n i a , 1 9 8 5 - 8 7 U n +0001240 6973 6f66 7420 436f 7270 6f72 6174 696f + i s o f t C o r p o r a t i o +0001260 6e2c 2041 6c6c 2052 6967 6874 7320 5265 + n , A l l R i g h t s R e +0001300 7365 7276 6564 2e00 0000 0004 0000 0000 + s e r v e d . \0 \0 \0 \0 004 \0 \0 \0 \0 +0001320 00e4 0001 0000 00fa 0004 0000 0106 0005 + \0 344 \0 001 \0 \0 \0 372 \0 004 \0 \0 001 006 \0 005 +0001340 0000 0112 0006 0000 000b 0000 0000 0126 + \0 \0 001 022 \0 006 \0 \0 \0 013 \0 \0 \0 \0 001 & +0001360 0001 0000 013c 0004 0000 0144 0005 0000 + \0 001 \0 \0 001 < \0 004 \0 \0 001 D \0 005 \0 \0 +0001400 001a 0000 0000 0194 0001 0000 01aa 0002 + \0 032 \0 \0 \0 \0 001 224 \0 001 \0 \0 001 252 \0 002 +0001420 2e66 696c 6500 0000 0000 0002 fffe 0000 + . f i l e \0 \0 \0 \0 \0 \0 002 377 376 \0 \0 +0001440 6701 6372 7430 2e73 0000 0000 0000 0000 + g 001 c r t 0 . s \0 \0 \0 \0 \0 \0 \0 \0 +0001460 0000 0000 2e66 696c 6500 0000 0000 0012 + \0 \0 \0 \0 . f i l e \0 \0 \0 \0 \0 \0 022 +0001500 fffe 0000 6701 666f 6f2e 6300 0000 0000 + 377 376 \0 \0 g 001 f o o . c \0 \0 \0 \0 \0 +0001520 0000 0000 0000 0000 6d61 696e 0000 0000 + \0 \0 \0 \0 \0 \0 \0 \0 m a i n \0 \0 \0 \0 +0001540 0000 00e4 0001 0024 0201 0000 0000 0000 + \0 \0 \0 344 \0 001 \0 $ 002 001 \0 \0 \0 \0 \0 \0 +0001560 0042 0000 02c8 0000 000b 0000 2e62 6600 + \0 B \0 \0 002 310 \0 \0 \0 013 \0 \0 . b f \0 +0001600 0000 0000 0000 00e4 0001 0000 6501 0000 + \0 \0 \0 \0 \0 \0 \0 344 \0 001 \0 \0 e 001 \0 \0 +0001620 0000 0001 0000 0000 0000 0000 0000 0000 + \0 \0 \0 001 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 +0001640 6900 0000 0000 0000 ffff fffc ffff 0004 + i \0 \0 \0 \0 \0 \0 \0 377 377 377 374 377 377 \0 004 +0001660 0100 2e65 6600 0000 0000 0000 0112 0001 + 001 \0 . e f \0 \0 \0 \0 \0 \0 \0 001 022 \0 001 +0001700 0000 6501 0000 0000 0006 0000 0000 0000 + \0 \0 e 001 \0 \0 \0 \0 \0 006 \0 \0 \0 \0 \0 \0 +0001720 0000 0000 0000 6261 7200 0000 0000 0000 + \0 \0 \0 \0 \0 \0 b a r \0 \0 \0 \0 \0 \0 \0 +0001740 0126 0001 0024 0201 0000 0000 0000 0032 + 001 & \0 001 \0 $ 002 001 \0 \0 \0 \0 \0 \0 \0 2 +0001760 0000 02e6 0000 0012 0000 2e62 6600 0000 + \0 \0 002 346 \0 \0 \0 022 \0 \0 . b f \0 \0 \0 +0002000 0000 0000 0126 0001 0000 6501 0000 0000 + \0 \0 \0 \0 001 & \0 001 \0 \0 e 001 \0 \0 \0 \0 +0002020 0009 0000 0000 0000 0000 0000 0000 6900 + \0 \t \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 i \0 +0002040 0000 0000 0000 ffff fffc ffff 0004 0100 + \0 \0 \0 \0 \0 \0 377 377 377 374 377 377 \0 004 001 \0 +0002060 2e65 6600 0000 0000 0000 0144 0001 0000 + . e f \0 \0 \0 \0 \0 \0 \0 001 D \0 001 \0 \0 +0002100 6501 0000 0000 0005 0000 0000 0000 0000 + e 001 \0 \0 \0 \0 \0 005 \0 \0 \0 \0 \0 \0 \0 \0 +0002120 0000 0000 2e66 696c 6500 0000 0000 0014 + \0 \0 \0 \0 . f i l e \0 \0 \0 \0 \0 \0 024 +0002140 fffe 0000 6701 6462 7878 782e 7300 0000 + 377 376 \0 \0 g 001 d b x x x . s \0 \0 \0 +0002160 0000 0000 0000 0000 2e66 696c 6500 0000 + \0 \0 \0 \0 \0 \0 \0 \0 . f i l e \0 \0 \0 +0002200 0000 0016 fffe 0000 6701 696e 6974 6670 + \0 \0 \0 026 377 376 \0 \0 g 001 i n i t f p +0002220 752e 7300 0000 0000 0000 0000 2e66 696c + u . s \0 \0 \0 \0 \0 \0 \0 \0 \0 . f i l +0002240 6500 0000 0000 0018 fffe 0000 6701 6375 + e \0 \0 \0 \0 \0 \0 030 377 376 \0 \0 g 001 c u +0002260 6578 6974 2e73 0000 0000 0000 0000 0000 + e x i t . s \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 +0002300 2e66 696c 6500 0000 0000 0021 fffe 0000 + . f i l e \0 \0 \0 \0 \0 \0 ! 377 376 \0 \0 +0002320 6701 6661 6b63 752e 6300 0000 0000 0000 + g 001 f a k c u . c \0 \0 \0 \0 \0 \0 \0 +0002340 0000 0000 5f63 6c65 616e 7570 0000 0194 + \0 \0 \0 \0 _ c l e a n u p \0 \0 001 224 +0002360 0001 0020 0201 0000 0000 0000 002a 0000 + \0 001 \0 002 001 \0 \0 \0 \0 \0 \0 \0 * \0 \0 +0002400 02fe 0000 0020 0000 2e62 6600 0000 0000 + 002 376 \0 \0 \0 \0 \0 . b f \0 \0 \0 \0 \0 +0002420 0000 0194 0001 0000 6501 0000 0000 0017 + \0 \0 001 224 \0 001 \0 \0 e 001 \0 \0 \0 \0 \0 027 +0002440 0000 0000 0000 0000 0000 0000 2e65 6600 + \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 . e f \0 +0002460 0000 0000 0000 01aa 0001 0000 6501 0000 + \0 \0 \0 \0 \0 \0 001 252 \0 001 \0 \0 e 001 \0 \0 +0002500 0000 0002 0000 0000 0000 0000 0000 0000 + \0 \0 \0 002 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 +0002520 5f61 635f 7200 0000 0040 01c8 0002 0012 + _ a c _ r \0 \0 \0 \0 @ 001 310 \0 002 \0 022 +0002540 0300 2e66 696c 6500 0000 0000 0024 fffe + 003 \0 . f i l e \0 \0 \0 \0 \0 \0 $ 377 376 +0002560 0000 6701 636f 7079 7269 6768 742e 6300 + \0 \0 g 001 c o p y r i g h t . c \0 +0002600 0000 0000 0000 5f61 635f 7200 0000 0040 + \0 \0 \0 \0 \0 \0 _ a c _ r \0 \0 \0 \0 @ +0002620 01cc 0002 0012 0300 5f73 7461 7274 0000 + 001 314 \0 002 \0 022 003 \0 _ s t a r t \0 \0 +0002640 0000 00a8 0001 0000 0200 5f64 6261 7267 + \0 \0 \0 250 \0 001 \0 \0 002 \0 _ d b a r g +0002660 7300 0040 02c8 0003 0000 0200 6578 6974 + s \0 \0 @ 002 310 \0 003 \0 \0 002 \0 e x i t +0002700 0000 0000 0000 0184 0001 0000 0200 696e + \0 \0 \0 \0 \0 \0 001 204 \0 001 \0 \0 002 \0 i n +0002720 6974 6670 7500 0000 017c 0001 0000 0200 + i t f p u \0 \0 \0 001 | \0 001 \0 \0 002 \0 +0002740 656e 7669 726f 6e00 0040 01c4 0002 0000 + e n v i r o n \0 \0 @ 001 304 \0 002 \0 \0 +0002760 0200 7370 6c69 6d69 7425 0040 01c0 0002 + 002 \0 s p l i m i t % \0 @ 001 300 \0 002 +0003000 0000 0200 5f64 6273 7562 6300 0000 0158 + \0 \0 002 \0 _ d b s u b c \0 \0 \0 001 X +0003020 0001 0000 0200 5f64 6273 7562 6e00 0000 + \0 001 \0 \0 002 \0 _ d b s u b n \0 \0 \0 +0003040 0178 0001 0000 0200 5f61 635f 7300 0000 + 001 x \0 001 \0 \0 002 \0 _ a c _ s \0 \0 \0 +0003060 0040 01d0 0002 0032 0201 0000 0000 0000 + \0 @ 001 320 \0 002 \0 2 002 001 \0 \0 \0 \0 \0 \0 +0003100 0000 0000 0000 0000 0000 0000 6574 6578 + \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 \0 e t e x +0003120 7400 0000 0000 01c0 ffff 0000 0200 6564 + t \0 \0 \0 \0 \0 001 300 377 377 \0 \0 002 \0 e d +0003140 6174 6100 0000 0040 02c8 ffff 0000 0200 + a t a \0 \0 \0 \0 @ 002 310 377 377 \0 \0 002 \0 +0003160 656e 6400 0000 0000 0040 04c8 ffff 0000 + e n d \0 \0 \0 \0 \0 \0 @ 004 310 377 377 \0 \0 +0003200 0200 5f73 6f72 6967 696e 0040 04c8 ffff + 002 \0 _ s o r i g i n \0 @ 004 310 377 377 +0003220 0000 0200 + \0 \0 002 \0 +0003224 diff --git a/gdb/foo.s b/gdb/foo.s new file mode 100644 index 00000000000..a7079d563c0 --- /dev/null +++ b/gdb/foo.s @@ -0,0 +1,65 @@ + file "foo.c" + data 1 + text + def main; val main; scl 2; type 044; endef + global main +main: + ln 1 + def ~bf; val ~; scl 101; line 1; endef + link.l %fp,&F%1 + movm.l &M%1,(4,%sp) + fmovm &FPM%1,(FPO%1,%sp) + def i; val -4+S%1; scl 1; type 04; endef + ln 4 + clr.l ((S%1-4).w,%fp) +L%15: + tst.l ((S%1-4).w,%fp) + blt L%14 + ln 5 + jsr bar +L%13: + add.l &1,((S%1-4).w,%fp) + bra L%15 +L%14: +L%12: + def ~ef; val ~; scl 101; line 6; endef + ln 6 + movm.l (4,%sp),&M%1 + fmovm (FPO%1,%sp),&FPM%1 + unlk %fp + rts + def main; val ~; scl -1; endef + set S%1,0 + set T%1,0 + set F%1,-8 + set FPO%1,4 + set FPM%1,0x0000 + set M%1,0x0000 + data 1 + text + def bar; val bar; scl 2; type 044; endef + global bar +bar: + ln 1 + def ~bf; val ~; scl 101; line 9; endef + link.l %fp,&F%2 + movm.l &M%2,(4,%sp) + fmovm &FPM%2,(FPO%2,%sp) + def i; val -4+S%2; scl 1; type 04; endef + ln 4 + mov.l &10,((S%2-4).w,%fp) +L%17: + def ~ef; val ~; scl 101; line 5; endef + ln 5 + movm.l (4,%sp),&M%2 + fmovm (FPO%2,%sp),&FPM%2 + unlk %fp + rts + def bar; val ~; scl -1; endef + set S%2,0 + set T%2,0 + set F%2,-8 + set FPO%2,4 + set FPM%2,0x0000 + set M%2,0x0000 + data 1 diff --git a/gdb/foo.sym b/gdb/foo.sym new file mode 100644 index 00000000000..4b6595a5a13 --- /dev/null +++ b/gdb/foo.sym @@ -0,0 +1,114 @@ +Symtab for file _globals_ + +Line table: + + +Blockvector: + +block #000 (object 0x41a5cc) [0x0..0x0] + char _ac_s[0]; static at 0x4001d0, + int _dbargs; static at 0x4002c8, + int environ; static at 0x4001c4, + int splimit%; static at 0x4001c0, + block #001 (object 0x41a5a8) [0x0..0x0] (under 0x41a5cc) + + +Symtab for file copyright.c + +Line table: + + +Blockvector: + +block #000 (object 0x41a460) [0x0..0x0] + block #001 (object 0x41a444) [0x0..0x0] (under 0x41a460) + char *_ac_r; static at 0x4001cc, + + +Symtab for file fakcu.c + +Line table: + + line 23 at 194 + line 24 at 1aa + +Blockvector: + +block #000 (object 0x41a3f0) [0x0..0x0] + void _cleanup; block (object 0x41a380) starting at 0x194, + block #001 (object 0x41a3d4) [0x0..0x0] (under 0x41a3f0) + char *_ac_r; static at 0x4001c8, + block #002 (object 0x41a380) [0x194..0x1b0] (under 0x41a3d4) _cleanup + + +Symtab for file cuexit.s + +Line table: + + +Blockvector: + +block #000 (object 0x41f210) [0x0..0x0] + block #001 (object 0x41f1ec) [0x0..0x0] (under 0x41f210) + + +Symtab for file initfpu.s + +Line table: + + +Blockvector: + +block #000 (object 0x41e1c4) [0x0..0x0] + block #001 (object 0x41e1a0) [0x0..0x0] (under 0x41e1c4) + + +Symtab for file dbxxx.s + +Line table: + + +Blockvector: + +block #000 (object 0x41d178) [0x0..0x0] + block #001 (object 0x41d154) [0x0..0x0] (under 0x41d178) + + +Symtab for file foo.c + +Line table: + + line 1 at e4 + line 2 at fa + line 4 at fa + line 5 at 106 + line 6 at 112 + line 7 at 126 + line 9 at 126 + line 10 at 13c + line 12 at 13c + line 13 at 144 + +Blockvector: + +block #000 (object 0x41a2d8) [0x0..0x0] + int bar; block (object 0x41a2b0) starting at 0x126, + int main; block (object 0x41a220) starting at 0xe4, + block #001 (object 0x41a23c) [0x0..0x0] (under 0x41a2d8) + block #002 (object 0x41a220) [0xe4..0x120] (under 0x41a23c) main + int i; local at 0xfffffffc, + block #003 (object 0x41a2b0) [0x126..0x150] (under 0x41a23c) bar + int i; local at 0xfffffffc, + + +Symtab for file crt0.s + +Line table: + + +Blockvector: + +block #000 (object 0x41b178) [0x0..0x0] + block #001 (object 0x41b154) [0x0..0x0] (under 0x41b178) + + diff --git a/gdb/frame.h b/gdb/frame.h new file mode 100644 index 00000000000..3f51c459312 --- /dev/null +++ b/gdb/frame.h @@ -0,0 +1,64 @@ +/* Definitions for dealing with stack frames, for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Note that frame.h requires param.h! */ + +#define FRAME CORE_ADDR + +struct frame_info + { + /* Nominal address of the frame described. */ + FRAME frame; + /* Address at which execution is occurring in this frame. + For the innermost frame, it's the current pc. + For other frames, it is a pc saved in the next frame. */ + CORE_ADDR pc; + /* The frame called by the frame we are describing, or 0. */ + FRAME next_frame; + }; + +/* Describe the saved registers of a frame. */ + +struct frame_saved_regs + { + /* For each register, address of where it was saved on entry to the frame, + or zero if it was not saved on entry to this frame. */ + CORE_ADDR regs[NUM_REGS]; + }; + +/* The stack frame that the user has specified for commands to act on. + Note that one cannot assume this is the address of valid data. */ + +extern FRAME selected_frame; + +extern struct frame_info get_frame_info (); +extern struct frame_info get_prev_frame_info (); + +extern void get_frame_saved_regs (); + +extern FRAME get_prev_frame (); + +extern FRAME get_current_frame (); + +extern struct block *get_frame_block (); +extern struct block *get_current_block (); +extern struct block *get_selected_block (); +extern struct symbol *get_frame_function (); +extern struct symbol *get_pc_function (); diff --git a/gdb/gdb.1 b/gdb/gdb.1 new file mode 100644 index 00000000000..11a42a69960 --- /dev/null +++ b/gdb/gdb.1 @@ -0,0 +1,91 @@ +.TH GDB 1 "13 April 1987" +.UC 4 +.SH NAME +gdb \- Project GNU's DeBugger +.SH SYNOPSIS +\fBgdb\fP [ \fBoptions\fP ] See documentation mentioned below. +.SH DESCRIPTION +\fIgdb\fP is a source level symbolic debugger for C programs, created by +Richard M. Stallman (rms) for the GNU Project, and distributed by the +Free Software Foundation. Eventually GNU (Gnu's Not Unix) will be a +complete replacement for Berkeley Unix, all of which everyone will be +able to use freely. See the \fIGNU Emacs\fP man page for pointers to more +information. +.PP +\fIgdb\fP has something of the flavor of \fIdbx\fP, +but has more features and power. It can also be used to debug o/s +kernels, but needs to be configured differently for that task. +.PP +Project GNU isn't using Unix man pages. Its style of complete +documentation can be found by: +.PP +The help and info commands inside \fIgdb\fP. +.PP +In the Info system in \fIGNU Emacs\fP. Type C-h i, and follow the +directions. This is equivalent to the reference manual for +\fIgdb\fP, and has about 55 pages of text. +.PP +\fIgdb\fP could be extended to work with other languages (e.g. Pascal) and +machines (e.g. encores). If you like, copy the sources and give it a +try. When you have it working send \fIdiff -c\fP's of the changed files to +bug-gdb@prep.ai.mit.edu (fuller details below), so they can benefit everyone. +.SH DISTRIBUTION +\fIgdb\fP is free; anyone may redistribute copies of +\fIgdb\fP to anyone under the terms stated in the +\fIgdb\fP General Public License, a copy of which accompanies each copy of +\fIgdb\fP, is readable with the info command inside \fIgdb\fP, +and which also appears in the \fIgdb\fP reference manual. +.PP +Copies of \fIgdb\fP may sometimes be received packaged with +distributions of Unix systems, but it is never included in the scope +of any license covering those systems. Such inclusion would violate +the terms on which distribution is permitted. In fact, the primary +purpose of the General Public License is to prohibit anyone from +attaching any other restrictions to redistribution of \fIgdb\fP. +.PP +You can order printed copies of the \fIgdb\fP reference manual for $10.00/copy +postpaid from the Free Software Foundation, which develops GNU software +(contact them for quantity prices on the manual). Their address is: +.nf + Free Software Foundation + 1000 Mass Ave. + Cambridge, MA 02138 +.fi +As with all software and publications from FSF, everyone is permitted to +make and distribute copies of the \fIgdb\fP reference manual. +The TeX source to the \fIgdb\fP reference +manual is also included in the \fIGNU Emacs\fP source distribution. +.PP +.SH OPTIONS +See documentation. +.SH EXAMPLES +See documentation. +.SH "SEE ALSO" +adb(1), sdb(1), dbx(1) +.SH BUGS +There is a mailing list, bug-gdb@prep.ai.mit.edu on the internet +(ucbvax!prep.ai.mit.edu!bug-gdb on UUCPnet), for reporting \fIgdb\fP +bugs and fixes. But before reporting something as a bug, please try +to be sure that it really is a bug, not a misunderstanding or a +deliberate feature. We ask you to read the section ``Reporting Emacs +Bugs'' near the end of the \fIGNU Emacs\fP reference manual +(or Info system) for hints +on how and when to report bugs. Also, include the version number of +the \fIgdb\fP you are running in \fIevery\fR bug report that you send in. +.PP +Do not expect a personal answer to a bug report. The purpose of reporting +bugs is to get them fixed for everyone in the next release, if possible. +For personal assistance, look in the SERVICE file +(see the \fIGNU Emacs\fP man page) for +a list of people who offer it. +.PP +Please do not send anything but bug reports to this mailing list. +Send other stuff to gnu@prep.ai.mit.edu (or the +corresponding UUCP address). For more information about GNU mailing +lists, see the file MAILINGLISTS (see the \fIGNU Emacs\fP man page). Bugs tend +actually to be fixed if they can be isolated, so it is in your +interest to report them in such a way that they can be easily +reproduced. +.PP +No bugs are known at this time. + diff --git a/gdb/gdb.ideas b/gdb/gdb.ideas new file mode 100644 index 00000000000..7b9e9761f03 --- /dev/null +++ b/gdb/gdb.ideas @@ -0,0 +1,694 @@ +BABYL OPTIONS: +Version: 5 +Labels: +Note: This is the header of an rmail file. +Note: If you are seeing it in rmail, +Note: it means the file has no messages in it. + +From: mly@MICHAEL.AI.MIT.EDU (Richard Mlynarik) +To: rms@prep.ai.mit.edu +Subject: gdb suggestions (from hpux cdb) +Reply-To: mly-prep@prep.ai.mit.edu + +"find-bug" command says "I can see the problem, but it will do you +good to find it yourself" + +The gdb manual should explicitly state that gdb has no control over +forked (or execed or whatever) subprocesses. + +I'd still like it if "delete" said what it had done. + + +Date: Tuesday, 13 May 1986, 00:40-EDT +From: +Sender: JC@LMI-ANGEL +Subject: interesting sdb features +To: rms@angel + +output format p = pointer to procedure. + +foo/x or foo/4x uses size of foo as size to print. + +foo[1;4] to get elements 1 thru 4. + +Continue to specified line number. + +Interactively delete all breakpoints (asking about each one). + + + +Command to write backtrace into a file, or even better to duplicate all +output to a file. This could work by playing with descriptor 1, +making it a pipe to `tee'. The original descriptor 1 is saved and +this mode can be turned off by putting it back. + Date: Wed, 18 Feb 87 15:37:14 EST + From: rms (Richard M. Stallman) + Message-Id: <8702182037.AA16492@prep.ai.mit.edu> + To: mly-prep@prep.ai.mit.edu + In-Reply-To: <8702181913.AA16118@prep.ai.mit.edu> + Subject: gdb "photo" command + + I don't think all this is worth the trouble to do now, + because the right way to do it on TRIX is totally different + and much easier. + + +Commands to enable and disable the autodisplays. Associate +autodisplays with breakpoints perhaps, so they only display +at those breakpoints; this is easier than using breakpoint commands. + +Remember how each breakpoint's position was specified. +Have command to reread symbol table and respecify each +breakpoint using same args (line number or function name) as before. + +Have way to proceed process in background so that can then suspend +gdb but have subprocess continue + + +Date: Fri, 24 Jul 87 21:30:25 EDT +From: phr@PREP.AI.MIT.EDU (Paul Rubin) +To: bug-gdb@PREP.AI.MIT.EDU + +After rereading the symbol table when user runs the "symbol-file" +command, when GDB notices that some of the source files are newer +it should reload them rather than just printing a message saying +they are newer. + + + +Message-Id: <8704171941.AA05045@orville.arpa> +To: mly@prep.ai.mit.edu +Cc: raible@orville.arpa, fouts@orville.arpa, creon@orville.arpa +Subject: gdb hack/questions, etc +Date: 17 Apr 87 11:41:42 PST (Fri) +From: raible@orville.arpa + + +A couple of things: + +1) Will gdb ever get dbx-sytly tracing? Wouldn't it be fairly easy to add? + +2) How about an xemacs gdb mode which has various windows, perhaps using + terminal.el for generality? + +3) Any word about that stupid IRIS SIGIOT problem? Do you know of anyone + else who has gotten IRIS subprocesses to work more reliably? + +4) Below is a hack adapted from ramsdell@linus.uucp which can be pretty + useful in gdb. Instead of using gdb to patch extensive changes to a + particular function, you can do the following (assuming the 50 lines + of code below is part of your executable): + 1) create a new file (foo.c) containing the new function + 2) run cc -c foo.c + 3) in gdb, and patch in the new function as follows: + +(gdb) info breakpoints +/* Load in the new object code... */ +#1 y 0x00000125 in main (dyn.c line 46) + break only if $function = funload ("foo"), 1 + silent + echo new code for func ($function) initialized\n + cont + +/* ...and use it instead of the old code. */ +#2 y 0x000001c2 in func (dyn.c line 59) + break only if $ret = $function (a), 1 + silent + set a = $ret + j 60 /* func has a return on line 60 */ + + This is more complicated than it has to be because of 2 bugs in v2.1: + 1) function calls in a breakpoint command list seem to abort + the execution of the rest of the command list. This is + why all function calls are in the conditional part. + (gdb reference manual section 5.5). + + 2) A 'return' in a command list also aborts the execution, and + in addition, prompts you for a y/n. + (gdb reference manual section 11.1). + + On the other hand, after doing 'cc -c foo.c' (which is pretty fast), + you can simply rerun your program to check out the changes. + This can be a big win! + +The code for this is included below (compile with cc -g): +======================================================== + +#include +#include + +typedef int (*intfun)(); +char *myname; + +intfun funload (filename) /* Dynamically load 1st function from a .o */ + char *filename; +{ + int fd, size; + struct exec hdr; + char buf[100]; + intfun fun; + + /* -A => incremental loading - use dyn as the base symbol table + -T => set the text segment origin to the following hex address + -N => magic number 407 (text not read-only) + */ + sprintf (buf, "ld -A %s -T %x -N %s.o -o %s -lc", + myname, sbrk (0), filename, filename); + + /* NOTE: if anything mallocs space between here and below, this will fail */ + system (buf); + + fd = open (filename, 0); + read (fd, &hdr, sizeof(hdr)); + size = hdr.a_text + hdr.a_data + hdr.a_bss; + + if ((fun = (intfun) sbrk (size)) < 0) + printf ("Couldn't find the space"), exit(); + + read (fd, fun, size); /* Load code. */ + /* NOTE: if anything mallocs space between here and above, this will fail */ + + close (fd); + return ((intfun) fun); +} + +main (argc, argv) + char **argv; +{ + intfun fun1, fun2; + + myname = *argv; + + fun1 = funload("fun1"); + printf ("The answer is %d.\n", (*fun1)(11) ); + + fun2 = funload("fun2"); + printf ("The answer is %d.\n", (*fun2)() ); +} +1,edited,, +Received: by PREP.AI.MIT.EDU; Tue, 16 Jun 87 03:12:54 EDT +Date: Tue, 16 Jun 87 03:12:54 EDT +From: rms (Richard M. Stallman) +Message-Id: <8706160712.AA07910@prep.ai.mit.edu> +To: rms +Subject: GDB ideas + +*** EOOH *** +Date: Tue, 16 Jun 87 03:12:54 EDT +From: rms (Richard M. Stallman) +To: rms +Subject: GDB ideas + +* Within a user-defined command, have local convenience variables, +local functions, local defined commands. + +** Optionally echo commands within a user-defined command. + +** Optionally record all user-typed commands in a log file. +Optionally record GDB output there too, marked as output so it +will not be executed if replayed. + +* Execution commands + +** Step until next branch, or next call. +(finish is step until next return). + +step branch +or should it be +continue branch + +** Stop on any branch, call or return +affecting ordinary step and continue commands. + +stop branch + +** Trace all branches, calls, returns. +This could be done by stopping on those events +and having a continue command to be executed after. + +stop branch +commands branch +continue +end + +** Commands to continue or step without any display after stop. +These may be useful in user-defined commands. + +Have one prefix command that does this, modifying whatever other +command you might use. For example, + +silent step 5 +silent cont + +** Clear all breakpoint ignore-counts when inferior exits or is killed. + +** Trace changes to a location (watchpoint). +Enable and disable them. + +** Info command to show command-line for running the program. + +* Auto-display + +** Enable and disable display expressions. +Allow syntax 1d, 2d, etc. in enable, disable and delete commands. +Then there is no more need for an undisplay command. + +** Displaying an auto variable should not do it in the wrong stack frame. +Either it should search for the proper stack frame to apply to +or it should deactivate itself when in the wrong frame. + +* Printing + +** Print an address as +offset. + +** Abbreviate initial whitespace modulo 16. + +** p/x of an array should print each element with /x. + +** Change the stack scan so that it has a more general idea +of what info is needed to describe a frame fully. + +* Expressions + +** Array slices. Can replace @. + +** %name for use of symbol names containing funny characters. + +** User-defined convenience functions that can appear in expressions. + +** Expression syntax to convert line number to address. + +** Expression syntax to specify a name scope with an address, line number +or frame number. + +Use the line number by itself, or an address with *, just as in b or l cmd: +38:foo or *0x40a:foo. No good; the latter would be parsed as +*(0x40a:foo). + +** Expression syntax to convert a frame number to its pc. +Perhaps unary %. + +* Possible bugs + +** Does set $pc= cause the current scope to be recalculated? +It should. + +1,, +Received: by PREP.AI.MIT.EDU; Wed, 17 Jun 87 09:59:37 EDT +From: phr@ATHENA.MIT.EDU +Received: by ATHENA (5.45/4.7) + id AA09084; Wed, 17 Jun 87 08:54:36 EDT +Received: by ORPHEUS.MIT.EDU (5.45/4.7) id AA02565; Wed, 17 Jun 87 08:54:29 EDT +Date: Wed, 17 Jun 87 08:54:29 EDT +Message-Id: <8706171254.AA02565@ORPHEUS.MIT.EDU> +To: rms@prep.ai.mit.edu +Subject: gdb suggestion +Status: RO + +*** EOOH *** +From: phr@ATHENA.MIT.EDU +Date: Wed, 17 Jun 87 08:54:29 EDT +To: rms@prep.ai.mit.edu +Subject: gdb suggestion + +Completion of file and function names; e.g. typing + break XWriteBi +prints + No such symbol: XWriteBi. + Setting default command to "break XWriteBitmapFile" +so you can set a break at XWriteBitmapFile by hitting return a second +time. Other interfaces ("complete to XWriteBitmapFile? (y/n)") +are also possible. + + +1,edited,, +Received: by PREP.AI.MIT.EDU; Wed, 24 Sep 86 16:33:11 EDT +Date: Wed, 24 Sep 86 16:33:11 EDT +From: mly (Richard Mlynarik) +Message-Id: <8609242033.AA11520@prep.ai.mit.edu> +To: rms +Cc: mly-prep +Subject: gdb gripes/suggestions/requests + +*** EOOH *** +Date: Wed, 24 Sep 86 16:33:11 EDT +From: mly (Richard Mlynarik) +To: rms +Cc: mly-prep +Subject: gdb gripes/suggestions/requests + +If would be really nice to have some way to do conditionals in user + commands -- though this is really stretching the functionality of + gdb a little too much, perhaps. (see ~mly/e/.gdbint for some of + the contortions I go through with || to get conditional + evaluation...) + +A -real- win wuold be some way to execute until he next function-call + (like c-d in the cadr debugger) This would even be useful if it + were rather slow -- it would probably be faster than setting + temporary breakpoints in all the functions which might be called, + and would certainly be faster than "step"ping one's way until a + funcall happened. + +"info source" should mention what the directory search-path is (ie + what "info dir" says) and in which directory it found each of the + source files (and which source files it cannot locate in the + search-path) + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA22869; Thu, 22 Oct 87 09:50:30 PDT +Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Thu, 22 Oct 87 12:17:59 EDT +Received: by PREP.AI.MIT.EDU; Thu, 22 Oct 87 12:21:00 EDT +Received: from pp.mcc.com by MCC.COM with TCP; Thu 22 Oct 87 10:54:41-CDT +Posted-Date: Thu, 22 Oct 87 10:55:13 CDT +Received: from big-d.aca.mcc.com by pp.mcc.com (4.12/KA70822) + id AA16571; Thu, 22 Oct 87 10:55:19 cdt +Return-Path: +Received: by big-d.aca.mcc.com (3.2/KA70106) + id AA04247; Thu, 22 Oct 87 10:55:13 CDT +Date: Thu, 22 Oct 87 10:55:13 CDT +From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) +Message-Id: <8710221555.AA04247@big-d.aca.mcc.com> +To: bug-gdb@prep.ai.mit.edu +Subject: expanding file names + +*** EOOH *** +Posted-Date: Thu, 22 Oct 87 10:55:13 CDT +Return-Path: +Date: Thu, 22 Oct 87 10:55:13 CDT +From: tiemann%pp.mcc.com@mcc.com (Michael Tiemann) +To: bug-gdb@prep.ai.mit.edu +Subject: expanding file names + +When running a program, gdb thoughtfully passes the argument list +through the shell, expanding files and environment variables as +needed. It would be nice if the same facility were added to the +command which adds directories to search paths. For example, it would +be nice to say "dir ~/foo" . + +Michael + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA25075; Fri, 23 Oct 87 10:42:52 PDT +Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Fri, 23 Oct 87 13:39:37 EDT +Received: by PREP.AI.MIT.EDU; Fri, 23 Oct 87 13:42:53 EDT +Received: from relay2.cs.net by RELAY.CS.NET id ac11193; 23 Oct 87 13:03 EDT +Received: from umb.edu by RELAY.CS.NET id ac05949; 23 Oct 87 13:01 EDT +Received: by umb.umb.edu; Fri, 23 Oct 87 10:18:40 EDT +Received: by ileaf.uucp (1.1/SMI-3.0DEV3) + id AA00599; Wed, 21 Oct 87 10:56:52 EDT +Received: from marvin.io.uucp by io.uucp (1.1/SMI-3.0DEV3) + id AA01359; Wed, 21 Oct 87 10:58:45 EDT +Received: by marvin.io.uucp (3.2/SMI-3.2) + id AA00334; Wed, 21 Oct 87 11:02:20 EDT +Date: Wed, 21 Oct 87 11:02:20 EDT +From: Mark Dionne +Message-Id: <8710211502.AA00334@marvin.io.uucp> +To: ileaf!umb!bug-gdb@prep.ai.mit.edu +Subject: gdb bug + +*** EOOH *** +Date: Wed, 21 Oct 87 11:02:20 EDT +From: Mark Dionne +To: ileaf!umb!bug-gdb@prep.ai.mit.edu +Subject: gdb bug + +The /FMT and @ options of the "print" command seem to interact +in GDB 2.1. For example: + +(gdb) p ($cmpn.buf[-1])@($cmpn.gapb - $cmpn.buf + 1) +$17 = {-16383, -24285, 55, 27944, -24285, -24285, 55, 28010, -24285, +-24285, 55, 28076, -24285, -24285, 55, 28142, -24285} +(gdb) p/x ($cmpn.buf[-1])@($cmpn.gapb - $cmpn.buf + 1) +$18 = 0xc001 + +I guess I see what's happening: the /x is applying to the whole +array rather than to the individual elements. Feature or bug? + + ...!harvard!umb!ileaf!md Mark Dionne, Interleaf + ...!sun!sunne!ileaf!md Ten Canal Park, Cambridge, MA 02141 + (617) 577-9813 x5551 + + + +1,, +Received: by PREP.AI.MIT.EDU; Sun, 6 Sep 87 14:27:19 EDT +Message-Id: <8709061827.AA18170@prep.ai.mit.edu> +Received: from relay2.cs.net by RELAY.CS.NET id af03990; 6 Sep 87 14:22 EDT +Received: from umb.edu by RELAY.CS.NET id ab03029; 6 Sep 87 14:16 EDT +Received: by umb.umb.edu; Sun, 6 Sep 87 12:10:34 EDT +Date: Sun, 6 Sep 87 12:10:34 EDT +Received: by typo.umb.edu; Sun, 6 Sep 87 12:04:21 EDT +From: Robert Morris +To: bug-gdb@PREP.AI.MIT.EDU +Subject: convenient script + +*** EOOH *** +Date: Sun, 6 Sep 87 12:10:34 EDT +From: Robert Morris +To: bug-gdb@PREP.AI.MIT.EDU +Subject: convenient script + +I find it easier to maintain binaries on our heterogenous +network if I keep this trivial script in gdb source directory. Use it +if you want. + + +------------ + +#! /bin/csh -f +# SETUP +# setup gdb files for presently known machines +# ram@umb.edu +# (ram%umb.edu@relay.cs.net if you have an incomplete mailer) +# or ...!harvard!umb!ram +# +# e.g. SETUP sun3 +# note that sunX means major release X of sun software, generally +# sun3 at this writing (gnu 18.41) +# +# note GDB with gnuemacs 18.41 is already configured for vaxen + +# Bob Morris, UMASS-Boston 9/6/87 +switch ($1) + case "sun2": + ; + case "sun3" : + set cputype="m68k"; + set inittype="suninit"; + breaksw; + default : + set cputype=$1; + set inittype=$1init; + breaksw; +endsw +echo \#include \"m-$1.h\" > param.h +echo \#include \"$cputype-pinsn.c\" > pinsn.c +ed initialize.h <& /dev/null +/init.h/ +c +#include "m-$inittype.h" +. +w +q +! + + + + +1,answered,, +Received: from prep.ai.mit.edu by wheaties.ai.mit.edu; Sat, 19 Dec 87 18:18:50 EST +Received: by PREP.AI.MIT.EDU; Sat, 19 Dec 87 18:24:38 EST +Received: from big-d.aca.mcc.com by MCC.COM with TCP; Sat 19 Dec 87 17:19:48-CST +Date: Sat, 19 Dec 87 17:19:41 CST +From: tiemann@mcc.com (Michael Tiemann) +Posted-Date: Sat, 19 Dec 87 17:19:41 CST +Message-Id: <8712192319.AA26775@big-d.aca.mcc.com> +Received: by big-d.aca.mcc.com (3.2/ACA-V2.1) + id AA26775; Sat, 19 Dec 87 17:19:41 CST +To: rms@prep.ai.mit.edu +Subject: gdb + +*** EOOH *** +Date: Sat, 19 Dec 87 17:19:41 CST +From: tiemann@mcc.com (Michael Tiemann) +Posted-Date: Sat, 19 Dec 87 17:19:41 CST +To: rms@prep.ai.mit.edu +Subject: gdb + +file values.c, function unpack_field_as_long: + + val &= (1 << bitsize) - 1; + +This is not as machine independent as it could be. If you feel like +fixing this potential problem, there are many other instances to worry +about. + +Michael + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA04771; Thu, 20 Aug 87 22:33:25 PDT +Received: from [128.52.22.14] by ucbvax.Berkeley.EDU (5.58/1.27) + id AA07119; Thu, 20 Aug 87 00:37:04 PDT +Received: by PREP.AI.MIT.EDU; Thu, 20 Aug 87 03:37:35 EDT +Date: Thu, 20 Aug 87 03:37:35 EDT +From: rms@prep.ai.mit.edu (Richard M. Stallman) +Message-Id: <8708200737.AA15589@prep.ai.mit.edu> +To: rms@prep.ai.mit.edu +Subject: GDB changes for next version + +*** EOOH *** +Date: Thu, 20 Aug 87 03:37:35 EDT +From: rms@prep.ai.mit.edu (Richard M. Stallman) +To: rms@prep.ai.mit.edu +Subject: GDB changes for next version + +1. Use links, rather than editing some files, to configure it. + +2. Can misc functions eval as their addresses rather than as + a char in that address? Is this reasonable in all cases + given that non-functions cannot be distinguished + and that you might use the result in various ways (arithmetic, etc.). + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA09136; Sat, 29 Aug 87 02:20:15 PDT +Received: from PREP.AI.MIT.EDU by ucbvax.Berkeley.EDU (5.58/1.27) + id AA26072; Sat, 29 Aug 87 02:21:51 PDT +Received: by PREP.AI.MIT.EDU; Sat, 29 Aug 87 05:22:30 EDT +Received: by RUTGERS.EDU (5.54/1.14) with UUCP + id AA22247; Sat, 29 Aug 87 05:21:13 EDT +Received: from sequent.UUCP by spool.wisc.edu; Sat, 29 Aug 87 04:18:41 CDT +Received: from reed.UUCP by ogcvax.OGC.EDU (5.51/OGC_4.8) + id AA08044; Fri, 28 Aug 87 20:06:41 PDT +Received: by reed.UUCP (5.51/5.17) + id AA05059; Fri, 28 Aug 87 19:19:15 PDT +From: uwvax!sequent!ogcvax!reed!keith@rutgers.edu (Keith Packard) +Message-Id: <8708290219.AA05059@reed.UUCP> +To: rms@prep.ai.mit.edu +Subject: Re: GDB +In-Reply-To: Your message of Thu, 20 Aug 87 03:39:37 EDT. + <8708200735.AA26546@EDDIE.MIT.EDU> +Date: Fri, 28 Aug 87 19:19:13 PDT + +*** EOOH *** +From: uwvax!sequent!ogcvax!reed!keith@rutgers.edu (Keith Packard) +To: rms@prep.ai.mit.edu +Subject: Re: GDB +In-Reply-To: Your message of Thu, 20 Aug 87 03:39:37 EDT. + <8708200735.AA26546@EDDIE.MIT.EDU> +Date: Fri, 28 Aug 87 19:19:13 PDT + + +Here is a simple test program for exibiting the trouble with signals: + +----- +# include + +main () +{ + int handle (); + int i; + signal (SIGALRM, handle); + alarm (5); + for (i = 0; i < 100000; i++) + printf ("%d\n", i); +} + +handle () +{ + printf ("signal!\n"); + alarm (5); +} +----- + +To demonstrate the problem, simply place a breakpoint before the call to +alarm and then start stepping through the program: + +(gdb) break 7 +(gdb) step +... +... + +Eventually, the alarm call occurs and the program ends up in some +signal handling code -- unfortuantely a machine dependent location. At this +point, because the fp has moved out of the current function (in fact on +many machines the frame is not in a consistent state at this point) gdb +assumes that a new function has started and suspends execution with another +prompt. + +A reasonable solution would be to have gdb insert a breakpoint at the +expected signal return address and continue to that breakpoint -- I've +implemented this and found that it works. There is, however, one nasty +problem -- longjmp around the suspended frame and the breakpoint is not hit +at the expected time. + +Have fun... + +keith packard + +tektronix!reed!keith + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA09143; Sat, 29 Aug 87 02:24:58 PDT +Received: by neptune.Berkeley.EDU (5.57/1.25) + id AA03738; Sat, 29 Aug 87 02:24:50 PDT +Date: Sat, 29 Aug 87 02:24:50 PDT +From: rms@neptune.berkeley.edu (Richard Stallman) +Message-Id: <8708290924.AA03738@neptune.Berkeley.EDU> +To: rms@neptune.Berkeley.EDU +Subject: GDB bug +Reply-To: rms@prep.ai.mit.edu + +*** EOOH *** +Date: Sat, 29 Aug 87 02:24:50 PDT +From: rms@neptune.berkeley.edu (Richard Stallman) +To: rms@neptune.Berkeley.EDU +Subject: GDB bug +Reply-To: rms@prep.ai.mit.edu + +Is there any way to make GDB, when stepping across a function call, +notice any attempt to longjump out of that call? +Perhaps an implicit breakpoint at longjump. +If longjump is called, find the pc in the jmp_buf and put +a self-deleting breakpoint there. + + +1,, +Received: by xcssun.Berkeley.EDU (5.57/1.25) + id AA07976; Fri, 28 Aug 87 09:26:12 PDT +Received: from PREP.AI.MIT.EDU by ucbvax.Berkeley.EDU (5.58/1.27) + id AA03230; Fri, 28 Aug 87 09:28:04 PDT +Received: by PREP.AI.MIT.EDU; Fri, 28 Aug 87 12:28:43 EDT +Date: Fri, 28 Aug 87 12:28:43 EDT +From: phr@prep.ai.mit.edu (Paul Rubin) +Message-Id: <8708281628.AA09926@prep.ai.mit.edu> +To: rms@prep.ai.mit.edu +Subject: gdb suggestions + +*** EOOH *** +Date: Fri, 28 Aug 87 12:28:43 EDT +From: phr@prep.ai.mit.edu (Paul Rubin) +To: rms@prep.ai.mit.edu +Subject: gdb suggestions + +1. I wish gdb had a command to re-read the sources so that I can edit +the program and recompile it without having to kill and restart gdb. + +2. Would be nice if gdb could somehow connect the subprocess's tty channels +to a pty, so I can run gdb in an X window and the subprocess in a different +(xterm) window. + +This might need hair to detect if the subprocess is running when you try +to examine variables, etc. and stop the subproc or report an error if it is. + + \ No newline at end of file diff --git a/gdb/infcmd.c b/gdb/infcmd.c new file mode 100644 index 00000000000..f2a9944839b --- /dev/null +++ b/gdb/infcmd.c @@ -0,0 +1,927 @@ +/* Memory-access and commands for inferior process, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" +#include "environ.h" +#include "value.h" + +#include +#include +#include + +#ifdef mac_aux +/* Warning! This table is positional and highly dependent on the local + system. Check it closely against when porting. */ +char *sys_siglist[] = { + "Signal 0", + "Hangup", + "Interrupt", + "Quit", + "Invalid instruction", + "Trace/breakpoint trap", + "IOT trap", + "EMT trap", + "Floating point exception", + "Killed", + "Bus error", + "Segmentation fault", + "Bad system call", + "Broken pipe", + "Alarm clock", + "Terminated", + "User signal 1", + "User signal 2", + "Child exited", + "Power-fail restart", + "Stopped", + "Stopped (tty input)", + "Stopped (tty output)", + "Stopped (signal)", + "Cputime limit exceeded", + "File size limit exceeded", + "Virtual timer expired", + "Profiling timer expired", + "Window changed", + "Continued", + "Urgent I/O condition", + "I/O possible", +}; +#else +/* More portable systems do it for you */ +extern char *sys_siglist[]; +#endif + +#define ERROR_NO_INFERIOR \ + if (inferior_pid == 0) error ("The program is not being run."); + +/* String containing arguments to give to the program, + with a space added at the front. Just a space means no args. */ + +static char *inferior_args; + +/* File name for default use for standard in/out in the inferior. */ + +char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +int inferior_pid; + +/* Last signal that the inferior received (why it stopped). */ + +int stop_signal; + +/* Address at which inferior stopped. */ + +CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +FRAME stop_frame; + +/* Number of breakpoint it stopped at, or 0 if none. */ + +int stop_breakpoint; + +/* Nonzero if stopped due to a step command. */ + +int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +int stop_stack_dummy; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +CORE_ADDR step_range_start; /* Inclusive */ +CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +CORE_ADDR step_frame; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +int step_multi; + +/* Environment to use for running inferior, + in format described in environ.h. */ + +struct environ *inferior_environ; + +CORE_ADDR read_pc (); +struct command_line *get_breakpoint_commands (); + +START_FILE + +int +have_inferior_p () +{ + return inferior_pid != 0; +} + +static void +set_args_command (args) + char *args; +{ + free (inferior_args); + if (!args) args = ""; + inferior_args = concat (" ", args, ""); +} + +void +tty_command (file) + char *file; +{ + if (file == 0) + error_no_arg ("terminal name for running target process"); + + inferior_io_terminal = savestring (file, strlen (file)); +} + +static void +run_command (args, from_tty) + char *args; + int from_tty; +{ + extern char **environ; + register int i; + char *exec_file; + char *allargs; + + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + dont_repeat (); + + if (inferior_pid) + { + if (query ("The program being debugged has been started already.\n\ +Start it from the beginning? ")) + kill_inferior (); + else + error ("Program already started."); + } + + if (args) + set_args_command (args); + + exec_file = (char *) get_exec_file (); + if (from_tty) + { + printf ("Starting program: %s%s\n", + exec_file, inferior_args); + fflush (stdout); + } + + allargs = concat ("exec ", exec_file, inferior_args); + inferior_pid = create_inferior (allargs, environ_vector (inferior_environ)); + + clear_proceed_status (); + + start_inferior (); +} + +void +cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + ERROR_NO_INFERIOR; + + clear_proceed_status (); + + /* If have argument, set proceed count of breakpoint we stopped at. */ + + if (stop_breakpoint && proc_count_exp) + { + set_ignore_count (stop_breakpoint, + parse_and_eval_address (proc_count_exp) - 1, + from_tty); + if (from_tty) + printf (" "); + } + + if (from_tty) + printf ("Continuing.\n"); + + proceed (-1, -1, 0); +} + +/* Step until outside of current statement. */ +static void step_1 (); + +static void +step_command (count_string) +{ + step_1 (0, 0, count_string); +} + +/* Likewise, but skip over subroutine calls as if single instructions. */ + +static void +next_command (count_string) +{ + step_1 (1, 0, count_string); +} + +/* Likewise, but step only one instruction. */ + +static void +stepi_command (count_string) +{ + step_1 (0, 1, count_string); +} + +static void +nexti_command (count_string) +{ + step_1 (1, 1, count_string); +} + +static void +step_1 (skip_subroutines, single_inst, count_string) + int skip_subroutines; + int single_inst; + char *count_string; +{ + register int count = 1; + + ERROR_NO_INFERIOR; + count = count_string ? parse_and_eval_address (count_string) : 1; + + for (; count > 0; count--) + { + clear_proceed_status (); + + step_frame = get_current_frame (); + + if (! single_inst) + { + find_pc_line_pc_range (stop_pc, &step_range_start, &step_range_end); + if (step_range_end == 0) + { + terminal_ours (); + error ("Current function has no line number information."); + } + } + else + { + /* Say we are stepping, but stop after one insn whatever it does. + Don't step through subroutine calls even to undebuggable functions. */ + step_range_start = step_range_end = 1; + if (!skip_subroutines) + step_over_calls = 0; + } + + if (skip_subroutines) + step_over_calls = 1; + + step_multi = (count > 1); + proceed (-1, -1, 1); + if (! stop_step) + break; + } +} + +/* Continue program at specified address. */ + +static void +jump_command (arg, from_tty) + char *arg; + int from_tty; +{ + register CORE_ADDR addr; + struct symtab_and_line sal; + + ERROR_NO_INFERIOR; + + if (!arg) + error_no_arg ("starting address"); + + sal = decode_line_spec (arg, 1); + + if (sal.symtab == 0 && sal.pc == 0) + error ("No source file has been specified."); + + if (sal.pc == 0) + sal.pc = find_line_pc (sal.symtab, sal.line); + + { + struct symbol *fn = get_frame_function (get_current_frame ()); + struct symbol *sfn = find_pc_function (sal.pc); + if (fn != 0 && sfn != fn + && ! query ("That is not in function %s. Continue there? ", + sal.line, SYMBOL_NAME (fn))) + error ("Not confirmed."); + } + + if (sal.pc == 0) + error ("No line %d in file \"%s\".", sal.line, sal.symtab->filename); + + addr = sal.pc; + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing at 0x%x.\n", addr); + + proceed (addr, 0, 0); +} + +/* Continue program giving it specified signal. */ + +static void +signal_command (signum_exp, from_tty) + char *signum_exp; + int from_tty; +{ + register int signum; + + dont_repeat (); /* Too dangerous. */ + ERROR_NO_INFERIOR; + + if (!signum_exp) + error_no_arg ("signal number"); + + signum = parse_and_eval_address (signum_exp); + + clear_proceed_status (); + + if (from_tty) + printf ("Continuing with signal %d.\n", signum); + + proceed (stop_pc, signum, 0); +} + +/* Execute a "stack dummy", a piece of code stored in the stack + by the debugger to be executed in the inferior. + + To call: first, do PUSH_DUMMY_FRAME. + Then push the contents of the dummy. It should end with a breakpoint insn. + Then call here, passing address at which to start the dummy. + + The contents of all registers are saved before the dummy frame is popped + and copied into the buffer BUFFER. + + The dummy's frame is automatically popped whenever that break is hit. + If that is the first time the program stops, run_stack_dummy + returns to its caller with that frame already gone. + Otherwise, the caller never gets returned to. */ + +/* 4 => return instead of letting the stack dummy run. */ + +static int stack_dummy_testing = 0; + +void +run_stack_dummy (addr, buffer) + CORE_ADDR addr; + REGISTER_TYPE *buffer; +{ + int saved_pc_changed = pc_changed; + int saved_stop_signal = stop_signal; + int saved_stop_pc = stop_pc; + int saved_stop_frame = stop_frame; + int saved_stop_breakpoint = stop_breakpoint; + int saved_stop_step = stop_step; + int saved_stop_stack_dummy = stop_stack_dummy; + FRAME saved_selected_frame; + int saved_selected_level; + struct command_line *saved_breakpoint_commands + = get_breakpoint_commands (); + + record_selected_frame (&saved_selected_frame, &saved_selected_level); + + /* Now proceed, having reached the desired place. */ + clear_proceed_status (); + if (stack_dummy_testing & 4) + { + POP_FRAME; + return; + } + proceed (addr, 0, 0); + + if (!stop_stack_dummy) + error ("Cannot continue previously requested operation."); + + set_breakpoint_commands (saved_breakpoint_commands); + select_frame (saved_selected_frame, saved_selected_level); + stop_signal = saved_stop_signal; + stop_pc = saved_stop_pc; + stop_frame = saved_stop_frame; + stop_breakpoint = saved_stop_breakpoint; + stop_step = saved_stop_step; + stop_stack_dummy = saved_stop_stack_dummy; + pc_changed = saved_pc_changed; + + /* On return, the stack dummy has been popped already. */ + + bcopy (stop_registers, buffer, sizeof stop_registers); +} + +/* "finish": Set a temporary breakpoint at the place + the selected frame will return to, then continue. */ + +static void +finish_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + register FRAME frame; + struct frame_info fi; + + register struct symbol *function; + + if (!have_inferior_p ()) + error ("The program is not being run."); + if (arg) + error ("The \"finish\" command does not take any arguments."); + + frame = get_prev_frame (selected_frame); + if (frame == 0) + error ("\"finish\" not meaningful in the outermost frame."); + + clear_proceed_status (); + + fi = get_frame_info (frame); + sal = find_pc_line (fi.pc, 0); + sal.pc = fi.pc; + set_momentary_breakpoint (sal, frame); + + /* Find the function we will return from. */ + + fi = get_frame_info (fi.next_frame); + function = find_pc_function (fi.pc); + + if (from_tty) + { + printf ("Run till exit from "); + print_selected_frame (); + } + + proceed (-1, -1, 0); + + if (stop_breakpoint == -3 && function != 0) + { + struct type *value_type; + register value val; + + if (TYPE_CODE (SYMBOL_TYPE (function)) != TYPE_CODE_VOID) + value_type = SYMBOL_TYPE (function); + else + return; + + val = value_being_returned (value_type, stop_registers); + printf ("Value returned is $%d = ", record_latest_value (val)); + value_print (val, stdout); + putchar ('\n'); + } +} + +static void +program_info () +{ + if (inferior_pid == 0) + { + printf ("The program being debugged is not being run.\n"); + return; + } + + printf ("Program being debugged is in process %d, stopped at 0x%x.\n", + inferior_pid, stop_pc); + if (stop_step) + printf ("It stopped after being stepped.\n"); + else if (stop_breakpoint) + printf ("It stopped at breakpoint %d.\n", stop_breakpoint); + else if (stop_signal) + printf ("It stopped with signal %d (%s).\n", + stop_signal, sys_siglist[stop_signal]); + + printf ("\nType \"info stack\" or \"info reg\" for more information.\n"); +} + +static void +environment_info (var) + char *var; +{ + if (var) + { + register char *val = get_in_environ (inferior_environ, var); + if (val) + printf ("%s = %s\n", var, val); + else + printf ("Environment variable \"%s\" not defined.\n", var); + } + else + { + register char **vector = environ_vector (inferior_environ); + while (*vector) + printf ("%s\n", *vector++); + } +} + +static void +set_environment_command (arg) + char *arg; +{ + register char *p, *val, *var; + + if (arg == 0) + error_no_arg ("environment variable and value"); + + p = (char *) index (arg, '='); + val = (char *) index (arg, ' '); + if (p != 0 && val != 0) + p = arg + min (p - arg, val - arg); + else if (val != 0 && p == 0) + p = val; + + if (p == 0) + error ("Space or \"=\" must separate variable name and its value"); + if (p[1] == 0) + error_no_arg ("value for the variable"); + if (p == arg) + error_no_arg ("environment variable to set"); + + val = p + 1; + while (*val == ' ' || *val == '\t') val++; + while (p != arg && (p[-1] == ' ' || p[-1] == '\t')) p--; + + var = savestring (arg, p - arg); + set_in_environ (inferior_environ, var, val); + free (var); +} + +static void +unset_environment_command (var) + char *var; +{ + if (var == 0) + error_no_arg ("environment variable"); + + unset_in_environ (inferior_environ, var); +} + +/* Read an integer from debugged memory, given address and number of bytes. */ + +read_memory_integer (memaddr, len) + CORE_ADDR memaddr; + int len; +{ + char cbuf; + short sbuf; + int ibuf; + long lbuf; + + if (len == sizeof (char)) + { + read_memory (memaddr, &cbuf, len); + return cbuf; + } + if (len == sizeof (short)) + { + read_memory (memaddr, &sbuf, len); + return sbuf; + } + if (len == sizeof (int)) + { + read_memory (memaddr, &ibuf, len); + return ibuf; + } + if (len == sizeof (lbuf)) + { + read_memory (memaddr, &lbuf, len); + return lbuf; + } + error ("Cannot handle integers of %d bytes.", len); +} + +CORE_ADDR +read_pc () +{ + return (CORE_ADDR) read_register (PC_REGNUM); +} + +write_pc (val) + CORE_ADDR val; +{ + write_register (PC_REGNUM, (long) val); +} + +char *reg_names[] = REGISTER_NAMES; + +static void +registers_info (addr_exp) + char *addr_exp; +{ + register int i; + int regnum; + + if (addr_exp) + { + if (*addr_exp >= '0' && *addr_exp <= '9') + regnum = atoi (addr_exp); + else + { + register char *p = addr_exp; + if (p[0] == '$') + p++; + for (regnum = 0; regnum < NUM_REGS; regnum++) + if (!strcmp (p, reg_names[regnum])) + break; + if (regnum == NUM_REGS) + error ("%s: invalid register name.", addr_exp); + } + } + else + printf ("Reg\tContents\n\n"); + + for (i = 0; i < NUM_REGS; i++) + { + unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + REGISTER_TYPE val; + + if (addr_exp != 0 && i != regnum) + continue; + + /* On machines with lots of registers, pause every 16 lines + so user can read the output. */ + if (addr_exp == 0 && i > 0 && i % 16 == 0) + { + printf ("--Type Return to print more--"); + fflush (stdout); + read_line (); + } + + /* Get the data in raw format, then convert also to virtual format. */ + read_relative_register_raw_bytes (i, raw_buffer); + REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); + + printf ("%s\t", reg_names[i]); + + /* If virtual format is floating, print it that way. */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (i)) == TYPE_CODE_FLT + && ! INVALID_FLOAT (virtual_buffer, REGISTER_VIRTUAL_SIZE (i))) + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout); + /* Else if virtual format is too long for printf, + print in hex a byte at a time. */ + else if (REGISTER_VIRTUAL_SIZE (i) > sizeof (long)) + { + register int j; + printf ("0x"); + for (j = 0; j < REGISTER_VIRTUAL_SIZE (i); j++) + printf ("%02x", virtual_buffer[j]); + } + /* Else print as integer in hex and in decimal. */ + else + { + long val; + + bcopy (virtual_buffer, &val, sizeof (long)); + if (val == 0) + printf ("0"); + else + printf ("0x%08x %d", val, val); + } + + /* If register has different raw and virtual formats, + print the raw format in hex now. */ + + if (REGISTER_CONVERTIBLE (i)) + { + register int j; + + printf (" (raw 0x"); + for (j = 0; j < REGISTER_RAW_SIZE (i); j++) + printf ("%02x", raw_buffer[j]); + printf (")"); + } + printf ("\n"); + } + + printf ("Contents are relative to selected stack frame.\n"); +} + +#ifdef ATTACH_DETACH +/* + * TODO: + * Should save/restore the tty state since it might be that the + * program to be debugged was started on this tty and it wants + * the tty in some state other than what we want. If it's running + * on another terminal or without a terminal, then saving and + * restoring the tty state is a harmless no-op. + */ + +/* + * attach_command -- + * takes a program started up outside of gdb and ``attaches'' to it. + * This stops it cold in it's tracks and allows us to start tracing + * it. For this to work, we must be able to send the process a + * signal and we must have the same effective uid as the program. + */ +static void +attach_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file; + int pid; + + dont_repeat(); + + if (!args) + error_no_arg ("process-id to attach"); + else + pid = atoi (args); + + if (inferior_pid) + { + if (query ("A program is being debugged already. Kill it? ")) + kill_inferior (); + else + error ("Inferior not killed."); + } + + exec_file = (char *) get_exec_file (); + + if (from_tty) + { + printf ("Attaching program: %s pid %d\n", + exec_file, pid); + fflush (stdout); + } + + attach_program (pid); +} + +/* + * detach_command -- + * takes a program previously attached to and detaches it. + * The program resumes execution and will no longer stop + * on signals, etc. We better not have left any breakpoints + * in the program or it'll die when it hits one. For this + * to work, it may be necessary for the process to have been + * previously attached. It *might* work if the program was + * started via the normal ptrace (PTRACE_TRACEME). + */ + +static void +detach_command (args, from_tty) + char *args; + int from_tty; +{ + char *exec_file = (char *)get_exec_file (); + int signal = 0; + + if (!inferior_pid) + error ("Not currently tracing a program\n"); + if (from_tty) + { + printf ("Detaching program: %s pid %d\n", + exec_file, inferior_pid); + fflush (stdout); + } + if (args) + signal = atoi (args); + + detach (signal); + inferior_pid = 0; +} +#endif /* ATTACH_DETACH */ + +static +initialize () +{ + add_com ("tty", class_run, tty_command, + "Set terminal for future runs of program being debugged."); + + add_com ("set-args", class_run, set_args_command, + "Specify arguments to give program being debugged when it is started.\n\ +Follow this command with any number of args, to be passed to the program."); + + add_info ("environment", environment_info, + "The environment to give the program, or one variable's value.\n\ +With an argument VAR, prints the value of environment variable VAR to\n\ +give the program being debugged. With no arguments, prints the entire\n\ +environment to be given to the program."); + + add_com ("unset-environment", class_run, unset_environment_command, + "Cancel environment variable VAR for the program.\n\ +This does not affect the program until the next \"run\" command."); + add_com ("set-environment", class_run, set_environment_command, + "Set environment variable value to give the program.\n\ +Arguments are VAR VALUE where VAR is variable name and VALUE is value.\n\ +VALUES of environment variables are uninterpreted strings.\n\ +This does not affect the program until the next \"run\" command."); + +#ifdef ATTACH_DETACH + add_com ("attach", class_run, attach_command, + "Attach to a process that was started up outside of GDB.\n\ +To do this, you must have permission to send the process a signal.\n\ +And it must have the same effective uid as the debugger.\n\n\ +Before using \"attach\", you must use the \"exec-file\" command\n\ +to specify the program running in the process,\n\ +and the \"symbol-file\" command to load its symbol table."); + add_com ("detach", class_run, detach_command, + "Detach the process previously attached.\n\ +The process is no longer traced and continues its execution."); +#endif /* ATTACH_DETACH */ + + add_com ("signal", class_run, signal_command, + "Continue program giving it signal number SIGNUMBER."); + + add_com ("stepi", class_run, stepi_command, + "Step one instruction exactly.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("si", "stepi", class_alias, 0); + + add_com ("nexti", class_run, nexti_command, + "Step one instruction, but proceed through subroutine calls.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("ni", "nexti", class_alias, 0); + + add_com ("finish", class_run, finish_command, + "Execute until selected stack frame returns.\n\ +Upon return, the value returned is printed and put in the value history."); + + add_com ("next", class_run, next_command, + "Step program, proceeding through subroutine calls.\n\ +Like the \"step\" command as long as subroutine calls do not happen;\n\ +when they do, the call is treated as one instruction.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("n", "next", class_run, 1); + + add_com ("step", class_run, step_command, + "Step program until it reaches a different source line.\n\ +Argument N means do this N times (or till program stops for another reason)."); + add_com_alias ("s", "step", class_run, 1); + + add_com ("jump", class_run, jump_command, + "Continue program being debugged at specified line or address.\n\ +Give as argument either LINENUM or *ADDR, where ADDR is an expression\n\ +for an address to start at."); + + add_com ("cont", class_run, cont_command, + "Continue program being debugged, after signal or breakpoint.\n\ +If proceeding from breakpoint, a number N may be used as an argument:\n\ +then the same breakpoint won't break until the Nth time it is reached."); + add_com_alias ("c", "cont", class_run, 1); + + add_com ("run", class_run, run_command, + "Start debugged program. You may specify arguments to give it.\n\ +Args may include \"*\", or \"[...]\"; they are expanded using \"sh\".\n\ +Input and output redirection with \">\", \"<\", or \">>\" are also allowed.\n\n\ +With no arguments, uses arguments last specified (with \"run\" or \"set-args\".\n\ +To cancel previous arguments and run with no arguments,\n\ +use \"set-args\" without arguments."); + add_com_alias ("r", "run", class_run, 1); + + add_info ("registers", registers_info, + "List of registers and their contents, for selected stack frame.\n\ +Register name as argument means describe only that register."); + + add_info ("program", program_info, + "Execution status of the program."); + + inferior_args = savestring (" ", 1); /* By default, no args. */ + inferior_environ = make_environ (); + init_environ (inferior_environ); +} + +END_FILE diff --git a/gdb/inferior.h b/gdb/inferior.h new file mode 100644 index 00000000000..21c937c37b0 --- /dev/null +++ b/gdb/inferior.h @@ -0,0 +1,85 @@ +/* Variables that describe the inferior process running under GDB: + Where it is, why it stopped, and how to step it. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* File name for default use for standard in/out in the inferior. */ + +extern char *inferior_io_terminal; + +/* Pid of our debugged inferior, or 0 if no inferior now. */ + +extern int inferior_pid; + +/* Last signal that the inferior received (why it stopped). */ + +extern int stop_signal; + +/* Address at which inferior stopped. */ + +extern CORE_ADDR stop_pc; + +/* Stack frame when program stopped. */ + +extern FRAME stop_frame; + +/* Number of breakpoint it stopped at, or 0 if none. */ + +extern int stop_breakpoint; + +/* Nonzero if stopped due to a step command. */ + +extern int stop_step; + +/* Nonzero if stopped due to completion of a stack dummy routine. */ + +extern int stop_stack_dummy; + +/* Range to single step within. + If this is nonzero, respond to a single-step signal + by continuing to step if the pc is in this range. */ + +extern CORE_ADDR step_range_start; /* Inclusive */ +extern CORE_ADDR step_range_end; /* Exclusive */ + +/* Stack frame address as of when stepping command was issued. + This is how we know when we step into a subroutine call, + and how to set the frame for the breakpoint used to step out. */ + +extern CORE_ADDR step_frame; + +/* 1 means step over all subroutine calls. + -1 means step over calls to undebuggable functions. */ + +extern int step_over_calls; + +/* If stepping, nonzero means step count is > 1 + so don't print frame next time inferior stops + if it stops due to stepping. */ + +extern int step_multi; + +/* Save register contents here when about to pop a stack dummy frame. */ + +extern char stop_registers[REGISTER_BYTES]; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +extern int pc_changed; diff --git a/gdb/inflow.c b/gdb/inflow.c new file mode 100644 index 00000000000..7bed5943bf4 --- /dev/null +++ b/gdb/inflow.c @@ -0,0 +1,661 @@ +/* Low level interface to ptrace, for GDB when running under Unix. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "frame.h" +#include "inferior.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef mac_aux +#include +#include +#include +#include +#include +#else +#include +#endif /* mac_aux */ + + +#ifdef UMAX_PTRACE +#include +#endif + +#ifdef NEW_SUN_PTRACE +#include +#include +#endif + +#ifdef SYSV_TTYS +#include +#endif + +extern int errno; + +/* Nonzero if we are debugging an attached outside process + rather than an inferior. */ + +static int attach_flag; + +#define UPAGE_MASK 0x00003FFF + +START_FILE + +/* Record terminal status separately for debugger and inferior. */ + +#ifdef SYSV_TTYS +static struct termio ti_inferior; +#else +static struct sgttyb sg_inferior; +static struct tchars tc_inferior; +static struct ltchars ltc_inferior; +static int lmode_inferior; +#endif +static int tflags_inferior; +static int pgrp_inferior; + +#ifdef SYSV_TTYS +static struct termio ti_ours; +#else +static struct sgttyb sg_ours; +static struct tchars tc_ours; +static struct ltchars ltc_ours; +static int lmode_ours; +#endif +static int tflags_ours; +static int pgrp_ours; + +/* Copy of inferior_io_terminal when inferior was last started. */ +static char *inferior_thisrun_terminal; + +static void terminal_ours_1 (); + +/* Nonzero if our terminal settings are in effect. + Zero if the inferior's settings are in effect. */ +static int terminal_is_ours; + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +void +terminal_init_inferior () +{ + +#ifdef SYSV_TTYS + ti_inferior = ti_ours; +#else + sg_inferior = sg_ours; + tc_inferior = tc_ours; + ltc_inferior = ltc_ours; + lmode_inferior = lmode_ours; +#endif + tflags_inferior = tflags_ours; + pgrp_inferior = inferior_pid; + + terminal_is_ours = 1; +} + +/* Put the inferior's terminal settings into effect. + This is preparation for starting or resuming the inferior. */ + +void +terminal_inferior () +{ + if (terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ + { + fcntl (0, F_SETFL, tflags_inferior); + fcntl (0, F_SETFL, tflags_inferior); +#ifdef SYSV_TTYS + ioctl (0, TCSETA, &ti_inferior); +#else + ioctl (0, TIOCSETN, &sg_inferior); + ioctl (0, TIOCSETC, &tc_inferior); + ioctl (0, TIOCSLTC, <c_inferior); + ioctl (0, TIOCLSET, &lmode_inferior); +#endif + ioctl (0, TIOCSPGRP, &pgrp_inferior); + } + terminal_is_ours = 0; +} + +/* Put some of our terminal settings into effect, + enough to get proper results from our output, + but do not change into or out of RAW mode + so that no input is discarded. + + After doing this, either terminal_ours or terminal_inferior + should be called to get back to a normal state of affairs. */ + +void +terminal_ours_for_output () +{ + terminal_ours_1 (1); +} + +/* Put our terminal settings into effect. + First record the inferior's terminal settings + so they can be restored properly later. */ + +void +terminal_ours () +{ + terminal_ours_1 (0); +} + +static void +terminal_ours_1 (output_only) + int output_only; +{ + /* Ignore this signal since it will happen when we try to set the pgrp. */ + int (*osigttou) (); + + if (!terminal_is_ours) /* && inferior_thisrun_terminal == 0) */ + { + terminal_is_ours = 1; + + osigttou = signal (SIGTTOU, SIG_IGN); + + ioctl (0, TIOCGPGRP, &pgrp_inferior); + ioctl (0, TIOCSPGRP, &pgrp_ours); + + signal (SIGTTOU, osigttou); + + tflags_inferior = fcntl (0, F_GETFL, 0); +#ifdef SYSV_TTYS + ioctl (0, TCGETA, &ti_inferior); +#else + ioctl (0, TIOCGETP, &sg_inferior); + ioctl (0, TIOCGETC, &tc_inferior); + ioctl (0, TIOCGLTC, <c_inferior); + ioctl (0, TIOCLGET, &lmode_inferior); +#endif + } + + fcntl (0, F_SETFL, tflags_ours); + fcntl (0, F_SETFL, tflags_ours); + + +#ifdef SYSV_TTYS + ti_ours.c_lflag |= ICANON | ISIG; + if (output_only) + ti_ours.c_lflag &= ~((ICANON|ISIG)&ti_inferior.c_lflag); + ioctl (0, TCSETA, &ti_ours); + ti_ours.c_lflag |= ICANON | ISIG; +#else + sg_ours.sg_flags &= ~RAW & ~CBREAK; + if (output_only) + sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags; + ioctl (0, TIOCSETN, &sg_ours); + ioctl (0, TIOCSETC, &tc_ours); + ioctl (0, TIOCSLTC, <c_ours); + ioctl (0, TIOCLSET, &lmode_ours); + sg_ours.sg_flags &= ~RAW & ~CBREAK; +#endif +} + +static void +term_status_command () +{ + register int i; + printf ("Inferior's terminal status (currently saved by GDB):\n"); +#ifdef SYSV_TTYS + printf ("fcntl flags = 0x%x, owner pid = %d.\n", + tflags_inferior, pgrp_inferior); + printf ("iflag = 0x%04x, oflag = 0x%04x, cflag = 0x%04x, lflag = 0x%04x\n", + ti_inferior.c_iflag, ti_inferior.c_oflag, + ti_inferior.c_cflag, ti_inferior.c_lflag); + printf ("line discipline = %d\n", ti_inferior.c_line); + printf ("control chars: "); + for (i = 0; i < NCC; i++) + printf ("0x%x ", ti_inferior.c_cc[i]); + printf ("\n"); +#else + printf ("fcntl flags = 0x%x, lmode = 0x%x,\nsgttyb.sg_flags = 0x%x, owner pid = %d.\n", + tflags_inferior, lmode_inferior, + sg_inferior.sg_flags, pgrp_inferior); + printf ("tchars: "); + for (i = 0; i < sizeof (struct tchars); i++) + printf ("0x%x ", ((char *)&tc_inferior)[i]); + printf ("\n"); + printf ("ltchars: "); + for (i = 0; i < sizeof (struct ltchars); i++) + printf ("0x%x ", ((char *)<c_inferior)[i]); + printf ("\n"); +#endif +} + +static void +new_tty (ttyname) + char *ttyname; +{ + register int tty; + register int fd; + +#if 0 + /* I think it is better not to do this. Then C-z on the GDB terminal + will still stop the program, while C-z on the data terminal + will be input. */ + + /* Disconnect the child process from our controlling terminal. */ + tty = open("/dev/tty", O_RDWR); + if (tty > 0) + { + ioctl(tty, TIOCNOTTY, 0); + close(tty); + } +#endif + /* Now open the specified new terminal. */ + + tty = open(ttyname, O_RDWR); + if (tty == -1) + _exit(1); + + dup2(tty, 0); + dup2(tty, 1); + dup2(tty, 2); + close(tty); +} + +/* Start an inferior process and returns its pid. + ALLARGS is a vector of program-name and args. + ENV is the environment vector to pass. */ + +int +create_inferior (allargs, env) + char **allargs; + char **env; +{ + int pid; + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + + /* exec is said to fail if the executable is open. */ + close_exec_file (); + + pid = vfork (); + if (pid < 0) + perror_with_name ("vfork"); + + if (pid == 0) + { + /* Run inferior in a separate process group. */ + setpgrp (getpid (), getpid ()); + + inferior_thisrun_terminal = inferior_io_terminal; + if (inferior_io_terminal != 0) + new_tty (inferior_io_terminal); + +/* Not needed on Sun, at least, and loses there + because it clobbers the superior. */ +/*??? signal (SIGQUIT, SIG_DFL); + signal (SIGINT, SIG_DFL); */ + + ptrace (0); + execle ("/bin/sh", "sh", "-c", allargs, 0, env); + + fprintf (stderr, "Cannot exec /bin/sh: %s.\n", + errno < sys_nerr ? sys_errlist[errno] : "unknown error"); + fflush (stderr); + _exit (0177); + } + return pid; +} + +/* Kill the inferior process. Make us have no inferior. */ + +static void +kill_command () +{ + if (inferior_pid == 0) + error ("The program is not being run."); + if (!query ("Kill the inferior process? ")) + error ("Not confirmed."); + kill_inferior (); +} + +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (8, inferior_pid, 0, 0); + wait (0); + inferior_died (); +} + +inferior_died () +{ + inferior_pid = 0; + attach_flag = 0; + mark_breakpoints_out (); + reopen_exec_file (); + if (have_core_file_p ()) + set_current_frame (read_register (FP_REGNUM)); +} + +/* 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; + ptrace (step ? 9 : 7, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef NEW_SUN_PTRACE + +/* Start debugging the process whose number is PID. */ + +attach (pid) + int pid; +{ + errno = 0; + ptrace (PTRACE_ATTACH, pid, 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PTRACE_DETACH, inferior_pid, 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif + +#ifdef NEW_SUN_PTRACE + +void +fetch_inferior_registers () +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + ptrace (PTRACE_GETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_GETFPREGS, inferior_pid, &inferior_fp_registers); + + bcopy (&inferior_registers, registers, 16 * 4); + bcopy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], + sizeof inferior_fp_registers.fps_regs); + *(int *)®isters[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps; + *(int *)®isters[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc; + bcopy (&inferior_fp_registers.fps_control, + ®isters[REGISTER_BYTE (FPC_REGNUM)], + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); +} + +/* 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; +{ + struct regs inferior_registers; + struct fp_status inferior_fp_registers; + extern char registers[]; + + bcopy (registers, &inferior_registers, 16 * 4); + bcopy (®isters[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers, + sizeof inferior_fp_registers.fps_regs); + inferior_registers.r_ps = *(int *)®isters[REGISTER_BYTE (PS_REGNUM)]; + inferior_registers.r_pc = *(int *)®isters[REGISTER_BYTE (PC_REGNUM)]; + bcopy (®isters[REGISTER_BYTE (FPC_REGNUM)], + &inferior_fp_registers.fps_control, + sizeof inferior_fp_registers - sizeof inferior_fp_registers.fps_regs); + + ptrace (PTRACE_SETREGS, inferior_pid, &inferior_registers); + ptrace (PTRACE_SETFPREGS, inferior_pid, &inferior_fp_registers); +} + +#else + +void +fetch_inferior_registers () +{ + register int regno; + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + register int i; + +#ifdef UMAX_PTRACE + unsigned int offset = 0; +#else + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) & UPAGE_MASK; +#endif + + for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + *(int *) &buf[i] = ptrace (3, inferior_pid, regaddr, 0); + regaddr += sizeof (int); + } + supply_register (regno, buf); + } +} + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + +#ifdef UMAX_PTRACE + unsigned int offset = 0; +#else + struct user u; + unsigned int offset = (char *) &u.u_ar0 - (char *) &u; + offset = ptrace (3, inferior_pid, offset, 0) & UPAGE_MASK; +#endif + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } + else for (regno = 0; regno < NUM_REGS; regno++) + { + regaddr = register_addr (regno, offset); + errno = 0; + ptrace (6, inferior_pid, regaddr, read_register (regno)); + if (errno != 0) + { + sprintf (buf, "writing register number %d", regno); + perror_with_name (buf); + } + } +} + +#endif /* not NEW_SUN_PTRACE */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. */ + +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)); + + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + buffer[i] = ptrace (1, inferior_pid, addr, 0); + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); +} + +/* Copy LEN bytes of data from debugger memnory 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. */ + + buffer[0] = ptrace (1, inferior_pid, addr, 0); + if (count > 1) + 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; + ptrace (4, inferior_pid, addr, buffer[i]); + if (errno) + return errno; + } + + return 0; +} + +static void +try_writing_regs_command () +{ + register int i; + register int value; + extern int errno; + + if (inferior_pid == 0) + error ("The program is not being run."); + + for (i = 0; ; i += 2) + { + QUIT; + errno = 0; + value = ptrace (3, inferior_pid, i, 0); + ptrace (6, inferior_pid, i, value); + if (errno == 0) + { + printf (" Succeeded with address 0x%x; value 0x%x (%d).\n", + i, value, value); + } + else if ((i & 0377) == 0) + printf (" Failed at 0x%x.\n", i); + } +} + +static +initialize () +{ + add_com ("term-status", class_obscure, term_status_command, + "Print info on inferior's saved terminal status."); + + add_com ("try-writing-regs", class_obscure, try_writing_regs_command, + "Try writing all locations in inferior's system block.\n\ +Report which ones can be written."); + + add_com ("kill", class_run, kill_command, + "Kill execution of program being debugged."); + + inferior_pid = 0; + +#ifdef SYSV_TTYS + ioctl (0, TCGETA, &ti_ours); +#else + ioctl (0, TIOCGETP, &sg_ours); + ioctl (0, TIOCGETC, &tc_ours); + ioctl (0, TIOCGLTC, <c_ours); + ioctl (0, TIOCLGET, &lmode_ours); +#endif + fcntl (0, F_GETFL, tflags_ours); + ioctl (0, TIOCGPGRP, &pgrp_ours); + + terminal_is_ours = 1; +} + +END_FILE diff --git a/gdb/infrun.c b/gdb/infrun.c new file mode 100644 index 00000000000..e980cec1620 --- /dev/null +++ b/gdb/infrun.c @@ -0,0 +1,943 @@ +/* Start and stop the inferior process, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include +#include +#include + +#ifdef UMAX_PTRACE +#include +#include +#endif UMAX_PTRACE + +extern char *sys_siglist[]; +extern int errno; + +/* Tables of how to react to signals; the user sets them. */ + +static char signal_stop[NSIG]; +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; + +/* This is the sequence of bytes we insert for a breakpoint. */ + +static char break_insn[] = BREAKPOINT; + +/* Nonzero => address for special breakpoint for resuming stepping. */ + +static CORE_ADDR step_resume_break_address; + +/* Original contents of the byte where the special breakpoint is. */ + +static char step_resume_break_shadow[sizeof break_insn]; + +/* Nonzero means the special breakpoint is a duplicate + so it has not itself been inserted. */ + +static int step_resume_break_duplicate; + +/* Nonzero if we are expecting a trace trap and should proceed from it. + 2 means expecting 2 trace traps and should continue both times. + That occurs when we tell sh to exec the program: we will get + a trap after the exec of sh and a second when the program is exec'd. */ + +static int trap_expected; + +/* Nonzero means expecting a trace trap + and should stop the inferior and return silently when it happens. */ + +static int stop_after_trap; + +/* Nonzero means expecting a trace trap due to attaching to a process. */ + +static int stop_after_attach; + +/* Nonzero if pc has been changed by the debugger + since the inferior stopped. */ + +int pc_changed; + +/* Save register contents here when about to pop a stack dummy frame. */ + +char stop_registers[REGISTER_BYTES]; + +/* Nonzero if program stopped due to error trying to insert breakpoints. */ + +static int breakpoints_failed; + +/* Nonzero if inferior is in sh before our program got exec'd. */ + +static int running_in_shell; + +/* Nonzero after stop if current stack frame should be printed. */ + +static int stop_print_frame; + +static void insert_step_breakpoint (); +static void remove_step_breakpoint (); +static void wait_for_inferior (); +static void normal_stop (); + +START_FILE + +/* Clear out all variables saying what to do when inferior is continued. + First do this, then set the ones you want, then call `proceed'. */ + +void +clear_proceed_status () +{ + trap_expected = 0; + step_range_start = 0; + step_range_end = 0; + step_frame = 0; + step_over_calls = -1; + step_resume_break_address = 0; + stop_after_trap = 0; + stop_after_attach = 0; + + /* Discard any remaining commands left by breakpoint we had stopped at. */ + clear_breakpoint_commands (); +} + +/* Basic routine for continuing the program in various fashions. + + ADDR is the address to resume at, or -1 for resume where stopped. + SIGNAL is the signal to give it, or 0 for none, + or -1 for act according to how it stopped. + STEP is nonzero if should trap after one instruction. + -1 means return after that and print nothing. + You should probably set various step_... variables + before calling here, if you are stepping. + + You should call clear_proceed_status before calling proceed. */ + +void +proceed (addr, signal, step) + CORE_ADDR addr; + int signal; + int step; +{ + int oneproc = 0; + + if (step > 0) + step_start_function = find_pc_function (read_pc ()); + if (step < 0) + stop_after_trap = 1; + + if (addr == -1) + { + /* If there is a breakpoint at the address we will resume at, + step one instruction before inserting breakpoints + so that we do not stop right away. */ + + if (!pc_changed && breakpoint_here_p (read_pc ())) + { + oneproc = 1; + /* We will get a trace trap after one instruction. + Continue it automatically and insert breakpoints then. */ + trap_expected = 1; + } + } + else + write_register (PC_REGNUM, addr); + + if (!oneproc) + { + int temp = insert_breakpoints (); + if (temp) + { + print_sys_errmsg ("ptrace", temp); + error ("Cannot insert breakpoints.\n\ +The same program may be running in another process."); + } + breakpoints_inserted = 1; + } + + /* Install inferior's terminal modes. */ + terminal_inferior (); + + if (signal >= 0) + stop_signal = signal; + /* If this signal should not be seen by program, + give it zero. Used for debugging signals. */ + else if (stop_signal < NSIG && !signal_program[stop_signal]) + stop_signal= 0; + + /* Resume inferior. */ + resume (oneproc || step, stop_signal); + + /* Wait for it to stop (if not standalone) + and in any case decode why it stopped, and act accordingly. */ + + wait_for_inferior (); + normal_stop (); +} + +/* Writing the inferior pc as a register calls this function + to inform infrun that the pc has been set in the debugger. */ + +writing_pc (val) + CORE_ADDR val; +{ + stop_pc = val; + pc_changed = 1; +} + +/* Start an inferior process for the first time. + Actually it was started by the fork that created it, + but it will have stopped one instruction after execing sh. + Here we must get it up to actual execution of the real program. */ + +start_inferior () +{ + /* We will get a trace trap after one instruction. + Continue it automatically. Eventually (after shell does an exec) + it will get another trace trap. Then insert breakpoints and continue. */ + trap_expected = 2; + running_in_shell = 0; /* Set to 1 at first SIGTRAP, 0 at second. */ + breakpoints_inserted = 0; + mark_breakpoints_out (); + + /* Set up the "saved terminal modes" of the inferior + based on what modes we are starting it with. */ + terminal_init_inferior (); + + /* Install inferior's terminal modes. */ + terminal_inferior (); + + wait_for_inferior (); + normal_stop (); +} + +#ifdef ATTACH_DETACH + +/* Attach to process PID, then initialize for debugging it + and wait for the trace-trap that results from attaching. */ + +void +attach_program (pid) + int pid; +{ + attach (pid); + inferior_pid = pid; + + mark_breakpoints_out (); + terminal_init_inferior (); + clear_proceed_status (); + stop_after_attach = 1; + /*proceed (-1, 0, -2);*/ + wait_for_inferior (); + normal_stop (); +} +#endif /* ATTACH_DETACH */ + +/* Wait for control to return from inferior to debugger. + If inferior gets a signal, we may decide to start it up again + instead of returning. That is why there is a loop in this function. + When this function actually returns it means the inferior + should be left stopped and GDB should read more commands. */ + +static void +wait_for_inferior () +{ + register int pid; + WAITTYPE w; + CORE_ADDR pc; + int tem; + int another_trap; + int random_signal; + CORE_ADDR stop_sp; + int stop_step_resume_break; + int newmisc; + int newfun_pc; + struct symbol *newfun; + struct symtab_and_line sal; + int prev_pc; + + while (1) + { + prev_pc = read_pc (); + pid = wait (&w); + pc_changed = 0; + fetch_inferior_registers (); + stop_pc = read_pc (); + set_current_frame (read_register (FP_REGNUM)); + stop_frame = get_current_frame (); + stop_sp = read_register (SP_REGNUM); + another_trap = 0; + stop_breakpoint = 0; + stop_step = 0; + stop_stack_dummy = 0; + stop_print_frame = 1; + stop_step_resume_break = 0; + random_signal = 0; + breakpoints_failed = 0; + + /* Look at the cause of the stop, and decide what to do. + The alternatives are: + 1) break; to really stop and return to the debugger, + 2) drop through to start up again + (set another_trap to 1 to single step once) + 3) set random_signal to 1, and the decision between 1 and 2 + will be made according to the signal handling tables. */ + + if (WIFEXITED (w)) + { + terminal_ours_for_output (); + if (WRETCODE (w)) + printf ("\nProgram exited with code 0%o.\n", WRETCODE (w)); + else + printf ("\nProgram exited normally.\n"); + fflush (stdout); + inferior_died (); + stop_print_frame = 0; + break; + } + else if (!WIFSTOPPED (w)) + { + kill_inferior (); + stop_print_frame = 0; + stop_signal = WTERMSIG (w); + terminal_ours_for_output (); + printf ("\nProgram terminated with signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); + printf ("The inferior process no longer exists.\n"); + fflush (stdout); + break; + } + else + { + stop_signal = WSTOPSIG (w); + + /* First, distinguish signals caused by the debugger from signals + that have to do with the program's own actions. + Note that breakpoint insns may cause SIGTRAP or SIGILL + or SIGEMT, depending on the operating system version. + Here we detect when a SIGILL or SIGEMT is really a breakpoint + and change it to SIGTRAP. */ + + if (stop_signal == SIGTRAP + || (breakpoints_inserted && + (stop_signal == SIGILL + || stop_signal == SIGEMT)) + || stop_after_attach) + { + if (stop_signal == SIGTRAP && stop_after_trap) + { + stop_print_frame = 0; + break; + } + if (stop_after_attach) + break; + /* Don't even think about breakpoints + if still running the shell that will exec the program + or if just proceeded over a breakpoint. */ + if (stop_signal == SIGTRAP && trap_expected) + stop_breakpoint = 0; + else + /* See if there is a breakpoint at the current PC. */ +#if DECR_PC_AFTER_BREAK + /* Notice the case of stepping through a jump + that leads just after a breakpoint. + Don't confuse that with hitting the breakpoint. + What we check for is that 1) stepping is going on + and 2) the pc before the last insn does not match + the address of the breakpoint before the current pc. */ + if (!(prev_pc != stop_pc - DECR_PC_AFTER_BREAK + && step_range_end && !step_resume_break_address)) +#endif /* DECR_PC_AFTER_BREAK not zero */ + { + select_frame (stop_frame, 0); /* For condition exprs. */ + stop_breakpoint = breakpoint_stop_status (stop_pc, stop_frame); + /* Following in case break condition called a function. */ + stop_print_frame = 1; + if (stop_breakpoint && DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + pc_changed = 0; + } + } + /* See if we stopped at the special breakpoint for + stepping over a subroutine call. */ + if (stop_pc - DECR_PC_AFTER_BREAK == step_resume_break_address) + { + stop_step_resume_break = 1; + if (DECR_PC_AFTER_BREAK) + { + stop_pc -= DECR_PC_AFTER_BREAK; + write_register (PC_REGNUM, stop_pc); + pc_changed = 0; + } + } + + if (stop_signal == SIGTRAP) + random_signal + = !(stop_breakpoint || trap_expected + || stop_step_resume_break + || (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame) + || (step_range_end && !step_resume_break_address)); + else + { + random_signal + = !(stop_breakpoint || stop_step_resume_break); + if (!random_signal) + stop_signal = SIGTRAP; + } + } + else + random_signal = 1; + + /* For the program's own signals, act according to + the signal handling tables. */ + + if (random_signal + && !(running_in_shell && stop_signal == SIGSEGV)) + { + /* Signal not for debugging purposes. */ + int printed = 0; + + if (stop_signal >= NSIG + || signal_print[stop_signal]) + { + printed = 1; + terminal_ours_for_output (); + printf ("\nProgram received signal %d, %s\n", + stop_signal, + stop_signal < NSIG + ? sys_siglist[stop_signal] + : "(undocumented)"); + fflush (stdout); + } + if (stop_signal >= NSIG + || signal_stop[stop_signal]) + break; + /* If not going to stop, give terminal back + if we took it away. */ + else if (printed) + terminal_inferior (); + } + + /* Handle cases caused by hitting a breakpoint. */ + + if (!random_signal + && (stop_breakpoint || stop_step_resume_break)) + { + /* Does a breakpoint want us to stop? */ + if (stop_breakpoint && stop_breakpoint != -1) + { + /* 0x1000000 is set in stop_breakpoint as returned by + breakpoint_status_p to indicate a silent breakpoint. */ + if (stop_breakpoint > 0 && stop_breakpoint & 0x1000000) + { + stop_breakpoint &= ~0x1000000; + stop_print_frame = 0; + } + break; + } + /* But if we have hit the step-resumption breakpoint, + remove it. It has done its job getting us here. */ + if (stop_step_resume_break + && (step_frame == 0 || stop_frame == step_frame)) + { + remove_step_breakpoint (); + step_resume_break_address = 0; + } + /* Otherwise, must remove breakpoints and single-step + to get us past the one we hit. */ + else + { + remove_breakpoints (); + remove_step_breakpoint (); + breakpoints_inserted = 0; + another_trap = 1; + } + + /* We come here if we hit a breakpoint but should not + stop for it. Possibly we also were stepping + and should stop for that. So fall through and + test for stepping. But, if not stepping, + do not stop. */ + } + + /* If this is the breakpoint at the end of a stack dummy, + just stop silently. */ + if (stop_sp INNER_THAN stop_pc && stop_pc INNER_THAN stop_frame) + { + stop_print_frame = 0; + stop_stack_dummy = 1; + break; + } + + if (step_resume_break_address) + /* Having a step-resume breakpoint overrides anything + else having to do with stepping commands until + that breakpoint is reached. */ + ; + /* If stepping through a line, keep going if still within it. */ + else if (!random_signal + && step_range_end + && stop_pc >= step_range_start + && stop_pc < step_range_end) + { + /* Don't step through the return from a function + unless that is the first instruction stepped through. */ + if (ABOUT_TO_RETURN (stop_pc)) + { + stop_step = 1; + break; + } + } + + /* We stepped out of the stepping range. See if that was due + to a subroutine call that we should proceed to the end of. */ + else if (!random_signal && step_range_end) + { + newfun = find_pc_function (stop_pc); + if (newfun) + { + newfun_pc = BLOCK_START (SYMBOL_BLOCK_VALUE (newfun)) + + FUNCTION_START_OFFSET; + } + else + { + newmisc = find_pc_misc_function (stop_pc); + if (newmisc >= 0) + newfun_pc = misc_function_vector[newmisc].address + + FUNCTION_START_OFFSET; + else newfun_pc = 0; + } + if (stop_pc == newfun_pc + && (step_over_calls > 0 || (step_over_calls && newfun == 0))) + { + /* A subroutine call has happened. */ + /* Set a special breakpoint after the return */ + step_resume_break_address = SAVED_PC_AFTER_CALL (stop_frame); + step_resume_break_duplicate + = breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + } + /* Subroutine call with source code we should not step over. + Do step to the first line of code in it. */ + else if (stop_pc == newfun_pc && step_over_calls) + { + SKIP_PROLOGUE (newfun_pc); + sal = find_pc_line (newfun_pc, 0); + /* Use the step_resume_break to step until + the end of the prologue, even if that involves jumps + (as it seems to on the vax under 4.2). */ + /* If the prologue ends in the middle of a source line, + continue to the end of that source line. + Otherwise, just go to end of prologue. */ + if (sal.end && sal.pc != newfun_pc) + step_resume_break_address = sal.end; + else + step_resume_break_address = newfun_pc; + + step_resume_break_duplicate + = breakpoint_here_p (step_resume_break_address); + if (breakpoints_inserted) + insert_step_breakpoint (); + /* Do not specify what the fp should be when we stop + since on some machines the prologue + is where the new fp value is established. */ + step_frame = 0; + /* And make sure stepping stops right away then. */ + step_range_end = step_range_start; + } + /* No subroutince call; stop now. */ + else + { + stop_step = 1; + break; + } + } + } + + /* If we did not do break;, it means we should keep + running the inferior and not return to debugger. */ + + /* If trap_expected is 2, it means continue once more + and insert breakpoints at the next trap. + If trap_expected is 1 and the signal was SIGSEGV, it means + the shell is doing some memory allocation--just resume it + with SIGSEGV. + Otherwise insert breakpoints now, and possibly single step. */ + + if (trap_expected > 1) + { + trap_expected--; + running_in_shell = 1; + resume (0, 0); + } + else if (running_in_shell && stop_signal == SIGSEGV) + { + resume (0, SIGSEGV); + } + else + { + /* Here, we are not awaiting another exec to get + the program we really want to debug. + Insert breakpoints now, unless we are trying + to one-proceed past a breakpoint. */ + running_in_shell = 0; + if (!breakpoints_inserted && !another_trap) + { + insert_step_breakpoint (); + breakpoints_failed = insert_breakpoints (); + if (breakpoints_failed) + break; + breakpoints_inserted = 1; + } + + trap_expected = another_trap; + + if (stop_signal == SIGTRAP) + stop_signal = 0; + + resume ((step_range_end && !step_resume_break_address) + || trap_expected, + stop_signal); + } + } +} + +/* Here to return control to GDB when the inferior stops for real. + Print appropriate messages, remove breakpoints, give terminal our modes. + + RUNNING_IN_SHELL nonzero means the shell got a signal before + exec'ing the program we wanted to run. + STOP_PRINT_FRAME nonzero means print the executing frame + (pc, function, args, file, line number and line text). + BREAKPOINTS_FAILED nonzero means stop was due to error + attempting to insert breakpoints. */ + +static void +normal_stop () +{ + if (breakpoints_failed) + { + terminal_ours_for_output (); + print_sys_errmsg ("ptrace", breakpoints_failed); + printf ("Stopped; cannot insert breakpoints.\n\ +The same program may be running in another process.\n"); + } + + if (inferior_pid) + remove_step_breakpoint (); + + if (inferior_pid && breakpoints_inserted) + if (remove_breakpoints ()) + { + terminal_ours_for_output (); + printf ("Cannot remove breakpoints because program is no longer writable.\n\ +It must be running in another process.\n\ +Further execution is probably impossible.\n"); + } + + breakpoints_inserted = 0; + + /* Delete the breakpoint we stopped at, if it wants to be deleted. + Delete any breakpoint that is to be deleted at the next stop. */ + + breakpoint_auto_delete (stop_breakpoint); + + if (step_multi && stop_step) + return; + + terminal_ours (); + + if (running_in_shell) + { + if (stop_signal == SIGSEGV) + printf ("\ +You have just encountered a bug in \"sh\". GDB starts your program\n\ +by running \"sh\" with a command to exec your program.\n\ +This is so that \"sh\" will process wildcards and I/O redirection.\n\ +This time, \"sh\" crashed.\n\ +\n\ +One known bug in \"sh\" bites when the environment takes up a lot of space.\n\ +Try \"info env\" to see the environment; then use \"unset-env\" to kill\n\ +some variables whose values are large; then do \"run\" again.\n\ +\n\ +If that works, you might want to put those \"unset-env\" commands\n\ +into a \".gdbinit\" file in this directory so they will happen every time.\n"); + /* Don't confuse user with his program's symbols on sh's data. */ + stop_print_frame = 0; + } + + if (inferior_pid == 0) + return; + + /* Select innermost stack frame except on return from a stack dummy routine, + or if the program has exited. */ + if (!stop_stack_dummy) + { + select_frame (stop_frame, 0); + + if (stop_print_frame) + { + if (stop_breakpoint > 0) + printf ("\nBpt %d, ", stop_breakpoint); + print_sel_frame (stop_step + && step_frame == stop_frame + && step_start_function == find_pc_function (stop_pc)); + /* Display the auto-display expressions. */ + do_displays (); + } + } + + /* Save the function value return registers + We might be about to restore their previous contents. */ + read_register_bytes (0, stop_registers, REGISTER_BYTES); + + if (stop_stack_dummy) + { + /* Pop the empty frame that contains the stack dummy. */ + POP_FRAME; + select_frame (read_register (FP_REGNUM), 0); + } +} + +static void +insert_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + { + read_memory (step_resume_break_address, + step_resume_break_shadow, sizeof break_insn); + write_memory (step_resume_break_address, + break_insn, sizeof break_insn); + } +} + +static void +remove_step_breakpoint () +{ + if (step_resume_break_address && !step_resume_break_duplicate) + write_memory (step_resume_break_address, step_resume_break_shadow, + sizeof break_insn); +} + +/* Specify how various signals in the inferior should be handled. */ + +static void +handle_command (args, from_tty) + char *args; + int from_tty; +{ + register char *p = args; + int signum; + register int digits, wordlen; + + if (!args) + error_no_arg ("signal to handle"); + + while (*p) + { + /* Find the end of the next word in the args. */ + for (wordlen = 0; p[wordlen] && p[wordlen] != ' ' && p[wordlen] != '\t'; + wordlen++); + for (digits = 0; p[digits] >= '0' && p[digits] <= '9'; digits++); + + /* If it is all digits, it is signal number to operate on. */ + if (digits == wordlen) + { + signum = atoi (p); + if (signum == SIGTRAP || signum == SIGINT) + { + if (!query ("Signal %d is used by the debugger.\nAre you sure you want to change it? ", signum)) + error ("Not confirmed."); + } + } + else if (signum == 0) + error ("First argument is not a signal number."); + + /* Else, if already got a signal number, look for flag words + saying what to do for it. */ + else if (!strncmp (p, "stop", wordlen)) + { + signal_stop[signum] = 1; + signal_print[signum] = 1; + } + else if (wordlen >= 2 && !strncmp (p, "print", wordlen)) + signal_print[signum] = 1; + else if (wordlen >= 2 && !strncmp (p, "pass", wordlen)) + signal_program[signum] = 1; + else if (!strncmp (p, "ignore", wordlen)) + signal_program[signum] = 0; + else if (wordlen >= 3 && !strncmp (p, "nostop", wordlen)) + signal_stop[signum] = 0; + else if (wordlen >= 4 && !strncmp (p, "noprint", wordlen)) + { + signal_print[signum] = 0; + signal_stop[signum] = 0; + } + else if (wordlen >= 4 && !strncmp (p, "nopass", wordlen)) + signal_program[signum] = 0; + else if (wordlen >= 3 && !strncmp (p, "noignore", wordlen)) + signal_program[signum] = 1; + /* Not a number and not a recognized flag word => complain. */ + else + { + p[wordlen] = 0; + error ("Unrecognized flag word: \"%s\".", p); + } + + /* Find start of next word. */ + p += wordlen; + while (*p == ' ' || *p == '\t') p++; + } + + if (from_tty) + { + /* Show the results. */ + printf ("Number\tStop\tPrint\tPass to program\tDescription\n"); + printf ("%d\t", signum); + printf ("%s\t", signal_stop[signum] ? "Yes" : "No"); + printf ("%s\t", signal_print[signum] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[signum] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[signum]); + } +} + +/* Print current contents of the tables set by the handle command. */ + +static void +signals_info (signum_exp) + char *signum_exp; +{ + register int i; + printf ("Number\tStop\tPrint\tPass to program\tDescription\n"); + + if (signum_exp) + { + i = parse_and_eval_address (signum_exp); + printf ("%d\t", i); + printf ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf ("%s\t", signal_print[i] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[i]); + return; + } + + printf ("\n"); + for (i = 0; i < NSIG; i++) + { + QUIT; + if (i > 0 && i % 16 == 0) + { + printf ("[Type Return to see more]"); + fflush (stdout); + read_line (); + } + printf ("%d\t", i); + printf ("%s\t", signal_stop[i] ? "Yes" : "No"); + printf ("%s\t", signal_print[i] ? "Yes" : "No"); + printf ("%s\t\t", signal_program[i] ? "Yes" : "No"); + printf ("%s\n", sys_siglist[i]); + } + + printf ("\nUse the \"handle\" command to change these tables.\n"); +} + +static +initialize () +{ + register int i; + + add_info ("signals", signals_info, + "What debugger does when program gets various signals.\n\ +Specify a signal number as argument to print info on that signal only."); + + add_com ("handle", class_run, handle_command, + "Specify how to handle a signal.\n\ +Args are signal number followed by flags.\n\ +Flags allowed are \"stop\", \"print\", \"pass\",\n\ + \"nostop\", \"noprint\" or \"nopass\".\n\ +Print means print a message if this signal happens.\n\ +Stop means reenter debugger if this signal happens (implies print).\n\ +Pass means let program see this signal; otherwise program doesn't know.\n\ +Pass and Stop may be combined."); + + for (i = 0; i < NSIG; i++) + { + signal_stop[i] = 1; + signal_print[i] = 1; + signal_program[i] = 1; + } + + /* Signals caused by debugger's own actions + should not be given to the program afterwards. */ + signal_program[SIGTRAP] = 0; + signal_program[SIGINT] = 0; + + /* Signals that are not errors should not normally enter the debugger. */ +#ifdef SIGALRM + signal_stop[SIGALRM] = 0; + signal_print[SIGALRM] = 0; +#endif /* SIGALRM */ +#ifdef SIGVTALRM + signal_stop[SIGVTALRM] = 0; + signal_print[SIGVTALRM] = 0; +#endif /* SIGVTALRM */ +#ifdef SIGPROF + signal_stop[SIGPROF] = 0; + signal_print[SIGPROF] = 0; +#endif /* SIGPROF */ +#ifdef SIGCHLD + signal_stop[SIGCHLD] = 0; + signal_print[SIGCHLD] = 0; +#endif /* SIGCHLD */ +#ifdef SIGCLD + signal_stop[SIGCLD] = 0; + signal_print[SIGCLD] = 0; +#endif /* SIGCLD */ +#ifdef SIGIO + signal_stop[SIGIO] = 0; + signal_print[SIGIO] = 0; +#endif /* SIGIO */ +#ifdef SIGURG + signal_stop[SIGURG] = 0; + signal_print[SIGURG] = 0; +#endif /* SIGURG */ +} + +END_FILE diff --git a/gdb/initialize.h b/gdb/initialize.h new file mode 100644 index 00000000000..e727c8039de --- /dev/null +++ b/gdb/initialize.h @@ -0,0 +1,126 @@ +/* Macros to enable automatic execution of an initialization function + in each object file without having to include a list of all object files + anywhere in the source code. This goes with firstfile.c and lastfile.c. + + Copyright (C) 1986 Free Software Foundation, Inc. + + NO WARRANTY + + BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY +NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" +WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY +AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY +WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE +LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR +OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR +DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR +A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS +PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. + + GENERAL PUBLIC LICENSE TO COPY + + 1. You may copy and distribute verbatim copies of this source file +as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy a valid copyright notice "Copyright +(C) 1986 Free Software Foundation, Inc."; and include following the +copyright notice a verbatim copy of the above disclaimer of warranty +and of this License. You may charge a distribution fee for the +physical act of transferring a copy. + + 2. You may modify your copy or copies of this source file or +any portion of it, and copy and distribute such modifications under +the terms of Paragraph 1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating + that you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, + that in whole or in part contains or is a derivative of this + program or any part thereof, to be licensed at no charge to all + third parties on terms identical to those contained in this + License Agreement (except that you may choose to grant more + extensive warranty protection to third parties, at your option). + + c) You may charge a distribution fee for the physical act of + transferring a copy, and you may at your option offer warranty + protection in exchange for a fee. + + 3. You may copy and distribute this program or any portion of it in +compiled, executable or object code form under the terms of Paragraphs +1 and 2 above provided that you do the following: + + a) cause each such copy to be accompanied by the + corresponding machine-readable source code, which must + be distributed under the terms of Paragraphs 1 and 2 above; or, + + b) cause each such copy to be accompanied by a + written offer, with no time limit, to give any third party + free (except for a nominal shipping charge) a machine readable + copy of the corresponding source code, to be distributed + under the terms of Paragraphs 1 and 2 above; or, + + c) in the case of a recipient of this program in compiled, executable + or object code form (without the corresponding source code) you + shall cause copies you distribute to be accompanied by a copy + of the written offer of source code which you received along + with the copy you received. + + 4. You may not copy, sublicense, distribute or transfer this program +except as expressly provided under this License Agreement. Any attempt +otherwise to copy, sublicense, distribute or transfer this program is void and +your rights to use the program under this License agreement shall be +automatically terminated. However, parties who have received computer +software programs from you with this License Agreement will not have +their licenses terminated so long as such parties remain in full compliance. + + 5. If you wish to incorporate parts of this program into other free +programs whose distribution conditions are different, write to the Free +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet +worked out a simple rule that can be stated here, but we will often permit +this. We will be guided by the two goals of preserving the free status of +all derivatives of our free software and of promoting the sharing and reuse of +software. + + +In other words, you are welcome to use, share and improve this program. +You are forbidden to forbid anyone else to use, share and improve +what you give them. Help stamp out software-hoarding! */ + + +/* Here a machine-specific header file must be included to define + the macro FILEADDR_ROUND which we use to round up from the address + of the end of one object file's text to the start of the next + object file's text. */ + +#include "m-suninit.h" + +/* This is used to make a file's initialization function. + It calls another function named `initialize', which must + appear later in the file. */ + +#define START_FILE \ + static initialize (), initialize_next_file (); \ + static initialize_1 (offset) \ + { initialize (); initialize_next_file (offset); } + +/* The argument OFFSET is the size of this function. + By adding it to the address of this function, + we find the next function, which is the next file's + initialization function. */ + +#define END_FILE \ + static initialize_next_file (offset) \ + int offset; \ + { long addr = FILEADDR_ROUND ((int) initialize_next_file + offset); \ + (*(void (*) ()) addr) (offset); } diff --git a/gdb/kdb-start.c b/gdb/kdb-start.c new file mode 100644 index 00000000000..bdbc2726831 --- /dev/null +++ b/gdb/kdb-start.c @@ -0,0 +1,21 @@ +#include "defs.h" +#include "param.h" + +static char *args[] = {"kdb", "kdb-symbols", 0}; + +static char *environment[] = {0}; + +char **environ; + +start () +{ +#ifdef NAMES_HAVE_UNDERSCORE + INIT_STACK (_kdb_stack_beg, _kdb_stack_end); +#else /* not NAMES_HAVE_UNDERSCORE */ + INIT_STACK (kdb_stack_beg, kdb_stack_end); +#endif /* not NAMES_HAVE_UNDERSCORE */ + + environ = environment; + + main (2, args, environment); +} diff --git a/gdb/lastfile.c b/gdb/lastfile.c new file mode 100644 index 00000000000..2ac8cb740ff --- /dev/null +++ b/gdb/lastfile.c @@ -0,0 +1,6 @@ +/* This ends the chain of files for the purpose of initialization, + because it does not attempt to find the start of the following file. */ + +initialize_last_file () +{ +} diff --git a/gdb/m-isi-ov.h b/gdb/m-isi-ov.h new file mode 100644 index 00000000000..46c181631d5 --- /dev/null +++ b/gdb/m-isi-ov.h @@ -0,0 +1,524 @@ +/* +Date: Thu, 2 Apr 87 00:02:42 EST +From: crl@maxwell.physics.purdue.edu (Charles R. LaBrec) +Message-Id: <8704020502.AA01744@maxwell.physics.purdue.edu> +To: bug-gdb@prep.ai.mit.edu +Subject: gdb for ISI Optimum V + +Here is an m-isi-ov.h file for gdb version 2.1. It supports the 68881 +registers, and tracks down the function prologue (since the ISI cc +puts it at the end of the function and branches to it if not +optimizing). Also included are diffs to core.c, findvar.c, and +inflow.c, since the original code assumed that registers are an int in +the user struct, which isn't the case for 68020's with 68881's (and +not using the NEW_SUN_PTRACE). I have not fixed the bugs associated +with the other direction (writing registers back to the user struct). +I have also included a diff that turns m68k-pinsn.c into isi-pinsn.c, +which is needed since the 3.05 release of as does not understand +floating point ops, and it compiles incorrectly under "cc -20" + +I have used gdb for a while now, and it seems to work relatively well, +but I do not guarantee that it is perfect. The more that use it, the +faster the bugs will get shaken out. One bug I know of is not in gdb, +but in the assembler. It seems to screw up the .stabs of variables. +For externs, this is not important since gdb uses the global symbol +value, but for statics, this makes gdb unable to find them. I am +currently trying to track it down. + +As an aside, I notice that only global functions are used as symbols +to print as relative addresses, i.e. "", and not +static functions, which end up printing as large offsets from the last +global one. Would there be a problem if static functions were also +recorded as misc functions in read_dbx_symtab? + +Charles LaBrec +crl @ maxwell.physics.purdue.edu + + Definitions to make GDB run on a ISI Optimum V (3.05) under 4.2bsd. + + Copyright (C) 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + + +/* Identify this machine */ +#ifndef ISI68K +#define ISI68K +#endif + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ + else if (op == 0060000) \ + pc += 4; /* Skip bra #word */ \ + else if (op == 00600377) \ + pc += 6; /* skip bra #long */ \ + else if ((op & 0177400) == 0060000) \ + pc += 2; /* skip bra #char */ \ +} + + +/* 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* 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 0x10800000 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x10000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* Data segment starts at etext rounded up to DATAROUND in {N,Z}MAGIC files */ + +#define DATAROUND 0x20000 +#define N_DATADDR(hdr) (hdr.a_magic != OMAGIC ? \ + (hdr.a_text + DATAROUND) & ~(DATAROUND-1) : hdr.a_text) + +/* Text segment starts at sizeof (struct exec) in {N,Z}MAGIC files */ + +#define N_TXTADDR(hdr) (hdr.a_magic != OMAGIC ? sizeof (struct exec) : 0) + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + On the ISI, the kernel resets the pc to the trap instr */ + +#define DECR_PC_AFTER_BREAK 0 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 29 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr" } + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ if (regno < 2) addr = blockend - 0x18 + regno * 4; \ + else if (regno < 8) addr = blockend - 0x54 + regno * 4; \ + else if (regno < 10) addr = blockend - 0x30 + regno * 4;\ + else if (regno < 15) addr = blockend - 0x5c + regno * 4;\ + else if (regno < 16) addr = blockend - 0x1c; \ + else if (regno < 18) addr = blockend - 0x44 + regno * 4;\ + else if (regno < 26) addr = (int) ((struct user *)0)->u_68881_regs \ + + (regno - 18) * 12; \ + else if (regno < 29) addr = (int) ((struct user *)0)->u_68881_regs \ + + 8 * 12 + (regno - 26) * 4; \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* 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, 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 (0, 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)) + +/* 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 ISI, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#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(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + register int insn; \ + register int offset; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next, \ + or a branch followed by a link a6 instruction; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ +retry: \ + insn = read_memory_integer (pc, 2); \ + if (insn == 044016) \ + next_addr = (frame_info).frame - read_memory_integer (pc += 2, 4), pc+=4; \ + else if (insn == 047126) \ + next_addr = (frame_info).frame - read_memory_integer (pc += 2, 2), pc+=2; \ + else if ((insn & 0177400) == 060000) /* bra insn */ \ + { offset = insn & 0377; \ + pc += 2; /* advance past bra */ \ + if (offset == 0) /* bra #word */ \ + offset = read_memory_integer (pc, 2), pc += 2; \ + else if (offset == 0377) /* bra #long */ \ + offset = read_memory_integer (pc, 4), pc += 4; \ + pc += offset; \ + goto retry; \ + } else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + insn = read_memory_integer (pc, 2), pc += 2; \ + regmask = read_memory_integer (pc, 2); \ + if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \ + else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \ + else if (insn == 0044327) /* moveml mask, (sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 0, the first written */ \ + next_addr -= 4; \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4); \ + } else if (insn == 0044347) /* moveml mask, -(sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (read_memory_integer (pc, 2) == 041147 \ + && read_memory_integer (pc+2, 2) == 042347) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ +} + +/* This sequence of words is the instructions + fmovem #,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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 ("movel fp, -(sp)"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* 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 \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/m-mac-aux.h b/gdb/m-mac-aux.h new file mode 100644 index 00000000000..2f1f84d3430 --- /dev/null +++ b/gdb/m-mac-aux.h @@ -0,0 +1,485 @@ +/* Parameters for execution on Macintosh under A/UX, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef mac_aux +#define mac_aux +#endif + +/* Get rid of any system-imposed stack limit if possible. */ + +#undef 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 + +/* COFF format object files */ + +#define COFF_FORMAT + +/* System eVil ttys */ + +#define SYSV_TTYS + +/* Debugger information will not be in DBX format. */ + +#undef READ_DBX_FORMAT + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x20000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 31 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags" } + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* 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, 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 (0, 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)) + +/* Enable use of alternate code to read and write registers. */ + +#undef NEW_SUN_PTRACE + +/* Enable use of alternate code for Sun's format of core dump file. */ + +#undef NEW_SUN_CORE + +/* Do implement the attach and detach commands. */ + +#undef ATTACH_DETACH + +/* It is safe to look for symsegs on a Sun, because Sun's ld + does not screw up with random garbage at end of file. */ + +#define READ_GDB_SYMSEGS + +/* 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 Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) (fi.frame) + +#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + int nextinsn; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + /* But before that can come an fmovem. Check for it. */ \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf227 == nextinsn \ + && (regmask & 0xff00) == 0xe000) \ + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 12); \ + regmask = read_memory_integer (pc + 2, 2); } \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* fmovemx to index of sp may follow. */ \ + regmask = read_memory_integer (pc + 2, 2); \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf236 == nextinsn \ + && (regmask & 0xff00) == 0xf000) \ + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \ + regmask = read_memory_integer (pc + 2, 2); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + set_current_frame (read_register (FP_REGNUM)); } + +/* This sequence of words is the instructions + fmovem 0xff,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 28 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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 ("movel #end, sp"); \ + asm ("movel #0,a6"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel a6,sp@-"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl sp@,a6"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea sp@(10)"); \ + asm ("movem #0xfffe,sp@-"); } + +/* 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 \ +{ asm ("subil #8,sp@(28)"); \ + asm ("movem sp@,#0xffff"); \ + asm ("rte"); } diff --git a/gdb/m-mac-auxinit.h b/gdb/m-mac-auxinit.h new file mode 100644 index 00000000000..bd420ef2fa0 --- /dev/null +++ b/gdb/m-mac-auxinit.h @@ -0,0 +1,5 @@ + +/* This is how the size of an individual .o file's text segment + is rounded on a mac under a/ux. */ + +#define FILEADDR_ROUND(addr) (addr) diff --git a/gdb/m-merlin.h b/gdb/m-merlin.h new file mode 100644 index 00000000000..7f87979e4af --- /dev/null +++ b/gdb/m-merlin.h @@ -0,0 +1,437 @@ +/* Definitions to make GDB run on a merlin under utek 2.1 + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef ns16000 +#define ns16000 +#endif + +# include + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* 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, 1); \ + if (op == 0x82) \ + { op = read_memory_integer (pc+2,1); \ + if ((op & 0x80) == 0) pc += 3; \ + else if ((op & 0xc0) == 0x80) pc += 4; \ + else pc += 6; \ + }} + +/* 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) \ + read_memory_integer (read_register (SP_REGNUM), 4) + +/* 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 (0xfef000) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x800000) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xf2} + +/* 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. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0x12) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 + +/* Define this to say that the "svc" insn is followed by + codes in memory saying which kind of system call it is. */ + +#define NS32K_SVC_IMMED_OPERANDS + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 25 + +#define NUM_GENERAL_REGS 8 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pc", "sp", "fp", "ps", \ + "fsr", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "l0", "l1", "l2", "l3", "l4", \ + } + +/* 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. */ + +#define AP_REGNUM FP_REGNUM +#define FP_REGNUM 10 /* Contains address of executing stack frame */ +#define SP_REGNUM 9 /* Contains address of top of stack */ +#define PC_REGNUM 8 /* Contains program counter */ +#define PS_REGNUM 11 /* Contains processor status */ +#define FPS_REGNUM 12 /* Floating point status register */ +#define FP0_REGNUM 13 /* Floating point register 0 */ +#define LP0_REGNUM 21 /* Double register 0 (same as FP0) */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ \ + switch (regno) { \ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: \ + addr = blockend + (R0 - regno) * sizeof (int); break; \ + case PC_REGNUM: \ + addr = blockend + PC * sizeof (int); break; \ + case SP_REGNUM: \ + addr = blockend + SP * sizeof (int); break; \ + case FP_REGNUM: \ + addr = blockend + FP * sizeof (int); break; \ + case PS_REGNUM: \ + addr = blockend + 12 * sizeof (int); break; \ + case FPS_REGNUM: \ + addr = 108; break; \ + case FP0_REGNUM + 0: case FP0_REGNUM + 1: \ + case FP0_REGNUM + 2: case FP0_REGNUM + 3: \ + case FP0_REGNUM + 4: case FP0_REGNUM + 5: \ + case FP0_REGNUM + 6: case FP0_REGNUM + 7: \ + addr = 76 + (regno - FP0_REGNUM) * sizeof (float); break; \ + case LP0_REGNUM + 0: case LP0_REGNUM + 1: \ + case LP0_REGNUM + 2: case LP0_REGNUM + 3: \ + addr = 76 + (regno - LP0_REGNUM) * sizeof (double); break; \ + default: \ + printf ("bad argument to REGISTER_U_ADDR %d\n", regno); \ + abort (); \ + } \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES ((NUM_REGS - 4) * sizeof (int) + 4 * sizeof (double)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) >= LP0_REGNUM ? \ + LP0_REGNUM * 4 + ((N) - LP0_REGNUM) * 8 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_RAW_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_VIRTUAL_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 8 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* 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_VIRTUAL_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_VIRTUAL_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 ? \ + ((N) >= LP0_REGNUM ? \ + builtin_type_double \ + : builtin_type_float) \ + : builtin_type_int) + +/* 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, 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 (0, 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)) + +/* 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 Merlin, the frame's nominal address is the FP value, + and at that address is saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +/* compute base of arguments */ +#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) \ +{ CORE_ADDR pc; \ + int insn; \ + int addr_mode; \ + int width; \ + \ + pc = FRAME_SAVED_PC (fi.frame); \ + insn = read_memory_integer (pc,2); \ + addr_mode = (insn >> 11) & 0x1f; \ + insn = insn & 0x7ff; \ + if ((insn & 0x7fc) == 0x57c \ + && addr_mode == 0x14) /* immediate */ \ + { if (insn == 0x57c) /* adjspb */ \ + width = 1; \ + else if (insn == 0x57d) /* adjspw */ \ + width = 2; \ + else if (insn == 0x57f) /* adjspd */ \ + width = 4; \ + numargs = read_memory_integer (pc+2,width); \ + if (width > 1) \ + flip_bytes (&numargs, width); \ + numargs = - sign_extend (numargs, width*8) / 4; } \ + else numargs = -1; \ +} + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ int regmask,regnum; \ + int localcount; \ + CORE_ADDR enter_addr; \ + CORE_ADDR next_addr; \ + \ + enter_addr = get_pc_function_start ((frame_info).pc); \ + regmask = read_memory_integer (enter_addr+1, 1); \ + localcount = ns32k_localcount (enter_addr); \ + next_addr = (frame_info).frame + localcount; \ + for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] \ + = (regmask & 1) ? (next_addr -= 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ + (frame_saved_regs).regs[FP_REGNUM] \ + = read_memory_integer ((frame_info).frame, 4); } + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = 0; regnum < 8; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (SP_REGNUM, sp); \ +} + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = 0; regnum < 8; regnum++) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ +} + +/* This sequence of words is the instructions + enter 0xff,0 82 ff 00 + jsr @0x00010203 7f ae c0 01 02 03 + adjspd 0x69696969 7f a5 01 02 03 04 + bpt f2 + Note this is 16 bytes. */ + +#define CALL_DUMMY { 0x7f00ff82, 0x0201c0ae, 0x01a57f03, 0xf2040302 } + +#define CALL_DUMMY_START_OFFSET 3 +#define CALL_DUMMY_LENGTH 16 +#define CALL_DUMMY_ADDR 5 +#define CALL_DUMMY_NARGS 11 + +/* 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, fun, nargs) \ +{ int flipped = fun | 0xc0000000; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ + flipped = - nargs * 4; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_NARGS)) = flipped; \ +} + +#ifdef notdef +/* 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 \ +{ asm ("pushl 8(sp)"); \ + asm ("pushl 8(sp)"); \ + asm ("pushal 0x14(sp)"); \ + asm ("pushr $037777"); } + +/* 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 \ +{ asm ("popr $037777"); \ + asm ("subl2 $8,(sp)"); \ + asm ("movl (sp),sp"); \ + asm ("rei"); } +#endif diff --git a/gdb/m-news800.h b/gdb/m-news800.h new file mode 100644 index 00000000000..44583e3294b --- /dev/null +++ b/gdb/m-news800.h @@ -0,0 +1,566 @@ +/* Parameters for execution on a Sony/NEWS, for GDB, the GNU debugger. + +Here is an m-news800.h file for gdb version 2.1. It supports the 68881 +registers. + +Now(9/2 '87) NEWS's printf has a bug. +And support Sun assembly format instead of Motorola one. +Probably not well support floating registers from core file rarely that +I do not know detail. +(hikichi@srava.sra.junet or hikichi%srava.sra.junet%kddlabs%seismo.CSS.GOV) + +Here is IEEE nan routine to use such bug fixed. + + printf("%g\n", Nan); + +> struct ieee { |* IEEE floating format *| +> unsigned int s:1; +> unsigned int e:11; +> unsigned int f1:20; +> unsigned int f2; +> }; +> +> #define ZERO_F(x) ((x.f1 == 0) && (x.f2 == 0)) |* zero fraction ? *| +> #define ZERO_E(x) (x.e == 0) |* zero exponential ? *| +> #define MAX_E(x) (x.e == 0x7ff) |* max exponential ? *| +> #define MINUS_S(x) (x.s == 1) |* minus ? *| +> +> int +> is_nan(arg) |* Not a Number ? *| +> struct ieee arg; +> { +> if (MAX_E(arg) && !ZERO_F(arg)) +> return (1); +> else +> return (0); +> } +> +> int +> is_plus_infinity(arg) +> struct ieee arg; +> { +> if (!MINUS_S(arg) && MAX_E(arg) && ZERO_F(arg)) +> return (1); +> else +> return (0); +> } +> +> int +> is_minus_infinity(arg) +> struct ieee arg; +> { +> if (MINUS_S(arg) && MAX_E(arg) && ZERO_F(arg)) +> return (1); +> else +> return (0); +> } +> +> int +> is_denormal(arg) +> struct ieee arg; +> { +> if (ZERO_E(arg)) +> return (1); +> else +> return (0); +> } + + Copyright (C) 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifdef 0 /* cannot use RCS id since initialize routine fails. */ +static char *RCSid = +"$Header: m-news800.h,v 1.1 87/09/21 21:27:52 hikichi Exp $"; +#endif lint + +/* + * $Log: m-news800.h,v $ + * Revision 1.1 87/09/21 21:27:52 hikichi + * Initial revision + * + */ + +/* Identify this machine */ +#ifndef news800 +#define news800 +#endif + +/* #define USE_GAS */ + +/* Motorola assembly format */ +#ifndef USE_GAS +#define MOTOROLA +#endif + +/* bug when printf special number; NAN */ +#define PRINTF_BUG + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + + +/* 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* 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 UADDR + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0x80000000 - ctob(UPAGES + 1)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p) 0 /* Just a first guess; not checked */ + +/* Say how long registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 29 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "pc", "ps", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr" } + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PC_REGNUM 16 /* Contains program counter */ +#define PS_REGNUM 17 /* Contains processor status */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ if (regno <= FP_REGNUM) \ + addr = blockend + 4 + regno * 4; \ + else if (regno == SP_REGNUM) \ + addr = blockend - 4 * 4; \ + else if (regno <= PS_REGNUM) \ + addr = blockend + (regno - PS_REGNUM) * 4; \ + else if (regno < FPC_REGNUM) \ + addr = blockend + 4 + 4 * 14 + 4 * 5 + (regno - FP0_REGNUM) * 12; \ + else \ + addr = blockend + 4 + 4 * 16 + (regno - FPC_REGNUM) * 4; \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+12) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* 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 NEWS, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#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(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + register int insn; \ + register int offset; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next, \ + or a branch followed by a link a6 instruction; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ +retry: \ + insn = read_memory_integer (pc, 2); \ + if (insn == 044016) \ + next_addr = (frame_info).frame - read_memory_integer (pc += 2, 4), pc+=4; \ + else if (insn == 047126) \ + next_addr = (frame_info).frame - read_memory_integer (pc += 2, 2), pc+=2; \ + else if ((insn & 0177400) == 060000) /* bra insn */ \ + { offset = insn & 0377; \ + pc += 2; /* advance past bra */ \ + if (offset == 0) /* bra #word */ \ + offset = read_memory_integer (pc, 2), pc += 2; \ + else if (offset == 0377) /* bra #long */ \ + offset = read_memory_integer (pc, 4), pc += 4; \ + pc += offset; \ + goto retry; \ + } else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + insn = read_memory_integer (pc, 2), pc += 2; \ + regmask = read_memory_integer (pc, 2); \ + if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \ + else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \ + (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \ + else if (insn == 0044327) /* moveml mask, (sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 0, the first written */ \ + next_addr -= 4; \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4); \ + } else if (insn == 0044347) /* moveml mask, -(sp) */ \ + { pc += 2; \ + /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (read_memory_integer (pc, 2) == 041147 \ + && read_memory_integer (pc+2, 2) == 042347) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ +} + +/* This sequence of words is the instructions + fmove.m #,-(sp) + movem.l 0xfffc,-(sp) + clr.w -(sp) + move.w ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jbsr (#32323232) + add.l #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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. */ + +#ifdef MOTOROLA +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("move.l $ end, sp"); \ + asm ("clr.l fp"); } +#else +#define INIT_STACK(beg, end) \ +{ asm (".globl end"); \ + asm ("movel $ end, sp"); \ + asm ("clrl fp"); } +#endif + +/* Push the frame pointer register on the stack. */ +#ifdef MOTOROLA +#define PUSH_FRAME_PTR \ + asm ("move.l fp, -(sp)"); +#else +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); +#endif + +/* Copy the top-of-stack to the frame pointer register. */ +#ifdef MOTOROLA +#define POP_FRAME_PTR \ + asm ("move.l (sp), fp"); +#else +#define POP_FRAME_PTR \ + asm ("movl (sp), fp"); +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define PUSH_REGISTERS \ +{ asm ("clr.w -(sp)"); \ + asm ("pea (10,sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#else +#define PUSH_REGISTERS \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } +#endif + +/* 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. */ + +#ifdef MOTOROLA +#define POP_REGISTERS \ +{ asm ("subi.l $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#else +#define POP_REGISTERS \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } +#endif + diff --git a/gdb/m-newsinit.h b/gdb/m-newsinit.h new file mode 100644 index 00000000000..d902edfeadb --- /dev/null +++ b/gdb/m-newsinit.h @@ -0,0 +1,4 @@ +/* This is how the size of an individual .o file's text segment + is rounded on a SONY NEWS. */ + +#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m-sun2.h b/gdb/m-sun2.h new file mode 100644 index 00000000000..833c9233807 --- /dev/null +++ b/gdb/m-sun2.h @@ -0,0 +1,421 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef sun2 +#define sun2 +#endif + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* 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 0x2800 + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0x1000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 18 + +/* Number that are really general registers */ + +#define NUM_GENERAL_REGS 16 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"} + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8) + +/* 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. On the 68000, all regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) 4 + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes. */ + +#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), 4); + +/* 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), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +/* 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, 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 (0, 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)) + +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = blockend + regno * 4; } + +/* 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 Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) (fi.frame) + +#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM);\ + register int regnum; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ +} + +/* This sequence of words is the instructions + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 24 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 24 + +#define CALL_DUMMY_START_OFFSET 8 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 16) = nargs * 4; \ + *(int *)((char *) dummyname + 10) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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 ("movel $ end, sp"); \ + asm ("clrl fp"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel fp, -(sp)"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea 10(sp)"); \ + asm ("movem $ 0xfffe,-(sp)"); } + +/* 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 \ +{ asm ("subil $8,28(sp)"); \ + asm ("movem (sp),$ 0xffff"); \ + asm ("rte"); } diff --git a/gdb/m-sun3.h b/gdb/m-sun3.h new file mode 100644 index 00000000000..9d703aa83a6 --- /dev/null +++ b/gdb/m-sun3.h @@ -0,0 +1,477 @@ +/* Parameters for execution on a Sun, for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef sun3 +#define sun3 +#endif + +/* 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. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* 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, 2); \ + if (op == 0047126) \ + pc += 4; /* Skip link #word */ \ + else if (op == 0044016) \ + pc += 6; /* Skip link #long */ \ +} + +/* Immediately after a function call, return the saved pc. + Can't 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) \ +read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR 0xf000000 + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0x4e, 0x4f} + +/* 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 2 + +/* Nonzero if instruction at PC is a return instruction. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 2) == 0x4e76) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 31 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", \ + "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", \ + "ps", "pc", \ + "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7", \ + "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags" } + +/* 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. */ + +#define FP_REGNUM 14 /* Contains address of executing stack frame */ +#define SP_REGNUM 15 /* Contains address of top of stack */ +#define PS_REGNUM 16 /* Contains processor status */ +#define PC_REGNUM 17 /* Contains program counter */ +#define FP0_REGNUM 18 /* Floating point register 0 */ +#define FPC_REGNUM 26 /* 68881 control register */ + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (16*4+8*12+8+20) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FPC_REGNUM ? (((N) - FPC_REGNUM) * 4) + 168 \ + : (N) >= FP0_REGNUM ? (((N) - FP0_REGNUM) * 12) + 72 \ + : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 12 bytes. */ + +#define REGISTER_RAW_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 12 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 68000, all regs are 4 bytes + except the floating point regs which are 8-byte doubles. */ + +#define REGISTER_VIRTUAL_SIZE(N) (((unsigned)(N) - FP0_REGNUM) < 8 ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 12 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) (((unsigned)(N) - FP0_REGNUM) < 8) + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_from_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ if ((REGNUM) >= FP0_REGNUM && (REGNUM) < FPC_REGNUM) \ + convert_to_68881 ((FROM), (TO)); \ + else \ + bcopy ((FROM), (TO), 4); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + (((unsigned)(N) - FP0_REGNUM) < 8 ? builtin_type_double : builtin_type_int) + +/* 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, 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 (0, 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)) + +/* Enable use of alternate code to read and write registers. */ + +#define NEW_SUN_PTRACE + +/* Enable use of alternate code for Sun's format of core dump file. */ + +#define NEW_SUN_CORE + +/* Do implement the attach and detach commands. */ + +#define ATTACH_DETACH + +/* It is safe to look for symsegs on a Sun, because Sun's ld + does not screw up with random garbage at end of file. */ + +#define READ_GDB_SYMSEGS + +/* 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 Sun, the frame's nominal address + is the address of a 4-byte word containing the calling frame's address. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +#define FRAME_ARGS_ADDRESS(fi) (fi.frame) + +#define FRAME_LOCALS_ADDRESS(fi) (fi.frame) + +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +#if 0 +#define FRAME_NUM_ARGS(val, fi) \ +{ register CORE_ADDR pc = FRAME_SAVED_PC (fi.frame); \ + register int insn = 0177777 & read_memory_integer (pc, 2); \ + val = 0; \ + if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ + val = read_memory_integer (pc + 2, 2); \ + else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ + || (insn & 0170777) == 0050117) /* addqw */ \ + { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ + else if (insn == 0157774) /* addal #WW, sp */ \ + val = read_memory_integer (pc + 2, 4); \ + val >>= 2; } +#endif + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ register int regnum; \ + register int regmask; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + int nextinsn; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info).pc >= (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ + && (frame_info).pc <= (frame_info).frame) \ + { next_addr = (frame_info).frame; \ + pc = (frame_info).frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ + else \ + { pc = get_pc_function_start ((frame_info).pc); \ + /* Verify we have a link a6 instruction next; \ + if not we lose. If we win, find the address above the saved \ + regs using the amount of storage from the link instruction. */\ + if (044016 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 4), pc+=4; \ + else if (047126 == read_memory_integer (pc, 2)) \ + next_addr = (frame_info).frame + read_memory_integer (pc += 2, 2), pc+=2; \ + else goto lose; \ + /* If have an addal #-n, sp next, adjust next_addr. */ \ + if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ + next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ + } \ + /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ + regmask = read_memory_integer (pc + 2, 2); \ + /* But before that can come an fmovem. Check for it. */ \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf227 == nextinsn \ + && (regmask & 0xff00) == 0xe000) \ + { pc += 4; /* Regmask's low bit is for register fp7, the first pushed */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 12); \ + regmask = read_memory_integer (pc + 2, 2); } \ + if (0044327 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 0, the first written */ \ + for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 4) - 4; } \ + else if (0044347 == read_memory_integer (pc, 2)) \ + { pc += 4; /* Regmask's low bit is for register 15, the first pushed */ \ + for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + else if (0x2f00 == 0xfff0 & read_memory_integer (pc, 2)) \ + { regnum = 0xf & read_memory_integer (pc, 2); pc += 2; \ + (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ + /* fmovemx to index of sp may follow. */ \ + regmask = read_memory_integer (pc + 2, 2); \ + nextinsn = 0xffff & read_memory_integer (pc, 2); \ + if (0xf236 == nextinsn \ + && (regmask & 0xff00) == 0xf000) \ + { pc += 10; /* Regmask's low bit is for register fp0, the first written */ \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--, regmask >>= 1) \ + if (regmask & 1) \ + (frame_saved_regs).regs[regnum] = (next_addr += 12) - 12; \ + regmask = read_memory_integer (pc + 2, 2); } \ + /* clrw -(sp); movw ccr,-(sp) may follow. */ \ + if (0x426742e7 == read_memory_integer (pc, 4)) \ + (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ + lose: ; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame; \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + char raw_buffer[12]; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ + sp = push_bytes (sp, raw_buffer, 12); } \ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + sp = push_word (sp, read_register (regnum)); \ + sp = push_word (sp, read_register (PS_REGNUM)); \ + write_register (SP_REGNUM, sp); } + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + char raw_buffer[12]; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], raw_buffer, 12); \ + write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ + for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + if (fsr.regs[PS_REGNUM]) \ + write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + set_current_frame (read_register (FP_REGNUM)); } + +/* This sequence of words is the instructions + fmovem 0xff,-(sp) + moveml 0xfffc,-(sp) + clrw -(sp) + movew ccr,-(sp) + /..* The arguments are pushed at this point by GDB; + no code is needed in the dummy for this. + The CALL_DUMMY_START_OFFSET gives the position of + the following jsr instruction. *../ + jsr @#32323232 + addl #69696969,sp + bpt + nop +Note this is 28 bytes. +We actually start executing at the jsr, since the pushing of the +registers is done by PUSH_DUMMY_FRAME. If this were real code, +the arguments for the function called by the jsr would be pushed +between the moveml and the jsr, and we could allow it to execute through. +But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, +and we cannot allow the moveml to push the registers again lest they be +taken for the arguments. */ + +#define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} + +#define CALL_DUMMY_LENGTH 28 + +#define CALL_DUMMY_START_OFFSET 12 + +/* 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, fun, nargs) \ +{ *(int *)((char *) dummyname + 20) = nargs * 4; \ + *(int *)((char *) dummyname + 14) = 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, 0, 0, 0, SIGTRAP, 0, 0, 0, \ + 0, SIGTRAP, 0, 0, 0, 0, 0, SIGKILL, \ + 0, 0, 0, 0, 0, 0, 0, 0, \ + SIGILL } + +/* 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 ("movel #end, sp"); \ + asm ("movel #0,a6"); } + +/* Push the frame pointer register on the stack. */ +#define PUSH_FRAME_PTR \ + asm ("movel a6,sp@-"); + +/* Copy the top-of-stack to the frame pointer register. */ +#define POP_FRAME_PTR \ + asm ("movl sp@,a6"); + +/* 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 \ +{ asm ("clrw -(sp)"); \ + asm ("pea sp@(10)"); \ + asm ("movem #0xfffe,sp@-"); } + +/* 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 \ +{ asm ("subil #8,sp@(28)"); \ + asm ("movem sp@,#0xffff"); \ + asm ("rte"); } diff --git a/gdb/m-suninit.h b/gdb/m-suninit.h new file mode 100644 index 00000000000..2e2f08cbb50 --- /dev/null +++ b/gdb/m-suninit.h @@ -0,0 +1,5 @@ + +/* This is how the size of an individual .o file's text segment + is rounded on a sun. */ + +#define FILEADDR_ROUND(addr) (addr) diff --git a/gdb/m-umax.h b/gdb/m-umax.h new file mode 100644 index 00000000000..d894b56cbe1 --- /dev/null +++ b/gdb/m-umax.h @@ -0,0 +1,425 @@ +/* Definitions to make GDB run on an encore under umax 4.2 + Copyright (C) 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef ns16000 +#define ns16000 +#endif + +#define HAVE_WAIT_STRUCT + +/* Encore's modifications to ptrace format */ + +#define UMAX_PTRACE + +/* Encore's modifications to core-file format */ + +#define UMAX_CORE + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Exec files and symbol tables are in COFF format */ + +#define COFF_FORMAT + +/* 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 unsigned char op = read_memory_integer (pc, 1); \ + if (op == 0x82) { op = read_memory_integer (pc+2,1); \ + if ((op & 0x80) == 0) pc += 3; \ + else if ((op & 0xc0) == 0x80) pc += 4; \ + else pc += 6; \ + } \ +} + +/* 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) \ + read_memory_integer (read_register (SP_REGNUM), 4) + +/* Address of end of stack space. */ + +#define STACK_END_ADDR (0xfffff000) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {0xf2} + +/* 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. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 0x12) + +#ifndef NaN +#include +#endif NaN + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, s) \ + ((s == sizeof (float))? \ + NaF (*(float *) p) : \ + NaD (*(double *) p)) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 25 + +#define NUM_GENERAL_REGS 8 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ + "sp", "fp", "pc", "ps", \ + "fsr", \ + "l0", "l1", "l2", "l3", "xx", \ + } + +/* 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. */ + +#define FP0_REGNUM 8 /* Floating point register 0 */ +#define SP_REGNUM 16 /* Contains address of top of stack */ +#define AP_REGNUM FP_REGNUM +#define FP_REGNUM 17 /* Contains address of executing stack frame */ +#define PC_REGNUM 18 /* Contains program counter */ +#define PS_REGNUM 19 /* Contains processor status */ +#define FPS_REGNUM 20 /* Floating point status register */ +#define LP0_REGNUM 21 /* Double register 0 (same as FP0) */ + +/* called from register_addr() -- blockend not used for now */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ \ + switch (regno) { \ + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: \ + addr = PU_R0 - (regno * sizeof (int)); break; \ + case SP_REGNUM: \ + addr = PU_SP; break; \ + case PC_REGNUM: \ + addr = PU_PC; break; \ + case FP_REGNUM: \ + addr = PU_FP; break; \ + case PS_REGNUM: \ + addr = PU_PSL; break; \ + case FPS_REGNUM: \ + addr = PU_FSR; break; \ + case FP0_REGNUM + 0: case FP0_REGNUM + 1: \ + case FP0_REGNUM + 2: case FP0_REGNUM + 3: \ + case FP0_REGNUM + 4: case FP0_REGNUM + 5: \ + case FP0_REGNUM + 6: case FP0_REGNUM + 7: \ + addr = PU_F0 + (regno - FP0_REGNUM) * sizeof (float); break; \ + case LP0_REGNUM + 0: case LP0_REGNUM + 1: \ + case LP0_REGNUM + 2: case LP0_REGNUM + 3: \ + addr = PU_F0 + (regno - LP0_REGNUM) * sizeof (double); break; \ + default: \ + printf ("bad argument to REGISTER_U_ADDR %d\n", regno); \ + abort (); \ + } \ +} + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES ((NUM_REGS - 4) * sizeof (int) + 4 * sizeof (double)) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) ((N) >= LP0_REGNUM ? \ + LP0_REGNUM * 4 + ((N) - LP0_REGNUM) * 8 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_RAW_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Number of bytes of storage in the program's representation + for register N. On the 32000, all regs are 4 bytes + except for the doubled floating registers. */ + +#define REGISTER_VIRTUAL_SIZE(N) ((N) >= LP0_REGNUM ? 8 : 4) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 8 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* 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_VIRTUAL_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_VIRTUAL_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) < FP0_REGNUM + 8) ? \ + builtin_type_float : \ + ((N) < LP0_REGNUM) ? \ + builtin_type_int : \ + builtin_type_double) + +/* 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 : 0), 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 : 0), 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)) + +/* 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 ns32000 series, the frame's nominal address is the FP + value, and at that address is saved previous FP value as a 4-byte word. */ + +#define FRAME_CHAIN(thisframe) (read_memory_integer (thisframe, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 4, 4)) + +/* Compute base of arguments. */ + +#define FRAME_ARGS_ADDRESS(fi) \ + ((n32k_get_enter_addr (fi.pc) > 1) ? \ + ((fi).frame) : (read_register (SP_REGNUM) - 4)) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi).frame) + +/* Get the address of the enter opcode for this function, if it is active. + Returns positive address > 1 if pc is between enter/exit, + 1 if pc before enter or after exit, 0 otherwise. */ + +extern CORE_ADDR n32k_get_enter_addr (); + +/* Return number of args passed to a frame. + Can return -1, meaning no way to tell. + Encore's C compiler often reuses same area on stack for args, + so this will often not work properly. If the arg names + are known, it's likely most of them will be printed. */ + +#define FRAME_NUM_ARGS(numargs, fi) \ +{ CORE_ADDR pc; \ + CORE_ADDR enter_addr; \ + unsigned int insn; \ + unsigned int addr_mode; \ + int width; \ + \ + numargs = -1; \ + enter_addr = n32k_get_enter_addr (fi.pc); \ + if (enter_addr > 0) \ + { \ + pc = (enter_addr == 1) ? \ + SAVED_PC_AFTER_CALL () : \ + FRAME_SAVED_PC (fi.frame); \ + insn = read_memory_integer (pc,2); \ + addr_mode = (insn >> 11) & 0x1f; \ + insn = insn & 0x7ff; \ + if ((insn & 0x7fc) == 0x57c && \ + addr_mode == 0x14) /* immediate */ \ + { \ + if (insn == 0x57c) /* adjspb */ \ + width = 1; \ + else if (insn == 0x57d) /* adjspw */ \ + width = 2; \ + else if (insn == 0x57f) /* adjspd */ \ + width = 4; \ + numargs = read_memory_integer (pc+2,width); \ + if (width > 1) \ + flip_bytes (&numargs, width); \ + numargs = - sign_extend (numargs, width*8) / 4;\ + } \ + } \ +} + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 8 + +/* 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) \ +{ \ + register int regmask, regnum; \ + int localcount; \ + register CORE_ADDR enter_addr; \ + register CORE_ADDR next_addr; \ + \ + bzero (&(frame_saved_regs), sizeof (frame_saved_regs)); \ + enter_addr = n32k_get_enter_addr ((frame_info).pc); \ + if (enter_addr > 1) \ + { \ + regmask = read_memory_integer (enter_addr+1, 1) & 0xff; \ + localcount = n32k_localcount (enter_addr); \ + next_addr = (frame_info).frame + localcount; \ + for (regnum = 0; regnum < 8; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] = (regmask & 1) ? \ + (next_addr -= 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info).frame + 4;\ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 4;\ + (frame_saved_regs).regs[FP_REGNUM] = \ + (read_memory_integer ((frame_info).frame, 4));\ + } \ + else if (enter_addr == 1) \ + { \ + CORE_ADDR sp = read_register (SP_REGNUM); \ + (frame_saved_regs).regs[PC_REGNUM] = sp; \ + (frame_saved_regs).regs[SP_REGNUM] = sp + 4; \ + } \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM);\ + register int regnum; \ + sp = push_word (sp, read_register (PC_REGNUM)); \ + sp = push_word (sp, read_register (FP_REGNUM)); \ + write_register (FP_REGNUM, sp); \ + for (regnum = 0; regnum < 8; regnum++) \ + sp = push_word (sp, read_register (regnum)); \ + write_register (SP_REGNUM, sp); \ +} + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info fi; \ + fi = get_frame_info (fp); \ + get_frame_saved_regs (&fi, &fsr); \ + for (regnum = 0; regnum < 8; regnum++) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ + write_register (SP_REGNUM, fp + 8); \ +} + +/* This sequence of words is the instructions + enter 0xff,0 82 ff 00 + jsr @0x00010203 7f ae c0 01 02 03 + adjspd 0x69696969 7f a5 01 02 03 04 + bpt f2 + Note this is 16 bytes. */ + +#define CALL_DUMMY { 0x7f00ff82, 0x0201c0ae, 0x01a57f03, 0xf2040302 } + +#define CALL_DUMMY_START_OFFSET 3 +#define CALL_DUMMY_LENGTH 16 +#define CALL_DUMMY_ADDR 5 +#define CALL_DUMMY_NARGS 11 + +/* 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, fun, nargs) \ +{ \ + int flipped; \ + flipped = fun | 0xc0000000; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_ADDR)) = flipped; \ + flipped = - nargs * 4; \ + flip_bytes (&flipped, 4); \ + *((int *) (((char *) dummyname)+CALL_DUMMY_NARGS)) = flipped; \ +} diff --git a/gdb/m-vax.h b/gdb/m-vax.h new file mode 100644 index 00000000000..578af44cb5b --- /dev/null +++ b/gdb/m-vax.h @@ -0,0 +1,375 @@ +/* Definitions to make GDB run on a vax under 4.2bsd. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#ifndef vax +#define vax +#endif + +/* 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. */ + +#define NAMES_HAVE_UNDERSCORE + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 2 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +#define SKIP_PROLOGUE(pc) \ +{ register int op = read_memory_integer (pc, 1); \ + if (op == 0x11) pc += 2; /* skip brb */ \ + if (op == 0x31) pc += 3; /* skip brw */ \ +} + +/* 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) FRAME_SAVED_PC(frame) + +/* 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 (0x80000000 - (UPAGES * NBPG)) + +/* Stack grows downward. */ + +#define INNER_THAN < + +/* Sequence of bytes for breakpoint instruction. */ + +#define BREAKPOINT {3} + +/* 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. */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 1) == 04) + +/* 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) + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 17 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc", "ps"} + +/* 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. */ + +#define AP_REGNUM 12 +#define FP_REGNUM 13 /* Contains address of executing stack frame */ +#define SP_REGNUM 14 /* Contains address of top of stack */ +#define PC_REGNUM 15 /* Contains program counter */ +#define PS_REGNUM 16 /* Contains processor status */ + +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = blockend - 0110 + regno * 4; \ + if (regno == PC_REGNUM) addr = blockend - 8; \ + if (regno == PS_REGNUM) addr = blockend - 4; \ + if (regno == FP_REGNUM) addr = blockend - 0120; \ + if (regno == AP_REGNUM) addr = blockend - 0124; \ + if (regno == SP_REGNUM) addr = blockend - 20; } + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (17*4) + +/* 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. On the vax, all regs are 4 bytes. */ + +#define REGISTER_RAW_SIZE(N) 4 + +/* Number of bytes of storage in the program's representation + for register N. On the vax, all regs are 4 bytes. */ + +#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), 4); + +/* 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), 4); + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) builtin_type_int + +/* 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, 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 (0, 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)) + +/* 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 FRAME_CHAIN(thisframe) (read_memory_integer (thisframe + 12, 4)) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + (chain != 0 && (FRAME_SAVED_PC (thisframe) >= first_object_file_end)) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +#define FRAME_SAVED_PC(frame) (read_memory_integer (frame + 16, 4)) + +/* Cannot find the AP register value directly from the FP value. + Must find it saved in the frame called by this one, or in the AP register + for the innermost frame. */ +#define FRAME_ARGS_ADDRESS(fi) \ + (((fi).next_frame \ + ? read_memory_integer ((fi).next_frame + 8, 4) \ + : read_register (AP_REGNUM))) + +#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 = (0xff & read_memory_integer (FRAME_ARGS_ADDRESS (fi), 1)); } + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 4 + +/* 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) \ +{ register int regnum; \ + register int regmask = read_memory_integer ((frame_info).frame+4, 4) >> 16; \ + register CORE_ADDR next_addr; \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + next_addr = (frame_info).frame + 16; \ + /* Regmask's low bit is for register 0, \ + which is the first one that would be pushed. */ \ + for (regnum = 0; regnum < 12; regnum++, regmask >>= 1) \ + (frame_saved_regs).regs[regnum] = (regmask & 1) ? (next_addr += 4) : 0; \ + (frame_saved_regs).regs[SP_REGNUM] = next_addr + 4; \ + if (read_memory_integer ((frame_info).frame + 4, 4) & 0x20000000) \ + (frame_saved_regs).regs[SP_REGNUM] += 4 + 4 * read_memory_integer (next_addr + 4, 4); \ + (frame_saved_regs).regs[PC_REGNUM] = (frame_info).frame + 16; \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info).frame + 12; \ + (frame_saved_regs).regs[AP_REGNUM] = (frame_info).frame + 8; \ + (frame_saved_regs).regs[PS_REGNUM] = (frame_info).frame + 4; \ +} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ 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, read_register (AP_REGNUM)); \ + sp = push_word (sp, (read_register (PS_REGNUM) & 0xffef) \ + + 0x2fff0000); \ + sp = push_word (sp, 0); \ + write_register (SP_REGNUM, sp); \ + write_register (FP_REGNUM, sp); \ + write_register (AP_REGNUM, sp + 17 * sizeof (int)); } + +/* Discard from the stack the innermost frame, restoring all registers. */ + +#define POP_FRAME \ +{ register CORE_ADDR fp = read_register (FP_REGNUM); \ + register int regnum; \ + register int regmask = read_memory_integer (fp + 4, 4); \ + write_register (PS_REGNUM, \ + (regmask & 0xffff) \ + | (read_register (PS_REGNUM) & 0xffff0000)); \ + write_register (PC_REGNUM, read_memory_integer (fp + 16, 4)); \ + write_register (FP_REGNUM, read_memory_integer (fp + 12, 4)); \ + write_register (AP_REGNUM, read_memory_integer (fp + 8, 4)); \ + fp += 16; \ + for (regnum = 0; regnum < 12; regnum++) \ + if (regmask & (0x10000 << regnum)) \ + write_register (regnum, read_memory_integer (fp += 4, 4)); \ + fp = fp + 4 + ((regmask >> 30) & 3); \ + if (regmask & 0x20000000) \ + { regnum = read_memory_integer (fp, 4); \ + fp += (regnum + 1) * 4; } \ + write_register (SP_REGNUM, fp); \ + set_current_frame (read_register (FP_REGNUM)); } + +/* This sequence of words is the instructions + calls #69, @#32323232 + bpt + Note this is 8 bytes. */ + +#define CALL_DUMMY {0x329f69fb, 0x03323232} + +#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, fun, nargs) \ +{ *((char *) dummyname + 1) = nargs; \ + *(int *)((char *) dummyname + 3) = 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 \ +{ asm ("pushl 8(sp)"); \ + asm ("pushl 8(sp)"); \ + asm ("pushal 0x14(sp)"); \ + asm ("pushr $037777"); } + +/* 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 \ +{ asm ("popr $037777"); \ + asm ("subl2 $8,(sp)"); \ + asm ("movl (sp),sp"); \ + asm ("rei"); } diff --git a/gdb/m-vaxinit.h b/gdb/m-vaxinit.h new file mode 100644 index 00000000000..6044867675f --- /dev/null +++ b/gdb/m-vaxinit.h @@ -0,0 +1,5 @@ + +/* This is how the size of an individual .o file's text segment + is rounded on a vax. */ + +#define FILEADDR_ROUND(addr) ((addr + 3) & -4) diff --git a/gdb/m68k-opcode.h b/gdb/m68k-opcode.h new file mode 100644 index 00000000000..111fd841d4f --- /dev/null +++ b/gdb/m68k-opcode.h @@ -0,0 +1,1272 @@ +/* Opcode table for m68000/m68020 and m68881. */ + +struct m68k_opcode +{ + char *name; + unsigned long opcode; + unsigned long match; + char *args; +}; + +/* We store four bytes of opcode for all opcodes because that + is the most any of them need. The actual length of an instruction + is always at least 2 bytes, and is as much longer as necessary to + hold the operands it has. + + The match component is a mask saying which bits must match + particular opcode in order for an instruction to be an instance + of that opcode. + + The args component is a string containing two characters + for each operand of the instruction. The first specifies + the kind of operand; the second, the place it is stored. */ + +/* Kinds of operands: + D data register only. Stored as 3 bits. + A address register only. Stored as 3 bits. + R either kind of register. Stored as 4 bits. + F floating point coprocessor register only. Stored as 3 bits. + O an offset (or width): immediate data 0-31 or data register. + Stored as 6 bits in special format for BF... insns. + + autoincrement only. Stored as 3 bits (number of the address register). + - autodecrement only. Stored as 3 bits (number of the address register). + Q quick immediate data. Stored as 3 bits. + This matches an immediate operand only when value is in range 1 .. 8. + M moveq immediate data. Stored as 8 bits. + This matches an immediate operand only when value is in range -128..127 + T trap vector immediate data. Stored as 4 bits. + + k K-factor for fmove.p instruction. Stored as a 7-bit constant or + a three bit register offset, depending on the field type. + + # immediate data. Stored in special places (b, w or l) + which say how many bits to store. + ^ immediate data for floating point instructions. Special places + are offset by 2 bytes from '#'... + B pc-relative address, converted to an offset + that is treated as immediate data. + d displacement and register. Stores the register as 3 bits + and stores the displacement in the entire second word. + + C the CCR. No need to store it; this is just for filtering validity. + S the SR. No need to store, just as with CCR. + U the USP. No need to store, just as with CCR. + + I Coprocessor ID. Not printed if 1. The Coprocessor ID is always + extracted from the 'd' field of word one, which means that an extended + coprocessor opcode can be skipped using the 'i' place, if needed. + + s System Control register for the floating point coprocessor. + + J Misc register for movec instruction, stored in 'j' format. + Possible values: + 000 SFC Source Function Code reg + 001 DFC Data Function Code reg + 002 CACR Cache Control Register + 800 USP User Stack Pointer + 801 VBR Vector Base reg + 802 CAAR Cache Address Register + 803 MSP Master Stack Pointer + 804 ISP Interrupt Stack Pointer + + These specify various classes of addressing modes. + They are all stored as 6 bits using an address mode and a register number; + they differ in which addressing modes they match. + + * all (modes 0-6,7.*) + ~ alterable memory (modes 2-6,7.0,7.1)(not 0,1,7.~) + % alterable (modes 0-6,7.0,7.1)(not 7.~) + ; data (modes 0,2-6,7.*)(not 1) + @ data, but not immediate (modes 0,2-6,7.???)(not 1,7.?) This may really be ;, the 68020 book says it is + ! control (modes 2,5,6,7.*-)(not 0,1,3,4,7.4) + & alterable control (modes 2,5,6,7.0,7.1)(not 0,1,7.???) + $ alterable data (modes 0,2-6,7.0,7.1)(not 1,7.~) + ? alterable control, or data register (modes 0,2,5,6,7.0,7.1)(not 1,3,4,7.~) + / control, or data register (modes 0,2,5,6,7.0,7.1,7.2,7.3)(not 1,3,4,7.4) +*/ + +/* Places to put an operand, for non-general operands: + s source, low bits of first word. + d dest, shifted 9 in first word + 1 second word, shifted 12 + 2 second word, shifted 6 + 3 second word, shifted 0 + 4 third word, shifted 12 + 5 third word, shifted 6 + 6 third word, shifted 0 + 7 second word, shifted 7 + 8 second word, shifted 10 + D store in both place 1 and place 3; for divul and divsl. + b second word, low byte + w second word (entire) + l second and third word (entire) + g branch offset for bra and similar instructions. + The place to store depends on the magnitude of offset. + t store in both place 7 and place 8; for floating point operations + c branch offset for cpBcc operations. + The place to store is word two if bit six of word one is zero, + and words two and three if bit six of word one is one. + i Increment by two, to skip over coprocessor extended operands. Only + works with the 'I' format. + k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number. + Also used for dynamic fmovem instruction. + C floating point coprocessor constant - 7 bits. Also used for static + K-factors... + j Movec register #, stored in 12 low bits of second word. + + Places to put operand, for general operands: + d destination, shifted 6 bits in first word + b source, at low bit of first word, and immediate uses one byte + w source, at low bit of first word, and immediate uses two bytes + l source, at low bit of first word, and immediate uses four bytes + s source, at low bit of first word. + Used sometimes in contexts where immediate is not allowed anyway. + f single precision float, low bit of 1st word, immediate uses 4 bytes + F double precision float, low bit of 1st word, immediate uses 8 bytes + x extended precision float, low bit of 1st word, immediate uses 12 bytes + p packed float, low bit of 1st word, immediate uses 12 bytes +*/ + +#define one(x) ((x) << 16) +#define two(x, y) (((x) << 16) + y) + +/* The assembler requires that this array be sorted as follows: + all instances of the same mnemonic must be consecutive. + All instances of the same mnemonic with the same number of operands + must be consecutive. + */ +struct m68k_opcode m68k_opcodes[] = +{ +{"abcd", one(0140400), one(0170770), "DsDd"}, +{"abcd", one(0140410), one(0170770), "-s-d"}, + + /* Add instructions */ +{"addal", one(0150700), one(0170700), "*lAd"}, +{"addaw", one(0150300), one(0170700), "*wAd"}, +{"addib", one(0003000), one(0177700), "#b$b"}, +{"addil", one(0003200), one(0177700), "#l$l"}, +{"addiw", one(0003100), one(0177700), "#w$w"}, +{"addqb", one(0050000), one(0170700), "Qd$b"}, +{"addql", one(0050200), one(0170700), "Qd%l"}, +{"addqw", one(0050100), one(0170700), "Qd%w"}, + +{"addb", one(0003000), one(0177700), "#b$b"}, /* addi written as add */ +{"addb", one(0050000), one(0170700), "Qd$b"}, /* addq written as add */ +{"addb", one(0150000), one(0170700), ";bDd"}, /* addb , Dd */ +{"addb", one(0150400), one(0170700), "Dd~b"}, /* addb Dd, */ + +{"addw", one(0003100), one(0177700), "#w$w"}, /* addi written as add */ +{"addw", one(0150300), one(0170700), "*wAd"}, /* adda written as add */ +{"addw", one(0050100), one(0170700), "Qd%w"}, /* addq written as add */ +{"addw", one(0150100), one(0170700), "*wDd"}, /* addw , Dd */ +{"addw", one(0150500), one(0170700), "Dd~w"}, /* addw Dd, */ + +{"addl", one(0003200), one(0177700), "#l$l"}, /* addi written as add */ +{"addl", one(0150700), one(0170700), "*lAd"}, /* adda written as add */ +{"addl", one(0050200), one(0170700), "Qd%l"}, /* addq written as add */ +{"addl", one(0150200), one(0170700), "*lDd"}, /* addl , Dd */ +{"addl", one(0150600), one(0170700), "Dd~l"}, /* addl Dd, */ + +{"addxb", one(0150400), one(0170770), "DsDd"}, +{"addxb", one(0150410), one(0170770), "-s-d"}, +{"addxl", one(0150600), one(0170770), "DsDd"}, +{"addxl", one(0150610), one(0170770), "-s-d"}, +{"addxw", one(0150500), one(0170770), "DsDd"}, +{"addxw", one(0150510), one(0170770), "-s-d"}, + +{"andib", one(0001000), one(0177700), "#b$b"}, +{"andib", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */ +{"andiw", one(0001100), one(0177700), "#w$w"}, +{"andiw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */ +{"andil", one(0001200), one(0177700), "#l$l"}, + +{"andb", one(0001000), one(0177700), "#b$b"}, /* andi written as or */ +{"andb", one(0001074), one(0177777), "#bCb"}, /* andi to ccr */ +{"andb", one(0140000), one(0170700), ";bDd"}, /* memory to register */ +{"andb", one(0140400), one(0170700), "Dd~b"}, /* register to memory */ +{"andw", one(0001100), one(0177700), "#w$w"}, /* andi written as or */ +{"andw", one(0001174), one(0177777), "#wSw"}, /* andi to sr */ +{"andw", one(0140100), one(0170700), ";wDd"}, /* memory to register */ +{"andw", one(0140500), one(0170700), "Dd~w"}, /* register to memory */ +{"andl", one(0001200), one(0177700), "#l$l"}, /* andi written as or */ +{"andl", one(0140200), one(0170700), ";lDd"}, /* memory to register */ +{"andl", one(0140600), one(0170700), "Dd~l"}, /* register to memory */ + +{"aslb", one(0160400), one(0170770), "QdDs"}, +{"aslb", one(0160440), one(0170770), "DdDs"}, +{"asll", one(0160600), one(0170770), "QdDs"}, +{"asll", one(0160640), one(0170770), "DdDs"}, +{"aslw", one(0160500), one(0170770), "QdDs"}, +{"aslw", one(0160540), one(0170770), "DdDs"}, +{"aslw", one(0160700), one(0177700), "~s"}, /* Shift memory */ +{"asrb", one(0160000), one(0170770), "QdDs"}, +{"asrb", one(0160040), one(0170770), "DdDs"}, +{"asrl", one(0160200), one(0170770), "QdDs"}, +{"asrl", one(0160240), one(0170770), "DdDs"}, +{"asrw", one(0160100), one(0170770), "QdDs"}, +{"asrw", one(0160140), one(0170770), "DdDs"}, +{"asrw", one(0160300), one(0177700), "~s"}, /* Shift memory */ + +{"bhi", one(0061000), one(0177400), "Bg"}, +{"bls", one(0061400), one(0177400), "Bg"}, +{"bcc", one(0062000), one(0177400), "Bg"}, +{"bcs", one(0062400), one(0177400), "Bg"}, +{"bne", one(0063000), one(0177400), "Bg"}, +{"beq", one(0063400), one(0177400), "Bg"}, +{"bvc", one(0064000), one(0177400), "Bg"}, +{"bvs", one(0064400), one(0177400), "Bg"}, +{"bpl", one(0065000), one(0177400), "Bg"}, +{"bmi", one(0065400), one(0177400), "Bg"}, +{"bge", one(0066000), one(0177400), "Bg"}, +{"blt", one(0066400), one(0177400), "Bg"}, +{"bgt", one(0067000), one(0177400), "Bg"}, +{"ble", one(0067400), one(0177400), "Bg"}, + +{"bchg", one(0000500), one(0170700), "Dd$s"}, +{"bchg", one(0004100), one(0177700), "#b$s"}, +{"bclr", one(0000600), one(0170700), "Dd$s"}, +{"bclr", one(0004200), one(0177700), "#b$s"}, +{"bfchg", two(0165300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bfclr", two(0166300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bfexts", two(0165700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfextu", two(0164700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfffo", two(0166700, 0), two(0177700, 0100000), "/sO2O3D1"}, +{"bfins", two(0167700, 0), two(0177700, 0100000), "D1?sO2O3"}, +{"bfset", two(0167300, 0), two(0177700, 0170000), "?sO2O3"}, +{"bftst", two(0164300, 0), two(0177700, 0170000), "/sO2O3"}, +{"bset", one(0000700), one(0170700), "Dd$s"}, +{"bset", one(0004300), one(0177700), "#b$s"}, +{"btst", one(0000400), one(0170700), "Dd@s"}, +{"btst", one(0004000), one(0177700), "#b@s"}, + +{"bkpt", one(0044110), one(0177770), "Qs"}, +{"bra", one(0060000), one(0177400), "Bg"}, +{"bsr", one(0060400), one(0177400), "Bg"}, +{"callm", one(0003300), one(0177700), "#b!s"}, +{"cas2l", two(0007374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF FOO this is really a 3 word ins */ +{"cas2w", two(0006374, 0), two(0177777, 0107070), "D3D6D2D5R1R4"}, /* JF ditto */ +{"casb", two(0005300, 0), two(0177700, 0177070), "D3D2~s"}, +{"casl", two(0007300, 0), two(0177700, 0177070), "D3D2~s"}, +{"casw", two(0006300, 0), two(0177700, 0177070), "D3D2~s"}, + +/* {"chk", one(0040600), one(0170700), ";wDd"}, JF FOO this looks wrong */ +{"chk2b", two(0000300, 0004000), two(0177700, 07777), "!sR1"}, +{"chk2l", two(0002300, 0004000), two(0177700, 07777), "!sR1"}, +{"chk2w", two(0001300, 0004000), two(0177700, 07777), "!sR1"}, +{"chkl", one(0040400), one(0170700), ";lDd"}, +{"chkw", one(0040600), one(0170700), ";wDd"}, +{"clrb", one(0041000), one(0177700), "$s"}, +{"clrl", one(0041200), one(0177700), "$s"}, +{"clrw", one(0041100), one(0177700), "$s"}, + +{"cmp2b", two(0000300, 0), two(0177700, 07777), "!sR1"}, +{"cmp2l", two(0002300, 0), two(0177700, 07777), "!sR1"}, +{"cmp2w", two(0001300, 0), two(0177700, 07777), "!sR1"}, +{"cmpal", one(0130700), one(0170700), "*lAd"}, +{"cmpaw", one(0130300), one(0170700), "*wAd"}, +{"cmpib", one(0006000), one(0177700), "#b;b"}, +{"cmpil", one(0006200), one(0177700), "#l;l"}, +{"cmpiw", one(0006100), one(0177700), "#w;w"}, +{"cmpb", one(0006000), one(0177700), "#b;b"}, /* cmpi written as cmp */ +{"cmpb", one(0130000), one(0170700), ";bDd"}, +{"cmpw", one(0006100), one(0177700), "#w;w"}, +{"cmpw", one(0130100), one(0170700), "*wDd"}, +{"cmpw", one(0130300), one(0170700), "*wAd"}, /* cmpa written as cmp */ +{"cmpl", one(0006200), one(0177700), "#l;l"}, +{"cmpl", one(0130200), one(0170700), "*lDd"}, +{"cmpl", one(0130700), one(0170700), "*lAd"}, +{"cmpmb", one(0130410), one(0170770), "+s+d"}, +{"cmpml", one(0130610), one(0170770), "+s+d"}, +{"cmpmw", one(0130510), one(0170770), "+s+d"}, + +{"dbcc", one(0052310), one(0177770), "DsBw"}, +{"dbcs", one(0052710), one(0177770), "DsBw"}, +{"dbeq", one(0053710), one(0177770), "DsBw"}, +{"dbf", one(0050710), one(0177770), "DsBw"}, +{"dbge", one(0056310), one(0177770), "DsBw"}, +{"dbgt", one(0057310), one(0177770), "DsBw"}, +{"dbhi", one(0051310), one(0177770), "DsBw"}, +{"dble", one(0057710), one(0177770), "DsBw"}, +{"dbls", one(0051710), one(0177770), "DsBw"}, +{"dblt", one(0056710), one(0177770), "DsBw"}, +{"dbmi", one(0055710), one(0177770), "DsBw"}, +{"dbne", one(0053310), one(0177770), "DsBw"}, +{"dbpl", one(0055310), one(0177770), "DsBw"}, +{"dbra", one(0050710), one(0177770), "DsBw"}, +{"dbt", one(0050310), one(0177770), "DsBw"}, +{"dbvc", one(0054310), one(0177770), "DsBw"}, +{"dbvs", one(0054710), one(0177770), "DsBw"}, + +{"divsl", two(0046100, 0006000), two(0177700, 0107770), ";lD3D1"}, +{"divsl", two(0046100, 0004000), two(0177700, 0107770), ";lDD"}, +{"divsll", two(0046100, 0004000), two(0177700, 0107770), ";lD3D1"}, +{"divsw", one(0100700), one(0170700), ";wDd"}, +{"divs", one(0100700), one(0170700), ";wDd"}, +{"divul", two(0046100, 0002000), two(0177700, 0107770), ";lD3D1"}, +{"divul", two(0046100, 0000000), two(0177700, 0107770), ";lDD"}, +{"divull", two(0046100, 0000000), two(0177700, 0107770), ";lD3D1"}, +{"divuw", one(0100300), one(0170700), ";wDd"}, +{"divu", one(0100300), one(0170700), ";wDd"}, +{"eorb", one(0005000), one(0177700), "#b$s"}, /* eori written as or */ +{"eorb", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */ +{"eorb", one(0130400), one(0170700), "Dd$s"}, /* register to memory */ +{"eorib", one(0005000), one(0177700), "#b$s"}, +{"eorib", one(0005074), one(0177777), "#bCs"}, /* eori to ccr */ +{"eoril", one(0005200), one(0177700), "#l$s"}, +{"eoriw", one(0005100), one(0177700), "#w$s"}, +{"eoriw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */ +{"eorl", one(0005200), one(0177700), "#l$s"}, +{"eorl", one(0130600), one(0170700), "Dd$s"}, +{"eorw", one(0005100), one(0177700), "#w$s"}, +{"eorw", one(0005174), one(0177777), "#wSs"}, /* eori to sr */ +{"eorw", one(0130500), one(0170700), "Dd$s"}, + +{"exg", one(0140500), one(0170770), "DdDs"}, +{"exg", one(0140510), one(0170770), "AdAs"}, +{"exg", one(0140610), one(0170770), "DdAs"}, +{"exg", one(0140610), one(0170770), "AsDd"}, + +{"extw", one(0044200), one(0177770), "Ds"}, +{"extl", one(0044300), one(0177770), "Ds"}, +{"extbl", one(0044700), one(0177770), "Ds"}, +{"extb.l", one(0044700), one(0177770), "Ds"}, /* Not sure we should support this one*/ + +{"illegal", one(0045374), one(0177777), ""}, +{"jmp", one(0047300), one(0177700), "!s"}, +{"jsr", one(0047200), one(0177700), "!s"}, +{"lea", one(0040700), one(0170700), "!sAd"}, +{"linkw", one(0047120), one(0177770), "As#w"}, +{"linkl", one(0044010), one(0177770), "As#l"}, +{"link", one(0047120), one(0177770), "As#w"}, +{"link", one(0044010), one(0177770), "As#l"}, + +{"lslb", one(0160410), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lslb", one(0160450), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lslw", one(0160510), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lslw", one(0160550), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lslw", one(0161700), one(0177700), "~s"}, /* Shift memory */ +{"lsll", one(0160610), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsll", one(0160650), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ + +{"lsrb", one(0160010), one(0170770), "QdDs"} /* lsrb #Q, Ds */, +{"lsrb", one(0160050), one(0170770), "DdDs"}, /* lsrb Dd, Ds */ +{"lsrl", one(0160210), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsrl", one(0160250), one(0170770), "DdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0160110), one(0170770), "QdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0160150), one(0170770), "DdDs"}, /* lsrb #Q, Ds */ +{"lsrw", one(0161300), one(0177700), "~s"}, /* Shift memory */ + +{"moveal", one(0020100), one(0170700), "*lAd"}, +{"moveaw", one(0030100), one(0170700), "*wAd"}, +{"moveb", one(0010000), one(0170000), ";b$d"}, /* move */ + +{"movec", one(0047173), one(0177777), "R1Jj"}, +{"movec", one(0047173), one(0177777), "R1#j"}, +{"movec", one(0047172), one(0177777), "JjR1"}, +{"movec", one(0047172), one(0177777), "#jR1"}, + +{"movel", one(0020000), one(0170000), "*l$d"}, +{"movel", one(0020100), one(0170700), "*lAd"}, +{"movel", one(0047140), one(0177770), "AsUd"}, /* move to USP */ +{"movel", one(0047150), one(0177770), "UdAs"}, /* move from USP */ +{"movel", one(0070000), one(0170400), "MsDd"}, /* moveq written as move */ + +{"moveml", one(0044300), one(0177700), "#w&s"}, /* movem reg to mem. */ +{"moveml", one(0044340), one(0177770), "#w-s"}, /* movem reg to autodecrement. */ +{"moveml", one(0046300), one(0177700), "!s#w"}, /* movem mem to reg. */ +{"moveml", one(0046330), one(0177770), "+s#w"}, /* movem autoinc to reg. */ + +{"movemw", one(0044200), one(0177700), "#w&s"}, /* movem reg to mem. */ +{"movemw", one(0044240), one(0177770), "#w-s"}, /* movem reg to autodecrement. */ +{"movemw", one(0046200), one(0177700), "!s#w"}, /* movem mem to reg. */ +{"movemw", one(0046230), one(0177770), "+s#w"}, /* movem autoinc to reg. */ + +{"movepl", one(0000510), one(0170770), "dsDd"}, /* memory to register */ +{"movepl", one(0000710), one(0170770), "Ddds"}, /* register to memory */ +{"movepw", one(0000410), one(0170770), "dsDd"}, /* memory to register */ +{"movepw", one(0000610), one(0170770), "Ddds"}, /* register to memory */ +{"moveq", one(0070000), one(0170400), "MsDd"}, +{"movew", one(0030000), one(0170000), "*w$d"}, +{"movew", one(0030100), one(0170700), "*wAd"}, /* movea, written as move */ +{"movew", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */ +{"movew", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */ +{"movew", one(0042300), one(0177700), ";wCd"}, /* move to ccr */ +{"movew", one(0043300), one(0177700), ";wSd"}, /* move to sr */ + +{"movesb", two(0007000, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesb", two(0007000, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ +{"movesl", two(0007200, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesl", two(0007200, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ +{"movesw", two(0007100, 0), two(0177700, 07777), "~sR1"}, /* moves from memory */ +{"movesw", two(0007100, 04000), two(0177700, 07777), "R1~s"}, /* moves to memory */ + +{"mulsl", two(0046000, 004000), two(0177700, 0107770), ";lD1"}, +{"mulsl", two(0046000, 006000), two(0177700, 0107770), ";lD3D1"}, +{"mulsw", one(0140700), one(0170700), ";wDd"}, +{"muls", one(0140700), one(0170700), ";wDd"}, +{"mulul", two(0046000, 000000), two(0177700, 0107770), ";lD1"}, +{"mulul", two(0046000, 002000), two(0177700, 0107770), ";lD3D1"}, +{"muluw", one(0140300), one(0170700), ";lDd"}, +{"mulu", one(0140300), one(0170700), ";lDd"}, +{"nbcd", one(0044000), one(0177700), "$s"}, +{"negb", one(0042000), one(0177700), "$s"}, +{"negl", one(0042200), one(0177700), "$s"}, +{"negw", one(0042100), one(0177700), "$s"}, +{"negxb", one(0040000), one(0177700), "$s"}, +{"negxl", one(0040200), one(0177700), "$s"}, +{"negxw", one(0040100), one(0177700), "$s"}, +{"nop", one(0047161), one(0177777), ""}, +{"notb", one(0043000), one(0177700), "$s"}, +{"notl", one(0043200), one(0177700), "$s"}, +{"notw", one(0043100), one(0177700), "$s"}, + +{"orb", one(0000000), one(0177700), "#b$s"}, /* ori written as or */ +{"orb", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */ +{"orb", one(0100000), one(0170700), ";bDd"}, /* memory to register */ +{"orb", one(0100400), one(0170700), "Dd~s"}, /* register to memory */ +{"orib", one(0000000), one(0177700), "#b$s"}, +{"orib", one(0000074), one(0177777), "#bCs"}, /* ori to ccr */ +{"oril", one(0000200), one(0177700), "#l$s"}, +{"oriw", one(0000100), one(0177700), "#w$s"}, +{"oriw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */ +{"orl", one(0000200), one(0177700), "#l$s"}, +{"orl", one(0100200), one(0170700), ";lDd"}, /* memory to register */ +{"orl", one(0100600), one(0170700), "Dd~s"}, /* register to memory */ +{"orw", one(0000100), one(0177700), "#w$s"}, +{"orw", one(0000174), one(0177777), "#wSs"}, /* ori to sr */ +{"orw", one(0100100), one(0170700), ";wDd"}, /* memory to register */ +{"orw", one(0100500), one(0170700), "Dd~s"}, /* register to memory */ + +{"pack", one(0100500), one(0170770), "DsDd#w"}, /* pack Ds, Dd, #w */ +{"pack", one(0100510), one(0170770), "-s-d#w"}, /* pack -(As), -(Ad), #w */ +{"pea", one(0044100), one(0177700), "!s"}, +{"reset", one(0047160), one(0177777), ""}, + +{"rolb", one(0160430), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rolb", one(0160470), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"roll", one(0160630), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"roll", one(0160670), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rolw", one(0160530), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rolw", one(0160570), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rolw", one(0163700), one(0177700), "~s"}, /* Rotate memory */ +{"rorb", one(0160030), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorb", one(0160070), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorl", one(0160230), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorl", one(0160270), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorw", one(0160130), one(0170770), "QdDs"}, /* rorb #Q, Ds */ +{"rorw", one(0160170), one(0170770), "DdDs"}, /* rorb Dd, Ds */ +{"rorw", one(0163300), one(0177700), "~s"}, /* Rotate memory */ + +{"roxlb", one(0160420), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxlb", one(0160460), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxll", one(0160620), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxll", one(0160660), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxlw", one(0160520), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxlw", one(0160560), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxlw", one(0162700), one(0177700), "~s"}, /* Rotate memory */ +{"roxrb", one(0160020), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrb", one(0160060), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrl", one(0160220), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrl", one(0160260), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrw", one(0160120), one(0170770), "QdDs"}, /* roxrb #Q, Ds */ +{"roxrw", one(0160160), one(0170770), "DdDs"}, /* roxrb Dd, Ds */ +{"roxrw", one(0162300), one(0177700), "~s"}, /* Rotate memory */ + +{"rtd", one(0047164), one(0177777), "#w"}, +{"rte", one(0047163), one(0177777), ""}, +{"rtm", one(0003300), one(0177760), "Rs"}, +{"rtr", one(0047167), one(0177777), ""}, +{"rts", one(0047165), one(0177777), ""}, + +{"scc", one(0052300), one(0177700), "$s"}, +{"scs", one(0052700), one(0177700), "$s"}, +{"seq", one(0053700), one(0177700), "$s"}, +{"sf", one(0050700), one(0177700), "$s"}, +{"sge", one(0056300), one(0177700), "$s"}, +{"sgt", one(0057300), one(0177700), "$s"}, +{"shi", one(0051300), one(0177700), "$s"}, +{"sle", one(0057700), one(0177700), "$s"}, +{"sls", one(0051700), one(0177700), "$s"}, +{"slt", one(0056700), one(0177700), "$s"}, +{"smi", one(0055700), one(0177700), "$s"}, +{"sne", one(0053300), one(0177700), "$s"}, +{"spl", one(0055300), one(0177700), "$s"}, +{"st", one(0050300), one(0177700), "$s"}, +{"svc", one(0054300), one(0177700), "$s"}, +{"svs", one(0054700), one(0177700), "$s"}, + +{"sbcd", one(0100400), one(0170770), "DsDd"}, +{"sbcd", one(0100410), one(0170770), "-s-d"}, +{"stop", one(0047162), one(0177777), "#w"}, + +{"subal", one(0110700), one(0170700), "*lAd"}, +{"subaw", one(0110300), one(0170700), "*wAd"}, +{"subb", one(0002000), one(0177700), "#b$s"}, /* subi written as sub */ +{"subb", one(0050400), one(0170700), "Qd%s"}, /* subq written as sub */ +{"subb", one(0110000), one(0170700), ";bDd"}, /* subb ??, Dd */ +{"subb", one(0110400), one(0170700), "Dd~s"}, /* subb Dd, ?? */ +{"subib", one(0002000), one(0177700), "#b$s"}, +{"subil", one(0002200), one(0177700), "#l$s"}, +{"subiw", one(0002100), one(0177700), "#w$s"}, +{"subl", one(0002200), one(0177700), "#l$s"}, +{"subl", one(0050600), one(0170700), "Qd%s"}, +{"subl", one(0110200), one(0170700), "*lDd"}, +{"subl", one(0110600), one(0170700), "Dd~s"}, +{"subl", one(0110700), one(0170700), "*lAd"}, +{"subqb", one(0050400), one(0170700), "Qd%s"}, +{"subql", one(0050600), one(0170700), "Qd%s"}, +{"subqw", one(0050500), one(0170700), "Qd%s"}, +{"subw", one(0002100), one(0177700), "#w$s"}, +{"subw", one(0050500), one(0170700), "Qd%s"}, +{"subw", one(0110100), one(0170700), "*wDd"}, +{"subw", one(0110300), one(0170700), "*wAd"}, /* suba written as sub */ +{"subw", one(0110500), one(0170700), "Dd~s"}, + +{"subxb", one(0110400), one(0170770), "DsDd"}, /* subxb Ds, Dd */ +{"subxb", one(0110410), one(0170770), "-s-d"}, /* subxb -(As), -(Ad) */ +{"subxl", one(0110600), one(0170770), "DsDd"}, +{"subxl", one(0110610), one(0170770), "-s-d"}, +{"subxw", one(0110500), one(0170770), "DsDd"}, +{"subxw", one(0110510), one(0170770), "-s-d"}, + +{"swap", one(0044100), one(0177770), "Ds"}, + +{"tas", one(0045300), one(0177700), "$s"}, +{"trap", one(0047100), one(0177760), "Ts"}, + +{"trapcc", one(0052374), one(0177777), ""}, +{"trapcs", one(0052774), one(0177777), ""}, +{"trapeq", one(0053774), one(0177777), ""}, +{"trapf", one(0050774), one(0177777), ""}, +{"trapge", one(0056374), one(0177777), ""}, +{"trapgt", one(0057374), one(0177777), ""}, +{"traphi", one(0051374), one(0177777), ""}, +{"traple", one(0057774), one(0177777), ""}, +{"trapls", one(0051774), one(0177777), ""}, +{"traplt", one(0056774), one(0177777), ""}, +{"trapmi", one(0055774), one(0177777), ""}, +{"trapne", one(0053374), one(0177777), ""}, +{"trappl", one(0055374), one(0177777), ""}, +{"trapt", one(0050374), one(0177777), ""}, +{"trapvc", one(0054374), one(0177777), ""}, +{"trapvs", one(0054774), one(0177777), ""}, + +{"trapcc.w", one(0052372), one(0177777), ""}, +{"trapcs.w", one(0052772), one(0177777), ""}, +{"trapeq.w", one(0053772), one(0177777), ""}, +{"trapf.w", one(0050772), one(0177777), ""}, +{"trapge.w", one(0056372), one(0177777), ""}, +{"trapgt.w", one(0057372), one(0177777), ""}, +{"traphi.w", one(0051372), one(0177777), ""}, +{"traple.w", one(0057772), one(0177777), ""}, +{"trapls.w", one(0051772), one(0177777), ""}, +{"traplt.w", one(0056772), one(0177777), ""}, +{"trapmi.w", one(0055772), one(0177777), ""}, +{"trapne.w", one(0053372), one(0177777), ""}, +{"trappl.w", one(0055372), one(0177777), ""}, +{"trapt.w", one(0050372), one(0177777), ""}, +{"trapvc.w", one(0054372), one(0177777), ""}, +{"trapvs.w", one(0054772), one(0177777), ""}, + +{"trapcc.l", one(0052373), one(0177777), ""}, +{"trapcs.l", one(0052773), one(0177777), ""}, +{"trapeq.l", one(0053773), one(0177777), ""}, +{"trapf.l", one(0050773), one(0177777), ""}, +{"trapge.l", one(0056373), one(0177777), ""}, +{"trapgt.l", one(0057373), one(0177777), ""}, +{"traphi.l", one(0051373), one(0177777), ""}, +{"traple.l", one(0057773), one(0177777), ""}, +{"trapls.l", one(0051773), one(0177777), ""}, +{"traplt.l", one(0056773), one(0177777), ""}, +{"trapmi.l", one(0055773), one(0177777), ""}, +{"trapne.l", one(0053373), one(0177777), ""}, +{"trappl.l", one(0055373), one(0177777), ""}, +{"trapt.l", one(0050373), one(0177777), ""}, +{"trapvc.l", one(0054373), one(0177777), ""}, +{"trapvs.l", one(0054773), one(0177777), ""}, + +{"trapv", one(0047166), one(0177777), ""}, + +{"tstb", one(0045000), one(0177700), ";b"}, +{"tstw", one(0045100), one(0177700), "*w"}, +{"tstl", one(0045200), one(0177700), "*l"}, + +{"unlk", one(0047130), one(0177770), "As"}, +{"unpk", one(0100600), one(0170770), "DsDd#w"}, +{"unpk", one(0100610), one(0170770), "-s-d#w"}, + /* JF floating pt stuff moved down here */ + +{"fabsb", two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fabsd", two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fabsl", two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fabsp", two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fabss", two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fabsw", two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fabsx", two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fabsx", two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt"}, + +{"facosb", two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"facosd", two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"facosl", two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"facosp", two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"facoss", two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"facosw", two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"facosx", two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"facosx", two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt"}, + +{"faddb", two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"faddd", two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"faddl", two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"faddp", two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fadds", two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"faddw", two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"faddx", two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"faddx", two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fasinb", two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fasind", two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fasinl", two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fasinp", two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fasins", two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fasinw", two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fasinx", two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fasinx", two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fatanb", two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fatand", two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fatanl", two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fatanp", two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fatans", two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fatanw", two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fatanx", two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fatanx", two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fatanhb", two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fatanhd", two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fatanhl", two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fatanhp", two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fatanhs", two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fatanhw", two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fatanhx", two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fatanhx", two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fbeq", one(0xF081), one(0xF1FF), "IdBc"}, +{"fbf", one(0xF080), one(0xF1FF), "IdBc"}, +{"fbge", one(0xF093), one(0xF1FF), "IdBc"}, +{"fbgl", one(0xF096), one(0xF1FF), "IdBc"}, +{"fbgle", one(0xF097), one(0xF1FF), "IdBc"}, +{"fbgt", one(0xF092), one(0xF1FF), "IdBc"}, +{"fble", one(0xF095), one(0xF1FF), "IdBc"}, +{"fblt", one(0xF094), one(0xF1FF), "IdBc"}, +{"fbne", one(0xF08E), one(0xF1FF), "IdBc"}, +{"fbnge", one(0xF09C), one(0xF1FF), "IdBc"}, +{"fbngl", one(0xF099), one(0xF1FF), "IdBc"}, +{"fbngle", one(0xF098), one(0xF1FF), "IdBc"}, +{"fbngt", one(0xF09D), one(0xF1FF), "IdBc"}, +{"fbnle", one(0xF09A), one(0xF1FF), "IdBc"}, +{"fbnlt", one(0xF09B), one(0xF1FF), "IdBc"}, +{"fboge", one(0xF083), one(0xF1FF), "IdBc"}, +{"fbogl", one(0xF086), one(0xF1FF), "IdBc"}, +{"fbogt", one(0xF082), one(0xF1FF), "IdBc"}, +{"fbole", one(0xF085), one(0xF1FF), "IdBc"}, +{"fbolt", one(0xF084), one(0xF1FF), "IdBc"}, +{"fbor", one(0xF087), one(0xF1FF), "IdBc"}, +{"fbseq", one(0xF091), one(0xF1FF), "IdBc"}, +{"fbsf", one(0xF090), one(0xF1FF), "IdBc"}, +{"fbsne", one(0xF09E), one(0xF1FF), "IdBc"}, +{"fbst", one(0xF09F), one(0xF1FF), "IdBc"}, +{"fbt", one(0xF08F), one(0xF1FF), "IdBc"}, +{"fbueq", one(0xF089), one(0xF1FF), "IdBc"}, +{"fbuge", one(0xF08B), one(0xF1FF), "IdBc"}, +{"fbugt", one(0xF08A), one(0xF1FF), "IdBc"}, +{"fbule", one(0xF08D), one(0xF1FF), "IdBc"}, +{"fbult", one(0xF08C), one(0xF1FF), "IdBc"}, +{"fbun", one(0xF088), one(0xF1FF), "IdBc"}, + +{"fcmpb", two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcmpd", two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcmpl", two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcmpp", two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcmps", two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcmpw", two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcmpx", two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcmpx", two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fcosb", two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcosd", two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcosl", two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcosp", two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcoss", two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcosw", two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcosx", two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fcosx", two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fcoshb", two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fcoshd", two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fcoshl", two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fcoshp", two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fcoshs", two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fcoshw", two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fcoshx", two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fcoshx", two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fdbeq", two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbf", two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbge", two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgl", two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgle", two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbgt", two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdble", two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdblt", two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbne", two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnge", two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngl", two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngle", two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbngt", two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnle", two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbnlt", two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdboge", two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbogl", two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbogt", two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbole", two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbolt", two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbor", two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbseq", two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbsf", two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbsne", two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbst", two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbt", two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbueq", two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbuge", two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbugt", two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbule", two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbult", two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw"}, +{"fdbun", two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw"}, + +{"fdivb", two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fdivd", two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fdivl", two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fdivp", two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fdivs", two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fdivw", two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fdivx", two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fdivx", two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fetoxb", two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fetoxd", two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fetoxl", two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fetoxp", two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fetoxs", two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fetoxw", two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fetoxx", two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fetoxx", two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fetoxm1b", two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fetoxm1d", two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fetoxm1l", two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fetoxm1p", two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fetoxm1s", two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fetoxm1w", two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fetoxm1x", two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fetoxm1x", two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fgetexpb", two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fgetexpd", two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fgetexpl", two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fgetexpp", two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fgetexps", two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fgetexpw", two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fgetexpx", two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fgetexpx", two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fgetmanb", two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fgetmand", two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fgetmanl", two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fgetmanp", two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fgetmans", two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fgetmanw", two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fgetmanx", two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fgetmanx", two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fintb", two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fintd", two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fintl", two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fintp", two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fints", two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fintw", two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fintx", two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fintx", two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fintrzb", two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fintrzd", two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fintrzl", two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fintrzp", two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fintrzs", two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fintrzw", two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fintrzx", two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fintrzx", two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flog10b", two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flog10d", two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flog10l", two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flog10p", two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flog10s", two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flog10w", two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flog10x", two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flog10x", two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flog2b", two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flog2d", two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flog2l", two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flog2p", two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flog2s", two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flog2w", two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flog2x", two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flog2x", two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flognb", two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flognd", two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flognl", two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flognp", two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flogns", two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flognw", two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flognx", two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flognx", two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt"}, + +{"flognp1b", two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"flognp1d", two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"flognp1l", two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"flognp1p", two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"flognp1s", two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"flognp1w", two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"flognp1x", two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"flognp1x", two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fmodb", two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fmodd", two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fmodl", two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fmodp", two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fmods", two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fmodw", two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fmodx", two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fmodx", two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fmoveb", two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7"}, /* fmove from to fp */ +{"fmoveb", two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7@b"}, /* fmove from fp to */ +{"fmoved", two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7"}, /* fmove from to fp */ +{"fmoved", two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7@F"}, /* fmove from fp to */ +{"fmovel", two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7"}, /* fmove from to fp */ +{"fmovel", two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7@l"}, /* fmove from fp to */ + /* JF for the assembler */ +{"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, +{"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii@ss8"}, +/* JF {"fmovep", two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7"}, /* fmove from to fp */ +{"fmovep", two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7@pkC"}, /* fmove.p with k-factors: */ +{"fmovep", two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7@pDk"}, /* fmove.p with k-factors: */ +{"fmoves", two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7"}, /* fmove from to fp */ +{"fmoves", two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7@f"}, /* fmove from fp to */ +{"fmovew", two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7"}, /* fmove from to fp */ +{"fmovew", two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7@w"}, /* fmove from fp to */ +{"fmovex", two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7"}, /* fmove from to fp */ +{"fmovex", two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7"}, /* fmove from to fp */ +{"fmovex", two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7@x"}, /* fmove from fp to */ + + /* fmove.l from/to system control registers: */ + +/* fmove.l and fmovem.l are the same instruction. fmovem.l makes sense in + more cases, so I've dumped fmove.l pro tem, but this is the wrong + way to solve the problem in the long run. Hmmm. */ +/* {"fmovel", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8@s"}, */ +/* {"fmovel", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii@ss8"}, */ + +{"fmovecrx", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"}, /* fmovecr.x #ccc, FPn */ +{"fmovecr", two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7"}, + +{"fmovemx", two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s"}, /* fmovem.x to autodecrement, static and dynamic */ +{"fmovemx", two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s"}, /* fmovem.x to autodecrement, static and dynamic */ + +{"fmovemx", two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x to control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x to control, static and dynamic: */ + +{"fmovemx", two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id#3+s"}, /* fmovem.x from autoincrement, static and dynamic: */ +{"fmovemx", two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "IiDk+s"}, /* fmovem.x from autoincrement, static and dynamic: */ + +{"fmovemx", two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id#3&s"}, /* fmovem.x from control, static and dynamic: */ +{"fmovemx", two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "IiDk&s"}, /* fmovem.x from control, static and dynamic: */ + +/* fmoveml and fmovel are the same instruction. This may cause some + confusion in the assembler. */ + +{"fmoveml", two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Ii#8%s"}, /* fmovem.l to/from system control register(s): */ +{"fmoveml", two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii%s#8"}, /* fmovem.l to/from system control register(s): */ + +{"fmulb", two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fmuld", two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fmull", two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fmulp", two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fmuls", two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fmulw", two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fmulx", two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fmulx", two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fnegb", two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fnegd", two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fnegl", two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fnegp", two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fnegs", two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fnegw", two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fnegx", two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fnegx", two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fremb", two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fremd", two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"freml", two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fremp", two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"frems", two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fremw", two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fremx", two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fremx", two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"frestore", one(0xF140), one(0xF1C0), "Id&s"}, +{"frestore", one(0xF158), one(0xF1F8), "Id+s"}, +{"fsave", one(0xF100), one(0xF1C0), "Id&s"}, +{"fsave", one(0xF120), one(0xF1F8), "Id-s"}, + +{"fsincosb", two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF7FC"}, +{"fsincosd", two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF7FC"}, +{"fsincosl", two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF7FC"}, +{"fsincosp", two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF7FC"}, +{"fsincoss", two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF7FC"}, +{"fsincosw", two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF7FC"}, +{"fsincosx", two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F7FC"}, +{"fsincosx", two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF7FC"}, + +{"fscaleb", two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fscaled", two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fscalel", two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fscalep", two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fscales", two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fscalew", two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fscalex", two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fscalex", two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fseq", two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsf", two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsge", two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsgl", two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsgle", two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsgt", two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsle", two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fslt", two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsne", two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsnge", two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsngl", two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsngle", two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsngt", two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsnle", two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsnlt", two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsoge", two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsogl", two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsogt", two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsole", two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsolt", two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsor", two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsseq", two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fssf", two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fssne", two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsst", two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fst", two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsueq", two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsuge", two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsugt", two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsule", two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsult", two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii@s"}, +{"fsun", two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii@s"}, + +{"fsgldivb", two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsgldivd", two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsgldivl", two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsgldivp", two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsgldivs", two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsgldivw", two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsgldivx", two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsgldivx", two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fsglmulb", two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsglmuld", two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsglmull", two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsglmulp", two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsglmuls", two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsglmulw", two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsglmulx", two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsglmulx", two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"fsinb", two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsind", two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsinl", two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsinp", two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsins", two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsinw", two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsinx", two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsinx", two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsinhb", two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsinhd", two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsinhl", two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsinhp", two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsinhs", two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsinhw", two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsinhx", two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsinhx", two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsqrtb", two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsqrtd", two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsqrtl", two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsqrtp", two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsqrts", two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsqrtw", two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsqrtx", two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"fsqrtx", two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt"}, + +{"fsubb", two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"fsubd", two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"fsubl", two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"fsubp", two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"fsubs", two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"fsubw", two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"fsubx", two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"fsubx", two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7"}, + +{"ftanb", two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftand", two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftanl", two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftanp", two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftans", two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftanw", two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftanx", two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftanx", two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftanhb", two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftanhd", two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftanhl", two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftanhp", two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftanhs", two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftanhw", two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftanhx", two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftanhx", two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftentoxb", two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftentoxd", two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftentoxl", two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftentoxp", two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftentoxs", two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftentoxw", two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftentoxx", two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftentoxx", two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt"}, + +{"ftrapeq", two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapf", two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapge", two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgl", two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgle", two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapgt", two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftraple", two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftraplt", two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapne", two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnge", two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngl", two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngle", two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapngt", two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnle", two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapnlt", two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapoge", two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapogl", two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapogt", two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapole", two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapolt", two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapor", two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapseq", two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapsf", two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapsne", two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapst", two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapt", two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapueq", two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapuge", two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapugt", two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapule", two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapult", two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii"}, +{"ftrapun", two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii"}, + +{"ftrapeqw", two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapfw", two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapgew", two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapglw", two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapglew", two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapgtw", two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraplew", two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapltw", two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnew", two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapngew", two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnglw", two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnglew", two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapngtw", two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnlew", two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapnltw", two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapogew", two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapoglw", two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapogtw", two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapolew", two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapoltw", two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraporw", two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapseqw", two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapsfw", two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapsnew", two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapstw", two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftraptw", two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapueqw", two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapugew", two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapugtw", two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapulew", two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapultw", two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w"}, +{"ftrapunw", two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w"}, + +{"ftrapeql", two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapfl", two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgel", two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgll", two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapglel", two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapgtl", two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraplel", two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapltl", two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnel", two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngel", two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngll", two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnglel", two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapngtl", two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnlel", two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapnltl", two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogel", two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogll", two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapogtl", two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapolel", two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapoltl", two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraporl", two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapseql", two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapsfl", two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapsnel", two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapstl", two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftraptl", two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapueql", two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapugel", two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapugtl", two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapulel", two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapultl", two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l"}, +{"ftrapunl", two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l"}, + +{"ftstb", two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b"}, +{"ftstd", two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F"}, +{"ftstl", two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l"}, +{"ftstp", two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p"}, +{"ftsts", two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f"}, +{"ftstw", two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w"}, +{"ftstx", two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8"}, +{"ftstx", two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x"}, + +{"ftwotoxb", two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7"}, +{"ftwotoxd", two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7"}, +{"ftwotoxl", two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7"}, +{"ftwotoxp", two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7"}, +{"ftwotoxs", two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7"}, +{"ftwotoxw", two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7"}, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7"}, +{"ftwotoxx", two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7"}, +{"ftwotoxx", two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt"}, + +/* Alternate mnemonics for SUN */ + +{"jbsr", one(0060400), one(0177400), "Bg"}, +{"jbsr", one(0047200), one(0177700), "!s"}, +{"jra", one(0060000), one(0177400), "Bg"}, +{"jra", one(0047300), one(0177700), "!s"}, + +{"jhi", one(0061000), one(0177400), "Bg"}, +{"jls", one(0061400), one(0177400), "Bg"}, +{"jcc", one(0062000), one(0177400), "Bg"}, +{"jcs", one(0062400), one(0177400), "Bg"}, +{"jne", one(0063000), one(0177400), "Bg"}, +{"jeq", one(0063400), one(0177400), "Bg"}, +{"jvc", one(0064000), one(0177400), "Bg"}, +{"jvs", one(0064400), one(0177400), "Bg"}, +{"jpl", one(0065000), one(0177400), "Bg"}, +{"jmi", one(0065400), one(0177400), "Bg"}, +{"jge", one(0066000), one(0177400), "Bg"}, +{"jlt", one(0066400), one(0177400), "Bg"}, +{"jgt", one(0067000), one(0177400), "Bg"}, +{"jle", one(0067400), one(0177400), "Bg"}, + +{"movql", one(0070000), one(0170400), "MsDd"}, +{"moveql", one(0070000), one(0170400), "MsDd"}, +{"moval", one(0020100), one(0170700), "*lAd"}, +{"movaw", one(0030100), one(0170700), "*wAd"}, +{"movb", one(0010000), one(0170000), ";b$d"}, /* mov */ +{"movl", one(0020000), one(0170000), "*l$d"}, +{"movl", one(0020100), one(0170700), "*lAd"}, +{"movl", one(0047140), one(0177770), "AsUd"}, /* mov to USP */ +{"movl", one(0047150), one(0177770), "UdAs"}, /* mov from USP */ +{"movl", one(0070000), one(0170400), "MsDd"}, /* movq written as mov */ +{"movml", one(0044300), one(0177700), "#w&s"}, /* movm reg to mem. */ +{"movml", one(0044340), one(0177770), "#w-s"}, /* movm reg to autodecrement. */ +{"movml", one(0046300), one(0177700), "!s#w"}, /* movm mem to reg. */ +{"movml", one(0046330), one(0177770), "+s#w"}, /* movm autoinc to reg. */ +{"movmw", one(0044200), one(0177700), "#w&s"}, /* movm reg to mem. */ +{"movmw", one(0044240), one(0177770), "#w-s"}, /* movm reg to autodecrement. */ +{"movmw", one(0046200), one(0177700), "!s#w"}, /* movm mem to reg. */ +{"movmw", one(0046230), one(0177770), "+s#w"}, /* movm autoinc to reg. */ +{"movpl", one(0000510), one(0170770), "dsDd"}, /* memory to register */ +{"movpl", one(0000710), one(0170770), "Ddds"}, /* register to memory */ +{"movpw", one(0000410), one(0170770), "dsDd"}, /* memory to register */ +{"movpw", one(0000610), one(0170770), "Ddds"}, /* register to memory */ +{"movq", one(0070000), one(0170400), "MsDd"}, +{"movw", one(0030000), one(0170000), "*w$d"}, +{"movw", one(0030100), one(0170700), "*wAd"}, /* mova, written as mov */ +{"movw", one(0040300), one(0177700), "Ss$s"}, /* Move from sr */ +{"movw", one(0041300), one(0177700), "Cs$s"}, /* Move from ccr */ +{"movw", one(0042300), one(0177700), ";wCd"}, /* mov to ccr */ +{"movw", one(0043300), one(0177700), ";wSd"}, /* mov to sr */ +/* movc not done*/ + +{"movsb", two(0007000, 0), two(0177700, 07777), "~sR1"}, +{"movsb", two(0007000, 04000), two(0177700, 07777), "R1~s"}, +{"movsl", two(0007200, 0), two(0177700, 07777), "~sR1"}, +{"movsl", two(0007200, 04000), two(0177700, 07777), "R1~s"}, +{"movsw", two(0007100, 0), two(0177700, 07777), "~sR1"}, +{"movsw", two(0007100, 04000), two(0177700, 07777), "R1~s"}, +}; + +int numopcodes=sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]); + +struct m68k_opcode *endop = m68k_opcodes+sizeof(m68k_opcodes)/sizeof(m68k_opcodes[0]);; diff --git a/gdb/m68k-pinsn.c b/gdb/m68k-pinsn.c new file mode 100644 index 00000000000..a22a36a5b57 --- /dev/null +++ b/gdb/m68k-pinsn.c @@ -0,0 +1,773 @@ +/* Print m68k instructions for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "m68k-opcode.h" + +/* 68k instructions are never longer than this many bytes. */ +#define MAXLEN 22 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0]) + +extern char *reg_names[]; +char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", + "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"}; + +static unsigned char *print_insn_arg (); +static unsigned char *print_indexed (); +static void print_base (); +static int fetch_arg (); + +#define NEXTBYTE(p) (p += 2, ((char *)p)[-1]) + +#define NEXTWORD(p) \ + (p += 2, ((((char *)p)[-2]) << 8) + p[-1]) + +#define NEXTLONG(p) \ + (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) + +#define NEXTSINGLE(p) \ + (p += 4, *((float *)(p - 4))) + +#define NEXTDOUBLE(p) \ + (p += 8, *((double *)(p - 8))) + +#define NEXTEXTEND(p) \ + (p += 12, 0.0) /* Need a function to convert from extended to double + precision... */ + +#define NEXTPACKED(p) \ + (p += 12, 0.0) /* Need a function to convert from packed to double + precision. Actually, it's easier to print a + packed number than a double anyway, so maybe + there should be a special case to handle this... */ + +/* Print the m68k instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register unsigned char *p; + register char *d; + register int bestmask; + int best; + + read_memory (memaddr, buffer, MAXLEN); + + bestmask = 0; + best = -1; + for (i = 0; i < NOPCODES; i++) + { + register unsigned int opcode = m68k_opcodes[i].opcode; + register unsigned int match = m68k_opcodes[i].match; + if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) + && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) + && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) + && ((0xff & buffer[3] & match) == (0xff & opcode))) + { + /* Don't use for printout the variants of divul and divsl + that have the same register number in two places. + The more general variants will match instead. */ + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 'D') + break; + + /* Don't use for printout the variants of most floating + point coprocessor instructions which use the same + register number in two places, as above. */ + if (*d == 0) + for (d = m68k_opcodes[i].args; *d; d += 2) + if (d[1] == 't') + break; + + if (*d == 0 && match > bestmask) + { + best = i; + bestmask = match; + } + } + } + + /* Handle undefined instructions. */ + if (best < 0) + { + fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]); + return 2; + } + + fprintf (stream, "%s", m68k_opcodes[best].name); + + /* Point at first word of argument data, + and at descriptor for first argument. */ + p = buffer + 2; + + /* Why do this this way? -MelloN */ + for (d = m68k_opcodes[best].args; *d; d += 2) + { + if (d[0] == '#') + { + if (d[1] == 'l' && p - buffer < 6) + p = buffer + 6; + else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) + p = buffer + 4; + } + if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4) + p = buffer + 4; + if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6) + p = buffer + 6; + } + + d = m68k_opcodes[best].args; + + if (*d) + fputc (' ', stream); + + while (*d) + { + p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream); + d += 2; + if (*d && *(d - 2) != 'I' && *d != 'k') + fprintf (stream, ","); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, buffer, p, addr, stream) + char *d; + unsigned char *buffer; + register unsigned char *p; + CORE_ADDR addr; /* PC for this arg to be relative to */ + FILE *stream; +{ + register int val; + register int place = d[1]; + int regno; + register char *regname; + register unsigned char *p1; + register double flval; + int flt_p; + + switch (*d) + { + case 'C': + fprintf (stream, "ccr"); + break; + + case 'S': + fprintf (stream, "sr"); + break; + + case 'U': + fprintf (stream, "usp"); + break; + + case 'J': + { + static struct { char *name; int value; } names[] + = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, + {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, + {"msp", 0x803}, {"isp", 0x804}}; + + val = fetch_arg (buffer, place, 12); + for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) + if (names[regno].value == val) + { + fprintf (stream, names[regno].name); + break; + } + if (regno < 0) + fprintf (stream, "%d", val); + } + break; + + case 'Q': + val = fetch_arg (buffer, place, 3); + if (val == 0) val = 8; + fprintf (stream, "#%d", val); + break; + + case 'M': + val = fetch_arg (buffer, place, 8); + if (val & 0x80) + val = val - 0x100; + fprintf (stream, "#%d", val); + break; + + case 'T': + val = fetch_arg (buffer, place, 4); + fprintf (stream, "#%d", val); + break; + + case 'D': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]); + break; + + case 'A': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]); + break; + + case 'R': + fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]); + break; + + case 'F': + fprintf (stream, "fp%d", fetch_arg (buffer, place, 3)); + break; + + case 'O': + val = fetch_arg (buffer, place, 6); + if (val & 0x20) + fprintf (stream, "%s", reg_names [val & 7]); + else + fprintf (stream, "%d", val); + break; + + case '+': + fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case '-': + fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]); + break; + + case 'k': + if (place == 'k') + fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]); + else if (place == 'C') + { + val = fetch_arg (buffer, place, 7); + if ( val > 63 ) /* This is a signed constant. */ + val -= 128; + fprintf (stream, "{#%d}", val); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + break; + + case '#': + p1 = buffer + 2; + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == '3') + val = fetch_arg (buffer, place, 8); + else if (place == 'b') + val = NEXTBYTE (p1); + else if (place == 'w') + val = NEXTWORD (p1); + else if (place == 'l') + val = NEXTLONG (p1); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case '^': + if (place == 's') + val = fetch_arg (buffer, place, 4); + else if (place == 'C') + val = fetch_arg (buffer, place, 7); + else if (place == '8') + val = fetch_arg (buffer, place, 3); + else if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + fprintf (stream, "#%d", val); + break; + + case 'B': + if (place == 'b') + val = NEXTBYTE (p); + else if (place == 'w') + val = NEXTWORD (p); + else if (place == 'l') + val = NEXTLONG (p); + else if (place == 'g') + { + val = ((char *)buffer)[1]; + if (val == 0) + val = NEXTWORD (p); + else if (val == -1) + val = NEXTLONG (p); + } + else if (place == 'c') + { + if (buffer[1] & 0x40) /* If bit six is one, long offset */ + val = NEXTLONG (p); + else + val = NEXTWORD (p); + } + else + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + + print_address (addr + val, stream); + break; + + case 'd': + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, fetch_arg (buffer, place, 3)); + break; + + case 's': + fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]); + break; + + case 'I': + val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */ + if (val != 1) /* Unusual coprocessor ID? */ + fprintf (stream, "(cpid=%d) ", val); + if (place == 'i') + p += 2; /* Skip coprocessor extended operands */ + break; + + case '*': + case '~': + case '%': + case ';': + case '@': + case '!': + case '$': + case '?': + case '/': + case '&': + + if (place == 'd') + { + val = fetch_arg (buffer, 'x', 6); + val = ((val & 7) << 3) + ((val >> 3) & 7); + } + else + val = fetch_arg (buffer, 's', 6); + + /* Get register number assuming address register. */ + regno = (val & 7) + 8; + regname = reg_names[regno]; + switch (val >> 3) + { + case 0: + fprintf (stream, "%s", reg_names[val]); + break; + + case 1: + fprintf (stream, "%s", regname); + break; + + case 2: + fprintf (stream, "(%s)", regname); + break; + + case 3: + fprintf (stream, "(%s)+", regname); + break; + + case 4: + fprintf (stream, "-(%s)", regname); + break; + + case 5: + val = NEXTWORD (p); + fprintf (stream, "%d(%s)", val, regname); + break; + + case 6: + p = print_indexed (regno, p, addr, stream); + break; + + case 7: + switch (val & 7) + { + case 0: + val = NEXTWORD (p); + fprintf (stream, "@#"); + print_address (val, stream); + break; + + case 1: + val = NEXTLONG (p); + fprintf (stream, "@#"); + print_address (val, stream); + break; + + case 2: + val = NEXTWORD (p); + print_address (addr + val, stream); + break; + + case 3: + p = print_indexed (-1, p, addr, stream); + break; + + case 4: + flt_p = 1; /* Assume it's a float... */ + switch( place ) + { + case 'b': + val = NEXTBYTE (p); + flt_p = 0; + break; + + case 'w': + val = NEXTWORD (p); + flt_p = 0; + break; + + case 'l': + val = NEXTLONG (p); + flt_p = 0; + break; + + case 'f': + flval = NEXTSINGLE(p); + break; + + case 'F': + flval = NEXTDOUBLE(p); + break; + + case 'x': + flval = NEXTEXTEND(p); + break; + + case 'p': + flval = NEXTPACKED(p); + break; + + default: + error ("Invalid arg format in opcode table: \"%c%c\".", + *d, place); + } + if ( flt_p ) /* Print a float? */ + fprintf (stream, "#%g", flval); + else + fprintf (stream, "#%d", val); + break; + + default: + fprintf (stream, "", val); + } + } + break; + + default: + error ("Invalid arg format in opcode table: \"%c\".", *d); + } + + return (unsigned char *) p; +} + +/* Fetch BITS bits from a position in the instruction specified by CODE. + CODE is a "place to put an argument", or 'x' for a destination + that is a general address (mode and register). + BUFFER contains the instruction. */ + +static int +fetch_arg (buffer, code, bits) + unsigned char *buffer; + char code; + int bits; +{ + register int val; + switch (code) + { + case 's': + val = buffer[1]; + break; + + case 'd': /* Destination, for register or quick. */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 9; + break; + + case 'x': /* Destination, for general arg */ + val = (buffer[0] << 8) + buffer[1]; + val >>= 6; + break; + + case 'k': + val = (buffer[3] >> 4); + break; + + case 'C': + val = buffer[3]; + break; + + case '1': + val = (buffer[2] << 8) + buffer[3]; + val >>= 12; + break; + + case '2': + val = (buffer[2] << 8) + buffer[3]; + val >>= 6; + break; + + case '3': + case 'j': + val = (buffer[2] << 8) + buffer[3]; + break; + + case '4': + val = (buffer[4] << 8) + buffer[5]; + val >>= 12; + break; + + case '5': + val = (buffer[4] << 8) + buffer[5]; + val >>= 6; + break; + + case '6': + val = (buffer[4] << 8) + buffer[5]; + break; + + case '7': + val = (buffer[2] << 8) + buffer[3]; + val >>= 7; + break; + + case '8': + val = (buffer[2] << 8) + buffer[3]; + val >>= 10; + break; + + default: + abort (); + } + + switch (bits) + { + case 3: + return val & 7; + case 4: + return val & 017; + case 5: + return val & 037; + case 6: + return val & 077; + case 7: + return val & 0177; + case 8: + return val & 0377; + case 12: + return val & 07777; + default: + abort (); + } +} + +/* Print an indexed argument. The base register is BASEREG (-1 for pc). + P points to extension word, in buffer. + ADDR is the nominal core address of that extension word. */ + +static unsigned char * +print_indexed (basereg, p, addr, stream) + int basereg; + unsigned char *p; + FILE *stream; + CORE_ADDR addr; +{ + register int word; + static char *scales[] = {"", "*2", "*4", "*8"}; + register int base_disp; + register int outer_disp; + char buf[40]; + + word = NEXTWORD (p); + + /* Generate the text for the index register. + Where this will be output is not yet determined. */ + sprintf (buf, "[%s.%c%s]", + reg_names[(word >> 12) & 0xf], + (word & 0x800) ? 'l' : 'w', + scales[(word >> 9) & 3]); + + /* Handle the 68000 style of indexing. */ + + if ((word & 0x100) == 0) + { + print_base (basereg, + ((word & 0x80) ? word | 0xff00 : word & 0xff) + + ((basereg == -1) ? addr : 0), + stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Handle the generalized kind. */ + /* First, compute the displacement to add to the base register. */ + + if (word & 0200) + basereg = -2; + if (word & 0100) + buf[0] = 0; + base_disp = 0; + switch ((word >> 4) & 3) + { + case 2: + base_disp = NEXTWORD (p); + break; + case 3: + base_disp = NEXTLONG (p); + } + if (basereg == -1) + base_disp += addr; + + /* Handle single-level case (not indirect) */ + + if ((word & 7) == 0) + { + print_base (basereg, base_disp, stream); + fprintf (stream, "%s", buf); + return p; + } + + /* Two level. Compute displacement to add after indirection. */ + + outer_disp = 0; + switch (word & 3) + { + case 2: + outer_disp = NEXTWORD (p); + break; + case 3: + outer_disp = NEXTLONG (p); + } + + fprintf (stream, "%d(", outer_disp); + print_base (basereg, base_disp, stream); + + /* If postindexed, print the closeparen before the index. */ + if (word & 4) + fprintf (stream, ")%s", buf); + /* If preindexed, print the closeparen after the index. */ + else + fprintf (stream, "%s)", buf); + + return p; +} + +/* Print a base register REGNO and displacement DISP, on STREAM. + REGNO = -1 for pc, -2 for none (suppressed). */ + +static void +print_base (regno, disp, stream) + int regno; + int disp; + FILE *stream; +{ + if (regno == -2) + fprintf (stream, "%d", disp); + else if (regno == -1) + fprintf (stream, "0x%x", disp); + else + fprintf (stream, "%d(%s)", disp, reg_names[regno]); +} + +/* This is not part of insn printing, but it is machine-specific, + so this is a convenient place to put it. + + Convert a 68881 extended float to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +#ifdef mac_aux +#ifdef __STDC__ +#define asm16(str) asm ("short " str#) +#else +#define asm16(str) asm ("short str") +#endif +#else +#ifdef __STDC__ +#define asm16(str) asm (".word " str#) +#else +#define asm16(str) asm (".word str") +#endif +#endif + +convert_from_68881 (from, to) + char *from; + double *to; +{ +#if 0 + asm ("movl a6@(8),a0"); + asm ("movl a6@(12),a1"); + asm ("fmovex a0@,fp0"); + asm ("fmoved fp0,a1@"); +#else + /* Hand-assemble those insns since some assemblers lose + and some have different syntax. */ + asm16 (020156); + asm16 (8); + asm16 (021156); + asm16 (12); + asm16 (0xf210); + asm16 (0x4800); + asm16 (0xf211); + asm16 (0x7400); +#endif +} + +/* The converse: convert the double *FROM to an extended float + and store where TO points. */ + +convert_to_68881 (from, to) + double *from; + char *to; +{ +#if 0 + asm ("movl a6@(8),a0"); + asm ("movl a6@(12),a1"); + asm ("fmoved a0@,fp0"); + asm ("fmovex fp0,a1@"); +#else + /* Hand-assemble those insns since some assemblers lose. */ + asm16 (020156); + asm16 (8); + asm16 (021156); + asm16 (12); + asm16 (0xf210); + asm16 (0x5400); + asm16 (0xf211); + asm16 (0x6800); +#endif +} diff --git a/gdb/main.c b/gdb/main.c new file mode 100644 index 00000000000..d6e993e5a39 --- /dev/null +++ b/gdb/main.c @@ -0,0 +1,1072 @@ +/* Top level for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include +#include +#include +#include +#include "defs.h" +#include "command.h" +#include "param.h" + +#ifdef SET_STACK_LIMIT_HUGE +#include +#include +#endif + +/* Version number of GDB, as a string. */ + +extern char *version; + +/* Chain containing all defined commands. */ + +struct cmd_list_element *cmdlist; + +/* Chain containing all defined info subcommands. */ + +struct cmd_list_element *infolist; + +/* stdio stream that command input is being read from. */ + +FILE *instream; + +/* Nonzero if we should refrain from using an X window. */ + +int inhibit_windows = 0; + +/* Function to call before reading a command, if nonzero. + The function receives two args: an input stream, + and a prompt string. */ + +void (*window_hook) (); + +void free_command_lines (); +char *read_line (); +static void initialize_main (); +void command_loop (); +static void source_command (); +void print_gdb_version (); + +/* gdb prints this when reading a command interactively */ +static char *prompt; + +/* Buffer used for reading command lines, and the size + allocated for it so far. */ + +char *line; +int linesize; + +/* This is how `error' returns to command level. */ + +jmp_buf to_top_level; + +return_to_top_level () +{ + quit_flag = 0; + immediate_quit = 0; + clear_breakpoint_commands (); + clear_momentary_breakpoints (); + do_cleanups (0); + longjmp (to_top_level, 1); +} + +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + extern void request_quit (); + int count; + int inhibit_gdbinit = 0; + int quiet = 0; + int batch = 0; + register int i; + + quit_flag = 0; + linesize = 100; + line = (char *) xmalloc (linesize); + instream = stdin; + +#ifdef SET_STACK_LIMIT_HUGE + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca (particularly stringtab + * in dbxread.c) does not fail. */ + getrlimit (RLIMIT_STACK, &rlim); + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } +#endif /* SET_STACK_LIMIT_HUGE */ + + /* Look for flag arguments. */ + + for (i = 1; i < argc; i++) + { + if (!strcmp (argv[i], "-q") || !strcmp (argv[i], "-quiet")) + quiet = 1; + else if (!strcmp (argv[i], "-nx")) + inhibit_gdbinit = 1; + else if (!strcmp (argv[i], "-nw")) + inhibit_windows = 1; + else if (!strcmp (argv[i], "-batch")) + batch = 1, quiet = 1; + else if (argv[i][0] == '-') + i++; + } + + /* Run the init function of each source file */ + + initialize_all_files (); + initialize_main (); /* But that omits this file! Do it now */ + + signal (SIGINT, request_quit); + signal (SIGQUIT, SIG_IGN); + + if (!quiet) + print_gdb_version (); + + /* Process the command line arguments. */ + + count = 0; + for (i = 1; i < argc; i++) + { + register char *arg = argv[i]; + /* Args starting with - say what to do with the following arg + as a filename. */ + if (arg[0] == '-') + { + extern void exec_file_command (), symbol_file_command (); + extern void core_file_command (), directory_command (); + extern void tty_command (); + + if (!strcmp (arg, "-q") || !strcmp (arg, "-nx") + || !strcmp (arg, "quiet") || !strcmp (arg, "-batch")) + /* Already processed above */ + continue; + + if (++i == argc) + fprintf (stderr, "No argument follows \"%s\".\n", arg); + if (!setjmp (to_top_level)) + { + /* -s foo: get syms from foo. -e foo: execute foo. + -se foo: do both with foo. -c foo: use foo as core dump. */ + if (!strcmp (arg, "-se")) + { + exec_file_command (argv[i], !batch); + symbol_file_command (argv[i], !batch); + } + else if (!strcmp (arg, "-s") || !strcmp (arg, "-symbols")) + symbol_file_command (argv[i], !batch); + else if (!strcmp (arg, "-e") || !strcmp (arg, "-exec")) + exec_file_command (argv[i], !batch); + else if (!strcmp (arg, "-c") || !strcmp (arg, "-core")) + core_file_command (argv[i], !batch); + /* -x foo: execute commands from foo. */ + else if (!strcmp (arg, "-x") || !strcmp (arg, "-command") + || !strcmp (arg, "-commands")) + source_command (argv[i]); + /* -d foo: add directory `foo' to source-file directory + search-list */ + else if (!strcmp (arg, "-d") || !strcmp (arg, "-dir") + || !strcmp (arg, "-directory")) + directory_command (argv[i], 0); + /* -t /def/ttyp1: use /dev/ttyp1 for inferior I/O. */ + else if (!strcmp (arg, "-t") || !strcmp (arg, "-tty")) + tty_command (argv[i], 0); + else + error ("Unknown command-line switch: \"%s\"\n", arg); + } + } + else + { + /* Args not thus accounted for + are treated as, first, the symbol/executable file + and, second, the core dump file. */ + count++; + if (!setjmp (to_top_level)) + switch (count) + { + case 1: + exec_file_command (arg, !batch); + symbol_file_command (arg, !batch); + break; + + case 2: + core_file_command (arg, !batch); + break; + + case 3: + fprintf (stderr, "Excess command line args ignored. (%s%s)\n", + arg, (i == argc - 1) ? "" : " ..."); + } + } + } + + /* Read init file, if it exists in home directory */ + if (getenv ("HOME")) + { + char *s; + s = (char *) xmalloc (strlen (getenv ("HOME")) + 10); + strcpy (s, getenv ("HOME")); + strcat (s, "/.gdbinit"); + if (!inhibit_gdbinit && access (s, R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (s); + } + + /* Read init file, if it exists in current directory. */ + if (!inhibit_gdbinit && access (".gdbinit", R_OK) == 0) + if (!setjmp (to_top_level)) + source_command (".gdbinit"); + + if (batch) + fatal ("Attempt to read commands from stdin in batch mode."); + + if (!quiet) + printf ("Type \"help\" for a list of commands.\n"); + + /* The command loop. */ + + while (1) + { + if (!setjmp (to_top_level)) + command_loop (); + clearerr (stdin); /* Don't get hung if C-d is typed. */ + } +} + +/* Execute the line P as a command. + Pass FROM_TTY as second argument to the defining function. */ + +void +execute_command (p, from_tty) + char *p; + int from_tty; +{ + register struct cmd_list_element *c; + register struct command_line *cmdlines; + + free_all_values (); + while (*p == ' ' || *p == '\t') p++; + if (*p) + { + c = lookup_cmd (&p, cmdlist, "", 0); + if (c->function == 0) + error ("That is not a command, just a help topic."); + else if (c->class == (int) class_user) + { + if (*p) + error ("User-defined commands cannot take command-line arguments: \"%s\"", + p); + cmdlines = (struct command_line *) c->function; + if (cmdlines == (struct command_line *) 0) + /* Null command */ + return; + while (cmdlines) + { + execute_command (cmdlines->line, 0); + cmdlines = cmdlines->next; + } + } + else + /* Pass null arg rather than an empty one. */ + (*c->function) (*p ? p : 0, from_tty); + } +} + +static void +do_nothing () +{ +} + +/* Read commands from `instream' and execute them + until end of file. */ +void +command_loop () +{ + struct cleanup *old_chain; + while (!feof (instream)) + { + if (instream == stdin) + printf ("%s", prompt); + fflush (stdout); + + if (window_hook && instream == stdin) + (*window_hook) (instream, prompt); + + quit_flag = 0; + old_chain = make_cleanup (do_nothing, 0); + execute_command (read_line (instream == stdin), instream == stdin); + /* Do any commands attached to breakpoint we stopped at. */ + do_breakpoint_commands (); + do_cleanups (old_chain); + } +} + +static void +stop_sig () +{ + signal (SIGTSTP, SIG_DFL); + sigsetmask (0); + kill (getpid (), SIGTSTP); + signal (SIGTSTP, stop_sig); + printf ("%s", prompt); + fflush (stdout); + + /* Forget about any previous command -- null line now will do nothing. */ + *line = 0; +} + +/* Commands call this if they do not want to be repeated by null lines. */ + +void +dont_repeat () +{ + *line = 0; +} + +/* Read one line from the command input stream `instream' + into the buffer `line' (whose current length is `linesize'). + The buffer is made bigger as necessary. + Returns the address of the start of the line. */ + +char * +read_line (repeat) + int repeat; +{ + register char *p = line; + register char *p1; + register int c; + char *nline; + + /* Control-C quits instantly if typed while in this loop + since it should not wait until the user types a newline. */ + immediate_quit++; + signal (SIGTSTP, stop_sig); + + while (1) + { + c = fgetc (instream); + if (c == -1 || c == '\n') + break; + if (p - line == linesize - 1) + { + linesize *= 2; + nline = (char *) xrealloc (line, linesize); + p += nline - line; + line = nline; + } + *p++ = c; + } + + signal (SIGTSTP, SIG_DFL); + immediate_quit--; + + /* If we just got an empty line, and that is supposed + to repeat the previous command, leave the last input unchanged. */ + if (p == line && repeat) + return line; + + /* If line is a comment, clear it out. */ + p1 = line; + while ((c = *p1) == ' ' || c == '\t') p1++; + if (c == '#') + p = line; + + *p = 0; + + return line; +} + +/* Read lines from the input stream + and accumulate them in a chain of struct command_line's + which is then returned. */ + +struct command_line * +read_command_lines () +{ + struct command_line *first = 0; + register struct command_line *next, *tail = 0; + register char *p, *p1; + struct cleanup *old_chain = 0; + + while (1) + { + dont_repeat (); + p = read_line (1); + /* Remove leading and trailing blanks. */ + while (*p == ' ' || *p == '\t') p++; + p1 = p + strlen (p); + while (p1 != p && (p1[-1] == ' ' || p1[-1] == '\t')) p1--; + + /* Is this "end"? */ + if (p1 - p == 3 && !strncmp (p, "end", 3)) + break; + + /* No => add this line to the chain of command lines. */ + next = (struct command_line *) xmalloc (sizeof (struct command_line)); + next->line = savestring (p, p1 - p); + next->next = 0; + if (tail) + { + tail->next = next; + } + else + { + /* We just read the first line. + From now on, arrange to throw away the lines we have + if we quit or get an error while inside this function. */ + first = next; + old_chain = make_cleanup (free_command_lines, &first); + } + tail = next; + } + + dont_repeat (); + + /* Now we are about to return the chain to our caller, + so freeing it becomes his responsibility. */ + if (first) + discard_cleanups (old_chain); + return first; +} + +/* Free a chain of struct command_line's. */ + +void +free_command_lines (lptr) + struct command_line **lptr; +{ + register struct command_line *l = *lptr; + register struct command_line *next; + + while (l) + { + next = l->next; + free (l->line); + free (l); + l = next; + } +} + +/* Add an element to the list of info subcommands. */ + +void +add_info (name, fun, doc) + char *name; + void (*fun) (); + char *doc; +{ + add_cmd (name, 0, fun, doc, &infolist); +} + +/* Add an alias to the list of info subcommands. */ + +void +add_info_alias (name, oldname, abbrev_flag) + char *name; + char *oldname; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, 0, abbrev_flag, &infolist); +} + +/* The "info" command is defined as a prefix, with allow_unknown = 0. + Therefore, its own definition is called only for "info" with no args. */ + +static void +info_command () +{ + printf ("\"info\" must be followed by the name of an info command.\n"); + help_cmd (0, infolist, "info ", -1, stdout); +} + +/* Add an element to the list of commands. */ + +void +add_com (name, class, fun, doc) + char *name; + int class; + void (*fun) (); + char *doc; +{ + add_cmd (name, class, fun, doc, &cmdlist); +} + +/* Add an alias or abbreviation command to the list of commands. */ + +void +add_com_alias (name, oldname, class, abbrev_flag) + char *name; + char *oldname; + int class; + int abbrev_flag; +{ + add_alias_cmd (name, oldname, class, abbrev_flag, &cmdlist); +} + +void +error_no_arg (why) + char *why; +{ + error ("Argument required (%s).", why); +} + +static void +help_command (command, from_tty) + char *command; + int from_tty; /* Ignored */ +{ + help_cmd (command, cmdlist, "", -2, stdout); +} + +static void +validate_comname (comname) + char *comname; +{ + register char *p; + + if (comname == 0) + error_no_arg ("name of command to define"); + + p = comname; + while (*p) + { + if (!(*p >= 'A' && *p <= 'Z') + && !(*p >= 'a' && *p <= 'z') + && !(*p >= '1' && *p <= '9') + && *p != '-') + error ("Junk in argument list: \"%s\"", p); + p++; + } +} + +static void +define_command (comname, from_tty) + char *comname; + int from_tty; +{ + register struct command_line *cmds; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", -1); + if (c) + { + if (c->class == (int) class_user || c->class == (int) class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, comname)) + error ("Command \"%s\" not redefined.", comname); + } + + if (from_tty) + printf ("Type commands for definition of \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + comname = savestring (comname, strlen (comname)); + + cmds = read_command_lines (); + + if (c && c->class == (int) class_user) + free_command_lines (&c->function); + + add_com (comname, class_user, cmds, + (c && c->class == (int) class_user) + ? c->doc : savestring ("User-defined.", 13)); +} + +static void +document_command (comname, from_tty) + char *comname; + int from_tty; +{ + struct command_line *doclines; + register struct cmd_list_element *c; + char *tem = comname; + + validate_comname (comname); + + c = lookup_cmd (&tem, cmdlist, "", 0); + + if (c->class != (int) class_user) + error ("Command \"%s\" is built-in.", comname); + + if (from_tty) + printf ("Type documentation for \"%s\".\n\ +End with a line saying just \"end\".\n", comname); + + doclines = read_command_lines (); + + if (c->doc) free (c->doc); + + { + register struct command_line *cl1; + register int len = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + len += strlen (cl1->line) + 1; + + c->doc = (char *) xmalloc (len + 1); + *c->doc = 0; + + for (cl1 = doclines; cl1; cl1 = cl1->next) + { + strcat (c->doc, cl1->line); + if (cl1->next) + strcat (c->doc, "\n"); + } + } + + free_command_lines (&doclines); +} + +static void +copying_info () +{ + immediate_quit++; + printf (" GDB GENERAL PUBLIC LICENSE\n\ +\n\ + Copyright (C) 1986 Richard M. Stallman\n\ + Everyone is permitted to copy and distribute verbatim copies\n\ + of this license, but changing it is not allowed.\n\ +\n\ + The license agreements of most software companies keep you at the\n\ +mercy of those companies. By contrast, our general public license is\n\ +intended to give everyone the right to share GDB. To make sure that\n\ +you get the rights we want you to have, we need to make restrictions\n\ +that forbid anyone to deny you these rights or to ask you to surrender\n\ +the rights. Hence this license agreement.\n\ +\n\ + Specifically, we want to make sure that you have the right to give\n\ +away copies of GDB, that you receive source code or else can get it\n\ +if you want it, that you can change GDB or use pieces of it in new\n\ +free programs, and that you know you can do these things.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + To make sure that everyone has such rights, we have to forbid you to\n\ +deprive anyone else of these rights. For example, if you distribute\n\ +copies of GDB, you must give the recipients all the rights that you\n\ +have. You must make sure that they, too, receive or can get the\n\ +source code. And you must tell them their rights.\n\ +\n\ + Also, for our own protection, we must make certain that everyone\n\ +finds out that there is no warranty for GDB. If GDB is modified by\n\ +someone else and passed on, we want its recipients to know that what\n\ +they have is not what we distributed, so that any problems introduced\n\ +by others will not reflect on our reputation.\n\ +\n\ + Therefore we (Richard Stallman and the Free Software Foundation,\n\ +Inc.) make the following terms which say what you must do to be\n\ +allowed to distribute or change GDB.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + COPYING POLICIES\n\ +\n\ + 1. You may copy and distribute verbatim copies of GDB source code as\n\ +you receive it, in any medium, provided that you conspicuously and\n\ +appropriately publish on each copy a valid copyright notice \"Copyright\n\ +\(C) 1987 Free Software Foundation, Inc.\" (or with the year updated if\n\ +that is appropriate); keep intact the notices on all files that refer\n\ +to this License Agreement and to the absence of any warranty; and give\n\ +any other recipients of the GDB program a copy of this License\n\ +Agreement along with the program. You may charge a distribution fee\n\ +for the physical act of transferring a copy.\n\ +\n\ + 2. You may modify your copy or copies of GDB or any portion of it,\n\ +and copy and distribute such modifications under the terms of\n\ +Paragraph 1 above, provided that you also do the following:\n\ +\n\ + a) cause the modified files to carry prominent notices stating\n\ + that you changed the files and the date of any change; and\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + b) cause the whole of any work that you distribute or publish,\n\ + that in whole or in part contains or is a derivative of GDB\n\ + or any part thereof, to be licensed to all third parties on terms\n\ + identical to those contained in this License Agreement (except that\n\ + you may choose to grant more extensive warranty protection to third\n\ + parties, at your option).\n\ +\n"); + printf ("\ + c) if the modified program serves as a debugger, cause it\n\ + when started running in the simplest and usual way, to print\n\ + an announcement including a valid copyright notice\n\ + \"Copyright (C) 1987 Free Software Foundation, Inc.\" (or with\n\ + the year updated if appropriate), saying that there\n\ + is no warranty (or else, saying that you provide\n\ + a warranty) and that users may redistribute the program under\n\ + these conditions, and telling the user how to view a copy of\n\ + this License Agreement.\n\ +\n\ + d) You may charge a distribution fee for the physical act of\n\ + transferring a copy, and you may at your option offer warranty\n\ + protection in exchange for a fee.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + 3. You may copy and distribute GDB or any portion of it in\n\ +compiled, executable or object code form under the terms of Paragraphs\n\ +1 and 2 above provided that you do the following:\n\ +\n\ + a) cause each such copy to be accompanied by the\n\ + corresponding machine-readable source code, which must\n\ + be distributed under the terms of Paragraphs 1 and 2 above; or,\n\ +\n\ + b) cause each such copy to be accompanied by a\n\ + written offer, with no time limit, to give any third party\n\ + free (except for a nominal shipping charge) a machine readable\n\ + copy of the corresponding source code, to be distributed\n\ + under the terms of Paragraphs 1 and 2 above; or,\n\n"); + + printf ("\ + c) in the case of a recipient of GDB in compiled, executable\n\ + or object code form (without the corresponding source code) you\n\ + shall cause copies you distribute to be accompanied by a copy\n\ + of the written offer of source code which you received along\n\ + with the copy you received.\n\ +--Type Return to print more--"); + fflush (stdout); + read_line (); + + printf ("\ + 4. You may not copy, sublicense, distribute or transfer GDB\n\ +except as expressly provided under this License Agreement. Any attempt\n\ +otherwise to copy, sublicense, distribute or transfer GDB is void and\n\ +your rights to use the program under this License agreement shall be\n\ +automatically terminated. However, parties who have received computer\n\ +software programs from you with this License Agreement will not have\n\ +their licenses terminated so long as such parties remain in full compliance.\n\ +\n\ + 5. If you wish to incorporate parts of GDB into other free\n\ +programs whose distribution conditions are different, write to the Free\n\ +Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet\n\ +worked out a simple rule that can be stated here, but we will often permit\n\ +this. We will be guided by the two goals of preserving the free status of\n\ +all derivatives of our free software and of promoting the sharing and reuse\n\ +of software.\n\ +\n\ +In other words, go ahead and share GDB, but don't try to stop\n\ +anyone else from sharing it farther. Help stamp out software hoarding!\n\ +"); + immediate_quit--; +} + +static void +warranty_info () +{ + immediate_quit++; + printf (" NO WARRANTY\n\ +\n\ + BECAUSE GDB IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO\n\ +WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT\n\ +WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,\n\ +RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE GDB \"AS IS\" WITHOUT\n\ +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT\n\ +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n\ +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND\n\ +PERFORMANCE OF GDB IS WITH YOU. SHOULD GDB PROVE DEFECTIVE, YOU\n\ +ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n"); + + printf ("\ + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.\n\ +STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY\n\ +WHO MAY MODIFY AND REDISTRIBUTE GDB, BE LIABLE TO\n\ +YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER\n\ +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR\n\ +INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA\n\ +BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A\n\ +FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GDB, EVEN\n\ +IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR\n\ +ANY CLAIM BY ANY OTHER PARTY.\n"); + immediate_quit--; +} + +static void +print_gdb_version () +{ + printf ("GDB %s, Copyright (C) 1987 Free Software Foundation, Inc.\n\ +There is ABSOLUTELY NO WARRANTY for GDB; type \"info warranty\" for details.\n\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"info copying\" to see the conditions.\n", + version); +} + +static void +version_info () +{ + immediate_quit++; + print_gdb_version (); + immediate_quit--; +} + +static void +set_prompt_command (text) + char *text; +{ + char *p, *q; + register int c; + char *new; + + if (text == 0) + error_no_arg ("string to which to set prompt"); + + new = (char *) xmalloc (strlen (text) + 2); + p = text; q = new; + while (c = *p++) + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + break; + c = parse_escape (&p); + if (c == 0) + break; /* C loses */ + else if (c > 0) + *q++ = c; + } + else + *q++ = c; + } + if (*(p - 1) != '\\') + *q++ = ' '; + *q++ = '\0'; + new = (char *) xrealloc (new, q - new); + free (prompt); + prompt = new; +} + +static void +quit_command () +{ + if (have_inferior_p ()) + { + if (query ("The program is running. Quit anyway? ")) + { + /* Prevent any warning message from reopen_exec_file, in case + we have a core file that's inconsistent with the exec file. */ + exec_file_command (0, 0); + kill_inferior (); + } + else + error ("Not confirmed."); + } + exit (0); +} + +int +input_from_terminal_p () +{ + return instream == stdin; +} + +static void +pwd_command (arg, from_tty) + char *arg; + int from_tty; +{ + char buf[MAXPATHLEN]; + if (arg) error ("The \"pwd\" command does not take an argument: %s", arg); + printf ("Working directory %s.\n", getwd (buf)); +} + +static void +cd_command (dir, from_tty) + char *dir; + int from_tty; +{ + if (dir == 0) + error_no_arg ("new working directory"); + + if (chdir (dir) < 0) + perror_with_name (dir); + if (from_tty) + pwd_command ((char *) 0, 1); +} + + +/* Clean up on error during a "source" command. + Close the file opened by the command + and restore the previous input stream. */ + +static void +source_cleanup (stream) + FILE *stream; +{ + fclose (instream); + instream = stream; +} + +static void +source_command (file) + char *file; +{ + FILE *stream; + struct cleanup *cleanups; + + if (file == 0) + error_no_arg ("file to read commands from"); + + stream = fopen (file, "r"); + if (stream == 0) + perror_with_name (file); + + cleanups = make_cleanup (source_cleanup, instream); + + instream = stream; + + command_loop (); + + do_cleanups (cleanups); +} + +static void +echo_command (text) + char *text; +{ + char *p = text; + register int c; + + if (text) + while (c = *p++) + { + if (c == '\\') + { + /* \ at end of argument is used after spaces + so they won't be lost. */ + if (*p == 0) + return; + + c = parse_escape (&p); + if (c >= 0) + fputc (c, stdout); + } + else + fputc (c, stdout); + } +} + +static void +dump_me_command () +{ + if (query ("Should GDB dump core? ")) + { + signal (SIGQUIT, SIG_DFL); + kill (getpid (), SIGQUIT); + } +} + + +static void +initialize_main () +{ + prompt = savestring ("(gdb) ", 6); + + /* Define the classes of commands. + They will appear in the help list in the reverse of this order. */ + + add_cmd ("obscure", class_obscure, 0, "Obscure features.", &cmdlist); + add_cmd ("alias", class_alias, 0, "Aliases of other commands.", &cmdlist); + add_cmd ("user", class_user, 0, "User-defined commands.\n\ +The commands in this class are those defined by the user.\n\ +Use the \"define\" command to define a command.", &cmdlist); + add_cmd ("support", class_support, 0, "Support facilities.", &cmdlist); + add_cmd ("status", class_info, 0, "Status inquiries.", &cmdlist); + add_cmd ("files", class_files, 0, "Specifying and examining files.", &cmdlist); + add_cmd ("breakpoints", class_breakpoint, 0, "Making program stop at certain points.", &cmdlist); + add_cmd ("data", class_vars, 0, "Examining data.", &cmdlist); + add_cmd ("stack", class_stack, 0, "Examining the stack.\n\ +The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\ +counting from zero for the innermost (currently executing) frame.\n\n\ +At any time gdb identifies one frame as the \"selected\" frame.\n\ +Variable lookups are done with respect to the selected frame.\n\ +When the program being debugged stops, gdb selects the innermost frame.\n\ +The commands below can be used to select other frames by number or address.", + &cmdlist); + add_cmd ("running", class_run, 0, "Running the program.", &cmdlist); + + add_com ("pwd", class_files, pwd_command, + "Print working directory. This is used for your program as well."); + add_com ("cd", class_files, cd_command, + "Set working directory to DIR for debugger and program being debugged.\n\ +The change does not take effect for the program being debugged\n\ +until the next time it is started."); + + add_com ("set-prompt", class_support, set_prompt_command, + "Change gdb's prompt from the default of \"(gdb)\""); + add_com ("echo", class_support, echo_command, + "Print a constant string. Give string as argument.\n\ +C escape sequences may be used in the argument.\n\ +No newline is added at the end of the argument;\n\ +use \"\\n\" if you want a newline to be printed.\n\ +Since leading and trailing whitespace are ignored in command arguments,\n\ +if you want to print some you must use \"\\\" before leading whitespace\n\ +to be printed or after trailing whitespace."); + add_com ("document", class_support, document_command, + "Document a user-defined command.\n\ +Give command name as argument. Give documentation on following lines.\n\ +End with a line of just \"end\"."); + add_com ("define", class_support, define_command, + "Define a new command name. Command name is argument.\n\ +Definition appears on following lines, one command per line.\n\ +End with a line of just \"end\".\n\ +Use the \"document\" command to give documentation for the new command.\n\ +Commands defined in this way do not take arguments."); + + add_com ("source", class_support, source_command, + "Read commands from a file named FILE.\n\ +Note that the file \".gdbinit\" is read automatically in this way\n\ +when gdb is started."); + add_com ("quit", class_support, quit_command, "Exit gdb."); + add_com ("help", class_support, help_command, "Print list of commands."); + add_com_alias ("q", "quit", class_support, 1); + add_com_alias ("h", "help", class_support, 1); + + add_com ("dump-me", class_obscure, dump_me_command, + "Get fatal error; make debugger dump its core."); + + add_prefix_cmd ("info", class_info, info_command, + "Generic command for printing status.", + &infolist, "info ", 0, &cmdlist); + add_com_alias ("i", "info", class_info, 1); + + add_info ("copying", copying_info, "Conditions for redistributing copies of GDB."); + add_info ("warranty", warranty_info, "Various kinds of warranty you do not have."); + add_info ("version", version_info, "Report what version of GDB this is."); +} diff --git a/gdb/ns32k-opcode.h b/gdb/ns32k-opcode.h new file mode 100644 index 00000000000..2d5ff300997 --- /dev/null +++ b/gdb/ns32k-opcode.h @@ -0,0 +1,307 @@ +/* ns32k-opcode.h */ + +#ifndef ns32k_opcodeT +#define ns32k_opcodeT int +#endif /* no ns32k_opcodeT */ + +struct not_wot /* ns32k opcode table: wot to do with this */ + /* particular opcode */ +{ + int obits; /* number of opcode bits */ + int ibits; /* number of instruction bits */ + ns32k_opcodeT code; /* op-code (may be > 8 bits!) */ + char *args; /* how to compile said opcode */ +}; + +struct not /* ns32k opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct not_wot detail; /* rest of opcode table [datum] */ +}; + +/* F : 32 bit float + * L : 64 bit float + * B : byte + * W : word + * D : double-word + * Q : quad-word + * d : displacement + * q : quick + * i : immediate (8 bits) + * r : register number (3 bits) + * p : displacement - pc relative addressing +*/ +static struct not +notstrs[] = +{ + { "absf", 14,24, 0x35be, "1F2F" }, + { "absl", 14,24, 0x34be, "1L2L" }, + { "absb", 14,24, 0x304e, "1B2B" }, + { "absw", 14,24, 0x314e, "1W2W" }, + { "absd", 14,24, 0x334e, "1D2D" }, + { "acbb", 7,16, 0x4c, "2B1q3p" }, + { "addf", 14,24, 0x01be, "1F2F" }, + { "addl", 14,24, 0x00be, "1L2L" }, + { "addb", 6,16, 0x00, "1B2B" }, + { "addw", 6,16, 0x01, "1W2W" }, + { "addd", 6,16, 0x03, "1D2D" }, + { "addcb", 6,16, 0x10, "1B2B" }, + { "addcw", 6,16, 0x11, "1W2W" }, + { "addcd", 6,16, 0x13, "1D2D" }, + { "addpb", 14,24, 0x3c4e, "1B2B" }, + { "addpw", 14,24, 0x3d4e, "1W2W" }, + { "addpd", 14,24, 0x3f4e, "1D2D" }, + { "addqb", 7,16, 0x0c, "2B1q" }, + { "addqw", 7,16, 0x0d, "2W1q" }, + { "addqd", 7,16, 0x0f, "2D1q" }, + { "addr", 6,16, 0x27, "1D2D" }, + { "adjspb", 11,16, 0x057c, "1B" }, + { "adjspw", 11,16, 0x057d, "1W" }, + { "adjspd", 11,16, 0x057f, "1D" }, + { "andb", 6,16, 0x28, "1B2B" }, + { "andw", 6,16, 0x29, "1W2W" }, + { "andd", 6,16, 0x2b, "1D2D" }, + { "ashb", 14,24, 0x044e, "1B2B" }, + { "ashw", 14,24, 0x054e, "1B2W" }, + { "ashd", 14,24, 0x074e, "1B2D" }, + { "beq", 8,8, 0x0a, "1p" }, + { "bne", 8,8, 0x1a, "1p" }, + { "bcs", 8,8, 0x2a, "1p" }, + { "bcc", 8,8, 0x3a, "1p" }, + { "bhi", 8,8, 0x4a, "1p" }, + { "bls", 8,8, 0x5a, "1p" }, + { "bgt", 8,8, 0x6a, "1p" }, + { "ble", 8,8, 0x7a, "1p" }, + { "bfs", 8,8, 0x8a, "1p" }, + { "bfc", 8,8, 0x9a, "1p" }, + { "blo", 8,8, 0xaa, "1p" }, + { "bhs", 8,8, 0xba, "1p" }, + { "blt", 8,8, 0xca, "1p" }, + { "bge", 8,8, 0xda, "1p" }, + { "bicb", 6,16, 0x08, "1B2B" }, + { "bicw", 6,16, 0x09, "1W2W" }, + { "bicd", 6,16, 0x0b, "1D2D" }, + { "bicpsrb", 11,16, 0x17c, "1B" }, + { "bicpsrw", 11,16, 0x17d, "1W" }, + { "bispsrb", 11,16, 0x37c, "1B" }, + { "bispsrw", 11,16, 0x37d, "1W" }, + { "bpt", 8,8, 0xf2, "" }, + { "br", 8,8, 0xea, "1p" }, + { "bsr", 8,8, 0x02, "1p" }, + { "caseb", 11,16, 0x77c, "1B" }, + { "casew", 11,16, 0x77d, "1W" }, + { "cased", 11,16, 0x77f, "1D" }, + { "cbitb", 14,24, 0x084e, "1B2D" }, + { "cbitw", 14,24, 0x094e, "1W2D" }, + { "cbitd", 14,24, 0x0b4e, "1D2D" }, + { "cbitib", 14,24, 0x0c4e, "1B2D" }, + { "cbitiw", 14,24, 0x0d4e, "1W2D" }, + { "cbitid", 14,24, 0x0f4e, "1D2D" }, + { "checkb", 11,24, 0x0ee, "2A3B1r" }, + { "checkw", 11,24, 0x1ee, "2A3B1r" }, + { "checkd", 11,24, 0x3ee, "2A3D1r" }, + { "cmpf", 14,24, 0x09be, "1F2F" }, + { "cmpl", 14,24, 0x08be, "1L2L" }, + { "cmpb", 6,16, 0x04, "1B2B" }, + { "cmpw", 6,16, 0x05, "1W2W" }, + { "cmpd", 6,16, 0x07, "1D2D" }, + { "cmpmb", 14,24, 0x04ce, "1D2D3d" }, + { "cmpmw", 14,24, 0x05ce, "1D2D3d" }, + { "cmpmd", 14,24, 0x07ce, "1D2D3d" }, + { "cmpqb", 7,16, 0x1c, "2B1q" }, + { "cmpqw", 7,16, 0x1d, "2W1q" }, + { "cmpqd", 7,16, 0x1f, "2D1q" }, + { "cmpsb", 16,16, 0x040e, "1i" }, + { "cmpsw", 16,16, 0x050e, "1i" }, + { "cmpsd", 16,16, 0x070e, "1i" }, + { "cmpst", 16,16, 0x840e, "1i" }, + { "comb", 14,24, 0x344e, "1B2B" }, + { "comw", 14,24, 0x354e, "1W2W" }, + { "comd", 14,24, 0x374e, "1D2D" }, + { "cvtp", 11,24, 0x036e, "2D3D1r" }, + { "cxp", 8,8, 0x22, "1p" }, + { "cxpd", 11,16, 0x07f, "1D" }, + { "deib", 14,24, 0x2cce, "1B2W" }, + { "deiw", 14,24, 0x2cce, "1W2D" }, + { "deid", 14,24, 0x2cce, "1D2Q" }, + { "dia", 8,8, 0xc2, "" }, + { "divf", 14,24, 0x21be, "1F2F" }, + { "divl", 14,24, 0x20be, "1L2L" }, + { "divb", 14,24, 0x3cce, "1B2B" }, + { "divw", 14,24, 0x3dce, "1W2W" }, + { "divd", 14,24, 0x3fce, "1D2D" }, + { "enter", 8,8, 0x82, "1i2d" }, + { "exit", 8,8, 0x92, "1i" }, + { "extb", 11,24, 0x02e, "2D3B1r4d" }, + { "extw", 11,24, 0x12e, "2D3W1r4d" }, + { "extd", 11,24, 0x32e, "2D3D1r4d" }, + { "extsb", 14,24, 0x0cce, "1D2B3i" }, + { "extsw", 14,24, 0x0dce, "1D2W3i" }, + { "extsd", 14,24, 0x0fce, "1D2D3i" }, + { "ffsb", 14,24, 0x046e, "1B2B" }, + { "ffsw", 14,24, 0x056e, "1W2B" }, + { "ffsd", 14,24, 0x076e, "1D2B" }, + { "flag", 8,8, 0xd2, "" }, + { "floorfb", 14,24, 0x3c3e, "1F2B" }, + { "floorfw", 14,24, 0x3d3e, "1F2W" }, + { "floorfd", 14,24, 0x3f3e, "1F2D" }, + { "floorlb", 14,24, 0x383e, "1L2B" }, + { "floorlw", 14,24, 0x393e, "1L2W" }, + { "floorld", 14,24, 0x3b3e, "1L2D" }, + { "ibitb", 14,24, 0x384e, "1B2D" }, + { "ibitw", 14,24, 0x394e, "1W2D" }, + { "ibitd", 14,24, 0x3b4e, "1D2D" }, + { "indexb", 11,24, 0x42e, "2B3B1r" }, + { "indexw", 11,24, 0x52e, "2W3W1r" }, + { "indexd", 11,24, 0x72e, "2D3D1r" }, + { "insb", 11,24, 0x0ae, "2B3B1r4d" }, + { "insw", 11,24, 0x1ae, "2W3W1r4d" }, + { "insd", 11,24, 0x3ae, "2D3D1r4d" }, + { "inssb", 14,24, 0x08ce, "1B2D3i" }, + { "inssw", 14,24, 0x09ce, "1W2D3i" }, + { "inssd", 14,24, 0x0bce, "1D2D3i" }, + { "jsr", 11,16, 0x67f, "1A" }, + { "jump", 11,16, 0x27f, "1A" }, + { "lfsr", 19,24, 0x00f3e,"1D" }, + { "lmr", 15,24, 0x0b1e, "2D1q" }, + { "lprb", 7,16, 0x6c, "2B1q" }, + { "lprw", 7,16, 0x6d, "2W1q" }, + { "lprd", 7,16, 0x6f, "2D1q" }, + { "lshb", 14,24, 0x144e, "1B2B" }, + { "lshw", 14,24, 0x154e, "1B2W" }, + { "lshd", 14,24, 0x174e, "1B2D" }, + { "meib", 14,24, 0x24ce, "1B2W" }, + { "meiw", 14,24, 0x25ce, "1W2D" }, + { "meid", 14,24, 0x27ce, "1D2Q" }, + { "modb", 14,24, 0x38ce, "1B2B" }, + { "modw", 14,24, 0x39ce, "1W2W" }, + { "modd", 14,24, 0x3bce, "1D2D" }, + { "movf", 14,24, 0x05be, "1F2F" }, + { "movl", 14,24, 0x04be, "1L2L" }, + { "movb", 6,16, 0x14, "1B2B" }, + { "movw", 6,16, 0x15, "1W2W" }, + { "movd", 6,16, 0x17, "1D2D" }, + { "movbf", 14,24, 0x043e, "1B2F" }, + { "movwf", 14,24, 0x053e, "1W2F" }, + { "movdf", 14,24, 0x073e, "1D2F" }, + { "movbl", 14,24, 0x003e, "1B2L" }, + { "movwl", 14,24, 0x013e, "1W2L" }, + { "movdl", 14,24, 0x033e, "1D2L" }, + { "movfl", 14,24, 0x1b3e, "1F2L" }, + { "movlf", 14,24, 0x163e, "1L2F" }, + { "movmb", 14,24, 0x00ce, "1D2D3d" }, + { "movmw", 14,24, 0x00de, "1D2D3d" }, + { "movmd", 14,24, 0x00fe, "1D2D3d" }, + { "movqb", 7,16, 0x5c, "2B1q" }, + { "movqw", 7,16, 0x5d, "2B1q" }, + { "movqd", 7,16, 0x5f, "2B1q" }, + { "movsb", 16,16, 0x000e, "1i" }, + { "movsw", 16,16, 0x010e, "1i" }, + { "movsd", 16,16, 0x030e, "1i" }, + { "movst", 16,16, 0x800e, "1i" }, + { "movsub", 14,24, 0x0cae, "1A1A" }, + { "movsuw", 14,24, 0x0dae, "1A1A" }, + { "movsud", 14,24, 0x0fae, "1A1A" }, + { "movusb", 14,24, 0x1cae, "1A1A" }, + { "movusw", 14,24, 0x1dae, "1A1A" }, + { "movusd", 14,24, 0x1fae, "1A1A" }, + { "movxbd", 14,24, 0x1cce, "1B2D" }, + { "movxwd", 14,24, 0x1dce, "1W2D" }, + { "movxbw", 14,24, 0x10ce, "1B2W" }, + { "movzbd", 14,24, 0x18ce, "1B2D" }, + { "movzwd", 14,24, 0x19ce, "1W2D" }, + { "movzbw", 14,24, 0x14ce, "1B2W" }, + { "mulf", 14,24, 0x31be, "1F2F" }, + { "mull", 14,24, 0x30be, "1L2L" }, + { "mulb", 14,24, 0x20ce, "1B2B" }, + { "mulw", 14,24, 0x21ce, "1W2W" }, + { "muld", 14,24, 0x23ce, "1D2D" }, + { "negf", 14,24, 0x15be, "1F2F" }, + { "negl", 14,24, 0x14be, "1L2L" }, + { "negb", 14,24, 0x204e, "1B2B" }, + { "negw", 14,24, 0x214e, "1W2W" }, + { "negd", 14,24, 0x234e, "1D2D" }, + { "nop", 8,8, 0xa2, "" }, + { "notb", 14,24, 0x244e, "1B2B" }, + { "notw", 14,24, 0x254e, "1W2W" }, + { "notd", 14,24, 0x274e, "1D2D" }, + { "orb", 6,16, 0x18, "1B1B" }, + { "orw", 6,16, 0x19, "1W1W" }, + { "ord", 6,16, 0x1b, "1D1D" }, + { "quob", 14,24, 0x30ce, "1B2B" }, + { "quow", 14,24, 0x31ce, "1W2W" }, + { "quod", 14,24, 0x33ce, "1D2D" }, + { "rdval", 19,24, 0x0031e,"1A" }, + { "remb", 14,24, 0x34ce, "1B2B" }, + { "remw", 14,24, 0x35ce, "1W2W" }, + { "remd", 14,24, 0x37ce, "1D2D" }, + { "restore", 8,8, 0x72, "1i" }, + { "ret", 8,8, 0x12, "1d" }, + { "reti", 8,8, 0x52, "" }, + { "rett", 8,8, 0x42, "" }, + { "rotb", 14,24, 0x004e, "1B2B" }, + { "rotw", 14,24, 0x014e, "1B2W" }, + { "rotd", 14,24, 0x034e, "1B2D" }, + { "roundfb", 14,24, 0x243e, "1F2B" }, + { "roundfw", 14,24, 0x253e, "1F2W" }, + { "roundfd", 14,24, 0x273e, "1F2D" }, + { "roundlb", 14,24, 0x203e, "1L2B" }, + { "roundlw", 14,24, 0x213e, "1L2W" }, + { "roundld", 14,24, 0x233e, "1L2D" }, + { "rxp", 8,8, 0x32, "1d" }, + { "sCONDb", 7,16, 0x3c, "2B1q" }, + { "sCONDw", 7,16, 0x3d, "2D1q" }, + { "sCONDd", 7,16, 0x3f, "2D1q" }, + { "save", 8,8, 0x62, "1i" }, + { "sbitb", 14,24, 0x184e, "1B2A" }, + { "sbitw", 14,24, 0x194e, "1W2A" }, + { "sbitd", 14,24, 0x1b4e, "1D2A" }, + { "sbitib", 14,24, 0x1c4e, "1B2A" }, + { "sbitiw", 14,24, 0x1d4e, "1W2A" }, + { "sbitid", 14,24, 0x1f4e, "1D2A" }, + { "setcfg", 15,24, 0x0b0e, "5D1q" }, + { "sfsr", 14,24, 0x673e, "5D1D" }, + { "skpsb", 16,16, 0x0c0e, "1i" }, + { "skpsw", 16,16, 0x0d0e, "1i" }, + { "skpsd", 16,16, 0x0f0e, "1i" }, + { "skpst", 16,16, 0x8c0e, "1i" }, + { "smr", 15,24, 0x0f1e, "2D1q" }, + { "sprb", 7,16, 0x2c, "2B1q" }, + { "sprw", 7,16, 0x2d, "2W1q" }, + { "sprd", 7,16, 0x2f, "2D1q" }, + { "subf", 14,24, 0x11be, "1F2F" }, + { "subl", 14,24, 0x10be, "1L2L" }, + { "subb", 6,16, 0x20, "1B2B" }, + { "subw", 6,16, 0x21, "1W2W" }, + { "subd", 6,16, 0x23, "1D2D" }, + { "subcb", 6,16, 0x30, "1B2B" }, + { "subcw", 6,16, 0x31, "1W2W" }, + { "subcd", 6,16, 0x33, "1D2D" }, + { "subpb", 14,24, 0x2c4e, "1B2B" }, + { "subpw", 14,24, 0x2d4e, "1W2W" }, + { "subpd", 14,24, 0x2f4e, "1D2D" }, +#ifndef NS32K_SVC_IMMED_OPERANDS + { "svc", 8,8, 0xe2, "2i1i" }, /* not really, but unix uses it */ +#else + { "svc", 8,8, 0xe2, "" }, /* not really, but unix uses it */ +#endif + { "tbitb", 6,16, 0x34, "1B2A" }, + { "tbitw", 6,16, 0x35, "1W2A" }, + { "tbitd", 6,16, 0x37, "1D2A" }, + { "truncfb", 14,24, 0x2c3e, "1F2B" }, + { "truncfw", 14,24, 0x2d3e, "1F2W" }, + { "truncfd", 14,24, 0x2f3e, "1F2D" }, + { "trunclb", 14,24, 0x283e, "1L2B" }, + { "trunclw", 14,24, 0x293e, "1L2W" }, + { "truncld", 14,24, 0x2b3e, "1L2D" }, + { "wait", 8,8, 0xb2, "" }, + { "wrval", 19,24, 0x0071e,"1A" }, + { "xorb", 6,16, 0x38, "1B2B" }, + { "xorw", 6,16, 0x39, "1W2W" }, + { "xord", 6,16, 0x3b, "1D2D" }, +}; /* notstrs */ + +/* end: ns32k.opcode.h */ + +#define MAX_ARGS 4 +#define ARG_LEN 50 diff --git a/gdb/ns32k-pinsn.c b/gdb/ns32k-pinsn.c new file mode 100644 index 00000000000..7afee487f05 --- /dev/null +++ b/gdb/ns32k-pinsn.c @@ -0,0 +1,437 @@ +/* Print 32000 instructions for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "ns32k-opcode.h" + +/* 32000 instructions are never longer than this. */ +#define MAXLEN 62 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof notstrs / sizeof notstrs[0]) + +extern char *reg_names[]; + +#define NEXT_IS_ADDR '|' + +/* + * extract "count" bits starting "offset" bits + * into buffer + */ + +int +bit_extract (buffer, offset, count) + char *buffer; + int offset; + int count; +{ + int result; + int mask; + int bit; + + buffer += offset >> 3; + offset &= 7; + bit = 1; + result = 0; + while (count--) + { + if ((*buffer & (1 << offset))) + result |= bit; + if (++offset == 8) + { + offset = 0; + buffer++; + } + bit <<= 1; + } + return result; +} + +double +dbit_extract (buffer, offset, count) +{ + union { + struct {int low, high; } ival; + double dval; + } foo; + + foo.ival.low = bit_extract (buffer, offset, 32); + foo.ival.high = bit_extract (buffer, offset+32, 32); + return foo.dval; +} + +sign_extend (value, bits) +{ + value = value & ((1 << bits) - 1); + return (value & (1 << (bits-1)) + ? value | (~((1 << bits) - 1)) + : value); +} + +flip_bytes (ptr, count) + char *ptr; + int count; +{ + char tmp; + + while (count > 0) + { + tmp = *ptr; + ptr[0] = ptr[count-1]; + ptr[count-1] = tmp; + ptr++; + count -= 2; + } +} + + +/* Print the 32000 instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) +CORE_ADDR memaddr; +FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register unsigned char *p; + register char *d; + unsigned short first_word; + int gen, disp; + int ioffset; /* bits into instruction */ + int aoffset; /* bits into arguments */ + char arg_bufs[MAX_ARGS+1][ARG_LEN]; + int argnum; + int maxarg; + + read_memory (memaddr, buffer, MAXLEN); + + first_word = *(unsigned short *) buffer; + for (i = 0; i < NOPCODES; i++) + if ((first_word & ((1 << notstrs[i].detail.obits) - 1)) + == notstrs[i].detail.code) + break; + + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0%o", buffer[0]); + return 1; + } + + fprintf (stream, "%s", notstrs[i].name); + + ioffset = notstrs[i].detail.ibits; + aoffset = notstrs[i].detail.ibits; + d = notstrs[i].detail.args; + + if (*d) + { + fputc ('\t', stream); + + maxarg = 0; + while (*d) + { + argnum = *d - '1'; + d++; + if (argnum > maxarg && argnum < MAX_ARGS) + maxarg = argnum; + ioffset = print_insn_arg (*d, ioffset, &aoffset, buffer, + memaddr, arg_bufs[argnum]); + d++; + } + for (argnum = 0; argnum <= maxarg; argnum++) + { + CORE_ADDR addr; + char *ch, *index (); + for (ch = arg_bufs[argnum]; *ch;) + { + if (*ch == NEXT_IS_ADDR) + { + ++ch; + addr = atoi (ch); + print_address (addr, stream); + while (*ch && *ch != NEXT_IS_ADDR) + ++ch; + if (*ch) + ++ch; + } + else + putc (*ch++, stream); + } + if (argnum < maxarg) + fprintf (stream, ", "); + } + } + return aoffset / 8; +} + +print_insn_arg (d, ioffset, aoffsetp, buffer, addr, result) + char d; + int ioffset, *aoffsetp; + char *buffer; + CORE_ADDR addr; + char *result; +{ + int addr_mode; + float Fvalue; + double Lvalue; + int Ivalue; + int disp1, disp2; + int index; + + switch (d) + { + case 'F': + case 'L': + case 'B': + case 'W': + case 'D': + case 'A': + addr_mode = bit_extract (buffer, ioffset-5, 5); + ioffset -= 5; + switch (addr_mode) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + sprintf (result, "r%d", addr_mode); + break; + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(r%d)", disp1, addr_mode & 7); + break; + case 0x10: + case 0x11: + case 0x12: + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(%d(%s))", disp2, disp1, + addr_mode==0x10?"fp":addr_mode==0x11?"sp":"sb"); + break; + case 0x13: + sprintf (result, "reserved"); + break; + case 0x14: + switch (d) + { + case 'B': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + Ivalue = sign_extend (Ivalue, 8); + *aoffsetp += 8; + sprintf (result, "$%d", Ivalue); + break; + case 'W': + Ivalue = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue, 2); + *aoffsetp += 16; + Ivalue = sign_extend (Ivalue, 16); + sprintf (result, "$%d", Ivalue); + break; + case 'D': + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + *aoffsetp += 32; + sprintf (result, "$%d", Ivalue); + break; + case 'A': + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + *aoffsetp += 32; + sprintf (result, "$|%d|", Ivalue); + break; + case 'F': + Fvalue = (float) bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Fvalue, 4); + *aoffsetp += 32; + sprintf (result, "$%g", Fvalue); + break; + case 'L': + Lvalue = dbit_extract (buffer, *aoffsetp, 64); + flip_bytes (&Lvalue, 8); + *aoffsetp += 64; + sprintf (result, "$%g", Lvalue); + break; + } + break; + case 0x15: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "@|%d|", disp1); + break; + case 0x16: + disp1 = get_displacement (buffer, aoffsetp); + disp2 = get_displacement (buffer, aoffsetp); + sprintf (result, "EXT(%d) + %d", disp1, disp2); + break; + case 0x17: + sprintf (result, "tos"); + break; + case 0x18: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(fp)", disp1); + break; + case 0x19: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sp)", disp1); + break; + case 0x1a: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "%d(sb)", disp1); + break; + case 0x1b: + disp1 = get_displacement (buffer, aoffsetp); + sprintf (result, "|%d|", addr + disp1); + break; + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + index = bit_extract (buffer, *aoffsetp, 8); + *aoffsetp += 8; + print_insn_arg (d, *aoffsetp, aoffsetp, buffer, addr, + result); + { + static char *ind[] = {"b", "w", "d", "q"}; + char *off; + + off = result + strlen (result); + sprintf (off, "[r%d:%s]", index & 7, + ind[addr_mode & 3]); + } + break; + } + break; + case 'q': + Ivalue = bit_extract (buffer, ioffset-4, 4); + Ivalue = sign_extend (Ivalue, 4); + sprintf (result, "%d", Ivalue); + ioffset -= 4; + break; + case 'r': + Ivalue = bit_extract (buffer, ioffset-3, 3); + sprintf (result, "r%d", Ivalue&7); + ioffset -= 3; + break; + case 'd': + sprintf (result, "%d", get_displacement (buffer, aoffsetp)); + break; + case 'p': + sprintf (result, "%c%d%c", NEXT_IS_ADDR, + addr + get_displacement (buffer, aoffsetp), + NEXT_IS_ADDR); + break; + case 'i': + Ivalue = bit_extract (buffer, *aoffsetp, 8); + *aoffsetp += 8; + sprintf (result, "0x%x", Ivalue); + break; + } + return ioffset; +} + +get_displacement (buffer, aoffsetp) + char *buffer; + int *aoffsetp; +{ + int Ivalue; + + Ivalue = bit_extract (buffer, *aoffsetp, 8); + switch (Ivalue & 0xc0) + { + case 0x00: + case 0x40: + Ivalue = sign_extend (Ivalue, 7); + *aoffsetp += 8; + break; + case 0x80: + Ivalue = bit_extract (buffer, *aoffsetp, 16); + flip_bytes (&Ivalue, 2); + Ivalue = sign_extend (Ivalue, 14); + *aoffsetp += 16; + break; + case 0xc0: + Ivalue = bit_extract (buffer, *aoffsetp, 32); + flip_bytes (&Ivalue, 4); + Ivalue = sign_extend (Ivalue, 30); + *aoffsetp += 32; + break; + } + return Ivalue; +} + +/* Return the number of locals in the current frame given a pc + pointing to the enter instruction. This is used in the macro + FRAME_FIND_SAVED_REGS. */ + +ns32k_localcount (enter_pc) + CORE_ADDR enter_pc; +{ + unsigned char localtype; + int localcount; + + localtype = read_memory_integer (enter_pc+2, 1); + if ((localtype & 0x80) == 0) + localcount = localtype; + else if ((localtype & 0xc0) == 0x80) + localcount = (((localtype & 0x3f) << 8) + | (read_memory_integer (enter_pc+3, 1) & 0xff)); + else + localcount = (((localtype & 0x3f) << 24) + | ((read_memory_integer (enter_pc+3, 1) & 0xff) << 16) + | ((read_memory_integer (enter_pc+4, 1) & 0xff) << 8 ) + | (read_memory_integer (enter_pc+5, 1) & 0xff)); + return localcount; +} + +/* + * Get the address of the enter opcode for the function + * containing PC, if there is an enter for the function, + * and if the pc is between the enter and exit. + * Returns positive address if pc is between enter/exit, + * 1 if pc before enter or after exit, 0 otherwise. + */ + +CORE_ADDR +n32k_get_enter_addr (pc) + CORE_ADDR pc; +{ + CORE_ADDR enter_addr; + unsigned char op; + + if (ABOUT_TO_RETURN (pc)) + return 1; /* after exit */ + + enter_addr = get_pc_function_start (pc); + + if (pc == enter_addr) + return 1; /* before enter */ + + op = read_memory_integer (enter_addr, 1); + + if (op != 0x82) + return 0; /* function has no enter/exit */ + + return enter_addr; /* pc is between enter and exit */ +} diff --git a/gdb/obstack.c b/gdb/obstack.c new file mode 120000 index 00000000000..887f348b1c0 --- /dev/null +++ b/gdb/obstack.c @@ -0,0 +1 @@ +../gcc/gcc-1.22/obstack.c \ No newline at end of file diff --git a/gdb/obstack.h b/gdb/obstack.h new file mode 120000 index 00000000000..db1184b4e26 --- /dev/null +++ b/gdb/obstack.h @@ -0,0 +1 @@ +../gcc/gcc-1.19/obstack.h \ No newline at end of file diff --git a/gdb/param.h b/gdb/param.h new file mode 100644 index 00000000000..56f2c8a4fe6 --- /dev/null +++ b/gdb/param.h @@ -0,0 +1 @@ +#include "m-mac-aux.h" diff --git a/gdb/pinsn.c b/gdb/pinsn.c new file mode 100644 index 00000000000..0b6414e4494 --- /dev/null +++ b/gdb/pinsn.c @@ -0,0 +1 @@ +#include "m68k-pinsn.c" diff --git a/gdb/printcmd.c b/gdb/printcmd.c new file mode 100644 index 00000000000..d84dd9db954 --- /dev/null +++ b/gdb/printcmd.c @@ -0,0 +1,979 @@ +/* Print values for GNU debugger gdb. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "expression.h" + +struct format_data +{ + int count; + char format; + char size; +}; + +/* Last specified output format. */ + +static char last_format = 'x'; + +/* Last specified examination size. 'b', 'h', 'w' or `q'. */ + +static char last_size = 'w'; + +/* Default address to examine next. */ + +static CORE_ADDR next_address; + +/* Last address examined. */ + +static CORE_ADDR last_examine_address; + +/* Contents of last address examined. + This is not valid past the end of the `x' command! */ + +static value last_examine_value; + +void do_displays (); +void print_address (); + +START_FILE + +/* Decode a format specification. *STRING_PTR should point to it. + OFORMAT and OSIZE are used as defaults for the format and size + if none are given in the format specification. + The structure returned describes all the data + found in the specification. In addition, *STRING_PTR is advanced + past the specification and past all whitespace following it. */ + +struct format_data +decode_format (string_ptr, oformat, osize) + char **string_ptr; + char oformat; + char osize; +{ + struct format_data val; + register char *p = *string_ptr; + + val.format = oformat; + val.size = osize; + val.count = 1; + + if (*p >= '0' && *p <= '9') + val.count = atoi (p); + while (*p >= '0' && *p <= '9') p++; + + /* Now process size or format letters that follow. */ + + while (1) + { + if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g') + val.size = *p++; + else if (*p >= 'a' && *p <= 'z') + val.format = *p++; + else + break; + } + + while (*p == ' ' || *p == '\t') p++; + *string_ptr = p; + + return val; +} + +/* Print value VAL on stdout according to FORMAT, a letter or 0. + Do not end with a newline. + 0 means print VAL according to its own type. */ + +static void +print_formatted (val, format) + register value val; + register char format; +{ + register CORE_ADDR val_long; + int len = TYPE_LENGTH (VALUE_TYPE (val)); + + if (VALUE_LVAL (val) == lval_memory) + next_address = VALUE_ADDRESS (val) + len; + + if (format && format != 's') + { + val_long = value_as_long (val); + + /* If value is unsigned, truncate it in case negative. */ + if (format != 'd') + { + if (len == sizeof (char)) + val_long &= (1 << 8 * sizeof(char)) - 1; + else if (len == sizeof (short)) + val_long &= (1 << 8 * sizeof(short)) - 1; + } + } + + switch (format) + { + case 's': + next_address = VALUE_ADDRESS (val) + + value_print (value_addr (val), stdout); + break; + + case 'i': + next_address = VALUE_ADDRESS (val) + + print_insn (VALUE_ADDRESS (val), stdout); + break; + + case 'x': + printf ("0x%x", val_long); + break; + + case 'd': + printf ("%d", val_long); + break; + + case 'u': + printf ("%u", val_long); + break; + + case 'o': + if (val_long) + printf ("0%o", val_long); + else + printf ("0"); + break; + + case 'a': + print_address (val_long, stdout); + break; + + case 'c': + value_print (value_cast (builtin_type_char, val), stdout); + break; + + case 'f': + if (TYPE_LENGTH (VALUE_TYPE (val)) == sizeof (float)) + VALUE_TYPE (val) = builtin_type_float; + if (TYPE_LENGTH (VALUE_TYPE (val)) == sizeof (double)) + VALUE_TYPE (val) = builtin_type_double; +#ifdef IEEE_FLOAT + if (is_nan (value_as_double (val))) + { + printf ("Nan"); + break; + } +#endif + printf ("%g", value_as_double (val)); + break; + + case 0: + value_print (val, stdout); + break; + + default: + error ("Undefined output format \"%c\".", format); + } +} + +/* Specify default address for `x' command. + `info lines' uses this. */ + +void +set_next_address (addr) + CORE_ADDR addr; +{ + next_address = addr; + + /* Make address available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_long (builtin_type_int, addr)); +} + +/* Print address ADDR symbolically on STREAM. + First print it as a number. Then perhaps print + after the number. */ + +void +print_address (addr, stream) + CORE_ADDR addr; + FILE *stream; +{ + register int i; + + fprintf (stream, "0x%x", addr); + + i = find_pc_misc_function (addr); + if (i >= 0) + if (misc_function_vector[i].address != addr) + fprintf (stream, " <%s+%d>", + misc_function_vector[i].name, + addr - misc_function_vector[i].address); + else + fprintf (stream, " <%s>", misc_function_vector[i].name); + +} + +/* Examine data at address ADDR in format FMT. + Fetch it from memory and print on stdout. */ + +static void +do_examine (fmt, addr) + struct format_data fmt; + CORE_ADDR addr; +{ + register char format = 0; + register char size; + register int count = 1; + struct type *val_type; + register int i; + register int maxelts; + + format = fmt.format; + size = fmt.size; + count = fmt.count; + next_address = addr; + + /* String or instruction format implies fetch single bytes + regardless of the specified size. */ + if (format == 's' || format == 'i') + size = 'b'; + + if (size == 'b') + val_type = builtin_type_char; + else if (size == 'h') + val_type = builtin_type_short; + else if (size == 'w') + val_type = builtin_type_long; + else if (size == 'g') + val_type = builtin_type_double; + + maxelts = 8; + if (size == 'w') + maxelts = 4; + if (size == 'g') + maxelts = 2; + if (format == 's' || format == 'i') + maxelts = 1; + + /* Print as many objects as specified in COUNT, at most maxelts per line, + with the address of the next one at the start of each line. */ + + while (count > 0) + { + print_address (next_address, stdout); + for (i = maxelts; + i > 0 && count > 0; + i--, count--) + { + fputc ('\t', stdout); + /* Note that this sets next_address for the next object. */ + last_examine_address = next_address; + last_examine_value = value_at (val_type, next_address); + print_formatted (last_examine_value, format); + } + fputc ('\n', stdout); + fflush (stdout); + } +} + +static void +validate_format (fmt, cmdname) + struct format_data fmt; + char *cmdname; +{ + if (fmt.size != 0) + error ("Size letters are meaningless in \"%s\" command.", cmdname); + if (fmt.count != 1) + error ("Item count other than 1 is meaningless in \"%s\" command.", + cmdname); + if (fmt.format == 'i' || fmt.format == 's') + error ("Format letter \"%c\" is meaningless in \"%s\" command.", + fmt.format, cmdname); +} + +static void +print_command (exp) + char *exp; +{ + struct expression *expr; + register struct cleanup *old_chain = 0; + register char format = 0; + register value val; + struct format_data fmt; + int histindex; + int cleanup = 0; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, 0); + validate_format (fmt, "print"); + last_format = format = fmt.format; + } + + if (exp && *exp) + { + expr = parse_c_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + cleanup = 1; + val = evaluate_expression (expr); + } + else + val = access_value_history (0); + + histindex = record_latest_value (val); + printf ("$%d = ", histindex); + + print_formatted (val, format); + printf ("\n"); + + if (cleanup) + do_cleanups (old_chain); +} + +static void +output_command (exp) + char *exp; +{ + struct expression *expr; + register struct cleanup *old_chain; + register char format = 0; + register value val; + struct format_data fmt; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + validate_format (fmt, "print"); + format = fmt.format; + } + + expr = parse_c_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + + val = evaluate_expression (expr); + + print_formatted (val, format); + + do_cleanups (old_chain); +} + +static void +set_command (exp) + char *exp; +{ + struct expression *expr = parse_c_expression (exp); + register struct cleanup *old_chain + = make_cleanup (free_current_contents, &expr); + evaluate_expression (expr); + do_cleanups (old_chain); +} + +static void +address_info (exp) + char *exp; +{ + register struct symbol *sym; + register CORE_ADDR val; + + if (exp == 0) + error ("Argument required."); + + sym = lookup_symbol (exp, get_selected_block (), VAR_NAMESPACE); + if (sym == 0) + { + register int i; + + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, exp)) + break; + + if (i < misc_function_count) + printf ("Symbol \"%s\" is at 0x%x in a file compiled without -g.\n", + exp, misc_function_vector[i].address); + else + error ("No symbol \"%s\" in current context.", exp); + return; + } + + printf ("Symbol \"%s\" is ", SYMBOL_NAME (sym)); + val = SYMBOL_VALUE (sym); + + switch (SYMBOL_CLASS (sym)) + { + case LOC_CONST: + case LOC_CONST_BYTES: + printf ("constant"); + break; + + case LOC_LABEL: + printf ("a label at address 0x%x", val); + break; + + case LOC_REGISTER: + printf ("a variable in register %s", reg_names[val]); + break; + + case LOC_STATIC: + printf ("static at address 0x%x", val); + break; + + case LOC_ARG: + printf ("an argument at offset %d", val); + break; + + case LOC_LOCAL: + printf ("a local variable at frame offset %d", val); + break; + + case LOC_TYPEDEF: + printf ("a typedef"); + break; + + case LOC_BLOCK: + printf ("a function at address 0x%x", + BLOCK_START (SYMBOL_BLOCK_VALUE (sym))); + break; + } + printf (".\n"); +} + +static void +x_command (exp, from_tty) + char *exp; + int from_tty; +{ + struct expression *expr; + struct format_data fmt; + struct cleanup *old_chain; + + fmt.format = last_format; + fmt.size = last_size; + fmt.count = 1; + + if (exp && *exp == '/') + { + exp++; + fmt = decode_format (&exp, last_format, last_size); + last_size = fmt.size; + last_format = fmt.format; + } + + /* If we have an expression, evaluate it and use it as the address. */ + + if (exp != 0 && *exp != 0) + { + expr = parse_c_expression (exp); + /* Cause expression not to be there any more + if this command is repeated with Newline. + But don't clobber a user-defined command's definition. */ + if (from_tty) + *exp = 0; + old_chain = make_cleanup (free_current_contents, &expr); + next_address = value_as_long (evaluate_expression (expr)); + do_cleanups (old_chain); + } + + do_examine (fmt, next_address); + + /* Make last address examined available to the user as $_. */ + set_internalvar (lookup_internalvar ("_"), + value_from_long (builtin_type_int, last_examine_address)); + + /* Make contents of last address examined available to the user as $__. */ + set_internalvar (lookup_internalvar ("__"), last_examine_value); +} + +/* Commands for printing types of things. */ + +static void +whatis_command (exp) + char *exp; +{ + struct expression *expr; + register value val; + register struct cleanup *old_chain; + + if (exp) + { + expr = parse_c_expression (exp); + old_chain = make_cleanup (free_current_contents, &expr); + val = evaluate_type (expr); + } + else + val = access_value_history (0); + + printf ("type = "); + type_print (VALUE_TYPE (val), "", stdout, 1); + printf ("\n"); + + if (exp) + do_cleanups (old_chain); +} + +static void +ptype_command (typename) + char *typename; +{ + register char *p = typename; + register int len; + extern struct block *get_current_block (); + register struct block *b + = (have_inferior_p () || have_core_file_p ()) ? get_current_block () : 0; + register struct type *type; + + if (typename == 0) + error_no_arg ("type name"); + + while (*p && *p != ' ' && *p != '\t') p++; + len = p - typename; + while (*p == ' ' || *p == '\t') p++; + + if (len == 6 && !strncmp (typename, "struct", 6)) + type = lookup_struct (p, b); + else if (len == 5 && !strncmp (typename, "union", 5)) + type = lookup_union (p, b); + else if (len == 4 && !strncmp (typename, "enum", 4)) + type = lookup_enum (p, b); + else + { + type = lookup_typename (typename, b, 1); + if (type == 0) + { + register struct symbol *sym + = lookup_symbol (typename, b, STRUCT_NAMESPACE); + if (sym == 0) + error ("No type named %s.", typename); + printf ("No type named %s, but there is a ", + typename); + switch (TYPE_CODE (SYMBOL_TYPE (sym))) + { + case TYPE_CODE_STRUCT: + printf ("struct"); + break; + + case TYPE_CODE_UNION: + printf ("union"); + break; + + case TYPE_CODE_ENUM: + printf ("enum"); + } + printf (" %s. Type \"help ptype\".\n", typename); + type = SYMBOL_TYPE (sym); + } + } + + type_print (type, "", stdout, 1); + printf ("\n"); +} + +struct display +{ + /* Chain link to next auto-display item. */ + struct display *next; + /* Expression to be evaluated and displayed. */ + struct expression *exp; + /* Item number of this auto-display item. */ + int number; + /* Display format specified. */ + struct format_data format; + /* Block in which expression is to be evaluated. */ + struct block *block; +}; + +/* Chain of expressions whose values should be displayed + automatically each time the program stops. */ + +static struct display *display_chain; + +static int display_number; + +/* Add an expression to the auto-display chain. + Specify the expression. */ + +static void +display_command (exp) + char *exp; +{ + struct format_data fmt; + register struct expression *expr; + register struct display *new; + + if (exp == 0) + { + do_displays (); + return; + } + + if (*exp == '/') + { + exp++; + fmt = decode_format (&exp, 0, 0); + if (fmt.size && fmt.format == 0) + fmt.format = 'x'; + if (fmt.format == 'i' || fmt.format == 's') + fmt.size = 'b'; + } + else + { + fmt.format = 0; + fmt.size = 0; + fmt.count = 0; + } + + expr = parse_c_expression (exp); + + new = (struct display *) xmalloc (sizeof (struct display)); + + new->exp = expr; + new->next = display_chain; + new->number = ++display_number; + new->format = fmt; + display_chain = new; + + dont_repeat (); +} + +static void +free_display (d) + struct display *d; +{ + free (d->exp); + free (d); +} + +/* Clear out the display_chain. + Done when new symtabs are loaded, since this invalidates + the types stored in many expressions. */ + +void +clear_displays () +{ + register struct display *d; + + while (d = display_chain) + { + free (d->exp); + display_chain = d->next; + free (d); + } +} + +/* Delete some values from the auto-display chain. + Specify the element numbers. */ + +static void +undisplay_command (args) + char *args; +{ + register char *p = args; + register char *p1; + register int num; + register struct display *d, *d1; + + if (args == 0) + { + if (query ("Delete all auto-display expressions? ")) + clear_displays (); + dont_repeat (); + return; + } + + while (*p) + { + p1 = p; + while (*p1 >= '0' && *p1 <= '9') p1++; + if (*p1 && *p1 != ' ' && *p1 != '\t') + error ("Arguments must be display numbers."); + + num = atoi (p); + + if (display_chain->number == num) + { + d1 = display_chain; + display_chain = d1->next; + free_display (d1); + } + else + for (d = display_chain; ; d = d->next) + { + if (d->next == 0) + error ("No display number %d.", num); + if (d->next->number == num) + { + d1 = d->next; + d->next = d1->next; + free_display (d1); + break; + } + } + + p = p1; + while (*p == ' ' || *p == '\t') p++; + } + dont_repeat (); +} + +/* Display all of the values on the auto-display chain. */ + +void +do_displays () +{ + register struct display *d; + + for (d = display_chain; d; d = d->next) + { + printf ("%d: ", d->number); + if (d->format.size) + { + printf ("x/"); + if (d->format.count != 1) + printf ("%d", d->format.count); + printf ("%c", d->format.format); + if (d->format.format != 'i' && d->format.format != 's') + printf ("%c", d->format.size); + printf (" "); + print_expression (d->exp, stdout); + if (d->format.count != 1) + printf ("\n"); + else + printf (" "); + do_examine (d->format, + value_as_long (evaluate_expression (d->exp))); + } + else + { + if (d->format.format) + printf ("/%c ", d->format.format); + print_expression (d->exp, stdout); + printf (" = "); + print_formatted (evaluate_expression (d->exp), d->format.format); + printf ("\n"); + } + fflush (stdout); + } +} + +static void +display_info () +{ + register struct display *d; + + if (!display_chain) + printf ("There are no auto-display expressions now.\n"); + else + printf ("Auto-display expressions now in effect:\n"); + for (d = display_chain; d; d = d->next) + { + printf ("%d: ", d->number); + if (d->format.size) + printf ("/%d%c%c ", d->format.count, d->format.size, + d->format.format); + else if (d->format.format) + printf ("/%c ", d->format.format); + print_expression (d->exp, stdout); + printf ("\n"); + fflush (stdout); + } +} + +/* Print the value in stack frame FRAME of a variable + specified by a struct symbol. */ + +void +print_variable_value (var, frame, stream) + struct symbol *var; + CORE_ADDR frame; + FILE *stream; +{ + value val = read_var_value (var, frame); + value_print (val, stream); +} + +/* Print the arguments of a stack frame, given the function FUNC + running in that frame (as a symbol), the address of the arglist, + and the number of args according to the stack frame (or -1 if unknown). */ + +static void print_frame_nameless_args (); + +print_frame_args (func, addr, num, stream) + struct symbol *func; + register CORE_ADDR addr; + int num; + FILE *stream; +{ + struct block *b; + int nsyms = 0; + int first = 1; + register int i; + register int last_offset = FRAME_ARGS_SKIP; + register struct symbol *sym, *nextsym; + register value val; + + if (func) + { + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + } + + while (1) + { + /* Find first arg that is not before LAST_OFFSET. */ + nextsym = 0; + for (i = 0; i < nsyms; i++) + { + QUIT; + sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (sym) == LOC_ARG + && SYMBOL_VALUE (sym) >= last_offset + && (nextsym == 0 + || SYMBOL_VALUE (sym) < SYMBOL_VALUE (nextsym))) + nextsym = sym; + } + if (nextsym == 0) + break; + sym = nextsym; + /* Print any nameless args between the last arg printed + and the next arg. */ + if (last_offset != (SYMBOL_VALUE (sym) / sizeof (int)) * sizeof (int)) + { + print_frame_nameless_args (addr, last_offset, SYMBOL_VALUE (sym), + stream); + first = 0; + } + /* Print the next arg. */ + val = value_at (SYMBOL_TYPE (sym), addr + SYMBOL_VALUE (sym)); + if (! first) + fprintf (stream, ", "); + fprintf (stream, "%s=", SYMBOL_NAME (sym)); + value_print (val, stream); + first = 0; + last_offset = SYMBOL_VALUE (sym) + TYPE_LENGTH (SYMBOL_TYPE (sym)); + /* Round up address of next arg to multiple of size of int. */ + last_offset + = ((last_offset + sizeof (int) - 1) / sizeof (int)) * sizeof (int); + } + if (num >= 0 && num * sizeof (int) + FRAME_ARGS_SKIP > last_offset) + print_frame_nameless_args (addr, last_offset, + num * sizeof (int) + FRAME_ARGS_SKIP, stream); +} + +static void +print_frame_nameless_args (argsaddr, start, end, stream) + CORE_ADDR argsaddr; + int start; + int end; + FILE *stream; +{ + while (start < end) + { + QUIT; + if (start != FRAME_ARGS_SKIP) + fprintf (stream, ", "); + fprintf (stream, "%d", + read_memory_integer (argsaddr + start, sizeof (int))); + start += sizeof (int); + } +} + +static +initialize () +{ + add_info ("address", address_info, + "Describe where variable VAR is stored."); + + add_com ("x", class_vars, x_command, + "Examine memory: x/FMT ADDRESS.\n\ +ADDRESS is an expression for the memory address to examine.\n\ +FMT is a repeat count followed by a format letter and a size letter.\n\ +Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\ + f(float), a(address), i(instruction), c(char) and s(string).\n\ +Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\ + g is meaningful only with f, for type double.\n\ +The specified number of objects of the specified size are printed\n\ +according to the format.\n\n\ +Defaults for format and size letters are those previously used.\n\ +Default count is 1. Default address is following last thing printed\n\ +with this command or \"print\"."); + + add_com ("ptype", class_vars, ptype_command, + "Print definition of type TYPE.\n\ +Argument may be a type name defined by typedef, or \"struct STRUCTNAME\"\n\ +or \"union UNIONNAME\" or \"enum ENUMNAME\".\n\ +The selected stack frame's lexical context is used to look up the name."); + + add_com ("whatis", class_vars, whatis_command, + "Print data type of expression EXP."); + + add_info ("display", display_info, + "Expressions to display when program stops, with code numbers."); + add_com ("undisplay", class_vars, undisplay_command, + "Cancel some expressions to be displayed whenever program stops.\n\ +Arguments are the code numbers of the expressions to stop displaying.\n\ +No argument means cancel all automatic-display expressions.\n\ +Do \"info display\" to see current list of code numbers."); + add_com ("display", class_vars, display_command, + "Print value of expression EXP each time the program stops.\n\ +/FMT may be used before EXP as in the \"print\" command.\n\ +/FMT \"i\" or \"s\" or including a size-letter is allowed,\n\ +as in the \"x\" command, and then EXP is used to get the address to examine\n\ +and examining is done as in the \"x\" command.\n\n\ +With no argument, display all currently requested auto-display expressions.\n\ +Use \"undisplay\" to cancel display requests previously made."); + + add_com ("output", class_vars, output_command, + "Like \"print\" but don't put in value history and don't print newline.\n\ +This is useful in user-defined commands."); + + add_com ("set", class_vars, set_command, + "Perform an assignment VAR = EXP. You must type the \"=\".\n\ +VAR may be a debugger \"convenience\" variables (names starting with $),\n\ +a register (a few standard names starting with $), or an actual variable\n\ +in the program being debugger. EXP is any expression."); + + add_com ("print", class_vars, print_command, + concat ("Print value of expression EXP.\n\ +Variables accessible are those of the lexical environment of the selected\n\ +stack frame, plus all those whose scope is global or an entire file.\n\ +\n\ +$NUM gets previous value number NUM. $ and $$ are the last two values.\n\ +$$NUM refers to NUM'th value back from the last one.\n\ +Names starting with $ refer to registers (with the values they would have\n\ +if the program were to return to the stack frame now selected, restoring\n\ +all registers saved by frames farther in) or else to debugger\n\ +\"convenience\" variables (any such name not a known register).\n\ +Use assignment expressions to give values to convenience variables.\n", + "\n\ +\{TYPE}ADREXP refers to a datum of data type TYPE, located at address ADREXP.\n\ +@ is a binary operator for treating consecutive data objects\n\ +anywhere in memory as an array. FOO@NUM gives an array whose first\n\ +element is FOO, whose second element is stored in the space following\n\ +where FOO is stored, etc. FOO must be an expression whose value\n\ +resides in memory.\n", + "\n\ +EXP may be preceded with /FMT, where FMT is a format letter\n\ +but no count or size letter (see \"x\" command).")); + add_com_alias ("p", "print", class_vars, 1); +} + +END_FILE diff --git a/gdb/song b/gdb/song new file mode 100644 index 00000000000..ad65ee9a429 --- /dev/null +++ b/gdb/song @@ -0,0 +1,44 @@ +Date: Tue, 6 Oct 87 08:52:07 PDT +To: bug-gnu-emacs@prep.ai.mit.edu +From: Lynn Slater +Sender: silvlis!wobegon!lrs@sun.com +Organization: Silvar-Lisco, 1080 Marsh Road, Menlo Park, CA 94025-1053 +Phone.......: (415) 853-6336 (Office); (415) 796-4149 (Home) +Subject: GDB sing-along + + +Somebody asked us what was GDB. With apologies to Oscar Hemmerstein +II, Richard Rodgers, and Julie Andrews, we offered the following reply: + +Let's start at the very beginning, a very good place to start, + When you're learning to sing, its Do, Re, Mi; + When you're learning to code, its G, D, B. + (background) G, D, B. + The first three letters just happen to be, G, D, B. + (background) G, D, B. + +(Chorus) + G!, GNU!, it's Stallman's hope, + + B, a break I set myself. + + D, debug that rotten code, + + Run, a far, far way to go. + + Print, to see what you have done, + + Set, a patch that follows print. + + Quit, and recompile your code - - - + +That will bring it back to G, + D, + B, + + +(Resume from the Chorus) + + +:-) Joel Bion, Mark Baushke, and Lynn Slater :-) + diff --git a/gdb/source.c b/gdb/source.c new file mode 100644 index 00000000000..27ffd8fdb06 --- /dev/null +++ b/gdb/source.c @@ -0,0 +1,667 @@ +/* List lines of source files for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include +#include +#include +#include "defs.h" +#include "initialize.h" +#include "symtab.h" + +/* Path of directories to search for source files. + Same format as the PATH environment variable's value. */ + +static char *source_path; + +/* Symtab of default file for listing lines of. */ + +struct symtab *current_source_symtab; + +/* Default next line to list. */ + +int current_source_line; + +/* Line for "info line" to work on if no line specified. */ + +static int line_info_default_line; + +/* First line number listed by last listing command. */ + +static int first_line_listed; + +START_FILE + +/* Set the source file default for the "list" command, + specifying a symtab. */ + +void +select_source_symtab (s) + register struct symtab *s; +{ + if (s) + { + struct symtab_and_line sal; + + /* Make the default place to list be the function `main' + if one exists. */ + if (lookup_symbol ("main", 0, VAR_NAMESPACE)) + { + sal = decode_line_spec ("main", 1); + current_source_symtab = sal.symtab; + current_source_line = sal.line - 9; + return; + } + + /* If there is no `main', use the last symtab in the list, + which is actually the first found in the file's symbol table. + But ignore .h files. */ + do + { + char *name = s->filename; + int len = strlen (name); + if (! (len > 2 && !strcmp (&name[len - 2], ".h"))) + current_source_symtab = s; + s = s->next; + } + while (s); + current_source_line = 1; + } +} + +static void +directories_info () +{ + printf ("Source directories searched: %s\n", source_path); +} + +static void +init_source_path () +{ + register struct symtab *s; + char wd[MAXPATHLEN]; + if (getwd (wd) == NULL) + perror_with_name ("getwd"); + + source_path = savestring (wd, strlen (wd)); + + /* Forget what we learned about line positions in source files; + must check again now since files may be found in + a different directory now. */ + for (s = symtab_list; s; s = s->next) + if (s->line_charpos != 0) + { + free (s->line_charpos); + s->line_charpos = 0; + } +} + +void +directory_command (dirname, from_tty) + char *dirname; + int from_tty; +{ + char *old = source_path; + + char wd[MAXPATHLEN]; + if (getwd (wd) == NULL) + perror_with_name ("getwd"); + + if (dirname == 0) + { + if (query ("Reinitialize source path to %s? ", wd)) + { + init_source_path (); + free (old); + } + } + else + { + struct stat st; + register int len = strlen (dirname); + register char *tem; + extern char *index (); + + if (index (dirname, ':')) + error ("Please add one directory at a time to the source path."); + if (dirname[len - 1] == '/') + /* Sigh. "foo/" => "foo" */ + dirname[--len] == '\0'; + + while (dirname[len - 1] == '.') + { + if (len == 1) + { + /* "." => getwd () */ + dirname = wd; + goto append; + } + else if (dirname[len - 2] == '/') + { + if (len == 2) + { + /* "/." => "/" */ + dirname[--len] = '\0'; + goto append; + } + else + { + /* "...foo/." => "...foo" */ + dirname[len -= 2] = '\0'; + continue; + } + } + break; + } + + if (dirname[0] != '/') + dirname = concat (wd, "/", dirname); + else + dirname = savestring (dirname, len); + make_cleanup (free, dirname); + + if (stat (dirname, &st) < 0) + perror_with_name (dirname); + if ((st.st_mode & S_IFMT) != S_IFDIR) + error ("%s is not a directory.", dirname); + + append: + len = strlen (dirname); + tem = source_path; + while (1) + { + if (!strncmp (tem, dirname, len) + && (tem[len] == '\0' || tem[len] == ':')) + { + printf ("\"%s\" is already in the source path.\n", + dirname); + break; + } + tem = index (tem, ':'); + if (tem) + tem++; + else + { + source_path = concat (old, ":", dirname); + free (old); + break; + } + } + if (from_tty) + directories_info (); + } +} + +/* Open a file named STRING, searching path PATH (dir names sep by colons) + using mode MODE and protection bits PROT in the calls to open. + If TRY_CWD_FIRST, try to open ./STRING before searching PATH. + (ie pretend the first element of PATH is ".") + If FILENAMED_OPENED is non-null, set it to a newly allocated string naming + the actual file opened (this string will always start with a "/" + + If a file is found, return the descriptor. + Otherwise, return -1, with errno set for the last name we tried to open. */ + +/* >>>> This should only allow files of certain types, + >>>> eg executable, non-directory */ +int +openp (path, try_cwd_first, string, mode, prot, filename_opened) + char *path; + int try_cwd_first; + char *string; + int mode; + int prot; + char **filename_opened; +{ + register int fd; + register char *filename; + register char *p, *p1; + register int len; + + /* ./foo => foo */ + while (string[0] == '.' && string[1] == '/') + string += 2; + + if (try_cwd_first || string[0] == '/') + { + filename = string; + fd = open (filename, mode, prot); + if (fd >= 0 || string[0] == '/') + goto done; + } + + filename = (char *) alloca (strlen (path) + strlen (string) + 2); + fd = -1; + for (p = path; p; p = p1 ? p1 + 1 : 0) + { + p1 = (char *) index (p, ':'); + if (p1) + len = p1 - p; + else + len = strlen (p); + + strncpy (filename, p, len); + filename[len] = 0; + strcat (filename, "/"); + strcat (filename, string); + + fd = open (filename, mode, prot); + if (fd >= 0) break; + } + + done: + if (filename_opened) + if (fd < 0) + *filename_opened = (char *) 0; + else if (filename[0] == '/') + *filename_opened = savestring (filename, strlen (filename)); + else + { + char dirname[MAXPATHLEN]; + if (getwd (dirname) == NULL) + perror_with_name ("getwd"); + *filename_opened = concat (dirname, "/", filename); + } + + return fd; +} + +/* Create and initialize the table S->line_charpos that records + the positions of the lines in the source file, which is assumed + to be open on descriptor DESC. + All set S->nlines to the number of such lines. */ + +static void +find_source_lines (s, desc) + struct symtab *s; + int desc; +{ + struct stat st; + register char *data, *p, *end; + int nlines = 0; + int lines_allocated = 1000; + int *line_charpos = (int *) xmalloc (lines_allocated * sizeof (int)); + extern int exec_mtime; + + fstat (desc, &st); + if (get_exec_file () != 0 && exec_mtime < st.st_mtime) + printf ("Source file is more recent than executable.\n"); + + data = (char *) alloca (st.st_size); + myread (desc, data, st.st_size); + end = data + st.st_size; + p = data; + line_charpos[0] = 0; + nlines = 1; + while (p != end) + { + if (*p++ == '\n') + { + if (nlines == lines_allocated) + line_charpos = (int *) xrealloc (line_charpos, + sizeof (int) * (lines_allocated *= 2)); + line_charpos[nlines++] = p - data; + } + } + s->nlines = nlines; + s->line_charpos = (int *) xrealloc (line_charpos, nlines * sizeof (int)); +} + +/* Return the character position of a line LINE in symtab S. + Return 0 if anything is invalid. */ + +int +source_line_charpos (s, line) + struct symtab *s; + int line; +{ + if (!s) return 0; + if (!s->line_charpos || line <= 0) return 0; + if (line > s->nlines) + line = s->nlines; + return s->line_charpos[line - 1]; +} + +/* Return the line number of character position POS in symtab S. */ + +int +source_charpos_line (s, chr) + register struct symtab *s; + register int chr; +{ + register int line = 0; + register int *lnp; + + if (s == 0 || s->line_charpos == 0) return 0; + lnp = s->line_charpos; + /* Files are usually short, so sequential search is Ok */ + while (line < s->nlines && *lnp <= chr) + { + line++; + lnp++; + } + if (line >= s->nlines) + line = s->nlines; + return line; +} + +/* Get full pathname and line number positions for a symtab. + Return nonzero if line numbers may have changed. + Set *FULLNAME to actual name of the file as found by `openp', + or to 0 if the file is not found. */ + +int +get_filename_and_charpos (s, line, fullname) + struct symtab *s; + int line; + char **fullname; +{ + register int desc, linenums_changed = 0; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, fullname); + if (desc < 0) + { + *fullname = NULL; + return 0; + } + if (s->line_charpos == 0) linenums_changed = 1; + if (linenums_changed) find_source_lines (s, desc); + close (desc); + return linenums_changed; +} + +/* Print source lines from the file of symtab S, + starting with line number LINE and stopping before line number STOPLINE. */ + +void +print_source_lines (s, line, stopline) + struct symtab *s; + int line, stopline; +{ + register int c; + register int desc; + register FILE *stream; + int nlines = stopline - line; + + desc = openp (source_path, 0, s->filename, O_RDONLY, 0, (char **) 0); + if (desc < 0) + perror_with_name (s->filename); + + if (s->line_charpos == 0) + find_source_lines (s, desc); + + if (line < 1 || line >= s->nlines) + { + close (desc); + error ("Line number out of range; %s has %d lines.", + s->filename, s->nlines); + } + + if (lseek (desc, s->line_charpos[line - 1], 0) < 0) + { + close (desc); + perror_with_name (s->filename); + } + + current_source_symtab = s; + current_source_line = line; + first_line_listed = line; + + stream = fdopen (desc, "r"); + clearerr (stream); + + while (nlines-- > 0) + { + c = fgetc (stream); + if (c == EOF) break; + line_info_default_line = current_source_line; + printf ("%d\t", current_source_line++); + do + { + if (c < 040 && c != '\t' && c != '\n') + { + fputc ('^', stdout); + fputc (c + 0100, stdout); + } + else if (c == 0177) + printf ("^?"); + else + fputc (c, stdout); + } while (c != '\n' && (c = fgetc (stream)) >= 0); + } + + fclose (stream); +} + +static void +list_command (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal, sal_end; + struct symbol *sym; + char *arg1; + int no_end = 1; + int dummy_end = 0; + int dummy_beg = 0; + int linenum_beg = 0; + char *p; + + if (symtab_list == 0) + error ("Listing source lines requires symbols."); + + /* "l" or "l +" lists next ten lines. */ + + if (arg == 0 || !strcmp (arg, "+")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, current_source_line, + current_source_line + 10); + return; + } + + /* "l -" lists previous ten lines, the ones before the ten just listed. */ + if (!strcmp (arg, "-")) + { + if (current_source_symtab == 0) + error ("No default source file yet. Do \"help list\"."); + print_source_lines (current_source_symtab, + max (first_line_listed - 10, 1), + first_line_listed); + return; + } + + /* Now if there is only one argument, decode it in SAL + and set NO_END. + If there are two arguments, decode them in SAL and SAL_END + and clear NO_END; however, if one of the arguments is blank, + set DUMMY_BEG or DUMMY_END to record that fact. */ + + arg1 = arg; + if (*arg1 == ',') + dummy_beg = 1; + else + sal = decode_line_1 (&arg1, 0, 0, 0); + + /* Record whether the BEG arg is all digits. */ + + for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++); + linenum_beg = (p == arg1); + + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == ',') + { + no_end = 0; + arg1++; + while (*arg1 == ' ' || *arg1 == '\t') + arg1++; + if (*arg1 == 0) + dummy_end = 1; + else if (dummy_beg) + sal_end = decode_line_1 (&arg1, 0, 0, 0); + else + sal_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line); + } + + if (*arg1) + error ("Junk at end of line specification."); + + if (!no_end && !dummy_beg && !dummy_end + && sal.symtab != sal_end.symtab) + error ("Specified start and end are in different files."); + if (dummy_beg && dummy_end) + error ("Two empty args do not say what lines to list."); + + /* if line was specified by address, + first print exactly which line, and which file. + In this case, sal.symtab == 0 means address is outside + of all known source files, not that user failed to give a filename. */ + if (*arg == '*') + { + if (sal.symtab == 0) + error ("No source file for address 0x%x.", sal.pc); + sym = find_pc_function (sal.pc); + if (sym) + printf ("0x%x is in %s (%s, line %d).\n", + sal.pc, SYMBOL_NAME (sym), sal.symtab->filename, sal.line); + else + printf ("0x%x is in %s, line %d.\n", + sal.pc, sal.symtab->filename, sal.line); + } + + /* If line was not specified by just a line number, + and it does not imply a symtab, it must be an undebuggable symbol + which means no source code. */ + + if (! linenum_beg && sal.symtab == 0) + error ("No line number known for %s.", arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + + if (dummy_beg && sal_end.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + if (dummy_beg) + print_source_lines (sal_end.symtab, max (sal_end.line - 9, 1), + sal_end.line + 1); + else if (sal.symtab == 0) + error ("No default source file yet. Do \"help list\"."); + else if (no_end) + print_source_lines (sal.symtab, max (sal.line - 5, 1), sal.line + 5); + else + print_source_lines (sal.symtab, sal.line, + dummy_end ? sal.line + 10 : sal_end.line + 1); +} + +/* Print info on range of pc's in a specified line. */ + +static void +line_info (arg, from_tty) + char *arg; + int from_tty; +{ + struct symtab_and_line sal; + int start_pc, end_pc; + + if (arg == 0) + { + sal.symtab = current_source_symtab; + sal.line = line_info_default_line; + } + else + { + sal = decode_line_spec (arg); + + /* If this command is repeated with RET, + turn it into the no-arg variant. */ + + if (from_tty) + *arg = 0; + } + + if (sal.symtab == 0) + error ("No source file specified."); + if (sal.line > 0 + && find_line_pc_range (sal.symtab, sal.line, &start_pc, &end_pc)) + { + if (start_pc == end_pc) + printf ("Line %d of \"%s\" is at pc 0x%x but contains no code.\n", + sal.line, sal.symtab->filename, start_pc); + else + printf ("Line %d of \"%s\" starts at pc 0x%x and ends at 0x%x.\n", + sal.line, sal.symtab->filename, start_pc, end_pc); + /* x/i should display this line's code. */ + set_next_address (start_pc); + /* Repeating "info line" should do the following line. */ + line_info_default_line = sal.line + 1; + } + else + printf ("Line number %d is out of range for \"%s\".\n", + sal.line, sal.symtab->filename); +} + +static +initialize () +{ + current_source_symtab = 0; + init_source_path (); + + add_com ("directory", class_files, directory_command, + "Add directory DIR to end of search path for source files.\n\ +With no argument, reset the search path to just the working directory\n\ +and forget cached info on line positions in source files."); + + add_info ("directories", directories_info, + "Current search path for finding source files."); + + add_info ("line", line_info, + "Core addresses of the code for a source line.\n\ +Line can be specified as\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ +Default is to describe the last source line that was listed.\n\n\ +This sets the default address for \"x\" to the line's first instruction\n\ +so that \"x/i\" suffices to start examining the machine code.\n\ +The address is also stored as the value of \"$_\"."); + + add_com ("list", class_files, list_command, + "List specified function or line.\n\ +With no argument, lists ten more lines after or around previous listing.\n\ +\"list -\" lists the ten lines before a previous ten-line listing.\n\ +One argument specifies a line, and ten lines are listed around that line.\n\ +Two arguments with comma between specify starting and ending lines to list.\n\ +Lines can be specified in these ways:\n\ + LINENUM, to list around that line in current file,\n\ + FILE:LINENUM, to list around that line in that file,\n\ + FUNCTION, to list around beginning of that function,\n\ + FILE:FUNCTION, to distinguish among like-named static functions.\n\ + *ADDRESS, to list around the line containing that address.\n\ +With two args if one is empty it stands for ten lines away from the other arg."); +} + +END_FILE diff --git a/gdb/stack.c b/gdb/stack.c new file mode 100644 index 00000000000..26987295635 --- /dev/null +++ b/gdb/stack.c @@ -0,0 +1,612 @@ +/* Print and select stack frames for GDB, the GNU debugger. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +START_FILE + +/* Thie "selected" stack frame is used by default for local and arg access. + May be zero, for no selected frame. */ + +FRAME selected_frame; + +/* Level of the selected frame: + 0 for innermost, 1 for its caller, ... + or -1 for frame specified by address with no defined level. */ + +int selected_frame_level; + +static void select_calling_frame (); + +void print_frame_info (); + +/* Print a stack frame briefly. FRAME should be the frame address + and LEVEL should be its level in the stack (or -1 for level not defined). + This prints the level, the function executing, the arguments, + and the file name and line number. + If the pc is not at the beginning of the source line, + the actual pc is printed at the beginning. + + If SOURCE is 1, print the source line as well. + If SOURCE is -1, print ONLY the source line. */ + +static void +print_stack_frame (frame, level, source) + FRAME frame; + int level; + int source; +{ + struct frame_info fi; + + fi = get_frame_info (frame); + + print_frame_info (&fi, level, source, 1); +} + +void +print_frame_info (fi, level, source, args) + struct frame_info *fi; + register int level; + int source; + int args; +{ + register FRAME frame = fi->frame; + struct symtab_and_line sal; + struct symbol *func; + register char *funname = 0; + int numargs; + + sal = find_pc_line (fi->pc, fi->next_frame); + func = get_frame_function (frame); + if (func) + funname = SYMBOL_NAME (func); + else + { + register int misc_index = find_pc_misc_function (fi->pc); + if (misc_index >= 0) + funname = misc_function_vector[misc_index].name; + } + + if (source >= 0 || !sal.symtab) + { + /* This avoids a bug in cc on the sun. */ + struct frame_info tem; + tem = *fi; + + if (level >= 0) + printf ("#%-2d ", level); + if (fi->pc != sal.pc || !sal.symtab) + printf ("0x%x in ", fi->pc); + printf ("%s (", funname ? funname : "??"); + if (args) + { + FRAME_NUM_ARGS (numargs, tem); + print_frame_args (func, FRAME_ARGS_ADDRESS (tem), numargs, stdout); + } + printf (")"); + if (sal.symtab) + printf (" (%s line %d)", sal.symtab->filename, sal.line); + printf ("\n"); + } + + if (source != 0 && sal.symtab) + { + if (source < 0 && fi->pc != sal.pc) + printf ("0x%x\t", fi->pc); + print_source_lines (sal.symtab, sal.line, sal.line + 1); + current_source_line = max (sal.line - 5, 1); + } + if (source != 0) + set_default_breakpoint (1, fi->pc, sal.symtab, sal.line); + + fflush (stdout); +} + +/* Call here to print info on selected frame, after a trap. */ + +void +print_sel_frame (just_source) + int just_source; +{ + print_stack_frame (selected_frame, -1, just_source ? -1 : 1); +} + +/* Print info on the selected frame, including level number + but not source. */ + +print_selected_frame () +{ + print_stack_frame (selected_frame, selected_frame_level, 0); +} + +/* Print verbosely the selected frame or the frame at address ADDR. + This means absolutely all information in the frame is printed. */ + +static void +frame_info (addr_exp) + char *addr_exp; +{ + FRAME frame = addr_exp ? parse_and_eval_address (addr_exp) : selected_frame; + struct frame_info fi; + struct frame_saved_regs fsr; + struct symtab_and_line sal; + struct symbol *func; + FRAME calling_frame; + int i, count; + char *funname = 0; + int numargs; + + fi = get_frame_info (frame); + get_frame_saved_regs (&fi, &fsr); + sal = find_pc_line (fi.pc, fi.next_frame); + func = get_frame_function (frame); + if (func) + funname = SYMBOL_NAME (func); + else + { + register int misc_index = find_pc_misc_function (fi.pc); + if (misc_index >= 0) + funname = misc_function_vector[misc_index].name; + } + calling_frame = get_prev_frame (frame); + + if (!addr_exp && selected_frame_level >= 0) + printf ("Stack level %d, frame at 0x%x:\n pc = 0x%x", + selected_frame_level, frame, fi.pc); + else + printf ("Stack frame at 0x%x:\n pc = 0x%x", + frame, fi.pc); + + if (funname) + printf (" in %s", funname); + if (sal.symtab) + printf (" (%s line %d)", sal.symtab->filename, sal.line); + printf ("; saved pc 0x%x\n", FRAME_SAVED_PC (frame)); + if (calling_frame) + printf (" called by frame at 0x%x", calling_frame); + if (fi.next_frame && calling_frame) + printf (","); + if (fi.next_frame) + printf (" caller of frame at 0x%x", fi.next_frame); + if (fi.next_frame || calling_frame) + printf ("\n"); + printf (" Arglist at 0x%x,", FRAME_ARGS_ADDRESS (fi)); + FRAME_NUM_ARGS (i, fi); + if (i < 0) + printf (" args: "); + else if (i == 0) + printf (" no args."); + else if (i == 1) + printf (" 1 arg: "); + else + printf (" %d args: ", i); + + FRAME_NUM_ARGS (numargs, fi); + print_frame_args (func, FRAME_ARGS_ADDRESS (fi), numargs, stdout); + printf ("\n"); + count = 0; + for (i = 0; i < NUM_REGS; i++) + if (fsr.regs[i]) + { + if (count % 4 != 0) + printf (", "); + else + { + if (count == 0) + printf (" Saved registers:"); + printf ("\n "); + } + printf ("%s at 0x%x", reg_names[i], fsr.regs[i]); + count++; + } + if (count) + printf ("\n"); +} + +/* Print briefly all stack frames or just the innermost COUNT frames. */ + +static void +backtrace_command (count_exp) + char *count_exp; +{ + struct frame_info fi; + register int count; + register FRAME frame; + register int i; + + if (count_exp) + count = parse_and_eval_address (count_exp); + else + count = -1; + + for (i = 0, frame = get_current_frame (), fi = get_frame_info (frame); + frame && count--; + i++, fi = get_prev_frame_info (fi.frame), frame = fi.frame) + { + QUIT; + print_frame_info (&fi, i, 0, 1); + } +} + +/* Print the local variables of a block B active in FRAME. */ + +static void +print_block_frame_locals (b, frame, stream) + struct block *b; + register FRAME frame; + register FILE *stream; +{ + int nsyms; + register int i; + register struct symbol *sym; + + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (sym) == LOC_LOCAL + || SYMBOL_CLASS (sym) == LOC_REGISTER) + { + fprintf (stream, "%s = ", SYMBOL_NAME (sym)); + print_variable_value (sym, frame, stream); + fprintf (stream, "\n"); + fflush (stream); + } + } +} + +/* Print on STREAM all the local variables in frame FRAME, + including all the blocks active in that frame + at its current pc. + + Returns 1 if the job was done, + or 0 if nothing was printed because we have no info + on the function running in FRAME. */ + +static int +print_frame_local_vars (frame, stream) + register FRAME frame; + register FILE *stream; +{ + register struct block *block = get_frame_block (frame); + if (block == 0) + return 0; + while (block != 0) + { + print_block_frame_locals (block, frame, stream); + /* After handling the function's top-level block, stop. + Don't continue to its superblock, the block of + per-file symbols. */ + if (BLOCK_FUNCTION (block)) + break; + block = BLOCK_SUPERBLOCK (block); + } + return 1; +} + +static void +locals_info () +{ + print_frame_local_vars (selected_frame, stdout); +} + +static int +print_frame_arg_vars (frame, stream) + register FRAME frame; + register FILE *stream; +{ + struct symbol *func = get_frame_function (frame); + register struct block *b; + int nsyms; + register int i; + register struct symbol *sym; + + if (func == 0) + return 0; + + b = SYMBOL_BLOCK_VALUE (func); + nsyms = BLOCK_NSYMS (b); + + for (i = 0; i < nsyms; i++) + { + sym = BLOCK_SYM (b, i); + if (SYMBOL_CLASS (sym) == LOC_ARG) + { + fprintf (stream, "%s = ", SYMBOL_NAME (sym)); + print_variable_value (sym, frame, stream); + fprintf (stream, "\n"); + fflush (stream); + } + } + + return 1; +} + +static void +args_info () +{ + print_frame_arg_vars (selected_frame, stdout); +} + +/* Select frame FRAME, and note that its stack level is LEVEL. + LEVEL may be -1 if an actual level number is not known. */ + +void +select_frame (frame, level) + FRAME frame; + int level; +{ + selected_frame = frame; + selected_frame_level = level; +} + +/* Store the selected frame and its level into *FRAMEP and *LEVELP. */ + +void +record_selected_frame (framep, levelp) + FRAME *framep; + int *levelp; +{ + *framep = selected_frame; + *levelp = selected_frame_level; +} + +/* Return the symbol-block in which the selected frame is executing. + Can return zero under various legitimate circumstances. */ + +struct block * +get_selected_block () +{ + if (!have_inferior_p () && !have_core_file_p ()) + return 0; + + if (!selected_frame) + return get_current_block (); + return get_frame_block (selected_frame); +} + +/* Find a frame a certain number of levels away from FRAME. + LEVEL_OFFSET_PTR points to an int containing the number of levels. + Positive means go to earlier frames (up); negative, the reverse. + The int that contains the number of levels is counted toward + zero as the frames for those levels are found. + If the top or bottom frame is reached, that frame is returned, + but the final value of *LEVEL_OFFSET_PTR is nonzero and indicates + how much farther the original request asked to go. */ + +FRAME +find_relative_frame (frame, level_offset_ptr) + register FRAME frame; + register int* level_offset_ptr; +{ + register FRAME prev; + struct frame_info fi; + register FRAME frame1, frame2; + + /* Going up is simple: just do get_prev_frame enough times + or until initial frame is reached. */ + while (*level_offset_ptr > 0) + { + prev = get_prev_frame (frame); + if (prev == 0) + break; + (*level_offset_ptr)--; + frame = prev; + } + /* Going down could be done by iterating get_frame_info to + find the next frame, but that would be quadratic + since get_frame_info must scan all the way from the current frame. + The following algotithm is linear. */ + if (*level_offset_ptr < 0) + { + /* First put frame1 at innermost frame + and frame2 N levels up from there. */ + frame1 = get_current_frame (); + frame2 = frame1; + while (*level_offset_ptr < 0 && frame2 != frame) + { + frame2 = get_prev_frame (frame2); + (*level_offset_ptr) ++; + } + /* Then slide frame1 and frame2 up in synchrony + and when frame2 reaches our starting point + frame1 must be N levels down from there. */ + while (frame2 != frame) + { + frame1 = get_prev_frame (frame1); + frame2 = get_prev_frame (frame2); + } + return frame1; + } + return frame; +} + +/* The "frame" command. With no arg, print selected frame briefly. + With arg LEVEL, select the frame at level LEVEL and print it. + With arg larger than 100000, use it as address of frame to select. + If from command file or user-defined command, don't print anything + if we have an argument. */ + +static void +frame_command (level_exp, from_tty) + char *level_exp; + int from_tty; +{ + register int i; + register FRAME frame; + unsigned int level, level1; + + if (level_exp) + { + level1 = level = parse_and_eval_address (level_exp); + if (level > 100000) + { + select_frame (level, -1); + frame_info (0); + return; + } + + frame = find_relative_frame (get_current_frame (), &level1); + if (level1 != 0) + error ("Stack level %d is out of range.", level); + select_frame (frame, level); + if (! from_tty) + return; + } + + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame up one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +static void +up_command (count_exp) + char *count_exp; +{ + register FRAME frame; + int count = 1, count1; + if (count_exp) + count = parse_and_eval_address (count_exp); + count1 = count; + + frame = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + error ("Initial frame selected; you cannot go up."); + select_frame (frame, selected_frame_level + count - count1); + + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +/* Select the frame down one or COUNT stack levels + from the previously selected frame, and print it briefly. */ + +static void +down_command (count_exp) + char *count_exp; +{ + register FRAME frame; + int count = -1, count1; + if (count_exp) + count = - parse_and_eval_address (count_exp); + count1 = count; + + frame = find_relative_frame (selected_frame, &count1); + if (count1 != 0 && count_exp == 0) + error ("Bottom (i.e., innermost) frame selected; you cannot go down."); + select_frame (frame, selected_frame_level + count - count1); + + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +static void +return_command (retval_exp, from_tty) + char *retval_exp; + int from_tty; +{ + struct symbol *thisfun = get_frame_function (selected_frame); + + /* If interactive, require confirmation. */ + + if (from_tty) + { + if (thisfun != 0) + { + if (!query ("Make %s return now? ", SYMBOL_NAME (thisfun))) + error ("Not confirmed."); + } + else + if (!query ("Make selected stack frame return now? ")) + error ("Not confirmed."); + } + + /* Do the real work. Pop until the specified frame is current. */ + + while (selected_frame != get_current_frame ()) + POP_FRAME; + + /* Then pop that frame. */ + + POP_FRAME; + + /* Compute the return value (if any) and store in the place + for return values. */ + + if (retval_exp) + set_return_value (parse_and_eval (retval_exp)); + + /* If interactive, print the frame that is now current. */ + + if (from_tty) + frame_command ("0", 1); +} + +static +initialize () +{ + add_com ("return", class_stack, return_command, + "Make selected stack frame return to its caller.\n\ +Control remains in the debugger, but when you continue\n\ +execution will resume in the frame above the one now selected.\n\ +If an argument is given, it is an expression for the value to return."); + + add_com ("up", class_stack, up_command, + "Select and print stack frame that called this one.\n\ +An argument says how many frames up to go."); + + add_com ("down", class_stack, down_command, + "Select and print stack frame called by this one.\n\ +An argument says how many frames down to go."); + add_com_alias ("do", "down", class_stack, 1); + + add_com ("frame", class_stack, frame_command, + "Select and print a stack frame.\n\ +With no argument, print the selected stack frame. (See also \"info frame\").\n\ +An argument specifies the frame to select.\n\ +It can be a stack frame number or the address of the frame.\n\ +With argument, nothing is printed if input is coming from\n\ +a command file or a user-defined command."); + + add_com_alias ("f", "frame", class_stack, 1); + + add_com ("backtrace", class_stack, backtrace_command, + "Print backtrace of all stack frames, or innermost COUNT frames."); + add_com_alias ("bt", "backtrace", class_stack, 0); + add_com_alias ("where", "backtrace", class_alias, 0); + add_info ("stack", backtrace_command, + "Backtrace of the stack, or innermost COUNT frames."); + add_info_alias ("s", "stack", 1); + add_info ("frame", frame_info, + "All about selected stack frame, or frame at ADDR."); + add_info_alias ("f", "frame", 1); + add_info ("locals", locals_info, + "Local variables of current stack frame."); + add_info ("args", args_info, + "Argument variables of current stack frame."); +} + +END_FILE diff --git a/gdb/standalone.c b/gdb/standalone.c new file mode 100644 index 00000000000..94adf64cf28 --- /dev/null +++ b/gdb/standalone.c @@ -0,0 +1,605 @@ +/* Interface to bare machine for GDB running as kernel debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include +#include +#include +#include + +#if defined (SIGTSTP) && defined (SIGIO) +#include +#include +#endif /* SIGTSTP and SIGIO defined (must be 4.2) */ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +START_FILE + +/* Random system calls, mostly no-ops to prevent link problems */ + +ioctl (desc, code, arg) +{} + +int (* signal ()) () +{} + +kill () +{} + +getpid () +{ + return 0; +} + +sigsetmask () +{} + +chdir () +{} + +char * +getwd (buf) + char *buf; +{ + buf[0] = '/'; + buf[1] = 0; + return buf; +} + +/* Used to check for existence of .gdbinit. Say no. */ + +access () +{ + return -1; +} + +exit () +{ + error ("Fatal error; restarting."); +} + +/* Reading "files". The contents of some files are written into kdb's + data area before it is run. These files are used to contain the + symbol table for kdb to load, and the source files (in case the + kdb user wants to print them). The symbols are stored in a file + named "kdb-symbols" in a.out format (except that all the text and + data have been stripped to save room). + + The files are stored in the following format: + int number of bytes of data for this file, including these four. + char[] name of the file, ending with a null. + padding to multiple of 4 boundary. + char[] file contents. The length can be deduced from what was + specified before. There is no terminating null here. + + If the int at the front is zero, it means there are no more files. + + Opening a file in kdb returns a nonzero value to indicate success, + but the value does not matter. Only one file can be open, and only + for reading. All the primitives for input from the file know + which file is open and ignore what is specified for the descriptor + or for the stdio stream. + + Input with fgetc can be done either on the file that is open + or on stdin (which reads from the terminal through tty_input () */ + +/* Address of data for the files stored in format described above. */ +char *files_start; + +/* The file stream currently open: */ + +char *sourcebeg; /* beginning of contents */ +int sourcesize; /* size of contents */ +char *sourceptr; /* current read pointer */ +int sourceleft; /* number of bytes to eof */ + +/* "descriptor" for the file now open. + Incremented at each close. + If specified descriptor does not match this, + it means the program is trying to use a closed descriptor. + We report an error for that. */ + +int sourcedesc; + +open (filename, modes) + char *filename; + int modes; +{ + register char *next; + extern int errno; + + if (modes) + { + errno = EROFS; + return -1; + } + + if (sourceptr) + { + errno = EMFILE; + return -1; + } + + for (next - files_start; * (int *) next; + next += * (int *) next) + { + if (!strcmp (next + 4, filename)) + { + sourcebeg = next + 4 + strlen (next + 4) + 1; + sourcebeg = (char *) (((int) sourcebeg + 3) & (-4)); + sourceptr = sourcebeg; + sourcesize = next + * (int *) next - sourceptr; + sourceleft = sourcesize; + return sourcedesc; + } + } + return 0; +} + +close (desc) + int desc; +{ + sourceptr = 0; + sourcedesc++; + /* Don't let sourcedesc get big enough to be confused with stdin. */ + if (sourcedesc == 100) + sourcedesc = 5; +} + +FILE * +fopen (filename, modes) + char *filename; + char *modes; +{ + return (FILE *) open (filename, *modes == 'w'); +} + +FILE * +fdopen (desc) + int desc; +{ + return (FILE *) desc; +} + +fclose (desc) + int desc; +{ + close (desc); +} + +fstat (desc, statbuf) + struct stat *statbuf; +{ + extern int errno; + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + statbuf->st_size = sourcesize; +} + +myread (desc, destptr, size, filename) + int desc; + char *destptr; + int size; + char *filename; +{ + int len = min (sourceleft, size); + extern int errno; + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + bcopy (sourceptr, destptr, len); + sourceleft -= len; + return len; +} + +int +fread (bufp, numelts, eltsize, stream) +{ + register int elts = min (numelts, sourceleft / eltsize); + register int len = elts * eltsize; + extern int errno; + + if (stream != sourcedesc) + { + errno = EBADF; + return -1; + } + + bcopy (sourceptr, bufp, len); + sourceleft -= len; + return elts; +} + +int +fgetc (desc) + int desc; +{ + extern int errno; + + if (desc == (int) stdin) + return tty_input (); + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (sourceleft-- <= 0) + return EOF; + return *sourceptr++; +} + +lseek (desc, pos) + int desc; + int pos; +{ + extern int errno; + + if (desc != sourcedesc) + { + errno = EBADF; + return -1; + } + + if (pos < 0 || pos > sourcesize) + { + errno = EINVAL; + return -1; + } + + sourceptr = sourcebeg + pos; + sourceleft = sourcesize - pos; +} + +/* Output in kdb can go only to the terminal, so the stream + specified may be ignored. */ + +printf (a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fprintf (ign, a1, a2, a3, a4, a5, a6, a7, a8, a9) +{ + char buffer[1024]; + sprintf (buffer, a1, a2, a3, a4, a5, a6, a7, a8, a9); + display_string (buffer); +} + +fwrite (buf, numelts, size, stream) + register char *buf; + int numelts, size; +{ + register int i = numelts * size; + while (i-- > 0) + fputc (*buf++, stream); +} + +fputc (c, ign) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + display_string (buf); +} + +/* sprintf refers to this, but loading this from the + library would cause fflush to be loaded from it too. + In fact there should be no need to call this (I hope). */ + +_flsbuf () +{ + error ("_flsbuf was actually called."); +} + +fflush (ign) +{ +} + +/* Entries into core and inflow, needed only to make things link ok. */ + +exec_file_command () +{} + +core_file_command () +{} + +char * +get_exec_file () +{ + /* Makes one printout look reasonable; value does not matter otherwise. */ + return "run"; +} + +have_core_file_p () +{ + return 0; +} + +kill_command () +{ + inferior_pid = 0; +} + +terminal_inferior () +{} + +terminal_ours () +{} + +terminal_init_inferior () +{} + +write_inferior_register () +{} + +read_inferior_register () +{} + +read_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + bcopy (memaddr, myaddr, len); +} + +/* Always return 0 indicating success. */ + +write_memory (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + bcopy (myaddr, memaddr, len); + return 0; +} + +static REGISTER_TYPE saved_regs[NUM_REGS]; + +REGISTER_TYPE +read_register (regno) + int regno; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + return saved_regs[regno]; +} + +void +write_register (regno, value) + int regno; + REGISTER_TYPE value; +{ + if (regno < 0 || regno >= NUM_REGS) + error ("Register number %d out of range.", regno); + saved_regs[regno] = value; +} + +/* System calls needed in relation to running the "inferior". */ + +vfork () +{ + /* Just appear to "succeed". Say the inferior's pid is 1. */ + return 1; +} + +/* These are called by code that normally runs in the inferior + that has just been forked. That code never runs, when standalone, + and these definitions are so it will link without errors. */ + +ptrace () +{} + +setpgrp () +{} + +execle () +{} + +_exit () +{} + +/* Malloc calls these. */ + +malloc_warning (str) + char *str; +{ + printf ("\n%s.\n\n", str); +} + +char *next_free; +char *memory_limit; + +char * +sbrk (amount) + int amount; +{ + if (next_free + amount > memory_limit) + return (char *) -1; + next_free += amount; + return next_free - amount; +} + +/* Various ways malloc might ask where end of memory is. */ + +char * +ulimit () +{ + return memory_limit; +} + +int +vlimit () +{ + return memory_limit - next_free; +} + +getrlimit (addr) + struct rlimit *addr; +{ + addr->rlim_cur = memory_limit - next_free; +} + +/* Context switching to and from program being debugged. */ + +/* GDB calls here to run the user program. + The frame pointer for this function is saved in + gdb_stack by save_frame_pointer; then we restore + all of the user program's registers, including PC and PS. */ + +static int fault_code; +static REGISTER_TYPE gdb_stack; + +resume () +{ + REGISTER_TYPE restore[NUM_REGS]; + + PUSH_FRAME_PTR; + save_frame_pointer (); + + bcopy (saved_regs, restore, sizeof restore); + POP_REGISTERS; + /* Control does not drop through here! */ +} + +save_frame_pointer (val) + CORE_ADDR val; +{ + gdb_stack = val; +} + +/* Fault handlers call here, running in the user program stack. + They must first push a fault code, + old PC, old PS, and any other info about the fault. + The exact format is machine-dependent and is known only + in the definition of PUSH_REGISTERS. */ + +fault () +{ + /* Transfer all registers and fault code to the stack + in canonical order: registers in order of GDB register number, + followed by fault code. */ + PUSH_REGISTERS; + + /* Transfer them to saved_regs and fault_code. */ + save_registers (); + + restore_gdb (); + /* Control does not reach here */ +} + +restore_gdb () +{ + CORE_ADDR new_fp = gdb_stack; + /* Switch to GDB's stack */ + POP_FRAME_PTR; + /* Return from the function `resume'. */ +} + +/* Assuming register contents and fault code have been pushed on the stack as + arguments to this function, copy them into the standard place + for the program's registers while GDB is running. */ + +save_registers (firstreg) + int firstreg; +{ + bcopy (&firstreg, saved_regs, sizeof saved_regs); + fault_code = (&firstreg)[NUM_REGS]; +} + +/* Store into the structure such as `wait' would return + the information on why the program faulted, + converted into a machine-independent signal number. */ + +static int fault_table[] = FAULT_TABLE; + +int +wait (w) + WAITTYPE *w; +{ + WSETSTOP (*w, fault_table[fault_code / FAULT_CODE_UNITS]); + return inferior_pid; +} + +/* Allocate a big space in which files for kdb to read will be stored. + Whatever is left is where malloc can allocate storage. + + Initialize it, so that there will be space in the executable file + for it. Then the files can be put into kdb by writing them into + kdb's executable file. */ + +/* The default size is as much space as we expect to be available + for kdb to use! */ + +#ifndef HEAP_SIZE +#define HEAP_SIZE 400000 +#endif + +char heap[HEAP_SIZE] = {0}; + +#ifndef STACK_SIZE +#define STACK_SIZE 100000 +#endif + +int kdb_stack_beg[STACK_SIZE / sizeof (int)]; +int kdb_stack_end; + +static +initialize () +{ + register char *next; + + /* Find start of data on files. */ + + files_start = heap; + + /* Find the end of the data on files. */ + + for (next - files_start; * (int *) next; + next += * (int *) next) + {} + + /* That is where free storage starts for sbrk to give out. */ + next_free = next; + + memory_limit = heap + sizeof heap; +} + +END_FILE diff --git a/gdb/stuff.c b/gdb/stuff.c new file mode 100644 index 00000000000..0f0a5032526 --- /dev/null +++ b/gdb/stuff.c @@ -0,0 +1,168 @@ +/* Program to stuff files into a specially prepared space in kdb. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Written 13-Mar-86 by David Bridgham. */ + +#include +#include +#include +#include +#include + +extern char *sys_errlist[]; +extern int errno; + +main (argc, argv) + int argc; + char *argv[]; +{ + register char *cp; + char *outfile; + register int i; + int offset; + int out_fd, in_fd; + struct stat stat_buf; + int size, pad; + char buf[1024]; + static char zeros[4] = {0}; + + if (argc < 4) + err("Not enough arguments\nUsage: %s -o kdb file1 file2 ...\n", + argv[0]); + + outfile = 0; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-o") == 0) + outfile = argv[++i]; + } + if (outfile == 0) + err("Output file not specified\n"); + + offset = get_offset (outfile, "_heap"); + + out_fd = open (outfile, O_WRONLY); + if (out_fd < 0) + err ("Error opening %s for write: %s\n", outfile, sys_errlist[errno]); + if (lseek (out_fd, offset, 0) < 0) + err ("Error seeking to heap in %s: %s\n", outfile, sys_errlist[errno]); + + /* For each file listed on the command line, write it into the + * 'heap' of the output file. Make sure to skip the arguments + * that name the output file. */ + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-o") == 0) + continue; + if ((in_fd = open (argv[i], O_RDONLY)) < 0) + err ("Error opening %s for read: %s\n", argv[i], sys_errlist[errno]); + if (fstat (in_fd, &stat_buf) < 0) + err ("Error stat'ing %s: %s\n", argv[i], sys_errlist[errno]); + size = strlen (argv[i]); + pad = 4 - (size & 3); + size += pad + stat_buf.st_size + sizeof (int); + write (out_fd, &size, sizeof (int)); + write (out_fd, argv[i], strlen (argv[i])); + write (out_fd, zeros, pad); + while ((size = read (in_fd, buf, sizeof (buf))) > 0) + write (out_fd, buf, size); + close (in_fd); + } + size = 0; + write (out_fd, &size, sizeof (int)); + close (out_fd); + return (0); +} + +/* Read symbol table from file and returns the offset into the file + * where symbol sym_name is located. If error, print message and + * exit. */ +get_offset (file, sym_name) + char *file; + char *sym_name; +{ + int f; + struct exec file_hdr; + struct nlist *symbol_table; + int size; + char *strings; + + f = open (file, O_RDONLY); + if (f < 0) + err ("Error opening %s: %s\n", file, sys_errlist[errno]); + if (read (f, &file_hdr, sizeof (file_hdr)) < 0) + err ("Error reading exec structure: %s\n", sys_errlist[errno]); + if (N_BADMAG (file_hdr)) + err ("File %s not an a.out file\n", file); + + /* read in symbol table */ + if ((symbol_table = (struct nlist *)malloc (file_hdr.a_syms)) == 0) + err ("Couldn't allocate space for symbol table\n"); + if (lseek (f, N_SYMOFF (file_hdr), 0) == -1) + err ("lseek error: %s\n", sys_errlist[errno]); + if (read (f, symbol_table, file_hdr.a_syms) == -1) + err ("Error reading symbol table from %s: %s\n", file, sys_errlist[errno]); + + /* read in string table */ + if (read (f, &size, 4) == -1) + err ("reading string table size: %s\n", sys_errlist[errno]); + if ((strings = (char *)malloc (size)) == 0) + err ("Couldn't allocate memory for string table\n"); + if (read (f, strings, size - 4) == -1) + err ("reading string table: %s\n", sys_errlist[errno]); + + /* Find the core address at which the first byte of kdb text segment + should be loaded into core when kdb is run. */ + origin = find_symbol ("_etext", symbol_table, file_hdr.a_syms, strings) + - file_hdr.a_text; + /* Find the core address at which the heap will appear. */ + coreaddr = find_symbol (sym_name, symbol_table, file_hdr.a_syms, strings); + /* Return address in file of the heap data space. */ + return (N_TXTOFF (file_hdr) + core_addr - origin); +} + +find_symbol (sym_name, symbol_table, length, strings) + char *sym_name; + struct nlist *symbol_table; + int length; + char *strings; +{ + register struct nlist *sym; + + /* Find symbol in question */ + for (sym = symbol_table; + sym != (struct nlist *)((char *)symbol_table + length); + sym++) + { + if ((sym->n_type & N_TYPE) != N_DATA) continue; + if (sym->n_un.n_strx == 0) continue; + if (strcmp (sym_name, strings + sym->n_un.n_strx - 4) == 0) + return sym->n_value; + } + err ("Data symbol %s not found in %s\n", sym_name, file); +} + +err (msg, a1, a2, a3) + char *msg; + int a1, a2, a3; +{ + fprintf (stderr, msg, a1, a2, a3); + exit (-1); +} diff --git a/gdb/symmisc.c b/gdb/symmisc.c new file mode 100644 index 00000000000..d17cbddadeb --- /dev/null +++ b/gdb/symmisc.c @@ -0,0 +1,535 @@ +/* Do various things to symbol tables (other than lookup)), for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" + +#include +#include + +static void free_symtab (); + +START_FILE + +/* Free all the symtabs that are currently installed, + and all storage associated with them. + Leaves us in a consistent state with no symtabs installed. */ + +void +free_all_symtabs () +{ + register struct symtab *s, *snext; + + /* All values will be invalid because their types will be! */ + + clear_value_history (); + clear_displays (); + clear_internalvars (); + clear_breakpoints (); + set_default_breakpoint (0, 0, 0, 0); + + current_source_symtab = 0; + + for (s = symtab_list; s; s = snext) + { + snext = s->next; + free_symtab (s); + } + symtab_list = 0; + obstack_free (symbol_obstack, 0); + obstack_init (symbol_obstack); + + if (misc_function_vector) + free (misc_function_vector); + misc_function_count = 0; + misc_function_vector = 0; +} + +/* Free a struct block <- B and all the symbols defined in that block. */ + +static void +free_symtab_block (b) + struct block *b; +{ + register int i, n; + n = BLOCK_NSYMS (b); + for (i = 0; i < n; i++) + { + free (SYMBOL_NAME (BLOCK_SYM (b, i))); + free (BLOCK_SYM (b, i)); + } + free (b); +} + +/* Free all the storage associated with the struct symtab <- S. + Note that some symtabs have contents malloc'ed structure by structure, + while some have contents that all live inside one big block of memory, + and some share the contents of another symbol table and so you should + not free the contents on their behalf (except sometimes the linetable, + which maybe per symtab even when the rest is not). + It is s->free_code that says which alternative to use. */ + +static void +free_symtab (s) + register struct symtab *s; +{ + register int i, n; + register struct blockvector *bv; + register struct type *type; + register struct typevector *tv; + + switch (s->free_code) + { + case free_nothing: + /* All the contents are part of a big block of memory + and some other symtab is in charge of freeing that block. + Therefore, do nothing. */ + break; + + case free_explicit: + /* All the contents are part of a big block of memory + and that is our `free_ptr' and will be freed below. */ + break; + + case free_contents: + /* Here all the contents were malloc'ed structure by structure + and must be freed that way. */ + /* First free the blocks (and their symbols. */ + bv = BLOCKVECTOR (s); + n = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < n; i++) + free_symtab_block (BLOCKVECTOR_BLOCK (bv, i)); + /* Free the blockvector itself. */ + free (bv); + /* Free the type vector. */ + tv = TYPEVECTOR (s); + if (tv) /* FIXME, should this happen? It does... */ + free (tv); + /* Also free the linetable. */ + + case free_linetable: + /* Everything will be freed either by our `free_ptr' + or by some other symbatb, except for our linetable. + Free that now. */ + free (LINETABLE (s)); + break; + } + + /* If there is a single block of memory to free, free it. */ + if (s->free_ptr) + free (s->free_ptr); + + if (s->line_charpos) + free (s->line_charpos); + free (s->filename); + free (s); +} + +/* Convert a raw symbol-segment to a struct symtab, + and relocate its internal pointers so that it is valid. */ + +/* This is how to relocate one pointer, given a name for it. + Works independent of the type of object pointed to. */ +#define RELOCATE(slot) (slot ? (* (char **) &slot += relocation) : 0) + +/* This is the inverse of RELOCATE. We use it when storing + a core address into a slot that has yet to be relocated. */ +#define UNRELOCATE(slot) (slot ? (* (char **) &slot -= relocation) : 0) + +/* During the process of relocation, this holds the amount to relocate by + (the address of the file's symtab data, in core in the debugger). */ +static int relocation; + +#define CORE_RELOCATE(slot) \ + ((slot) += (((slot) < data_start) ? text_relocation \ + : ((slot) < bss_start) ? data_relocation : bss_relocation)) + +#define TEXT_RELOCATE(slot) ((slot) += text_relocation) + +/* Relocation amounts for addresses in the program's core image. */ +static int text_relocation, data_relocation, bss_relocation; + +/* Boundaries that divide program core addresses into text, data and bss; + used to determine which relocation amount to use. */ +static int data_start, bss_start; + +static void relocate_typevector (); +static void relocate_blockvector (); +static void relocate_type (); +static void relocate_block (); +static void relocate_symbol (); + +/* Relocate a file symbol table so that all the pointers + are valid C pointers. Pass the struct symtab for the file + and the amount to relocate by. */ + +static struct symtab * +relocate_symtab (root) + struct symbol_root *root; +{ + struct symtab *sp = (struct symtab *) xmalloc (sizeof (struct symtab)); + bzero (sp, sizeof (struct symtab)); + + relocation = (int) root; + text_relocation = root->textrel; + data_relocation = root->datarel; + bss_relocation = root->bssrel; + data_start = root->databeg; + bss_start = root->bssbeg; + + sp->filename = root->filename; + sp->ldsymoff = root->ldsymoff; + sp->language = root->language; + sp->compilation = root->compilation; + sp->version = root->version; + sp->blockvector = root->blockvector; + sp->typevector = root->typevector; + sp->free_code = free_explicit; + sp->free_ptr = (char *) root; + + RELOCATE (TYPEVECTOR (sp)); + RELOCATE (BLOCKVECTOR (sp)); + RELOCATE (sp->version); + RELOCATE (sp->compilation); + RELOCATE (sp->filename); + + relocate_typevector (TYPEVECTOR (sp)); + relocate_blockvector (BLOCKVECTOR (sp)); + + return sp; +} + +static void +relocate_typevector (tv) + struct typevector *tv; +{ + register int ntypes = TYPEVECTOR_NTYPES (tv); + register int i; + + for (i = 0; i < ntypes; i++) + RELOCATE (TYPEVECTOR_TYPE (tv, i)); + for (i = 0; i < ntypes; i++) + relocate_type (TYPEVECTOR_TYPE (tv, i)); +} + +static void +relocate_blockvector (blp) + register struct blockvector *blp; +{ + register int nblocks = BLOCKVECTOR_NBLOCKS (blp); + register int i; + for (i = 0; i < nblocks; i++) + RELOCATE (BLOCKVECTOR_BLOCK (blp, i)); + for (i = 0; i < nblocks; i++) + relocate_block (BLOCKVECTOR_BLOCK (blp, i)); +} + +static void +relocate_block (bp) + register struct block *bp; +{ + register int nsyms = BLOCK_NSYMS (bp); + register int i; + + TEXT_RELOCATE (BLOCK_START (bp)); + TEXT_RELOCATE (BLOCK_END (bp)); + + /* These two should not be recursively processed. + The superblock need not be because all blocks are + processed from relocate_blockvector. + The function need not be because it will be processed + under the block which is its scope. */ + RELOCATE (BLOCK_SUPERBLOCK (bp)); + RELOCATE (BLOCK_FUNCTION (bp)); + + for (i = 0; i < nsyms; i++) + RELOCATE (BLOCK_SYM (bp, i)); + + for (i = 0; i < nsyms; i++) + relocate_symbol (BLOCK_SYM (bp, i)); +} + +static void +relocate_symbol (sp) + register struct symbol *sp; +{ + RELOCATE (SYMBOL_NAME (sp)); + if (SYMBOL_CLASS (sp) == LOC_BLOCK) + { + RELOCATE (SYMBOL_BLOCK_VALUE (sp)); + /* We can assume the block that belongs to this symbol + is not relocated yet, since it comes after + the block that contains this symbol. */ + BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp)) = sp; + UNRELOCATE (BLOCK_FUNCTION (SYMBOL_BLOCK_VALUE (sp))); + } + else if (SYMBOL_CLASS (sp) == LOC_STATIC) + CORE_RELOCATE (SYMBOL_VALUE (sp)); + else if (SYMBOL_CLASS (sp) == LOC_LABEL) + TEXT_RELOCATE (SYMBOL_VALUE (sp)); + RELOCATE (SYMBOL_TYPE (sp)); +} + +/* We cannot come up with an a priori spanning tree + for the network of types, since types can be used + for many symbols and also as components of other types. + Therefore, we need to be able to mark types that we + already have relocated (or are already in the middle of relocating) + as in a garbage collector. */ + +static void +relocate_type (tp) + register struct type *tp; +{ + register int nfields = TYPE_NFIELDS (tp); + register int i; + + RELOCATE (TYPE_NAME (tp)); + RELOCATE (TYPE_TARGET_TYPE (tp)); + RELOCATE (TYPE_FIELDS (tp)); + RELOCATE (TYPE_POINTER_TYPE (tp)); + + for (i = 0; i < nfields; i++) + { + RELOCATE (TYPE_FIELD_TYPE (tp, i)); + RELOCATE (TYPE_FIELD_NAME (tp, i)); + } +} + +/* Read symsegs from file named NAME open on DESC, + make symtabs from them, and return a chain of them. + Assumes DESC is prepositioned at the end of the string table, + just before the symsegs if there are any. */ + +struct symtab * +read_symsegs (desc, name) + int desc; + char *name; +{ + struct symbol_root root; + register char *data; + register struct symtab *sp, *chain = 0; + register int len; + + while (1) + { + len = myread (desc, &root, sizeof root); + if (len == 0 || root.format == 0) + break; + if (root.format != 1 || + root.length < sizeof root) + error ("Invalid symbol segment format code"); + data = (char *) xmalloc (root.length); + bcopy (&root, data, sizeof root); + len = myread (desc, data + sizeof root, + root.length - sizeof root); + sp = relocate_symtab (data); + sp->next = chain; + chain = sp; + } + + return chain; +} + +static int block_depth (); +static void print_spaces (); +static void print_symbol (); + +print_symtabs (filename) + char *filename; +{ + FILE *outfile; + register struct symtab *s; + register int i, j; + int len, line, blen; + register struct linetable *l; + struct blockvector *bv; + register struct block *b; + int depth; + struct cleanup *cleanups; + extern int fclose(); + + if (filename == 0) + error_no_arg ("file to write symbol data in"); + outfile = fopen (filename, "w"); + + cleanups = make_cleanup (fclose, outfile); + immediate_quit++; + + for (s = symtab_list; s; s = s->next) + { + /* First print the line table. */ + fprintf (outfile, "Symtab for file %s\n\n", s->filename); + fprintf (outfile, "Line table:\n\n"); + l = LINETABLE (s); + len = l->nitems; + for (i = 0; i < len; i++) + { + if (l->item[i] < 0) + line = - l->item[i] - 1; + else + fprintf (outfile, " line %d at %x\n", ++line, l->item[i]); + } + /* Now print the block info. */ + fprintf (outfile, "\nBlockvector:\n\n"); + bv = BLOCKVECTOR (s); + len = BLOCKVECTOR_NBLOCKS (bv); + for (i = 0; i < len; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + depth = block_depth (b) * 2; + print_spaces (depth, outfile); + fprintf (outfile, "block #%03d (object 0x%x) ", i, b); + fprintf (outfile, "[0x%x..0x%x]", BLOCK_START (b), BLOCK_END (b)); + if (BLOCK_SUPERBLOCK (b)) + fprintf (outfile, " (under 0x%x)", BLOCK_SUPERBLOCK (b)); + if (BLOCK_FUNCTION (b)) + fprintf (outfile, " %s", SYMBOL_NAME (BLOCK_FUNCTION (b))); + fputc ('\n', outfile); + blen = BLOCK_NSYMS (b); + for (j = 0; j < blen; j++) + { + print_symbol (BLOCK_SYM (b, j), depth + 1, outfile); + } + } + + fprintf (outfile, "\n\n"); + } + + immediate_quit--; + do_cleanups (cleanups); +} + +static void +print_symbol (symbol, depth, outfile) + struct symbol *symbol; + int depth; + FILE *outfile; +{ + print_spaces (depth, outfile); + if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE) + { + fprintf (outfile, "label %s at 0x%x", SYMBOL_NAME (symbol), + SYMBOL_VALUE (symbol)); + return; + } + if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE) + { + if (TYPE_NAME (SYMBOL_TYPE (symbol))) + { + type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + else + { + fprintf (outfile, "%s %s = ", + (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM + ? "enum" + : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT + ? "struct" : "union")), + SYMBOL_NAME (symbol)); + type_print_1 (SYMBOL_TYPE (symbol), "", outfile, 1, depth); + } + fprintf (outfile, ";\n"); + } + else + { + if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF) + fprintf (outfile, "typedef "); + if (SYMBOL_TYPE (symbol)) + { + type_print_1 (SYMBOL_TYPE (symbol), SYMBOL_NAME (symbol), + outfile, 1, depth); + fprintf (outfile, "; "); + } + else + fprintf (outfile, "%s ", SYMBOL_NAME (symbol)); + + switch (SYMBOL_CLASS (symbol)) + { + case LOC_CONST: + fprintf (outfile, "const %d (0x%x),", + SYMBOL_VALUE (symbol), SYMBOL_VALUE (symbol)); + break; + + case LOC_CONST_BYTES: + fprintf (outfile, "const %d hex bytes:", + TYPE_LENGTH (SYMBOL_TYPE (symbol))); + { + int i; + for (i = 0; i < TYPE_LENGTH (SYMBOL_TYPE (symbol)); i++) + fprintf (outfile, " %2x", SYMBOL_VALUE_BYTES (symbol) [i]); + fprintf (outfile, ","); + } + break; + + case LOC_STATIC: + fprintf (outfile, "static at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_REGISTER: + fprintf (outfile, "register %d,", SYMBOL_VALUE (symbol)); + break; + + case LOC_ARG: + fprintf (outfile, "arg at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_LOCAL: + fprintf (outfile, "local at 0x%x,", SYMBOL_VALUE (symbol)); + break; + + case LOC_TYPEDEF: + break; + + case LOC_LABEL: + fprintf (outfile, "label at 0x%x", SYMBOL_VALUE (symbol)); + break; + + case LOC_BLOCK: + fprintf (outfile, "block (object 0x%x) starting at 0x%x,", + SYMBOL_VALUE (symbol), + BLOCK_START (SYMBOL_BLOCK_VALUE (symbol))); + break; + } + } + fprintf (outfile, "\n"); +} + +/* Return the nexting depth of a block within other blocks in its symtab. */ + +static int +block_depth (block) + struct block *block; +{ + register int i = 0; + while (block = BLOCK_SUPERBLOCK (block)) i++; + return i; +} + +static +initialize () +{ + add_com ("printsyms", class_obscure, print_symtabs, + "Print dump of current symbol definitions to file OUTFILE."); +} + +END_FILE diff --git a/gdb/symseg.h b/gdb/symseg.h new file mode 100644 index 00000000000..11f4807ed5e --- /dev/null +++ b/gdb/symseg.h @@ -0,0 +1,323 @@ +/* GDB symbol table format definitions. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Format of GDB symbol table data. + There is one symbol segment for each source file or + independant compilation. These segments are simply concatenated + to form the GDB symbol table. A zero word where the beginning + of a segment is expected indicates there are no more segments. + +Format of a symbol segment: + + The symbol segment begins with a word containing 1 + if it is in the format described here. Other formats may + be designed, with other code numbers. + + The segment contains many objects which point at each other. + The pointers are offsets in bytes from the beginning of the segment. + Thus, each segment can be loaded into core and its pointers relocated + to make valid in-core pointers. + + All the data objects in the segment can be found indirectly from + one of them, the root object, of type `struct symbol_root'. + It appears at the beginning of the segment. + + The total size of the segment, in bytes, appears as the `length' + field of this object. This size includes the size of the + root object. + + All the object data types are defined here to contain pointer types + appropriate for in-core use on a relocated symbol segment. + Casts to and from type int are required for working with + unrelocated symbol segments such as are found in the file. + + The ldsymaddr word is filled in by the loader to contain + the offset (in bytes) within the ld symbol table + of the first nonglobal symbol from this compilation. + This makes it possible to match those symbols + (which contain line number information) reliably with + the segment they go with. + + Core addresses within the program that appear in the symbol segment + are not relocated by the loader. They are inserted by the assembler + and apply to addresses as output by the assembler, so GDB must + relocate them when it loads the symbol segment. It gets the information + on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg + words of the root object. + + The words textrel, datarel and bssrel + are filled in by ld with the amounts to relocate within-the-file + text, data and bss addresses by; databeg and bssbeg can be + used to tell which kind of relocation an address needs. */ + +enum language {language_c}; + +struct symbol_root +{ + int format; /* Data format version */ + int length; /* # bytes in this symbol segment */ + int ldsymoff; /* Offset in ld symtab of this file's syms */ + int textrel; /* Relocation for text addresses */ + int datarel; /* Relocation for data addresses */ + int bssrel; /* Relocation for bss addresses */ + char *filename; /* Name of source file compiled */ + char *filedir; /* Name of directory it was reached from */ + struct blockvector *blockvector; /* Vector of all symbol naming blocks */ + struct typevector *typevector; /* Vector of all data types */ + enum language language; /* Code identifying the language used */ + char *version; /* Version info. Not fully specified */ + char *compilation; /* Compilation info. Not fully specified */ + int databeg; /* Address within the file of data start */ + int bssbeg; /* Address within the file of bss start */ +}; + +/* All data types of symbols in the compiled program + are represented by `struct type' objects. + All of these objects are pointed to by the typevector. + The type vector may have empty slots that contain zero. */ + +struct typevector +{ + int length; + struct type *type[1]; +}; + +/* Different kinds of data types are distinguished by the `code' field. */ + +enum type_code +{ + TYPE_CODE_UNDEF, /* Not used; catches errors */ + TYPE_CODE_PTR, /* Pointer type */ + TYPE_CODE_ARRAY, /* Array type, lower bound zero */ + TYPE_CODE_STRUCT, /* C struct or Pascal record */ + TYPE_CODE_UNION, /* C union or Pascal variant part */ + TYPE_CODE_ENUM, /* Enumeration type */ + TYPE_CODE_FUNC, /* Function type */ + TYPE_CODE_INT, /* Integer type */ + TYPE_CODE_FLT, /* Floating type */ + TYPE_CODE_VOID, /* Void type (values zero length) */ + TYPE_CODE_SET, /* Pascal sets */ + TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */ + TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */ +}; + +/* This appears in a type's flags word for an unsigned integer type. */ +#define TYPE_FLAG_UNSIGNED 1 + +/* Other flag bits are used with GDB. */ + +struct type +{ + /* Code for kind of type */ + enum type_code code; + /* Name of this type, or zero if none. + This is used for printing only. + Type names specified as input are defined by symbols. */ + char *name; + /* Length in bytes of storage for a value of this type */ + int length; + /* For a pointer type, describes the type of object pointed to. + For an array type, describes the type of the elements. + For a function type, describes the type of the value. + Unused otherwise. */ + struct type *target_type; + /* Type that is a pointer to this type. + Zero if no such pointer-to type is known yet. + The debugger may add the address of such a type + if it has to construct one later. */ + struct type *pointer_type; + /* Type that is a function returning this type. + Zero if no such function type is known here. + The debugger may add the address of such a type + if it has to construct one later. */ + struct type *function_type; + /* Flags about this type. */ + short flags; + /* Number of fields described for this type */ + short nfields; + /* For structure and union types, a description of each field. + For set and pascal array types, there is one "field", + whose type is the domain type of the set or array. + For range types, there are two "fields", + the minimum and maximum values (both inclusive). + For enum types, each possible value is described by one "field". + For range types, there are two "fields", that record constant values + (inclusive) for the minimum and maximum. + + Using a pointer to a separate array of fields + allows all types to have the same size, which is useful + because we can allocate the space for a type before + we know what to put in it. */ + struct field + { + /* Position of this field, counting in bits from start of + containing structure. For a function type, this is the + position in the argument list of this argument. + For a range bound or enum value, this is the value itself. */ + int bitpos; + /* Size of this field, in bits, or zero if not packed. + For an unpacked field, the field's type's length + says how many bytes the field occupies. */ + int bitsize; + /* In a struct or enum type, type of this field. + In a function type, type of this argument. + In an array type, the domain-type of the array. */ + struct type *type; + /* Name of field, value or argument. + Zero for range bounds and array domains. */ + char *name; + } *fields; +}; + +/* All of the name-scope contours of the program + are represented by `struct block' objects. + All of these objects are pointed to by the blockvector. + + Each block represents one name scope. + Each lexical context has its own block. + + The first two blocks in the blockvector are special. + The first one contains all the symbols defined in this compilation + whose scope is the entire program linked together. + The second one contains all the symbols whose scope is the + entire compilation excluding other separate compilations. + In C, these correspond to global symbols and static symbols. + + Each block records a range of core addresses for the code that + is in the scope of the block. The first two special blocks + give, for the range of code, the entire range of code produced + by the compilation that the symbol segment belongs to. + + The blocks appear in the blockvector + in order of increasing starting-address, + and, within that, in order of decreasing ending-address. + + This implies that within the body of one function + the blocks appear in the order of a depth-first tree walk. */ + +struct blockvector +{ + /* Number of blocks in the list. */ + int nblocks; + /* The blocks themselves. */ + struct block *block[1]; +}; + +struct block +{ + /* Addresses in the executable code that are in this block. + Note: in an unrelocated symbol segment in a file, + these are always zero. They can be filled in from the + N_LBRAC and N_RBRAC symbols in the loader symbol table. */ + int startaddr, endaddr; + /* The symbol that names this block, + if the block is the body of a function; + otherwise, zero. + Note: In an unrelocated symbol segment in an object file, + this field may be zero even when the block has a name. + That is because the block is output before the name + (since the name resides in a higher block). + Since the symbol does point to the block (as its value), + it is possible to find the block and set its name properly. */ + struct symbol *function; + /* The `struct block' for the containing block, or 0 if none. */ + /* Note that in an unrelocated symbol segment in an object file + this pointer may be zero when the correct value should be + the second special block (for symbols whose scope is one compilation). + This is because the compiler ouptuts the special blocks at the + very end, after the other blocks. */ + struct block *superblock; + /* Number of local symbols. */ + int nsyms; + /* The symbols. */ + struct symbol *sym[1]; +}; + +/* Represent one symbol name; a variable, constant, function or typedef. */ + +/* Different name spaces for symbols. Looking up a symbol specifies + a namespace and ignores symbol definitions in other name spaces. + + VAR_NAMESPACE is the usual namespace. + In C, this contains variables, function names, typedef names + and enum type values. + + STRUCT_NAMESPACE is used in C to hold struct, union and enum type names. + Thus, if `struct foo' is used in a C program, + it produces a symbol named `foo' in the STRUCT_NAMESPACE. + + LABEL_NAMESPACE may be used for names of labels (for gotos); + currently it is not used and labels are not recorded at all. */ + +/* For a non-global symbol allocated statically, + the correct core address cannot be determined by the compiler. + The compiler puts an index number into the symbol's value field. + This index number can be matched with the "desc" field of + an entry in the loader symbol table. */ + +enum namespace +{ + UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE, +}; + +/* An address-class says where to find the value of the symbol in core. */ + +enum address_class +{ + LOC_UNDEF, /* Not used; catches errors */ + LOC_CONST, /* Value is constant int */ + LOC_STATIC, /* Value is at fixed address */ + LOC_REGISTER, /* Value is in register */ + LOC_ARG, /* Value is at spec'd position in arglist */ + LOC_LOCAL, /* Value is at spec'd pos in stack frame */ + LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE + Symbols in the namespace STRUCT_NAMESPACE + all have this class. */ + LOC_LABEL, /* Value is address in the code */ + LOC_BLOCK, /* Value is address of a `struct block'. + Function names have this class. */ + LOC_EXTERNAL, /* Value is at address not in this compilation. + This is used for .comm symbols + and for extern symbols within functions. + Inside GDB, this is changed to LOC_STATIC once the + real address is obtained from a loader symbol. */ + LOC_CONST_BYTES /* Value is a constant byte-sequence. */ +}; + +struct symbol +{ + /* Symbol name */ + char *name; + /* Name space code. */ + enum namespace namespace; + /* Address class */ + enum address_class class; + /* Data type of value */ + struct type *type; + /* constant value, or address if static, or register number, + or offset in arguments, or offset in stack frame. */ + union + { + long value; + struct block *block; /* for LOC_BLOCK */ + char *bytes; /* for LOC_CONST_BYTES */ + } + value; +}; diff --git a/gdb/symtab.c b/gdb/symtab.c new file mode 100644 index 00000000000..a413bfa6ddf --- /dev/null +++ b/gdb/symtab.c @@ -0,0 +1,1099 @@ +/* Symbol table lookup for the GNU debugger, GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "param.h" + +#include +#include + +#ifdef mac_aux +#define REGCMP +#endif + +START_FILE + +/* Allocate an obstack to hold objects that should be freed + when we load a new symbol table. + This includes the symbols made by dbxread + and the types that are not permanent. */ + +struct obstack obstack1; + +struct obstack *symbol_obstack = &obstack1; + +/* These variables point to the objects + representing the predefined C data types. */ + +struct type *builtin_type_void; +struct type *builtin_type_char; +struct type *builtin_type_short; +struct type *builtin_type_int; +struct type *builtin_type_long; +struct type *builtin_type_unsigned_char; +struct type *builtin_type_unsigned_short; +struct type *builtin_type_unsigned_int; +struct type *builtin_type_unsigned_long; +struct type *builtin_type_float; +struct type *builtin_type_double; + +/* Lookup the symbol table of a source file named NAME. */ + +struct symtab * +lookup_symtab (name) + char *name; +{ + register struct symtab *s; + register char *copy; + + for (s = symtab_list; s; s = s->next) + if (!strcmp (name, s->filename)) + return s; + + /* If name not found as specified, see if adding ".c" helps. */ + + copy = (char *) alloca (strlen (name) + 3); + strcpy (copy, name); + strcat (copy, ".c"); + for (s = symtab_list; s; s = s->next) + if (!strcmp (copy, s->filename)) + return s; + + return 0; +} + +/* Lookup a typedef or primitive type named NAME, + visible in lexical block BLOCK. + If NOERR is nonzero, return zero if NAME is not suitably defined. */ + +struct type * +lookup_typename (name, block, noerr) + char *name; + struct block *block; + int noerr; +{ + register struct symbol *sym = lookup_symbol (name, block, VAR_NAMESPACE); + if (sym == 0 || SYMBOL_CLASS (sym) != LOC_TYPEDEF) + { + if (!strcmp (name, "int")) + return builtin_type_int; + if (!strcmp (name, "long")) + return builtin_type_long; + if (!strcmp (name, "short")) + return builtin_type_short; + if (!strcmp (name, "char")) + return builtin_type_char; + if (!strcmp (name, "float")) + return builtin_type_float; + if (!strcmp (name, "double")) + return builtin_type_double; + if (!strcmp (name, "void")) + return builtin_type_void; + + if (noerr) + return 0; + error ("No type named %s.", name); + } + return SYMBOL_TYPE (sym); +} + +struct type * +lookup_unsigned_typename (name) + char *name; +{ + if (!strcmp (name, "int")) + return builtin_type_unsigned_int; + if (!strcmp (name, "long")) + return builtin_type_unsigned_long; + if (!strcmp (name, "short")) + return builtin_type_unsigned_short; + if (!strcmp (name, "char")) + return builtin_type_unsigned_char; + error ("No type named unsigned %s.", name); +} + +/* Lookup a structure type named "struct NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_struct (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No struct type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_STRUCT) + error ("This context has union or enum %s, not a struct.", name); + return SYMBOL_TYPE (sym); +} + +/* Lookup a union type named "union NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_union (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No union type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_UNION) + error ("This context has struct or enum %s, not a union.", name); + return SYMBOL_TYPE (sym); +} + +/* Lookup an enum type named "enum NAME", + visible in lexical block BLOCK. */ + +struct type * +lookup_enum (name, block) + char *name; + struct block *block; +{ + register struct symbol *sym = lookup_symbol (name, block, STRUCT_NAMESPACE); + if (sym == 0) + error ("No enum type named %s.", name); + if (TYPE_CODE (SYMBOL_TYPE (sym)) != TYPE_CODE_ENUM) + error ("This context has struct or union %s, not an enum.", name); + return SYMBOL_TYPE (sym); +} + +/* Given a type TYPE, return a type of pointers to that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_pointer_type (type) + struct type *type; +{ + register struct type *ptype = TYPE_POINTER_TYPE (type); + if (ptype) return ptype; + + /* This is the first time anyone wanted a pointer to a TYPE. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + ptype = (struct type *) xmalloc (sizeof (struct type)); + else + ptype = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + + bzero (ptype, sizeof (struct type)); + TYPE_TARGET_TYPE (ptype) = type; + TYPE_POINTER_TYPE (type) = ptype; + /* New type is permanent if type pointed to is permanent. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (ptype) = sizeof (char *); + TYPE_CODE (ptype) = TYPE_CODE_PTR; + return ptype; +} + +/* Given a type TYPE, return a type of functions that return that type. + May need to construct such a type if this is the first use. */ + +struct type * +lookup_function_type (type) + struct type *type; +{ + register struct type *ptype = TYPE_FUNCTION_TYPE (type); + if (ptype) return ptype; + + /* This is the first time anyone wanted a function returning a TYPE. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + ptype = (struct type *) xmalloc (sizeof (struct type)); + else + ptype = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + + bzero (ptype, sizeof (struct type)); + TYPE_TARGET_TYPE (ptype) = type; + TYPE_FUNCTION_TYPE (type) = ptype; + /* New type is permanent if type returned is permanent. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + TYPE_FLAGS (ptype) |= TYPE_FLAG_PERM; + TYPE_LENGTH (ptype) = 1; + TYPE_CODE (ptype) = TYPE_CODE_FUNC; + TYPE_NFIELDS (ptype) = 0; + return ptype; +} + +/* Smash TYPE to be a type of pointers to TO_TYPE. + If TO_TYPE is not permanent and has no pointer-type yet, + record TYPE as its pointer-type. */ + +void +smash_to_pointer_type (type, to_type) + struct type *type, *to_type; +{ + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + /* We assume the machine has only one representation for pointers! */ + TYPE_LENGTH (type) = sizeof (char *); + TYPE_CODE (type) = TYPE_CODE_PTR; + + if (TYPE_POINTER_TYPE (to_type) == 0 + && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM)) + { + TYPE_POINTER_TYPE (to_type) = type; + } +} + +/* Smash TYPE to be a type of functions returning TO_TYPE. + If TO_TYPE is not permanent and has no function-type yet, + record TYPE as its function-type. */ + +void +smash_to_function_type (type, to_type) + struct type *type, *to_type; +{ + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_FUNC; + TYPE_NFIELDS (type) = 0; + + if (TYPE_FUNCTION_TYPE (to_type) == 0 + && !(TYPE_FLAGS (type) & TYPE_FLAG_PERM)) + { + TYPE_FUNCTION_TYPE (to_type) = type; + } +} + +static struct symbol *lookup_block_symbol (); + +/* Find the definition for a specified symbol name NAME + in namespace NAMESPACE, visible from lexical block BLOCK. + Returns the struct symbol pointer, or zero if no symbol is found. */ + +struct symbol * +lookup_symbol (name, block, namespace) + char *name; + register struct block *block; + enum namespace namespace; +{ + register int i, n; + register struct symbol *sym; + register struct symtab *s; + struct blockvector *bv; + + /* Search specified block and its superiors. */ + + while (block != 0) + { + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + block = BLOCK_SUPERBLOCK (block); + } + + /* Now search all symtabs' global blocks. */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 0); + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + } + + /* Now search all symtabs' per-file blocks. + Not strictly correct, but more useful than an error. */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + block = BLOCKVECTOR_BLOCK (bv, 1); + sym = lookup_block_symbol (block, name, namespace); + if (sym) return sym; + } + return 0; +} + +/* Look for a symbol in block BLOCK using binary search. */ + +static struct symbol * +lookup_block_symbol (block, name, namespace) + register struct block *block; + char *name; + enum namespace namespace; +{ + register int bot, top, inc; + register struct symbol *sym; + + top = BLOCK_NSYMS (block); + bot = 0; + + /* First, advance BOT to not far before + the first symbol whose name is NAME. */ + + while (1) + { + inc = (top - bot + 1); + /* No need to keep binary searching for the last few bits worth. */ + if (inc < 7) + break; + inc >>= 1; + sym = BLOCK_SYM (block, bot + inc); + if (strcmp (SYMBOL_NAME (sym), name) < 0) + bot += inc; + else + top = bot + inc; + } + + /* Now scan forward until we run out of symbols, + find one whose name is greater than NAME, + or find one we want. + If there is more than one symbol with the right name and namespace, + we return the first one. dbxread.c is careful to make sure + that if one is a register then it comes first. */ + + top = BLOCK_NSYMS (block); + while (bot < top) + { + sym = BLOCK_SYM (block, bot); + inc = strcmp (SYMBOL_NAME (sym), name); + if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace) + return sym; + if (inc > 0) + return 0; + bot++; + } + return 0; +} + +/* Return the symbol for the function which contains a specified + lexical block, described by a struct block BL. */ + +struct symbol * +block_function (bl) + struct block *bl; +{ + while (BLOCK_FUNCTION (bl) == 0 && BLOCK_SUPERBLOCK (bl) != 0) + bl = BLOCK_SUPERBLOCK (bl); + + return BLOCK_FUNCTION (bl); +} + +/* Subroutine of find_pc_line */ + +static struct symtab * +find_pc_symtab (pc) + register CORE_ADDR pc; +{ + register struct block *b; + struct blockvector *bv; + register struct symtab *s; + + /* Search all symtabs for one whose file contains our pc */ + + for (s = symtab_list; s; s = s->next) + { + bv = BLOCKVECTOR (s); + b = BLOCKVECTOR_BLOCK (bv, 0); + if (BLOCK_START (b) <= pc + && BLOCK_END (b) > pc) + break; + } + + return s; +} + +/* Find the source file and line number for a given PC value. + Return a structure containing a symtab pointer, a line number, + and a pc range for the entire source line. + The value's .pc field is NOT the specified pc. + NOTCURRENT nonzero means, if specified pc is on a line boundary, + use the line that ends there. Otherwise, in that case, the line + that begins there is used. */ + +struct symtab_and_line +find_pc_line (pc, notcurrent) + CORE_ADDR pc; + int notcurrent; +{ + struct symtab *s; + register struct linetable *l; + register int len; + register int i, item; + int line; + struct symtab_and_line value; + struct blockvector *bv; + + /* Info on best line seen so far, and where it starts, and its file. */ + + int best_line = 0; + CORE_ADDR best_pc = 0; + CORE_ADDR best_end = 0; + struct symtab *best_symtab = 0; + + /* Store here the first line number + of a file which contains the line at the smallest pc after PC. + If we don't find a line whose range contains PC, + we will use a line one less than this, + with a range from the start of that file to the first line's pc. */ + int alt_line = 0; + CORE_ADDR alt_pc = 0; + struct symtab *alt_symtab = 0; + + /* Info on best line seen in this file. */ + + int prev_line; + CORE_ADDR prev_pc; + + /* Info on first line of this file. */ + + int first_line; + CORE_ADDR first_pc; + + /* If this pc is not from the current frame, + it is the address of the end of a call instruction. + Quite likely that is the start of the following statement. + But what we want is the statement containing the instruction. + Fudge the pc to make sure we get that. */ + + if (notcurrent) pc -= 1; + + s = find_pc_symtab (pc); + if (s == 0) + { + value.symtab = 0; + value.line = 0; + value.pc = pc; + return value; + } + + bv = BLOCKVECTOR (s); + + /* Look at all the symtabs that share this blockvector. + They all have the same apriori range, that we found was right; + but they have different line tables. */ + + for (; s && BLOCKVECTOR (s) == bv; s = s->next) + { + /* Find the best line in this symtab. */ + l = LINETABLE (s); + len = l->nitems; + prev_line = -1; + first_line = -1; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + line = - item - 1; + else + { + line++; + if (first_line < 0) + { + first_line = line; + first_pc = item; + } + /* Return the last line that did not start after PC. */ + if (pc >= item) + { + prev_line = line; + prev_pc = item; + } + else + break; + } + } + + /* Is this file's best line closer than the best in the other files? + If so, record this file, and its best line, as best so far. */ + if (prev_line >= 0 && prev_pc > best_pc) + { + best_pc = prev_pc; + best_line = prev_line; + best_symtab = s; + if (i < len) + best_end = item; + else + best_end = 0; + } + /* Is this file's first line closer than the first lines of other files? + If so, record this file, and its first line, as best alternate. */ + if (first_line >= 0 && first_pc > pc + && (alt_pc == 0 || first_pc < alt_pc)) + { + alt_pc = first_pc; + alt_line = first_line; + alt_symtab = s; + } + } + if (best_symtab == 0) + { + value.symtab = alt_symtab; + value.line = alt_line - 1; + value.pc = BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)); + value.end = alt_pc; + } + else + { + value.symtab = best_symtab; + value.line = best_line; + value.pc = best_pc; + value.end = (best_end ? best_end + : (alt_pc ? alt_pc + : BLOCK_END (BLOCKVECTOR_BLOCK (bv, 0)))); + } + return value; +} + +/* Find the range of pc values in a line. + Store the starting pc of the line into *STARTPTR + and the ending pc (start of next line) into *ENDPTR. + Returns 1 to indicate success. + Returns 0 if could not find the specified line. */ + +int +find_line_pc_range (symtab, thisline, startptr, endptr) + struct symtab *symtab; + int thisline; + CORE_ADDR *startptr, *endptr; +{ + register struct linetable *l; + register int i, line, item; + int len; + register CORE_ADDR prev_pc; + CORE_ADDR last_pc; + + if (symtab == 0) + return 0; + + l = LINETABLE (symtab); + len = l->nitems; + prev_pc = -1; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + line = - item - 1; + else + { + line++; + /* As soon as we find a line following the specified one + we know the end pc and can return. */ + if (line > thisline) + { + /* If we have not seen an entry for the specified line, + assume that means the specified line has zero bytes. */ + *startptr = prev_pc == -1 ? item : prev_pc; + *endptr = item; + return 1; + } + /* If we see an entry for the specified line, + it gives the beginning. */ + if (line == thisline) + prev_pc = item; + last_pc = item; + } + } + if (prev_pc != -1) + { + /* If we found the specified line but no later line, it's file's last. + Its range is from line's pc to file's end pc. */ + *startptr = last_pc; + *endptr = BLOCK_END (BLOCKVECTOR_BLOCK (BLOCKVECTOR (symtab), 0)); + return 1; + } + + return 0; +} + +/* Find the PC value for a given source file and line number. + Returns zero for invalid line number. + The source file is specified with a struct symtab. */ + +CORE_ADDR +find_line_pc (symtab, line) + struct symtab *symtab; + int line; +{ + register struct linetable *l; + register int len; + register int i; + register int item; + register int nextline = -1; + + if (line <= 0) + return 0; + + l = LINETABLE (symtab); + len = l->nitems; + for (i = 0; i < len; i++) + { + item = l->item[i]; + if (item < 0) + nextline = - item - 1; + else + { + nextline++; + if (line <= nextline) + return item; + } + } + return 0; +} + +int +find_pc_line_pc_range (pc, startptr, endptr) + CORE_ADDR pc; + CORE_ADDR *startptr, *endptr; +{ + struct symtab_and_line sal; + sal = find_pc_line (pc, 0); + *startptr = sal.pc; + *endptr = sal.end; + return sal.symtab != 0; +} + +/* Parse a string that specifies a line number. + Pass the address of a char * variable; that variable will be + advanced over the characters actually parsed. + + The string can be: + + LINENUM -- that line number in current file. PC returned is 0. + FILE:LINENUM -- that line in that file. PC returned is 0. + FUNCTION -- line number of openbrace of that function. + PC returned is the start of the function. + FILE:FUNCTION -- likewise, but prefer functions in that file. + *EXPR -- line in which address EXPR appears. + + FUNCTION may be an undebuggable function found in misc_function_vector. + + If the argument FUNFIRSTLINE is nonzero, we want the first line + of real code inside a function when a function is specified. + + DEFAULT_SYMTAB specifies the file to use if none is specified. + It defaults to current_source_symtab. + DEFAULT_LINE specifies the line number to use for relative + line numbers (that start with signs). Defaults to current_source_line. + + Note that it is possible to return zero for the symtab + if no file is validly specified. Callers must check that. + Also, the line number returned may be invalid. */ + +struct symtab_and_line +decode_line_1 (argptr, funfirstline, default_symtab, default_line) + char **argptr; + int funfirstline; + struct symtab *default_symtab; + int default_line; +{ + struct symtab_and_line value; + register char *p, *p1; + register struct symtab *s; + register struct symbol *sym; + register CORE_ADDR pc; + register int i; + char *copy; + + /* Defaults have defaults. */ + + if (default_symtab == 0) + { + default_symtab = current_source_symtab; + default_line = current_source_line; + } + + /* See if arg is *PC */ + + if (**argptr == '*') + { + (*argptr)++; + pc = parse_and_eval_address_1 (argptr); + value = find_pc_line (pc, 0); + value.pc = pc; + return value; + } + + /* Maybe arg is FILE : LINENUM or FILE : FUNCTION */ + + s = 0; + + for (p = *argptr; *p; p++) + { + if (p[0] == ':' || p[0] == ' ' || p[0] == '\t') + break; + } + while (p[0] == ' ' || p[0] == '\t') p++; + + if (p[0] == ':') + { + /* Extract the file name. */ + p1 = p; + while (p != *argptr && p[-1] == ' ') --p; + copy = (char *) alloca (p - *argptr + 1); + bcopy (*argptr, copy, p - *argptr); + copy[p - *argptr] = 0; + + /* Find that file's data. */ + s = lookup_symtab (copy); + if (s == 0) + { + if (symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + error ("No source file named %s.", copy); + } + + /* Discard the file name from the arg. */ + p = p1 + 1; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + } + + /* S is specified file's symtab, or 0 if no file specified. + arg no longer contains the file name. */ + + /* Check whether arg is all digits (and sign) */ + + p = *argptr; + if (*p == '-' || *p == '+') p++; + while (*p >= '0' && *p <= '9') + p++; + + if (p != *argptr && (*p == 0 || *p == ' ' || *p == '\t' || *p == ',')) + { + /* We found a token consisting of all digits -- at least one digit. */ + enum sign {none, plus, minus} sign = none; + + if (**argptr == '+') + sign = plus, (*argptr)++; + else if (**argptr == '-') + sign = minus, (*argptr)++; + value.line = atoi (*argptr); + switch (sign) + { + case plus: + if (p == *argptr) + value.line = 5; + if (s == 0) + value.line = default_line + value.line; + break; + case minus: + if (p == *argptr) + value.line = 15; + if (s == 0) + value.line = default_line - value.line; + else + value.line = 1; + break; + } + + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + if (s == 0) + s = default_symtab; + value.symtab = s; + value.pc = 0; + return value; + } + + /* Arg token is not digits => try it as a function name + Find the next token (everything up to end or next whitespace). */ + p = *argptr; + while (*p && *p != ' ' && *p != '\t' && *p != ',') p++; + copy = (char *) alloca (p - *argptr + 1); + bcopy (*argptr, copy, p - *argptr); + copy[p - *argptr] = 0; + while (*p == ' ' || *p == '\t') p++; + *argptr = p; + + /* Look up that token as a function. + If file specified, use that file's per-file block to start with. */ + + sym = lookup_symbol (copy, s ? BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), 1) : 0, + VAR_NAMESPACE); + + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + { + /* Arg is the name of a function */ + pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (pc); + value = find_pc_line (pc, 0); + value.pc = (value.end && value.pc != pc) ? value.end : pc; + return value; + } + + if (sym) + error ("%s is not a function.", copy); + + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, copy)) + { + value.symtab = 0; + value.line = 0; + value.pc = misc_function_vector[i].address + FUNCTION_START_OFFSET; + if (funfirstline) + SKIP_PROLOGUE (value.pc); + return value; + } + + if (symtab_list == 0) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + error ("Function %s not defined.", copy); +} + +struct symtab_and_line +decode_line_spec (string, funfirstline) + char *string; + int funfirstline; +{ + struct symtab_and_line sal; + if (string == 0) + error ("Empty line specification."); + sal = decode_line_1 (&string, funfirstline, + current_source_symtab, current_source_line); + if (*string) + error ("Junk at end of line specification: %s", string); + return sal; +} + +static void +sources_info () +{ + register struct symtab *s; + register int column = 0; + + if (symtab_list == 0) + { + printf ("No symbol table is loaded.\n"); + return; + } + printf ("Source files for which symbol table is known:\n"); + for (s = symtab_list; s; s = s->next) + { + if (column != 0 && column + strlen (s->filename) >= 70) + { + printf ("\n"); + column = 0; + } + else if (column != 0) + { + printf (" "); + column++; + } + printf ("%s", s->filename); + column += strlen (s->filename); + if (s->next) + { + printf (","); + column++; + } + } + printf ("\n"); +} + +/* List all symbols (if REGEXP is 0) or all symbols matching REGEXP. + If CLASS is zero, list all symbols except functions and type names. + If CLASS is 1, list only functions. + If CLASS is 2, list only type names. */ + +#define MORE \ +{ print_count++; \ + if (print_count >= 21) \ + { printf ("--Type Return to print more--"); \ + print_count = 0; \ + fflush (stdout); \ + read_line (); } } + +static void +list_symbols (regexp, class) + char *regexp; + int class; +{ + register struct symtab *s; + register struct blockvector *bv; + struct blockvector *prev_bv = 0; + register struct block *b; + register int i, j; + register struct symbol *sym; + char *val = 0; + int found_in_file; + static char *classnames[] + = {"variable", "function", "type"}; + int print_count = 0; +#ifdef REGCMP + extern char *regcmp(), *regex(), *loc1; +#endif + + if (regexp) { +#ifdef REGCMP + val = regcmp(regexp, (char *)0); + if (val == 0) + error ("Invalid regexp: %s", regexp); +#else + if (val = (char *) re_comp (regexp)) + error ("Invalid regexp: %s", val); +#endif + } + + printf (regexp + ? "All %ss matching regular expression \"%s\":\n" + : "All defined %ss:\n", + classnames[class], + regexp); + + for (s = symtab_list; s; s = s->next) + { + found_in_file = 0; + bv = BLOCKVECTOR (s); + /* Often many files share a blockvector. + Scan each blockvector only once so that + we don't get every symbol many times. + It happens that the first symtab in the list + for any given blockvector is the main file. */ + if (bv != prev_bv) + for (i = 0; i < 2; i++) + { + b = BLOCKVECTOR_BLOCK (bv, i); + for (j = 0; j < BLOCK_NSYMS (b); j++) + { + QUIT; + sym = BLOCK_SYM (b, j); + if (regexp) { +#ifdef REGCMP + if (!regex(val, SYMBOL_NAME (sym))) + continue; +#else + if (!re_exec (SYMBOL_NAME (sym))) + continue; +#endif + } + if ((class == 0 && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_BLOCK) + || (class == 1 && SYMBOL_CLASS (sym) == LOC_BLOCK) + || (class == 2 && SYMBOL_CLASS (sym) == LOC_TYPEDEF)) + { + if (!found_in_file) + { + printf ("\nFile %s:\n", s->filename); + print_count += 2; + } + found_in_file = 1; + MORE; + if (class != 2 && i == 1) + printf ("static "); + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE) + printf ("typedef "); + + type_print (SYMBOL_TYPE (sym), + (SYMBOL_CLASS (sym) == LOC_TYPEDEF + ? "" : SYMBOL_NAME (sym)), + stdout, 0); + if (class == 2 + && SYMBOL_NAMESPACE (sym) != STRUCT_NAMESPACE + && (TYPE_NAME ((SYMBOL_TYPE (sym))) == 0 + || 0 != strcmp (TYPE_NAME ((SYMBOL_TYPE (sym))), + SYMBOL_NAME (sym)))) + printf (" %s", SYMBOL_NAME (sym)); + printf (";\n"); + } + } + } + prev_bv = bv; + } +#ifdef REGCMP + if (val) + (void)free(val); +#endif +} + +static void +variables_info (regexp) + char *regexp; +{ + list_symbols (regexp, 0); +} + +static void +functions_info (regexp) + char *regexp; +{ + list_symbols (regexp, 1); +} + +static void +types_info (regexp) + char *regexp; +{ + list_symbols (regexp, 2); +} + +/* Initialize the standard C scalar types. */ + +static +struct type * +init_type (code, length, uns, name) + enum type_code code; + int length, uns; + char *name; +{ + register struct type *type; + + type = (struct type *) xmalloc (sizeof (struct type)); + bzero (type, sizeof *type); + TYPE_CODE (type) = code; + TYPE_LENGTH (type) = length; + TYPE_FLAGS (type) = uns ? TYPE_FLAG_UNSIGNED : 0; + TYPE_FLAGS (type) |= TYPE_FLAG_PERM; + TYPE_NFIELDS (type) = 0; + TYPE_NAME (type) = name; + + return type; +} + +static +initialize () +{ + add_info ("variables", variables_info, + "All global and static variable names, or those matching REGEXP."); + add_info ("functions", functions_info, + "All function names, or those matching REGEXP."); + add_info ("types", types_info, + "All types names, or those matching REGEXP."); + add_info ("sources", sources_info, + "Source files in the program."); + + obstack_init (symbol_obstack); + + builtin_type_void = init_type (TYPE_CODE_VOID, 0, 0, "void"); + + builtin_type_float = init_type (TYPE_CODE_FLT, sizeof (float), 0, "float"); + builtin_type_double = init_type (TYPE_CODE_FLT, sizeof (double), 0, "double"); + + builtin_type_char = init_type (TYPE_CODE_INT, sizeof (char), 0, "char"); + builtin_type_short = init_type (TYPE_CODE_INT, sizeof (short), 0, "short"); + builtin_type_long = init_type (TYPE_CODE_INT, sizeof (long), 0, "long"); + builtin_type_int = init_type (TYPE_CODE_INT, sizeof (int), 0, "int"); + + builtin_type_unsigned_char = init_type (TYPE_CODE_INT, sizeof (char), 1, "unsigned char"); + builtin_type_unsigned_short = init_type (TYPE_CODE_INT, sizeof (short), 1, "unsigned short"); + builtin_type_unsigned_long = init_type (TYPE_CODE_INT, sizeof (long), 1, "unsigned long"); + builtin_type_unsigned_int = init_type (TYPE_CODE_INT, sizeof (int), 1, "unsigned int"); +} + +END_FILE diff --git a/gdb/symtab.h b/gdb/symtab.h new file mode 100644 index 00000000000..4d9335513e2 --- /dev/null +++ b/gdb/symtab.h @@ -0,0 +1,228 @@ +/* Symbol table definitions for GDB. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* An obstack to hold objects that should be freed + when we load a new symbol table. + This includes the symbols made by dbxread + and the types that are not permanent. */ + +extern struct obstack *symbol_obstack; + +/* Some definitions and declarations to go with use of obstacks. */ +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +extern char *xmalloc (); +extern void free (); + +/* gdb can know one or several symbol tables at the same time; + the ultimate intent is to have one for each separately-compiled module. + Each such symbol table is recorded by a struct symtab, and they + are all chained together. */ + +/* In addition, gdb can record any number of miscellaneous undebuggable + functions' addresses. In a system that appends _ to function names, + the _'s are removed from the names stored in this table. */ + +struct misc_function +{ + char *name; + CORE_ADDR address; +}; + +/* Address and length of the vector recording all misc function names/addresses. */ + +struct misc_function *misc_function_vector; +int misc_function_count; + +#include "symseg.h" + +/* Each source file is represented by a struct symtab. + These objects are chained through the `next' field. */ + +struct symtab + { + /* Chain of all existing symtabs. */ + struct symtab *next; + /* List of all symbol scope blocks for this symtab. */ + struct blockvector *blockvector; + /* Table mapping core addresses to line numbers for this file. */ + struct linetable *linetable; + /* Vector containing all types defined for this symtab. */ + struct typevector *typevector; + /* Name of this source file. */ + char *filename; + /* This component says how to free the data we point to: + free_contents => do a tree walk and free each object. + free_explicit => free what free_ptr points at, and the linetable. + free_nothing => do nothing; some other symtab will free + the data this one uses. + free_linetable => free just the linetable. */ + enum free_code {free_nothing, free_contents, free_explicit, free_linetable} + free_code; + /* Pointer to one block storage to be freed, if nonzero. */ + char *free_ptr; + /* Total number of lines found in source file. */ + int nlines; + /* Array mapping line number to character position. */ + int *line_charpos; + /* Language of this source file. */ + enum language language; + /* String of version information. May be zero. */ + char *version; + /* String of compilation information. May be zero. */ + char *compilation; + /* Offset within loader symbol table + of first local symbol for this file. */ + int ldsymoff; + }; + +/* This is the list of struct symtab's that gdb considers current. */ + +struct symtab *symtab_list; + +/* This symtab variable specifies the current file for printing source lines */ + +struct symtab *current_source_symtab; + +/* This is the next line to print for listing source lines. */ + +int current_source_line; + +#define BLOCKLIST(symtab) (symtab)->blockvector +#define BLOCKVECTOR(symtab) (symtab)->blockvector + +#define TYPEVECTOR(symtab) (symtab)->typevector + +#define LINELIST(symtab) (symtab)->linetable +#define LINETABLE(symtab) (symtab)->linetable + +/* Recording the code addresses of source lines. */ + +struct linetable + { + int nitems; + int item[1]; + }; + +/* Each item is either minus a line number, or a program counter. + If it represents a line number, that is the line described by the next + program counter value. If it is positive, it is the program + counter at which the code for the next line starts. + + Consecutive lines can be recorded by program counter entries + with no line number entries between them. Line number entries + are used when there are lines to skip with no code on them. + This is to make the table shorter. */ + +/* Macros normally used to access components of symbol table structures. */ + +#define BLOCKLIST_NBLOCKS(blocklist) (blocklist)->nblocks +#define BLOCKLIST_BLOCK(blocklist,n) (blocklist)->block[n] +#define BLOCKVECTOR_NBLOCKS(blocklist) (blocklist)->nblocks +#define BLOCKVECTOR_BLOCK(blocklist,n) (blocklist)->block[n] + +#define TYPEVECTOR_NTYPES(typelist) (typelist)->length +#define TYPEVECTOR_TYPE(typelist,n) (typelist)->type[n] + +#define BLOCK_START(bl) (bl)->startaddr +#define BLOCK_END(bl) (bl)->endaddr +#define BLOCK_NSYMS(bl) (bl)->nsyms +#define BLOCK_SYM(bl, n) (bl)->sym[n] +#define BLOCK_FUNCTION(bl) (bl)->function +#define BLOCK_SUPERBLOCK(bl) (bl)->superblock + +#define SYMBOL_NAME(symbol) (symbol)->name +#define SYMBOL_NAMESPACE(symbol) (symbol)->namespace +#define SYMBOL_CLASS(symbol) (symbol)->class +#define SYMBOL_VALUE(symbol) (symbol)->value.value +#define SYMBOL_VALUE_BYTES(symbol) (symbol)->value.bytes +#define SYMBOL_BLOCK_VALUE(symbol) (symbol)->value.block +#define SYMBOL_TYPE(symbol) (symbol)->type + +/* This appears in a type's flags word + if it is a (pointer to a|function returning a)* built in scalar type. + These types are never freed. */ +#define TYPE_FLAG_PERM 4 + +#define TYPE_NAME(thistype) (thistype)->name +#define TYPE_TARGET_TYPE(thistype) (thistype)->target_type +#define TYPE_POINTER_TYPE(thistype) (thistype)->pointer_type +#define TYPE_FUNCTION_TYPE(thistype) (thistype)->function_type +#define TYPE_LENGTH(thistype) (thistype)->length +#define TYPE_FLAGS(thistype) (thistype)->flags +#define TYPE_UNSIGNED(thistype) ((thistype)->flags & TYPE_FLAG_UNSIGNED) +#define TYPE_CODE(thistype) (thistype)->code +#define TYPE_NFIELDS(thistype) (thistype)->nfields +#define TYPE_FIELDS(thistype) (thistype)->fields + +#define TYPE_FIELD(thistype, n) (thistype)->fields[n] +#define TYPE_FIELD_TYPE(thistype, n) (thistype)->fields[n].type +#define TYPE_FIELD_NAME(thistype, n) (thistype)->fields[n].name +#define TYPE_FIELD_VALUE(thistype, n) (* (int*) &(thistype)->fields[n].type) +#define TYPE_FIELD_BITPOS(thistype, n) (thistype)->fields[n].bitpos +#define TYPE_FIELD_BITSIZE(thistype, n) (thistype)->fields[n].bitsize +#define TYPE_FIELD_PACKED(thistype, n) (thistype)->fields[n].bitsize + +/* Functions that work on the objects described above */ + +extern struct symtab *lookup_symtab (); +extern struct symbol *lookup_symbol (); +extern struct type *lookup_typename (); +extern struct type *lookup_unsigned_typename (); +extern struct type *lookup_struct (); +extern struct type *lookup_union (); +extern struct type *lookup_enum (); +extern struct type *lookup_pointer_type (); +extern struct type *lookup_function_type (); +extern struct symbol *block_function (); +extern struct symbol *find_pc_function (); +extern int find_pc_misc_function (); + +extern struct type *builtin_type_void; +extern struct type *builtin_type_char; +extern struct type *builtin_type_short; +extern struct type *builtin_type_int; +extern struct type *builtin_type_long; +extern struct type *builtin_type_unsigned_char; +extern struct type *builtin_type_unsigned_short; +extern struct type *builtin_type_unsigned_int; +extern struct type *builtin_type_unsigned_long; +extern struct type *builtin_type_float; +extern struct type *builtin_type_double; + +struct symtab_and_line +{ + struct symtab *symtab; + int line; + CORE_ADDR pc; + CORE_ADDR end; +}; + +/* Given a pc value, return line number it is in. + Second arg nonzero means if pc is on the boundary + use the previous statement's line number. */ + +struct symtab_and_line find_pc_line (); + +/* Given a string, return the line specified by it. + For commands like "list" and "breakpoint". */ + +struct symtab_and_line decode_line_spec (); +struct symtab_and_line decode_line_1 (); diff --git a/gdb/test2.c b/gdb/test2.c new file mode 100644 index 00000000000..e6964f0e8f2 --- /dev/null +++ b/gdb/test2.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +main () +{ + struct user u; + printf ("&u.u_ar0 - &u = %d, 0%o\n", (int) &u.u_ar0 - (int) &u, + (int) &u.u_ar0 - (int) &u); + printf ("sizeof (struct pcb) = %d, 0%o\n", + sizeof (struct pcb), sizeof (struct pcb)); +} diff --git a/gdb/test3.c b/gdb/test3.c new file mode 100644 index 00000000000..cd27cdde381 --- /dev/null +++ b/gdb/test3.c @@ -0,0 +1,25 @@ +enum foo {foo1, foo2}; + +static double statdouble; + +newfun (ac) + struct haha {int a; } ac; +{ +} + +struct temp {int a; }; + +bar (a) + enum foo a; +{ + static int lose; + double happy; + typedef int myint; + + { + union wow { int a; char b; } wowvar; + static union wow wowvar1; + typedef int yourint; + char *winner; + } +} diff --git a/gdb/testattach.c b/gdb/testattach.c new file mode 100644 index 00000000000..c56a0fe1b42 --- /dev/null +++ b/gdb/testattach.c @@ -0,0 +1,10 @@ +main () +{ + int x = 0; + + while (1) + { + sleep (1); + x++; + } +} diff --git a/gdb/testbf.c b/gdb/testbf.c new file mode 100644 index 00000000000..dd661a0d060 --- /dev/null +++ b/gdb/testbf.c @@ -0,0 +1,13 @@ +struct foo +{ + int a : 5, : 4, b : 5; + char c; + int : 3, d : 8, : 0, e : 5; +}; + +struct foo x; + +main () +{ + printf (x); +} diff --git a/gdb/testbit.c b/gdb/testbit.c new file mode 100644 index 00000000000..9359f0b84b5 --- /dev/null +++ b/gdb/testbit.c @@ -0,0 +1,12 @@ +struct foo +{ + unsigned bar : 1; + unsigned lose : 1; +}; + +main () +{ + struct foo *win; + + printf ("%d, %d\n", win->bar, win->lose); +} diff --git a/gdb/testenum.c b/gdb/testenum.c new file mode 100644 index 00000000000..3d85f5ec416 --- /dev/null +++ b/gdb/testenum.c @@ -0,0 +1,25 @@ +/* Source file for showing ENUM lossage in GDB. + Compile with "cc -o foo -g foo.c". */ + +enum bar { value1, value2, value3 }; + +struct foo { + enum bar enum_value; + int int_value; + char *pointer_value; +}; + +struct foo foo_instance; +struct foo *foo_instance_pointer; + +main () +{ + foo_instance_pointer = &foo_instance; + foo_instance.enum_value = value2; + foo_instance.int_value = 1; + foo_instance.pointer_value = "Text to make a char *"; + + /* In GDB, set a breakpoint at this line. Then try to change the + value of foo_instance.enum_value in any way. I can't do it. */ +} + diff --git a/gdb/testfb.c b/gdb/testfb.c new file mode 100644 index 00000000000..1699471c241 --- /dev/null +++ b/gdb/testfb.c @@ -0,0 +1,12 @@ + +main () +{ + foo(2); + foo(3); +} + +foo (i) +{ + printf ("i is %d, ", i); + printf ("i*i is %d\n", i * i); +} diff --git a/gdb/testfun.c b/gdb/testfun.c new file mode 100644 index 00000000000..eeeebd7d24b --- /dev/null +++ b/gdb/testfun.c @@ -0,0 +1,22 @@ +main () +{ + register double a = 1.5; + foo (a); +} + +foo (x) +{ + printf ("%f\n", x); +} + +do_add (x, y) +{ + return x + y; +} + +double +do_float_add (x, y, z) + register double x, y, z; +{ + return x + y + z; +} diff --git a/gdb/testkill.c b/gdb/testkill.c new file mode 100644 index 00000000000..0e43c1f9f7d --- /dev/null +++ b/gdb/testkill.c @@ -0,0 +1,5 @@ + + main() + { + printf("foo\n"); + } diff --git a/gdb/testrec.c b/gdb/testrec.c new file mode 100644 index 00000000000..797c08b41a6 --- /dev/null +++ b/gdb/testrec.c @@ -0,0 +1,12 @@ +main () +{ + foo (4); +} + +foo (x) + int x; +{ + if (x > 0) + foo (x - 1); +} + diff --git a/gdb/testreg.c b/gdb/testreg.c new file mode 100644 index 00000000000..f19ec05cbcc --- /dev/null +++ b/gdb/testreg.c @@ -0,0 +1,22 @@ +main (argc, argv) + int argc; + char **argv; +{ + register int d1 = 34; + register int d2 = 35; + register int d3 = 36; + register int d4 = 37; + register char *a1 = "1"; + register char *a2 = "2"; + register char *a3 = "3"; + register char *a4 = "4"; + register char *a5 = "5"; + int x[4]; + foo (); + foo (0x222, abort (), 0x444); +} + +foo () +{ + return 22; +} diff --git a/gdb/testregs.c b/gdb/testregs.c new file mode 100644 index 00000000000..7a5acb3c300 --- /dev/null +++ b/gdb/testregs.c @@ -0,0 +1,20 @@ +typedef struct aa { int b;} *hack; + +static int +foo (argc) +{ + register int a = 0x1234; + register int b = 0x56788765; + register char *x = (char *) 0xabababab; + register char *y = (char *) 0xcdcdcdcd; + register double d = 1.582; + int loser; + printf ("Address of loser is 0x%x.\n", &loser); + printf ("Address of argc is 0x%x.\n", &argc); + abort (); +} + +main (argc) +{ + foo (argc); +} diff --git a/gdb/testshort.c b/gdb/testshort.c new file mode 100644 index 00000000000..2c606311e7b --- /dev/null +++ b/gdb/testshort.c @@ -0,0 +1,16 @@ +main () +{ + register int ntabs; + register short x; + short stops[30]; + + foo (); +} + +foo () +{ + register int ntabs; + register short x; + + printf (x, ntabs); +} diff --git a/gdb/testsig.c b/gdb/testsig.c new file mode 100644 index 00000000000..ded2d20b357 --- /dev/null +++ b/gdb/testsig.c @@ -0,0 +1,17 @@ +# include + +main () +{ + int handle (); + int i; + signal (SIGALRM, handle); + alarm (5); + for (i = 0; i < 100000; i++) + printf ("%d\n", i); +} + +handle () +{ + printf ("signal!\n"); + alarm (5); +} diff --git a/gdb/utils.c.OK b/gdb/utils.c.OK new file mode 100644 index 00000000000..7c52ea48188 --- /dev/null +++ b/gdb/utils.c.OK @@ -0,0 +1,422 @@ +/* General utility routines for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include +#include "defs.h" + +void error (); +void fatal (); + +/* Chain of cleanup actions established with make_cleanup, + to be executed if an error happens. */ + +static struct cleanup *cleanup_chain; + +/* Nonzero means a quit has been requested. */ + +int quit_flag; + +/* Nonzero means quit immediately if Control-C is typed now, + rather than waiting until QUIT is executed. */ + +int immediate_quit; + +/* Add a new cleanup to the cleanup_chain, + and return the previous chain pointer + to be passed later to do_cleanups or discard_cleanups. + Args are FUNCTION to clean up with, and ARG to pass to it. */ + +struct cleanup * +make_cleanup (function, arg) + void (*function) (); + int arg; +{ + register struct cleanup *new + = (struct cleanup *) xmalloc (sizeof (struct cleanup)); + register struct cleanup *old_chain = cleanup_chain; + + new->next = cleanup_chain; + new->function = function; + new->arg = arg; + cleanup_chain = new; + + return old_chain; +} + +/* Discard cleanups and do the actions they describe + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +do_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + (*ptr->function) (ptr->arg); + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* Discard cleanups, not doing the actions they describe, + until we get back to the point OLD_CHAIN in the cleanup_chain. */ + +void +discard_cleanups (old_chain) + register struct cleanup *old_chain; +{ + register struct cleanup *ptr; + while ((ptr = cleanup_chain) != old_chain) + { + cleanup_chain = ptr->next; + free (ptr); + } +} + +/* This function is useful for cleanups. + Do + + foo = xmalloc (...); + old_chain = make_cleanup (free_current_contents, &foo); + + to arrange to free the object thus allocated. */ + +void +free_current_contents (location) + char **location; +{ + free (*location); +} + +/* Generally useful subroutines used throughout the program. */ + +/* Like malloc but get error if no storage available. */ + +char * +xmalloc (size) + long size; +{ + register char *val = (char *) malloc (size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Like realloc but get error if no storage available. */ + +char * +xrealloc (ptr, size) + char *ptr; + long size; +{ + register char *val = (char *) realloc (ptr, size); + if (!val) + fatal ("virtual memory exhausted.", 0); + return val; +} + +/* Print the system error message for errno, and also mention STRING + as the file name for which the error was encountered. + Then return to command level. */ + +void +perror_with_name (string) + char *string; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + extern int errno; + char *err; + char *combined; + + if (errno < sys_nerr) + err = sys_errlist[errno]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + error ("%s.", combined); +} + +/* Print the system error message for ERRCODE, and also mention STRING + as the file name for which the error was encountered. */ + +void +print_sys_errmsg (string, errcode) + char *string; + int errcode; +{ + extern int sys_nerr; + extern char *sys_errlist[]; + char *err; + char *combined; + + if (errcode < sys_nerr) + err = sys_errlist[errcode]; + else + err = "unknown error"; + + combined = (char *) alloca (strlen (err) + strlen (string) + 3); + strcpy (combined, string); + strcat (combined, ": "); + strcat (combined, err); + + printf ("%s.\n", combined); +} + +void +quit () +{ + fflush (stdout); +#ifdef TIOCFLUSH + ioctl (fileno (stdout), TIOCFLUSH, 0); +#endif + error ("Quit"); +} + +/* Control C comes here */ + +void +request_quit () +{ + quit_flag = 1; + if (immediate_quit) + quit (); +} + +/* Print an error message and return to command level. + STRING is the error message, used as a fprintf string, + and ARG is passed as an argument to it. */ + +void +error (string, arg1, arg2, arg3) + char *string; + int arg1, arg2, arg3; +{ + fflush (stdout); + fprintf (stderr, string, arg1, arg2, arg3); + fprintf (stderr, "\n"); + return_to_top_level (); +} + +/* Print an error message and exit reporting failure. + This is for a error that we cannot continue from. + STRING and ARG are passed to fprintf. */ + +void +fatal (string, arg) + char *string; + int arg; +{ + fprintf (stderr, "gdb: "); + fprintf (stderr, string, arg); + fprintf (stderr, "\n"); + exit (1); +} + +/* Make a copy of the string at PTR with SIZE characters + (and add a null character at the end in the copy). + Uses malloc to get the space. Returns the address of the copy. */ + +char * +savestring (ptr, size) + char *ptr; + int size; +{ + register char *p = (char *) xmalloc (size + 1); + bcopy (ptr, p, size); + p[size] = 0; + return p; +} + +char * +concat (s1, s2, s3) + char *s1, *s2, *s3; +{ + register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; + register char *val = (char *) xmalloc (len); + strcpy (val, s1); + strcat (val, s2); + strcat (val, s3); + return val; +} + +void +print_spaces (n, file) + register int n; + register FILE *file; +{ + while (n-- > 0) + fputc (' ', file); +} + +/* Ask user a y-or-n question and return 1 iff answer is yes. + Takes three args which are given to printf to print the question. + The first, a control string, should end in "? ". + It should not say how to answer, because we do that. */ + +int +query (ctlstr, arg1, arg2) + char *ctlstr; +{ + register int answer; + + /* Automatically answer "yes" if input is not from a terminal. */ + if (!input_from_terminal_p ()) + return 1; + + while (1) + { + printf (ctlstr, arg1, arg2); + printf ("(y or n) "); + fflush (stdout); + answer = fgetc (stdin); + clearerr (stdin); /* in case of C-d */ + if (answer != '\n') + while (fgetc (stdin) != '\n') clearerr (stdin); + if (answer >= 'a') + answer -= 040; + if (answer == 'Y') + return 1; + if (answer == 'N') + return 0; + printf ("Please answer y or n.\n"); + } +} + +/* Parse a C escape sequence. STRING_PTR points to a variable + containing a pointer to the string to parse. That pointer + is updated past the characters we use. The value of the + escape sequence is returned. + + A negative value means the sequence \ newline was seen, + which is supposed to be equivalent to nothing at all. + + If \ is followed by a null character, we return a negative + value and leave the string pointer pointing at the null character. + + If \ is followed by 000, we return 0 and leave the string pointer + after the zeros. A value of 0 does not mean end of string. */ + +int +parse_escape (string_ptr) + char **string_ptr; +{ + register int c = *(*string_ptr)++; + switch (c) + { + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'e': + return 033; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case '\n': + return -2; + case 0: + (*string_ptr)--; + return 0; + case '^': + c = *(*string_ptr)++; + if (c == '\\') + c = parse_escape (string_ptr); + if (c == '?') + return 0177; + return (c & 0200) | (c & 037); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + register int i = c - '0'; + register int count = 0; + while (++count < 3) + { + if ((c = *(*string_ptr)++) >= '0' && c <= '7') + { + i *= 8; + i += c - '0'; + } + else + { + (*string_ptr)--; + break; + } + } + return i; + } + default: + return c; + } +} + +void +printchar (ch, stream) + unsigned char ch; + FILE *stream; +{ + register int c = ch; + if (c < 040 || c >= 0177) + { + if (c == '\n') + fprintf (stream, "\\n"); + else if (c == '\b') + fprintf (stream, "\\b"); + else if (c == '\t') + fprintf (stream, "\\t"); + else if (c == '\f') + fprintf (stream, "\\f"); + else if (c == '\r') + fprintf (stream, "\\r"); + else if (c == 033) + fprintf (stream, "\\e"); + else if (c == '\a') + fprintf (stream, "\\a"); + else + fprintf (stream, "\\%03o", c); + } + else + { + if (c == '\\' || c == '"' || c == '\'') + fputc ('\\', stream); + fputc (c, stream); + } +} diff --git a/gdb/valarith.c b/gdb/valarith.c new file mode 100644 index 00000000000..03bc1e1e923 --- /dev/null +++ b/gdb/valarith.c @@ -0,0 +1,365 @@ +/* Perform arithmetic and other operations on values, for GDB. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "value.h" +#include "expression.h" + +START_FILE + +value +value_add (arg1, arg2) + value arg1, arg2; +{ + register value val, valint, valptr; + register int len; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + if ((TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_PTR) + && + (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT + || TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT)) + /* Exactly one argument is a pointer, and one is an integer. */ + { + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + { + valptr = arg1; + valint = arg2; + } + else + { + valptr = arg2; + valint = arg1; + } + len = TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (valptr))); + if (len == 0) len = 1; /* For (void *) */ + val = value_from_long (builtin_type_long, + value_as_long (valptr) + + (len * value_as_long (valint))); + VALUE_TYPE (val) = VALUE_TYPE (valptr); + return val; + } + + return value_binop (arg1, arg2, BINOP_ADD); +} + +value +value_sub (arg1, arg2) + value arg1, arg2; +{ + register value val; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + && + TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_INT) + { + val = value_from_long (builtin_type_long, + value_as_long (arg1) + - TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1))) * value_as_long (arg2)); + VALUE_TYPE (val) = VALUE_TYPE (arg1); + return val; + } + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR + && + VALUE_TYPE (arg1) == VALUE_TYPE (arg2)) + { + val = value_from_long (builtin_type_long, + (value_as_long (arg1) - value_as_long (arg2)) + / TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)))); + return val; + } + + return value_binop (arg1, arg2, BINOP_SUB); +} + +/* Return the value of ARRAY[IDX]. */ + +value +value_subscript (array, idx) + value array, idx; +{ + return value_ind (value_add (array, idx)); +} + +/* Perform a binary operation on two integers or two floats. + Does not support addition and subtraction on pointers; + use value_add or value_sub if you want to handle those possibilities. */ + +value +value_binop (arg1, arg2, op) + value arg1, arg2; + int op; +{ + register value val; + + COERCE_ENUM (arg1); + COERCE_ENUM (arg2); + + if ((TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_FLT + && + TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT) + || + (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_FLT + && + TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_INT)) + error ("Argument to arithmetic operation not a number."); + + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_FLT + || + TYPE_CODE (VALUE_TYPE (arg2)) == TYPE_CODE_FLT) + { + double v1, v2, v; + v1 = value_as_double (arg1); + v2 = value_as_double (arg2); + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + default: + error ("Integer-only operation on floating point number."); + } + + val = allocate_value (builtin_type_double); + *(double *) VALUE_CONTENTS (val) = v; + } + else + { + long v1, v2, v; + v1 = value_as_long (arg1); + v2 = value_as_long (arg2); + + switch (op) + { + case BINOP_ADD: + v = v1 + v2; + break; + + case BINOP_SUB: + v = v1 - v2; + break; + + case BINOP_MUL: + v = v1 * v2; + break; + + case BINOP_DIV: + v = v1 / v2; + break; + + case BINOP_REM: + v = v1 % v2; + break; + + case BINOP_LSH: + v = v1 << v2; + break; + + case BINOP_RSH: + v = v1 >> v2; + break; + + case BINOP_LOGAND: + v = v1 & v2; + break; + + case BINOP_LOGIOR: + v = v1 | v2; + break; + + case BINOP_LOGXOR: + v = v1 ^ v2; + break; + + case BINOP_AND: + v = v1 && v2; + break; + + case BINOP_OR: + v = v1 || v2; + break; + + default: + error ("Invalid binary operation on numbers."); + } + + val = allocate_value (builtin_type_long); + *(long *) VALUE_CONTENTS (val) = v; + } + + return val; +} + +/* Simulate the C operator ! -- return 1 if ARG1 contains zeros. */ + +int +value_zerop (arg1) + value arg1; +{ + register int len; + register char *p; + + COERCE_ARRAY (arg1); + + len = TYPE_LENGTH (VALUE_TYPE (arg1)); + p = VALUE_CONTENTS (arg1); + + while (--len >= 0) + { + if (*p++) + break; + } + + return len < 0; +} + +/* Simulate the C operator == by returning a 1 + iff ARG1 and ARG2 have equal contents. */ + +int +value_equal (arg1, arg2) + register value arg1, arg2; + +{ + register int len; + register char *p1, *p2; + enum type_code code1; + enum type_code code2; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (VALUE_TYPE (arg1)); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + return value_as_long (arg1) == value_as_long (arg2); + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) == value_as_double (arg2); + else if ((code1 == TYPE_CODE_PTR && code2 == TYPE_CODE_INT) + || (code2 == TYPE_CODE_PTR && code1 == TYPE_CODE_INT)) + return value_as_long (arg1) == value_as_long (arg2); + else if (code1 == code2 + && ((len = TYPE_LENGTH (VALUE_TYPE (arg1))) + == TYPE_LENGTH (VALUE_TYPE (arg2)))) + { + p1 = VALUE_CONTENTS (arg1); + p2 = VALUE_CONTENTS (arg2); + while (--len >= 0) + { + if (*p1++ != *p2++) + break; + } + return len < 0; + } + else + error ("Invalid type combination in equality test."); +} + +/* Simulate the C operator < by returning 1 + iff ARG1's contents are less than ARG2's. */ + +int +value_less (arg1, arg2) + register value arg1, arg2; +{ + register enum type_code code1; + register enum type_code code2; + + COERCE_ARRAY (arg1); + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (VALUE_TYPE (arg1)); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + + if (code1 == TYPE_CODE_INT && code2 == TYPE_CODE_INT) + return value_as_long (arg1) < value_as_long (arg2); + else if ((code1 == TYPE_CODE_FLT || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_FLT || code2 == TYPE_CODE_INT)) + return value_as_double (arg1) < value_as_double (arg2); + else if ((code1 == TYPE_CODE_PTR || code1 == TYPE_CODE_INT) + && (code2 == TYPE_CODE_PTR || code2 == TYPE_CODE_INT)) + return value_as_long (arg1) < value_as_long (arg2); + else + error ("Invalid type combination in ordering comparison."); +} + +/* The unary operators - and ~. Both free the argument ARG1. */ + +value +value_neg (arg1) + register value arg1; +{ + register struct type *type; + + COERCE_ENUM (arg1); + + type = VALUE_TYPE (arg1); + + if (TYPE_CODE (type) == TYPE_CODE_FLT) + return value_from_double (type, - value_as_double (arg1)); + else if (TYPE_CODE (type) == TYPE_CODE_INT) + return value_from_long (type, - value_as_long (arg1)); + else + error ("Argument to negate operation not a number."); +} + +value +value_lognot (arg1) + register value arg1; +{ + COERCE_ENUM (arg1); + + if (TYPE_CODE (VALUE_TYPE (arg1)) != TYPE_CODE_INT) + error ("Argument to complement operation not an integer."); + + return value_from_long (VALUE_TYPE (arg1), ~ value_as_long (arg1)); +} + +static +initialize () +{ +} + +END_FILE diff --git a/gdb/valops.c b/gdb/valops.c new file mode 100644 index 00000000000..9f0e3cced9f --- /dev/null +++ b/gdb/valops.c @@ -0,0 +1,600 @@ +/* Perform non-arithmetic operations on values, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "value.h" + +START_FILE + +/* Cast value ARG2 to type TYPE and return as a value. + More general than a C cast: accepts any two types of the same length, + and if ARG2 is an lvalue it can be cast into anything at all. */ + +value +value_cast (type, arg2) + struct type *type; + register value arg2; +{ + register enum type_code code1; + register enum type_code code2; + register int scalar; + + /* Coerce arrays but not enums. Enums will work as-is + and coercing them would cause an infinite recursion. */ + if (TYPE_CODE (VALUE_TYPE (arg2)) != TYPE_CODE_ENUM) + COERCE_ARRAY (arg2); + + code1 = TYPE_CODE (type); + code2 = TYPE_CODE (VALUE_TYPE (arg2)); + scalar = (code2 == TYPE_CODE_INT || code2 == TYPE_CODE_FLT + || code2 == TYPE_CODE_ENUM); + + if (code1 == TYPE_CODE_FLT && scalar) + return value_from_double (type, value_as_double (arg2)); + else if ((code1 == TYPE_CODE_INT || code1 == TYPE_CODE_ENUM) + && (scalar || code2 == TYPE_CODE_PTR)) + return value_from_long (type, value_as_long (arg2)); + else if (TYPE_LENGTH (type) == TYPE_LENGTH (VALUE_TYPE (arg2))) + { + VALUE_TYPE (arg2) = type; + return arg2; + } + else if (VALUE_LVAL (arg2) == lval_memory) + return value_at (type, VALUE_ADDRESS (arg2) + VALUE_OFFSET (arg2)); + else + error ("Invalid cast."); +} + +/* Return the value with a specified type located at specified address. */ + +value +value_at (type, addr) + struct type *type; + CORE_ADDR addr; +{ + register value val = allocate_value (type); + + read_memory (addr, VALUE_CONTENTS (val), TYPE_LENGTH (type)); + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = addr; + + return val; +} + +/* Store the contents of FROMVAL into the location of TOVAL. + Return a new value with the location of TOVAL and contents of FROMVAL. */ + +value +value_assign (toval, fromval) + register value toval, fromval; +{ + register struct type *type = VALUE_TYPE (toval); + register value val; + char raw_buffer[MAX_REGISTER_RAW_SIZE]; + char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + int use_buffer = 0; + + COERCE_ARRAY (fromval); + + if (VALUE_LVAL (toval) != lval_internalvar) + fromval = value_cast (type, fromval); + + /* If TOVAL is a special machine register requiring conversion + of program values to a special raw format, + convert FROMVAL's contents now, with result in `raw_buffer', + and set USE_BUFFER to the number of bytes to write. */ + + if (VALUE_REGNO (toval) >= 0 + && REGISTER_CONVERTIBLE (VALUE_REGNO (toval))) + { + int regno = VALUE_REGNO (toval); + if (VALUE_TYPE (fromval) != REGISTER_VIRTUAL_TYPE (regno)) + fromval = value_cast (REGISTER_VIRTUAL_TYPE (regno), fromval); + bcopy (VALUE_CONTENTS (fromval), virtual_buffer, + REGISTER_VIRTUAL_SIZE (regno)); + REGISTER_CONVERT_TO_RAW (regno, virtual_buffer, raw_buffer); + use_buffer = REGISTER_RAW_SIZE (regno); + } + + switch (VALUE_LVAL (toval)) + { + case lval_internalvar: + set_internalvar (VALUE_INTERNALVAR (toval), fromval); + break; + + case lval_internalvar_component: + set_internalvar_component (VALUE_INTERNALVAR (toval), + VALUE_OFFSET (toval), + VALUE_BITPOS (toval), + VALUE_BITSIZE (toval), + fromval); + break; + + case lval_memory: + if (VALUE_BITSIZE (toval)) + { + int val; + read_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + modify_field (&val, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + } + else if (use_buffer) + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + write_memory (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + break; + + case lval_register: + if (VALUE_BITSIZE (toval)) + { + int val; + + read_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + modify_field (&val, value_as_long (fromval), + VALUE_BITPOS (toval), VALUE_BITSIZE (toval)); + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + &val, sizeof val); + } + else if (use_buffer) + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + raw_buffer, use_buffer); + else + write_register_bytes (VALUE_ADDRESS (toval) + VALUE_OFFSET (toval), + VALUE_CONTENTS (fromval), TYPE_LENGTH (type)); + break; + + default: + error ("Left side of = operation is not an lvalue."); + } + + /* Return a value just like TOVAL except with the contents of FROMVAL. */ + + val = allocate_value (type); + bcopy (toval, val, VALUE_CONTENTS (val) - (char *) val); + bcopy (VALUE_CONTENTS (fromval), VALUE_CONTENTS (val), TYPE_LENGTH (type)); + + return val; +} + +/* Extend a value VAL to COUNT repetitions of its type. */ + +value +value_repeat (arg1, count) + value arg1; + int count; +{ + register value val; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Only values in memory can be extended with '@'."); + if (count < 1) + error ("Invalid number %d of repetitions.", count); + + val = allocate_repeat_value (VALUE_TYPE (arg1), count); + + read_memory (VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1), + VALUE_CONTENTS (val), + TYPE_LENGTH (VALUE_TYPE (val)) * count); + VALUE_LVAL (val) = lval_memory; + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1); + + return val; +} + +value +value_of_variable (var) + struct symbol *var; +{ + return read_var_value (var, (CORE_ADDR) 0); +} + +/* Given a value which is an array, return a value which is + a pointer to its first element. */ + +value +value_coerce_array (arg1) + value arg1; +{ + register struct type *type; + register value val; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + /* Get type of elements. */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_ARRAY) + type = TYPE_TARGET_TYPE (VALUE_TYPE (arg1)); + else + /* A phony array made by value_repeat. + Its type is the type of the elements, not an array type. */ + type = VALUE_TYPE (arg1); + + /* Get the type of the result. */ + type = lookup_pointer_type (type); + val = value_from_long (builtin_type_long, + VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)); + VALUE_TYPE (val) = type; + return val; +} + +/* Return a pointer value for the object for which ARG1 is the contents. */ + +value +value_addr (arg1) + value arg1; +{ + register struct type *type; + register value val, arg1_coerced; + + /* Taking the address of an array is really a no-op + once the array is coerced to a pointer to its first element. */ + arg1_coerced = arg1; + COERCE_ARRAY (arg1_coerced); + if (arg1 != arg1_coerced) + return arg1_coerced; + + if (VALUE_LVAL (arg1) != lval_memory) + error ("Attempt to take address of value not located in memory."); + + /* Get the type of the result. */ + type = lookup_pointer_type (VALUE_TYPE (arg1)); + val = value_from_long (builtin_type_long, + VALUE_ADDRESS (arg1) + VALUE_OFFSET (arg1)); + VALUE_TYPE (val) = type; + return val; +} + +/* Given a value of a pointer type, apply the C unary * operator to it. */ + +value +value_ind (arg1) + value arg1; +{ + COERCE_ARRAY (arg1); + + /* Allow * on an integer so we can cast it to whatever we want. */ + if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_INT) + return value_at (builtin_type_long, + (CORE_ADDR) value_as_long (arg1)); + else if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_PTR) + return value_at (TYPE_TARGET_TYPE (VALUE_TYPE (arg1)), + (CORE_ADDR) value_as_long (arg1)); + error ("Attempt to take contents of a non-pointer value."); +} + +/* Pushing small parts of stack frames. */ + +/* Push one word (the size of object that a register holds). */ + +CORE_ADDR +push_word (sp, buffer) + CORE_ADDR sp; + REGISTER_TYPE buffer; +{ + register int len = sizeof (REGISTER_TYPE); + +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, &buffer, len); +#else /* stack grows upward */ + write_memory (sp, &buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push LEN bytes with data at BUFFER. */ + +CORE_ADDR +push_bytes (sp, buffer, len) + CORE_ADDR sp; + char *buffer; + int len; +{ +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, buffer, len); +#else /* stack grows upward */ + write_memory (sp, buffer, len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Push onto the stack the specified value VALUE. */ + +CORE_ADDR +value_push (sp, arg) + register CORE_ADDR sp; + value arg; +{ + register int len = TYPE_LENGTH (VALUE_TYPE (arg)); + +#if 1 INNER_THAN 2 + sp -= len; + write_memory (sp, VALUE_CONTENTS (arg), len); +#else /* stack grows upward */ + write_memory (sp, VALUE_CONTENTS (arg), len); + sp += len; +#endif /* stack grows upward */ + + return sp; +} + +/* Perform the standard coercions that are specified + for arguments to be passed to C functions. */ + +value +value_arg_coerce (arg) + value arg; +{ + register struct type *type; + + COERCE_ENUM (arg); + + type = VALUE_TYPE (arg); + + if (TYPE_CODE (type) == TYPE_CODE_INT + && TYPE_LENGTH (type) < sizeof (int)) + return value_cast (builtin_type_int, arg); + + if (type == builtin_type_float) + return value_cast (builtin_type_double, arg); + + return arg; +} + +/* Push the value ARG, first coercing it as an argument + to a C function. */ + +CORE_ADDR +value_arg_push (sp, arg) + register CORE_ADDR sp; + value arg; +{ + return value_push (sp, value_arg_coerce (arg)); +} + +/* Perform a function call in the inferior. + ARGS is a vector of values of arguments (NARGS of them). + FUNCTION is a value, the function to be called. + Returns a value representing what the function returned. + May fail to return, if a breakpoint or signal is hit + during the execution of the function. */ + +value +call_function (function, nargs, args) + value function; + int nargs; + value *args; +{ + register CORE_ADDR sp; + register int i; + CORE_ADDR start_sp; + static REGISTER_TYPE dummy[] = CALL_DUMMY; + REGISTER_TYPE dummy1[sizeof dummy / sizeof (REGISTER_TYPE)]; + CORE_ADDR old_sp; + struct type *value_type; + + PUSH_DUMMY_FRAME; + + { + register CORE_ADDR funaddr; + register struct type *ftype = VALUE_TYPE (function); + register enum type_code code = TYPE_CODE (ftype); + + /* Determine address to call. */ + if (code == TYPE_CODE_FUNC) + { + funaddr = VALUE_ADDRESS (function); + value_type = TYPE_TARGET_TYPE (ftype); + } + else if (code == TYPE_CODE_PTR) + { + funaddr = value_as_long (function); + if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) + == TYPE_CODE_FUNC) + value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)); + else + value_type = builtin_type_int; + } + else if (code == TYPE_CODE_INT) + { + /* Handle the case of functions lacking debugging info. + Their values are characters since their addresses are char */ + if (TYPE_LENGTH (ftype) == 1) + funaddr = value_as_long (value_addr (function)); + else + /* Handle integer used as address of a function. */ + funaddr = value_as_long (function); + + value_type = builtin_type_int; + } + else + error ("Invalid data type for function to be called."); + + /* Create a call sequence customized for this function + and the number of arguments for it. */ + bcopy (dummy, dummy1, sizeof dummy); + FIX_CALL_DUMMY (dummy1, funaddr, nargs); + } + + old_sp = sp = read_register (SP_REGNUM); + +#if 1 INNER_THAN 2 /* Stack grows down */ + sp -= sizeof dummy; + write_memory (sp, dummy1, sizeof dummy); + start_sp = sp; + for (i = nargs - 1; i >= 0; i--) + sp = value_arg_push (sp, args[i]); +#else /* Stack grows up */ + start_sp = sp; + write_memory (sp, dummy1, sizeof dummy); + sp += sizeof dummy; + for (i = 0; i < nargs; i++) + sp = value_arg_push (sp, args[i]); +#endif /* Stack grows up */ + + write_register (SP_REGNUM, sp); + + /* Figure out the value returned by the function. */ + { + char retbuf[REGISTER_BYTES]; + + /* Execute the stack dummy routine, calling FUNCTION. + When it is done, discard the empty frame + after storing the contents of all regs into retbuf. */ + run_stack_dummy (start_sp + CALL_DUMMY_START_OFFSET, retbuf); + + return value_being_returned (value_type, retbuf); + } +} + +/* Create a value for a string constant: + Call the function malloc in the inferior to get space for it, + then copy the data into that space + and then return the address with type char *. + PTR points to the string constant data; LEN is number of characters. */ + +value +value_string (ptr, len) + char *ptr; + int len; +{ + register value val; + register struct symbol *sym; + value blocklen; + register char *copy = (char *) alloca (len + 1); + char *i = ptr; + register char *o = copy, *ibeg = ptr; + register int c; + + /* Copy the string into COPY, processing escapes. + We could not conveniently process them in expread + because the string there wants to be a substring of the input. */ + + while (i - ibeg < len) + { + c = *i++; + if (c == '\\') + { + c = parse_escape (&i); + if (c == -1) + continue; + } + *o++ = c; + } + *o = 0; + + /* Get the length of the string after escapes are processed. */ + + len = o - copy; + + /* Find the address of malloc in the inferior. */ + + sym = lookup_symbol ("malloc", 0, VAR_NAMESPACE); + if (sym != 0) + { + if (SYMBOL_CLASS (sym) != LOC_BLOCK) + error ("\"malloc\" exists in this program but is not a function."); + val = value_of_variable (sym); + } + else + { + register int i; + for (i = 0; i < misc_function_count; i++) + if (!strcmp (misc_function_vector[i].name, "malloc")) + break; + if (i < misc_function_count) + val = value_from_long (builtin_type_long, + misc_function_vector[i].address); + else + error ("String constants require the program to have a function \"malloc\"."); + } + + blocklen = value_from_long (builtin_type_int, len + 1); + val = call_function (val, 1, &blocklen); + if (value_zerop (val)) + error ("No memory available for string constant."); + write_memory (value_as_long (val), copy, len + 1); + VALUE_TYPE (val) = lookup_pointer_type (builtin_type_char); + return val; +} + +/* Given ARG1, a value of type (pointer to a)* structure/union, + extract the component named NAME from the ultimate target structure/union + and return it as a value with its appropriate type. + ERR is used in the error message if ARG1's type is wrong. */ + +value +value_struct_elt (arg1, name, err) + register value arg1; + char *name; + char *err; +{ + register struct type *t; + register int i; + + COERCE_ARRAY (arg1); + + t = VALUE_TYPE (arg1); + + /* Follow pointers until we get to a non-pointer. */ + + while (TYPE_CODE (t) == TYPE_CODE_PTR) + { + arg1 = value_ind (arg1); + COERCE_ARRAY (arg1); + t = VALUE_TYPE (arg1); + } + + if (TYPE_CODE (t) != TYPE_CODE_STRUCT + && + TYPE_CODE (t) != TYPE_CODE_UNION) + error ("Attempt to extract a component of a value that is not a %s.", err); + + for (i = TYPE_NFIELDS (t) - 1; i >= 0; i--) + { + if (!strcmp (TYPE_FIELD_NAME (t, i), name)) + break; + } + + if (i < 0) + error ("Structure has no component named %s.", name); + + return value_field (arg1, i); +} + +static +initialize () +{ } + +END_FILE diff --git a/gdb/valprint.c b/gdb/valprint.c new file mode 100644 index 00000000000..78c8d63eb17 --- /dev/null +++ b/gdb/valprint.c @@ -0,0 +1,622 @@ +/* Print values for GNU debugger gdb. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include "defs.h" +#include "initialize.h" +#include "symtab.h" +#include "value.h" + +/* Maximum number of chars to print for a string pointer value + or vector contents. */ + +static int print_max; + +static void type_print_varspec_suffix (); +static void type_print_varspec_prefix (); +static void type_print_base (); + +START_FILE + +char **unsigned_type_table; +char **signed_type_table; +char **float_type_table; + +/* Print the value VAL in C-ish syntax on stream STREAM. + If the object printed is a string pointer, returns + the number of string bytes printed. */ + +value_print (val, stream) + value val; + FILE *stream; +{ + register int i, n, typelen; + + /* A "repeated" value really contains several values in a row. + They are made by the @ operator. + Print such values as if they were arrays. */ + + if (VALUE_REPEATED (val)) + { + n = VALUE_REPETITIONS (val); + typelen = TYPE_LENGTH (VALUE_TYPE (val)); + fputc ('{', stream); + /* Print arrays of characters using string syntax. */ + if (VALUE_TYPE (val) == builtin_type_char + || VALUE_TYPE (val) == builtin_type_unsigned_char) + { + fputc ('"', stream); + for (i = 0; i < n && i < print_max; i++) + { + QUIT; + printchar (VALUE_CONTENTS (val)[i], stream); + } + if (i < n) + fprintf (stream, "..."); + fputc ('"', stream); + } + else + { + for (i = 0; i < n && i < print_max; i++) + { + if (i) + fprintf (stream, ", "); + val_print (VALUE_TYPE (val), VALUE_CONTENTS (val) + typelen * i, + VALUE_ADDRESS (val) + typelen * i, stream); + } + if (i < n) + fprintf (stream, "..."); + } + fputc ('}', stream); + } + else + { + /* A simple (nonrepeated) value */ + /* If it is a pointer, indicate what it points to. */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR) + { + fprintf (stream, "("); + type_print (VALUE_TYPE (val), "", stream, -1); + fprintf (stream, ") "); + } + return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), + VALUE_ADDRESS (val), stream); + } +} + +/* Print on STREAM data stored in debugger at address VALADDR + according to the format of type TYPE. + ADDRESS is the location in the inferior that the data + is supposed to have come from. + + If the data are a string pointer, returns the number of + sting characters printed. */ + +int +val_print (type, valaddr, address, stream) + struct type *type; + char *valaddr; + CORE_ADDR address; + FILE *stream; +{ + register int i; + int len; + struct type *elttype; + int eltlen; + int val; + unsigned char c; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + if (TYPE_LENGTH (type) >= 0) + { + elttype = TYPE_TARGET_TYPE (type); + eltlen = TYPE_LENGTH (elttype); + len = TYPE_LENGTH (type) / eltlen; + fprintf (stream, "{"); + /* For an array of chars, print with string syntax. */ + if (elttype == builtin_type_char + || elttype == builtin_type_unsigned_char) + { + fputc ('"', stream); + for (i = 0; i < len && i < print_max; i++) + { + QUIT; + printchar (valaddr[i], stream); + } + if (i < len) + fprintf (stream, "..."); + fputc ('"', stream); + } + else + { + for (i = 0; i < len && i < print_max; i++) + { + if (i) fprintf (stream, ", "); + val_print (elttype, valaddr + i * eltlen, + 0, stream); + } + if (i < len) + fprintf (stream, "..."); + } + fprintf (stream, "}"); + break; + } + /* Array of unspecified length: treat like pointer. */ + + case TYPE_CODE_PTR: + fprintf (stream, "0x%x", * (int *) valaddr); + /* For a pointer to char or unsigned char, + also print the string pointed to, unless pointer is null. */ + if ((TYPE_TARGET_TYPE (type) == builtin_type_char + || TYPE_TARGET_TYPE (type) == builtin_type_unsigned_char) + && unpack_long (type, valaddr) != 0) + { + fputc (' ', stream); + fputc ('"', stream); + for (i = 0; i < print_max; i++) + { + QUIT; + read_memory (unpack_long (type, valaddr) + i, &c, 1); + if (c == 0) + break; + printchar (c, stream); + } + fputc ('"', stream); + if (i == print_max) + fprintf (stream, "..."); + fflush (stream); + /* Return number of characters printed, plus one for the + terminating null if we have "reached the end". */ + return i + (i != print_max); + } + break; + + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + for (i = 0; i < len; i++) + { + if (i) fprintf (stream, ", "); + fprintf (stream, "%s = ", TYPE_FIELD_NAME (type, i)); + if (TYPE_FIELD_PACKED (type, i)) + { + val = unpack_field_as_long (type, valaddr, i); + val_print (TYPE_FIELD_TYPE (type, i), &val, 0, stream); + } + else + val_print (TYPE_FIELD_TYPE (type, i), + valaddr + TYPE_FIELD_BITPOS (type, i) / 8, + 0, stream); + } + fprintf (stream, "}"); + break; + + case TYPE_CODE_ENUM: + len = TYPE_NFIELDS (type); + val = unpack_long (builtin_type_int, valaddr); + for (i = 0; i < len; i++) + { + QUIT; + if (val == TYPE_FIELD_VALUE (type, i)) + break; + } + if (i < len) + fprintf (stream, "%s", TYPE_FIELD_NAME (type, i)); + else + fprintf (stream, "%d", val); + break; + + case TYPE_CODE_FUNC: + fprintf (stream, "{"); + type_print (type, "", stream, -1); + fprintf (stream, "} "); + fprintf (stream, "0x%x", address); + break; + + case TYPE_CODE_INT: + fprintf (stream, + TYPE_UNSIGNED (type) ? "%u" : "%d", + unpack_long (type, valaddr)); + if (type == builtin_type_char + || type == builtin_type_unsigned_char) + { + fprintf (stream, " '"); + printchar (unpack_long (type, valaddr), stream); + fputc ('\'', stream); + } + break; + + case TYPE_CODE_FLT: +#ifdef IEEE_FLOAT + if (is_nan (unpack_double (type, valaddr))) + { + fprintf (stream, "Nan"); + break; + } +#endif + fprintf (stream, "%g", unpack_double (type, valaddr)); + break; + + case TYPE_CODE_VOID: + fprintf (stream, "void"); + break; + + default: + error ("Invalid type code in symbol table."); + } + fflush (stream); +} + +#ifdef IEEE_FLOAT + +union ieee { + int i[2]; + double d; +}; + +/* Nonzero if ARG (a double) is a NAN. */ + +int +is_nan (arg) + union ieee arg; +{ + int lowhalf, highhalf; + union { int i; char c; } test; + + /* Separate the high and low words of the double. + Distinguish big and little-endian machines. */ + test.i = 1; + if (test.c != 1) + /* Big-endian machine */ + lowhalf = arg.i[1], highhalf = arg.i[0]; + else + lowhalf = arg.i[0], highhalf = arg.i[1]; + + /* Nan: exponent is the maximum possible, and fraction is nonzero. */ + return (((highhalf>>20) & 0x7ff) == 0x7ff + && + ! ((highhalf & 0xfffff == 0) && (lowhalf == 0))); +} +#endif + +/* Print a description of a type TYPE + in the form of a declaration of a variable named VARSTRING. + Output goes to STREAM (via stdio). + If SHOW is positive, we show the contents of the outermost level + of structure even if there is a type name that could be used instead. + If SHOW is negative, we never show the details of elements' types. */ + +type_print (type, varstring, stream, show) + struct type *type; + char *varstring; + FILE *stream; + int show; +{ + type_print_1 (type, varstring, stream, show, 0); +} + +/* LEVEL is the depth to indent lines by. */ + +type_print_1 (type, varstring, stream, show, level) + struct type *type; + char *varstring; + FILE *stream; + int show; + int level; +{ + register enum type_code code; + type_print_base (type, stream, show, level); + code = TYPE_CODE (type); + if ((varstring && *varstring) + || + /* Need a space if going to print stars or brackets; + but not if we will print just a type name. */ + ((show > 0 || TYPE_NAME (type) == 0) + && + (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC + || code == TYPE_CODE_ARRAY))) + fprintf (stream, " "); + type_print_varspec_prefix (type, stream, show, 0); + fprintf (stream, "%s", varstring); + type_print_varspec_suffix (type, stream, show, 0); +} + +/* Print any asterisks or open-parentheses needed before the + variable name (to describe its type). + + On outermost call, pass 0 for PASSED_A_PTR. + On outermost call, SHOW > 0 means should ignore + any typename for TYPE and show its details. + SHOW is always zero on recursive calls. */ + +static void +type_print_varspec_prefix (type, stream, show, passed_a_ptr) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; +{ + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_PTR: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); + fputc ('*', stream); + break; + + case TYPE_CODE_FUNC: + case TYPE_CODE_ARRAY: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fputc ('(', stream); + break; + } +} + +/* Print any array sizes, function arguments or close parentheses + needed after the variable name (to describe its type). + Args work like type_print_varspec_prefix. */ + +static void +type_print_varspec_suffix (type, stream, show, passed_a_ptr) + struct type *type; + FILE *stream; + int show; + int passed_a_ptr; +{ + if (TYPE_NAME (type) && show <= 0) + return; + + QUIT; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf (stream, ")"); + fprintf (stream, "["); + if (TYPE_LENGTH (type) >= 0) + fprintf (stream, "%d", + TYPE_LENGTH (type) / TYPE_LENGTH (TYPE_TARGET_TYPE (type))); + fprintf (stream, "]"); + break; + + case TYPE_CODE_PTR: + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1); + break; + + case TYPE_CODE_FUNC: + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); + if (passed_a_ptr) + fprintf (stream, ")"); + fprintf (stream, "()"); + break; + } +} + +/* Print the name of the type (or the ultimate pointer target, + function value or array element), or the description of a + structure or union. + + SHOW nonzero means don't print this type as just its name; + show its real definition even if it has a name. + SHOW zero means print just typename or struct tag if there is one + SHOW negative means abbreviate structure elements. + SHOW is decremented for printing of structure elements. + + LEVEL is the depth to indent by. + We increase it for some recursive calls. */ + +static void +type_print_base (type, stream, show, level) + struct type *type; + FILE *stream; + int show; + int level; +{ + char *name; + register int i; + register int len; + register int lastval; + + QUIT; + + if (TYPE_NAME (type) && show <= 0) + { + fprintf (stream, TYPE_NAME (type)); + return; + } + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + case TYPE_CODE_PTR: + case TYPE_CODE_FUNC: + type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); + break; + + case TYPE_CODE_STRUCT: + fprintf (stream, "struct "); + goto struct_union; + + case TYPE_CODE_UNION: + fprintf (stream, "union "); + struct_union: + if (TYPE_NAME (type) && (name = TYPE_NAME (type))) + { + while (*name != ' ') name++; + fprintf (stream, "%s ", name + 1); + } + if (show < 0) + fprintf (stream, "{...}"); + else + { + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + fprintf (stream, "\n"); + for (i = 0; i < len; i++) + { + QUIT; + print_spaces (level + 4, stream); + + /* If this is a bit-field and there is a gap before it, + print a nameless field to account for the gap. */ + + if (TYPE_FIELD_PACKED (type, i)) + { + int gap = (TYPE_FIELD_BITPOS (type, i) + - (i > 0 + ? (TYPE_FIELD_BITPOS (type, i - 1) + + (TYPE_FIELD_PACKED (type, i - 1) + ? TYPE_FIELD_BITSIZE (type, i - 1) + : TYPE_LENGTH (TYPE_FIELD_TYPE (type, i - 1)) * 8)) + : 0)); + if (gap != 0) + { + fprintf (stream, "int : %d;\n", gap); + print_spaces (level + 4, stream); + } + } + + /* Print the declaration of this field. */ + + type_print_1 (TYPE_FIELD_TYPE (type, i), + TYPE_FIELD_NAME (type, i), + stream, show - 1, level + 4); + + /* Print the field width. */ + + if (TYPE_FIELD_PACKED (type, i)) + fprintf (stream, " : %d", TYPE_FIELD_BITSIZE (type, i)); + + fprintf (stream, ";\n"); + } + print_spaces (level, stream); + fputc ('}', stream); + } + break; + + case TYPE_CODE_ENUM: + fprintf (stream, "enum "); + if (TYPE_NAME (type)) + { + name = TYPE_NAME (type); + while (*name != ' ') name++; + fprintf (stream, "%s ", name + 1); + } + if (show < 0) + fprintf (stream, "{...}"); + else + { + fprintf (stream, "{"); + len = TYPE_NFIELDS (type); + lastval = 0; + for (i = 0; i < len; i++) + { + QUIT; + if (i) fprintf (stream, ", "); + fprintf (stream, "%s", TYPE_FIELD_NAME (type, i)); + if (lastval != TYPE_FIELD_VALUE (type, i)) + { + fprintf (stream, " : %d", TYPE_FIELD_VALUE (type, i)); + lastval = TYPE_FIELD_VALUE (type, i); + } + lastval++; + } + fprintf (stream, "}"); + } + break; + + case TYPE_CODE_INT: + if (TYPE_UNSIGNED (type)) + name = unsigned_type_table[TYPE_LENGTH (type)]; + else + name = signed_type_table[TYPE_LENGTH (type)]; + fprintf (stream, "%s", name); + break; + + case TYPE_CODE_FLT: + name = float_type_table[TYPE_LENGTH (type)]; + fprintf (stream, "%s", name); + break; + + case TYPE_CODE_VOID: + fprintf (stream, "void"); + break; + + case 0: + fprintf (stream, "struct unknown"); + break; + + default: + error ("Invalid type code in symbol table."); + } +} + +static void +set_maximum_command (arg) + char *arg; +{ + if (!arg) error_no_arg ("value for maximum elements to print"); + print_max = atoi (arg); +} + +static +initialize () +{ + add_com ("set-maximum", class_vars, set_maximum_command, + "Set NUMBER as limit on string chars or array elements to print."); + + print_max = 200; + + unsigned_type_table + = (char **) xmalloc ((1 + sizeof (unsigned long)) * sizeof (char *)); + bzero (unsigned_type_table, (1 + sizeof (unsigned long))); + unsigned_type_table[sizeof (unsigned char)] = "unsigned char"; + unsigned_type_table[sizeof (unsigned short)] = "unsigned short"; + unsigned_type_table[sizeof (unsigned long)] = "unsigned long"; + unsigned_type_table[sizeof (unsigned int)] = "unsigned int"; + + signed_type_table + = (char **) xmalloc ((1 + sizeof (long)) * sizeof (char *)); + bzero (signed_type_table, (1 + sizeof (long))); + signed_type_table[sizeof (char)] = "char"; + signed_type_table[sizeof (short)] = "short"; + signed_type_table[sizeof (long)] = "long"; + signed_type_table[sizeof (int)] = "int"; + + float_type_table + = (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *)); + bzero (float_type_table, (1 + sizeof (double))); + float_type_table[sizeof (float)] = "float"; + float_type_table[sizeof (double)] = "double"; +} + +END_FILE diff --git a/gdb/value.h b/gdb/value.h new file mode 100644 index 00000000000..9801d9abca9 --- /dev/null +++ b/gdb/value.h @@ -0,0 +1,130 @@ +/* Definitions for values of C expressions, for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +enum lval_type { not_lval, lval_memory, lval_register, lval_internalvar, + lval_internalvar_component }; + +struct value + { + enum lval_type lval; + union + { + CORE_ADDR address; + struct internalvar *internalvar; + } location; + int offset; + int bitsize; + int bitpos; + struct type *type; + struct value *next; + short repeated; + short repetitions; + short regno; + long contents[1]; + }; + +typedef struct value *value; + +#define VALUE_TYPE(val) (val)->type +#define VALUE_CONTENTS(val) ((char *) (val)->contents) +#define VALUE_LVAL(val) (val)->lval +#define VALUE_ADDRESS(val) (val)->location.address +#define VALUE_INTERNALVAR(val) (val)->location.internalvar +#define VALUE_OFFSET(val) (val)->offset +#define VALUE_BITSIZE(val) (val)->bitsize +#define VALUE_BITPOS(val) (val)->bitpos +#define VALUE_NEXT(val) (val)->next +#define VALUE_REPEATED(val) (val)->repeated +#define VALUE_REPETITIONS(val) (val)->repetitions +#define VALUE_REGNO(val) (val)->regno + +/* If ARG is an array, convert it to a pointer. + If ARG is an enum, convert it to an integer. */ + +#define COERCE_ARRAY(arg) \ +{ if (VALUE_REPEATED (arg) \ + || TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ARRAY) \ + arg = value_coerce_array (arg); \ + if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* If ARG is an enum, convert it to an integer. */ + +#define COERCE_ENUM(arg) \ +{ if (TYPE_CODE (VALUE_TYPE (arg)) == TYPE_CODE_ENUM) \ + arg = value_cast (builtin_type_unsigned_int, arg); \ +} + +/* Internal variables (variables for convenience of use of debugger) + are recorded as a chain of these structures. */ + +struct internalvar +{ + struct internalvar *next; + char *name; + value value; +}; + +long value_as_long (); +double value_as_double (); +long unpack_long (); +double unpack_double (); +long unpack_field_as_long (); +value value_from_long (); +value value_from_double (); +value value_at (); +value value_of_variable (); +value value_of_register (); +value read_var_value (); +value locate_var_value (); +value allocate_value (); +value allocate_repeat_value (); +value value_string (); + +value value_binop (); +value value_add (); +value value_sub (); +value value_coerce_array (); +value value_ind (); +value value_addr (); +value value_assign (); +value value_neg (); +value value_lognot (); +value value_struct_elt (); +value value_field (); +value value_cast (); +value value_repeat (); +value value_subscript (); + +value call_function (); +value value_being_returned (); + +value evaluate_expression (); +value evaluate_type (); +value parse_and_eval (); + +value access_value_history (); +value value_of_internalvar (); +struct internalvar *lookup_internalvar (); + +int value_equal (); +int value_less (); +int value_zerop (); diff --git a/gdb/values.c b/gdb/values.c new file mode 100644 index 00000000000..9af5d96f3e8 --- /dev/null +++ b/gdb/values.c @@ -0,0 +1,749 @@ +/* Low level packing and unpacking of values for GDB. + Copyright (C) 1986, 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "value.h" + +/* The value-history records all the values printed + by print commands during this session. Each chunk + records 60 consecutive values. The first chunk on + the chain records the most recent values. + The total number of values is in value_history_count. */ + +#define VALUE_HISTORY_CHUNK 60 + +struct value_history_chunk +{ + struct value_history_chunk *next; + value values[VALUE_HISTORY_CHUNK]; +}; + +/* Chain of chunks now in use. */ + +static struct value_history_chunk *value_history_chain; + +static int value_history_count; /* Abs number of last entry stored */ + +START_FILE + +/* List of all value objects currently allocated + (except for those released by calls to release_value) + This is so they can be freed after each command. */ + +static value all_values; + +/* Allocate a value that has the correct length for type TYPE. */ + +value +allocate_value (type) + struct type *type; +{ + register value val; + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type)); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 0; + VALUE_REPETITIONS (val) = 0; + VALUE_REGNO (val) = -1; + return val; +} + +/* Allocate a value that has the correct length + for COUNT repetitions type TYPE. */ + +value +allocate_repeat_value (type, count) + struct type *type; + int count; +{ + register value val; + + val = (value) xmalloc (sizeof (struct value) + TYPE_LENGTH (type) * count); + VALUE_NEXT (val) = all_values; + all_values = val; + VALUE_TYPE (val) = type; + VALUE_LVAL (val) = not_lval; + VALUE_ADDRESS (val) = 0; + VALUE_OFFSET (val) = 0; + VALUE_BITPOS (val) = 0; + VALUE_BITSIZE (val) = 0; + VALUE_REPEATED (val) = 1; + VALUE_REPETITIONS (val) = count; + VALUE_REGNO (val) = -1; + return val; +} + +/* Free all the values that have been allocated (except for those released). + Called after each command, successful or not. */ + +void +free_all_values () +{ + register value val, next; + + for (val = all_values; val; val = next) + { + next = VALUE_NEXT (val); + free (val); + } + + all_values = 0; +} + +/* Remove VAL from the chain all_values + so it will not be freed automatically. */ + +void +release_value (val) + register value val; +{ + register value v; + + if (all_values == val) + { + all_values = val->next; + return; + } + + for (v = all_values; v; v = v->next) + { + if (v->next == val) + { + v->next = val->next; + break; + } + } +} + +/* Return a copy of the value ARG. + It contains the same contents, for same memory address, + but it's a different block of storage. */ + +static value +value_copy (arg) + value arg; +{ + register value val; + register struct type *type = VALUE_TYPE (arg); + if (VALUE_REPEATED (arg)) + val = allocate_repeat_value (type, VALUE_REPETITIONS (arg)); + else + val = allocate_value (type); + VALUE_LVAL (val) = VALUE_LVAL (arg); + VALUE_ADDRESS (val) = VALUE_ADDRESS (arg); + VALUE_OFFSET (val) = VALUE_OFFSET (arg); + VALUE_BITPOS (val) = VALUE_BITPOS (arg); + VALUE_BITSIZE (val) = VALUE_BITSIZE (arg); + VALUE_REGNO (val) = VALUE_REGNO (arg); + bcopy (VALUE_CONTENTS (arg), VALUE_CONTENTS (val), + TYPE_LENGTH (VALUE_TYPE (arg)) + * (VALUE_REPEATED (arg) ? VALUE_REPETITIONS (arg) : 1)); + return val; +} + +/* Access to the value history. */ + +/* Record a new value in the value history. + Returns the absolute history index of the entry. */ + +int +record_latest_value (val) + value val; +{ + register int i; + + /* Get error now if about to store an invalid float. */ + if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FLT) + value_as_double (val); + + /* Here we treat value_history_count as origin-zero + and applying to the value being stored now. */ + + i = value_history_count % VALUE_HISTORY_CHUNK; + if (i == 0) + { + register struct value_history_chunk *new + = (struct value_history_chunk *) xmalloc (sizeof (struct value_history_chunk)); + bzero (new->values, sizeof new->values); + new->next = value_history_chain; + value_history_chain = new; + } + + value_history_chain->values[i] = val; + release_value (val); + + /* Now we regard value_history_count as origin-one + and applying to the value just stored. */ + + return ++value_history_count; +} + +/* Return a copy of the value in the history with sequence number NUM. */ + +value +access_value_history (num) + int num; +{ + register struct value_history_chunk *chunk; + register int i; + register int absnum = num; + + if (absnum <= 0) + absnum += value_history_count; + + if (absnum <= 0) + { + if (num == 0) + error ("The history is empty."); + else if (num == 1) + error ("There is only one value in the history."); + else + error ("History does not go back to $$%d.", -num); + } + if (absnum > value_history_count) + error ("History has not yet reached $%d.", absnum); + + absnum--; + + /* Now absnum is always absolute and origin zero. */ + + chunk = value_history_chain; + for (i = (value_history_count - 1) / VALUE_HISTORY_CHUNK - absnum / VALUE_HISTORY_CHUNK; + i > 0; i--) + chunk = chunk->next; + + return value_copy (chunk->values[absnum % VALUE_HISTORY_CHUNK]); +} + +/* Clear the value history entirely. + Must be done when new symbol tables are loaded, + because the type pointers become invalid. */ + +void +clear_value_history () +{ + register struct value_history_chunk *next; + register int i; + register value val; + + while (value_history_chain) + { + for (i = 0; i < VALUE_HISTORY_CHUNK; i++) + if (val = value_history_chain->values[i]) + free (val); + next = value_history_chain->next; + free (value_history_chain); + value_history_chain = next; + } + value_history_count = 0; +} + +static void +history_info (num_exp) + char *num_exp; +{ + register int i; + register value val; + register int num; + + if (num_exp) + num = parse_and_eval_address (num_exp) - 5; + else + num = value_history_count - 9; + + if (num <= 0) + num = 1; + + for (i = num; i < num + 10 && i <= value_history_count; i++) + { + val = access_value_history (i); + printf ("$%d = ", i); + value_print (val, stdout); + printf ("\n"); + } +} + +/* Internal variables. These are variables within the debugger + that hold values assigned by debugger commands. + The user refers to them with a '$' prefix + that does not appear in the variable names stored internally. */ + +static struct internalvar *internalvars; + +/* Look up an internal variable with name NAME. NAME should not + normally include a dollar sign. + + If the specified internal variable does not exist, + one is created, with a void value. */ + +struct internalvar * +lookup_internalvar (name) + char *name; +{ + register struct internalvar *var; + + for (var = internalvars; var; var = var->next) + if (!strcmp (var->name, name)) + return var; + + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, "", ""); + var->value = allocate_value (builtin_type_void); + release_value (var->value); + var->next = internalvars; + internalvars = var; + return var; +} + +value +value_of_internalvar (var) + struct internalvar *var; +{ + register value val = value_copy (var->value); + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; +} + +void +set_internalvar_component (var, offset, bitpos, bitsize, newval) + struct internalvar *var; + int offset, bitpos, bitsize; + value newval; +{ + register char *addr = VALUE_CONTENTS (var->value) + offset; + if (bitsize) + modify_field (addr, value_as_long (newval), + bitpos, bitsize); + else + bcopy (VALUE_CONTENTS (newval), addr, + TYPE_LENGTH (VALUE_TYPE (newval))); +} + +void +set_internalvar (var, val) + struct internalvar *var; + value val; +{ + free (var->value); + var->value = value_copy (val); + release_value (var->value); +} + +char * +internalvar_name (var) + struct internalvar *var; +{ + return var->name; +} + +/* Free all internalvars. Done when new symtabs are loaded, + because that makes the values invalid. */ + +void +clear_internalvars () +{ + register struct internalvar *var; + + while (internalvars) + { + var = internalvars; + internalvars = var->next; + free (var->name); + free (var->value); + free (var); + } +} + +static void +convenience_info () +{ + register struct internalvar *var; + + if (internalvars) + printf ("Debugger convenience variables:\n\n"); + else + printf ("No debugger convenience variables now defined.\n\ +Convenience variables have names starting with \"$\";\n\ +use \"set\" as in \"set $foo = 5\" to define them.\n"); + + for (var = internalvars; var; var = var->next) + { + printf ("$%s: ", var->name); + value_print (var->value, stdout); + printf ("\n"); + } +} + +/* Extract a value as a C number (either long or double). + Knows how to convert fixed values to double, or + floating values to long. + Does not deallocate the value. */ + +long +value_as_long (val) + register value val; +{ + return unpack_long (VALUE_TYPE (val), VALUE_CONTENTS (val)); +} + +double +value_as_double (val) + register value val; +{ + return unpack_double (VALUE_TYPE (val), VALUE_CONTENTS (val)); +} + +/* Unpack raw data (copied from debugee) at VALADDR + as a long, or as a double, assuming the raw data is described + by type TYPE. Knows how to convert different sizes of values + and can convert between fixed and floating point. */ + +long +unpack_long (type, valaddr) + struct type *type; + char *valaddr; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + if (code == TYPE_CODE_ENUM) + code = TYPE_CODE_INT; + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + return * (float *) valaddr; + + if (len == sizeof (double)) + return * (double *) valaddr; + } + else if (code == TYPE_CODE_INT && nosign) + { + if (len == sizeof (char)) + return * (unsigned char *) valaddr; + + if (len == sizeof (short)) + return * (unsigned short *) valaddr; + + if (len == sizeof (int)) + return * (unsigned int *) valaddr; + + if (len == sizeof (long)) + return * (unsigned long *) valaddr; + } + else if (code == TYPE_CODE_INT) + { + if (len == sizeof (char)) + return * (char *) valaddr; + + if (len == sizeof (short)) + return * (short *) valaddr; + + if (len == sizeof (int)) + return * (int *) valaddr; + + if (len == sizeof (long)) + return * (long *) valaddr; + } + else if (code == TYPE_CODE_PTR) + { + if (len == sizeof (char *)) + return (CORE_ADDR) * (char **) valaddr; + } + + error ("Value not integer or pointer."); +} + +double +unpack_double (type, valaddr) + struct type *type; + char *valaddr; +{ + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + register int nosign = TYPE_UNSIGNED (type); + + if (code == TYPE_CODE_FLT) + { + if (INVALID_FLOAT (valaddr, len)) + error ("Invalid floating value found in program."); + + if (len == sizeof (float)) + return * (float *) valaddr; + + if (len == sizeof (double)) + return * (double *) valaddr; + } + else if (code == TYPE_CODE_INT && nosign) + { + if (len == sizeof (char)) + return * (unsigned char *) valaddr; + + if (len == sizeof (short)) + return * (unsigned short *) valaddr; + + if (len == sizeof (int)) + return * (unsigned int *) valaddr; + + if (len == sizeof (long)) + return * (unsigned long *) valaddr; + } + else if (code == TYPE_CODE_INT) + { + if (len == sizeof (char)) + return * (char *) valaddr; + + if (len == sizeof (short)) + return * (short *) valaddr; + + if (len == sizeof (int)) + return * (int *) valaddr; + + if (len == sizeof (long)) + return * (long *) valaddr; + } + + error ("Value not floating number."); +} + +/* Given a value ARG1 of a struct or union type, + extract and return the value of one of its fields. + FIELDNO says which field. */ + +value +value_field (arg1, fieldno) + register value arg1; + register int fieldno; +{ + register value v; + register struct type *type = TYPE_FIELD_TYPE (VALUE_TYPE (arg1), fieldno); + register int offset; + + /* Handle packed fields */ + + offset = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) / 8; + if (TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno)) + { + v = value_from_long (type, + unpack_field_as_long (VALUE_TYPE (arg1), + VALUE_CONTENTS (arg1), + fieldno)); + VALUE_BITPOS (v) = TYPE_FIELD_BITPOS (VALUE_TYPE (arg1), fieldno) % 8; + VALUE_BITSIZE (v) = TYPE_FIELD_BITSIZE (VALUE_TYPE (arg1), fieldno); + } + else + { + v = allocate_value (type); + bcopy (VALUE_CONTENTS (arg1) + offset, + VALUE_CONTENTS (v), + TYPE_LENGTH (type)); + } + VALUE_LVAL (v) = VALUE_LVAL (arg1); + if (VALUE_LVAL (arg1) == lval_internalvar) + VALUE_LVAL (v) = lval_internalvar_component; + VALUE_ADDRESS (v) = VALUE_ADDRESS (arg1); + VALUE_OFFSET (v) = offset + VALUE_OFFSET (arg1); + return v; +} + +long +unpack_field_as_long (type, valaddr, fieldno) + struct type *type; + char *valaddr; + int fieldno; +{ + long val; + int bitpos = TYPE_FIELD_BITPOS (type, fieldno); + int bitsize = TYPE_FIELD_BITSIZE (type, fieldno); + union { int i; char c; } test; + + bcopy (valaddr + bitpos / 8, &val, sizeof val); + + /* Extracting bits depends on endianness of the machine. */ + test.i = 1; + if (test.c == 1) + /* Little-endian. */ + val = val >> (bitpos % 8); + else + val = val >> (sizeof val * 8 - bitpos % 8 - bitsize); + + val &= (1 << bitsize) - 1; + return val; +} + +modify_field (addr, fieldval, bitpos, bitsize) + char *addr; + int fieldval; + int bitpos, bitsize; +{ + long oword; + union { int i; char c; } test; + + bcopy (addr, &oword, sizeof oword); + + /* Shifting for bit field depends on endianness of the machine. */ + test.c = 1; + if (test.i != 1) + /* not little-endian: assume big-endian. */ + bitpos = sizeof oword * 8 - bitpos - bitsize; + + oword &= ~(((1 << bitsize) - 1) << bitpos); + oword |= fieldval << bitpos; + bcopy (&oword, addr, sizeof oword); +} + +/* Convert C numbers into newly allocated values */ + +value +value_from_long (type, num) + struct type *type; + register long num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + if (code == TYPE_CODE_INT || code == TYPE_CODE_ENUM) + { + if (len == sizeof (char)) + * (char *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (short)) + * (short *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (int)) + * (int *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (long)) + * (long *) VALUE_CONTENTS (val) = num; + else + error ("Integer type encountered with unexpected data length."); + } + else + error ("Unexpected type encountered for integer constant."); + + return val; +} + +value +value_from_double (type, num) + struct type *type; + double num; +{ + register value val = allocate_value (type); + register enum type_code code = TYPE_CODE (type); + register int len = TYPE_LENGTH (type); + + if (code == TYPE_CODE_FLT) + { + if (len == sizeof (float)) + * (float *) VALUE_CONTENTS (val) = num; + else if (len == sizeof (double)) + * (double *) VALUE_CONTENTS (val) = num; + else + error ("Floating type encountered with unexpected data length."); + } + else + error ("Unexpected type encountered for floating constant."); + + return val; +} + +/* Deal with the value that is "about to be returned". */ + +/* Return the value that a function returning now + would be returning to its caller, assuming its type is VALTYPE. + RETBUF is where we look for what ought to be the contents + of the registers (in raw form). This is because it is often + desirable to restore old values to those registers + after saving the contents of interest, and then call + this function using the saved values. */ + +value +value_being_returned (valtype, retbuf) + register struct type *valtype; + char retbuf[REGISTER_BYTES]; +{ + register value val; + + if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT + || TYPE_CODE (valtype) == TYPE_CODE_UNION) + return value_at (valtype, EXTRACT_STRUCT_VALUE_ADDRESS (retbuf)); + + val = allocate_value (valtype); + EXTRACT_RETURN_VALUE (valtype, retbuf, VALUE_CONTENTS (val)); + + return val; +} + +/* Store VAL so it will be returned if a function returns now. + Does not verify that VAL's type matches what the current + function wants to return. */ + +void +set_return_value (val) + value val; +{ + register enum type_code code = TYPE_CODE (VALUE_TYPE (val)); + char regbuf[REGISTER_BYTES]; + double dbuf; + long lbuf; + + if (code == TYPE_CODE_STRUCT + || code == TYPE_CODE_UNION) + error ("Specifying a struct or union return value is not supported."); + + if (code == TYPE_CODE_FLT) + { + dbuf = value_as_double (val); + + STORE_RETURN_VALUE (VALUE_TYPE (val), &dbuf); + } + else + { + lbuf = value_as_long (val); + STORE_RETURN_VALUE (VALUE_TYPE (val), &lbuf); + } +} + +static +initialize () +{ + add_info ("convenience", convenience_info, + "Debugger convenience (\"$foo\") variables.\n\ +These variables are created when you assign them values;\n\ +thus, \"print $foo=1\" gives \"$foo\" the value 1. Values may be any type.\n\n\ +A few convenience variables are given values automatically GDB:\n\ +\"$_\"holds the last address examined with \"x\" or \"info lines\",\n\ +\"$__\" holds the contents of the last address examined with \"x\"."); + + add_info ("history", history_info, + "Elements of value history (around item number IDX, or last ten)."); +} + +END_FILE diff --git a/gdb/vax-opcode.h b/gdb/vax-opcode.h new file mode 100644 index 00000000000..1ad14546424 --- /dev/null +++ b/gdb/vax-opcode.h @@ -0,0 +1,365 @@ +/* vax.opcode.h */ + +#ifndef vax_opcodeT +#define vax_opcodeT int +#endif /* no vax_opcodeT */ + +struct vot_wot /* vax opcode table: wot to do with this */ + /* particular opcode */ +{ + char * args; /* how to compile said opcode */ + vax_opcodeT code; /* op-code (may be > 8 bits!) */ +}; + +struct vot /* vax opcode text */ +{ + char * name; /* opcode name: lowercase string [key] */ + struct vot_wot detail; /* rest of opcode table [datum] */ +}; + +#define vot_how args +#define vot_code code +#define vot_detail detail +#define vot_name name + +static struct vot +votstrs[] = +{ +{ "halt", {"", 0x00 } }, +{ "nop", {"", 0x01 } }, +{ "rei", {"", 0x02 } }, +{ "bpt", {"", 0x03 } }, +{ "ret", {"", 0x04 } }, +{ "rsb", {"", 0x05 } }, +{ "ldpctx", {"", 0x06 } }, +{ "svpctx", {"", 0x07 } }, +{ "cvtps", {"rwabrwab", 0x08 } }, +{ "cvtsp", {"rwabrwab", 0x09 } }, +{ "index", {"rlrlrlrlrlwl", 0x0a } }, +{ "crc", {"abrlrwab", 0x0b } }, +{ "prober", {"rbrwab", 0x0c } }, +{ "probew", {"rbrwab", 0x0d } }, +{ "insque", {"abab", 0x0e } }, +{ "remque", {"abwl", 0x0f } }, +{ "bsbb", {"bb", 0x10 } }, +{ "brb", {"bb", 0x11 } }, +{ "bneq", {"bb", 0x12 } }, +{ "bnequ", {"bb", 0x12 } }, +{ "beql", {"bb", 0x13 } }, +{ "beqlu", {"bb", 0x13 } }, +{ "bgtr", {"bb", 0x14 } }, +{ "bleq", {"bb", 0x15 } }, +{ "jsb", {"ab", 0x16 } }, +{ "jmp", {"ab", 0x17 } }, +{ "bgeq", {"bb", 0x18 } }, +{ "blss", {"bb", 0x19 } }, +{ "bgtru", {"bb", 0x1a } }, +{ "blequ", {"bb", 0x1b } }, +{ "bvc", {"bb", 0x1c } }, +{ "bvs", {"bb", 0x1d } }, +{ "bcc", {"bb", 0x1e } }, +{ "bgequ", {"bb", 0x1e } }, +{ "blssu", {"bb", 0x1f } }, +{ "bcs", {"bb", 0x1f } }, +{ "addp4", {"rwabrwab", 0x20 } }, +{ "addp6", {"rwabrwabrwab", 0x21 } }, +{ "subp4", {"rwabrwab", 0x22 } }, +{ "subp6", {"rwabrwabrwab", 0x23 } }, +{ "cvtpt", {"rwababrwab", 0x24 } }, +{ "mulp", {"rwabrwabrwab", 0x25 } }, +{ "cvttp", {"rwababrwab", 0x26 } }, +{ "divp", {"rwabrwabrwab", 0x27 } }, +{ "movc3", {"rwabab", 0x28 } }, +{ "cmpc3", {"rwabab", 0x29 } }, +{ "scanc", {"rwababrb", 0x2a } }, +{ "spanc", {"rwababrb", 0x2b } }, +{ "movc5", {"rwabrbrwab", 0x2c } }, +{ "cmpc5", {"rwabrbrwab", 0x2d } }, +{ "movtc", {"rwabrbabrwab", 0x2e } }, +{ "movtuc", {"rwabrbabrwab", 0x2f } }, +{ "bsbw", {"bw", 0x30 } }, +{ "brw", {"bw", 0x31 } }, +{ "cvtwl", {"rwwl", 0x32 } }, +{ "cvtwb", {"rwwb", 0x33 } }, +{ "movp", {"rwabab", 0x34 } }, +{ "cmpp3", {"rwabab", 0x35 } }, +{ "cvtpl", {"rwabwl", 0x36 } }, +{ "cmpp4", {"rwabrwab", 0x37 } }, +{ "editpc", {"rwababab", 0x38 } }, +{ "matchc", {"rwabrwab", 0x39 } }, +{ "locc", {"rbrwab", 0x3a } }, +{ "skpc", {"rbrwab", 0x3b } }, +{ "movzwl", {"rwwl", 0x3c } }, +{ "acbw", {"rwrwmwbw", 0x3d } }, +{ "movaw", {"awwl", 0x3e } }, +{ "pushaw", {"aw", 0x3f } }, +{ "addf2", {"rfmf", 0x40 } }, +{ "addf3", {"rfrfwf", 0x41 } }, +{ "subf2", {"rfmf", 0x42 } }, +{ "subf3", {"rfrfwf", 0x43 } }, +{ "mulf2", {"rfmf", 0x44 } }, +{ "mulf3", {"rfrfwf", 0x45 } }, +{ "divf2", {"rfmf", 0x46 } }, +{ "divf3", {"rfrfwf", 0x47 } }, +{ "cvtfb", {"rfwb", 0x48 } }, +{ "cvtfw", {"rfww", 0x49 } }, +{ "cvtfl", {"rfwl", 0x4a } }, +{ "cvtrfl", {"rfwl", 0x4b } }, +{ "cvtbf", {"rbwf", 0x4c } }, +{ "cvtwf", {"rwwf", 0x4d } }, +{ "cvtlf", {"rlwf", 0x4e } }, +{ "acbf", {"rfrfmfbw", 0x4f } }, +{ "movf", {"rfwf", 0x50 } }, +{ "cmpf", {"rfrf", 0x51 } }, +{ "mnegf", {"rfwf", 0x52 } }, +{ "tstf", {"rf", 0x53 } }, +{ "emodf", {"rfrbrfwlwf", 0x54 } }, +{ "polyf", {"rfrwab", 0x55 } }, +{ "cvtfd", {"rfwd", 0x56 } }, + /* opcode 57 is not defined yet */ +{ "adawi", {"rwmw", 0x58 } }, + /* opcode 59 is not defined yet */ + /* opcode 5a is not defined yet */ + /* opcode 5b is not defined yet */ +{ "insqhi", {"abaq", 0x5c } }, +{ "insqti", {"abaq", 0x5d } }, +{ "remqhi", {"aqwl", 0x5e } }, +{ "remqti", {"aqwl", 0x5f } }, +{ "addd2", {"rdmd", 0x60 } }, +{ "addd3", {"rdrdwd", 0x61 } }, +{ "subd2", {"rdmd", 0x62 } }, +{ "subd3", {"rdrdwd", 0x63 } }, +{ "muld2", {"rdmd", 0x64 } }, +{ "muld3", {"rdrdwd", 0x65 } }, +{ "divd2", {"rdmd", 0x66 } }, +{ "divd3", {"rdrdwd", 0x67 } }, +{ "cvtdb", {"rdwb", 0x68 } }, +{ "cvtdw", {"rdww", 0x69 } }, +{ "cvtdl", {"rdwl", 0x6a } }, +{ "cvtrdl", {"rdwl", 0x6b } }, +{ "cvtbd", {"rbwd", 0x6c } }, +{ "cvtwd", {"rwwd", 0x6d } }, +{ "cvtld", {"rlwd", 0x6e } }, +{ "acbd", {"rdrdmdbw", 0x6f } }, +{ "movd", {"rdwd", 0x70 } }, +{ "cmpd", {"rdrd", 0x71 } }, +{ "mnegd", {"rdwd", 0x72 } }, +{ "tstd", {"rd", 0x73 } }, +{ "emodd", {"rdrbrdwlwd", 0x74 } }, +{ "polyd", {"rdrwab", 0x75 } }, +{ "cvtdf", {"rdwf", 0x76 } }, + /* opcode 77 is not defined yet */ +{ "ashl", {"rbrlwl", 0x78 } }, +{ "ashq", {"rbrqwq", 0x79 } }, +{ "emul", {"rlrlrlwq", 0x7a } }, +{ "ediv", {"rlrqwlwl", 0x7b } }, +{ "clrd", {"wd", 0x7c } }, +{ "clrq", {"wd", 0x7c } }, +{ "clrg", {"wg", 0x7c } }, +{ "movq", {"rqwq", 0x7d } }, +{ "movaq", {"aqwl", 0x7e } }, +{ "movad", {"adwl", 0x7e } }, +{ "pushaq", {"aq", 0x7f } }, +{ "pushad", {"ad", 0x7f } }, +{ "addb2", {"rbmb", 0x80 } }, +{ "addb3", {"rbrbwb", 0x81 } }, +{ "subb2", {"rbmb", 0x82 } }, +{ "subb3", {"rbrbwb", 0x83 } }, +{ "mulb2", {"rbmb", 0x84 } }, +{ "mulb3", {"rbrbwb", 0x85 } }, +{ "divb2", {"rbmb", 0x86 } }, +{ "divb3", {"rbrbwb", 0x87 } }, +{ "bisb2", {"rbmb", 0x88 } }, +{ "bisb3", {"rbrbwb", 0x89 } }, +{ "bicb2", {"rbmb", 0x8a } }, +{ "bicb3", {"rbrbwb", 0x8b } }, +{ "xorb2", {"rbmb", 0x8c } }, +{ "xorb3", {"rbrbwb", 0x8d } }, +{ "mnegb", {"rbwb", 0x8e } }, +{ "caseb", {"rbrbrb", 0x8f } }, +{ "movb", {"rbwb", 0x90 } }, +{ "cmpb", {"rbrb", 0x91 } }, +{ "mcomb", {"rbwb", 0x92 } }, +{ "bitb", {"rbrb", 0x93 } }, +{ "clrb", {"wb", 0x94 } }, +{ "tstb", {"rb", 0x95 } }, +{ "incb", {"mb", 0x96 } }, +{ "decb", {"mb", 0x97 } }, +{ "cvtbl", {"rbwl", 0x98 } }, +{ "cvtbw", {"rbww", 0x99 } }, +{ "movzbl", {"rbwl", 0x9a } }, +{ "movzbw", {"rbww", 0x9b } }, +{ "rotl", {"rbrlwl", 0x9c } }, +{ "acbb", {"rbrbmbbw", 0x9d } }, +{ "movab", {"abwl", 0x9e } }, +{ "pushab", {"ab", 0x9f } }, +{ "addw2", {"rwmw", 0xa0 } }, +{ "addw3", {"rwrwww", 0xa1 } }, +{ "subw2", {"rwmw", 0xa2 } }, +{ "subw3", {"rwrwww", 0xa3 } }, +{ "mulw2", {"rwmw", 0xa4 } }, +{ "mulw3", {"rwrwww", 0xa5 } }, +{ "divw2", {"rwmw", 0xa6 } }, +{ "divw3", {"rwrwww", 0xa7 } }, +{ "bisw2", {"rwmw", 0xa8 } }, +{ "bisw3", {"rwrwww", 0xa9 } }, +{ "bicw2", {"rwmw", 0xaa } }, +{ "bicw3", {"rwrwww", 0xab } }, +{ "xorw2", {"rwmw", 0xac } }, +{ "xorw3", {"rwrwww", 0xad } }, +{ "mnegw", {"rwww", 0xae } }, +{ "casew", {"rwrwrw", 0xaf } }, +{ "movw", {"rwww", 0xb0 } }, +{ "cmpw", {"rwrw", 0xb1 } }, +{ "mcomw", {"rwww", 0xb2 } }, +{ "bitw", {"rwrw", 0xb3 } }, +{ "clrw", {"ww", 0xb4 } }, +{ "tstw", {"rw", 0xb5 } }, +{ "incw", {"mw", 0xb6 } }, +{ "decw", {"mw", 0xb7 } }, +{ "bispsw", {"rw", 0xb8 } }, +{ "bicpsw", {"rw", 0xb9 } }, +{ "popr", {"rw", 0xba } }, +{ "pushr<", {"rw", 0xbb } }, +{ "chmk", {"rw", 0xbc } }, +{ "chme", {"rw", 0xbd } }, +{ "chms", {"rw", 0xbe } }, +{ "chmu", {"rw", 0xbf } }, +{ "addl2", {"rlml", 0xc0 } }, +{ "addl3", {"rlrlwl", 0xc1 } }, +{ "subl2", {"rlml", 0xc2 } }, +{ "subl3", {"rlrlwl", 0xc3 } }, +{ "mull2", {"rlml", 0xc4 } }, +{ "mull3", {"rlrlwl", 0xc5 } }, +{ "divl2", {"rlml", 0xc6 } }, +{ "divl3", {"rlrlwl", 0xc7 } }, +{ "bisl2", {"rlml", 0xc8 } }, +{ "bisl3", {"rlrlwl", 0xc9 } }, +{ "bicl2", {"rlml", 0xca } }, +{ "bicl3", {"rlrlwl", 0xcb } }, +{ "xorl2", {"rlml", 0xcc } }, +{ "xorl3", {"rlrlwl", 0xcd } }, +{ "mnegl", {"rlwl", 0xce } }, +{ "casel", {"rlrlrl", 0xcf } }, +{ "movl", {"rlwl", 0xd0 } }, +{ "cmpl", {"rlrl", 0xd1 } }, +{ "mcoml", {"rlwl", 0xd2 } }, +{ "bitl", {"rlrl", 0xd3 } }, +{ "clrf", {"wf", 0xd4 } }, +{ "clrl", {"wl", 0xd4 } }, +{ "tstl", {"rl", 0xd5 } }, +{ "incl", {"ml", 0xd6 } }, +{ "decl", {"ml", 0xd7 } }, +{ "adwc", {"rlml", 0xd8 } }, +{ "sbwc", {"rlml", 0xd9 } }, +{ "mtpr", {"rlrl", 0xda } }, +{ "mfpr", {"rlwl", 0xdb } }, +{ "movpsl", {"wl", 0xdc } }, +{ "pushl", {"rl", 0xdd } }, +{ "moval", {"alwl", 0xde } }, +{ "movaf", {"afwl", 0xde } }, +{ "pushal", {"al", 0xdf } }, +{ "pushaf", {"af", 0xdf } }, +{ "bbs", {"rlabbb", 0xe0 } }, +{ "bbc", {"rlabbb", 0xe1 } }, +{ "bbss", {"rlabbb", 0xe2 } }, +{ "bbcs", {"rlabbb", 0xe3 } }, +{ "bbsc", {"rlabbb", 0xe4 } }, +{ "bbcc", {"rlabbb", 0xe5 } }, +{ "bbssi", {"rlabbb", 0xe6 } }, +{ "bbcci", {"rlabbb", 0xe7 } }, +{ "blbs", {"rlbb", 0xe8 } }, +{ "blbc", {"rlbb", 0xe9 } }, +{ "ffs", {"rlrbvbwl", 0xea } }, +{ "ffc", {"rlrbvbwl", 0xeb } }, +{ "cmpv", {"rlrbvbrl", 0xec } }, +{ "cmpzv", {"rlrbvbrl", 0xed } }, +{ "extv", {"rlrbvbwl", 0xee } }, +{ "extzv", {"rlrbvbwl", 0xef } }, +{ "insv", {"rlrlrbvb", 0xf0 } }, +{ "acbl", {"rlrlmlbw", 0xf1 } }, +{ "aoblss", {"rlmlbb", 0xf2 } }, +{ "aobleq", {"rlmlbb", 0xf3 } }, +{ "sobgeq", {"mlbb", 0xf4 } }, +{ "sobgtr", {"mlbb", 0xf5 } }, +{ "cvtlb", {"rlwb", 0xf6 } }, +{ "cvtlw", {"rlww", 0xf7 } }, +{ "ashp", {"rbrwabrbrwab", 0xf8 } }, +{ "cvtlp", {"rlrwab", 0xf9 } }, +{ "callg", {"abab", 0xfa } }, +{ "calls", {"rlab", 0xfb } }, +{ "xfc", {"", 0xfc } }, + /* undefined opcodes here */ +{ "cvtdh", {"rdwh", 0x32fd } }, +{ "cvtgf", {"rgwh", 0x33fd } }, +{ "addg2", {"rgmg", 0x40fd } }, +{ "addg3", {"rgrgwg", 0x41fd } }, +{ "subg2", {"rgmg", 0x42fd } }, +{ "subg3", {"rgrgwg", 0x43fd } }, +{ "mulg2", {"rgmg", 0x44fd } }, +{ "mulg3", {"rgrgwg", 0x45fd } }, +{ "divg2", {"rgmg", 0x46fd } }, +{ "divg3", {"rgrgwg", 0x47fd } }, +{ "cvtgb", {"rgwb", 0x48fd } }, +{ "cvtgw", {"rgww", 0x49fd } }, +{ "cvtgl", {"rgwl", 0x4afd } }, +{ "cvtrgl", {"rgwl", 0x4bfd } }, +{ "cvtbg", {"rbwg", 0x4cfd } }, +{ "cvtwg", {"rwwg", 0x4dfd } }, +{ "cvtlg", {"rlwg", 0x4efd } }, +{ "acbg", {"rgrgmgbw", 0x4ffd } }, +{ "movg", {"rgwg", 0x50fd } }, +{ "cmpg", {"rgrg", 0x51fd } }, +{ "mnegg", {"rgwg", 0x52fd } }, +{ "tstg", {"rg", 0x53fd } }, +{ "emodg", {"rgrwrgwlwg", 0x54fd } }, +{ "polyg", {"rgrwab", 0x55fd } }, +{ "cvtgh", {"rgwh", 0x56fd } }, + /* undefined opcodes here */ +{ "addh2", {"rhmh", 0x60fd } }, +{ "addh3", {"rhrhwh", 0x61fd } }, +{ "subh2", {"rhmh", 0x62fd } }, +{ "subh3", {"rhrhwh", 0x63fd } }, +{ "mulh2", {"rhmh", 0x64fd } }, +{ "mulh3", {"rhrhwh", 0x65fd } }, +{ "divh2", {"rhmh", 0x66fd } }, +{ "divh3", {"rhrhwh", 0x67fd } }, +{ "cvthb", {"rhwb", 0x68fd } }, +{ "cvthw", {"rhww", 0x69fd } }, +{ "cvthl", {"rhwl", 0x6afd } }, +{ "cvtrhl", {"rhwl", 0x6bfd } }, +{ "cvtbh", {"rbwh", 0x6cfd } }, +{ "cvtwh", {"rwwh", 0x6dfd } }, +{ "cvtlh", {"rlwh", 0x6efd } }, +{ "acbh", {"rhrhmhbw", 0x6ffd } }, +{ "movh", {"rhwh", 0x70fd } }, +{ "cmph", {"rhrh", 0x71fd } }, +{ "mnegh", {"rhwh", 0x72fd } }, +{ "tsth", {"rh", 0x73fd } }, +{ "emodh", {"rhrwrhwlwh", 0x74fd } }, +{ "polyh", {"rhrwab", 0x75fd } }, +{ "cvthg", {"rhwg", 0x76fd } }, + /* undefined opcodes here */ +{ "clrh", {"wh", 0x7cfd } }, +{ "clro", {"wo", 0x7cfd } }, +{ "movo", {"rowo", 0x7dfd } }, +{ "movah", {"ahwl", 0x7efd } }, +{ "movao", {"aowl", 0x7efd } }, +{ "pushah", {"ah", 0x7ffd } }, +{ "pushao", {"ao", 0x7ffd } }, + /* undefined opcodes here */ +{ "cvtfh", {"rfwh", 0x98fd } }, +{ "cvtfg", {"rfwg", 0x99fd } }, + /* undefined opcodes here */ +{ "cvthf", {"rhwf", 0xf6fd } }, +{ "cvthd", {"rhwd", 0xf7fd } }, + /* undefined opcodes here */ +{ "bugl", {"rl", 0xfdff } }, +{ "bugw", {"rw", 0xfeff } }, + /* undefined opcodes here */ + +{ "" , "" } /* empty is end sentinel */ + +}; /* votstrs */ + +/* end: vax.opcode.h */ diff --git a/gdb/vax-pinsn.c b/gdb/vax-pinsn.c new file mode 100644 index 00000000000..9d9741555d5 --- /dev/null +++ b/gdb/vax-pinsn.c @@ -0,0 +1,241 @@ +/* Print vax instructions for GDB, the GNU debugger. + Copyright (C) 1986 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +#include + +#include "defs.h" +#include "param.h" +#include "symtab.h" +#include "vax-opcode.h" + +/* Vax instructions are never longer than this. */ +#define MAXLEN 62 + +/* Number of elements in the opcode table. */ +#define NOPCODES (sizeof votstrs / sizeof votstrs[0]) + +extern char *reg_names[]; + +static unsigned char *print_insn_arg (); + +/* Print the vax instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned char buffer[MAXLEN]; + register int i; + register unsigned char *p; + register char *d; + + read_memory (memaddr, buffer, MAXLEN); + + for (i = 0; i < NOPCODES; i++) + if (votstrs[i].detail.code == buffer[0] + || votstrs[i].detail.code == *(unsigned short *)buffer) + break; + + /* Handle undefined instructions. */ + if (i == NOPCODES) + { + fprintf (stream, "0%o", buffer[0]); + return 1; + } + + fprintf (stream, "%s", votstrs[i].name); + + /* Point at first byte of argument data, + and at descriptor for first argument. */ + p = buffer + 1 + (votstrs[i].detail.code >= 0x100); + d = votstrs[i].detail.args; + + if (*d) + fputc (' ', stream); + + while (*d) + { + p = print_insn_arg (d, p, memaddr + (p - buffer), stream); + d += 2; + if (*d) + fprintf (stream, ","); + } + return p - buffer; +} + +static unsigned char * +print_insn_arg (d, p, addr, stream) + char *d; + register char *p; + CORE_ADDR addr; + FILE *stream; +{ + register int regnum = *p & 0xf; + float floatlitbuf; + + if (*d == 'b') + { + if (d[1] == 'b') + fprintf (stream, "0x%x", addr + *p++ + 1); + else + { + fprintf (stream, "0x%x", addr + *(short *)p + 2); + p += 2; + } + } + else + switch ((*p++ >> 4) & 0xf) + { + case 0: + case 1: + case 2: + case 3: /* Literal mode */ + if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h') + { + *(int *)&floatlitbuf = 0x4000 + ((p[-1] & 0x3f) << 4); + fprintf (stream, "$%f", floatlitbuf); + } + else + fprintf (stream, "$%d", p[-1] & 0x3f); + break; + + case 4: /* Indexed */ + p = (char *) print_insn_arg (d, p, addr + 1, stream); + fprintf (stream, "[%s]", reg_names[regnum]); + break; + + case 5: /* Register */ + fprintf (stream, reg_names[regnum]); + break; + + case 7: /* Autodecrement */ + fputc ('-', stream); + case 6: /* Register deferred */ + fprintf (stream, "(%s)", reg_names[regnum]); + break; + + case 9: /* Autoincrement deferred */ + fputc ('@', stream); + if (regnum == PC_REGNUM) + { + fputc ('#', stream); + print_address (*(long *)p, stream); + p += 4; + break; + } + case 8: /* Autoincrement */ + if (regnum == PC_REGNUM) + { + fputc ('#', stream); + switch (d[1]) + { + case 'b': + fprintf (stream, "%d", *p++); + break; + + case 'w': + fprintf (stream, "%d", *(short *)p); + p += 2; + break; + + case 'l': + fprintf (stream, "%d", *(long *)p); + p += 4; + break; + + case 'q': + fprintf (stream, "0x%x%08x", ((long *)p)[1], ((long *)p)[0]); + p += 8; + break; + + case 'o': + fprintf (stream, "0x%x%08x%08x%08x", + ((long *)p)[3], ((long *)p)[2], + ((long *)p)[1], ((long *)p)[0]); + p += 16; + break; + + case 'f': + if (INVALID_FLOAT (p, 4)) + fprintf (stream, "<>", *(int *) p); + else + fprintf (stream, "%f", *(float *) p); + p += 4; + break; + + case 'd': + if (INVALID_FLOAT (p, 8)) + fprintf (stream, "<>", + ((long *)p)[1], ((long *)p)[0]); + else + fprintf (stream, "%f", *(double *) p); + p += 8; + break; + + case 'g': + fprintf (stream, "g-float"); + p += 8; + break; + + case 'h': + fprintf (stream, "h-float"); + p += 16; + break; + + } + } + else + fprintf (stream, "(%s)+", reg_names[regnum]); + break; + + case 11: /* Byte displacement deferred */ + fputc ('@', stream); + case 10: /* Byte displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *p + 2, stream); + else + fprintf (stream, "%d(%s)", *p, reg_names[regnum]); + p += 1; + break; + + case 13: /* Word displacement deferred */ + fputc ('@', stream); + case 12: /* Word displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *(short *)p + 3, stream); + else + fprintf (stream, "%d(%s)", *(short *)p, reg_names[regnum]); + p += 2; + break; + + case 15: /* Long displacement deferred */ + fputc ('@', stream); + case 14: /* Long displacement */ + if (regnum == PC_REGNUM) + print_address (addr + *(long *)p + 5, stream); + else + fprintf (stream, "%d(%s)", *(long *)p, reg_names[regnum]); + p += 4; + } + + return (unsigned char *) p; +} diff --git a/gdb/version.c b/gdb/version.c new file mode 100644 index 00000000000..452ccd82067 --- /dev/null +++ b/gdb/version.c @@ -0,0 +1,3 @@ +/* Define the current version number of GDB. */ + +char *version = "2.4+"; diff --git a/gdb/wait.h b/gdb/wait.h new file mode 100644 index 00000000000..fe7f384501d --- /dev/null +++ b/gdb/wait.h @@ -0,0 +1,25 @@ + +/* Define how to access the structure that the wait system call stores. + On many systems, there is a structure defined for this. + But on vanilla-ish USG systems there is not. */ + +#ifndef HAVE_WAIT_STRUCT +#define WAITTYPE int +#define WIFSTOPPED(w) (((w)&0377) == 0177) +#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) +#define WIFEXITED(w) (((w)&0377) == 0) +#define WRETCODE(w) ((w) >> 8) +#define WSTOPSIG(w) ((w) >> 8) +#define WCOREDUMP(w) (((w)&0200) != 0) +#define WTERMSIG(w) ((w) & 0177) +#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8))) +#else +#include +#define WAITTYPE union wait +#define WRETCODE(w) (w).w_retcode +#define WSTOPSIG(w) (w).w_stopsig +#define WCOREDUMP(w) (w).w_coredump +#define WTERMSIG(w) (w).w_termsig +#define WSETSTOP(w,sig) \ + ((w).stopsig = (sig), (w).coredump = 0, (w).termsig = 0177) +#endif diff --git a/gdb/xgdb.c b/gdb/xgdb.c new file mode 100644 index 00000000000..1b858e87b4e --- /dev/null +++ b/gdb/xgdb.c @@ -0,0 +1,672 @@ +/* Interface from GDB to X windows. + Copyright (C) 1987 Free Software Foundation, Inc. + +GDB is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY. No author or distributor accepts responsibility to anyone +for the consequences of using it or for whether it serves any +particular purpose or works at all, unless he says so in writing. +Refer to the GDB General Public License for full details. + +Everyone is granted permission to copy, modify and redistribute GDB, +but only under the conditions described in the GDB General Public +License. A copy of this license is supposed to have been given to you +along with GDB so you can know your rights and responsibilities. It +should be in a file named COPYING. Among other things, the copyright +notice and this notice must be preserved on all copies. + +In other words, go ahead and share GDB, but don't try to stop +anyone else from sharing it farther. Help stamp out software hoarding! +*/ + +/* Original version was contributed by Derek Beatty, 30 June 87. */ + +#include "defs.h" +#include "initialize.h" +#include "param.h" +#include "symtab.h" +#include "frame.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Cursor used in GDB window. */ + +#define gdb_width 16 +#define gdb_height 16 +#define gdb_x_hot 7 +#define gdb_y_hot 0 +static short gdb_bits[] = { + 0x0000, 0x0140, 0x0220, 0x0220, + 0x23e2, 0x13e4, 0x09c8, 0x0ff8, + 0x0220, 0x3ffe, 0x0630, 0x03e0, + 0x0220, 0x1ffc, 0x2632, 0x01c0}; + +#define gdb_mask_width 16 +#define gdb_mask_height 16 +#define gdb_mask_x_hot 7 +#define gdb_mask_y_hot 0 +static short gdb_mask_bits[] = { + 0x0360, 0x07f0, 0x07f0, 0x77f7, + 0x7fff, 0x7fff, 0x1ffc, 0x1ffc, + 0x7fff, 0x7fff, 0x7fff, 0x0ff8, + 0x3ffe, 0x7fff, 0x7fff, 0x7fff}; + +/* The X display on which the window appears. */ + +Display *screen_display; + +/* The graphics context. */ + +GC default_gc; + +/* Windows manipulated by this package. */ + +static Window icon_window; +static Widget containing_widget; +static Widget source_name_widget; +static Widget source_text_widget; +static Widget exec_name_widget; +static Widget button_box_widget; + +/* Source text display. */ + +static struct symtab *source_window_symtab = 0; + +/* Forward declarations */ + +static Widget create_text_widget (); + +START_FILE + +/* Display an appropriate piece of source code in the source window. */ + +xgdb_display_source () +{ + char *filename; + static Arg labelArgs[1]; + int linenumbers_changed = 0; + static int new = 1; + + struct symtab_and_line get_selected_frame_sal (); + struct symtab_and_line sal; + struct frame_info fi; + + /* Do nothing if called before we are initialized */ + + if (!containing_widget) return; + + /* Get the symtab and line number of the selected frame. */ + + fi = get_frame_info (selected_frame); + sal = find_pc_line (fi.pc, fi.next_frame); + + /* Strictly this is wrong, but better than a blank display */ + + if (sal.symtab == NULL) + { + sal.symtab = current_source_symtab; + /* current_source_line may be off by a small number like 4 */ + sal.line = current_source_line; + } + + /* Do a path search and get the exact filename of this source file. + Also scan it and find its source lines if not already done. */ + + if (sal.symtab) + linenumbers_changed = get_filename_and_charpos (sal.symtab, sal.line, + &filename); + + if (!filename) sal.symtab = NULL; + + /* If the source window may be wrong, destroy it (and make a new one). */ + + if (linenumbers_changed || source_window_symtab != sal.symtab) + { + static Arg fileArgs[1]; + new = 1; + source_window_symtab = sal.symtab; + + XtSetArg (fileArgs[0], XtNfile, filename); + XtSetValues (source_text_widget, fileArgs, XtNumber (fileArgs)); + + XtSetArg (labelArgs[0], XtNlabel, + filename ? filename : "No source displayed."); + XtSetValues (source_name_widget, labelArgs, XtNumber (labelArgs)); + if (filename) free (filename); + } + + /* Update display and cursor positions as necessary. + Cursor should be placed on line sal.line. */ + + { + static int top_line_number, bottom_line_number; + int current_top; + Arg textArgs[1]; + + if (! new) + { + int new_top; + + /* Get positions of start of display, and caret */ + XtSetArg (textArgs[0], XtNdisplayPosition, NULL); + XtGetValues (source_text_widget, textArgs, XtNumber (textArgs)); + new_top = source_charpos_line (source_window_symtab, + (int) textArgs[0].value); + bottom_line_number += new_top - top_line_number; + top_line_number = new_top; + } + + /* If appropriate, scroll the text display. */ + if (sal.line < top_line_number + || sal.line > bottom_line_number + || new) + { + /* yes, these magic numbers are ugly, but I don't know how + * to get the height of a text widget in a V11-portable way + */ + top_line_number = (sal.line > 15) ? sal.line - 15 : 0; + bottom_line_number = top_line_number + 35; + + XtSetArg (textArgs[0], XtNdisplayPosition, + source_line_charpos (source_window_symtab, top_line_number)); + XtSetValues (source_text_widget, textArgs, XtNumber (textArgs)); + } + + /* Set the text display cursor position within the text. */ + + XtSetArg (textArgs[0], XtNinsertPosition, + source_line_charpos (source_window_symtab, sal.line)); + XtSetValues (source_text_widget, textArgs, XtNumber (textArgs)); + } +} + +/* Display FILENAME in the title bar at bottom of window. */ + +xgdb_display_exec_file (filename) + char *filename; +{ + static Arg labelArgs[1]; + + XtSetArg (labelArgs[0], XtNlabel, filename); + XtSetValues (exec_name_widget, labelArgs, XtNumber (labelArgs)); +} + +/* Do any necessary prompting, etc. */ + +static char *prompt_string; + +static void +print_prompt () +{ + if (prompt_string) + printf ("%s", prompt_string); +} + +/* Handlers for buttons. */ + +/* Subroutine used by "print" and "print*" buttons. + STARFLAG is 1 for print*, 0 for print. + Get the "selection" from X and use it as the operand of a print command. */ + +static void +print_1 (starflag) + int starflag; +{ + int selected_length; + char *selected_text; + + char *cmd = starflag ? "print * " : "print "; + register int cmdlen = strlen (cmd); + + selected_text = XFetchBytes (&selected_length); + if (selected_length) + { + char *line = xmalloc (cmdlen + selected_length + 1); + strcpy (line, cmd); + strncpy (line + cmdlen, selected_text, selected_length); + line[cmdlen + selected_length] = 0; + + execute_command (line, 0); + + free (selected_text); + free (line); + } + + print_prompt (); +} + +static void +print_button () +{ + print_1 (0); +} + +static void +print_star_button () +{ + print_1 (1); +} + +/* Subroutine used by "stop at" and "go till" buttons. + Set a breakpoint at the position indicated by the "selection" + in the source window, and, if RUNFLAG is nonzero, continue. */ + +static void +breakpoint_button_1 (runflag) + int runflag; +{ + XtTextPosition start, finish; + + XtTextGetSelectionPos (screen_display, source_text_widget, &start, &finish); + if (!source_window_symtab) + printf ("No source file displayed.\n"); + else + { + set_breakpoint (source_window_symtab, + source_charpos_line (source_window_symtab, start), + runflag); + if (runflag) + { + cont_command (0, 1); + xgdb_display_source (); + } + } + print_prompt (); +} + +static void +breakpoint_button () +{ + breakpoint_button_1 (0); +} + +static void +until_button () +{ + breakpoint_button_1 (1); +} + +/* decide if a character is trash */ +static int +garbage (c) + char c; +{ + if ('a' <= c && c <= 'z') return 0; + if ('A' <= c && c <= 'Z') return 0; + if ('0' <= c && c <= '9') return 0; + if (c == '_') return 0; + return 1; +} + +/* Set a breakpoint at the place specified by the "selection" in X. */ + +static void +explicit_breakpoint_button () +{ + int selected_length; + char *selected_text; + + selected_text = XFetchBytes (screen_display, &selected_length); + if (selected_length) + { + char *line = (char *) xmalloc (selected_length + 6); + register char *p, *sp, *end; + + strcpy (line, "break "); + + /* Copy selection but exclude "garbage" characters. */ + + p = selected_text; + end = p + selected_length; + sp = line + strlen (line); + + while (garbage (*p) && p != end) p++; + while (!garbage (*p) && p != end) + *sp++ = *p++; + *sp = 0; + + execute_command (line, 0); + free (selected_text); + free (line); + } + print_prompt (); +} + +/* Various trivial buttons, + most of which just run one GDB command with no arg. */ + +static void +next_button () +{ + execute_command ("next", 0); + xgdb_display_source (); + print_prompt (); +} + +static void +step_button () +{ + execute_command ("step", 0); + xgdb_display_source (); + print_prompt (); +} + +static void +cont_button () +{ + execute_command ("cont", 0); + xgdb_display_source (); + print_prompt (); +} + +static void +finish_button () +{ + execute_command ("finish", 0); + xgdb_display_source (); + print_prompt (); +} + +#if 0 +static void +deiconify_button () +{ + XUnmapWindow (screen_display, icon_window); + XMapWindow (screen_display, containing_widget); +} + +static void +iconify_button () +{ +#if 0 + static Arg iconArgs[1]; + XtSetArg (iconArgs[0], XtNlabel, prompt_string); + XtCommandSetValues (icon_window, iconArgs, XtNumber (iconArgs)); +#endif 0 + XUnmapWindow (screen_display, containing_widget); + XMapWindow (screen_display, icon_window); +} +#endif 0 + +static void +up_button () +{ + execute_command ("up", 0); + xgdb_display_source (); + print_prompt (); +} + +static void +down_button () +{ + execute_command ("down", 0); + xgdb_display_source (); + print_prompt (); +} + +/* Define and display all the buttons. */ + +static void +addbutton (parent, name, function) + Widget parent; + char *name; + void (*function) (); +{ + static Arg commandArgs[2]; + + XtSetArg (commandArgs[0], XtNlabel, name); + XtSetArg (commandArgs[1], XtNfunction, function); + XtCreateWidget (name, commandWidgetClass, parent, + commandArgs, XtNumber (commandArgs)); +} + +/* Create the button windows and store them in `buttons'. */ + +static void +create_buttons (parent) + Widget parent; +{ + addbutton (parent, "Brk At", breakpoint_button); + addbutton (parent, "Brk In", explicit_breakpoint_button); + addbutton (parent, "Go 'til", until_button); + + addbutton (parent, "Print", print_button); + addbutton (parent, "Print*", print_star_button); + + addbutton (parent, "Next", next_button); + addbutton (parent, "Step", step_button); + addbutton (parent, "Cont", cont_button); + addbutton (parent, "Finish", finish_button); + + addbutton (parent, "Up", up_button); + addbutton (parent, "Down", down_button); + +/* addbutton (parent, "Iconify", iconify_button); */ +} + +/* Create a "label window" that just displays the string LABEL. */ + +static Widget +create_label (name, label) + char *name, *label; +{ + static Arg labelArgs[2]; + + XtSetArg (labelArgs[0], XtNname, name); + XtSetArg (labelArgs[1], XtNlabel, label); + return XtCreateWidget ("label1", labelWidgetClass, containing_widget, + labelArgs, XtNumber (labelArgs)); +} + +/* Create a subwindow of PARENT that displays and scrolls the contents + of file FILENAME. */ + +static Widget +create_text_widget (parent, filename) + Window parent; + char *filename; +{ + static Arg fileArgs[2]; + + XtSetArg (fileArgs[0], XtNfile, filename); + XtSetArg (fileArgs[1], XtNtextOptions, scrollVertical); + return XtTextDiskCreate (parent, fileArgs, XtNumber (fileArgs)); +} + +/* Entry point to create the widgets representing our display. */ + +int +xgdb_create_window () +{ + static Arg frameArgs[]= { + {XtNwidth, (XtArgVal) 600}, + {XtNheight, (XtArgVal) 700}, + }; + + XrmResourceDataBase db; + FILE *rdb_file; + XGCValues dummy; + + /* Init and database stuff. */ + screen_display = XOpenDisplay (NULL); + if (screen_display == 0) + { + fprintf (stderr, "Cannot connect to X server"); + return 0; + } + + { + char *dummy1[1]; + dummy1[0] = 0; + XtInitialize ("gdb", "gdb", 0, 0, 0, dummy1); + } + + /* should be checking .Xdefaults in $HOME */ + rdb_file = fopen (".Xresources", "r"); + if (rdb_file != NULL) + { + XrmGetDataBase (rdb_file, &db); + XrmSetCurrentDataBase (db); + fclose (rdb_file); + } + + /* Create the containing_widget. */ + + containing_widget = XtCreateWidget ("frame", vPaneWidgetClass, 0, + frameArgs, XtNumber (frameArgs)); + + default_gc = XCreateGC (screen_display, containing_widget, 0, dummy); + + /* Create source file name window and add to containing_widget */ + source_name_widget + = create_label ("Source File", "No source file yet."); + + /* Create an empty source-display window and add to containing_widget */ + source_text_widget = create_text_widget (containing_widget, "/dev/null"); + + /* Create window full of buttons. */ + button_box_widget = XtCreateWidget ("Buttons", buttonBoxWidgetClass, + containing_widget, NULL, 0); + create_buttons (button_box_widget); + + /* Create exec file name window and add */ + exec_name_widget = create_label ("Executable", "No executable specified."); + +#if 0 + /* Create icon window. */ + { + static Arg iconArgs[2]; + void (*compiler_bug) () = deiconify_button; + XtSetArg (iconArgs[0], XtNlabel, "(gdb)"); + XtSetArg (iconArgs[1], XtNfunction, compiler_bug); + icon_window = XtCommandCreate (DefaultRootWindow (screen_display), + iconArgs, XtNumber (iconArgs)); + XMoveWindow (screen_display, icon_window, 100, 100); /* HACK */ +#if 0 + XSetIconWindow (screen_display, containing_widget, icon_window); +#endif 0 + } +#endif 0 + +#if 0 + /* Now make the whole thing appear on the display. */ + { + Pixmap pm1, pm2; + XImage image; + Cursor curse; + + image.width = gdb_width; + image.height = gdb_height; + image.xoffset = 0; + image.format = XYBitmap; + image.byte_order = LSBFirst; + image.bitmap_unit = 16; + image.bitmap_bit_order = LSBFirst; + image.depth = 1; + image.bytes_per_line = 2; + image.bits_per_pixel = 1; + + pm1 = XCreatePixmap (screen_display, DefaultScreen (screen_display), + gdb_width, gdb_height, 1); + pm2 = XCreatePixmap (screen_display, DefaultScreen (screen_display), + gdb_width, gdb_height, 1); + + image.data = (char *) gdb_bits; + XPutImage (screen_display, pm1, default_gc, &image, 0, 0, 0, 0, + gdb_width, gdb_height); + + image.data = (char *) gdb_mask_bits; + XPutImage (screen_display, pm2, default_gc, &image, 0, 0, 0, 0, + gdb_width, gdb_height); + + curse = XCreatePixmapCursor (screen_display, pm1, pm2, + BlackPixel (screen_display, + DefaultScreen (screen_display)), + WhitePixel (screen_display, + DefaultScreen (screen_display)), + gdb_x_hot, gdb_y_hot); + + XFreePixmap (screen_display, pm1); + XFreePixmap (screen_display, pm2); + + XDefineCursor (screen_display, containing_widget, curse); + XDefineCursor (screen_display, icon_window, curse); + } +#endif 0 + + XtRealizeWidget (containing_widget); + XFlush (screen_display); + + return 1; +} + +/* xgdb_dispatch -- Loop, dispatching on window events, + until data is available on FP (which is normally stdin). + Then return, so the data on FP can be processed. */ + +void +xgdb_dispatch (fp) + FILE *fp; +{ + int inmask = 1 << fileno (fp); + int xmask = 1 << ConnectionNumber (screen_display); + int rfds = 0; + int nfds; + XEvent ev; + int pend; + + while (! (rfds & inmask)) + { + pend = XPending (); + if (!pend) + { + rfds = inmask | xmask; + /* this isn't right for 4.3 but it works 'cuz of 4.2 compatibility */ + nfds = select (32, &rfds, 0, 0, (struct timeval *) 0); + } + if (pend || rfds & xmask) + { + XNextEvent (screen_display, &ev); + XtDispatchEvent (&ev); + } + } +} + +/* If we use an X window, the GDB command loop is told to call this function + before reading a command from stdin. + PROMPT is saved for later use so buttons can print a prompt-string. */ + +void +xgdb_window_hook (infile, prompt) + FILE *infile; + char *prompt; +{ + prompt_string = prompt; + xgdb_display_source (); + xgdb_dispatch (infile); +} + +static +initialize () +{ + extern void (*window_hook) (); + extern int inhibit_windows; + + if (getenv ("DISPLAY") && ! inhibit_windows) + if (xgdb_create_window ()) + window_hook = xgdb_window_hook; + + specify_exec_file_hook (xgdb_display_exec_file); +} + +END_FILE