added manual page, some improvements
This commit is contained in:
parent
e3bb56818b
commit
096e8368c5
|
@ -19,7 +19,6 @@
|
|||
#include "expr.h"
|
||||
|
||||
extern char *Salloc();
|
||||
extern t_lineno currline;
|
||||
extern FILE *db_in;
|
||||
|
||||
int errorgiven;
|
||||
|
@ -126,6 +125,7 @@ list_command(p_tree *p;)
|
|||
[ ',' lin_num(&t2)
|
||||
| { t2 = mknode(OP_INTEGER, t1->t_ival); }
|
||||
]
|
||||
| qualified_name(&t1)
|
||||
] { *p = mknode(OP_LIST, t1, t2); }
|
||||
;
|
||||
|
||||
|
@ -348,8 +348,8 @@ position(p_tree *p;)
|
|||
AT
|
||||
[ STRING { str = tok.str; }
|
||||
':'
|
||||
| { if (! currfile) str = 0;
|
||||
else str = currfile->sy_idf->id_text;
|
||||
| { if (! listfile) str = 0;
|
||||
else str = listfile->sy_idf->id_text;
|
||||
}
|
||||
]
|
||||
lin_num(&lin) { *p = mknode(OP_AT, lin->t_ival, str);
|
||||
|
|
|
@ -55,7 +55,7 @@ debugger_string
|
|||
|
||||
| /* type name */
|
||||
{ s = NewSymbol(str, CurrentScope, TYPE, currnam); }
|
||||
't' type_name(&(s->sy_type))
|
||||
't' type_name(&(s->sy_type), s)
|
||||
{ if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; }
|
||||
|
||||
| /* tag name (only C?) */
|
||||
|
@ -102,43 +102,43 @@ debugger_string
|
|||
tmp = s->sy_type;
|
||||
} else s = NewSymbol(str, FileScope, VAR, currnam);
|
||||
}
|
||||
'G' type(&(s->sy_type), (int *) 0)
|
||||
'G' type(&(s->sy_type), (int *) 0, s)
|
||||
{ if (tmp) s->sy_type = tmp; }
|
||||
|
||||
| /* static variable */
|
||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
||||
'S' type(&(s->sy_type), (int *) 0)
|
||||
'S' type(&(s->sy_type), (int *) 0, s)
|
||||
|
||||
| /* static variable, local scope */
|
||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
||||
'V' type(&(s->sy_type), (int *) 0)
|
||||
'V' type(&(s->sy_type), (int *) 0, s)
|
||||
|
||||
| /* register variable */
|
||||
{ s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
|
||||
'r' type(&(s->sy_type), (int *) 0)
|
||||
'r' type(&(s->sy_type), (int *) 0, s)
|
||||
|
||||
| /* value parameter */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
'p' type(&(s->sy_type), (int *) 0)
|
||||
'p' type(&(s->sy_type), (int *) 0, s)
|
||||
{ add_param_type('p', s); }
|
||||
|
||||
| /* value parameter but address passed */
|
||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
||||
'i' type(&(s->sy_type), (int *) 0)
|
||||
'i' type(&(s->sy_type), (int *) 0, s)
|
||||
{ add_param_type('i', s); }
|
||||
|
||||
| /* variable parameter */
|
||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
||||
'v' type(&(s->sy_type), (int *) 0)
|
||||
'v' type(&(s->sy_type), (int *) 0, s)
|
||||
{ add_param_type('v', s); }
|
||||
|
||||
| /* local variable */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
type_name(&(s->sy_type))
|
||||
type_name(&(s->sy_type), s)
|
||||
|
||||
| /* function result in Pascal; ignore ??? */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
'X' type_name(&(s->sy_type))
|
||||
'X' type_name(&(s->sy_type), s)
|
||||
]
|
||||
';'?
|
||||
;
|
||||
|
@ -216,13 +216,13 @@ string_const
|
|||
STRING /* has SINGLE quotes! */
|
||||
;
|
||||
|
||||
type_name(p_type *t;)
|
||||
type_name(p_type *t; p_symbol sy;)
|
||||
{ int type_index[2]; p_type *p; }
|
||||
:
|
||||
type_index(type_index)
|
||||
[
|
||||
'='
|
||||
type(t, type_index)
|
||||
type(t, type_index, sy)
|
||||
{ p = tp_lookup(type_index);
|
||||
if (*p && *p != incomplete_type) {
|
||||
if (!((*p)->ty_flags & T_CROSS))
|
||||
|
@ -261,7 +261,7 @@ tag_name(p_symbol t;)
|
|||
:
|
||||
type_index(type_index)
|
||||
'='
|
||||
type(&(t->sy_type), type_index)
|
||||
type(&(t->sy_type), type_index, t)
|
||||
{ p = tp_lookup(type_index);
|
||||
if (*p && *p != incomplete_type) {
|
||||
if (!((*p)->ty_flags & T_CROSS))
|
||||
|
@ -284,7 +284,7 @@ function(p_symbol p;)
|
|||
p->sy_type->ty_class = T_PROCEDURE;
|
||||
p->sy_type->ty_size = pointer_size;
|
||||
}
|
||||
type(&(p->sy_type->ty_retval), (int *) 0)
|
||||
type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0)
|
||||
{ if (CurrentScope != FileScope &&
|
||||
saw_code) {
|
||||
/* if saw_code is not set, it is a nested
|
||||
|
@ -321,10 +321,10 @@ routine(p_symbol p;)
|
|||
CurrentScope->sc_proclevel = currnam->on_desc;
|
||||
}
|
||||
INTEGER ';'
|
||||
type(&(p->sy_type->ty_retval), (int *) 0)
|
||||
type(&(p->sy_type->ty_retval), (int *) 0, (p_symbol) 0)
|
||||
;
|
||||
|
||||
type(p_type *ptp; int *type_index;)
|
||||
type(p_type *ptp; int *type_index; p_symbol sy;)
|
||||
{ register p_type tp = 0;
|
||||
p_type t1, t2;
|
||||
long ic1, ic2;
|
||||
|
@ -355,7 +355,7 @@ type(p_type *ptp; int *type_index;)
|
|||
* integer_const.
|
||||
* Upperbound -1 means unsigned int or unsigned long.
|
||||
*/
|
||||
'r' type_name(&t1) ';'
|
||||
'r' type_name(&t1, (p_symbol) 0) ';'
|
||||
[ 'A' integer_const(&ic1) { A_used = 1; }
|
||||
| integer_const(&ic1)
|
||||
]
|
||||
|
@ -373,16 +373,16 @@ type(p_type *ptp; int *type_index;)
|
|||
/* array; first type is bound type, next type
|
||||
* is element type
|
||||
*/
|
||||
'a' type(&t1, (int *) 0) ';' type(&t2, (int *) 0)
|
||||
'a' type(&t1, (int *) 0, (p_symbol) 0) ';' type(&t2, (int *) 0, (p_symbol) 0)
|
||||
{ *ptp = array_type(t1, t2); }
|
||||
|
|
||||
/* structure type */
|
||||
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
|
||||
structure_type(tp)
|
||||
structure_type(tp, sy)
|
||||
|
|
||||
/* union type */
|
||||
'u' { tp = new_type(); tp->ty_class = T_UNION; }
|
||||
structure_type(tp)
|
||||
structure_type(tp, sy)
|
||||
|
|
||||
/* enumeration type */
|
||||
'e' { tp = new_type(); tp->ty_class = T_ENUM; }
|
||||
|
@ -392,13 +392,13 @@ type(p_type *ptp; int *type_index;)
|
|||
'*' { tp = new_type(); tp->ty_class =T_POINTER;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_ptrto), (int *) 0)
|
||||
type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0)
|
||||
|
|
||||
/* function type */
|
||||
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_retval), (int *) 0)
|
||||
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
|
||||
/*
|
||||
[ %prefer
|
||||
',' param_list(tp)
|
||||
|
@ -410,7 +410,7 @@ type(p_type *ptp; int *type_index;)
|
|||
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_retval), (int *) 0)
|
||||
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
|
||||
',' param_list(tp)
|
||||
|
|
||||
/* another procedure type */
|
||||
|
@ -425,7 +425,7 @@ type(p_type *ptp; int *type_index;)
|
|||
* the second one represents the low bound
|
||||
*/
|
||||
'S' { tp = new_type(); tp->ty_class = T_SET; }
|
||||
type(&(tp->ty_setbase), (int *) 0) ';'
|
||||
type(&(tp->ty_setbase), (int *) 0, (p_symbol) 0) ';'
|
||||
[
|
||||
integer_const(&(tp->ty_size)) ';'
|
||||
integer_const(&(tp->ty_setlow)) ';'
|
||||
|
@ -435,9 +435,9 @@ type(p_type *ptp; int *type_index;)
|
|||
|
|
||||
/* file type of Pascal */
|
||||
'L' { tp = new_type(); tp->ty_class = T_FILE; }
|
||||
type(&(tp->ty_fileof), (int *) 0)
|
||||
type(&(tp->ty_fileof), (int *) 0, (p_symbol) 0)
|
||||
|
|
||||
type_name(ptp)
|
||||
type_name(ptp, (p_symbol) 0)
|
||||
{ if (type_index &&
|
||||
*ptp == incomplete_type &&
|
||||
type_index[0] == last_index[0] &&
|
||||
|
@ -449,19 +449,18 @@ type(p_type *ptp; int *type_index;)
|
|||
{ if (! *ptp) *ptp = tp; }
|
||||
;
|
||||
|
||||
structure_type(register p_type tp;)
|
||||
structure_type(register p_type tp; p_symbol sy;)
|
||||
{ register struct fields *fldp;
|
||||
register p_symbol s;
|
||||
char *str;
|
||||
}
|
||||
:
|
||||
integer_const(&(tp->ty_size)) /* size in bytes */
|
||||
{ open_scope((p_symbol) 0, 0); }
|
||||
[ { fldp = get_field_space(tp); }
|
||||
name(&(fldp->fld_name))
|
||||
{ s = NewSymbol(fldp->fld_name, CurrentScope, FIELD, currnam);
|
||||
s->sy_field = fldp;
|
||||
{ open_scope(sy, 0);
|
||||
if (sy) sy->sy_name.nm_scope = CurrentScope;
|
||||
}
|
||||
type(&(fldp->fld_type), (int *) 0) ','
|
||||
[
|
||||
name(&str) { fldp = get_field_space(tp, str); }
|
||||
type(&(fldp->fld_type), (int *) 0, (p_symbol) 0) ','
|
||||
integer_const(&(fldp->fld_pos)) ',' /* offset in bits */
|
||||
integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
|
||||
]*
|
||||
|
@ -504,7 +503,7 @@ param_list(p_type t;)
|
|||
| 'v' { p->par_kind = 'v'; }
|
||||
| 'i' { p->par_kind = 'i'; }
|
||||
]
|
||||
type(&(p->par_type), (int *) 0) ';'
|
||||
type(&(p->par_type), (int *) 0, (p_symbol) 0) ';'
|
||||
{ t->ty_nbparams +=
|
||||
param_size(p->par_type, p->par_kind);
|
||||
p++;
|
||||
|
@ -638,15 +637,23 @@ DBSlex()
|
|||
}
|
||||
|
||||
static struct fields *
|
||||
get_field_space(tp)
|
||||
get_field_space(tp, s)
|
||||
register p_type tp;
|
||||
char *s;
|
||||
{
|
||||
register struct fields *p;
|
||||
p_symbol sy;
|
||||
|
||||
if (! (tp->ty_nfields & 07)) {
|
||||
tp->ty_fields = (struct fields *)
|
||||
Realloc((char *) tp->ty_fields,
|
||||
(tp->ty_nfields+8)*sizeof(struct fields));
|
||||
}
|
||||
return &tp->ty_fields[tp->ty_nfields++];
|
||||
p = &tp->ty_fields[tp->ty_nfields++];
|
||||
p->fld_name = s;
|
||||
sy = NewSymbol(s, CurrentScope, FIELD, currnam);
|
||||
sy->sy_field = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
static
|
||||
|
|
|
@ -99,7 +99,7 @@ DbxRead(f)
|
|||
saw_code = 0;
|
||||
sym = add_file(n->on_mptr);
|
||||
|
||||
if (! currfile) newfile(sym->sy_idf);
|
||||
if (! listfile) newfile(sym->sy_idf);
|
||||
open_scope(sym, 0);
|
||||
sym->sy_file->f_scope = CurrentScope;
|
||||
FileScope = CurrentScope;
|
||||
|
|
293
util/grind/grind.1
Normal file
293
util/grind/grind.1
Normal file
|
@ -0,0 +1,293 @@
|
|||
.\" $Header$
|
||||
.TH GRIND 1ACK
|
||||
.SH NAME
|
||||
grind \- source-level debugger for ACK
|
||||
.SH SYNOPSIS
|
||||
.B grind
|
||||
[
|
||||
.I <ACK object file>
|
||||
]
|
||||
[
|
||||
.I <object file>
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.B Grind
|
||||
is a utility for source-level debugging and execution of
|
||||
programs written in C or Modula-2 (Pascal will be added later).
|
||||
Its operation resembles the operation of
|
||||
.IR dbx ,
|
||||
a source-level debugger
|
||||
available on many Unix systems. However, some
|
||||
.B Grind
|
||||
commands are not available in
|
||||
.IR dbx ,
|
||||
and some more
|
||||
.I dbx
|
||||
commands are not available in
|
||||
.BR grind ,
|
||||
and some things are just plain different.
|
||||
.LP
|
||||
.I <object file>
|
||||
is an object file, produced by
|
||||
.IR ack (1ACK)
|
||||
with the
|
||||
.B \-g
|
||||
option to include a symbol table.
|
||||
.LP
|
||||
If no
|
||||
.I <object file>
|
||||
is specified, "a.out" is used.
|
||||
.LP
|
||||
For some machines, the debugger does not recognize the object file
|
||||
format. For these machines, the result of the
|
||||
.IR led (6ACK)
|
||||
program must be saved and offered to
|
||||
.BR grind .
|
||||
.SH USAGE
|
||||
Some
|
||||
.B grind
|
||||
commands take an expression argument.
|
||||
.SS Expressions
|
||||
.B Grind expressions
|
||||
are combinations of variables, constants, and operators.
|
||||
The syntax and the operators depend on the source language of the program
|
||||
being debugged. However, the type rules are probably less strict than the
|
||||
rules of this language. For instance, in Modula-2 one cannot combine
|
||||
values of type INTEGER with values of type REAL in an expression without
|
||||
using conversion routines. In
|
||||
.BR grind ,
|
||||
the conversions needed are performed automatically.
|
||||
Expressions cannot involve strings, structures, or
|
||||
arrays, although elements of structures or arrays may be used.
|
||||
.SS Operators
|
||||
.LP
|
||||
.B Grind
|
||||
supports operators for addition, subtraction, multiplication, division,
|
||||
remainder, bitwise or, bitwise xor, bitwise and, boolean or,
|
||||
boolean and, left-shift, right-shift, address-of, dereference, less than,
|
||||
less than or equal, equal, not equal, greater than, greater than or equal,
|
||||
selection.
|
||||
.LP
|
||||
The syntax and priority of these operators depends on the source language.
|
||||
Parentheses can be used for grouping.
|
||||
.SS "Scope Rules"
|
||||
.LP
|
||||
.B dbx
|
||||
uses the current file and function to resolve scope conflicts.
|
||||
Their values are updated as files and functions are entered and exited
|
||||
during execution.
|
||||
Names can also be qualified with procedure- or module names, as in
|
||||
\fImodule\fP`\fIproc\fP`\fIname\fP.
|
||||
.B Grind
|
||||
tries to be intelligent about names, so qualification is only needed when
|
||||
names are used for more than one object in a program and the current scope
|
||||
does not help.
|
||||
.SS "Positions"
|
||||
In general, there are two ways to specify a position; the first way is
|
||||
to specify filename and linenumber, in a so-called at-clause, like this:
|
||||
.RS
|
||||
\fBat\fP [ "\fIfilename\fP": ] \fIlinenumber\fP
|
||||
.RE
|
||||
The
|
||||
.I filename
|
||||
part is optional.
|
||||
The second way is to specify a function name, like this:
|
||||
.RS
|
||||
\fBin \fIfunction\fP
|
||||
.RE
|
||||
This indicates the first statement within the named function (except for
|
||||
the trace command discussed later).
|
||||
.SS "Commands"
|
||||
.TP
|
||||
.B \s+2^\s0C
|
||||
Interrupt. Stop the program being debugged and enter
|
||||
.BR grind .
|
||||
.TP
|
||||
\fBrun\fP [ \fIargs\fP ] [ < \fIinfile\fP ] [ > \fIoutfile\fP ]
|
||||
Start executing
|
||||
.I <object file>
|
||||
with command line arguments
|
||||
.IR args ,
|
||||
and possible redirection of standard input and/or standard output.
|
||||
.TP
|
||||
.B rerun
|
||||
Repeats the last
|
||||
.B run
|
||||
command.
|
||||
\fBcont\fP [ \fBat\fP \fIsourceline\fP ]
|
||||
Continue execution from where it stopped, or, if \fIsourceline\fP is
|
||||
given, at that source line.
|
||||
.TP
|
||||
\fBtrace\fP [ \fBon\fP \fIexpression\fP ] [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ]
|
||||
Display tracing information.
|
||||
If no argument is specified, each source line is displayed before
|
||||
execution.
|
||||
In addition, if an \fBon\fP-clause is given, the value of the expression
|
||||
is printed.
|
||||
If a position is given there are two possibilities: if the position is
|
||||
given as \fBin\fP \fIfunction\fP, then the tracing information is
|
||||
displayed only while executing the function or
|
||||
procedure
|
||||
.IR function .
|
||||
If the position is given as \fBat\fP \fIlinenumber\fP,
|
||||
then the tracing information is displayed only whenever the source line
|
||||
indicated is reached.
|
||||
If a condition is given, tracing information is only displayed when
|
||||
.I condition
|
||||
is true.
|
||||
.TP
|
||||
\fBstop\fP [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ]
|
||||
Stop execution when the
|
||||
.I position
|
||||
is reached, and then when
|
||||
.I condition
|
||||
becomes true.
|
||||
If no position is given, stop when
|
||||
.I condition
|
||||
becomes true.
|
||||
If no condition is given, stop when
|
||||
.I position
|
||||
is reached.
|
||||
Either a position or a condition (or both) must be given.
|
||||
.TP
|
||||
\fBwhen\fP [ \fIposition\fP ] [ \fBif\fP \fIcondition\fP ] { \fIcommand\fP [ ; \fIcommand ] ... }
|
||||
Execute the
|
||||
.B grind
|
||||
.IR command (s)
|
||||
when the
|
||||
.I position
|
||||
is reached, and then when
|
||||
.I condition
|
||||
becomes true.
|
||||
If no position is given, stop when
|
||||
.I condition
|
||||
becomes true.
|
||||
If no condition is given, stop when
|
||||
.I position
|
||||
is reached.
|
||||
Either a position or a condition (or both) must be given.
|
||||
.TP
|
||||
\fBprint\fP \fIexpression\fP [ ',' \fIexpression\fP ] ...
|
||||
Print the value of each expression.
|
||||
.TP
|
||||
\fBdisplay\fP \fIexpression\fP [ ',' \fIexpression\fP ] ...
|
||||
Print the value of each expression whenever the program stops.
|
||||
.TP
|
||||
.B dump
|
||||
Saves the data (global data + stack) of the program. These data can
|
||||
be restore with the
|
||||
.B restore
|
||||
command discussed later.
|
||||
.B Dump
|
||||
and
|
||||
.B restore
|
||||
combinations can be used as a poor man's implementation of an "undo"
|
||||
facility.
|
||||
.TP
|
||||
.B status
|
||||
Display active
|
||||
.BR trace ,
|
||||
.BR stop ,
|
||||
.BR when ,
|
||||
and
|
||||
.B display
|
||||
commands, and associated command numbers.
|
||||
Also display current
|
||||
.B dump
|
||||
records.
|
||||
.TP
|
||||
\fBdelete\fP \fIcommandnumber\fP
|
||||
Remove the command corresponding to \fIcommandnumber\fP
|
||||
(as displayed by
|
||||
.BR status ).
|
||||
.TP
|
||||
\fBrestore\fP \fIcommandnumber\fP
|
||||
Restore the data corresponding to the dump of \fIcommandnumber\fP
|
||||
(as displayed by
|
||||
.BR status ).
|
||||
This restores the values of all variables of the program to the values
|
||||
at the time the dump was made. The program counter is also restored.
|
||||
This effectively puts the program back into the state it was when the
|
||||
dump was made, except for file-handling: the state of the files that
|
||||
the program handles is not changed.
|
||||
Apart from this,
|
||||
.B restore
|
||||
even works when the program is finished.
|
||||
.TP
|
||||
\fBstep\fP [ \fIn\fP ]
|
||||
Execute the next
|
||||
.I n
|
||||
source lines.
|
||||
If omitted,
|
||||
.I n
|
||||
is taken to be 1.
|
||||
This command steps into functions.
|
||||
.TP
|
||||
\fBnext\fP [ \fIn\fP ]
|
||||
Execute the next
|
||||
.I n
|
||||
source lines.
|
||||
If omitted,
|
||||
.I n
|
||||
is taken to be 1.
|
||||
.B Next
|
||||
steps past function-calls.
|
||||
.TP
|
||||
\fBwhich\fP \fIname\fP
|
||||
Print the fully-qualified name of the given name.
|
||||
.TP
|
||||
\fBfind\fP \fIname\fP
|
||||
Print the fully qualified name of all symbols matching
|
||||
.IR name .
|
||||
.TP
|
||||
\fBset\fP \fIexpression\fP \fBto\fP \fIexpression\fP
|
||||
Assign the value of the second
|
||||
.I expression
|
||||
to the designator indicated by the first
|
||||
.IR expression .
|
||||
Needless to say, the first
|
||||
.I expression
|
||||
must indicate a designator (something that can be assigned to).
|
||||
If the types do not match,
|
||||
.B grind
|
||||
tries to apply conversions.
|
||||
.TP
|
||||
\fBwhere\fP [ \fIn\fP ]
|
||||
List all, or the top
|
||||
.IR n ,
|
||||
active functions on the stack.
|
||||
.TP
|
||||
\fBfile\fP [ \fIfilename\fP ]
|
||||
.br
|
||||
Print the name of the current source file, or
|
||||
change the current source file to
|
||||
.IR filename .
|
||||
.TP
|
||||
\fBlist\fP [ \fIstartline\fP [ , \fIendline\fP ] | \fIfunction\fP ]
|
||||
If no arguments are given, list the next ten lines from current source file,
|
||||
if a
|
||||
.I startline
|
||||
is given, list from
|
||||
.I startline
|
||||
through
|
||||
.IR endline ,
|
||||
or
|
||||
list from five lines above, to five lines below
|
||||
the first statement of
|
||||
.IR function .
|
||||
.TP
|
||||
.B quit
|
||||
Exit
|
||||
.BR grind .
|
||||
.SH ENVIRONMENT
|
||||
P.M.
|
||||
.SH SEE ALSO
|
||||
.BR ack (1ACK).
|
||||
.BR led (6ACK).
|
||||
.SH BUGS
|
||||
.LP
|
||||
.B Grind
|
||||
does not correctly handle bit-fields.
|
||||
.LP
|
||||
.B Grind
|
||||
does not understand WITH statements.
|
|
@ -13,7 +13,6 @@ extern char *dirs[];
|
|||
extern FILE *fopen();
|
||||
extern FILE *db_out;
|
||||
extern t_lineno currline;
|
||||
#define window_size 21
|
||||
|
||||
static int
|
||||
mk_filnm(dir, file, newname)
|
||||
|
@ -55,6 +54,7 @@ open_file(fn, mode, ffn)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#define window_size 21
|
||||
/* Print a window of window_size lines around line "line" of
|
||||
file "file".
|
||||
*/
|
||||
|
@ -103,7 +103,7 @@ lines(file, l1, l2)
|
|||
for (n = l1; n <= l2; n++) {
|
||||
register int c;
|
||||
|
||||
fprintf(db_out, "%c%5d\t", n == currline ? '>' : ' ', n);
|
||||
fprintf(db_out, "%c%5d\t", currfile && file == currfile->sy_file && n == currline ? '>' : ' ', n);
|
||||
do {
|
||||
c = getc(f);
|
||||
if (c != EOF) putc(c, db_out);
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
|
||||
static char *usage = "Usage: %s [-d] [<ack.out>] [<a.out>]";
|
||||
static char *usage = "Usage: %s [<ack.out>] [<a.out>]";
|
||||
static char *progname;
|
||||
char *AckObj;
|
||||
char *AObj;
|
||||
char *dirs[] = { "", 0 };
|
||||
FILE *db_out;
|
||||
FILE *db_in;
|
||||
t_lineno currline;
|
||||
int debug;
|
||||
extern struct tokenname tkidf[];
|
||||
extern char *strindex();
|
||||
|
|
|
@ -19,24 +19,25 @@
|
|||
#define MAXARG 128
|
||||
|
||||
extern char *strncpy();
|
||||
extern struct idf *str2idf();
|
||||
|
||||
extern char *AObj;
|
||||
extern t_lineno currline;
|
||||
extern FILE *db_out;
|
||||
extern int debug;
|
||||
extern struct idf *str2idf();
|
||||
extern long pointer_size;
|
||||
|
||||
static int child_pid; /* process id of child */
|
||||
static int to_child, from_child; /* file descriptors for communication */
|
||||
static int child_status;
|
||||
static int restoring;
|
||||
static int fild1[2], fild2[2]; /* pipe file descriptors */
|
||||
|
||||
int db_ss;
|
||||
t_lineno currline, listline;
|
||||
|
||||
static int catch_sigpipe();
|
||||
static int stopped();
|
||||
static int uputm(), ugetm();
|
||||
static int fild1[2], fild2[2]; /* pipe file descriptors */
|
||||
|
||||
int
|
||||
init_run()
|
||||
|
@ -289,10 +290,8 @@ stopped(s, a)
|
|||
if (s) {
|
||||
fprintf(db_out, "%s ", s);
|
||||
pos = print_position((t_addr) a, 1);
|
||||
newfile(str2idf(pos->filename, 1));
|
||||
currline = pos->lineno;
|
||||
fputs("\n", db_out);
|
||||
lines(currfile->sy_file, (int)currline, (int)currline);
|
||||
list_position(pos);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "tree.h"
|
||||
#include "operator.h"
|
||||
|
||||
p_symbol currfile;
|
||||
p_symbol currfile, listfile;
|
||||
|
||||
extern FILE *db_out;
|
||||
|
||||
|
@ -141,6 +141,11 @@ def_scope(s)
|
|||
case PROC:
|
||||
case FUNCTION:
|
||||
case MODULE:
|
||||
case TYPE:
|
||||
case VAR:
|
||||
case REGVAR:
|
||||
case LOCVAR:
|
||||
case VARPAR:
|
||||
return s->sy_name.nm_scope;
|
||||
}
|
||||
return 0;
|
||||
|
@ -163,7 +168,8 @@ consistent(p, sc)
|
|||
|
||||
switch(p->t_oper) {
|
||||
case OP_NAME:
|
||||
sym = Lookfromscope(p->t_idf, FILELINK|FILESYM|PROC|FUNCTION|MODULE, sc->sc_static_encl);
|
||||
#define CLASS (FILELINK|FILESYM|PROC|FUNCTION|MODULE|TYPE|VAR|REGVAR|LOCVAR|VARPAR)
|
||||
sym = Lookfromscope(p->t_idf, CLASS, sc->sc_static_encl);
|
||||
if (sym) {
|
||||
target_sc = def_scope(sym);
|
||||
while (sc && sc != target_sc) {
|
||||
|
@ -175,7 +181,7 @@ consistent(p, sc)
|
|||
|
||||
case OP_SELECT:
|
||||
arg = p->t_args[1];
|
||||
sym = Lookfromscope(arg->t_idf, FILELINK|FILESYM|PROC|FUNCTION|MODULE, sc->sc_static_encl);
|
||||
sym = Lookfromscope(arg->t_idf, CLASS, sc->sc_static_encl);
|
||||
if (sym) {
|
||||
target_sc = def_scope(sym);
|
||||
while (sc && sc != target_sc) {
|
||||
|
@ -322,7 +328,6 @@ pr_sym(s)
|
|||
do_find(p)
|
||||
p_tree p;
|
||||
{
|
||||
p_symbol sym = 0;
|
||||
register p_symbol s;
|
||||
p_tree arg;
|
||||
|
||||
|
@ -340,7 +345,6 @@ do_find(p)
|
|||
arg = p->t_args[1];
|
||||
assert(arg->t_oper == OP_NAME);
|
||||
s = arg->t_idf->id_def;
|
||||
sym = 0;
|
||||
while (s) {
|
||||
if (consistent(p, s->sy_scope)) {
|
||||
pr_sym(s);
|
||||
|
|
|
@ -56,4 +56,4 @@ typedef struct symbol {
|
|||
extern p_symbol NewSymbol(), Lookup(), Lookfromscope(), add_file();
|
||||
extern p_symbol identify();
|
||||
|
||||
extern p_symbol currfile;
|
||||
extern p_symbol currfile, listfile;
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
#include "expr.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
extern t_lineno currline;
|
||||
extern t_lineno currline, listline;
|
||||
extern long pointer_size;
|
||||
extern char *strrindex();
|
||||
|
||||
p_tree run_command;
|
||||
t_lineno list_line;
|
||||
|
||||
|
||||
/*VARARGS1*/
|
||||
p_tree
|
||||
|
@ -104,6 +106,55 @@ freenode(p)
|
|||
free_tree(p);
|
||||
}
|
||||
|
||||
static t_addr
|
||||
get_addr(p)
|
||||
p_tree p;
|
||||
{
|
||||
t_addr a = ILL_ADDR;
|
||||
register p_symbol sym;
|
||||
|
||||
if (! p) return NO_ADDR;
|
||||
if (p->t_address != 0) return p->t_address;
|
||||
switch(p->t_oper) {
|
||||
case OP_AT:
|
||||
if (! p->t_filename &&
|
||||
(! listfile || ! (p->t_filename = listfile->sy_idf->id_text))) {
|
||||
error("no current file");
|
||||
break;
|
||||
}
|
||||
a = get_addr_from_position(&(p->t_pos));
|
||||
if (a == ILL_ADDR) {
|
||||
error("could not determine address of \"%s\":%d",
|
||||
p->t_filename, p->t_lino);
|
||||
break;
|
||||
}
|
||||
p->t_address = a;
|
||||
break;
|
||||
|
||||
case OP_IN:
|
||||
a = get_addr(p->t_args[0]);
|
||||
p->t_address = a;
|
||||
break;
|
||||
|
||||
case OP_NAME:
|
||||
case OP_SELECT:
|
||||
sym = identify(p, FUNCTION|PROC|MODULE);
|
||||
if (! sym) {
|
||||
break;
|
||||
}
|
||||
if (! sym->sy_name.nm_scope || ! sym->sy_name.nm_scope->sc_bp_opp) {
|
||||
error("could not determine address of \"%s\"", p->t_str);
|
||||
break;
|
||||
}
|
||||
a = sym->sy_name.nm_scope->sc_bp_opp;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
print_node(p, top_level)
|
||||
register p_tree p;
|
||||
{
|
||||
|
@ -169,7 +220,7 @@ print_node(p, top_level)
|
|||
break;
|
||||
case OP_WHERE:
|
||||
fputs("where", db_out);
|
||||
if (p->t_ival != 0x7fffffff) fprintf(" %ld", p->t_ival);
|
||||
if (p->t_ival != 0x7fffffff) fprintf(db_out, " %ld", p->t_ival);
|
||||
break;
|
||||
case OP_CONT:
|
||||
fputs("cont", db_out);
|
||||
|
@ -301,11 +352,36 @@ eval(p)
|
|||
do_list(p)
|
||||
p_tree p;
|
||||
{
|
||||
if (currfile) {
|
||||
lines(currfile->sy_file,
|
||||
p->t_args[0] ? (int) p->t_args[0]->t_ival : (int) currline-4,
|
||||
p->t_args[1] ? (int) p->t_args[1]->t_ival : (int) currline+5);
|
||||
currline = p->t_args[1] ? p->t_args[1]->t_ival + 1 : currline + 10;
|
||||
int l1, l2;
|
||||
|
||||
if (! p->t_args[0]) {
|
||||
l1 = listline;
|
||||
l2 = listline + 9;
|
||||
}
|
||||
else {
|
||||
if (p->t_args[0]->t_oper == OP_INTEGER) {
|
||||
l1 = p->t_args[0]->t_ival;
|
||||
assert(p->t_args[1] != 0);
|
||||
l2 = p->t_args[1]->t_ival;
|
||||
}
|
||||
else {
|
||||
t_addr a = get_addr(p->t_args[0]);
|
||||
p_position pos;
|
||||
|
||||
if (a == ILL_ADDR) {
|
||||
error("could not determine address");
|
||||
return;
|
||||
}
|
||||
pos = get_position_from_addr(a);
|
||||
newfile(str2idf(pos->filename, 1));
|
||||
l1 = pos->lineno - 5;
|
||||
if (l1 < 1) l1 = 1;
|
||||
l2 = l1+9;
|
||||
}
|
||||
}
|
||||
if (listfile) {
|
||||
lines(listfile->sy_file, l1, l2);
|
||||
listline = l2+1;
|
||||
}
|
||||
else fprintf(db_out, "no current file\n");
|
||||
}
|
||||
|
@ -316,7 +392,7 @@ do_file(p)
|
|||
if (p->t_args[0]) {
|
||||
newfile(p->t_args[0]->t_idf);
|
||||
}
|
||||
else if (currfile) fprintf(db_out, "%s\n", currfile->sy_idf->id_text);
|
||||
else if (listfile) fprintf(db_out, "%s\n", listfile->sy_idf->id_text);
|
||||
else fprintf(db_out, "no current file\n");
|
||||
}
|
||||
|
||||
|
@ -325,69 +401,20 @@ newfile(id)
|
|||
{
|
||||
register p_symbol sym = Lookup(id, PervasiveScope, FILESYM);
|
||||
|
||||
if (currfile != sym) currline = 1;
|
||||
currfile = sym;
|
||||
if (! currfile) {
|
||||
currline = 1;
|
||||
currfile = add_file(id->id_text);
|
||||
currfile->sy_file->f_scope = FileScope;
|
||||
if (listfile != sym) listline = 1;
|
||||
listfile = sym;
|
||||
if (! listfile) {
|
||||
listline = 1;
|
||||
listfile = add_file(id->id_text);
|
||||
listfile->sy_file->f_scope = FileScope;
|
||||
}
|
||||
find_language(strrindex(id->id_text, '.'));
|
||||
}
|
||||
|
||||
static t_addr
|
||||
get_pos(p)
|
||||
p_tree p;
|
||||
{
|
||||
t_addr a = ILL_ADDR;
|
||||
register p_symbol sym;
|
||||
|
||||
if (! p) return NO_ADDR;
|
||||
if (p->t_address != 0) return p->t_address;
|
||||
switch(p->t_oper) {
|
||||
case OP_AT:
|
||||
if (! p->t_filename &&
|
||||
(! currfile || ! (p->t_filename = currfile->sy_idf->id_text))) {
|
||||
error("no current file");
|
||||
break;
|
||||
}
|
||||
a = get_addr_from_position(&(p->t_pos));
|
||||
if (a == ILL_ADDR) {
|
||||
error("could not determine address of \"%s\":%d",
|
||||
p->t_filename, p->t_lino);
|
||||
break;
|
||||
}
|
||||
p->t_address = a;
|
||||
break;
|
||||
|
||||
case OP_IN:
|
||||
a = get_pos(p->t_args[0]);
|
||||
p->t_address = a;
|
||||
break;
|
||||
|
||||
case OP_NAME:
|
||||
case OP_SELECT:
|
||||
sym = identify(p, FUNCTION|PROC|MODULE);
|
||||
if (! sym) {
|
||||
break;
|
||||
}
|
||||
if (! sym->sy_name.nm_scope || ! sym->sy_name.nm_scope->sc_bp_opp) {
|
||||
error("could not determine address of \"%s\"", p->t_str);
|
||||
break;
|
||||
}
|
||||
a = sym->sy_name.nm_scope->sc_bp_opp;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
do_stop(p)
|
||||
p_tree p;
|
||||
{
|
||||
t_addr a = get_pos(p->t_args[0]);
|
||||
t_addr a = get_addr(p->t_args[0]);
|
||||
|
||||
if (a == ILL_ADDR) {
|
||||
return;
|
||||
|
@ -410,7 +437,7 @@ do_trace(p)
|
|||
|
||||
p->t_address = NO_ADDR;
|
||||
if (p->t_args[0]) {
|
||||
a = get_pos(p->t_args[0]);
|
||||
a = get_addr(p->t_args[0]);
|
||||
if (a == ILL_ADDR) return;
|
||||
if (p->t_args[0]->t_oper == OP_AT) {
|
||||
e = a;
|
||||
|
@ -542,7 +569,7 @@ do_delete(p)
|
|||
if (p) switch(p->t_oper) {
|
||||
case OP_WHEN:
|
||||
case OP_STOP: {
|
||||
t_addr a = get_pos(p->t_args[0]);
|
||||
t_addr a = get_addr(p->t_args[0]);
|
||||
|
||||
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||
set_or_clear_breakpoint(a, CLRBP);
|
||||
|
@ -550,7 +577,7 @@ do_delete(p)
|
|||
break;
|
||||
}
|
||||
case OP_TRACE: {
|
||||
t_addr a = get_pos(p->t_args[0]);
|
||||
t_addr a = get_addr(p->t_args[0]);
|
||||
|
||||
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||
t_addr e;
|
||||
|
@ -642,16 +669,20 @@ perform(p, a)
|
|||
break;
|
||||
}
|
||||
}
|
||||
{
|
||||
p_position pos = get_position_from_addr(a);
|
||||
|
||||
newfile(str2idf(pos->filename, 1));
|
||||
currline = pos->lineno;
|
||||
lines(currfile->sy_file, (int)currline, (int)currline);
|
||||
if (p->t_args[2]) do_print(p->t_args[2]);
|
||||
}
|
||||
list_position(get_position_from_addr(a));
|
||||
if (p->t_args[2]) do_print(p->t_args[2]);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
list_position(pos)
|
||||
p_position pos;
|
||||
{
|
||||
newfile(str2idf(pos->filename, 1));
|
||||
currfile = listfile;
|
||||
currline = pos->lineno;
|
||||
listline = currline-5;
|
||||
lines(currfile->sy_file, (int)currline, (int)currline);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue