Initial version
This commit is contained in:
parent
f614fc6dc3
commit
dbf9a060c2
141
util/grind/Amakefile
Normal file
141
util/grind/Amakefile
Normal file
|
@ -0,0 +1,141 @@
|
|||
AMAKELIB = { . , /usr/local/lib/amake } ;
|
||||
|
||||
%include ack-defs.amk ;
|
||||
%include common.amk ;
|
||||
%include cc_hh_tools.amk ;
|
||||
%include tok_tools.amk ;
|
||||
%include op_tools.amk ;
|
||||
%include char_tools.amk ;
|
||||
%include LLgen.amk ;
|
||||
%include cc-c.amk ;
|
||||
%include loader.amk ;
|
||||
%include lint.amk ;
|
||||
|
||||
%default grind ;
|
||||
|
||||
TOKENNAMES = tokenname.c [
|
||||
gen_tokens,
|
||||
cc-dest = symbol2str.c,
|
||||
LL-dest = tokenfile.g
|
||||
];
|
||||
|
||||
DBS_LLTARGETS = {
|
||||
dbx_string.c[type=C-src],
|
||||
DBSpars.c[type=C-src],
|
||||
DBSpars.h[type=C-incl]
|
||||
} ;
|
||||
|
||||
DBS_LLSRC = {
|
||||
dbx_string.g
|
||||
} ;
|
||||
|
||||
CMD_LLTARGETS = {
|
||||
tokenfile.c[type=C-src],
|
||||
commands.c[type=C-src],
|
||||
Lpars.c[type=C-src],
|
||||
Lpars.h[type=C-incl]
|
||||
} ;
|
||||
|
||||
CMD_LLSRC = {
|
||||
tokenname.c,
|
||||
commands.g
|
||||
} ;
|
||||
|
||||
GENNEXTSRC = {
|
||||
file.h[type=C-incl],
|
||||
next.c[type=C-src]
|
||||
} ;
|
||||
|
||||
CSRC = {
|
||||
dbxread.c,
|
||||
main.c,
|
||||
list.c,
|
||||
tree.c,
|
||||
expr.c,
|
||||
position.c,
|
||||
idf.c,
|
||||
run.c,
|
||||
dump.c,
|
||||
symbol.c,
|
||||
print.c,
|
||||
value.c,
|
||||
type.c,
|
||||
rd.c,
|
||||
modula-2.c
|
||||
} ;
|
||||
|
||||
HSRC = {
|
||||
tokenname.h,
|
||||
operator.h,
|
||||
class.h,
|
||||
position.h,
|
||||
idf.h,
|
||||
message.h,
|
||||
avl.h,
|
||||
scope.h,
|
||||
langdep.h,
|
||||
sizes.h,
|
||||
rd.h
|
||||
} ;
|
||||
|
||||
HHSRC = {
|
||||
file.hh,
|
||||
type.hh,
|
||||
symbol.hh,
|
||||
tree.hh,
|
||||
avl.cc,
|
||||
scope.cc,
|
||||
itemlist.cc,
|
||||
langdep.cc
|
||||
} ;
|
||||
|
||||
LIBRARIES = {
|
||||
$EMHOME/modules/lib/libassert.a,
|
||||
$EMHOME/modules/lib/liballoc.a,
|
||||
$EMHOME/modules/lib/malloc.o,
|
||||
$EMHOME/modules/lib/libstring.a,
|
||||
$EMHOME/modules/lib/libobject.a,
|
||||
$EMHOME/modules/lib/libsystem.a
|
||||
} ;
|
||||
|
||||
DBFLAGS = { -g, -DDEBUG } ;
|
||||
PROFFLAGS = { } ;
|
||||
|
||||
LDFLAGS = {
|
||||
-Bstatic,
|
||||
$PROFFLAGS,
|
||||
$DBFLAGS
|
||||
} ;
|
||||
|
||||
INCLUDES = {
|
||||
-I$EMHOME/modules/h,
|
||||
-I$EMHOME/modules/pkg,
|
||||
-I$EMHOME/h
|
||||
} ;
|
||||
|
||||
CFLAGS = {
|
||||
$INCLUDES,
|
||||
$PROFFLAGS,
|
||||
$DBFLAGS
|
||||
} ;
|
||||
|
||||
LINTFLAGS = {
|
||||
$INCLUDES
|
||||
} ;
|
||||
|
||||
%cluster {
|
||||
%targets $DBS_LLTARGETS ;
|
||||
%sources $DBS_LLSRC ;
|
||||
%use LLgen(prefix => DBS) ;
|
||||
} ;
|
||||
|
||||
%cluster {
|
||||
%targets lint.out[type = lint-output];
|
||||
%sources $CMD_LLSRC + $CSRC + $DBS_LLTARGETS + $HHSRC + char.ct + operators.ot ;
|
||||
%use lint(realdest => lint.out) ;
|
||||
} ;
|
||||
|
||||
%cluster {
|
||||
%targets grind[type = program];
|
||||
%sources $CMD_LLSRC + $CSRC + $DBS_LLTARGETS + $HHSRC + char.ct + operators.ot ;
|
||||
} ;
|
40
util/grind/LLgen.amk
Normal file
40
util/grind/LLgen.amk
Normal file
|
@ -0,0 +1,40 @@
|
|||
# LLgen: LL(1) parser generator
|
||||
# variables: LLGEN, LLFLAGS
|
||||
|
||||
# tool definition for the new version of LLgen that allows for more than
|
||||
# one parser in one program. Unfortunately, for historical reasons there
|
||||
# is no proper default prefix for LLgen-generated files (LL.output versus
|
||||
# Lpars.[ch]). If LLgen would generate LLpars.[ch] instead of Lpars.[ch],
|
||||
# we could have a default value for prefix of 'LL', which would make
|
||||
# things a bit more simple.
|
||||
|
||||
%instance deftypesuffix(LLgen-src, '%.g') ;
|
||||
|
||||
%include ack-defs.amk;
|
||||
|
||||
%if (%not defined(LLGEN), {
|
||||
LLGEN = $EMHOME/bin/LLgen;
|
||||
});
|
||||
|
||||
%if (%not defined(LLFLAGS), {
|
||||
LLFLAGS = {};
|
||||
});
|
||||
|
||||
%tool LLgen (
|
||||
verbose: %boolean => %false;
|
||||
flags: %string %list => $LLFLAGS;
|
||||
prefix: %string => '';
|
||||
src: %in %list [type = LLgen-src];
|
||||
parser: %out %list [type = C-src]
|
||||
=> match($src) + if($prefix == '', Lpars.c, $prefix'pars.c');
|
||||
tokens: %out [type = C-incl, compare]
|
||||
=> if($prefix == '', Lpars.h, $prefix'pars.h');
|
||||
diagn: %out [type = text]
|
||||
=> if($prefix == '', LL.output, $prefix.output) %conform $verbose;
|
||||
cmd: %in [type = command] => $LLGEN;
|
||||
)
|
||||
{
|
||||
exec($cmd, args => if($verbose, {'-vvv'}, {}) + $flags + $src);
|
||||
echo({'LLgen ', $src, ' done'});
|
||||
};
|
||||
|
6
util/grind/PROBLEMS
Normal file
6
util/grind/PROBLEMS
Normal file
|
@ -0,0 +1,6 @@
|
|||
- front-end cannot generate DBX symbol table information for bit-fields,
|
||||
because it does not know about byte-order.
|
||||
- single stepping on a line by line basis is difficult if you use breakpoints.
|
||||
The problem is where to set the next breakpoint. One solution is to use
|
||||
single-stepping until we are at a different line, but this is probably
|
||||
extremely slow. Another solution is to adapt edb's method.
|
3
util/grind/READ_ME
Normal file
3
util/grind/READ_ME
Normal file
|
@ -0,0 +1,3 @@
|
|||
This is GRIND (GRind Is Not Dbx). This program is still being developed,
|
||||
so behaviour may change without notice.
|
||||
|
5
util/grind/ack-defs.amk
Normal file
5
util/grind/ack-defs.amk
Normal file
|
@ -0,0 +1,5 @@
|
|||
# definition of EMHOME
|
||||
|
||||
%if (%not defined(EMHOME), {
|
||||
EMHOME = /usr/proj/em/Work;
|
||||
});
|
245
util/grind/avl.cc
Normal file
245
util/grind/avl.cc
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
|
||||
/* Implementation of AVL-trees: trees in which the difference in depth
|
||||
of the left branch and the right branch is at most one.
|
||||
The difference in depth is indicated by a "balance" flag in each node:
|
||||
this flag has one of three values:
|
||||
. indicating that the left branch has the same depth as the right branch,
|
||||
+ indicating that the right branch is deeper,
|
||||
- indicating that the left branch is deeper.
|
||||
So, a node has the following structure:
|
||||
*/
|
||||
|
||||
struct avl_node {
|
||||
struct avl_node
|
||||
*left,
|
||||
*right; /* the left and right branches */
|
||||
char *info; /* pointer to information in this node */
|
||||
char balance; /* balance information described above */
|
||||
};
|
||||
|
||||
/* create definitions for new_avl_node() and free_avl_node() */
|
||||
/* STATICALLOCDEF "avl_node" 10 */
|
||||
|
||||
/* There is also a tree header, which contains the root of the tree and
|
||||
the address of a user-supplied comparison routine:
|
||||
*/
|
||||
|
||||
struct avl_tree {
|
||||
struct avl_node
|
||||
*root; /* root of the avl tree */
|
||||
int (*cmp)(); /* address of comparison routine */
|
||||
};
|
||||
/* create definitions for new_avl_tree() and free_avl_tree() */
|
||||
/* STATICALLOCDEF "avl_tree" 2 */
|
||||
|
||||
/* The next routine adds a node to an avl tree. It returns 1 if the
|
||||
tree got deeper.
|
||||
*/
|
||||
static int
|
||||
balance_add(ppsc, n, cmp)
|
||||
struct avl_node **ppsc; /* address of root */
|
||||
register char *n; /* user-supplied information */
|
||||
int (*cmp)(); /* user-supplied comparison routine */
|
||||
{
|
||||
register struct avl_node *psc = *ppsc, *qsc, *ssc;
|
||||
|
||||
if (! psc) {
|
||||
*ppsc = new_avl_node();
|
||||
(*ppsc)->balance = '.';
|
||||
(*ppsc)->info = n;
|
||||
return 1;
|
||||
}
|
||||
if ((*cmp)(n, psc->info) < 0) {
|
||||
if (balance_add(&(psc->left), n, cmp)) {
|
||||
/* left hand side got deeper */
|
||||
if (psc->balance == '+') {
|
||||
/* but the right hand side was deeper */
|
||||
psc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
if (psc->balance == '.') {
|
||||
/* but the right hand side was as deep */
|
||||
psc->balance = '-';
|
||||
return 1;
|
||||
}
|
||||
/* left hand side already was one deeper; re-organize */
|
||||
qsc = psc->left;
|
||||
if (qsc->balance == '-') {
|
||||
/* if left-hand side of left node was deeper,
|
||||
this node becomes the new root
|
||||
*/
|
||||
psc->balance = '.';
|
||||
qsc->balance = '.';
|
||||
psc->left = qsc->right;
|
||||
qsc->right = psc;
|
||||
*ppsc = qsc;
|
||||
return 0;
|
||||
}
|
||||
/* else the right node of the left node becomes the new root */
|
||||
ssc = qsc->right;
|
||||
psc->left = ssc->right;
|
||||
qsc->right = ssc->left;
|
||||
ssc->left = qsc;
|
||||
ssc->right = psc;
|
||||
*ppsc = ssc;
|
||||
if (ssc->balance == '.') {
|
||||
psc->balance = '.';
|
||||
qsc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
if (ssc->balance == '-') {
|
||||
psc->balance = '+';
|
||||
qsc->balance = '.';
|
||||
ssc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
psc->balance = '.';
|
||||
qsc->balance = '-';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (balance_add(&(psc->right), n, cmp)) {
|
||||
/* right hand side got deeper */
|
||||
if (psc->balance == '-') {
|
||||
/* but the left hand side was deeper */
|
||||
psc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
if (psc->balance == '.') {
|
||||
/* but the left hand side as deep */
|
||||
psc->balance = '+';
|
||||
return 1;
|
||||
}
|
||||
/* right hand side already was one deeper; re-organize */
|
||||
qsc = psc->right;
|
||||
if (qsc->balance == '+') {
|
||||
/* if right-hand side of left node was deeper,
|
||||
this node becomes the new root
|
||||
*/
|
||||
psc->balance = '.';
|
||||
qsc->balance = '.';
|
||||
psc->right = qsc->left;
|
||||
qsc->left = psc;
|
||||
*ppsc = qsc;
|
||||
return 0;
|
||||
}
|
||||
/* else the left node of the right node becomes the new root */
|
||||
ssc = qsc->left;
|
||||
psc->right = ssc->left;
|
||||
qsc->left = ssc->right;
|
||||
ssc->right = qsc;
|
||||
ssc->left = psc;
|
||||
*ppsc = ssc;
|
||||
if (ssc->balance == '.') {
|
||||
psc->balance = '.';
|
||||
qsc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
if (ssc->balance == '+') {
|
||||
psc->balance = '-';
|
||||
qsc->balance = '.';
|
||||
ssc->balance = '.';
|
||||
return 0;
|
||||
}
|
||||
psc->balance = '.';
|
||||
qsc->balance = '+';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern struct avl_tree *create_avl_tree(int (*cmp)());
|
||||
Returns a fresh avl_tree structure.
|
||||
*/
|
||||
struct avl_tree *
|
||||
create_avl_tree(cmp)
|
||||
int (*cmp)(); /* comparison routine */
|
||||
{
|
||||
register struct avl_tree *p = new_avl_tree();
|
||||
|
||||
p->cmp = cmp;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* extern add_to_avl_tree(struct avl_tree *tree, char *n);
|
||||
Adds the information indicated by 'n' to the avl_tree indicated by 'tree'
|
||||
*/
|
||||
add_to_avl_tree(tree, n)
|
||||
struct avl_tree *tree; /* tree to be added to */
|
||||
char *n; /* information */
|
||||
{
|
||||
balance_add(&(tree->root), n, tree->cmp);
|
||||
}
|
||||
|
||||
/* extern char *find_ngt(struct avl_tree *tree, char *n);
|
||||
Returns the information in the largest node that still compares <= to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
char *
|
||||
find_ngt(tree, n)
|
||||
struct avl_tree *tree; /* tree to be searched in */
|
||||
char *n; /* information to be compared with */
|
||||
{
|
||||
register struct avl_node *nd = tree->root, *lastnd = 0;
|
||||
|
||||
for (;;) {
|
||||
while (nd && (*tree->cmp)(nd->info, n) > 0) {
|
||||
nd = nd->left;
|
||||
}
|
||||
while (nd && (*tree->cmp)(nd->info, n) <= 0) {
|
||||
lastnd = nd;
|
||||
nd = nd->right;
|
||||
}
|
||||
if (! nd) break;
|
||||
}
|
||||
return lastnd ? lastnd->info : (char *) 0;
|
||||
}
|
||||
|
||||
/* extern char *find_nlt(struct avl_tree *tree, char *n);
|
||||
Returns the information in the largest node that still compares >= to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
char *
|
||||
find_nlt(tree, n)
|
||||
struct avl_tree *tree; /* tree to be searched in */
|
||||
char *n; /* information to be compared with */
|
||||
{
|
||||
register struct avl_node *nd = tree->root, *lastnd = 0;
|
||||
|
||||
for (;;) {
|
||||
while (nd && (*tree->cmp)(nd->info, n) < 0) {
|
||||
nd = nd->right;
|
||||
}
|
||||
while (nd && (*tree->cmp)(nd->info, n) >= 0) {
|
||||
lastnd = nd;
|
||||
nd = nd->left;
|
||||
}
|
||||
if (! nd) break;
|
||||
}
|
||||
return lastnd ? lastnd->info : (char *) 0;
|
||||
}
|
||||
|
||||
/* extern char *find_eq(struct avl_tree *tree, char *n);
|
||||
Returns the information in the node that compares equal to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
char *
|
||||
find_eq(tree, n)
|
||||
struct avl_tree *tree; /* tree to be searched in */
|
||||
char *n; /* information to be compared with */
|
||||
{
|
||||
register struct avl_node *nd = tree->root;
|
||||
|
||||
for (;;) {
|
||||
while (nd && (*tree->cmp)(nd->info, n) < 0) {
|
||||
nd = nd->right;
|
||||
}
|
||||
while (nd && (*tree->cmp)(nd->info, n) > 0) {
|
||||
nd = nd->left;
|
||||
}
|
||||
if (! nd) break;
|
||||
}
|
||||
return nd ? nd->info : (char *) 0;
|
||||
}
|
43
util/grind/avl.h
Normal file
43
util/grind/avl.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* AVL-trees: trees in which the difference in depth
|
||||
of the left branch and the right branch is at most one.
|
||||
Information in the nodes is represented by a pointer, which is to
|
||||
be supplied by the user. The user is also expected to supply a
|
||||
comparison routine for each AVL tree. This routine is offered two
|
||||
parameters, both pointers, and is expected to return:
|
||||
a negative number if the comparison result is <
|
||||
0 if the comparison result is =
|
||||
a positive number if the comparison result is >
|
||||
*/
|
||||
|
||||
typedef struct avl_tree *AVL_tree;
|
||||
|
||||
/* extern AVL_tree create_avl_tree(int (*cmp)());
|
||||
Returns a fresh avl_tree structure. 'cmp' will be used as comparison
|
||||
routine for this tree.
|
||||
*/
|
||||
extern AVL_tree create_avl_tree();
|
||||
|
||||
/* extern add_to_avl_tree(AVL_tree tree, char *n);
|
||||
Adds the information indicated by 'n' to the avl_tree indicated by 'tree'.
|
||||
*/
|
||||
extern add_to_avl_tree();
|
||||
|
||||
/* extern char *find_ngt(AVL_tree tree, char *n);
|
||||
Returns the information in the largest node that still compares <= to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
extern char *find_ngt();
|
||||
|
||||
/* extern char *find_nlt(AVL_tree tree, char *n);
|
||||
Returns the information in the largest node that still compares >= to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
extern char *find_nlt();
|
||||
|
||||
/* extern char *find_eq(AVL_tree tree, char *n);
|
||||
Returns the information in the node that compares equal to 'n',
|
||||
or 0 if not present.
|
||||
*/
|
||||
extern char *find_eq();
|
43
util/grind/cc_hh_tools.amk
Normal file
43
util/grind/cc_hh_tools.amk
Normal file
|
@ -0,0 +1,43 @@
|
|||
%instance deftypesuffix(hh-src, '%.hh') ;
|
||||
%instance deftypesuffix(cc-src, '%.cc') ;
|
||||
|
||||
ALLOCD = make.allocd;
|
||||
NEXT = make.next;
|
||||
|
||||
%tool allochd (
|
||||
hhsrc: %in [type = hh-src, persistent];
|
||||
hsrc: %out [type = C-incl] => match($hhsrc);
|
||||
prog: %in [type = command] => $ALLOCD;
|
||||
)
|
||||
{
|
||||
exec($prog, stdin => $hhsrc, stdout => $hsrc);
|
||||
echo({$hsrc ,'created'});
|
||||
};
|
||||
|
||||
|
||||
%tool alloccd (
|
||||
ccsrc: %in [type = cc-src, persistent];
|
||||
csrc: %out [type = C-src] => match($ccsrc);
|
||||
prog: %in [type = command] => $ALLOCD;
|
||||
)
|
||||
{
|
||||
exec($prog, stdin => $ccsrc, stdout => $csrc);
|
||||
echo({$csrc ,'created'});
|
||||
};
|
||||
|
||||
|
||||
# Possibly there's only one type of { cc-src, hh-src } available,
|
||||
# so introduce a new attribute.
|
||||
|
||||
%derive f[cc-or-hh-src] %when get($f, type) == cc-src
|
||||
%or get($f, type) == hh-src;
|
||||
|
||||
%tool mknext (
|
||||
cchhsrc: %in %list [cc-or-hh-src];
|
||||
next: %out [type = C-src] => next.c;
|
||||
prog: %in [type = command] => $NEXT;
|
||||
)
|
||||
{
|
||||
exec($prog, args => $cchhsrc, stdout => $next);
|
||||
echo({$next ,'created'});
|
||||
};
|
71
util/grind/char.ct
Normal file
71
util/grind/char.ct
Normal file
|
@ -0,0 +1,71 @@
|
|||
% character tables for debugger
|
||||
% $Header$
|
||||
%S257
|
||||
%F %s,
|
||||
%
|
||||
% CHARACTER CLASSES
|
||||
%
|
||||
%iSTGARB
|
||||
STSKIP: \t\013\014\015
|
||||
STNL:;\012
|
||||
STIDF:a-zA-Z_$
|
||||
STSTR:"'
|
||||
STDOT:.
|
||||
STNUM:0-9
|
||||
STSIMP:,<>{}:`
|
||||
%T#include "class.h"
|
||||
%Tchar tkclass[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% INIDF
|
||||
%
|
||||
%S129
|
||||
%C
|
||||
1:a-zA-Z0-9_$
|
||||
%Tchar inidf[] = {
|
||||
%F %s,
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% INEXT
|
||||
%
|
||||
%S129
|
||||
%C
|
||||
1:-#+{}~`@%^=|\\;:?/,a-zA-Z0-9_$.
|
||||
%Tchar inext[] = {
|
||||
%F %s,
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISDIG
|
||||
%
|
||||
%C
|
||||
1:0-9
|
||||
%Tchar isdig[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISHEX
|
||||
%
|
||||
%C
|
||||
1:A-F0-9
|
||||
%Tchar ishex[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISOCT
|
||||
%
|
||||
%C
|
||||
1:0-7
|
||||
%Tchar isoct[] = {
|
||||
%p
|
||||
%T};
|
||||
%
|
||||
% ISTOKEN
|
||||
%
|
||||
%C
|
||||
1:-abcefiprstuvxAEFGLMPQSTVX,;:+=()*
|
||||
%T char istoken[] = {
|
||||
%p
|
||||
%T};
|
24
util/grind/char_tools.amk
Normal file
24
util/grind/char_tools.amk
Normal file
|
@ -0,0 +1,24 @@
|
|||
# tabgen: tool definition for character table generator
|
||||
# variables: TABGEN, CHTAB
|
||||
|
||||
%include ack-defs.amk;
|
||||
|
||||
%if (%not defined(TABGEN), {
|
||||
TABGEN = $EMHOME/bin/tabgen;
|
||||
});
|
||||
|
||||
%if (%not defined(CHTAB), {
|
||||
CHTAB = chtab.c;
|
||||
});
|
||||
|
||||
%instance deftypesuffix(char_tab, '%.ct');
|
||||
|
||||
%tool gen_tab (
|
||||
chtab: %in [type = char_tab];
|
||||
cfile: %out [type = C-src] => $CHTAB;
|
||||
mktab: %in [type = command] => $TABGEN;
|
||||
)
|
||||
{
|
||||
exec($mktab, args => '-f' $chtab, stdout => $cfile);
|
||||
echo({$cfile, 'created'});
|
||||
};
|
48
util/grind/class.h
Normal file
48
util/grind/class.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* U S E O F C H A R A C T E R C L A S S E S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
/* As a starter, chars are divided into classes, according to which
|
||||
token they can be the start of.
|
||||
At present such a class number is supposed to fit in 4 bits.
|
||||
*/
|
||||
|
||||
#define class(ch) (tkclass[ch])
|
||||
|
||||
/* Being the start of a token is, fortunately, a mutual exclusive
|
||||
property, so, as there are less than 16 classes they can be
|
||||
packed in 4 bits.
|
||||
*/
|
||||
|
||||
#define STSKIP 0 /* spaces and so on: skipped characters */
|
||||
#define STNL 1 /* newline character(s): update linenumber etc. */
|
||||
#define STGARB 2 /* garbage ascii character: not allowed */
|
||||
#define STDOT 3 /* '.' can start a number, or be a separate token */
|
||||
#define STCOMP 4 /* this one can start a compound token */
|
||||
#define STIDF 5 /* being the initial character of an identifier */
|
||||
#define STCHAR 6 /* the starter of a character constant */
|
||||
#define STSTR 7 /* the starter of a string */
|
||||
#define STNUM 8 /* the starter of a numeric constant */
|
||||
#define STEOI 9 /* End-Of-Information mark */
|
||||
#define STSIMP 10 /* this character can occur as token */
|
||||
|
||||
/* But occurring inside a token is not, so we need 1 bit for each
|
||||
class. This is implemented as a collection of tables to speed up
|
||||
the decision whether a character has a special meaning.
|
||||
*/
|
||||
#define in_idf(ch) ((unsigned)ch < 0177 && inidf[ch])
|
||||
#define in_ext(ch) ((unsigned)ch < 0177 && inext[ch])
|
||||
#define is_oct(ch) ((unsigned)ch < 0177 && isoct[ch])
|
||||
#define is_dig(ch) ((unsigned)ch < 0177 && isdig[ch])
|
||||
#define is_hex(ch) ((unsigned)ch < 0177 && ishex[ch])
|
||||
#define is_token(ch) ((unsigned)ch < 0177 && istoken[ch])
|
||||
|
||||
extern char tkclass[];
|
||||
extern char inidf[], isoct[], isdig[], ishex[], inext[], istoken[];
|
590
util/grind/commands.g
Normal file
590
util/grind/commands.g
Normal file
|
@ -0,0 +1,590 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Command grammar */
|
||||
{
|
||||
#include <stdio.h>
|
||||
#include <alloc.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "ops.h"
|
||||
#include "class.h"
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include "symbol.h"
|
||||
#include "tree.h"
|
||||
|
||||
extern char *Salloc();
|
||||
extern t_lineno currline;
|
||||
extern FILE *db_in;
|
||||
|
||||
int errorgiven;
|
||||
int extended_charset = 0;
|
||||
jmp_buf jmpbuf;
|
||||
|
||||
static int init_del();
|
||||
static int skip_to_eol();
|
||||
|
||||
static struct token {
|
||||
int tokno;
|
||||
long ival;
|
||||
char *str;
|
||||
double fval;
|
||||
struct idf *idf;
|
||||
} tok, aside;
|
||||
|
||||
#define TOK tok.tokno
|
||||
#define ASIDE aside.tokno
|
||||
}
|
||||
%start Commands, commands;
|
||||
|
||||
%lexical LLlex;
|
||||
|
||||
commands
|
||||
{ p_tree com, lastcom = 0;
|
||||
}
|
||||
:
|
||||
{ if (! setjmp(jmpbuf)) {
|
||||
init_del();
|
||||
}
|
||||
else {
|
||||
skip_to_eol();
|
||||
goto prmpt;
|
||||
}
|
||||
}
|
||||
[ %persistent command_line(&com)
|
||||
{ if (com) {
|
||||
if (errorgiven) {
|
||||
freenode(com);
|
||||
com = 0;
|
||||
}
|
||||
if (lastcom && !in_status(lastcom) &&
|
||||
lastcom != run_command) {
|
||||
freenode(lastcom);
|
||||
lastcom = 0;
|
||||
}
|
||||
|
||||
if (com) {
|
||||
if (repeatable(com)) {
|
||||
lastcom = com;
|
||||
}
|
||||
eval(com);
|
||||
if (! repeatable(com) &&
|
||||
! in_status(com) &&
|
||||
com != run_command) {
|
||||
freenode(com);
|
||||
}
|
||||
}
|
||||
} else if (lastcom && ! errorgiven) eval(lastcom);
|
||||
}
|
||||
[ '\n' { prmpt: prompt(); }
|
||||
| ';'
|
||||
] { errorgiven = 0; }
|
||||
]*
|
||||
{ signal_child(SIGKILL); }
|
||||
;
|
||||
|
||||
command_line(p_tree *p;)
|
||||
:
|
||||
list_command(p)
|
||||
| file_command(p)
|
||||
| run_command(p)
|
||||
| stop_command(p)
|
||||
| when_command(p)
|
||||
| continue_command(p)
|
||||
| step_command(p)
|
||||
| next_command(p)
|
||||
| regs_command(p)
|
||||
| WHERE { *p = mknode(OP_WHERE); }
|
||||
| STATUS { *p = mknode(OP_STATUS); }
|
||||
| DUMP { *p = mknode(OP_DUMP); }
|
||||
| RESTORE INTEGER { *p = mknode(OP_RESTORE, tok.ival); }
|
||||
| delete_command(p)
|
||||
| print_command(p)
|
||||
| trace_command(p)
|
||||
| { *p = 0; }
|
||||
;
|
||||
|
||||
list_command(p_tree *p;)
|
||||
{ p_tree t1 = 0, t2 = 0; }
|
||||
:
|
||||
LIST
|
||||
[
|
||||
| lin_num(&t1)
|
||||
[ ',' lin_num(&t2)
|
||||
| { t2 = mknode(OP_INTEGER, t1->t_ival); }
|
||||
]
|
||||
] { *p = mknode(OP_LIST, t1, t2); }
|
||||
;
|
||||
|
||||
file_command(p_tree *p;)
|
||||
:
|
||||
XFILE { extended_charset = 1; }
|
||||
[ { *p = 0; }
|
||||
| name(p) { (*p)->t_idf = str2idf((*p)->t_str, 0); }
|
||||
] { *p = mknode(OP_FILE, *p);
|
||||
extended_charset = 0;
|
||||
}
|
||||
;
|
||||
|
||||
run_command(p_tree *p;)
|
||||
:
|
||||
RUN { extended_charset = 1; *p = 0; }
|
||||
args(p) { *p = mknode(OP_RUN, *p);
|
||||
extended_charset = 0;
|
||||
freenode(run_command);
|
||||
run_command = *p;
|
||||
}
|
||||
| RERUN { if (! run_command) {
|
||||
error("no run command given yet");
|
||||
}
|
||||
else *p = run_command;
|
||||
}
|
||||
;
|
||||
|
||||
stop_command(p_tree *p;)
|
||||
{ p_tree whr = 0, cond = 0; }
|
||||
:
|
||||
STOP
|
||||
where(&whr)?
|
||||
condition(&cond)? { if (! whr && ! cond) {
|
||||
error("no position or condition");
|
||||
*p = 0;
|
||||
}
|
||||
else *p = mknode(OP_STOP, whr, cond);
|
||||
}
|
||||
;
|
||||
|
||||
trace_command(p_tree *p;)
|
||||
{ p_tree whr = 0, cond = 0, exp = 0; }
|
||||
:
|
||||
TRACE
|
||||
[ ON expression(&exp) ]?
|
||||
where(&whr)?
|
||||
condition(&cond)? { *p = mknode(OP_TRACE, whr, cond, exp); }
|
||||
;
|
||||
|
||||
continue_command(p_tree *p;)
|
||||
{ long l; p_tree pos = 0; }
|
||||
:
|
||||
CONT
|
||||
[ INTEGER { l = tok.ival; }
|
||||
| { l = 1; }
|
||||
]
|
||||
position(&pos)?
|
||||
{ *p = mknode(OP_CONT, mknode(OP_INTEGER, l), pos); }
|
||||
;
|
||||
|
||||
when_command(p_tree *p;)
|
||||
{ p_tree whr = 0, cond = 0; }
|
||||
:
|
||||
WHEN
|
||||
where(&whr)?
|
||||
condition(&cond)?
|
||||
'{'
|
||||
command_line(p)
|
||||
[ ';' { *p = mknode(OP_LINK, *p, (p_tree) 0);
|
||||
p = &((*p)->t_args[1]);
|
||||
}
|
||||
command_line(p)
|
||||
]*
|
||||
'}'
|
||||
{ if (! whr && ! cond) {
|
||||
error("no position or condition");
|
||||
freenode(*p);
|
||||
*p = 0;
|
||||
}
|
||||
else *p = mknode(OP_WHEN, whr, cond, *p);
|
||||
}
|
||||
;
|
||||
|
||||
step_command(p_tree *p;)
|
||||
{ long l; }
|
||||
:
|
||||
STEP
|
||||
[ INTEGER { l = tok.ival; }
|
||||
| { l = 1; }
|
||||
] { *p = mknode(OP_STEP, l); }
|
||||
;
|
||||
|
||||
next_command(p_tree *p;)
|
||||
{ long l; }
|
||||
:
|
||||
NEXT
|
||||
[ INTEGER { l = tok.ival; }
|
||||
| { l = 1; }
|
||||
] { *p = mknode(OP_NEXT, l); }
|
||||
;
|
||||
|
||||
regs_command(p_tree *p;)
|
||||
{ long l; }
|
||||
:
|
||||
REGS
|
||||
[ INTEGER { l = tok.ival; }
|
||||
| { l = 0; }
|
||||
] { *p = mknode(OP_REGS, l); }
|
||||
;
|
||||
|
||||
delete_command(p_tree *p;)
|
||||
:
|
||||
DELETE
|
||||
INTEGER { *p = mknode(OP_DELETE, tok.ival); }
|
||||
;
|
||||
|
||||
print_command(p_tree *p;)
|
||||
:
|
||||
PRINT expression(p) { *p = mknode(OP_PRINT, *p);
|
||||
p = &((*p)->t_args[0]);
|
||||
}
|
||||
[ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0);
|
||||
p = &((*p)->t_args[1]);
|
||||
}
|
||||
expression(p)
|
||||
]*
|
||||
;
|
||||
|
||||
condition(p_tree *p;)
|
||||
:
|
||||
IF expression(p)
|
||||
;
|
||||
|
||||
where(p_tree *p;)
|
||||
:
|
||||
IN qualified_name(p) { *p = mknode(OP_IN, *p); }
|
||||
|
|
||||
position(p)
|
||||
;
|
||||
|
||||
expression(p_tree *p;)
|
||||
:
|
||||
qualified_name(p)
|
||||
;
|
||||
|
||||
position(p_tree *p;)
|
||||
{ p_tree lin;
|
||||
char *str;
|
||||
}
|
||||
:
|
||||
AT
|
||||
[ STRING { str = tok.str; }
|
||||
':'
|
||||
| { if (! currfile) str = 0;
|
||||
else str = currfile->sy_idf->id_text;
|
||||
}
|
||||
]
|
||||
lin_num(&lin) { *p = mknode(OP_AT, lin->t_ival, str);
|
||||
freenode(lin);
|
||||
}
|
||||
;
|
||||
|
||||
args(p_tree *p;)
|
||||
{ int first_time = 1; }
|
||||
:
|
||||
[ { if (! first_time) {
|
||||
*p = mknode(OP_LINK, *p, (p_tree) 0);
|
||||
p = &((*p)->t_args[1]);
|
||||
}
|
||||
first_time = 0;
|
||||
}
|
||||
arg(p)
|
||||
]*
|
||||
;
|
||||
|
||||
arg(p_tree *p;)
|
||||
:
|
||||
name(p)
|
||||
|
|
||||
'>' name(p) { (*p)->t_oper = OP_OUTPUT; }
|
||||
|
|
||||
'<' name(p) { (*p)->t_oper = OP_INPUT; }
|
||||
;
|
||||
|
||||
lin_num(p_tree *p;)
|
||||
:
|
||||
INTEGER { *p = mknode(OP_INTEGER, tok.ival); }
|
||||
;
|
||||
|
||||
qualified_name(p_tree *p;)
|
||||
:
|
||||
name(p)
|
||||
[ '`' { *p = mknode(OP_SELECT, *p, (p_tree) 0); }
|
||||
name(&((*p)->t_args[1]))
|
||||
]*
|
||||
;
|
||||
|
||||
name(p_tree *p;)
|
||||
:
|
||||
[ XFILE
|
||||
| LIST
|
||||
| RUN
|
||||
| RERUN
|
||||
| STOP
|
||||
| WHEN
|
||||
| AT
|
||||
| IN
|
||||
| IF
|
||||
| NAME
|
||||
| CONT
|
||||
| STEP
|
||||
| NEXT
|
||||
| REGS
|
||||
| WHERE
|
||||
| STATUS
|
||||
| PRINT
|
||||
| DELETE
|
||||
| DUMP
|
||||
| RESTORE
|
||||
| TRACE
|
||||
| ON
|
||||
] { *p = mknode(OP_NAME, tok.idf, tok.str); }
|
||||
;
|
||||
|
||||
{
|
||||
int
|
||||
LLlex()
|
||||
{
|
||||
register int c;
|
||||
|
||||
if (ASIDE) {
|
||||
tok = aside;
|
||||
ASIDE = 0;
|
||||
return TOK;
|
||||
}
|
||||
do {
|
||||
c = getc(db_in);
|
||||
} while (c != EOF && class(c) == STSKIP);
|
||||
if (c == EOF) return c;
|
||||
switch(class(c)) {
|
||||
case STSTR:
|
||||
TOK = get_string(c);
|
||||
break;
|
||||
case STIDF:
|
||||
TOK = get_name(c);
|
||||
break;
|
||||
case STDOT:
|
||||
c = getc(db_in);
|
||||
if (c == EOF || class(c) != STNUM) {
|
||||
ungetc(c,db_in);
|
||||
TOK = '.';
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case STNUM:
|
||||
TOK = get_number(c);
|
||||
break;
|
||||
case STNL:
|
||||
case STSIMP:
|
||||
TOK = c;
|
||||
break;
|
||||
default:
|
||||
error("illegal character '\\0%o'", c);
|
||||
return LLlex();
|
||||
}
|
||||
return TOK;
|
||||
}
|
||||
|
||||
int
|
||||
get_name(c)
|
||||
register int c;
|
||||
{
|
||||
char buf[512+1];
|
||||
register char *p = &buf[0];
|
||||
register struct idf *id;
|
||||
|
||||
do {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
} while ((extended_charset && in_ext(c)) || in_idf(c));
|
||||
ungetc(c, db_in);
|
||||
*p = 0;
|
||||
if (extended_charset) {
|
||||
tok.idf = 0;
|
||||
tok.str = Salloc(buf, (unsigned) (p - buf));
|
||||
return NAME;
|
||||
}
|
||||
id = str2idf(buf, 1);
|
||||
tok.idf = id;
|
||||
tok.str = id->id_text;
|
||||
return id->id_reserved ? id->id_reserved : NAME;
|
||||
}
|
||||
|
||||
static int
|
||||
quoted(ch)
|
||||
int ch;
|
||||
{
|
||||
/* quoted() replaces an escaped character sequence by the
|
||||
character meant.
|
||||
*/
|
||||
/* first char after backslash already in ch */
|
||||
if (!is_oct(ch)) { /* a quoted char */
|
||||
switch (ch) {
|
||||
case 'n':
|
||||
ch = '\n';
|
||||
break;
|
||||
case 't':
|
||||
ch = '\t';
|
||||
break;
|
||||
case 'b':
|
||||
ch = '\b';
|
||||
break;
|
||||
case 'r':
|
||||
ch = '\r';
|
||||
break;
|
||||
case 'f':
|
||||
ch = '\f';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { /* a quoted octal */
|
||||
register int oct = 0, cnt = 0;
|
||||
|
||||
do {
|
||||
oct = oct*8 + (ch-'0');
|
||||
ch = getc(db_in);
|
||||
} while (is_oct(ch) && ++cnt < 3);
|
||||
ungetc(ch, db_in);
|
||||
ch = oct;
|
||||
}
|
||||
return ch&0377;
|
||||
|
||||
}
|
||||
|
||||
int get_string(c)
|
||||
int c;
|
||||
{
|
||||
register int ch;
|
||||
char buf[512];
|
||||
register int len = 0;
|
||||
|
||||
while (ch = getc(db_in), ch != c) {
|
||||
if (ch == '\n') {
|
||||
error("newline in string");
|
||||
break;
|
||||
}
|
||||
if (ch == '\\') {
|
||||
ch = getc(db_in);
|
||||
ch = quoted(ch);
|
||||
}
|
||||
buf[len++] = ch;
|
||||
}
|
||||
buf[len++] = 0;
|
||||
tok.str = Salloc(buf, (unsigned) len);
|
||||
return STRING;
|
||||
}
|
||||
|
||||
static int
|
||||
val_in_base(c, base)
|
||||
register int c;
|
||||
{
|
||||
return is_dig(c)
|
||||
? c - '0'
|
||||
: base != 16
|
||||
? -1
|
||||
: is_hex(c)
|
||||
? (c - 'a' + 10) & 017
|
||||
: -1;
|
||||
}
|
||||
|
||||
int
|
||||
get_number(c)
|
||||
register int c;
|
||||
{
|
||||
char buf[512+1];
|
||||
register int base = 10;
|
||||
register char *p = &buf[0];
|
||||
register long val = 0;
|
||||
register int val_c;
|
||||
|
||||
if (c == '0') {
|
||||
/* check if next char is an 'x' or an 'X' */
|
||||
c = getc(db_in);
|
||||
if (c == 'x' || c == 'X') {
|
||||
base = 16;
|
||||
c = getc(db_in);
|
||||
}
|
||||
else base = 8;
|
||||
}
|
||||
while (val_c = val_in_base(c, base), val_c >= 0) {
|
||||
val = val * base + val_c;
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
}
|
||||
if (base == 16 || !((c == '.' || c == 'e' || c == 'E'))) {
|
||||
ungetc(c, db_in);
|
||||
tok.ival = val;
|
||||
return INTEGER;
|
||||
}
|
||||
if (c == '.') {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
}
|
||||
while (is_dig(c)) {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
if (c == '+' || c == '-') {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
}
|
||||
if (! is_dig(c)) {
|
||||
error("malformed floating constant");
|
||||
}
|
||||
while (is_dig(c)) {
|
||||
if (p - buf < 512) *p++ = c;
|
||||
c = getc(db_in);
|
||||
}
|
||||
}
|
||||
ungetc(c, db_in);
|
||||
*p++ = 0;
|
||||
if (p == &buf[512+1]) {
|
||||
error("floating point constant too long");
|
||||
}
|
||||
return REAL;
|
||||
}
|
||||
|
||||
extern char * symbol2str();
|
||||
|
||||
LLmessage(t)
|
||||
{
|
||||
if (t > 0) {
|
||||
if (! errorgiven) {
|
||||
error("%s missing before %s", symbol2str(t), symbol2str(TOK));
|
||||
}
|
||||
aside = tok;
|
||||
}
|
||||
else if (t == 0) {
|
||||
if (! errorgiven) {
|
||||
error("%s unexpected", symbol2str(TOK));
|
||||
}
|
||||
}
|
||||
else if (! errorgiven) {
|
||||
error("EOF expected");
|
||||
}
|
||||
errorgiven = 1;
|
||||
}
|
||||
|
||||
static int
|
||||
catch_del()
|
||||
{
|
||||
signal(SIGINT, catch_del);
|
||||
signal_child(SIGEMT);
|
||||
longjmp(jmpbuf, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
init_del()
|
||||
{
|
||||
signal(SIGINT, catch_del);
|
||||
}
|
||||
|
||||
static int
|
||||
skip_to_eol()
|
||||
{
|
||||
while (TOK != '\n' && TOK > 0) LLlex();
|
||||
wait_for_child("interrupted");
|
||||
}
|
||||
}
|
679
util/grind/dbx_string.g
Normal file
679
util/grind/dbx_string.g
Normal file
|
@ -0,0 +1,679 @@
|
|||
/* $Header$
|
||||
Grammar of a string of a debugger symbol table entry.
|
||||
*/
|
||||
|
||||
{
|
||||
#include <out.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
#include "class.h"
|
||||
#include "idf.h"
|
||||
|
||||
extern char *strindex();
|
||||
extern long str2long();
|
||||
extern double atof();
|
||||
extern int saw_code;
|
||||
extern long pointer_size;
|
||||
|
||||
static char *DbxPtr; /* current pointer in DBX string */
|
||||
static int AllowName; /* set if NAME legal at this point */
|
||||
static long ival;
|
||||
static double fval;
|
||||
static char *strval;
|
||||
static int last_index[2];
|
||||
static struct outname *currnam;
|
||||
|
||||
static struct literal *get_literal_space();
|
||||
static struct fields *get_field_space();
|
||||
static end_field();
|
||||
static char *string_val();
|
||||
}
|
||||
|
||||
%start DbxParser, debugger_string;
|
||||
|
||||
%prefix DBS;
|
||||
|
||||
%lexical DBSlex;
|
||||
|
||||
%onerror DBSonerror;
|
||||
|
||||
%token INTEGER, REAL, STRING, NAME;
|
||||
|
||||
debugger_string
|
||||
{ register p_symbol s;
|
||||
char *str;
|
||||
p_type tmp = 0;
|
||||
}
|
||||
:
|
||||
name(&str)
|
||||
[ /* constant name */
|
||||
{ s = NewSymbol(str, CurrentScope, CONST, currnam); }
|
||||
'c' const_name(s)
|
||||
|
||||
| /* type name */
|
||||
{ s = NewSymbol(str, CurrentScope, TYPE, currnam); }
|
||||
't' type_name(&(s->sy_type))
|
||||
|
||||
| /* tag name (only C?) */
|
||||
{ s = NewSymbol(str, CurrentScope, TAG, currnam); }
|
||||
'T' tag_name(s)
|
||||
|
||||
| /* end scope */
|
||||
'E' INTEGER
|
||||
{ close_scope(); }
|
||||
|
||||
| /* module begin */
|
||||
{ s = NewSymbol(str, CurrentScope, MODULE, currnam); }
|
||||
'M' INTEGER
|
||||
{ open_scope(s, 1);
|
||||
s->sy_name.nm_scope = CurrentScope;
|
||||
CurrentScope->sc_start = currnam->on_valu;
|
||||
CurrentScope->sc_proclevel = currnam->on_desc;
|
||||
add_scope_addr(CurrentScope);
|
||||
}
|
||||
|
||||
| /* external procedure */
|
||||
{ s = NewSymbol(str, PervasiveScope, PROC, currnam); }
|
||||
'P' routine(s)
|
||||
|
||||
| /* private procedure */
|
||||
{ s = NewSymbol(str, CurrentScope, PROC, currnam); }
|
||||
'Q' routine(s)
|
||||
|
||||
| /* external function */
|
||||
{ s = NewSymbol(str, PervasiveScope, FUNCTION, currnam); }
|
||||
'F' function(s)
|
||||
|
||||
| /* private function */
|
||||
{ s = NewSymbol(str, CurrentScope, FUNCTION, currnam); }
|
||||
'f' function(s)
|
||||
|
||||
| /* global variable, external */
|
||||
/* maybe we already know it; but we need
|
||||
the type information anyway for other
|
||||
types.
|
||||
*/
|
||||
{ s = Lookup(findidf(str), PervasiveScope, VAR);
|
||||
if (s) {
|
||||
tmp = s->sy_type;
|
||||
} else s = NewSymbol(str, PervasiveScope, VAR, currnam);
|
||||
}
|
||||
'G' type(&(s->sy_type), (int *) 0)
|
||||
{ if (tmp) s->sy_type = tmp; }
|
||||
|
||||
| /* static variable */
|
||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
||||
'S' type(&(s->sy_type), (int *) 0)
|
||||
|
||||
| /* static variable, local scope */
|
||||
{ s = NewSymbol(str, CurrentScope, VAR, currnam); }
|
||||
'V' type(&(s->sy_type), (int *) 0)
|
||||
|
||||
| /* register variable */
|
||||
{ s = NewSymbol(str, CurrentScope, REGVAR, currnam); }
|
||||
'r' type(&(s->sy_type), (int *) 0)
|
||||
|
||||
| /* value parameter */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
'p' type(&(s->sy_type), (int *) 0)
|
||||
{ add_param_type('p', s); }
|
||||
|
||||
| /* value parameter but address passed */
|
||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
||||
'i' type(&(s->sy_type), (int *) 0)
|
||||
{ add_param_type('i', s); }
|
||||
|
||||
| /* variable parameter */
|
||||
{ s = NewSymbol(str, CurrentScope, VARPAR, currnam); }
|
||||
'v' type(&(s->sy_type), (int *) 0)
|
||||
{ add_param_type('v', s); }
|
||||
|
||||
| /* local variable */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
type_name(&(s->sy_type))
|
||||
|
||||
| /* function result in Pascal; ignore ??? */
|
||||
{ s = NewSymbol(str, CurrentScope, LOCVAR, currnam); }
|
||||
'X' type_name(&(s->sy_type))
|
||||
]
|
||||
';'?
|
||||
;
|
||||
|
||||
name(char **s;)
|
||||
:
|
||||
/* anything up to a ':' */
|
||||
NAME { *s = strval; }
|
||||
;
|
||||
|
||||
const_name(p_symbol cst;)
|
||||
{ int type_index[2];
|
||||
long iconst;
|
||||
register char *p;
|
||||
}
|
||||
:
|
||||
'='
|
||||
[
|
||||
'b' integer_const(&(cst->sy_const.co_ival)) /* boolean */
|
||||
|
|
||||
'c' integer_const(&(cst->sy_const.co_ival)) /* character */
|
||||
{ cst->sy_type = char_type; }
|
||||
|
|
||||
'i' integer_const(&(cst->sy_const.co_ival)) /* integer */
|
||||
{ cst->sy_type = long_type; }
|
||||
|
|
||||
'r' real_const(&(cst->sy_const.co_rval)) /* real */
|
||||
{ cst->sy_type = double_type; }
|
||||
|
|
||||
's' string_const /* string */
|
||||
{ cst->sy_const.co_sval = string_val(strval);
|
||||
cst->sy_type = string_type;
|
||||
}
|
||||
|
|
||||
'e' type_index(type_index) ',' integer_const(&(cst->sy_const.co_ival))
|
||||
/* enumeration constant;
|
||||
* enumeration type, value
|
||||
*/
|
||||
{ cst->sy_type = *tp_lookup(type_index); }
|
||||
|
||||
|
|
||||
'S' type_index(type_index)
|
||||
{ cst->sy_type = *tp_lookup(type_index);
|
||||
cst->sy_const.co_setval = p =
|
||||
Malloc((unsigned) cst->sy_type->ty_size);
|
||||
}
|
||||
[ ',' integer_const(&iconst)
|
||||
{ *p++ = iconst; }
|
||||
]+
|
||||
/* set constant:
|
||||
* settype, values of the bytes
|
||||
* in the set.
|
||||
*/
|
||||
]
|
||||
;
|
||||
|
||||
integer_const(long *iconst;)
|
||||
{ int sign = 0; }
|
||||
:
|
||||
[ '+' | '-' { sign = 1; } ]?
|
||||
INTEGER { *iconst = sign ? -ival : ival; }
|
||||
;
|
||||
|
||||
real_const(double *f;)
|
||||
{ int sign = 0; }
|
||||
:
|
||||
[ '+' | '-' { sign = 1; } ]?
|
||||
REAL { *f = sign ? fval : -fval; }
|
||||
;
|
||||
|
||||
string_const
|
||||
:
|
||||
STRING /* has SINGLE quotes! */
|
||||
;
|
||||
|
||||
type_name(p_type *t;)
|
||||
{ int type_index[2]; p_type *p; }
|
||||
:
|
||||
type_index(type_index)
|
||||
[
|
||||
'='
|
||||
type(t, type_index)
|
||||
{ p = tp_lookup(type_index);
|
||||
if (*p && *p != incomplete_type) {
|
||||
if (!((*p)->ty_flags & T_CROSS))
|
||||
error("Redefining (%d,%d) %d",
|
||||
type_index[0],
|
||||
type_index[1],
|
||||
(*p)->ty_class);
|
||||
if (*t && *p != *t) free_type(*p);
|
||||
}
|
||||
if (*t) *p = *t;
|
||||
}
|
||||
|
|
||||
{ p = tp_lookup(type_index); }
|
||||
]
|
||||
{ if (*p == 0) *p = incomplete_type;
|
||||
*t = *p;
|
||||
}
|
||||
;
|
||||
|
||||
type_index(int *type_index;)
|
||||
:
|
||||
[
|
||||
INTEGER { type_index[0] = 0; type_index[1] = ival; }
|
||||
|
|
||||
'(' INTEGER { type_index[0] = ival; }
|
||||
',' INTEGER { type_index[1] = ival; }
|
||||
')'
|
||||
]
|
||||
{ last_index[0] = type_index[0];
|
||||
last_index[1] = type_index[1];
|
||||
}
|
||||
;
|
||||
|
||||
tag_name(p_symbol t;)
|
||||
{ int type_index[2]; p_type *p; }
|
||||
:
|
||||
type_index(type_index)
|
||||
'='
|
||||
type(&(t->sy_type), type_index)
|
||||
{ p = tp_lookup(type_index);
|
||||
if (*p && *p != incomplete_type) {
|
||||
if (!((*p)->ty_flags & T_CROSS))
|
||||
error("Redefining (%d,%d) %d",
|
||||
type_index[0],
|
||||
type_index[1],
|
||||
(*p)->ty_class);
|
||||
if (t->sy_type && *p != t->sy_type) {
|
||||
free_type(*p);
|
||||
}
|
||||
}
|
||||
if (t->sy_type) *p = t->sy_type;
|
||||
if (*p == 0) *p = incomplete_type;
|
||||
}
|
||||
;
|
||||
|
||||
function(p_symbol p;)
|
||||
:
|
||||
{ p->sy_type = new_type();
|
||||
p->sy_type->ty_class = T_PROCEDURE;
|
||||
p->sy_type->ty_size = pointer_size;
|
||||
}
|
||||
type(&(p->sy_type->ty_retval), (int *) 0)
|
||||
{ if (CurrentScope != FileScope &&
|
||||
saw_code) {
|
||||
/* if saw_code is not set, it is a nested
|
||||
procedure
|
||||
*/
|
||||
close_scope();
|
||||
}
|
||||
saw_code = 0;
|
||||
open_scope(p, 1);
|
||||
p->sy_name.nm_scope = CurrentScope;
|
||||
CurrentScope->sc_start = currnam->on_valu;
|
||||
add_scope_addr(CurrentScope);
|
||||
CurrentScope->sc_proclevel = currnam->on_desc;
|
||||
}
|
||||
;
|
||||
|
||||
routine(p_symbol p;)
|
||||
:
|
||||
{ p->sy_type = new_type();
|
||||
p->sy_type->ty_class = T_PROCEDURE;
|
||||
p->sy_type->ty_size = pointer_size;
|
||||
if (CurrentScope != FileScope &&
|
||||
saw_code) {
|
||||
/* if saw_code is not set, it is a nested
|
||||
procedure
|
||||
*/
|
||||
close_scope();
|
||||
}
|
||||
saw_code = 0;
|
||||
open_scope(p, 1);
|
||||
p->sy_name.nm_scope = CurrentScope;
|
||||
CurrentScope->sc_start = currnam->on_valu;
|
||||
add_scope_addr(CurrentScope);
|
||||
CurrentScope->sc_proclevel = currnam->on_desc;
|
||||
}
|
||||
INTEGER ';'
|
||||
type(&(p->sy_type->ty_retval), (int *) 0)
|
||||
;
|
||||
|
||||
type(p_type *ptp; int *type_index;)
|
||||
{ register p_type tp = 0;
|
||||
p_type t1, t2;
|
||||
long ic1, ic2;
|
||||
int A_used = 0;
|
||||
}
|
||||
: { *ptp = 0; }
|
||||
[
|
||||
/* type cross reference */
|
||||
/* these are used in C for references to a struct, union or
|
||||
* enum that has not been declared (yet)
|
||||
*/
|
||||
'x' { tp = new_type(); tp->ty_flags = T_CROSS; }
|
||||
[ 's' /* struct */
|
||||
{ tp->ty_class = T_STRUCT; }
|
||||
| 'u' /* union */
|
||||
{ tp->ty_class = T_UNION; }
|
||||
| 'e' /* enum */
|
||||
{ tp->ty_class = T_ENUM; }
|
||||
]
|
||||
{ AllowName = 1; }
|
||||
name(&(tp->ty_tag))
|
||||
|
|
||||
/* subrange */
|
||||
/* the integer_const's represent the lower and the upper bound.
|
||||
* A subrange type defined as subrange of itself is an integer type.
|
||||
* If the second integer_const == 0, but the first is not, we
|
||||
* have a floating point type with size equal to the first
|
||||
* integer_const.
|
||||
* Upperbound -1 means unsigned int or unsigned long.
|
||||
*/
|
||||
'r' type_name(&t1) ';'
|
||||
[ 'A' integer_const(&ic1) { A_used = 1; }
|
||||
| integer_const(&ic1)
|
||||
]
|
||||
';'
|
||||
[ 'A' integer_const(&ic2) { A_used |= 2; }
|
||||
| integer_const(&ic2)
|
||||
]
|
||||
{ *ptp = subrange_type(A_used,
|
||||
last_index,
|
||||
ic1,
|
||||
ic2,
|
||||
type_index);
|
||||
}
|
||||
|
|
||||
/* array; first type is bound type, next type
|
||||
* is element type
|
||||
*/
|
||||
'a' type(&t1, (int *) 0) ';' type(&t2, (int *) 0)
|
||||
{ *ptp = array_type(t1, t2); }
|
||||
|
|
||||
/* structure type */
|
||||
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
|
||||
structure_type(tp)
|
||||
|
|
||||
/* union type */
|
||||
'u' { tp = new_type(); tp->ty_class = T_UNION; }
|
||||
structure_type(tp)
|
||||
|
|
||||
/* enumeration type */
|
||||
'e' { tp = new_type(); tp->ty_class = T_ENUM; }
|
||||
enum_type(tp)
|
||||
|
|
||||
/* pointer type */
|
||||
'*' { tp = new_type(); tp->ty_class =T_POINTER;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_ptrto), (int *) 0)
|
||||
|
|
||||
/* function type */
|
||||
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_retval), (int *) 0)
|
||||
/*
|
||||
[ %prefer
|
||||
',' param_list(tp)
|
||||
|
|
||||
]
|
||||
*/
|
||||
|
|
||||
/* procedure type */
|
||||
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||
tp->ty_size = pointer_size;
|
||||
}
|
||||
type(&(tp->ty_retval), (int *) 0)
|
||||
',' param_list(tp)
|
||||
|
|
||||
/* another procedure type */
|
||||
'p' { tp = new_type(); tp->ty_class = T_PROCEDURE;
|
||||
tp->ty_size = pointer_size;
|
||||
tp->ty_retval = void_type;
|
||||
}
|
||||
param_list(tp)
|
||||
|
|
||||
/* set type */
|
||||
/* the first integer_const represents the size in bytes,
|
||||
* the second one represents the low bound
|
||||
*/
|
||||
'S' { tp = new_type(); tp->ty_class = T_SET; }
|
||||
type(&(tp->ty_setbase), (int *) 0) ';'
|
||||
[
|
||||
integer_const(&(tp->ty_size)) ';'
|
||||
integer_const(&(tp->ty_setlow)) ';'
|
||||
|
|
||||
{ set_bounds(tp); }
|
||||
]
|
||||
|
|
||||
/* file type of Pascal */
|
||||
'L' { tp = new_type(); tp->ty_class = T_FILE; }
|
||||
type(&(tp->ty_fileof), (int *) 0)
|
||||
|
|
||||
type_name(ptp)
|
||||
{ if (type_index &&
|
||||
*ptp == incomplete_type &&
|
||||
type_index[0] == last_index[0] &&
|
||||
type_index[1] == last_index[1]) {
|
||||
*ptp = void_type;
|
||||
}
|
||||
}
|
||||
]
|
||||
{ if (! *ptp) *ptp = tp; }
|
||||
;
|
||||
|
||||
structure_type(register p_type tp;)
|
||||
{ register struct fields *fldp; }
|
||||
:
|
||||
integer_const(&(tp->ty_size)) /* size in bytes */
|
||||
[ { fldp = get_field_space(tp); }
|
||||
name(&(fldp->fld_name))
|
||||
type(&(fldp->fld_type), (int *) 0) ','
|
||||
integer_const(&(fldp->fld_pos)) ',' /* offset in bits */
|
||||
integer_const(&(fldp->fld_bitsize)) ';' /* size in bits */
|
||||
]*
|
||||
';' { end_field(tp); }
|
||||
;
|
||||
|
||||
enum_type(register p_type tp;)
|
||||
{ register struct literal *litp;
|
||||
long maxval = 0;
|
||||
}
|
||||
:
|
||||
[ { litp = get_literal_space(tp);
|
||||
}
|
||||
name(&(litp->lit_name))
|
||||
integer_const(&(litp->lit_val)) ','
|
||||
{ if (maxval < litp->lit_val) maxval = litp->lit_val;
|
||||
AllowName = 1;
|
||||
}
|
||||
]*
|
||||
';' { end_literal(tp, maxval); }
|
||||
;
|
||||
|
||||
param_list(p_type t;)
|
||||
{ register struct param *p;
|
||||
long iconst;
|
||||
}
|
||||
:
|
||||
integer_const(&iconst) ';' /* number of parameters */
|
||||
{ t->ty_nparams = iconst;
|
||||
t->ty_params = p = (struct param *)
|
||||
Malloc((unsigned)(t->ty_nparams * sizeof(struct param)));
|
||||
}
|
||||
[
|
||||
[ 'p' { p->par_kind = 'p'; }
|
||||
| 'v' { p->par_kind = 'v'; }
|
||||
| 'i' { p->par_kind = 'i'; }
|
||||
]
|
||||
type(&(p->par_type), (int *) 0) ';'
|
||||
{ t->ty_nbparams +=
|
||||
param_size(p->par_type, p->par_kind);
|
||||
p++;
|
||||
}
|
||||
]*
|
||||
;
|
||||
|
||||
{
|
||||
static char *dbx_string;
|
||||
static char *DbxOldPtr;
|
||||
|
||||
struct outname *
|
||||
DbxString(n)
|
||||
struct outname *n;
|
||||
{
|
||||
currnam = n;
|
||||
DbxPtr = n->on_mptr;
|
||||
dbx_string = DbxPtr;
|
||||
AllowName = 1;
|
||||
DbxParser();
|
||||
return currnam;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
DBSmessage(n)
|
||||
{
|
||||
fatal("error in Dbx string \"%s\", DbxPtr = \"%s\", DbxOldPtr = \"%s\"",
|
||||
dbx_string,
|
||||
DbxPtr,
|
||||
DbxOldPtr);
|
||||
|
||||
}
|
||||
|
||||
DBSonerror(tk, p)
|
||||
int *p;
|
||||
{
|
||||
DbxPtr = DbxOldPtr;
|
||||
/* ??? if (DBSsymb < 0) {
|
||||
while (*p && *p != ';') p++;
|
||||
if (*p) DbxPtr = ";";
|
||||
return;
|
||||
}
|
||||
*/
|
||||
if (! tk) {
|
||||
while (*p && *p != NAME) p++;
|
||||
if (*p) {
|
||||
AllowName = 1;
|
||||
}
|
||||
}
|
||||
else if (tk == NAME) AllowName = 1;
|
||||
}
|
||||
|
||||
DBSlex()
|
||||
{
|
||||
register char *cp = DbxPtr;
|
||||
int allow_name = AllowName;
|
||||
register int c;
|
||||
|
||||
AllowName = 0;
|
||||
DbxOldPtr = cp;
|
||||
c = *cp;
|
||||
if (c == '\\' && *(cp+1) == '\0') {
|
||||
currnam++;
|
||||
cp = currnam->on_mptr;
|
||||
DbxOldPtr = cp;
|
||||
c = *cp;
|
||||
}
|
||||
if (! c) {
|
||||
DbxPtr = cp;
|
||||
return -1;
|
||||
}
|
||||
if ((! allow_name && is_token(c)) || c == ';') {
|
||||
DbxPtr = cp+1;
|
||||
return c;
|
||||
}
|
||||
if (is_dig(c)) {
|
||||
int retval = INTEGER;
|
||||
|
||||
while (++cp, is_dig(*cp)) /* nothing */;
|
||||
c = *cp;
|
||||
if (c == '.') {
|
||||
retval = REAL;
|
||||
while (++cp, is_dig(*cp)) /* nothing */;
|
||||
c = *cp;
|
||||
}
|
||||
if (c == 'e' || c == 'E') {
|
||||
char *oldcp = cp;
|
||||
|
||||
cp++;
|
||||
c = *cp;
|
||||
if (c == '-' || c == '+') {
|
||||
cp++;
|
||||
c = *cp;
|
||||
}
|
||||
if (is_dig(c)) {
|
||||
retval = REAL;
|
||||
while (++cp, is_dig(*cp)) /* nothing */;
|
||||
}
|
||||
else cp = oldcp;
|
||||
}
|
||||
c = *cp;
|
||||
*cp = 0;
|
||||
if (retval == INTEGER) {
|
||||
ival = str2long(DbxOldPtr, 10);
|
||||
}
|
||||
else {
|
||||
fval = atof(DbxOldPtr);
|
||||
}
|
||||
*cp = c;
|
||||
DbxPtr = cp;
|
||||
return retval;
|
||||
}
|
||||
if (c == '\'') {
|
||||
cp++;
|
||||
strval = cp;
|
||||
while ((c = *cp) && c != '\'') {
|
||||
if (c == '\\') cp++; /* backslash escapes next character */
|
||||
if (!(c = *cp)) break; /* but not a null byte */
|
||||
cp++;
|
||||
}
|
||||
if (! c) DBSmessage(0); /* no return */
|
||||
*cp = 0;
|
||||
DbxPtr = cp + 1;
|
||||
return STRING;
|
||||
}
|
||||
strval = cp;
|
||||
while ((c = *cp) && c != ':' && c != ',') cp++;
|
||||
DbxPtr = *cp ? cp+1 : cp;
|
||||
*cp = 0;
|
||||
return NAME;
|
||||
}
|
||||
|
||||
static struct fields *
|
||||
get_field_space(tp)
|
||||
register p_type tp;
|
||||
{
|
||||
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++];
|
||||
}
|
||||
|
||||
static
|
||||
end_field(tp)
|
||||
register p_type tp;
|
||||
{
|
||||
tp->ty_fields = (struct fields *)
|
||||
Realloc((char *) tp->ty_fields,
|
||||
tp->ty_nfields * sizeof(struct fields));
|
||||
}
|
||||
|
||||
static struct literal *
|
||||
get_literal_space(tp)
|
||||
register p_type tp;
|
||||
{
|
||||
if (! (tp->ty_nenums & 07)) {
|
||||
tp->ty_literals = (struct literal *)
|
||||
Realloc((char *) tp->ty_literals,
|
||||
(tp->ty_nenums+8)*sizeof(struct literal));
|
||||
}
|
||||
return &tp->ty_literals[tp->ty_nenums++];
|
||||
}
|
||||
|
||||
static char *
|
||||
string_val(s)
|
||||
char *s;
|
||||
{
|
||||
register char *ns = s, *os = s;
|
||||
register unsigned int i = 1;
|
||||
|
||||
for (;;) {
|
||||
if (!*os) break;
|
||||
i++;
|
||||
if (*os == '\\') {
|
||||
os++;
|
||||
*ns++ = *os++;
|
||||
}
|
||||
else *ns++ = *os++;
|
||||
}
|
||||
*ns = '\0';
|
||||
return Salloc(s, i);
|
||||
}
|
||||
|
||||
}
|
194
util/grind/dbxread.c
Normal file
194
util/grind/dbxread.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/* $Header$
|
||||
Read the symbol table from an ACK a.out format file.
|
||||
*/
|
||||
|
||||
#include <stb.h>
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "symbol.h"
|
||||
#include "idf.h"
|
||||
#include "scope.h"
|
||||
#include "rd.h"
|
||||
|
||||
extern char *Malloc();
|
||||
extern char *strindex();
|
||||
extern struct outname *DbxString();
|
||||
|
||||
int saw_code = 0;
|
||||
|
||||
static char *AckStrings; /* ACK a.out string table */
|
||||
static struct outname *AckNames; /* ACK a.out symbol table entries */
|
||||
static unsigned int NAckNames; /* Number of ACK symbol table entries */
|
||||
static struct outname *EndAckNames; /* &AckNames[NAckNames] */
|
||||
|
||||
/* Read the symbol table from file 'f', which is supposed to be an
|
||||
ACK a.out format file. Offer DBX strings to the DBX string parser.
|
||||
*/
|
||||
int
|
||||
DbxRead(f)
|
||||
char *f;
|
||||
{
|
||||
struct outhead h;
|
||||
register struct outname *n;
|
||||
register struct outname *line_file = 0;
|
||||
long OffsetStrings;
|
||||
int had_lbrac = 0;
|
||||
|
||||
/* Open file, read header, and check magic word */
|
||||
if (! rd_open(f)) {
|
||||
fatal("%s: not an ACK object file", f);
|
||||
}
|
||||
rd_ohead(&h);
|
||||
if (BADMAGIC(h) && h.oh_magic != O_CONVERTED) {
|
||||
fatal("%s: not an ACK object file", f);
|
||||
}
|
||||
|
||||
/* Allocate space for name table and read it */
|
||||
AckNames = (struct outname *)
|
||||
Malloc((unsigned)(sizeof(struct outname) * h.oh_nname));
|
||||
AckStrings = Malloc((unsigned) h.oh_nchar);
|
||||
rd_name(AckNames, h.oh_nname);
|
||||
rd_string(AckStrings, h.oh_nchar);
|
||||
|
||||
/* Adjust file offsets in name table to point at strings */
|
||||
OffsetStrings = OFF_CHAR(h);
|
||||
NAckNames = h.oh_nname;
|
||||
EndAckNames = &AckNames[h.oh_nname];
|
||||
for (n = EndAckNames; --n >= AckNames;) {
|
||||
if (n->on_foff) {
|
||||
if ((unsigned)(n->on_foff - OffsetStrings) >= h.oh_nchar) {
|
||||
fatal("%s: error in object file", f);
|
||||
}
|
||||
n->on_mptr = AckStrings + (n->on_foff - OffsetStrings);
|
||||
}
|
||||
else n->on_mptr = 0;
|
||||
}
|
||||
|
||||
/* Offer strings to the DBX string parser if they contain a ':'.
|
||||
Also offer filename-line number information to add_position_addr().
|
||||
Here, the order may be important.
|
||||
*/
|
||||
for (n = &AckNames[0]; n < EndAckNames; n++) {
|
||||
int tp = n->on_type >> 8;
|
||||
register p_symbol sym;
|
||||
|
||||
if (tp & (S_STB >> 8)) {
|
||||
switch(tp) {
|
||||
#ifdef N_BINCL
|
||||
case N_BINCL:
|
||||
n->on_valu = (long) line_file;
|
||||
line_file = n;
|
||||
break;
|
||||
case N_EINCL:
|
||||
if (line_file) {
|
||||
line_file = (struct outname *) line_file->on_valu;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case N_SO:
|
||||
if (n->on_mptr[strlen(n->on_mptr)-1] == '/') {
|
||||
/* another N_SO follows ... */
|
||||
break;
|
||||
}
|
||||
while (CurrentScope != PervasiveScope) {
|
||||
close_scope();
|
||||
}
|
||||
saw_code = 0;
|
||||
sym = add_file(n->on_mptr);
|
||||
|
||||
if (! currfile) newfile(sym->sy_idf);
|
||||
open_scope(sym, 0);
|
||||
sym->sy_file->f_scope = CurrentScope;
|
||||
FileScope = CurrentScope;
|
||||
clean_tp_tab();
|
||||
/* fall through */
|
||||
case N_SOL:
|
||||
if (! line_file) line_file = n;
|
||||
else line_file->on_mptr = n->on_mptr;
|
||||
break;
|
||||
case N_MAIN:
|
||||
newfile(FileScope->sc_definedby->sy_idf);
|
||||
break;
|
||||
case N_SLINE:
|
||||
assert(line_file);
|
||||
if (! saw_code && !CurrentScope->sc_bp_opp) {
|
||||
CurrentScope->sc_bp_opp = n->on_valu;
|
||||
if (! CurrentScope->sc_start) {
|
||||
CurrentScope->sc_start = n->on_valu;
|
||||
if (CurrentScope->sc_has_activation_record) {
|
||||
add_scope_addr(CurrentScope);
|
||||
}
|
||||
}
|
||||
}
|
||||
saw_code = 1;
|
||||
add_position_addr(line_file->on_mptr, n);
|
||||
break;
|
||||
case N_LBRAC: /* block, desc = nesting level */
|
||||
if (had_lbrac) {
|
||||
open_scope((p_symbol) 0, 0);
|
||||
saw_code = 0;
|
||||
}
|
||||
else {
|
||||
register p_scope sc =
|
||||
get_scope_from_addr(n->on_valu);
|
||||
|
||||
if (!sc || sc->sc_bp_opp) {
|
||||
had_lbrac = 1;
|
||||
}
|
||||
else CurrentScope = sc;
|
||||
}
|
||||
break;
|
||||
#ifdef N_SCOPE
|
||||
case N_SCOPE:
|
||||
if (n->on_mptr && strindex(n->on_mptr, ':')) {
|
||||
n = DbxString(n);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case N_RBRAC: /* end block, desc = nesting level */
|
||||
had_lbrac = 0;
|
||||
if (CurrentScope != FileScope) close_scope();
|
||||
saw_code = 0;
|
||||
break;
|
||||
case N_FUN: /* function, value = address */
|
||||
case N_GSYM: /* global variable */
|
||||
case N_STSYM: /* data, static, value = address */
|
||||
case N_LCSYM: /* bss, static, value = address */
|
||||
case N_RSYM: /* register var, value = reg number */
|
||||
case N_SSYM: /* struct/union el, value = offset */
|
||||
case N_PSYM: /* parameter, value = offset from AP */
|
||||
case N_LSYM: /* local sym, value = offset from FP */
|
||||
if (had_lbrac) {
|
||||
open_scope((p_symbol) 0, 0);
|
||||
saw_code = 0;
|
||||
had_lbrac = 0;
|
||||
}
|
||||
if (n->on_mptr && strindex(n->on_mptr, ':')) {
|
||||
n = DbxString(n);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
if (n->on_mptr && (n->on_type&S_TYP) >= S_MIN) {
|
||||
struct idf *id = str2idf(n->on_mptr, 0);
|
||||
|
||||
sym = new_symbol();
|
||||
sym->sy_next = id->id_def;
|
||||
id->id_def = sym;
|
||||
sym->sy_class = SYMENTRY;
|
||||
sym->sy_onam = *n;
|
||||
sym->sy_idf = id;
|
||||
}
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
close_scope();
|
||||
add_position_addr((char *) 0, (struct outname *) 0);
|
||||
rd_close();
|
||||
return (h.oh_magic == O_CONVERTED);
|
||||
}
|
65
util/grind/dump.c
Normal file
65
util/grind/dump.c
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "operator.h"
|
||||
#include "position.h"
|
||||
#include "tree.h"
|
||||
#include "message.h"
|
||||
|
||||
extern long pointer_size;
|
||||
extern p_tree get_from_item_list();
|
||||
|
||||
struct dump {
|
||||
char *globals, *stack;
|
||||
struct message_hdr mglobal, mstack;
|
||||
};
|
||||
|
||||
/* dumping and restoring of child process.
|
||||
*/
|
||||
do_dump(p)
|
||||
p_tree p;
|
||||
{
|
||||
struct dump *d = (struct dump *) Malloc(sizeof(struct dump));
|
||||
|
||||
if (! get_dump(&d->mglobal, &d->globals, &d->mstack, &d->stack)) {
|
||||
error("no debuggee");
|
||||
free((char *) d);
|
||||
return;
|
||||
}
|
||||
p->t_args[0] = (struct tree *) d;
|
||||
p->t_address = (t_addr) BUFTOA(d->mglobal.m_buf+PC_OFF*pointer_size);
|
||||
add_to_item_list(p);
|
||||
}
|
||||
|
||||
/* dumping and restoring of child process.
|
||||
*/
|
||||
do_restore(p)
|
||||
p_tree p;
|
||||
{
|
||||
struct dump *d;
|
||||
|
||||
p = get_from_item_list((int) p->t_ival);
|
||||
if (!p || p->t_oper != OP_DUMP) {
|
||||
error("no such dump");
|
||||
return;
|
||||
}
|
||||
|
||||
d = (struct dump *) p->t_args[0];
|
||||
|
||||
if (! put_dump(&d->mglobal, d->globals, &d->mstack, d->stack)) {
|
||||
error("no debuggee");
|
||||
}
|
||||
do_items();
|
||||
}
|
||||
|
||||
free_dump(p)
|
||||
p_tree p;
|
||||
{
|
||||
struct dump *d = (struct dump *) p->t_args[0];
|
||||
|
||||
free(d->globals);
|
||||
free(d->stack);
|
||||
free((char *) d);
|
||||
}
|
13
util/grind/expr.c
Normal file
13
util/grind/expr.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include "position.h"
|
||||
#include "operator.h"
|
||||
#include "tree.h"
|
||||
|
||||
int
|
||||
eval_cond(p)
|
||||
p_tree p;
|
||||
{
|
||||
/* to be written !!! */
|
||||
return 1;
|
||||
}
|
38
util/grind/file.hh
Normal file
38
util/grind/file.hh
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Structure for information about files. This information consists of three
|
||||
parts:
|
||||
- file name and directory
|
||||
- mapping of line numbers to offsets in file
|
||||
- mapping of object adresses to lines in file and vice versa
|
||||
*/
|
||||
|
||||
#define LOGHSIZ 6 /* make sure HSIZ is a power of 2 */
|
||||
#define HSIZ (1 << LOGHSIZ)
|
||||
#define HASH(line) ((line) & (HSIZ-1))
|
||||
|
||||
typedef struct file {
|
||||
struct symbol *f_sym;
|
||||
char *f_fullname; /* name including directory */
|
||||
struct scope *f_scope; /* reference to scope of this file */
|
||||
t_lineno f_nlines; /* number of lines in file */
|
||||
union {
|
||||
long *ff_linepos; /* positions of lines in file */
|
||||
struct file *ff_next; /* only for BINCL, EINCL */
|
||||
} f_x;
|
||||
#define f_linepos f_x.ff_linepos
|
||||
#define f_next f_x.ff_next
|
||||
struct outname *f_start;
|
||||
struct outname *f_end;
|
||||
struct outname *f_line_addr[HSIZ];
|
||||
/* hash table, mapping line numbers to
|
||||
outname structures. Collisions are
|
||||
resolved by chaining:
|
||||
*/
|
||||
#define next_outname(n) ((struct outname *) ((n)->on_mptr))
|
||||
#define setnext_outname(n,m) ((n)->on_mptr = (char *) (m))
|
||||
|
||||
struct file *f_nextmap; /* next file in mapping */
|
||||
} t_file, *p_file;
|
||||
|
||||
/* ALLOCDEF "file" 10 */
|
15
util/grind/idf.c
Normal file
15
util/grind/idf.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* I N S T A N T I A T I O N O F I D F P A C K A G E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include <idf_pkg.body>
|
21
util/grind/idf.h
Normal file
21
util/grind/idf.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* U S E R D E C L A R E D P A R T O F I D F */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct id_u {
|
||||
int id_res;
|
||||
struct symbol *id_df;
|
||||
};
|
||||
|
||||
#define IDF_TYPE struct id_u
|
||||
#define id_reserved id_user.id_res
|
||||
#define id_def id_user.id_df
|
||||
|
||||
#include <idf_pkg.spec>
|
163
util/grind/itemlist.cc
Normal file
163
util/grind/itemlist.cc
Normal file
|
@ -0,0 +1,163 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "tree.h"
|
||||
#include "operator.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
extern int db_ss;
|
||||
|
||||
typedef struct item {
|
||||
struct item *i_next;
|
||||
struct tree *i_node;
|
||||
} t_item, *p_item;
|
||||
|
||||
/* STATICALLOCDEF "item" 10 */
|
||||
|
||||
struct itemlist {
|
||||
p_item il_first, il_last;
|
||||
int il_count;
|
||||
};
|
||||
|
||||
static struct itemlist item_list;
|
||||
|
||||
int
|
||||
in_item_list(p)
|
||||
p_tree p;
|
||||
{
|
||||
register p_item i = item_list.il_first;
|
||||
|
||||
while (i) {
|
||||
if (i->i_node == p) return 1;
|
||||
i = i->i_next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
item_addr_actions(a)
|
||||
t_addr a;
|
||||
{
|
||||
/* Perform actions associated with position 'a', and return 1 if we must stop
|
||||
there, and 0 if not.
|
||||
*/
|
||||
register p_item i = item_list.il_first;
|
||||
int stopping = 0;
|
||||
|
||||
while (i) {
|
||||
register p_tree p = i->i_node;
|
||||
|
||||
if (p->t_address == a || p->t_address == NO_ADDR) {
|
||||
switch(p->t_oper) {
|
||||
case OP_TRACE:
|
||||
case OP_WHEN:
|
||||
if (! p->t_args[1] ||
|
||||
eval_cond(p->t_args[1])) {
|
||||
perform(p, a);
|
||||
}
|
||||
break;
|
||||
case OP_STOP:
|
||||
if (! p->t_args[1] ||
|
||||
eval_cond(p->t_args[1])) stopping = 1;
|
||||
break;
|
||||
case OP_DUMP:
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
i = i->i_next;
|
||||
}
|
||||
return stopping;
|
||||
}
|
||||
|
||||
add_to_item_list(p)
|
||||
p_tree p;
|
||||
{
|
||||
p_item i;
|
||||
|
||||
if (in_item_list(p)) return 1;
|
||||
|
||||
i = new_item();
|
||||
i->i_node = p;
|
||||
if (p->t_address == NO_ADDR &&
|
||||
(p->t_oper != OP_TRACE || ! p->t_args[0])) db_ss++;
|
||||
if (item_list.il_first == 0) {
|
||||
item_list.il_first = i;
|
||||
}
|
||||
else {
|
||||
item_list.il_last->i_next = i;
|
||||
}
|
||||
p->t_itemno = ++item_list.il_count;
|
||||
item_list.il_last = i;
|
||||
pr_item(p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p_tree
|
||||
remove_from_item_list(n)
|
||||
int n;
|
||||
{
|
||||
register p_item i = item_list.il_first, prev = 0;
|
||||
p_tree p = 0;
|
||||
|
||||
while (i) {
|
||||
if (i->i_node->t_itemno == n) break;
|
||||
prev = i;
|
||||
i = i->i_next;
|
||||
}
|
||||
if (i) {
|
||||
if (prev) {
|
||||
prev->i_next = i->i_next;
|
||||
}
|
||||
else item_list.il_first = i->i_next;
|
||||
if (i == item_list.il_last) item_list.il_last = prev;
|
||||
p = i->i_node;
|
||||
if (p->t_address == NO_ADDR &&
|
||||
(p->t_oper != OP_TRACE || ! p->t_args[0])) db_ss--;
|
||||
free_item(i);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
p_tree
|
||||
get_from_item_list(n)
|
||||
int n;
|
||||
{
|
||||
register p_item i = item_list.il_first;
|
||||
|
||||
while (i) {
|
||||
if (i->i_node->t_itemno == n) return i->i_node;
|
||||
i = i->i_next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
print_items()
|
||||
{
|
||||
register p_item i = item_list.il_first;
|
||||
|
||||
for (; i; i = i->i_next) {
|
||||
pr_item(i->i_node);
|
||||
}
|
||||
}
|
||||
|
||||
pr_item(p)
|
||||
p_tree p;
|
||||
{
|
||||
fprintf(db_out, "(%d)\t", p->t_itemno);
|
||||
print_node(p, 1);
|
||||
}
|
||||
|
||||
do_items()
|
||||
{
|
||||
register p_item i = item_list.il_first;
|
||||
|
||||
for (; i; i = i->i_next) {
|
||||
if (i->i_node->t_oper != OP_DUMP) eval(i->i_node);
|
||||
}
|
||||
}
|
47
util/grind/langdep.cc
Normal file
47
util/grind/langdep.cc
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include "langdep.h"
|
||||
|
||||
struct langlist {
|
||||
struct langlist *l_next;
|
||||
struct langdep *l_lang;
|
||||
char *l_suff;
|
||||
};
|
||||
|
||||
/* STATICALLOCDEF "langlist" 5 */
|
||||
|
||||
static struct langlist *list;
|
||||
|
||||
struct langdep *currlang;
|
||||
|
||||
static int
|
||||
add_language(suff, lang)
|
||||
char *suff;
|
||||
struct langdep *lang;
|
||||
{
|
||||
struct langlist *p = new_langlist();
|
||||
|
||||
p->l_next = list;
|
||||
p->l_suff = suff;
|
||||
p->l_lang = lang;
|
||||
list = p;
|
||||
}
|
||||
|
||||
int
|
||||
init_languages()
|
||||
{
|
||||
add_language(".mod", m2_dep);
|
||||
}
|
||||
|
||||
int
|
||||
find_language(suff)
|
||||
char *suff;
|
||||
{
|
||||
register struct langlist *p = list;
|
||||
|
||||
while (p) {
|
||||
currlang = p->l_lang;
|
||||
if (! strcmp(p->l_suff, suff)) break;
|
||||
p = p->l_next;
|
||||
}
|
||||
}
|
32
util/grind/langdep.h
Normal file
32
util/grind/langdep.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* language-dependent routines and formats, together in one structure: */
|
||||
|
||||
struct langdep {
|
||||
/* formats (for fprintf): */
|
||||
char *decint_fmt; /* decimal ints (format for long) */
|
||||
char *octint_fmt; /* octal ints (format for long) */
|
||||
char *hexint_fmt; /* hexadecimal ints (format for long) */
|
||||
char *uns_fmt; /* unsigneds (format for long) */
|
||||
char *addr_fmt; /* address (format for long) */
|
||||
char *real_fmt; /* real (format for double) */
|
||||
char *char_fmt; /* character (format for int) */
|
||||
|
||||
/* display openers and closers: */
|
||||
char *open_array_display;
|
||||
char *close_array_display;
|
||||
char *open_struct_display;
|
||||
char *close_struct_display;
|
||||
char *open_set_display;
|
||||
char *close_set_display;
|
||||
|
||||
/* language dependant routines: */
|
||||
int (*printstring)();
|
||||
long (*arrayelsize)();
|
||||
};
|
||||
|
||||
extern struct langdep *m2_dep, *currlang;
|
||||
|
||||
extern int find_language();
|
||||
|
||||
extern int init_languages();
|
146
util/grind/list.c
Normal file
146
util/grind/list.c
Normal file
|
@ -0,0 +1,146 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "idf.h"
|
||||
#include "file.h"
|
||||
#include "symbol.h"
|
||||
|
||||
static line_positions();
|
||||
extern char *dirs[];
|
||||
extern FILE *fopen();
|
||||
extern FILE *db_out;
|
||||
#define window_size 21
|
||||
|
||||
static int
|
||||
mk_filnm(dir, file, newname)
|
||||
char *dir;
|
||||
char *file;
|
||||
char **newname;
|
||||
{
|
||||
register char *dst = Malloc((unsigned) (strlen(dir) + strlen(file) + 2));
|
||||
|
||||
*newname = dst;
|
||||
if (*dir) {
|
||||
while (*dst++ = *dir++) /* nothing */;
|
||||
*(dst - 1) = '/';
|
||||
}
|
||||
while (*dst++ = *file++) /* nothing */;
|
||||
}
|
||||
|
||||
static FILE *
|
||||
open_file(fn, mode, ffn)
|
||||
char *fn;
|
||||
char *mode;
|
||||
char **ffn;
|
||||
{
|
||||
FILE *f;
|
||||
char **p;
|
||||
|
||||
if (fn[0] == '/') {
|
||||
*ffn = fn;
|
||||
return fopen(fn, mode);
|
||||
}
|
||||
p = dirs;
|
||||
while (*p) {
|
||||
mk_filnm(*p++, fn, ffn);
|
||||
if ((f = fopen(*ffn, mode)) != NULL) {
|
||||
return f;
|
||||
}
|
||||
free(*ffn);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Print a window of window_size lines around line "line" of
|
||||
file "file".
|
||||
*/
|
||||
window(file, line)
|
||||
p_file file;
|
||||
int line;
|
||||
{
|
||||
lines(file,
|
||||
line + ((window_size >> 1) - window_size), line + (window_size >> 1));
|
||||
}
|
||||
|
||||
lines(file, l1, l2)
|
||||
register p_file file;
|
||||
int l1, l2;
|
||||
{
|
||||
static p_file last_file;
|
||||
static FILE *last_f;
|
||||
register FILE *f;
|
||||
register int n;
|
||||
|
||||
if (last_file != file) {
|
||||
if (last_f) fclose(last_f);
|
||||
last_f = 0;
|
||||
if (!(f = open_file(file->f_sym->sy_idf->id_text,
|
||||
"r",
|
||||
&file->f_fullname))) {
|
||||
error("could not open %s", file->f_sym->sy_idf->id_text);
|
||||
return;
|
||||
}
|
||||
printf("filedesc = %d\n", fileno(f));
|
||||
last_file = file;
|
||||
last_f = f;
|
||||
if (! file->f_linepos) {
|
||||
line_positions(file, f);
|
||||
}
|
||||
}
|
||||
else f = last_f;
|
||||
|
||||
if (l1 < 1) l1 = 1;
|
||||
if (l2 > file->f_nlines) l2 = file->f_nlines;
|
||||
if (l1 > l2) {
|
||||
error("%s has only %d lines", file->f_sym->sy_idf->id_text, file->f_nlines);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, *(file->f_linepos+(l1-1)), 0);
|
||||
for (n = l1; n <= l2; n++) {
|
||||
register int c;
|
||||
|
||||
fprintf(db_out, "%6d ", n);
|
||||
do {
|
||||
c = getc(f);
|
||||
if (c != EOF) putc(c, db_out);
|
||||
} while (c != '\n' && c != EOF);
|
||||
if (c == EOF) break;
|
||||
}
|
||||
clearerr(f);
|
||||
}
|
||||
|
||||
static
|
||||
line_positions(file, f)
|
||||
p_file file;
|
||||
register FILE *f;
|
||||
{
|
||||
int nl;
|
||||
unsigned int n_alloc = 256;
|
||||
register long cnt = 0;
|
||||
register int c;
|
||||
|
||||
file->f_linepos = (long *) Malloc(n_alloc * sizeof(long));
|
||||
file->f_linepos[0] = 0;
|
||||
nl = 1;
|
||||
while ((c = getc(f)) != EOF) {
|
||||
cnt++;
|
||||
if (c == '\n') {
|
||||
if (nl == n_alloc) {
|
||||
n_alloc <<= 1;
|
||||
file->f_linepos =
|
||||
(long *) Realloc((char *)(file->f_linepos),
|
||||
n_alloc * sizeof(long));
|
||||
}
|
||||
file->f_linepos[nl++] = cnt;
|
||||
}
|
||||
}
|
||||
if (cnt == file->f_linepos[nl-1]) nl--;
|
||||
file->f_linepos = (long *) Realloc((char *)(file->f_linepos),
|
||||
(unsigned)nl * sizeof(long));
|
||||
file->f_nlines = nl;
|
||||
clearerr(f);
|
||||
}
|
121
util/grind/main.c
Normal file
121
util/grind/main.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
#include <stdio.h>
|
||||
#include <varargs.h>
|
||||
|
||||
#include "tokenname.h"
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
|
||||
static char *usage = "Usage: %s [-d] [<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();
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
char *p;
|
||||
|
||||
db_out = stdout;
|
||||
db_in = stdin;
|
||||
progname = argv[0];
|
||||
while (p = strindex(progname, '/')) {
|
||||
progname = p + 1;
|
||||
}
|
||||
if (argv[1][0] == '-') {
|
||||
switch(argv[1][1]) {
|
||||
case 'd':
|
||||
debug++;
|
||||
break;
|
||||
default:
|
||||
fatal(usage, progname);
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
if (argc > 3) {
|
||||
fatal(usage, progname);
|
||||
}
|
||||
AckObj = argv[1] ? argv[1] : "a.out";
|
||||
if (argc == 3) AObj = argv[2];
|
||||
init_idf();
|
||||
init_types();
|
||||
init_scope();
|
||||
init_languages();
|
||||
if (DbxRead(AckObj) && AObj == 0) AObj = AckObj;
|
||||
else if (AObj == 0) AObj = "a.out";
|
||||
reserve(tkidf);
|
||||
if (currfile) CurrentScope = currfile->sy_file->f_scope;
|
||||
if (! init_run()) {
|
||||
fatal("something wrong with file descriptors");
|
||||
}
|
||||
prompt();
|
||||
Commands();
|
||||
fputc( '\n', db_out);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
prompt()
|
||||
{
|
||||
if (isatty(fileno(db_in))) {
|
||||
fprintf(db_out, "%s -> ", progname);
|
||||
fflush(db_out);
|
||||
}
|
||||
}
|
||||
|
||||
/*VARARGS1*/
|
||||
fatal(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
{
|
||||
fmt = va_arg(ap, char *);
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
va_end(ap);
|
||||
abort();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
extern int errorgiven;
|
||||
|
||||
/*VARARGS1*/
|
||||
error(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
char *fmt;
|
||||
|
||||
va_start(ap);
|
||||
{
|
||||
fmt = va_arg(ap, char *);
|
||||
fprintf(stderr, "%s: ", progname);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
va_end(ap);
|
||||
errorgiven = 1;
|
||||
}
|
||||
|
||||
rd_fatal()
|
||||
{
|
||||
fatal("read error in %s", AckObj);
|
||||
}
|
||||
|
||||
No_Mem()
|
||||
{
|
||||
fatal("out of memory");
|
||||
}
|
26
util/grind/make.allocd
Executable file
26
util/grind/make.allocd
Executable file
|
@ -0,0 +1,26 @@
|
|||
sed -e '
|
||||
s:^.*[ ]ALLOCDEF[ ].*"\(.*\)"[ ]*\([0-9][0-9]*\).*$:\
|
||||
/* allocation definitions of struct \1 */\
|
||||
extern char *st_alloc();\
|
||||
extern struct \1 *h_\1;\
|
||||
#ifdef DEBUG\
|
||||
extern int cnt_\1;\
|
||||
extern char *std_alloc();\
|
||||
#define new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
|
||||
#else\
|
||||
#define new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
|
||||
#endif\
|
||||
#define free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
|
||||
:' -e '
|
||||
s:^.*[ ]STATICALLOCDEF[ ].*"\(.*\)"[ ]*\([0-9][0-9]*\).*$:\
|
||||
/* allocation definitions of struct \1 */\
|
||||
extern char *st_alloc();\
|
||||
struct \1 *h_\1;\
|
||||
#ifdef DEBUG\
|
||||
int cnt_\1;\
|
||||
#define new_\1() ((struct \1 *) std_alloc((char **)\&h_\1, sizeof(struct \1), \2, \&cnt_\1))\
|
||||
#else\
|
||||
#define new_\1() ((struct \1 *) st_alloc((char **)\&h_\1, sizeof(struct \1), \2))\
|
||||
#endif\
|
||||
#define free_\1(p) st_free(p, \&h_\1, sizeof(struct \1))\
|
||||
:'
|
6
util/grind/make.next
Executable file
6
util/grind/make.next
Executable file
|
@ -0,0 +1,6 @@
|
|||
sed -n '
|
||||
s:^.*[ ]ALLOCDEF[ ].*"\(.*\)".*$:struct \1 *h_\1 = 0;\
|
||||
#ifdef DEBUG\
|
||||
int cnt_\1 = 0;\
|
||||
#endif:p
|
||||
' $*
|
18
util/grind/make.ops
Executable file
18
util/grind/make.ops
Executable file
|
@ -0,0 +1,18 @@
|
|||
awk '
|
||||
BEGIN { n = 0 }
|
||||
{ print "#define " $1 " " n; n++
|
||||
if ($3 !~ /0/) print "extern int " $3 "();" ;
|
||||
}
|
||||
' < $1 > ops.h
|
||||
|
||||
cat > ops.c <<'EOF'
|
||||
#include "operator.h"
|
||||
#include "ops.h"
|
||||
|
||||
t_operator operators[] = {
|
||||
EOF
|
||||
awk ' { print "{ " $2 ", " $3 "}, /* " $1 " */" }' < $1 >> ops.c
|
||||
cat >> ops.c <<'EOF'
|
||||
{ 0, 0 }
|
||||
};
|
||||
EOF
|
36
util/grind/make.tokcase
Executable file
36
util/grind/make.tokcase
Executable file
|
@ -0,0 +1,36 @@
|
|||
cat <<'--EOT--'
|
||||
/* Generated by make.tokcase */
|
||||
/* $Header$ */
|
||||
#include "Lpars.h"
|
||||
|
||||
char *
|
||||
symbol2str(tok)
|
||||
int tok;
|
||||
{
|
||||
#define SIZBUF 8
|
||||
/* allow for a few invocations in f.i. an argument list */
|
||||
static char buf[SIZBUF] = { '\'', 0, '\'', 0, '\'', 0, '\'', 0};
|
||||
static int index = 1;
|
||||
|
||||
switch (tok) {
|
||||
--EOT--
|
||||
|
||||
sed '
|
||||
/{[A-Z]/!d
|
||||
s/.*{\(.*\),.*\(".*"\).*$/ case \1 :\
|
||||
return \2;/
|
||||
'
|
||||
|
||||
cat <<'--EOT--'
|
||||
default:
|
||||
if (tok <= 0) return "end of file";
|
||||
if (tok == '\n') return "<newline>";
|
||||
if (tok < 040 || tok >= 0177) {
|
||||
return "bad token";
|
||||
}
|
||||
index = (index+4) & (SIZBUF-1);
|
||||
buf[index] = tok;
|
||||
return &buf[index-1];
|
||||
}
|
||||
}
|
||||
--EOT--
|
6
util/grind/make.tokfile
Executable file
6
util/grind/make.tokfile
Executable file
|
@ -0,0 +1,6 @@
|
|||
sed '
|
||||
/{[A-Z]/!d
|
||||
s/.*{//
|
||||
s/,.*//
|
||||
s/.*/%token &;/
|
||||
'
|
59
util/grind/message.h
Normal file
59
util/grind/message.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* $Header$ */
|
||||
|
||||
#define BUFLEN 24 /* size of buffer in message header */
|
||||
|
||||
struct message_hdr {
|
||||
int m_type;
|
||||
/* Possible values of m_type: */
|
||||
#define DB_RUN 020000 /* set for commands that cause child to run */
|
||||
#define SETBP 0 /* set breakpoint at address in m_size */
|
||||
#define CLRBP 1 /* clear breakpoint at address in m_size */
|
||||
#define SETSS (2|DB_RUN) /* set single stepping, # of steps in m_size */
|
||||
#define SETSSF (3|DB_RUN) /* set single stepping, counting calls as one step */
|
||||
#define GETEMREGS 4 /* get EM registers, m_size contains level */
|
||||
#define GETBYTES 5 /* get data; m_size contains size, m_buf contains address */
|
||||
#define GETSTR 6 /* get string; m_buf contains address */
|
||||
#define SETBYTES 7 /* set data; m_buf contains address, m_size contains size */
|
||||
#define CALL 8 /* call function;
|
||||
m_size contains size of parameter buffer,
|
||||
m_buf contains address + size of function result
|
||||
*/
|
||||
#define CONT (9|DB_RUN) /* continue */
|
||||
#define SETEMREGS 10 /* set EM registers, m_size contains level
|
||||
Actually, only the program counter is set.
|
||||
*/
|
||||
#define DB_SS 040000 /* debugger wants single stepping (to be orred with
|
||||
SETSS(F) or CONT
|
||||
*/
|
||||
#define CLRSS 12 /* clear single stepping */
|
||||
#define DUMP 13 /* dump command */
|
||||
#define DGLOB 14 /* data area */
|
||||
#define DSTACK 15 /* stack area */
|
||||
#define SETTRACE 16 /* start tracing; range in m_mes */
|
||||
#define CLRTRACE 17 /* end tracing */
|
||||
|
||||
#define OK 50 /* answer of child to most messages */
|
||||
#define FAIL 51 /* answer of child when something goes wrong */
|
||||
#define DATA 52 /* answer of child when data requested */
|
||||
#define END_SS 53 /* when stopped because of user single stepping */
|
||||
long m_size; /* size */
|
||||
char m_buf[BUFLEN]; /* some of the data required included in message */
|
||||
};
|
||||
|
||||
#define LB_OFF 0
|
||||
#define AB_OFF 1
|
||||
#define PC_OFF 2
|
||||
#define HP_OFF 3
|
||||
#define SP_OFF 4
|
||||
|
||||
#define IN_FD 3
|
||||
#define OUT_FD 6
|
||||
|
||||
#define BUFTOL(c) (*((long *) (c)))
|
||||
#define LTOBUF(c,l) (*((long *) (c)) = (l))
|
||||
#define BUFTOA(c) (*((char **) (c)))
|
||||
#define ATOBUF(c,p) (*((char **) (c)) = (p))
|
||||
#define BUFTOS(c) (*((short *) (c)))
|
||||
#define BUFTOI(c) (*((int *) (c)))
|
||||
#define BUFTOF(c) (*((float *) (c)))
|
||||
#define BUFTOD(c) (*((double *) (c)))
|
61
util/grind/modula-2.c
Normal file
61
util/grind/modula-2.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Language dependant support; this one is for Modula-2 */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "langdep.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
|
||||
static int
|
||||
print_string();
|
||||
|
||||
static long
|
||||
array_elsize();
|
||||
|
||||
static struct langdep m2 = {
|
||||
"%ld",
|
||||
"%loB",
|
||||
"%lXH",
|
||||
"%lu",
|
||||
"%lXH",
|
||||
"%g",
|
||||
"%oC",
|
||||
|
||||
"[",
|
||||
"]",
|
||||
"(",
|
||||
")",
|
||||
"{",
|
||||
"}",
|
||||
|
||||
print_string,
|
||||
array_elsize
|
||||
};
|
||||
|
||||
struct langdep *m2_dep = &m2;
|
||||
|
||||
static int
|
||||
print_string(s)
|
||||
char *s;
|
||||
{
|
||||
register char *str = s;
|
||||
int delim = '\'';
|
||||
|
||||
while (*str) {
|
||||
if (*str++ == '\'') delim = '"';
|
||||
}
|
||||
fprintf(db_out, "%c%s%c", delim, s, delim);
|
||||
}
|
||||
|
||||
extern long int_size;
|
||||
|
||||
static long
|
||||
array_elsize(size)
|
||||
long size;
|
||||
{
|
||||
if (! (int_size % size)) return size;
|
||||
if (! (size % int_size)) return size;
|
||||
return ((size + int_size - 1) / int_size) * int_size;
|
||||
}
|
14
util/grind/op_tools.amk
Normal file
14
util/grind/op_tools.amk
Normal file
|
@ -0,0 +1,14 @@
|
|||
MAKE_OPS = make.ops;
|
||||
|
||||
%instance deftypesuffix(op_tab, '%.ot');
|
||||
|
||||
%tool gen_ops (
|
||||
ops: %in [type = op_tab];
|
||||
cfile: %out [type = C-src] => ops.c;
|
||||
hfile: %out [type = C-incl] => ops.h;
|
||||
mkops: %in [type = command] => $MAKE_OPS;
|
||||
)
|
||||
{
|
||||
exec($mkops, args => $ops);
|
||||
echo({$cfile, 'and', $hfile, 'created'});
|
||||
};
|
12
util/grind/operator.h
Normal file
12
util/grind/operator.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include "ops.h"
|
||||
|
||||
typedef struct operator {
|
||||
int op_nargs;
|
||||
int (*op_fun)();
|
||||
} t_operator, *p_operator;
|
||||
|
||||
extern t_operator operators[];
|
||||
|
||||
#define nargs(n) (operators[(n)].op_nargs)
|
24
util/grind/operators.ot
Normal file
24
util/grind/operators.ot
Normal file
|
@ -0,0 +1,24 @@
|
|||
OP_LIST 2 do_list
|
||||
OP_FILE 1 do_file
|
||||
OP_LINK 2 0
|
||||
OP_RUN 1 start_child
|
||||
OP_INPUT 1 0
|
||||
OP_OUTPUT 1 0
|
||||
OP_INTEGER 0 0
|
||||
OP_NAME 0 0
|
||||
OP_AT 0 0
|
||||
OP_IN 1 0
|
||||
OP_STOP 2 do_stop
|
||||
OP_WHEN 3 do_stop
|
||||
OP_CONT 2 do_continue
|
||||
OP_STEP 0 do_step
|
||||
OP_NEXT 0 do_next
|
||||
OP_REGS 0 do_regs
|
||||
OP_WHERE 0 do_where
|
||||
OP_STATUS 0 do_status
|
||||
OP_DELETE 0 do_delete
|
||||
OP_SELECT 2 0
|
||||
OP_PRINT 1 do_print
|
||||
OP_DUMP 0 do_dump
|
||||
OP_RESTORE 0 do_restore
|
||||
OP_TRACE 3 do_trace
|
196
util/grind/position.c
Normal file
196
util/grind/position.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
#include <out.h>
|
||||
#include <stb.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "scope.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include "symbol.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
|
||||
static p_file mapping;
|
||||
static int nfiles = 0;
|
||||
|
||||
/* static p_file get_map_from_addr(t_addr t);
|
||||
Returns the file entry that contains the code at the address 't',
|
||||
or 0 if there is no information available, or 't' represents an address
|
||||
below the start address of the first file.
|
||||
*/
|
||||
static p_file
|
||||
get_map_from_addr(t)
|
||||
t_addr t;
|
||||
{
|
||||
register p_file p = mapping, oldp = 0;
|
||||
|
||||
/* linear search is probably acceptable here */
|
||||
while (p && p->f_start->on_valu <= t) {
|
||||
oldp = p;
|
||||
p = p->f_nextmap;
|
||||
}
|
||||
return oldp ? oldp : p->f_start->on_valu <= t ? p : 0;
|
||||
}
|
||||
|
||||
/* extern char *get_filename_from_addr(t_addr t);
|
||||
Returns the source filename that contains the code at the address 't',
|
||||
or 0 if there is no information available, or 't' represents an address
|
||||
below the start address of the first file.
|
||||
*/
|
||||
char *
|
||||
get_filename_from_addr(t)
|
||||
t_addr t;
|
||||
{
|
||||
register p_file map = get_map_from_addr(t);
|
||||
|
||||
if (! map) return 0;
|
||||
return map->f_sym->sy_idf->id_text;
|
||||
}
|
||||
|
||||
/* extern t_lineno get_lineno_from_addr(t_addr t);
|
||||
Returns the source line number of the line that contains the code at address
|
||||
't'. 0 is returned if no source line number could be found.
|
||||
*/
|
||||
t_lineno
|
||||
get_lineno_from_addr(t)
|
||||
t_addr t;
|
||||
{
|
||||
p_position p;
|
||||
|
||||
p = get_position_from_addr(t);
|
||||
return p == 0 ? 0 : p->lineno;
|
||||
}
|
||||
|
||||
/* extern p_position get_position_from_addr(t_addr t);
|
||||
Returns a pointer to a structure containing the source position of the code
|
||||
at address 't'. 0 is returned if no source position could be found.
|
||||
*/
|
||||
p_position
|
||||
get_position_from_addr(t)
|
||||
t_addr t;
|
||||
{
|
||||
register p_file map = get_map_from_addr(t);
|
||||
static t_position retval;
|
||||
register int i,j,m;
|
||||
|
||||
if (! map) return 0;
|
||||
i = 0;
|
||||
j = map->f_end - map->f_start;
|
||||
do {
|
||||
m = ((i + j) >> 1) + ((i + j) & 1);
|
||||
while ((map->f_start[m].on_type >> 8) != N_SLINE) m++;
|
||||
assert(m <= j);
|
||||
if (map->f_start[m].on_valu > t) {
|
||||
j = m - 1;
|
||||
while (j > i && (map->f_start[j].on_type >> 8) != N_SLINE) j--;
|
||||
}
|
||||
else i = m;
|
||||
} while (i < j);
|
||||
retval.filename = map->f_sym->sy_idf->id_text;
|
||||
retval.lineno = map->f_start[j].on_desc;
|
||||
return &retval;
|
||||
}
|
||||
|
||||
/* extern t_addr get_addr_from_position(p_position p);
|
||||
Returns the address of the code at position 'p', or ILL_ADDR if it could
|
||||
not be found. If there is no symbolic information for the filename in
|
||||
position 'p', an error message will be given.
|
||||
*/
|
||||
t_addr
|
||||
get_addr_from_position(p)
|
||||
p_position p;
|
||||
{
|
||||
register p_symbol sym = Lookup(findidf(p->filename), PervasiveScope, FILESYM);
|
||||
|
||||
if (sym) {
|
||||
register unsigned int i;
|
||||
register p_file map = sym->sy_file;
|
||||
|
||||
for (i = p->lineno; i > 0; i--) {
|
||||
register struct outname *n = map->f_line_addr[HASH(i)];
|
||||
|
||||
while (n) {
|
||||
if (n->on_desc == i) return (t_addr) n->on_valu;
|
||||
n = next_outname(n);
|
||||
}
|
||||
}
|
||||
return ILL_ADDR;
|
||||
}
|
||||
error("no symbolic information for file %s", p->filename);
|
||||
return ILL_ADDR;
|
||||
}
|
||||
|
||||
/* extern add_position_addr(char *filename, struct outname *n);
|
||||
Adds the ('filename','lineno'),'t' pair to the mapping information.
|
||||
*/
|
||||
add_position_addr(filename, n)
|
||||
char *filename;
|
||||
register struct outname *n;
|
||||
{
|
||||
static char *lastfile = 0;
|
||||
static p_file lastmap = 0;
|
||||
register p_file map = lastmap;
|
||||
|
||||
if (filename != lastfile) { /* new file ... */
|
||||
register p_symbol sym;
|
||||
|
||||
nfiles++;
|
||||
lastfile = filename;
|
||||
if (! filename) { /* last call */
|
||||
return;
|
||||
}
|
||||
sym = Lookup(findidf(filename), PervasiveScope, FILESYM);
|
||||
if (sym) map = sym->sy_file;
|
||||
else {
|
||||
sym = add_file(filename);
|
||||
map = sym->sy_file;
|
||||
map->f_scope = FileScope;
|
||||
}
|
||||
if (! mapping) mapping = map;
|
||||
else lastmap->f_nextmap = map;
|
||||
lastmap = map;
|
||||
map->f_start = n;
|
||||
}
|
||||
else map = lastmap;
|
||||
map->f_end = n;
|
||||
setnext_outname(n, map->f_line_addr[HASH(n->on_desc)]);
|
||||
map->f_line_addr[HASH(n->on_desc)] = n;
|
||||
}
|
||||
|
||||
/* extern struct scope *get_scope_from_position(p_position p);
|
||||
Returns the scope of the code at position 'p', or 0 if it could not be found.
|
||||
*/
|
||||
struct scope *
|
||||
get_scope_from_position(p)
|
||||
p_position p;
|
||||
{
|
||||
t_addr a = get_addr_from_position(p);
|
||||
|
||||
if (a != ILL_ADDR) {
|
||||
return get_scope_from_addr(a);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* extern p_position print_position(t_addr a, int print_function);
|
||||
Prints position 'a' and returns it. If 'print_function' is set,
|
||||
an attempt is made to print the function name as well.
|
||||
*/
|
||||
p_position
|
||||
print_position(a, print_function)
|
||||
t_addr a;
|
||||
int print_function;
|
||||
{
|
||||
register p_scope sc = base_scope(get_scope_from_addr(a));
|
||||
register p_position pos = get_position_from_addr(a);
|
||||
|
||||
if (sc && print_function) {
|
||||
fprintf(db_out, "in %s ", sc->sc_definedby->sy_idf->id_text);
|
||||
}
|
||||
if (pos) fprintf(db_out, "at \"%s\":%u", pos->filename, pos->lineno);
|
||||
return pos;
|
||||
}
|
57
util/grind/position.h
Normal file
57
util/grind/position.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* maps from address to filename-lineno pair and reverse,
|
||||
maps from filename-lineno pair or address to scope.
|
||||
*/
|
||||
|
||||
typedef unsigned int t_lineno;
|
||||
typedef long t_addr;
|
||||
#define ILL_ADDR ((t_addr) -1)
|
||||
#define NO_ADDR ((t_addr) -3)
|
||||
|
||||
typedef struct pos {
|
||||
t_lineno lineno;
|
||||
char *filename;
|
||||
} t_position, *p_position;
|
||||
|
||||
/* extern char *get_filename_from_addr(t_addr t);
|
||||
Returns the source filename that contains the code at the address 't',
|
||||
or 0 if there is no information available, or 't' represents an address
|
||||
below the start address of the first file.
|
||||
*/
|
||||
extern char *get_filename_from_addr();
|
||||
|
||||
/* extern t_lineno get_lineno_from_addr(t_addr t);
|
||||
Returns the source line number of the line that contains the code at address
|
||||
't'. 0 is returned if no source line number could be found.
|
||||
*/
|
||||
extern t_lineno get_lineno_from_addr();
|
||||
|
||||
/* extern p_position get_position_from_addr(t_addr t);
|
||||
Returns a pointer to a structure containing the source position of the code
|
||||
at address 't'. 0 is returned if no source position could be found.
|
||||
*/
|
||||
extern p_position get_position_from_addr();
|
||||
|
||||
/* extern t_addr get_addr_from_position(p_position p);
|
||||
Returns the address of the code at position 'p', or ILL_ADDR if it could
|
||||
not be found. If there is no symbolic information for the filename in
|
||||
position 'p', an error message will be given.
|
||||
*/
|
||||
extern t_addr get_addr_from_position();
|
||||
|
||||
/* extern add_position_addr(char *filename, struct outname *n);
|
||||
Adds the ('filename','n'->on_desc),'n'->on_valu pair to the mapping information.
|
||||
*/
|
||||
extern add_position_addr();
|
||||
|
||||
/* extern struct scope *get_scope_from_position(p_position p);
|
||||
Returns the scope of the code at position 'p', or 0 if it could not be found.
|
||||
*/
|
||||
extern struct scope *get_scope_from_position();
|
||||
|
||||
/* extern p_position print_position(t_addr a, int print_function);
|
||||
Prints position 'a' and returns it. If 'print_function' is set,
|
||||
an attempt is made to print the function name as well.
|
||||
*/
|
||||
extern p_position print_position();
|
322
util/grind/print.c
Normal file
322
util/grind/print.c
Normal file
|
@ -0,0 +1,322 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "message.h"
|
||||
#include "langdep.h"
|
||||
#include "scope.h"
|
||||
#include "symbol.h"
|
||||
#include "position.h"
|
||||
#include "idf.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
extern long float_size, pointer_size, int_size;
|
||||
|
||||
static
|
||||
print_literal(tp, v)
|
||||
p_type tp;
|
||||
int v;
|
||||
{
|
||||
register struct literal *lit = tp->ty_literals;
|
||||
register int i;
|
||||
|
||||
for (i = tp->ty_nenums; i; i--, lit++) {
|
||||
if (lit->lit_val == v) {
|
||||
fprintf(db_out, lit->lit_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! i) {
|
||||
fprintf(db_out, "unknown enumeration value %d", v);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
print_unsigned(tp, v)
|
||||
p_type tp;
|
||||
long v;
|
||||
{
|
||||
if (tp == uchar_type) {
|
||||
fprintf(db_out, currlang->char_fmt, (int) v);
|
||||
}
|
||||
else fprintf(db_out, currlang->uns_fmt, v);
|
||||
}
|
||||
|
||||
static
|
||||
print_integer(tp, v)
|
||||
p_type tp;
|
||||
long v;
|
||||
{
|
||||
if (tp == char_type) {
|
||||
fprintf(db_out, currlang->char_fmt, (int) v);
|
||||
}
|
||||
else fprintf(db_out, currlang->decint_fmt, v);
|
||||
}
|
||||
|
||||
print_params(tp, AB, static_link)
|
||||
p_type tp;
|
||||
t_addr AB;
|
||||
{
|
||||
char *param_bytes;
|
||||
register char *p;
|
||||
register int i;
|
||||
register struct param *par;
|
||||
long size;
|
||||
|
||||
if (! tp) return;
|
||||
assert(tp->ty_class == T_PROCEDURE);
|
||||
|
||||
if ((i = tp->ty_nparams) == 0) return;
|
||||
|
||||
/* get parameter bytes */
|
||||
par = tp->ty_params;
|
||||
size = tp->ty_nbparams;
|
||||
if (static_link) size += pointer_size;
|
||||
param_bytes = p = Malloc((unsigned)size);
|
||||
if (static_link) p += pointer_size;
|
||||
if (! get_bytes(size, AB, param_bytes)) {
|
||||
error("no debuggee");
|
||||
free(param_bytes);
|
||||
return;
|
||||
}
|
||||
|
||||
while (i--) {
|
||||
if (par->par_kind == 'v' || par->par_kind == 'i') {
|
||||
/* call by reference parameter, or
|
||||
call by value parameter, but address is passed;
|
||||
try and get value.
|
||||
*/
|
||||
char *q;
|
||||
|
||||
if ((size = par->par_type->ty_size) == 0) {
|
||||
size = compute_size(par->par_type, param_bytes);
|
||||
}
|
||||
q = Malloc((unsigned) size);
|
||||
if (! get_bytes(size, (t_addr) BUFTOA(p), q)) {
|
||||
fprintf(db_out, currlang->addr_fmt, BUFTOA(p));
|
||||
}
|
||||
else {
|
||||
print_val(par->par_type, q, 1, 0, param_bytes);
|
||||
}
|
||||
free(q);
|
||||
}
|
||||
else print_val(par->par_type, p, 1, 0, param_bytes);
|
||||
if (i) fputs(", ", db_out);
|
||||
p += param_size(par->par_type, par->par_kind);
|
||||
par++;
|
||||
}
|
||||
free(param_bytes);
|
||||
}
|
||||
|
||||
print_val(tp, addr, compressed, indent, AB)
|
||||
p_type tp; /* type of value to be printed */
|
||||
char *addr; /* address to get value from */
|
||||
int compressed; /* for parameter lists */
|
||||
int indent; /* indentation */
|
||||
char *AB; /* argument base for dynamic subranges */
|
||||
{
|
||||
long sz;
|
||||
register int i;
|
||||
long elsize;
|
||||
|
||||
if (indent == 0) indent = 4;
|
||||
switch(tp->ty_class) {
|
||||
case T_SUBRANGE:
|
||||
print_val(tp->ty_base, addr, compressed, indent, AB);
|
||||
break;
|
||||
case T_ARRAY:
|
||||
if (tp->ty_elements == char_type ||
|
||||
tp->ty_elements == uchar_type) {
|
||||
print_val(string_type, addr, compressed, indent, AB);
|
||||
break;
|
||||
}
|
||||
if ((sz = tp->ty_size) == 0) sz = compute_size(tp, AB);
|
||||
if (compressed) {
|
||||
fprintf(db_out, currlang->open_array_display);
|
||||
}
|
||||
else {
|
||||
fprintf(db_out, "\n%*c%s%*c",
|
||||
indent,
|
||||
' ',
|
||||
currlang->open_array_display,
|
||||
4-strlen(currlang->open_array_display), ' ');
|
||||
}
|
||||
indent += 4;
|
||||
elsize = (*currlang->arrayelsize)(tp->ty_elements->ty_size);
|
||||
for (i = sz/elsize; i; i--) {
|
||||
print_val(tp->ty_elements, addr, compressed, indent, AB);
|
||||
addr += elsize;
|
||||
if (compressed && i > 1) {
|
||||
fprintf(db_out, ", ...");
|
||||
break;
|
||||
}
|
||||
if (i > 1) {
|
||||
fputc(',', db_out);
|
||||
}
|
||||
fprintf(db_out, "\n%*c", i > 1 ? indent : indent - 4, ' ');
|
||||
}
|
||||
fprintf(db_out, currlang->close_array_display);
|
||||
indent -= 4;
|
||||
break;
|
||||
case T_STRUCT: {
|
||||
register struct fields *fld = tp->ty_fields;
|
||||
|
||||
if (compressed) {
|
||||
fprintf(db_out, currlang->open_struct_display);
|
||||
}
|
||||
else {
|
||||
fprintf(db_out, "\n%*c%s%*c",
|
||||
indent,
|
||||
' ',
|
||||
currlang->open_struct_display,
|
||||
4-strlen(currlang->open_struct_display), ' ');
|
||||
}
|
||||
indent += 4;
|
||||
for (i = tp->ty_nfields; i; i--, fld++) {
|
||||
if (! compressed) fprintf(db_out, "%s = ", fld->fld_name);
|
||||
if (fld->fld_bitsize != fld->fld_type->ty_size << 3) {
|
||||
/* apparently a bit field */
|
||||
/* ??? */
|
||||
fprintf(db_out, "<bitfield, %d, %d>", fld->fld_bitsize, fld->fld_type->ty_size);
|
||||
}
|
||||
else print_val(fld->fld_type, addr+(fld->fld_pos>>3), compressed, indent, AB);
|
||||
if (compressed && i > 1) {
|
||||
fprintf(db_out, ", ...");
|
||||
break;
|
||||
}
|
||||
if (i > 1) {
|
||||
fputc(',', db_out);
|
||||
}
|
||||
fprintf(db_out, "\n%*c", i > 1 ? indent : indent - 4, ' ');
|
||||
}
|
||||
indent -= 4;
|
||||
fprintf(db_out, currlang->close_struct_display);
|
||||
break;
|
||||
}
|
||||
case T_UNION:
|
||||
fprintf(db_out, "<union>");
|
||||
break;
|
||||
case T_ENUM:
|
||||
print_literal(tp, tp->ty_size == 1
|
||||
? (*addr & 0xFF)
|
||||
: tp->ty_size == 2
|
||||
? (BUFTOS(addr) & 0xFFFF)
|
||||
: (int) BUFTOL(addr));
|
||||
break;
|
||||
case T_PROCEDURE: {
|
||||
register p_scope sc = get_scope_from_addr((t_addr) BUFTOA(addr));
|
||||
|
||||
if (sc && sc->sc_definedby) {
|
||||
fprintf(db_out, sc->sc_definedby->sy_idf->id_text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Fall through */
|
||||
case T_POINTER:
|
||||
fprintf(db_out, currlang->addr_fmt, (long) BUFTOA(addr));
|
||||
break;
|
||||
case T_FILE:
|
||||
fprintf(db_out, "<file>");
|
||||
break;
|
||||
case T_SET: {
|
||||
long val = tp->ty_setlow;
|
||||
p_type base = tp->ty_setbase;
|
||||
long nelements = tp->ty_size << 3;
|
||||
int count = 0;
|
||||
int rsft = 3 + (int_size == 2 ? 1 : 2);
|
||||
long mask = int_size == 2 ? 0xFFFF : 0xFFFFFFFF;
|
||||
|
||||
if (base->ty_class == T_SUBRANGE) base = base->ty_base;
|
||||
if (compressed) {
|
||||
fprintf(db_out, currlang->open_set_display);
|
||||
}
|
||||
else {
|
||||
fprintf(db_out, "\n%*c%s%*c",
|
||||
indent,
|
||||
' ',
|
||||
currlang->open_set_display,
|
||||
4-strlen(currlang->open_set_display), ' ');
|
||||
}
|
||||
indent += 4;
|
||||
for (i = 0; i < nelements; i++) {
|
||||
if (*((int *) addr + (i >> rsft)) & (1 << (i & mask))) {
|
||||
count++;
|
||||
if (count > 1) {
|
||||
if (compressed) {
|
||||
fprintf(db_out, ", ...");
|
||||
break;
|
||||
}
|
||||
fprintf(db_out, ",\n%*c", indent , ' ');
|
||||
}
|
||||
switch(base->ty_class) {
|
||||
case T_INTEGER:
|
||||
print_integer(base, val+i);
|
||||
break;
|
||||
case T_UNSIGNED:
|
||||
print_unsigned(base, val+i);
|
||||
break;
|
||||
case T_ENUM:
|
||||
print_literal(base, (int)val+i);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (! compressed) {
|
||||
fprintf(db_out, "\n%*c", indent-4 , ' ');
|
||||
}
|
||||
indent -= 4;
|
||||
fprintf(db_out, currlang->close_set_display);
|
||||
}
|
||||
break;
|
||||
case T_REAL: {
|
||||
double val = tp->ty_size == float_size
|
||||
? BUFTOF(addr)
|
||||
: BUFTOD(addr);
|
||||
fprintf(db_out, currlang->real_fmt, val);
|
||||
break;
|
||||
}
|
||||
case T_UNSIGNED:
|
||||
print_unsigned(tp, tp->ty_size == 1
|
||||
? (*addr & 0xFF)
|
||||
: tp->ty_size == 2
|
||||
? (BUFTOS(addr) & 0xFFFF)
|
||||
: BUFTOL(addr));
|
||||
break;
|
||||
case T_INTEGER:
|
||||
print_integer(tp, tp->ty_size == 1
|
||||
? *addr
|
||||
: tp->ty_size == 2
|
||||
? BUFTOS(addr)
|
||||
: BUFTOL(addr));
|
||||
break;
|
||||
case T_STRING:
|
||||
(*currlang->printstring)(addr);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
print_sym(sym)
|
||||
p_symbol sym;
|
||||
{
|
||||
char *buf;
|
||||
char *AB;
|
||||
|
||||
if (get_value(sym, &buf, &AB)) {
|
||||
fputs(" = ", db_out);
|
||||
print_val(sym->sy_type, buf, 0, 0, AB);
|
||||
if (buf) free(buf);
|
||||
if (AB) free(AB);
|
||||
fputs("\n", db_out);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
134
util/grind/rd.c
Normal file
134
util/grind/rd.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* a.out file reading ... */
|
||||
|
||||
#include "rd.h"
|
||||
|
||||
#if defined(sun) && defined(mc68020)
|
||||
|
||||
#include <a.out.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static FILE *inf;
|
||||
static struct exec bh;
|
||||
static long seg_strings;
|
||||
static struct outhead hh;
|
||||
|
||||
#define readf(a, b, c) (fread((char *)(a), (b), (int)(c), inf))
|
||||
|
||||
int
|
||||
rd_open(f)
|
||||
char *f;
|
||||
{
|
||||
if ((inf = fopen(f, "r")) == NULL) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
rd_ohead(h)
|
||||
struct outhead *h;
|
||||
{
|
||||
if (! readf(&bh, sizeof(struct exec), 1)) rd_fatal();
|
||||
if (N_BADMAG(bh)) rd_fatal();
|
||||
|
||||
h->oh_magic = O_CONVERTED;
|
||||
h->oh_stamp = 0;
|
||||
h->oh_nsect = 4;
|
||||
h->oh_nname = 3 + bh.a_syms / sizeof(struct nlist);
|
||||
h->oh_nrelo = (bh.a_trsize + bh.a_drsize) / sizeof(struct reloc_info_68k);
|
||||
h->oh_flags = h->oh_nrelo ? HF_LINK : 0;
|
||||
if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
|
||||
h->oh_nemit = bh.a_text + bh.a_data;
|
||||
if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
|
||||
fseek(inf, N_STROFF(bh), 0);
|
||||
h->oh_nchar = getw(inf) + 6 + 6 + 5 - 4; /* ".text", ".data", ".bss",
|
||||
minus the size word */
|
||||
seg_strings = h->oh_nchar - 17;
|
||||
if (bh.a_magic == ZMAGIC) bh.a_text -= sizeof(struct exec);
|
||||
fseek(inf, sizeof(struct exec) + bh.a_text + bh.a_data, 0);
|
||||
hh = *h;
|
||||
}
|
||||
|
||||
/*ARGSUSED1*/
|
||||
rd_name(names, count)
|
||||
register struct outname *names;
|
||||
unsigned int count; /* ignored; complete namelist is read */
|
||||
{
|
||||
names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh);
|
||||
names->on_desc = 0; names->on_type = S_MIN | S_SCT;
|
||||
names++;
|
||||
names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 6;
|
||||
names->on_desc = 0; names->on_type = (S_MIN+2) | S_SCT;
|
||||
names++;
|
||||
names->on_valu = 0; names->on_foff = seg_strings + OFF_CHAR(hh) + 12;
|
||||
names->on_desc = 0; names->on_type = (S_MIN+3) | S_SCT;
|
||||
names++;
|
||||
count = bh.a_syms / sizeof(struct nlist);
|
||||
while (count > 0) {
|
||||
struct nlist n;
|
||||
|
||||
if (! readf(&n, sizeof(struct nlist), 1)) rd_fatal();
|
||||
count--;
|
||||
names->on_desc = n.n_desc;
|
||||
if (n.n_un.n_strx - 4 < 0) names->on_foff = 0;
|
||||
else names->on_foff = OFF_CHAR(hh) - 4 + n.n_un.n_strx;
|
||||
names->on_valu = n.n_value;
|
||||
|
||||
if (n.n_type & N_STAB) {
|
||||
names->on_type = n.n_type << 8;
|
||||
names++;
|
||||
continue;
|
||||
}
|
||||
switch(n.n_type & ~N_EXT) {
|
||||
case N_ABS:
|
||||
names->on_type = S_ABS;
|
||||
break;
|
||||
case N_TEXT:
|
||||
names->on_type = S_MIN;
|
||||
break;
|
||||
case N_DATA:
|
||||
names->on_type = S_MIN + 2;
|
||||
names->on_valu -= bh.a_text;
|
||||
break;
|
||||
case N_BSS:
|
||||
names->on_type = S_MIN + 3;
|
||||
names->on_valu -= bh.a_text + bh.a_data;
|
||||
break;
|
||||
case N_UNDF:
|
||||
if (! names->on_valu) {
|
||||
names->on_type = S_UND;
|
||||
break;
|
||||
}
|
||||
names->on_type = (S_MIN + 3) | S_COM;
|
||||
break;
|
||||
case N_FN:
|
||||
names->on_type = S_FIL;
|
||||
break;
|
||||
default:
|
||||
rd_fatal();
|
||||
}
|
||||
if (n.n_type & N_EXT) names->on_type |= S_EXT;
|
||||
names++;
|
||||
}
|
||||
}
|
||||
|
||||
extern char *strcpy();
|
||||
|
||||
rd_string(strings, count)
|
||||
register char *strings;
|
||||
long count;
|
||||
{
|
||||
if (bh.a_magic == ZMAGIC) bh.a_text += sizeof(struct exec);
|
||||
fseek(inf, N_STROFF(bh)+4, 0);
|
||||
if (! readf(strings, (int)count-17, 1)) rd_fatal();
|
||||
strings += count-17;
|
||||
strcpy(strings, ".text"); strings += 6;
|
||||
strcpy(strings, ".data"); strings += 6;
|
||||
strcpy(strings, ".bss");
|
||||
}
|
||||
|
||||
rd_close()
|
||||
{
|
||||
fclose(inf);
|
||||
}
|
||||
|
||||
#endif
|
5
util/grind/rd.h
Normal file
5
util/grind/rd.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <out.h>
|
||||
|
||||
#define O_CONVERTED 0x202
|
523
util/grind/run.c
Normal file
523
util/grind/run.c
Normal file
|
@ -0,0 +1,523 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Running a process and communication */
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
|
||||
#include "ops.h"
|
||||
#include "message.h"
|
||||
#include "position.h"
|
||||
#include "tree.h"
|
||||
#include "file.h"
|
||||
#include "symbol.h"
|
||||
#include "idf.h"
|
||||
#include "scope.h"
|
||||
|
||||
#define MAXARG 128
|
||||
|
||||
extern char *strncpy();
|
||||
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;
|
||||
|
||||
int db_ss;
|
||||
|
||||
static int catch_sigpipe();
|
||||
static int stopped();
|
||||
static int uputm(), ugetm();
|
||||
static int fild1[2], fild2[2]; /* pipe file descriptors */
|
||||
|
||||
int
|
||||
init_run()
|
||||
{
|
||||
/* take file descriptors so that listing cannot take them */
|
||||
int i;
|
||||
|
||||
for (i = IN_FD; i <= OUT_FD; i++) close(i);
|
||||
if (pipe(fild1) < 0 ||
|
||||
pipe(fild2) < 0 ||
|
||||
fild1[0] != IN_FD ||
|
||||
fild2[1] != OUT_FD) {
|
||||
return 0;
|
||||
}
|
||||
to_child = fild1[1];
|
||||
from_child = fild2[0];
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
start_child(p)
|
||||
p_tree p;
|
||||
{
|
||||
/* start up the process to be debugged and set up communication */
|
||||
|
||||
char *argp[MAXARG]; /* argument list */
|
||||
register p_tree pt = p->t_args[0], pt1;
|
||||
unsigned int nargs = 1; /* #args */
|
||||
char *in_redirect = 0; /* standard input redirected */
|
||||
char *out_redirect = 0; /* standard output redirected */
|
||||
|
||||
signal_child(SIGKILL); /* like families in China, this debugger is only
|
||||
allowed one child
|
||||
*/
|
||||
|
||||
/* first check arguments and redirections and build argument list */
|
||||
while (pt) {
|
||||
switch(pt->t_oper) {
|
||||
case OP_LINK:
|
||||
pt1 = pt->t_args[1];
|
||||
pt = pt->t_args[0];
|
||||
continue;
|
||||
case OP_NAME:
|
||||
if (nargs < (MAXARG-1)) {
|
||||
argp[nargs++] = pt->t_str;
|
||||
}
|
||||
else {
|
||||
error("too many arguments");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case OP_INPUT:
|
||||
if (in_redirect) {
|
||||
error("input redirected twice?");
|
||||
return 0;
|
||||
}
|
||||
in_redirect = pt->t_str;
|
||||
break;
|
||||
case OP_OUTPUT:
|
||||
if (out_redirect) {
|
||||
error("output redirected twice?");
|
||||
return 0;
|
||||
}
|
||||
out_redirect = pt->t_str;
|
||||
break;
|
||||
}
|
||||
if (pt != pt1) pt = pt1;
|
||||
else break;
|
||||
}
|
||||
argp[0] = AObj;
|
||||
argp[nargs] = 0;
|
||||
|
||||
/* create child process */
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
error("could not create child");
|
||||
return 0;
|
||||
}
|
||||
if (child_pid == 0) {
|
||||
/* this is the child process */
|
||||
close(fild1[1]);
|
||||
close(fild2[0]);
|
||||
|
||||
signal(SIGINT, SIG_IGN);
|
||||
|
||||
/* I/O redirection */
|
||||
if (in_redirect) {
|
||||
int fd;
|
||||
close(0);
|
||||
if ((fd = open(in_redirect, 0)) < 0) {
|
||||
error("could not open input file");
|
||||
exit(-1);
|
||||
}
|
||||
if (fd != 0) {
|
||||
dup2(fd, 0);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
if (out_redirect) {
|
||||
int fd;
|
||||
close(1);
|
||||
if ((fd = creat(in_redirect, 0666)) < 0) {
|
||||
error("could not open output file");
|
||||
exit(-1);
|
||||
}
|
||||
if (fd != 1) {
|
||||
dup2(fd, 1);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
/* and run process to be debugged */
|
||||
execv(AObj, argp);
|
||||
error("could not exec %s", AObj);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* debugger */
|
||||
close(fild1[0]);
|
||||
close(fild2[1]);
|
||||
|
||||
pipe(fild1); /* to occupy file descriptors */
|
||||
signal(SIGPIPE, catch_sigpipe);
|
||||
if (! wait_for_child((char *) 0)) {
|
||||
error("child not responding");
|
||||
return 0;
|
||||
}
|
||||
do_items();
|
||||
if (! restoring) send_cont(1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
wait_for_child(s)
|
||||
char *s; /* to pass on to 'stopped' */
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
if (child_pid) {
|
||||
if (ugetm(&m)) {
|
||||
return stopped(s, (t_addr) m.m_size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
signal_child(sig)
|
||||
{
|
||||
if (child_pid) {
|
||||
kill(child_pid, sig);
|
||||
if (sig == SIGKILL) {
|
||||
wait(&child_status);
|
||||
init_run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
catch_sigpipe()
|
||||
{
|
||||
child_pid = 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ureceive(p, c)
|
||||
char *p;
|
||||
long c;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (! child_pid) return 0;
|
||||
|
||||
while (c >= 0x1000) {
|
||||
i = read(from_child, p, 0x1000);
|
||||
if (i <= 0) {
|
||||
if (i == 0) child_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
p += i;
|
||||
c -= i;
|
||||
}
|
||||
while (c > 0) {
|
||||
i = read(from_child, p, (int)c);
|
||||
if (i <= 0) {
|
||||
if (i == 0) child_pid = 0;
|
||||
return 0;
|
||||
}
|
||||
p += i;
|
||||
c -= i;
|
||||
}
|
||||
return c == 0;
|
||||
}
|
||||
|
||||
static int
|
||||
usend(p, c)
|
||||
char *p;
|
||||
long c;
|
||||
{
|
||||
int i;
|
||||
|
||||
while (c >= 0x1000) {
|
||||
i = write(to_child, p, 0x1000);
|
||||
if (i < 0) return 0;
|
||||
p += i;
|
||||
c -= i;
|
||||
}
|
||||
while (c > 0) {
|
||||
i = write(to_child, p, (int)c);
|
||||
if (i < 0) return 0;
|
||||
p += i;
|
||||
c -= i;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ugetm(message)
|
||||
struct message_hdr *message;
|
||||
{
|
||||
if (! ureceive((char *) message, (long) sizeof(struct message_hdr))) {
|
||||
return 0;
|
||||
}
|
||||
if (debug) printf("Got %d\n", message->m_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
uputm(message)
|
||||
struct message_hdr *message;
|
||||
{
|
||||
if (! usend((char *) message, (long) sizeof(struct message_hdr))) {
|
||||
return 0;
|
||||
}
|
||||
if (debug) printf("Sent %d\n", message->m_type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct message_hdr answer;
|
||||
static int single_stepping;
|
||||
|
||||
static int
|
||||
stopped(s, a)
|
||||
char *s; /* stop message */
|
||||
t_addr a; /* address where stopped */
|
||||
{
|
||||
p_position pos;
|
||||
|
||||
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);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
could_send(m, stop_message)
|
||||
struct message_hdr *m;
|
||||
{
|
||||
int type;
|
||||
t_addr a;
|
||||
for (;;) {
|
||||
if (child_pid) {
|
||||
if (! uputm(m) ||
|
||||
! ugetm(&answer)) {
|
||||
if (child_pid) {
|
||||
error("something wrong!");
|
||||
return 1;
|
||||
}
|
||||
wait(&child_status);
|
||||
init_run();
|
||||
if (child_status & 0177) {
|
||||
fprintf(db_out,
|
||||
"Child died with signal %d\n",
|
||||
child_status & 0177);
|
||||
}
|
||||
else {
|
||||
fprintf(db_out,
|
||||
"Child terminated, exit status %d\n",
|
||||
child_status >> 8);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
a = answer.m_size;
|
||||
type = answer.m_type;
|
||||
if (m->m_type & DB_RUN) {
|
||||
/* run command */
|
||||
CurrentScope = get_scope_from_addr((t_addr) a);
|
||||
if (! item_addr_actions(a) &&
|
||||
( type == DB_SS || type == OK)) {
|
||||
/* no explicit breakpoints at this position.
|
||||
Also, child did not stop because of
|
||||
SETSS or SETSSF, otherwise we would
|
||||
have gotten END_SS.
|
||||
So, continue.
|
||||
*/
|
||||
if ((m->m_type & ~ DB_SS) != CONT) {
|
||||
m->m_type = CONT | (m->m_type & DB_SS);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (type != END_SS && single_stepping) {
|
||||
m->m_type = CLRSS;
|
||||
uputm(m) && ugetm(&answer);
|
||||
}
|
||||
single_stepping = 0;
|
||||
}
|
||||
if (stop_message) stopped("stopped", a);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
int
|
||||
get_bytes(size, from, to)
|
||||
long size;
|
||||
t_addr from;
|
||||
char *to;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = GETBYTES;
|
||||
m.m_size = size;
|
||||
ATOBUF(m.m_buf, (char *) from);
|
||||
|
||||
if (! could_send(&m, 0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(answer.m_type == DATA && answer.m_size == m.m_size);
|
||||
|
||||
return ureceive(to, answer.m_size);
|
||||
}
|
||||
|
||||
int
|
||||
get_dump(globmessage, globbuf, stackmessage, stackbuf)
|
||||
struct message_hdr *globmessage, *stackmessage;
|
||||
char **globbuf, **stackbuf;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = DUMP;
|
||||
if (! could_send(&m, 0)) {
|
||||
return 0;
|
||||
}
|
||||
assert(answer.m_type == DGLOB);
|
||||
*globmessage = answer;
|
||||
*globbuf = Malloc((unsigned) answer.m_size);
|
||||
if (! ureceive(*globbuf, answer.m_size) || ! ugetm(stackmessage)) {
|
||||
free(*globbuf);
|
||||
return 0;
|
||||
}
|
||||
assert(stackmessage->m_type == DSTACK);
|
||||
*stackbuf = Malloc((unsigned) stackmessage->m_size);
|
||||
if (! ureceive(*stackbuf, stackmessage->m_size)) {
|
||||
free(*globbuf);
|
||||
free(*stackbuf);
|
||||
return 0;
|
||||
}
|
||||
ATOBUF(globmessage->m_buf+SP_OFF*pointer_size,
|
||||
BUFTOA(stackmessage->m_buf+SP_OFF*pointer_size));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
put_dump(globmessage, globbuf, stackmessage, stackbuf)
|
||||
struct message_hdr *globmessage, *stackmessage;
|
||||
char *globbuf, *stackbuf;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
if (! child_pid) {
|
||||
restoring = 1;
|
||||
start_child(run_command);
|
||||
restoring = 0;
|
||||
}
|
||||
return uputm(globmessage) &&
|
||||
usend(globbuf, globmessage->m_size) &&
|
||||
uputm(stackmessage) &&
|
||||
usend(stackbuf, stackmessage->m_size) &&
|
||||
ugetm(&m) && stopped("restored", m.m_size);
|
||||
}
|
||||
|
||||
t_addr *
|
||||
get_EM_regs(level)
|
||||
int level;
|
||||
{
|
||||
struct message_hdr m;
|
||||
static t_addr buf[5];
|
||||
register t_addr *to = &buf[0];
|
||||
|
||||
m.m_type = GETEMREGS;
|
||||
m.m_size = level;
|
||||
|
||||
if (! could_send(&m, 0)) {
|
||||
return 0;
|
||||
}
|
||||
*to++ = (t_addr) BUFTOA(answer.m_buf);
|
||||
*to++ = (t_addr) BUFTOA(answer.m_buf+pointer_size);
|
||||
*to++ = (t_addr) BUFTOA(answer.m_buf+2*pointer_size);
|
||||
*to++ = (t_addr) BUFTOA(answer.m_buf+3*pointer_size);
|
||||
*to++ = (t_addr) BUFTOA(answer.m_buf+4*pointer_size);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
set_pc(PC)
|
||||
t_addr PC;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = SETEMREGS;
|
||||
m.m_size = 0;
|
||||
ATOBUF(m.m_buf+PC_OFF*pointer_size, (char *)PC);
|
||||
return could_send(&m, 0);
|
||||
}
|
||||
|
||||
int
|
||||
send_cont(stop_message)
|
||||
int stop_message;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = (CONT | (db_ss ? DB_SS : 0));
|
||||
m.m_size = 0;
|
||||
return could_send(&m, stop_message);
|
||||
}
|
||||
|
||||
int
|
||||
do_single_step(type, count)
|
||||
int type;
|
||||
long count;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = type | (db_ss ? DB_SS : 0);
|
||||
m.m_size = count;
|
||||
single_stepping = 1;
|
||||
if (could_send(&m, 1)) {
|
||||
return 1;
|
||||
}
|
||||
single_stepping = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
set_or_clear_breakpoint(a, type)
|
||||
t_addr a;
|
||||
int type;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
if (a == ILL_ADDR || a == NO_ADDR) return 0;
|
||||
|
||||
m.m_type = type;
|
||||
m.m_size = a;
|
||||
if (debug) printf("%s breakpoint at 0x%lx\n", type == SETBP ? "setting" : "clearing", (long) a);
|
||||
if (! could_send(&m, 0)) { }
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
set_or_clear_trace(start, end, type)
|
||||
t_addr start, end;
|
||||
int type;
|
||||
{
|
||||
struct message_hdr m;
|
||||
|
||||
m.m_type = type;
|
||||
ATOBUF(m.m_buf, (char *) start);
|
||||
ATOBUF(m.m_buf+pointer_size, (char *) end);
|
||||
if (debug) printf("%s trace at [0x%lx,0x%lx]\n", type == SETTRACE ? "setting" : "clearing", (long) start, (long) end);
|
||||
if (! could_send(&m, 0)) { }
|
||||
|
||||
return 1;
|
||||
}
|
131
util/grind/scope.cc
Normal file
131
util/grind/scope.cc
Normal file
|
@ -0,0 +1,131 @@
|
|||
/* Scope mechanism */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
#include <out.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include "type.h"
|
||||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
#include "avl.h"
|
||||
|
||||
p_scope PervasiveScope, CurrentScope, FileScope;
|
||||
|
||||
/* STATICALLOCDEF "scope" 10 */
|
||||
|
||||
static AVL_tree ScopeTree;
|
||||
|
||||
static int
|
||||
cmp_starts(s1, s2)
|
||||
char *s1, *s2;
|
||||
{
|
||||
register p_scope c1 = (p_scope)s1, c2 = (p_scope)s2;
|
||||
|
||||
return c1->sc_start < c2->sc_start
|
||||
? -1
|
||||
: c1->sc_start == c2->sc_start
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
open_scope(name, has_activation)
|
||||
p_symbol name;
|
||||
int has_activation;
|
||||
{
|
||||
register p_scope sc = new_scope();
|
||||
|
||||
sc->sc_has_activation_record = has_activation;
|
||||
sc->sc_static_encl = CurrentScope;
|
||||
sc->sc_definedby = name;
|
||||
sc->sc_proclevel = CurrentScope->sc_proclevel;
|
||||
/* sc_proclevel possibly reset by caller */
|
||||
CurrentScope = sc;
|
||||
}
|
||||
|
||||
init_scope()
|
||||
{
|
||||
register p_scope sc = new_scope();
|
||||
|
||||
PervasiveScope = sc;
|
||||
CurrentScope = sc;
|
||||
open_scope((p_symbol) 0, 0); /* this one will be closed at the
|
||||
first N_SO
|
||||
*/
|
||||
ScopeTree = create_avl_tree(cmp_starts);
|
||||
}
|
||||
|
||||
close_scope()
|
||||
{
|
||||
register p_scope sc = CurrentScope;
|
||||
|
||||
assert(sc != 0);
|
||||
CurrentScope = sc->sc_static_encl;
|
||||
}
|
||||
|
||||
add_scope_addr(scope)
|
||||
p_scope scope;
|
||||
{
|
||||
add_to_avl_tree(ScopeTree, (char *)scope);
|
||||
}
|
||||
|
||||
/* extern p_scope get_scope_from_addr(t_addr a);
|
||||
Returns the scope of the code at address 'a', or 0 if it could not be found.
|
||||
*/
|
||||
p_scope
|
||||
get_scope_from_addr(a)
|
||||
t_addr a;
|
||||
{
|
||||
t_scope sc;
|
||||
|
||||
sc.sc_start = a;
|
||||
return (p_scope) find_ngt(ScopeTree, (char *) &sc);
|
||||
}
|
||||
|
||||
/* extern p_scope get_next_scope_from_addr(t_addr a);
|
||||
Returns the scope following the one of the code at address 'a',
|
||||
and that has an activation record,
|
||||
or 0 if it could not be found.
|
||||
*/
|
||||
p_scope
|
||||
get_next_scope_from_addr(a)
|
||||
t_addr a;
|
||||
{
|
||||
t_scope sc;
|
||||
|
||||
sc.sc_start = a;
|
||||
for (;;) {
|
||||
p_scope psc = (p_scope) find_nlt(ScopeTree, (char *) &sc);
|
||||
if (! psc || psc->sc_has_activation_record) return psc;
|
||||
sc.sc_start = psc->sc_start+1;
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* extern int has_static_link(p_scope sc);
|
||||
Returns 1 if the procedure of this scope takes a static link.
|
||||
*/
|
||||
int
|
||||
has_static_link(sc)
|
||||
register p_scope sc;
|
||||
{
|
||||
return sc->sc_proclevel > 1;
|
||||
}
|
||||
|
||||
/* extern p_scope base_scope(p_scope sc);
|
||||
Returns the closest enclosing scope of 'sc' that has an activation record.
|
||||
*/
|
||||
p_scope
|
||||
base_scope(sc)
|
||||
register p_scope sc;
|
||||
{
|
||||
while (sc && ! sc->sc_has_activation_record) {
|
||||
sc = sc->sc_static_encl;
|
||||
}
|
||||
return sc;
|
||||
}
|
54
util/grind/scope.h
Normal file
54
util/grind/scope.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* scope structure */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
typedef struct scope {
|
||||
struct scope *sc_static_encl; /* linked list of enclosing scopes */
|
||||
struct symbol *sc_symbs; /* symbols defined in this scope */
|
||||
struct symbol *sc_definedby; /* symbol defining this scope */
|
||||
long sc_start; /* start address of code of this scope */
|
||||
long sc_bp_opp; /* first breakpoint opportunity */
|
||||
short sc_proclevel; /* proc level of this scope */
|
||||
char sc_has_activation_record;
|
||||
} t_scope, *p_scope;
|
||||
|
||||
extern p_scope PervasiveScope, CurrentScope, FileScope;
|
||||
|
||||
/* extern init_scope();
|
||||
Initializes the scope routines.
|
||||
*/
|
||||
extern init_scope();
|
||||
|
||||
/* extern open_scope(struct symbol *name, int has_activation);
|
||||
Opens a new scope and assigns it to CurrentScope; The new scope is defined
|
||||
by 'name' and if 'has_activation' is set, it has an activation record.
|
||||
*/
|
||||
extern open_scope();
|
||||
|
||||
/* extern close_scope();
|
||||
Closes the current scope; CurrentScope becomes the statically enclosing
|
||||
scope.
|
||||
*/
|
||||
extern close_scope();
|
||||
|
||||
/* extern add_scope_addr(p_scope sc);
|
||||
Adds scope 'sc' to the list of scopes that have an address at runtime.
|
||||
*/
|
||||
extern add_scope_addr();
|
||||
|
||||
/* extern p_scope get_scope_from_addr(t_addr a);
|
||||
Returns the scope of the code at address 'a', or 0 if it could not be found.
|
||||
*/
|
||||
extern p_scope get_scope_from_addr();
|
||||
|
||||
/* extern p_scope get_next_scope_from_addr(t_addr a);
|
||||
Returns the scope following the one of the code at address 'a',
|
||||
and that has an activation record,
|
||||
or 0 if it could not be found.
|
||||
*/
|
||||
extern p_scope get_next_scope_from_addr();
|
||||
|
||||
/* extern p_scope base_scope(p_scope sc);
|
||||
Returns the closest enclosing scope of 'sc' that has an activation record.
|
||||
*/
|
||||
extern p_scope base_scope();
|
8
util/grind/sizes.h
Normal file
8
util/grind/sizes.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
/* For the time being ... */
|
||||
|
||||
#define SZ_INT 4
|
||||
#define SZ_SHORT 2
|
||||
#define SZ_POINTER 4
|
||||
#define SZ_LONG 4
|
||||
#define SZ_FLOAT 4
|
||||
#define SZ_DOUBLE 8
|
237
util/grind/symbol.c
Normal file
237
util/grind/symbol.c
Normal file
|
@ -0,0 +1,237 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Symbol handling */
|
||||
|
||||
#include <alloc.h>
|
||||
#include <out.h>
|
||||
#include <stb.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include "type.h"
|
||||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
#include "tree.h"
|
||||
#include "operator.h"
|
||||
|
||||
p_symbol currfile;
|
||||
|
||||
p_symbol
|
||||
NewSymbol(s, scope, class, nam)
|
||||
char *s;
|
||||
register p_scope scope;
|
||||
struct outname *nam;
|
||||
{
|
||||
register p_symbol sym;
|
||||
|
||||
sym = new_symbol();
|
||||
sym->sy_idf = str2idf(s, 0);
|
||||
sym->sy_scope = scope;
|
||||
sym->sy_prev_sc = scope->sc_symbs;
|
||||
scope->sc_symbs = sym;
|
||||
sym->sy_next = sym->sy_idf->id_def;
|
||||
sym->sy_idf->id_def = sym;
|
||||
sym->sy_class = class;
|
||||
switch(class) {
|
||||
case MODULE:
|
||||
case PROC:
|
||||
case FUNCTION:
|
||||
case VAR:
|
||||
case REGVAR:
|
||||
case LOCVAR:
|
||||
case VARPAR:
|
||||
sym->sy_name.nm_value = nam->on_valu;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* Lookup a definition for 'id' in scope 'scope' with class in the 'class'
|
||||
bitset.
|
||||
*/
|
||||
p_symbol
|
||||
Lookup(id, scope, class)
|
||||
struct idf *id;
|
||||
p_scope scope;
|
||||
int class;
|
||||
{
|
||||
register p_symbol p = id ? id->id_def : 0;
|
||||
|
||||
while (p) {
|
||||
if (p->sy_scope == scope && (p->sy_class & class)) {
|
||||
return p;
|
||||
}
|
||||
p = p->sy_next;
|
||||
}
|
||||
return (p_symbol) 0;
|
||||
}
|
||||
|
||||
/* Lookup a definition for 'id' with class in the 'class' bitset,
|
||||
starting in scope 'sc' and also looking in enclosing scopes.
|
||||
*/
|
||||
p_symbol
|
||||
Lookfromscope(id, class, sc)
|
||||
register struct idf *id;
|
||||
int class;
|
||||
register p_scope sc;
|
||||
{
|
||||
if (! id) return (p_symbol) 0;
|
||||
|
||||
while (sc) {
|
||||
register p_symbol sym = id->id_def;
|
||||
while (sym) {
|
||||
if (sym->sy_scope == sc && (sym->sy_class & class)) {
|
||||
return sym;
|
||||
}
|
||||
sym = sym->sy_next;
|
||||
}
|
||||
sc = sc->sc_static_encl;
|
||||
}
|
||||
return (p_symbol) 0;
|
||||
}
|
||||
|
||||
/* Lookup a definition for 'id' with class in the 'class' bitset,
|
||||
starting in scope 'CurrentScope' and also looking in enclosing scopes.
|
||||
*/
|
||||
p_symbol
|
||||
Lookfor(id, class)
|
||||
register struct idf *id;
|
||||
int class;
|
||||
{
|
||||
return Lookfromscope(id, class, CurrentScope);
|
||||
}
|
||||
|
||||
extern char *strrindex();
|
||||
|
||||
p_symbol
|
||||
add_file(s)
|
||||
char *s;
|
||||
{
|
||||
register p_symbol sym = NewSymbol(s,
|
||||
PervasiveScope,
|
||||
FILESYM,
|
||||
(struct outname *) 0);
|
||||
register char *p;
|
||||
|
||||
sym->sy_file = new_file();
|
||||
sym->sy_file->f_sym = sym;
|
||||
p = strrindex(s, '.');
|
||||
if (p) {
|
||||
char c = *p;
|
||||
p_symbol sym1;
|
||||
|
||||
*p = 0;
|
||||
sym1 = NewSymbol(Salloc(s, (unsigned) strlen(s)+1),
|
||||
PervasiveScope,
|
||||
FILELINK,
|
||||
(struct outname *) 0);
|
||||
*p = c;
|
||||
sym1->sy_filelink = sym;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* Determine if the OP_SELECT tree indicated by 'p' could lead to scope 'sc'.
|
||||
*/
|
||||
static int
|
||||
consistent(p, sc)
|
||||
p_tree p;
|
||||
p_scope sc;
|
||||
{
|
||||
p_tree arg;
|
||||
p_symbol sym;
|
||||
|
||||
assert(p->t_oper == OP_SELECT);
|
||||
sc = sc->sc_static_encl;
|
||||
if (!sc) return 0;
|
||||
|
||||
p = p->t_args[0];
|
||||
|
||||
switch(p->t_oper) {
|
||||
case OP_NAME:
|
||||
sym = Lookfromscope(p->t_idf, FILELINK|FILESYM|PROC|MODULE, sc);
|
||||
return sym != 0;
|
||||
|
||||
case OP_SELECT:
|
||||
arg = p->t_args[1];
|
||||
sym = Lookfromscope(arg->t_idf, FILELINK|FILESYM|PROC|MODULE, sc);
|
||||
if (sym == 0) return 0;
|
||||
return consistent(p, sym->sy_scope);
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return 0; /* notreached? */
|
||||
}
|
||||
|
||||
/* Try to find the name referred to in the node indicated by 'p', and
|
||||
try to be just a little bit intelligent about it.
|
||||
*/
|
||||
p_symbol
|
||||
identify(p, class_set)
|
||||
p_tree p;
|
||||
int class_set;
|
||||
{
|
||||
p_symbol sym = 0;
|
||||
register p_symbol s;
|
||||
p_tree arg;
|
||||
|
||||
switch(p->t_oper) {
|
||||
case OP_NAME:
|
||||
if (! p->t_sc) p->t_sc = CurrentScope;
|
||||
sym = Lookfromscope(p->t_idf, class_set, p->t_sc);
|
||||
if (sym) {
|
||||
/* Found it. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* We could not find it using scope p->t_sc; now we try to identify
|
||||
it using class_set. If this results in only one definition, we
|
||||
take this one.
|
||||
*/
|
||||
s = p->t_idf->id_def;
|
||||
while (s) {
|
||||
if (s->sy_class & class_set) {
|
||||
if (sym) {
|
||||
error("could not identify \"%s\"", p->t_str);
|
||||
sym = 0;
|
||||
break;
|
||||
}
|
||||
sym = s;
|
||||
}
|
||||
s = s->sy_next;
|
||||
}
|
||||
if (!sym && !s) {
|
||||
error("could not find \"%s\"", p->t_str);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_SELECT:
|
||||
arg = p->t_args[1];
|
||||
assert(arg->t_oper == OP_NAME);
|
||||
s = arg->t_idf->id_def;
|
||||
sym = 0;
|
||||
while (s) {
|
||||
if ((s->sy_class & class_set) && consistent(p, s->sy_scope)) {
|
||||
if (sym) {
|
||||
error("could not identify \"%s\"", arg->t_str);
|
||||
sym = 0;
|
||||
}
|
||||
sym = s;
|
||||
}
|
||||
s = s->sy_next;
|
||||
}
|
||||
if (!sym && !s) {
|
||||
error("could not find \"%s\"", arg->t_str);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
return sym;
|
||||
}
|
58
util/grind/symbol.hh
Normal file
58
util/grind/symbol.hh
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* $Header$
|
||||
Symbol table data structure.
|
||||
Each identifier structure refers to a list of possible meanings of this
|
||||
identifier. Each of these meanings is represented by a "symbol" structure.
|
||||
*/
|
||||
|
||||
typedef union constant { /* depends on type */
|
||||
long co_ival;
|
||||
double co_rval;
|
||||
char *co_sval;
|
||||
char *co_setval;
|
||||
} t_const, *p_const;
|
||||
|
||||
typedef struct name {
|
||||
long nm_value; /* address or offset */
|
||||
struct scope *nm_scope; /* for names that define a scope */
|
||||
} t_name, *p_name;
|
||||
|
||||
typedef struct symbol {
|
||||
struct symbol *sy_next; /* link to next meaning */
|
||||
struct symbol *sy_prev_sc; /* link to previous decl in scope */
|
||||
struct type *sy_type; /* type of symbol */
|
||||
int sy_class;
|
||||
#define CONST 0x0001
|
||||
#define TYPE 0x0002
|
||||
#define TAG 0x0004
|
||||
#define MODULE 0x0008
|
||||
#define PROC 0x0010
|
||||
#define FUNCTION 0x0020
|
||||
#define VAR 0x0040
|
||||
#define REGVAR 0x0080
|
||||
#define LOCVAR 0x0100
|
||||
#define VARPAR 0x0200
|
||||
/* #define SYMENTRY 0x0400 /* a non-dbx entry */
|
||||
#define FILESYM 0x0800 /* a filename */
|
||||
#define FILELINK 0x1000 /* a filename without its suffix */
|
||||
struct idf *sy_idf; /* reference back to its idf structure */
|
||||
struct scope *sy_scope; /* scope in which this symbol resides */
|
||||
union {
|
||||
t_const syv_const; /* CONST */
|
||||
t_name syv_name;
|
||||
/* struct outname syv_onam; /* for non-dbx entries */
|
||||
struct file *syv_file; /* for FILESYM */
|
||||
struct symbol *syv_fllink; /* for FILELINK */
|
||||
} sy_v;
|
||||
#define sy_const sy_v.syv_const
|
||||
#define sy_name sy_v.syv_name
|
||||
#define sy_onam sy_v.syv_onam
|
||||
#define sy_file sy_v.syv_file
|
||||
#define sy_filelink sy_v.syv_fllink
|
||||
} t_symbol, *p_symbol;
|
||||
|
||||
/* ALLOCDEF "symbol" 50 */
|
||||
|
||||
extern p_symbol NewSymbol(), Lookup(), Lookfor(), Lookfromscope(), add_file();
|
||||
extern p_symbol identify();
|
||||
|
||||
extern p_symbol currfile;
|
15
util/grind/tok_tools.amk
Normal file
15
util/grind/tok_tools.amk
Normal file
|
@ -0,0 +1,15 @@
|
|||
MAKE_TOKFILE = make.tokfile;
|
||||
MAKE_TOKCASE = make.tokcase;
|
||||
|
||||
%tool gen_tokens (
|
||||
csrc: %in [type = C-src, gen_tokens, persistent];
|
||||
tokfile: %out [type = LLgen-src] => get($csrc, LL-dest);
|
||||
symbols: %out [type = C-src, b] => get($csrc, cc-dest);
|
||||
mktok: %in [type = command] => $MAKE_TOKFILE;
|
||||
mkcase: %in [type = command] => $MAKE_TOKCASE;
|
||||
)
|
||||
{
|
||||
exec($mktok, stdin => $csrc, stdout => $tokfile);
|
||||
exec($mkcase, stdin => $csrc, stdout => $symbols);
|
||||
echo({$tokfile, 'and', $symbols, 'created'});
|
||||
};
|
88
util/grind/tokenname.c
Normal file
88
util/grind/tokenname.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T O K E N D E F I N I T I O N S */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
#include "tokenname.h"
|
||||
#include "Lpars.h"
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
|
||||
/* To centralize the declaration of %tokens, their presence in this
|
||||
file is taken as their declaration. The Makefile will produce
|
||||
a grammar file (tokenfile.g) from this file. This scheme ensures
|
||||
that all tokens have a printable name.
|
||||
Also, the "token2str.c" file is produced from this file.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
struct tokenname tkspec[] = { /* the names of the special tokens */
|
||||
{NAME, "name"},
|
||||
{STRING, "string"},
|
||||
{INTEGER, "number"},
|
||||
{REAL, "real"},
|
||||
{CHAR, "char"},
|
||||
{0, ""}
|
||||
};
|
||||
#endif
|
||||
|
||||
struct tokenname tkidf[] = { /* names of the identifier tokens */
|
||||
{LIST, "list"},
|
||||
{XFILE, "file"},
|
||||
{RUN, "run"},
|
||||
{RERUN, "rerun"},
|
||||
{STOP, "stop"},
|
||||
{WHEN, "when"},
|
||||
{AT, "at"},
|
||||
{IN, "in"},
|
||||
{ON, "on"},
|
||||
{IF, "if"},
|
||||
{CONT, "cont"},
|
||||
{STEP, "step"},
|
||||
{NEXT, "next"},
|
||||
{REGS, "regs"},
|
||||
{WHERE, "where"},
|
||||
{STATUS, "status"},
|
||||
{DELETE, "delete"},
|
||||
{PRINT, "print"},
|
||||
{DUMP, "dump"},
|
||||
{RESTORE, "restore"},
|
||||
{TRACE, "trace"},
|
||||
{-1, "quit"},
|
||||
{0, ""}
|
||||
};
|
||||
|
||||
#if 0
|
||||
struct tokenname tkinternal[] = { /* internal keywords */
|
||||
{0, "0"}
|
||||
};
|
||||
|
||||
struct tokenname tkstandard[] = { /* standard identifiers */
|
||||
{0, ""}
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Some routines to handle tokennames */
|
||||
|
||||
reserve(resv)
|
||||
register struct tokenname *resv;
|
||||
{
|
||||
/* The names of the tokens described in resv are entered
|
||||
as reserved words.
|
||||
*/
|
||||
register struct idf *p;
|
||||
|
||||
while (resv->tn_symbol) {
|
||||
p = str2idf(resv->tn_name, 0);
|
||||
if (!p) fatal("out of Memory");
|
||||
p->id_reserved = resv->tn_symbol;
|
||||
resv++;
|
||||
}
|
||||
}
|
17
util/grind/tokenname.h
Normal file
17
util/grind/tokenname.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*
|
||||
* Author: Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/* T O K E N N A M E S T R U C T U R E */
|
||||
|
||||
/* $Header$ */
|
||||
|
||||
struct tokenname { /* Used for defining the name of a
|
||||
token as identified by its symbol
|
||||
*/
|
||||
int tn_symbol;
|
||||
char *tn_name;
|
||||
};
|
594
util/grind/tree.c
Normal file
594
util/grind/tree.c
Normal file
|
@ -0,0 +1,594 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <varargs.h>
|
||||
#include <assert.h>
|
||||
#include <alloc.h>
|
||||
#include <out.h>
|
||||
|
||||
#include "operator.h"
|
||||
#include "position.h"
|
||||
#include "file.h"
|
||||
#include "idf.h"
|
||||
#include "tree.h"
|
||||
#include "message.h"
|
||||
#include "scope.h"
|
||||
#include "symbol.h"
|
||||
#include "langdep.h"
|
||||
|
||||
extern FILE *db_out;
|
||||
extern t_lineno currline;
|
||||
extern long pointer_size;
|
||||
extern char *strrindex();
|
||||
|
||||
p_tree run_command;
|
||||
|
||||
/*VARARGS1*/
|
||||
p_tree
|
||||
mknode(va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list ap;
|
||||
register p_tree p = new_tree();
|
||||
|
||||
va_start(ap);
|
||||
{
|
||||
register int i, na;
|
||||
|
||||
p->t_oper = va_arg(ap, int);
|
||||
switch(p->t_oper) {
|
||||
case OP_NAME:
|
||||
p->t_idf = va_arg(ap, struct idf *);
|
||||
p->t_str = va_arg(ap, char *);
|
||||
break;
|
||||
case OP_INTEGER:
|
||||
p->t_ival = va_arg(ap, long);
|
||||
break;
|
||||
case OP_AT:
|
||||
p->t_lino = va_arg(ap, long);
|
||||
p->t_filename = va_arg(ap, char *);
|
||||
break;
|
||||
case OP_NEXT:
|
||||
case OP_STEP:
|
||||
case OP_REGS:
|
||||
case OP_DELETE:
|
||||
case OP_RESTORE:
|
||||
p->t_ival = va_arg(ap, long);
|
||||
break;
|
||||
default:
|
||||
na = nargs(p->t_oper);
|
||||
assert(na <= MAXARGS);
|
||||
for (i = 0; i < na; i++) {
|
||||
p->t_args[i] = va_arg(ap, p_tree);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
return p;
|
||||
}
|
||||
|
||||
freenode(p)
|
||||
register p_tree p;
|
||||
{
|
||||
register int na, i;
|
||||
|
||||
if (! p) return;
|
||||
switch(p->t_oper) {
|
||||
case OP_NAME:
|
||||
case OP_INTEGER:
|
||||
case OP_AT:
|
||||
case OP_CONT:
|
||||
case OP_NEXT:
|
||||
case OP_STEP:
|
||||
case OP_REGS:
|
||||
case OP_DELETE:
|
||||
break;
|
||||
default:
|
||||
na = nargs(p->t_oper);
|
||||
assert(na <= MAXARGS);
|
||||
for (i = 0; i < na; i++) {
|
||||
freenode(p->t_args[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
free_tree(p);
|
||||
}
|
||||
|
||||
print_node(p, top_level)
|
||||
register p_tree p;
|
||||
{
|
||||
if (!p) return;
|
||||
switch(p->t_oper) {
|
||||
case OP_LIST:
|
||||
fputs("list ", db_out);
|
||||
if (p->t_args[0]) {
|
||||
print_node(p->t_args[0], 0);
|
||||
if (p->t_args[1]) {
|
||||
fputs(", ", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OP_PRINT:
|
||||
fputs("print ", db_out);
|
||||
print_node(p->t_args[0], 0);
|
||||
break;
|
||||
case OP_FILE:
|
||||
fputs("file ", db_out);
|
||||
print_node(p->t_args[0], 0);
|
||||
break;
|
||||
case OP_DELETE:
|
||||
fprintf(db_out, "delete %d", p->t_ival);
|
||||
break;
|
||||
case OP_REGS:
|
||||
fprintf(db_out, "regs %d", p->t_ival);
|
||||
break;
|
||||
case OP_NEXT:
|
||||
fprintf(db_out, "next %d", p->t_ival);
|
||||
break;
|
||||
case OP_STEP:
|
||||
fprintf(db_out, "step %d", p->t_ival);
|
||||
break;
|
||||
case OP_STATUS:
|
||||
fputs("status", db_out);
|
||||
break;
|
||||
case OP_DUMP:
|
||||
fputs("dump ", db_out);
|
||||
print_position(p->t_address, 1);
|
||||
break;
|
||||
case OP_RESTORE:
|
||||
fprintf(db_out, "restore %d", p->t_ival);
|
||||
break;
|
||||
case OP_WHERE:
|
||||
fputs("where", db_out);
|
||||
break;
|
||||
case OP_CONT:
|
||||
fputs("cont", db_out);
|
||||
if (p->t_args[0]) {
|
||||
fprintf(db_out, " %d", p->t_args[0]->t_ival);
|
||||
}
|
||||
if (p->t_args[1]) {
|
||||
fputs(" ", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case OP_WHEN:
|
||||
fputs("when ", db_out);
|
||||
if (p->t_address != NO_ADDR) {
|
||||
print_position(p->t_address, 1);
|
||||
}
|
||||
else print_node(p->t_args[0], 0);
|
||||
if (p->t_args[1]) {
|
||||
fputs(" if ", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
}
|
||||
p = p->t_args[2];
|
||||
fputs(" { ", db_out);
|
||||
while (p->t_oper == OP_LINK) {
|
||||
print_node(p->t_args[0], 0);
|
||||
fputs("; ", db_out);
|
||||
p = p->t_args[1];
|
||||
}
|
||||
print_node(p, 0);
|
||||
fputs(" }", db_out);
|
||||
break;
|
||||
case OP_STOP:
|
||||
fputs("stop ", db_out);
|
||||
if (p->t_address != NO_ADDR) {
|
||||
print_position(p->t_address, 1);
|
||||
}
|
||||
else print_node(p->t_args[0], 0);
|
||||
if (p->t_args[1]) {
|
||||
fputs(" if ", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
}
|
||||
break;
|
||||
case OP_TRACE:
|
||||
fputs("trace ", db_out);
|
||||
if (p->t_args[2]) {
|
||||
fputs("on ", db_out);
|
||||
print_node(p->t_args[2], 0);
|
||||
fputs(" ", db_out);
|
||||
}
|
||||
if (p->t_address != NO_ADDR) {
|
||||
print_position(p->t_address, 1);
|
||||
}
|
||||
else print_node(p->t_args[0], 0);
|
||||
if (p->t_args[1]) {
|
||||
fputs(" if ", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
}
|
||||
break;
|
||||
case OP_AT:
|
||||
fprintf(db_out, "at \"%s\":%ld", p->t_filename, p->t_lino);
|
||||
break;
|
||||
case OP_IN:
|
||||
fputs("in ", db_out);
|
||||
print_node(p->t_args[0], 0);
|
||||
break;
|
||||
case OP_SELECT:
|
||||
print_node(p->t_args[0], 0);
|
||||
fputs("`", db_out);
|
||||
print_node(p->t_args[1], 0);
|
||||
break;
|
||||
case OP_NAME:
|
||||
fputs(p->t_str, db_out);
|
||||
break;
|
||||
case OP_INTEGER:
|
||||
fprintf(db_out, "%d", p->t_ival);
|
||||
break;
|
||||
}
|
||||
if (top_level) fputs("\n", db_out);
|
||||
}
|
||||
|
||||
int
|
||||
repeatable(com)
|
||||
p_tree com;
|
||||
{
|
||||
switch(com->t_oper) {
|
||||
case OP_CONT:
|
||||
case OP_NEXT:
|
||||
case OP_STEP:
|
||||
case OP_LIST:
|
||||
case OP_STATUS:
|
||||
case OP_PRINT:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
in_status(com)
|
||||
p_tree com;
|
||||
{
|
||||
switch(com->t_oper) {
|
||||
case OP_STOP:
|
||||
case OP_WHEN:
|
||||
case OP_TRACE:
|
||||
case OP_DUMP:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
eval(p)
|
||||
p_tree p;
|
||||
{
|
||||
if (p) (*operators[p->t_oper].op_fun)(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,
|
||||
p->t_args[1] ? (int) p->t_args[1]->t_ival : (int) currline+9);
|
||||
currline = p->t_args[1] ? p->t_args[1]->t_ival + 1 : currline + 10;
|
||||
}
|
||||
else fprintf(db_out, "no current file\n");
|
||||
}
|
||||
|
||||
do_file(p)
|
||||
p_tree 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 fprintf(db_out, "no current file\n");
|
||||
}
|
||||
|
||||
newfile(id)
|
||||
register struct idf *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;
|
||||
}
|
||||
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, 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]);
|
||||
|
||||
if (a == ILL_ADDR) {
|
||||
return;
|
||||
}
|
||||
|
||||
p->t_address = a;
|
||||
add_to_item_list(p);
|
||||
if (a != NO_ADDR) {
|
||||
if (! set_or_clear_breakpoint(a, SETBP)) {
|
||||
error("could not set breakpoint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_trace(p)
|
||||
p_tree p;
|
||||
{
|
||||
t_addr a;
|
||||
t_addr e;
|
||||
|
||||
p->t_address = NO_ADDR;
|
||||
if (p->t_args[0]) {
|
||||
a = get_pos(p->t_args[0]);
|
||||
if (a == ILL_ADDR) return;
|
||||
if (p->t_args[0]->t_oper == OP_AT) {
|
||||
e = a;
|
||||
p->t_address = a;
|
||||
}
|
||||
else {
|
||||
p_scope sc = get_next_scope_from_addr(a+1);
|
||||
|
||||
if (sc) e = sc->sc_start - 1;
|
||||
else e = 0xffffffff;
|
||||
}
|
||||
if (! set_or_clear_trace(a, e, SETTRACE)) {
|
||||
error("could not set trace");
|
||||
}
|
||||
}
|
||||
add_to_item_list(p);
|
||||
}
|
||||
|
||||
do_continue(p)
|
||||
p_tree p;
|
||||
{
|
||||
int count;
|
||||
|
||||
if (p) {
|
||||
count = p->t_args[0]->t_ival;
|
||||
if (p->t_args[1]) {
|
||||
t_addr a = get_addr_from_position(&(p->t_args[1]->t_pos));
|
||||
p_scope sc = get_scope_from_addr(a);
|
||||
|
||||
if (a == ILL_ADDR || base_scope(sc) != base_scope(CurrentScope) ||
|
||||
! set_pc(a)) {
|
||||
error("cannot continue at line %d",
|
||||
p->t_args[1]->t_lino);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else count = 1;
|
||||
while (count--) {
|
||||
if (! send_cont(count==0)) {
|
||||
error("no debuggee");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do_step(p)
|
||||
p_tree p;
|
||||
{
|
||||
if (! do_single_step(SETSS, p->t_ival)) {
|
||||
error("no debuggee");
|
||||
}
|
||||
}
|
||||
|
||||
do_next(p)
|
||||
p_tree p;
|
||||
{
|
||||
|
||||
if (! do_single_step(SETSSF, p->t_ival)) {
|
||||
error("no debuggee");
|
||||
}
|
||||
}
|
||||
|
||||
extern t_addr *get_EM_regs();
|
||||
|
||||
do_regs(p)
|
||||
p_tree p;
|
||||
{
|
||||
t_addr *buf;
|
||||
int n = p->t_ival;
|
||||
|
||||
if (! (buf = get_EM_regs(n))) {
|
||||
error("no debuggee");
|
||||
return;
|
||||
}
|
||||
fprintf(db_out, "EM registers %d levels back:\n", n);
|
||||
fprintf(db_out, "\tLocalBase =\t0x%lx\n\tArgumentBase =\t0x%lx\n",
|
||||
(long) buf[LB_OFF], (long) buf[AB_OFF]);
|
||||
fprintf(db_out, "\tProgramCounter=\t0x%lx\n\tHeapPointer = \t0x%lx\n",
|
||||
(long) buf[PC_OFF],
|
||||
(long) buf[HP_OFF]);
|
||||
fprintf(db_out, "\tStackPointer =\t0x%lx\n", (long) buf[SP_OFF]);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
do_where(p)
|
||||
p_tree p;
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (;;) {
|
||||
t_addr AB;
|
||||
t_addr PC;
|
||||
p_scope sc;
|
||||
t_addr *buf;
|
||||
|
||||
if (! (buf = get_EM_regs(i++))) {
|
||||
error("no debuggee");
|
||||
return;
|
||||
}
|
||||
AB = buf[AB_OFF];
|
||||
PC = buf[PC_OFF];
|
||||
if (! AB) break;
|
||||
sc = base_scope(get_scope_from_addr(PC));
|
||||
if (! sc || sc->sc_start > PC) break;
|
||||
fprintf(db_out, "%s(", sc->sc_definedby->sy_idf->id_text);
|
||||
print_params(sc->sc_definedby->sy_type, AB, has_static_link(sc));
|
||||
fputs(") ", db_out);
|
||||
print_position(PC, 0);
|
||||
fputs("\n", db_out);
|
||||
}
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
do_status(p)
|
||||
p_tree p;
|
||||
{
|
||||
print_items();
|
||||
}
|
||||
|
||||
extern p_tree remove_from_item_list();
|
||||
|
||||
do_delete(p)
|
||||
p_tree p;
|
||||
{
|
||||
p = remove_from_item_list((int) p->t_ival);
|
||||
|
||||
if (p) switch(p->t_oper) {
|
||||
case OP_WHEN:
|
||||
case OP_STOP: {
|
||||
t_addr a = get_pos(p->t_args[0]);
|
||||
|
||||
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||
set_or_clear_breakpoint(a, CLRBP);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_TRACE: {
|
||||
t_addr a = get_pos(p->t_args[0]);
|
||||
|
||||
if (a != ILL_ADDR && a != NO_ADDR) {
|
||||
t_addr e;
|
||||
if (p->t_args[0]->t_oper == OP_AT) {
|
||||
e = a;
|
||||
}
|
||||
else {
|
||||
p_scope sc = get_next_scope_from_addr(a+1);
|
||||
|
||||
if (sc) e = sc->sc_start - 1;
|
||||
else e = 0xffffffff;
|
||||
}
|
||||
set_or_clear_trace(a, e, CLRTRACE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OP_DUMP:
|
||||
free_dump(p);
|
||||
}
|
||||
freenode(p);
|
||||
}
|
||||
|
||||
do_print(p)
|
||||
p_tree p;
|
||||
{
|
||||
p_symbol sym;
|
||||
|
||||
switch(p->t_oper) {
|
||||
case OP_PRINT:
|
||||
do_print(p->t_args[0]);
|
||||
break;
|
||||
case OP_LINK:
|
||||
do_print(p->t_args[0]);
|
||||
do_print(p->t_args[1]);
|
||||
break;
|
||||
case OP_NAME:
|
||||
case OP_SELECT:
|
||||
sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR);
|
||||
if (! sym) return;
|
||||
print_node(p, 0);
|
||||
if (! print_sym(sym)) {
|
||||
fputs(" currently not available\n", db_out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
perform(p, a)
|
||||
register p_tree p;
|
||||
t_addr a;
|
||||
{
|
||||
switch(p->t_oper) {
|
||||
case OP_WHEN:
|
||||
p = p->t_args[2];
|
||||
while (p->t_oper == OP_LINK) {
|
||||
eval(p->t_args[0]);
|
||||
p = p->t_args[1];
|
||||
}
|
||||
eval(p);
|
||||
break;
|
||||
case OP_TRACE:
|
||||
if (p->t_args[0] && p->t_args[0]->t_oper == OP_IN) {
|
||||
register p_scope sc = base_scope(CurrentScope);
|
||||
|
||||
if (sc != get_scope_from_addr(p->t_args[0]->t_address)) {
|
||||
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]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
32
util/grind/tree.hh
Normal file
32
util/grind/tree.hh
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* $Header$ */
|
||||
|
||||
#define MAXARGS 3
|
||||
|
||||
typedef struct tree {
|
||||
int t_oper; /* operator */
|
||||
t_addr t_address; /* some operators use an address */
|
||||
int t_itemno; /* item number in status list */
|
||||
union {
|
||||
long tt_ival;
|
||||
struct {
|
||||
struct idf *tt_idf;
|
||||
char *tt_str;
|
||||
struct scope *tt_scope;
|
||||
} tt_x;
|
||||
struct tree *tt_args[MAXARGS];
|
||||
t_position tt_pos;
|
||||
} t_xxxx;
|
||||
#define t_ival t_xxxx.tt_ival
|
||||
#define t_idf t_xxxx.tt_x.tt_idf
|
||||
#define t_str t_xxxx.tt_x.tt_str
|
||||
#define t_sc t_xxxx.tt_x.tt_scope
|
||||
#define t_args t_xxxx.tt_args
|
||||
#define t_lino t_xxxx.tt_pos.lineno
|
||||
#define t_filename t_xxxx.tt_pos.filename
|
||||
#define t_pos t_xxxx.tt_pos
|
||||
} t_tree, *p_tree;
|
||||
|
||||
/* ALLOCDEF "tree" 100 */
|
||||
|
||||
extern p_tree mknode();
|
||||
extern p_tree run_command;
|
387
util/grind/type.c
Normal file
387
util/grind/type.c
Normal file
|
@ -0,0 +1,387 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* Routines to create type structures */
|
||||
|
||||
#include <alloc.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "sizes.h"
|
||||
#include "symbol.h"
|
||||
#include "scope.h"
|
||||
#include "message.h"
|
||||
#include "langdep.h"
|
||||
|
||||
p_type int_type, char_type, short_type, long_type;
|
||||
p_type uint_type, uchar_type, ushort_type, ulong_type;
|
||||
p_type void_type, incomplete_type;
|
||||
p_type float_type, double_type;
|
||||
p_type string_type;
|
||||
|
||||
long int_size = SZ_INT,
|
||||
char_size = 1,
|
||||
short_size = SZ_SHORT,
|
||||
long_size = SZ_LONG,
|
||||
pointer_size = SZ_POINTER;
|
||||
|
||||
long float_size = SZ_FLOAT,
|
||||
double_size = SZ_DOUBLE;
|
||||
|
||||
struct bounds {
|
||||
long low, high;
|
||||
};
|
||||
|
||||
static struct bounds ibounds[2] = {
|
||||
{ -128, 127 },
|
||||
{ -32768, 32767 }
|
||||
};
|
||||
|
||||
static struct bounds ubounds[2] = {
|
||||
{ 0, 255 },
|
||||
{ 0, 65535 }
|
||||
};
|
||||
|
||||
static long max_int[8], max_uns[8];
|
||||
|
||||
struct integer_types {
|
||||
long maxval;
|
||||
p_type type;
|
||||
};
|
||||
|
||||
static struct integer_types i_types[4];
|
||||
static struct integer_types u_types[5];
|
||||
|
||||
#define ufit(n, nb) Xfit(n, nb, ubounds)
|
||||
#define ifit(n, nb) Xfit(n, nb, ibounds)
|
||||
#define Xfit(n, nb, b) ((n) >= (b)[(nb)-1].low && (n) <= (b)[(nb)-1].high)
|
||||
|
||||
/* Create a subrange type, but is it really a subrange? */
|
||||
p_type
|
||||
subrange_type(A, base_index, c1, c2, result_index)
|
||||
int *base_index, *result_index;
|
||||
long c1, c2;
|
||||
{
|
||||
int itself = 0;
|
||||
register p_type p;
|
||||
p_type base_type;
|
||||
|
||||
if (!A) {
|
||||
/* Subrange of itself is a special case ... */
|
||||
if (result_index &&
|
||||
result_index[0] == base_index[0] &&
|
||||
result_index[1] == base_index[1]) {
|
||||
|
||||
/* c1 = 0 and c2 = 0 -> void */
|
||||
if (c1 == 0 && c2 == 0) {
|
||||
return void_type;
|
||||
}
|
||||
|
||||
/* c1 = 0 and c2 = 127 -> char ??? */
|
||||
if (c1 == 0 && c2 == 127) {
|
||||
return char_type;
|
||||
}
|
||||
itself = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (itself) base_type = int_type; else base_type = *(tp_lookup(base_index));
|
||||
|
||||
if (! A) {
|
||||
/* c2 = 0 and c1 > 0 -> real */
|
||||
if (c2 == 0 && c1 > 0) {
|
||||
if (c1 == float_size) return float_type;
|
||||
return double_type;
|
||||
}
|
||||
|
||||
/* c1 = 0 and base_index indicates int_type or itself -> unsigned,
|
||||
c1 = -c2 - 1 and base_index indicates int_type or itself -> integer
|
||||
*/
|
||||
if (itself || base_type == int_type) {
|
||||
register struct integer_types *ip = 0;
|
||||
if (c1 == 0) {
|
||||
ip = &u_types[0];
|
||||
}
|
||||
else if (c1 == -c2 - 1) {
|
||||
ip = &i_types[0];
|
||||
}
|
||||
if (ip) {
|
||||
while (ip->maxval != 0 && ip->maxval != c2) ip++;
|
||||
if (ip->maxval) return ip->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* if we get here, it actually is a subrange type */
|
||||
p = new_type();
|
||||
p->ty_class = T_SUBRANGE;
|
||||
p->ty_low = c1;
|
||||
p->ty_up = c2;
|
||||
p->ty_base = base_type;
|
||||
p->ty_A = A;
|
||||
|
||||
/* determine size of subrange type */
|
||||
p->ty_size = base_type->ty_size;
|
||||
if (!A && p->ty_base == uint_type) {
|
||||
if (ufit(p->ty_up, 1)) {
|
||||
p->ty_size = 1;
|
||||
}
|
||||
else if (ufit(p->ty_up, (int)short_size)) {
|
||||
p->ty_size = short_size;
|
||||
}
|
||||
}
|
||||
if (!A && p->ty_base == int_type) {
|
||||
if (ifit(p->ty_up, 1) && ifit(p->ty_low, 1)) {
|
||||
p->ty_size = 1;
|
||||
}
|
||||
else if (ifit(p->ty_up, (int)short_size) &&
|
||||
ifit(p->ty_low, (int)short_size)) {
|
||||
p->ty_size = short_size;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static long
|
||||
nel(tp)
|
||||
register p_type tp;
|
||||
{
|
||||
switch(tp->ty_class) {
|
||||
case T_SUBRANGE:
|
||||
if (tp->ty_A) return 0;
|
||||
if (tp->ty_low <= tp->ty_up) return tp->ty_up - tp->ty_low + 1;
|
||||
return tp->ty_low - tp->ty_up + 1;
|
||||
case T_UNSIGNED:
|
||||
case T_INTEGER:
|
||||
if (tp->ty_size == 1) return 256;
|
||||
if (tp->ty_size == 2) return 65536L;
|
||||
assert(0);
|
||||
break;
|
||||
case T_ENUM:
|
||||
return tp->ty_nenums;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_type
|
||||
array_type(bound_type, el_type)
|
||||
p_type bound_type, el_type;
|
||||
{
|
||||
register p_type tp = new_type();
|
||||
|
||||
tp->ty_class = T_ARRAY;
|
||||
tp->ty_index = bound_type;
|
||||
tp->ty_elements = el_type;
|
||||
tp->ty_size = (*currlang->arrayelsize)(el_type->ty_size) * nel(bound_type);
|
||||
return tp;
|
||||
}
|
||||
|
||||
p_type
|
||||
basic_type(fund, size)
|
||||
int fund;
|
||||
long size;
|
||||
{
|
||||
register p_type p = new_type();
|
||||
|
||||
p->ty_class = fund;
|
||||
p->ty_size = size;
|
||||
return p;
|
||||
}
|
||||
|
||||
set_bounds(tp)
|
||||
register p_type tp;
|
||||
{
|
||||
/* Determine the size and low of a set type */
|
||||
register p_type base = tp->ty_setbase;
|
||||
|
||||
if (base->ty_class == T_SUBRANGE) {
|
||||
tp->ty_size = (base->ty_up - base->ty_low + 7) >> 3;
|
||||
tp->ty_setlow = base->ty_low;
|
||||
}
|
||||
else if (base->ty_class == T_INTEGER) {
|
||||
tp->ty_size = (max_int[(int)base->ty_size] + 1) >> 2;
|
||||
tp->ty_setlow = -max_int[(int)base->ty_size] - 1;
|
||||
}
|
||||
else {
|
||||
assert(base->ty_class == T_UNSIGNED);
|
||||
tp->ty_size = (max_uns[(int)base->ty_size] + 1) >> 3;
|
||||
tp->ty_setlow = 0;
|
||||
}
|
||||
}
|
||||
|
||||
init_types()
|
||||
{
|
||||
register int i = 0;
|
||||
register long x = 0;
|
||||
|
||||
while (x >= 0) {
|
||||
i++;
|
||||
x = (x << 8) + 0377;
|
||||
max_uns[i] = x;
|
||||
max_int[i] = x & ~(1L << (8*i - 1));
|
||||
}
|
||||
int_type = basic_type(T_INTEGER, int_size);
|
||||
long_type = basic_type(T_INTEGER, long_size);
|
||||
short_type = basic_type(T_INTEGER, short_size);
|
||||
char_type = basic_type(T_INTEGER, char_size);
|
||||
uint_type = basic_type(T_UNSIGNED, int_size);
|
||||
ulong_type = basic_type(T_UNSIGNED, long_size);
|
||||
ushort_type = basic_type(T_UNSIGNED, short_size);
|
||||
uchar_type = basic_type(T_UNSIGNED, char_size);
|
||||
string_type = basic_type(T_STRING, 0L);
|
||||
void_type = basic_type(T_VOID, 0L);
|
||||
incomplete_type = basic_type(T_INCOMPLETE, 0L);
|
||||
float_type = basic_type(T_REAL, float_size);
|
||||
double_type = basic_type(T_REAL, double_size);
|
||||
|
||||
i_types[0].maxval = max_int[(int)int_size]; i_types[0].type = int_type;
|
||||
i_types[1].maxval = max_int[(int)short_size]; i_types[1].type = short_type;
|
||||
i_types[2].maxval = max_int[(int)long_size]; i_types[2].type = long_type;
|
||||
u_types[0].maxval = max_uns[(int)int_size]; u_types[0].type = uint_type;
|
||||
u_types[1].maxval = max_uns[(int)short_size]; u_types[1].type = ushort_type;
|
||||
u_types[2].maxval = max_uns[(int)long_size]; u_types[2].type = ulong_type;
|
||||
u_types[3].maxval = max_uns[1]; u_types[3].type = uchar_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some code to handle type indices, which are pairs of integers.
|
||||
* What we need is a two-dimensional array, but we don't know how large
|
||||
* it is going to be, so we use a list of rows instead.
|
||||
*/
|
||||
static struct tp_index {
|
||||
unsigned len;
|
||||
p_type *row;
|
||||
} *list_row;
|
||||
static unsigned list_len;
|
||||
|
||||
#define NINCR 10
|
||||
|
||||
p_type *
|
||||
tp_lookup(type_index)
|
||||
int *type_index;
|
||||
{
|
||||
register int i;
|
||||
register struct tp_index *p;
|
||||
|
||||
while (type_index[0] >= list_len) {
|
||||
if (list_len) {
|
||||
list_row = (struct tp_index *) Realloc((char *) list_row,
|
||||
(list_len += NINCR) * sizeof(struct tp_index));
|
||||
}
|
||||
else list_row = (struct tp_index *)
|
||||
Malloc((list_len = NINCR) * sizeof(struct tp_index));
|
||||
for (i = NINCR; i > 0; i--) {
|
||||
list_row[list_len - i].len = 0;
|
||||
}
|
||||
}
|
||||
p = &list_row[type_index[0]];
|
||||
while (type_index[1] >= p->len) {
|
||||
if (p->len) {
|
||||
p->row = (p_type *) Realloc((char *) p->row,
|
||||
(p->len += NINCR) * sizeof(p_type));
|
||||
}
|
||||
else p->row = (p_type *) Malloc((p->len = NINCR) * sizeof(p_type));
|
||||
for (i = NINCR; i > 0; i--) {
|
||||
p->row[p->len - i] = 0;
|
||||
}
|
||||
}
|
||||
return &(p->row[type_index[1]]);
|
||||
}
|
||||
|
||||
clean_tp_tab()
|
||||
{
|
||||
if (list_len) {
|
||||
register int i = list_len;
|
||||
|
||||
while (--i >= 0) {
|
||||
register int j = list_row[i].len;
|
||||
if (j) {
|
||||
while (--j > 0) {
|
||||
p_type p = list_row[i].row[j];
|
||||
if (p == incomplete_type) {
|
||||
error("incomplete type (%d,%d) 0x%x", i, j, &list_row[i].row[j]);
|
||||
}
|
||||
}
|
||||
free((char *) list_row[i].row);
|
||||
}
|
||||
}
|
||||
free((char *) list_row);
|
||||
list_len = 0;
|
||||
list_row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
end_literal(tp, maxval)
|
||||
register p_type tp;
|
||||
long maxval;
|
||||
{
|
||||
tp->ty_literals = (struct literal *)
|
||||
Realloc((char *) tp->ty_literals,
|
||||
tp->ty_nenums * sizeof(struct literal));
|
||||
if (ufit(maxval, 1)) tp->ty_size = 1;
|
||||
else if (ufit(maxval, (int)short_size)) tp->ty_size = short_size;
|
||||
else tp->ty_size = int_size;
|
||||
}
|
||||
|
||||
long
|
||||
param_size(t, v)
|
||||
int v;
|
||||
p_type t;
|
||||
{
|
||||
if (v == 'i' || v == 'v') {
|
||||
/* addresss; only exception is a conformant array, which also
|
||||
takes a descriptor.
|
||||
*/
|
||||
if (t->ty_class == T_ARRAY &&
|
||||
t->ty_index->ty_class == T_SUBRANGE &&
|
||||
t->ty_index->ty_A) {
|
||||
return pointer_size + 3 * int_size;
|
||||
}
|
||||
return pointer_size;
|
||||
}
|
||||
return ((t->ty_size + int_size - 1) / int_size) * int_size;
|
||||
}
|
||||
|
||||
add_param_type(v, s)
|
||||
int v; /* 'v' or 'i' for address, 'p' for value */
|
||||
p_symbol s; /* parameter itself */
|
||||
{
|
||||
register p_scope sc = base_scope(s->sy_scope);
|
||||
register p_type prc_type;
|
||||
|
||||
if (! sc) return;
|
||||
prc_type = sc->sc_definedby->sy_type;
|
||||
assert(prc_type->ty_class == T_PROCEDURE);
|
||||
|
||||
prc_type->ty_nparams++;
|
||||
prc_type->ty_params = (struct param *) Realloc((char *) prc_type->ty_params,
|
||||
(unsigned)prc_type->ty_nparams * sizeof(struct param));
|
||||
prc_type->ty_params[prc_type->ty_nparams - 1].par_type = s->sy_type;
|
||||
prc_type->ty_params[prc_type->ty_nparams - 1].par_kind = v;
|
||||
prc_type->ty_nbparams += param_size(s->sy_type, v);
|
||||
}
|
||||
|
||||
/* Compute the size of a parameter of dynamic size
|
||||
*/
|
||||
|
||||
long
|
||||
compute_size(tp, AB)
|
||||
p_type tp;
|
||||
char *AB;
|
||||
{
|
||||
long low, high;
|
||||
|
||||
assert(tp->ty_class == T_ARRAY);
|
||||
assert(tp->ty_index->ty_class == T_SUBRANGE);
|
||||
assert(tp->ty_index->ty_A != 0);
|
||||
|
||||
if (tp->ty_index->ty_A & 1) {
|
||||
low = BUFTOI(AB+tp->ty_index->ty_low);
|
||||
} else low = tp->ty_index->ty_low;
|
||||
if (tp->ty_index->ty_A & 2) {
|
||||
high = BUFTOI(AB+tp->ty_index->ty_up);
|
||||
} else high = tp->ty_index->ty_up;
|
||||
return (high - low + 1) * tp->ty_elements->ty_size;
|
||||
}
|
118
util/grind/type.hh
Normal file
118
util/grind/type.hh
Normal file
|
@ -0,0 +1,118 @@
|
|||
/* $Header$ */
|
||||
|
||||
/* internal type representation */
|
||||
|
||||
/* structure for struct/union elements */
|
||||
struct fields {
|
||||
long fld_pos; /* position of field */
|
||||
long fld_bitsize; /* size in bits */
|
||||
struct type *fld_type; /* type of field */
|
||||
char *fld_name; /* name of field */
|
||||
};
|
||||
|
||||
/* structure for enumeration literals */
|
||||
struct literal {
|
||||
long lit_val; /* value of literal */
|
||||
char *lit_name; /* name of literal */
|
||||
};
|
||||
|
||||
/* structure for parameters */
|
||||
struct param {
|
||||
struct type *par_type; /* type of parameter */
|
||||
char par_kind; /* kind of parameter ('p', 'i', or 'v') */
|
||||
};
|
||||
|
||||
typedef struct type {
|
||||
short ty_class;
|
||||
#define T_SUBRANGE 1
|
||||
#define T_ARRAY 2
|
||||
#define T_STRUCT 3
|
||||
#define T_UNION 4
|
||||
#define T_ENUM 5
|
||||
#define T_POINTER 6
|
||||
#define T_FILE 7
|
||||
#define T_PROCEDURE 8
|
||||
#define T_SET 9
|
||||
#define T_REAL 10
|
||||
#define T_INTEGER 11
|
||||
#define T_VOID 12
|
||||
#define T_UNSIGNED 13
|
||||
#define T_STRING 14 /* only for string constants ... */
|
||||
#define T_INCOMPLETE 100
|
||||
short ty_flags;
|
||||
#define T_CROSS 0x0001
|
||||
long ty_size;
|
||||
union {
|
||||
/* cross references */
|
||||
char *typ_tag;
|
||||
#define ty_tag ty_v.typ_tag
|
||||
/* procedures/functions: */
|
||||
struct {
|
||||
int typ_nparams;
|
||||
struct type *typ_retval;
|
||||
struct param *typ_params;
|
||||
long typ_nbparams;
|
||||
} ty_proc;
|
||||
#define ty_nparams ty_v.ty_proc.typ_nparams
|
||||
#define ty_retval ty_v.ty_proc.typ_retval
|
||||
#define ty_params ty_v.ty_proc.typ_params
|
||||
#define ty_nbparams ty_v.ty_proc.typ_nbparams
|
||||
/* pointers, files: */
|
||||
struct type *typ_ptrto;
|
||||
#define ty_ptrto ty_v.typ_ptrto
|
||||
#define ty_fileof ty_v.typ_ptrto
|
||||
/* arrays: */
|
||||
struct {
|
||||
struct type *typ_index;
|
||||
struct type *typ_elements;
|
||||
} ty_array;
|
||||
#define ty_index ty_v.ty_array.typ_index
|
||||
#define ty_elements ty_v.ty_array.typ_elements
|
||||
/* subranges: */
|
||||
struct {
|
||||
long typ_low, typ_up;
|
||||
int typ_A;
|
||||
struct type *typ_base;
|
||||
} ty_subrange;
|
||||
#define ty_A ty_v.ty_subrange.typ_A
|
||||
#define ty_low ty_v.ty_subrange.typ_low
|
||||
#define ty_up ty_v.ty_subrange.typ_up
|
||||
#define ty_base ty_v.ty_subrange.typ_base
|
||||
/* structures/unions: */
|
||||
struct {
|
||||
unsigned typ_nfields; /* number of field structures */
|
||||
struct fields *typ_fields;
|
||||
} ty_struct;
|
||||
#define ty_nfields ty_v.ty_struct.typ_nfields
|
||||
#define ty_fields ty_v.ty_struct.typ_fields
|
||||
/* enumerations: */
|
||||
struct {
|
||||
unsigned typ_nenums; /* number of enumeration literals */
|
||||
struct literal *typ_literals;
|
||||
} ty_enum;
|
||||
#define ty_nenums ty_v.ty_enum.typ_nenums
|
||||
#define ty_literals ty_v.ty_enum.typ_literals
|
||||
/* bit sets: */
|
||||
struct {
|
||||
struct type *typ_setbase; /* base type of set elements */
|
||||
long typ_setlow; /* low bound */
|
||||
} ty_set;
|
||||
#define ty_setbase ty_v.ty_set.typ_setbase
|
||||
#define ty_setlow ty_v.ty_set.typ_setlow
|
||||
} ty_v;
|
||||
} t_type, *p_type;
|
||||
|
||||
/* ALLOCDEF "type" 50 */
|
||||
|
||||
extern p_type
|
||||
subrange_type(),
|
||||
array_type(),
|
||||
*tp_lookup();
|
||||
extern long
|
||||
param_size(),
|
||||
compute_size();
|
||||
|
||||
extern p_type char_type, uchar_type,
|
||||
long_type, double_type, string_type;
|
||||
extern p_type void_type, incomplete_type;
|
||||
|
125
util/grind/value.c
Normal file
125
util/grind/value.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/* $Header$ */
|
||||
|
||||
#include <alloc.h>
|
||||
|
||||
#include "position.h"
|
||||
#include "scope.h"
|
||||
#include "symbol.h"
|
||||
#include "type.h"
|
||||
#include "message.h"
|
||||
|
||||
int stack_offset; /* for up and down commands */
|
||||
|
||||
extern long pointer_size;
|
||||
extern t_addr *get_EM_regs();
|
||||
|
||||
/* Get the value of the symbol indicated by sym.
|
||||
Return 0 on failure,
|
||||
1 on success.
|
||||
On success, 'buf' contains the value, and 'AB' may contain the parameters
|
||||
of the procedure invocation containing sym.
|
||||
For both of these, storage is allocated by Malloc; this storage must
|
||||
be freed by caller (I don't like this any more than you do, but caller
|
||||
does not know sizes).
|
||||
*/
|
||||
int
|
||||
get_value(sym, buf, AB)
|
||||
register p_symbol sym;
|
||||
char **buf, **AB;
|
||||
{
|
||||
p_type tp = sym->sy_type;
|
||||
long size = tp->ty_size;
|
||||
int retval = 0;
|
||||
t_addr *EM_regs;
|
||||
int i;
|
||||
p_scope sc, symsc;
|
||||
|
||||
*buf = 0;
|
||||
*AB = 0;
|
||||
switch(sym->sy_class) {
|
||||
case VAR:
|
||||
/* exists if child exists; nm_value contains addres */
|
||||
*buf = Malloc((unsigned) size);
|
||||
if (get_bytes(size, (t_addr) sym->sy_name.nm_value, *buf)) {
|
||||
retval = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case VARPAR:
|
||||
case LOCVAR:
|
||||
/* first find the stack frame in which it resides */
|
||||
symsc = base_scope(sym->sy_scope);
|
||||
|
||||
/* now symsc contains the scope where the storage for sym is
|
||||
allocated. Now find it on the stack of child.
|
||||
*/
|
||||
i = stack_offset;
|
||||
for (;;) {
|
||||
sc = 0;
|
||||
if (! (EM_regs = get_EM_regs(i++))) {
|
||||
/* no child? */
|
||||
break;
|
||||
}
|
||||
if (! EM_regs[AB_OFF]) {
|
||||
/* no more frames */
|
||||
break;
|
||||
}
|
||||
sc = base_scope(get_scope_from_addr(EM_regs[PC_OFF]));
|
||||
if (! sc || sc->sc_start > EM_regs[PC_OFF]) {
|
||||
sc = 0;
|
||||
break;
|
||||
}
|
||||
if (sc == symsc) break; /* found it */
|
||||
}
|
||||
|
||||
if (! sc) break; /* not found */
|
||||
|
||||
if (sym->sy_class == LOCVAR) {
|
||||
/* Either local variable or value parameter */
|
||||
*buf = Malloc((unsigned) size);
|
||||
if (get_bytes(size,
|
||||
EM_regs[sym->sy_name.nm_value < 0
|
||||
? LB_OFF
|
||||
: AB_OFF
|
||||
] +
|
||||
(t_addr) sym->sy_name.nm_value,
|
||||
*buf)) {
|
||||
retval = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we get here, we have a var parameter. Get the parameters
|
||||
of the current procedure invocation.
|
||||
*/
|
||||
{
|
||||
p_type proctype = sc->sc_definedby->sy_type;
|
||||
|
||||
size = proctype->ty_nbparams;
|
||||
if (has_static_link(sc)) size += pointer_size;
|
||||
*AB = Malloc((unsigned) size);
|
||||
if (! get_bytes(size, EM_regs[AB_OFF], *AB)) {
|
||||
break;
|
||||
}
|
||||
if ((size = tp->ty_size) == 0) {
|
||||
size = compute_size(tp, *AB);
|
||||
}
|
||||
}
|
||||
*buf = Malloc((unsigned) size);
|
||||
if (get_bytes(size,
|
||||
(t_addr) BUFTOA(*AB+sym->sy_name.nm_value),
|
||||
*buf)) {
|
||||
retval = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (retval == 0) {
|
||||
if (*buf) free(*buf);
|
||||
if (*AB) free(*AB);
|
||||
*buf = 0;
|
||||
*AB = 0;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
Loading…
Reference in a new issue