added manual page, some improvements

This commit is contained in:
ceriel 1990-09-21 16:58:20 +00:00
parent e3bb56818b
commit 096e8368c5
10 changed files with 465 additions and 132 deletions

View file

@ -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);

View file

@ -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

View file

@ -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
View 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.

View file

@ -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);

View file

@ -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();

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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);
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);
}