added manual page, some improvements
This commit is contained in:
parent
e3bb56818b
commit
096e8368c5
|
@ -19,7 +19,6 @@
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
extern char *Salloc();
|
extern char *Salloc();
|
||||||
extern t_lineno currline;
|
|
||||||
extern FILE *db_in;
|
extern FILE *db_in;
|
||||||
|
|
||||||
int errorgiven;
|
int errorgiven;
|
||||||
|
@ -126,6 +125,7 @@ list_command(p_tree *p;)
|
||||||
[ ',' lin_num(&t2)
|
[ ',' lin_num(&t2)
|
||||||
| { t2 = mknode(OP_INTEGER, t1->t_ival); }
|
| { t2 = mknode(OP_INTEGER, t1->t_ival); }
|
||||||
]
|
]
|
||||||
|
| qualified_name(&t1)
|
||||||
] { *p = mknode(OP_LIST, t1, t2); }
|
] { *p = mknode(OP_LIST, t1, t2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -348,8 +348,8 @@ position(p_tree *p;)
|
||||||
AT
|
AT
|
||||||
[ STRING { str = tok.str; }
|
[ STRING { str = tok.str; }
|
||||||
':'
|
':'
|
||||||
| { if (! currfile) str = 0;
|
| { if (! listfile) str = 0;
|
||||||
else str = currfile->sy_idf->id_text;
|
else str = listfile->sy_idf->id_text;
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
lin_num(&lin) { *p = mknode(OP_AT, lin->t_ival, str);
|
lin_num(&lin) { *p = mknode(OP_AT, lin->t_ival, str);
|
||||||
|
|
|
@ -55,7 +55,7 @@ debugger_string
|
||||||
|
|
||||||
| /* type name */
|
| /* type name */
|
||||||
{ s = NewSymbol(str, CurrentScope, TYPE, currnam); }
|
{ 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; }
|
{ if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s; }
|
||||||
|
|
||||||
| /* tag name (only C?) */
|
| /* tag name (only C?) */
|
||||||
|
@ -102,43 +102,43 @@ debugger_string
|
||||||
tmp = s->sy_type;
|
tmp = s->sy_type;
|
||||||
} else s = NewSymbol(str, FileScope, VAR, currnam);
|
} 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; }
|
{ if (tmp) s->sy_type = tmp; }
|
||||||
|
|
||||||
| /* static variable */
|
| /* static variable */
|
||||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
{ 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 */
|
| /* static variable, local scope */
|
||||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
||||||
'V' type(&(s->sy_type), (int *) 0)
|
'V' type(&(s->sy_type), (int *) 0, s)
|
||||||
|
|
||||||
| /* register variable */
|
| /* register variable */
|
||||||
{ s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
|
{ s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
|
||||||
'r' type(&(s->sy_type), (int *) 0)
|
'r' type(&(s->sy_type), (int *) 0, s)
|
||||||
|
|
||||||
| /* value parameter */
|
| /* value parameter */
|
||||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
{ 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); }
|
{ add_param_type('p', s); }
|
||||||
|
|
||||||
| /* value parameter but address passed */
|
| /* value parameter but address passed */
|
||||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
{ 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); }
|
{ add_param_type('i', s); }
|
||||||
|
|
||||||
| /* variable parameter */
|
| /* variable parameter */
|
||||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
{ 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); }
|
{ add_param_type('v', s); }
|
||||||
|
|
||||||
| /* local variable */
|
| /* local variable */
|
||||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||||
type_name(&(s->sy_type))
|
type_name(&(s->sy_type), s)
|
||||||
|
|
||||||
| /* function result in Pascal; ignore ??? */
|
| /* function result in Pascal; ignore ??? */
|
||||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
{ 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! */
|
STRING /* has SINGLE quotes! */
|
||||||
;
|
;
|
||||||
|
|
||||||
type_name(p_type *t;)
|
type_name(p_type *t; p_symbol sy;)
|
||||||
{ int type_index[2]; p_type *p; }
|
{ int type_index[2]; p_type *p; }
|
||||||
:
|
:
|
||||||
type_index(type_index)
|
type_index(type_index)
|
||||||
[
|
[
|
||||||
'='
|
'='
|
||||||
type(t, type_index)
|
type(t, type_index, sy)
|
||||||
{ p = tp_lookup(type_index);
|
{ p = tp_lookup(type_index);
|
||||||
if (*p && *p != incomplete_type) {
|
if (*p && *p != incomplete_type) {
|
||||||
if (!((*p)->ty_flags & T_CROSS))
|
if (!((*p)->ty_flags & T_CROSS))
|
||||||
|
@ -261,7 +261,7 @@ tag_name(p_symbol t;)
|
||||||
:
|
:
|
||||||
type_index(type_index)
|
type_index(type_index)
|
||||||
'='
|
'='
|
||||||
type(&(t->sy_type), type_index)
|
type(&(t->sy_type), type_index, t)
|
||||||
{ p = tp_lookup(type_index);
|
{ p = tp_lookup(type_index);
|
||||||
if (*p && *p != incomplete_type) {
|
if (*p && *p != incomplete_type) {
|
||||||
if (!((*p)->ty_flags & T_CROSS))
|
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_class = T_PROCEDURE;
|
||||||
p->sy_type->ty_size = pointer_size;
|
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 &&
|
{ if (CurrentScope != FileScope &&
|
||||||
saw_code) {
|
saw_code) {
|
||||||
/* if saw_code is not set, it is a nested
|
/* if saw_code is not set, it is a nested
|
||||||
|
@ -321,10 +321,10 @@ routine(p_symbol p;)
|
||||||
CurrentScope->sc_proclevel = currnam->on_desc;
|
CurrentScope->sc_proclevel = currnam->on_desc;
|
||||||
}
|
}
|
||||||
INTEGER ';'
|
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;
|
{ register p_type tp = 0;
|
||||||
p_type t1, t2;
|
p_type t1, t2;
|
||||||
long ic1, ic2;
|
long ic1, ic2;
|
||||||
|
@ -355,7 +355,7 @@ type(p_type *ptp; int *type_index;)
|
||||||
* integer_const.
|
* integer_const.
|
||||||
* Upperbound -1 means unsigned int or unsigned long.
|
* 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; }
|
[ 'A' integer_const(&ic1) { A_used = 1; }
|
||||||
| integer_const(&ic1)
|
| integer_const(&ic1)
|
||||||
]
|
]
|
||||||
|
@ -373,16 +373,16 @@ type(p_type *ptp; int *type_index;)
|
||||||
/* array; first type is bound type, next type
|
/* array; first type is bound type, next type
|
||||||
* is element 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); }
|
{ *ptp = array_type(t1, t2); }
|
||||||
|
|
|
|
||||||
/* structure type */
|
/* structure type */
|
||||||
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
|
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
|
||||||
structure_type(tp)
|
structure_type(tp, sy)
|
||||||
|
|
|
|
||||||
/* union type */
|
/* union type */
|
||||||
'u' { tp = new_type(); tp->ty_class = T_UNION; }
|
'u' { tp = new_type(); tp->ty_class = T_UNION; }
|
||||||
structure_type(tp)
|
structure_type(tp, sy)
|
||||||
|
|
|
|
||||||
/* enumeration type */
|
/* enumeration type */
|
||||||
'e' { tp = new_type(); tp->ty_class = T_ENUM; }
|
'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 = new_type(); tp->ty_class =T_POINTER;
|
||||||
tp->ty_size = pointer_size;
|
tp->ty_size = pointer_size;
|
||||||
}
|
}
|
||||||
type(&(tp->ty_ptrto), (int *) 0)
|
type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0)
|
||||||
|
|
|
|
||||||
/* function type */
|
/* function type */
|
||||||
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||||
tp->ty_size = pointer_size;
|
tp->ty_size = pointer_size;
|
||||||
}
|
}
|
||||||
type(&(tp->ty_retval), (int *) 0)
|
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
|
||||||
/*
|
/*
|
||||||
[ %prefer
|
[ %prefer
|
||||||
',' param_list(tp)
|
',' param_list(tp)
|
||||||
|
@ -410,7 +410,7 @@ type(p_type *ptp; int *type_index;)
|
||||||
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||||
tp->ty_size = pointer_size;
|
tp->ty_size = pointer_size;
|
||||||
}
|
}
|
||||||
type(&(tp->ty_retval), (int *) 0)
|
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
|
||||||
',' param_list(tp)
|
',' param_list(tp)
|
||||||
|
|
|
|
||||||
/* another procedure type */
|
/* another procedure type */
|
||||||
|
@ -425,7 +425,7 @@ type(p_type *ptp; int *type_index;)
|
||||||
* the second one represents the low bound
|
* the second one represents the low bound
|
||||||
*/
|
*/
|
||||||
'S' { tp = new_type(); tp->ty_class = T_SET; }
|
'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_size)) ';'
|
||||||
integer_const(&(tp->ty_setlow)) ';'
|
integer_const(&(tp->ty_setlow)) ';'
|
||||||
|
@ -435,9 +435,9 @@ type(p_type *ptp; int *type_index;)
|
||||||
|
|
|
|
||||||
/* file type of Pascal */
|
/* file type of Pascal */
|
||||||
'L' { tp = new_type(); tp->ty_class = T_FILE; }
|
'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 &&
|
{ if (type_index &&
|
||||||
*ptp == incomplete_type &&
|
*ptp == incomplete_type &&
|
||||||
type_index[0] == last_index[0] &&
|
type_index[0] == last_index[0] &&
|
||||||
|
@ -449,19 +449,18 @@ type(p_type *ptp; int *type_index;)
|
||||||
{ if (! *ptp) *ptp = tp; }
|
{ if (! *ptp) *ptp = tp; }
|
||||||
;
|
;
|
||||||
|
|
||||||
structure_type(register p_type tp;)
|
structure_type(register p_type tp; p_symbol sy;)
|
||||||
{ register struct fields *fldp;
|
{ register struct fields *fldp;
|
||||||
register p_symbol s;
|
char *str;
|
||||||
}
|
}
|
||||||
:
|
:
|
||||||
integer_const(&(tp->ty_size)) /* size in bytes */
|
integer_const(&(tp->ty_size)) /* size in bytes */
|
||||||
{ open_scope((p_symbol) 0, 0); }
|
{ open_scope(sy, 0);
|
||||||
[ { fldp = get_field_space(tp); }
|
if (sy) sy->sy_name.nm_scope = CurrentScope;
|
||||||
name(&(fldp->fld_name))
|
|
||||||
{ s = NewSymbol(fldp->fld_name, CurrentScope, FIELD, currnam);
|
|
||||||
s->sy_field = fldp;
|
|
||||||
}
|
}
|
||||||
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_pos)) ',' /* offset in bits */
|
||||||
integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
|
integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
|
||||||
]*
|
]*
|
||||||
|
@ -504,7 +503,7 @@ param_list(p_type t;)
|
||||||
| 'v' { p->par_kind = 'v'; }
|
| 'v' { p->par_kind = 'v'; }
|
||||||
| 'i' { p->par_kind = 'i'; }
|
| 'i' { p->par_kind = 'i'; }
|
||||||
]
|
]
|
||||||
type(&(p->par_type), (int *) 0) ';'
|
type(&(p->par_type), (int *) 0, (p_symbol) 0) ';'
|
||||||
{ t->ty_nbparams +=
|
{ t->ty_nbparams +=
|
||||||
param_size(p->par_type, p->par_kind);
|
param_size(p->par_type, p->par_kind);
|
||||||
p++;
|
p++;
|
||||||
|
@ -638,15 +637,23 @@ DBSlex()
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct fields *
|
static struct fields *
|
||||||
get_field_space(tp)
|
get_field_space(tp, s)
|
||||||
register p_type tp;
|
register p_type tp;
|
||||||
|
char *s;
|
||||||
{
|
{
|
||||||
|
register struct fields *p;
|
||||||
|
p_symbol sy;
|
||||||
|
|
||||||
if (! (tp->ty_nfields & 07)) {
|
if (! (tp->ty_nfields & 07)) {
|
||||||
tp->ty_fields = (struct fields *)
|
tp->ty_fields = (struct fields *)
|
||||||
Realloc((char *) tp->ty_fields,
|
Realloc((char *) tp->ty_fields,
|
||||||
(tp->ty_nfields+8)*sizeof(struct 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
|
static
|
||||||
|
|
|
@ -99,7 +99,7 @@ DbxRead(f)
|
||||||
saw_code = 0;
|
saw_code = 0;
|
||||||
sym = add_file(n->on_mptr);
|
sym = add_file(n->on_mptr);
|
||||||
|
|
||||||
if (! currfile) newfile(sym->sy_idf);
|
if (! listfile) newfile(sym->sy_idf);
|
||||||
open_scope(sym, 0);
|
open_scope(sym, 0);
|
||||||
sym->sy_file->f_scope = CurrentScope;
|
sym->sy_file->f_scope = CurrentScope;
|
||||||
FileScope = 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 *fopen();
|
||||||
extern FILE *db_out;
|
extern FILE *db_out;
|
||||||
extern t_lineno currline;
|
extern t_lineno currline;
|
||||||
#define window_size 21
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mk_filnm(dir, file, newname)
|
mk_filnm(dir, file, newname)
|
||||||
|
@ -55,6 +54,7 @@ open_file(fn, mode, ffn)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define window_size 21
|
||||||
/* Print a window of window_size lines around line "line" of
|
/* Print a window of window_size lines around line "line" of
|
||||||
file "file".
|
file "file".
|
||||||
*/
|
*/
|
||||||
|
@ -103,7 +103,7 @@ lines(file, l1, l2)
|
||||||
for (n = l1; n <= l2; n++) {
|
for (n = l1; n <= l2; n++) {
|
||||||
register int c;
|
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 {
|
do {
|
||||||
c = getc(f);
|
c = getc(f);
|
||||||
if (c != EOF) putc(c, db_out);
|
if (c != EOF) putc(c, db_out);
|
||||||
|
|
|
@ -7,14 +7,13 @@
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
#include "scope.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;
|
static char *progname;
|
||||||
char *AckObj;
|
char *AckObj;
|
||||||
char *AObj;
|
char *AObj;
|
||||||
char *dirs[] = { "", 0 };
|
char *dirs[] = { "", 0 };
|
||||||
FILE *db_out;
|
FILE *db_out;
|
||||||
FILE *db_in;
|
FILE *db_in;
|
||||||
t_lineno currline;
|
|
||||||
int debug;
|
int debug;
|
||||||
extern struct tokenname tkidf[];
|
extern struct tokenname tkidf[];
|
||||||
extern char *strindex();
|
extern char *strindex();
|
||||||
|
|
|
@ -19,24 +19,25 @@
|
||||||
#define MAXARG 128
|
#define MAXARG 128
|
||||||
|
|
||||||
extern char *strncpy();
|
extern char *strncpy();
|
||||||
|
extern struct idf *str2idf();
|
||||||
|
|
||||||
extern char *AObj;
|
extern char *AObj;
|
||||||
extern t_lineno currline;
|
|
||||||
extern FILE *db_out;
|
extern FILE *db_out;
|
||||||
extern int debug;
|
extern int debug;
|
||||||
extern struct idf *str2idf();
|
|
||||||
extern long pointer_size;
|
extern long pointer_size;
|
||||||
|
|
||||||
static int child_pid; /* process id of child */
|
static int child_pid; /* process id of child */
|
||||||
static int to_child, from_child; /* file descriptors for communication */
|
static int to_child, from_child; /* file descriptors for communication */
|
||||||
static int child_status;
|
static int child_status;
|
||||||
static int restoring;
|
static int restoring;
|
||||||
|
static int fild1[2], fild2[2]; /* pipe file descriptors */
|
||||||
|
|
||||||
int db_ss;
|
int db_ss;
|
||||||
|
t_lineno currline, listline;
|
||||||
|
|
||||||
static int catch_sigpipe();
|
static int catch_sigpipe();
|
||||||
static int stopped();
|
static int stopped();
|
||||||
static int uputm(), ugetm();
|
static int uputm(), ugetm();
|
||||||
static int fild1[2], fild2[2]; /* pipe file descriptors */
|
|
||||||
|
|
||||||
int
|
int
|
||||||
init_run()
|
init_run()
|
||||||
|
@ -289,10 +290,8 @@ stopped(s, a)
|
||||||
if (s) {
|
if (s) {
|
||||||
fprintf(db_out, "%s ", s);
|
fprintf(db_out, "%s ", s);
|
||||||
pos = print_position((t_addr) a, 1);
|
pos = print_position((t_addr) a, 1);
|
||||||
newfile(str2idf(pos->filename, 1));
|
|
||||||
currline = pos->lineno;
|
|
||||||
fputs("\n", db_out);
|
fputs("\n", db_out);
|
||||||
lines(currfile->sy_file, (int)currline, (int)currline);
|
list_position(pos);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
#include "operator.h"
|
#include "operator.h"
|
||||||
|
|
||||||
p_symbol currfile;
|
p_symbol currfile, listfile;
|
||||||
|
|
||||||
extern FILE *db_out;
|
extern FILE *db_out;
|
||||||
|
|
||||||
|
@ -141,6 +141,11 @@ def_scope(s)
|
||||||
case PROC:
|
case PROC:
|
||||||
case FUNCTION:
|
case FUNCTION:
|
||||||
case MODULE:
|
case MODULE:
|
||||||
|
case TYPE:
|
||||||
|
case VAR:
|
||||||
|
case REGVAR:
|
||||||
|
case LOCVAR:
|
||||||
|
case VARPAR:
|
||||||
return s->sy_name.nm_scope;
|
return s->sy_name.nm_scope;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -163,7 +168,8 @@ consistent(p, sc)
|
||||||
|
|
||||||
switch(p->t_oper) {
|
switch(p->t_oper) {
|
||||||
case OP_NAME:
|
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) {
|
if (sym) {
|
||||||
target_sc = def_scope(sym);
|
target_sc = def_scope(sym);
|
||||||
while (sc && sc != target_sc) {
|
while (sc && sc != target_sc) {
|
||||||
|
@ -175,7 +181,7 @@ consistent(p, sc)
|
||||||
|
|
||||||
case OP_SELECT:
|
case OP_SELECT:
|
||||||
arg = p->t_args[1];
|
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) {
|
if (sym) {
|
||||||
target_sc = def_scope(sym);
|
target_sc = def_scope(sym);
|
||||||
while (sc && sc != target_sc) {
|
while (sc && sc != target_sc) {
|
||||||
|
@ -322,7 +328,6 @@ pr_sym(s)
|
||||||
do_find(p)
|
do_find(p)
|
||||||
p_tree p;
|
p_tree p;
|
||||||
{
|
{
|
||||||
p_symbol sym = 0;
|
|
||||||
register p_symbol s;
|
register p_symbol s;
|
||||||
p_tree arg;
|
p_tree arg;
|
||||||
|
|
||||||
|
@ -340,7 +345,6 @@ do_find(p)
|
||||||
arg = p->t_args[1];
|
arg = p->t_args[1];
|
||||||
assert(arg->t_oper == OP_NAME);
|
assert(arg->t_oper == OP_NAME);
|
||||||
s = arg->t_idf->id_def;
|
s = arg->t_idf->id_def;
|
||||||
sym = 0;
|
|
||||||
while (s) {
|
while (s) {
|
||||||
if (consistent(p, s->sy_scope)) {
|
if (consistent(p, s->sy_scope)) {
|
||||||
pr_sym(s);
|
pr_sym(s);
|
||||||
|
|
|
@ -56,4 +56,4 @@ typedef struct symbol {
|
||||||
extern p_symbol NewSymbol(), Lookup(), Lookfromscope(), add_file();
|
extern p_symbol NewSymbol(), Lookup(), Lookfromscope(), add_file();
|
||||||
extern p_symbol identify();
|
extern p_symbol identify();
|
||||||
|
|
||||||
extern p_symbol currfile;
|
extern p_symbol currfile, listfile;
|
||||||
|
|
|
@ -19,11 +19,13 @@
|
||||||
#include "expr.h"
|
#include "expr.h"
|
||||||
|
|
||||||
extern FILE *db_out;
|
extern FILE *db_out;
|
||||||
extern t_lineno currline;
|
extern t_lineno currline, listline;
|
||||||
extern long pointer_size;
|
extern long pointer_size;
|
||||||
extern char *strrindex();
|
extern char *strrindex();
|
||||||
|
|
||||||
p_tree run_command;
|
p_tree run_command;
|
||||||
|
t_lineno list_line;
|
||||||
|
|
||||||
|
|
||||||
/*VARARGS1*/
|
/*VARARGS1*/
|
||||||
p_tree
|
p_tree
|
||||||
|
@ -104,6 +106,55 @@ freenode(p)
|
||||||
free_tree(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)
|
print_node(p, top_level)
|
||||||
register p_tree p;
|
register p_tree p;
|
||||||
{
|
{
|
||||||
|
@ -169,7 +220,7 @@ print_node(p, top_level)
|
||||||
break;
|
break;
|
||||||
case OP_WHERE:
|
case OP_WHERE:
|
||||||
fputs("where", db_out);
|
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;
|
break;
|
||||||
case OP_CONT:
|
case OP_CONT:
|
||||||
fputs("cont", db_out);
|
fputs("cont", db_out);
|
||||||
|
@ -301,11 +352,36 @@ eval(p)
|
||||||
do_list(p)
|
do_list(p)
|
||||||
p_tree p;
|
p_tree p;
|
||||||
{
|
{
|
||||||
if (currfile) {
|
int l1, l2;
|
||||||
lines(currfile->sy_file,
|
|
||||||
p->t_args[0] ? (int) p->t_args[0]->t_ival : (int) currline-4,
|
if (! p->t_args[0]) {
|
||||||
p->t_args[1] ? (int) p->t_args[1]->t_ival : (int) currline+5);
|
l1 = listline;
|
||||||
currline = p->t_args[1] ? p->t_args[1]->t_ival + 1 : currline + 10;
|
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");
|
else fprintf(db_out, "no current file\n");
|
||||||
}
|
}
|
||||||
|
@ -316,7 +392,7 @@ do_file(p)
|
||||||
if (p->t_args[0]) {
|
if (p->t_args[0]) {
|
||||||
newfile(p->t_args[0]->t_idf);
|
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");
|
else fprintf(db_out, "no current file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,69 +401,20 @@ newfile(id)
|
||||||
{
|
{
|
||||||
register p_symbol sym = Lookup(id, PervasiveScope, FILESYM);
|
register p_symbol sym = Lookup(id, PervasiveScope, FILESYM);
|
||||||
|
|
||||||
if (currfile != sym) currline = 1;
|
if (listfile != sym) listline = 1;
|
||||||
currfile = sym;
|
listfile = sym;
|
||||||
if (! currfile) {
|
if (! listfile) {
|
||||||
currline = 1;
|
listline = 1;
|
||||||
currfile = add_file(id->id_text);
|
listfile = add_file(id->id_text);
|
||||||
currfile->sy_file->f_scope = FileScope;
|
listfile->sy_file->f_scope = FileScope;
|
||||||
}
|
}
|
||||||
find_language(strrindex(id->id_text, '.'));
|
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)
|
do_stop(p)
|
||||||
p_tree 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) {
|
if (a == ILL_ADDR) {
|
||||||
return;
|
return;
|
||||||
|
@ -410,7 +437,7 @@ do_trace(p)
|
||||||
|
|
||||||
p->t_address = NO_ADDR;
|
p->t_address = NO_ADDR;
|
||||||
if (p->t_args[0]) {
|
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 (a == ILL_ADDR) return;
|
||||||
if (p->t_args[0]->t_oper == OP_AT) {
|
if (p->t_args[0]->t_oper == OP_AT) {
|
||||||
e = a;
|
e = a;
|
||||||
|
@ -542,7 +569,7 @@ do_delete(p)
|
||||||
if (p) switch(p->t_oper) {
|
if (p) switch(p->t_oper) {
|
||||||
case OP_WHEN:
|
case OP_WHEN:
|
||||||
case OP_STOP: {
|
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) {
|
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||||
set_or_clear_breakpoint(a, CLRBP);
|
set_or_clear_breakpoint(a, CLRBP);
|
||||||
|
@ -550,7 +577,7 @@ do_delete(p)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_TRACE: {
|
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) {
|
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||||
t_addr e;
|
t_addr e;
|
||||||
|
@ -642,16 +669,20 @@ perform(p, a)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
list_position(get_position_from_addr(a));
|
||||||
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]);
|
if (p->t_args[2]) do_print(p->t_args[2]);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
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