gdb-2.4+.aux.coff

This commit is contained in:
gdb-2.4+.aux.coff
1988-01-16 04:39:57 +00:00
committed by Pedro Alves
commit 7b4ac7e1ed
118 changed files with 48217 additions and 0 deletions
+108
View File
@@ -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);
}
+136
View File
@@ -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
+1182
View File
File diff suppressed because it is too large Load Diff
+103
View File
@@ -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

+147
View File
@@ -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-
+3338
View File
File diff suppressed because it is too large Load Diff
+84
View File
@@ -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

+997
View File
@@ -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.
+138
View File
@@ -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.
+1025
View File
File diff suppressed because it is too large Load Diff
+85
View File
@@ -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
+160
View File
@@ -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
@
+304
View File
@@ -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
+763
View File
@@ -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 *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
*(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
bcopy (corestr.c_fpstatus.fps_regs,
&registers[REGISTER_BYTE (FP0_REGNUM)],
sizeof corestr.c_fpstatus.fps_regs);
bcopy (&corestr.c_fpstatus.fps_control,
&registers[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
@
+966
View File
@@ -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
@
+731
View File
@@ -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, &ltc_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, &ltc_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, &ltc_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 *)&ltc_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, &registers[REGISTER_BYTE (FP0_REGNUM)],
sizeof inferior_fp_registers.fps_regs);
*(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
*(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
bcopy (&inferior_fp_registers.fps_control,
&registers[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 (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
sizeof inferior_fp_registers.fps_regs);
inferior_registers.r_ps = *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
inferior_registers.r_pc = *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
bcopy (&registers[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, &ltc_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
@
+523
View File
@@ -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
@
+43
View File
@@ -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
@
+828
View File
@@ -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");
@
+1110
View File
File diff suppressed because it is too large Load Diff
+705
View File
@@ -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
@
+575
View File
@@ -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);
@
+1153
View File
File diff suppressed because it is too large Load Diff
+461
View File
@@ -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
@
+29
View File
@@ -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.
+852
View File
@@ -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
+191
View File
@@ -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));
}
}
+13
View File
@@ -0,0 +1,13 @@
main() {
int i;
for (i = 0; i >= 0; i++)
bar();
}
bar()
{
int i;
i = 10;
}
+65
View File
@@ -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)
+93
View File
@@ -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
+51
View File
@@ -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,
+333
View File
@@ -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
+1096
View File
File diff suppressed because it is too large Load Diff
+1860
View File
File diff suppressed because it is too large Load Diff
+454
View File
@@ -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;
}
+154
View File
@@ -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 ();
+717
View File
@@ -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 *)&registers[REGISTER_BYTE (PS_REGNUM)] = corestr.c_regs.r_ps;
*(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = corestr.c_regs.r_pc;
bcopy (corestr.c_fpstatus.fps_regs,
&registers[REGISTER_BYTE (FP0_REGNUM)],
sizeof corestr.c_fpstatus.fps_regs);
bcopy (&corestr.c_fpstatus.fps_control,
&registers[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
+2183
View File
File diff suppressed because it is too large Load Diff
+75
View File
@@ -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 ();
+250
View File
@@ -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;
}
}
+23
View File
@@ -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 ();
+556
View File
@@ -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
+304
View 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, ")");
}
+1189
View File
File diff suppressed because it is too large Load Diff
+167
View File
@@ -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 ();
+409
View File
@@ -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 (&registers[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, &registers[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 *) &registers[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 *) &registers[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, &registers[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
+154
View 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
+13
View File
@@ -0,0 +1,13 @@
main() {
int i;
for (i = 0; i >= 0; i++)
bar();
}
bar()
{
int i;
i = 10;
}
+39
View File
@@ -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| | | |
+213
View File
@@ -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
+65
View File
@@ -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
+114
View File
@@ -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)
+64
View File
@@ -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 ();
+91
View File
@@ -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.
+694
View File
@@ -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.

+927
View File
@@ -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
+85
View 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;
+661
View File
@@ -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, &ltc_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, &ltc_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, &ltc_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 *)&ltc_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, &registers[REGISTER_BYTE (FP0_REGNUM)],
sizeof inferior_fp_registers.fps_regs);
*(int *)&registers[REGISTER_BYTE (PS_REGNUM)] = inferior_registers.r_ps;
*(int *)&registers[REGISTER_BYTE (PC_REGNUM)] = inferior_registers.r_pc;
bcopy (&inferior_fp_registers.fps_control,
&registers[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 (&registers[REGISTER_BYTE (FP0_REGNUM)], &inferior_fp_registers,
sizeof inferior_fp_registers.fps_regs);
inferior_registers.r_ps = *(int *)&registers[REGISTER_BYTE (PS_REGNUM)];
inferior_registers.r_pc = *(int *)&registers[REGISTER_BYTE (PC_REGNUM)];
bcopy (&registers[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, &ltc_ours);
ioctl (0, TIOCLGET, &lmode_ours);
#endif
fcntl (0, F_GETFL, tflags_ours);
ioctl (0, TIOCGPGRP, &pgrp_ours);
terminal_is_ours = 1;
}
END_FILE
+943
View 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
+126
View 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); }
+21
View File
@@ -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);
}
+6
View File
@@ -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 ()
{
}
+524
View 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"); }
+485
View File
@@ -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"); }
+5
View File
@@ -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)
+437
View File
@@ -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
+566
View File
@@ -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
+4
View File
@@ -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)
+421
View File
@@ -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"); }
+477
View File
@@ -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"); }
+5
View File
@@ -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)
+425
View File
@@ -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; \
}
+375
View File
@@ -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"); }
+5
View File
@@ -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)
+1272
View File
File diff suppressed because it is too large Load Diff
+773
View File
@@ -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
}
+1072
View File
File diff suppressed because it is too large Load Diff
+307
View File
@@ -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
+437
View File
@@ -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 */
}
+1
View File
@@ -0,0 +1 @@
../gcc/gcc-1.22/obstack.c
+1
View File
@@ -0,0 +1 @@
../gcc/gcc-1.19/obstack.h
+1
View File
@@ -0,0 +1 @@
#include "m-mac-aux.h"
+1
View File
@@ -0,0 +1 @@
#include "m68k-pinsn.c"
+979
View File
@@ -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
+44
View 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 :-)
+667
View File
@@ -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
+612
View 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
+605
View 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
+168
View 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);
}
+535
View File
@@ -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
+323
View 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;
};
+1099
View File
File diff suppressed because it is too large Load Diff
+228
View File
@@ -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 ();
+13
View File
@@ -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));
}
+25
View File
@@ -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;
}
}
+10
View File
@@ -0,0 +1,10 @@
main ()
{
int x = 0;
while (1)
{
sleep (1);
x++;
}
}
+13
View File
@@ -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);
}
+12
View File
@@ -0,0 +1,12 @@
struct foo
{
unsigned bar : 1;
unsigned lose : 1;
};
main ()
{
struct foo *win;
printf ("%d, %d\n", win->bar, win->lose);
}
+25
View File
@@ -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. */
}
+12
View File
@@ -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