gdb-2.4+.aux.coff
This commit is contained in:
commit
7b4ac7e1ed
|
@ -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);
|
||||
}
|
||||
|
|
@ -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 <stdio.h>
|
||||
#include "defs.h"
|
||||
#include "initialize.h"
|
||||
#include "symtab.h"
|
||||
#include "value.h"
|
||||
|
||||
|
||||
--- 21,27 -----
|
||||
#include <stdio.h>
|
||||
#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
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <AA00274> 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 </cmu/common/mailqs/q004/QF.mooncrest.20b9cce3.d0134>;
|
||||
Tue, 26 May 87 13:12:08 edt
|
||||
Received: FROM mooncrest VIA qmail
|
||||
ID </cmu/itc/kazar/.Outgoing/QF.mooncrest.20b9ccb0.1b570>;
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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-
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <AA00199> 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 </cmu/common/mailqs/q004/QF.z.itc.cmu.edu.20b7fa53.6bb39>;
|
||||
Mon, 25 May 87 04:01:27 edt
|
||||
Received: FROM z.itc.cmu.edu VIA qmail
|
||||
ID </cmu/itc/zs01/.Outgoing/QF.z.itc.cmu.edu.20b7fa49.a49502>;
|
||||
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
|
||||
|
||||
|
|
@ -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 <beatty@unh.cs.cmu.edu>
|
||||
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 <beatty@unh.cs.cmu.edu>
|
||||
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 <X/Xlib.h>
|
||||
#include <X/Xt/Xtlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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 <beatty@unh.cs.cmu.edu>
|
||||
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.
|
||||
|
|
@ -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.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,85 @@
|
|||
# -I. for "#include <obstack.h>"
|
||||
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
|
|
@ -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 <obstack.h>"
|
||||
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
|
||||
@
|
|
@ -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 <a.out.h>
|
||||
#include <stdio.h>
|
||||
#include <obstack.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
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
|
|
@ -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 <a.out.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_CORE
|
||||
#include <sys/core.h>
|
||||
#else /* not NEW_SUN_CORE */
|
||||
#ifdef UMAX_CORE
|
||||
#include <sys/ptrace.h>
|
||||
#else /* not UMAX_CORE */
|
||||
#ifdef mac_aux
|
||||
#include <sys/seg.h>
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/user.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#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
|
||||
@
|
|
@ -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 <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef mac_aux
|
||||
/* Warning! This table is positional and highly dependent on the local
|
||||
system. Check it closely against <sys/signal.h> 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
|
||||
@
|
|
@ -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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sgtty.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef mac_aux
|
||||
#include <sys/seg.h>
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/user.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#endif /* mac_aux */
|
||||
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_PTRACE
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#endif
|
||||
|
||||
#ifdef SYSV_TTYS
|
||||
#include <termio.h>
|
||||
#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 <sys/user.h>
|
||||
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
|
||||
@
|
|
@ -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
|
||||
@
|
|
@ -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
|
||||
@
|
|
@ -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 <stdio.h>
|
||||
|
||||
#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, "<invalid address mode 0%o>", 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");
|
||||
@
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <sys/types.h>
|
||||
@
|
||||
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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#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
|
||||
@
|
|
@ -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 <stdio.h>
|
||||
#include <obstack.h>
|
||||
|
||||
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);
|
||||
@
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#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
|
||||
@
|
|
@ -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.
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
main() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i >= 0; i++)
|
||||
bar();
|
||||
}
|
||||
|
||||
bar()
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 10;
|
||||
}
|
|
@ -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)
|
|
@ -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
|
|
@ -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,
|
||||
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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 ();
|
|
@ -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 <a.out.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* Recognize COFF format systems because a.out.h defines AOUTHDR. */
|
||||
#ifdef AOUTHDR
|
||||
#define COFF_FORMAT
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_CORE
|
||||
#include <sys/core.h>
|
||||
#else /* not NEW_SUN_CORE */
|
||||
#ifdef UMAX_CORE
|
||||
#include <sys/ptrace.h>
|
||||
#else /* not UMAX_CORE */
|
||||
#ifdef mac_aux
|
||||
#include <sys/seg.h>
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/user.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 ();
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 ();
|
|
@ -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
|
|
@ -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 <stdio.h>
|
||||
|
||||
/* 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, ")");
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 ();
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,13 @@
|
|||
main() {
|
||||
int i;
|
||||
|
||||
for (i = 0; i >= 0; i++)
|
||||
bar();
|
||||
}
|
||||
|
||||
bar()
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 10;
|
||||
}
|
|
@ -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| | | |
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
@ -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 ();
|
|
@ -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.
|
||||
|
|
@ -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: <rms@LMI-ANGEL>
|
||||
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 <stdio.h>
|
||||
#include <a.out.h>
|
||||
|
||||
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 <file:line>+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: <tiemann@big-d.aca.mcc.com>
|
||||
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: <tiemann@big-d.aca.mcc.com>
|
||||
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 <io!marvin!md%ileaf.uucp%umb.umb.edu@relay.cs.net>
|
||||
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 <io!marvin!md%ileaf.uucp%umb.umb.edu@relay.cs.net>
|
||||
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 <ram%typo.umb.edu@RELAY.CS.NET>
|
||||
To: bug-gdb@PREP.AI.MIT.EDU
|
||||
Subject: convenient script
|
||||
|
||||
*** EOOH ***
|
||||
Date: Sun, 6 Sep 87 12:10:34 EDT
|
||||
From: Robert Morris <ram%typo.umb.edu@RELAY.CS.NET>
|
||||
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 <signal.h>
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -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 <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef mac_aux
|
||||
/* Warning! This table is positional and highly dependent on the local
|
||||
system. Check it closely against <sys/signal.h> 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
|
|
@ -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;
|
|
@ -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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sgtty.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef mac_aux
|
||||
#include <sys/seg.h>
|
||||
#include <sys/mmu.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/user.h>
|
||||
#else
|
||||
#include <sys/user.h>
|
||||
#endif /* mac_aux */
|
||||
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
#include <a.out.h>
|
||||
#endif
|
||||
|
||||
#ifdef NEW_SUN_PTRACE
|
||||
#include <sys/ptrace.h>
|
||||
#include <machine/reg.h>
|
||||
#endif
|
||||
|
||||
#ifdef SYSV_TTYS
|
||||
#include <termio.h>
|
||||
#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
|
|
@ -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 <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <a.out.h>
|
||||
|
||||
#ifdef UMAX_PTRACE
|
||||
#include <sys/param.h>
|
||||
#include <sys/ptrace.h>
|
||||
#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
|
|
@ -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); }
|
|
@ -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);
|
||||
}
|
|
@ -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 ()
|
||||
{
|
||||
}
|
|
@ -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. "<function + offset>", 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 #<f0-f7>,-(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"); }
|
|
@ -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"); }
|
|
@ -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)
|
|
@ -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 <machine/reg.h>
|
||||
|
||||
/* 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
|
|
@ -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 #<f0-f7>,-(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
|
||||
|
|
@ -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)
|
|
@ -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"); }
|
|
@ -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"); }
|
|
@ -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)
|
|
@ -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 <nan.h>
|
||||
#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; \
|
||||
}
|
|
@ -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"); }
|
|
@ -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)
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <stdio.h>
|
||||
|
||||
#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, "<invalid address mode 0%o>", 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
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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 <stdio.h>
|
||||
|
||||
#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 */
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
../gcc/gcc-1.22/obstack.c
|
|
@ -0,0 +1 @@
|
|||
../gcc/gcc-1.19/obstack.h
|
|
@ -0,0 +1 @@
|
|||
#include "m-mac-aux.h"
|
|
@ -0,0 +1 @@
|
|||
#include "m68k-pinsn.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 <stdio.h>
|
||||
#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
|
||||
<SYMBOL + OFFSET> 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
|
|
@ -0,0 +1,44 @@
|
|||
Date: Tue, 6 Oct 87 08:52:07 PDT
|
||||
To: bug-gnu-emacs@prep.ai.mit.edu
|
||||
From: Lynn Slater <silvlis!wobegon!lrs@sun.com>
|
||||
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,
|
||||
<link>
|
||||
|
||||
(Resume from the Chorus)
|
||||
|
||||
|
||||
:-) Joel Bion, Mark Baushke, and Lynn Slater :-)
|
||||
|
|
@ -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 <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#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
|
|
@ -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 <stdio.h>
|
||||
|
||||
#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
|
|
@ -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 <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined (SIGTSTP) && defined (SIGIO)
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#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
|
|
@ -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 <stdio.h>
|
||||
#include <a.out.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <stdio.h>
|
||||
#include <obstack.h>
|
||||
|
||||
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
|
|
@ -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;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -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 ();
|
|
@ -0,0 +1,13 @@
|
|||
#include <sys/param.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/user.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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));
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
main ()
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
sleep (1);
|
||||
x++;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
struct foo
|
||||
{
|
||||
unsigned bar : 1;
|
||||
unsigned lose : 1;
|
||||
};
|
||||
|
||||
main ()
|
||||
{
|
||||
struct foo *win;
|
||||
|
||||
printf ("%d, %d\n", win->bar, win->lose);
|
||||
}
|
|
@ -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. */
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
|
||||
main ()
|
||||
{
|
||||
foo(2);
|
||||
foo(3);
|
||||
}
|
||||
|
||||
foo (i)
|
||||
{
|
||||
printf ("i is %d, ", i);
|
||||
printf ("i*i is %d\n", i * i);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue