more fixes

This commit is contained in:
ceriel 1990-10-17 17:00:03 +00:00
parent c33f7cbe76
commit 7e58923415
20 changed files with 490 additions and 311 deletions

View file

@ -45,7 +45,7 @@ static struct langdep c = {
"0x%lX",
"%lu",
"0x%lX",
"%g",
"%.14g",
"{",
"}",

View file

@ -49,16 +49,15 @@ commands
| %default ';' { give_prompt = 0; }
]
{ if (com) {
if (errorgiven) {
freenode(com);
com = 0;
}
if (lastcom) {
freenode(lastcom);
lastcom = 0;
}
if (com) {
if (errorgiven) {
freenode(com);
com = 0;
}
else {
eval(com);
if (repeatable(com)) {
lastcom = com;
@ -67,6 +66,7 @@ commands
com != run_command &&
com != print_command) {
freenode(com);
com = 0;
}
}
} else if (lastcom && ! errorgiven) {
@ -98,7 +98,7 @@ command_line(p_tree *p;)
| where_command(p)
| STATUS { *p = mknode(OP_STATUS); }
| DUMP { *p = mknode(OP_DUMP); }
| RESTORE INTEGER { *p = mknode(OP_RESTORE, tok.ival); }
| RESTORE count(p)? { *p = mknode(OP_RESTORE, *p); }
| delete_command(p)
| print_command(p)
| display_command(p)
@ -112,14 +112,14 @@ command_line(p_tree *p;)
]
;
where_command(p_tree *p;)
{ long l; }
:
WHERE
[ INTEGER { l = tok.ival; }
| '-' INTEGER { l = - tok.ival; }
| { l = 0x7fffffff; }
] { *p = mknode(OP_WHERE, l); }
WHERE { *p = mknode(OP_WHERE, (p_tree) 0); }
[ count(&(*p)->t_args[0])?
| '-' count(&(*p)->t_args[0])
{ (*p)->t_args[0]->t_ival = - (*p)->t_args[0]->t_ival; }
]
;
list_command(p_tree *p;)
@ -153,9 +153,9 @@ file_command(p_tree *p;)
help_command(p_tree *p;)
:
[ HELP | '?' ]
[ { *p = mknode(OP_HELP, (struct idf *) 0, (char *) 0); }
| name(p) { (*p)->t_oper = OP_HELP; }
| '?' { *p = mknode(OP_HELP, str2idf("help",0), (char *) 0); }
{ *p = mknode(OP_HELP, (p_tree) 0); }
[ name(&(*p)->t_args[0])?
| '?' { (*p)->t_args[0] = mknode(OP_NAME, str2idf("help",0), (char *) 0); }
]
;
@ -210,7 +210,9 @@ when_command(p_tree *p;)
:
WHEN
where(&whr)?
condition(&cond)?
condition(&cond)? { *p = mknode(OP_WHEN, whr, cond, (p_tree) 0);
p = &(*p)->t_args[2];
}
'{'
command_line(p)
[ ';' { if (*p) {
@ -223,46 +225,34 @@ when_command(p_tree *p;)
'}'
{ if (! whr && ! cond) {
error("no position or condition");
freenode(*p);
*p = 0;
}
else if (! *p) {
error("no commands given");
}
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); }
STEP { *p = mknode(OP_STEP, (p_tree) 0); }
count(&(*p)->t_args[0])?
;
next_command(p_tree *p;)
{ long l; }
:
NEXT
[ INTEGER { l = tok.ival; }
| { l = 1; }
] { *p = mknode(OP_NEXT, l); }
NEXT { *p = mknode(OP_NEXT, (p_tree) 0); }
count(&(*p)->t_args[0])?
;
regs_command(p_tree *p;)
{ long l; }
:
REGS
[ INTEGER { l = tok.ival; }
| { l = 0; }
] { *p = mknode(OP_REGS, l); }
REGS { *p = mknode(OP_REGS, (p_tree) 0); }
count(&(*p)->t_args[0])?
;
delete_command(p_tree *p;)
:
DELETE count_list(p) { *p = mknode(OP_DELETE, *p); }
DELETE count_list(p)? { *p = mknode(OP_DELETE, *p); }
;
print_command(p_tree *p;)
@ -323,13 +313,13 @@ able_command(p_tree *p;)
[ ENABLE { *p = mknode(OP_ENABLE, (p_tree) 0); }
| DISABLE { *p = mknode(OP_DISABLE, (p_tree) 0); }
]
count_list(&(*p)->t_args[0])
count_list(&(*p)->t_args[0])?
;
count_list(p_tree *p;)
:
count(p)
[ ',' { *p = mknode(OP_LIST, *p, (p_tree) 0); }
[ ',' { *p = mknode(OP_LINK, *p, (p_tree) 0); }
count(&(*p)->t_args[1])
]*
;
@ -341,7 +331,8 @@ condition(p_tree *p;)
where(p_tree *p;)
:
IN qualified_name(p) { *p = mknode(OP_IN, *p); }
IN qualified_name(p) { *p = mknode(OP_IN, *p, (p_tree) 0); }
position(&((*p)->t_args[1]))?
|
position(p)
;

View file

@ -65,8 +65,12 @@ debugger_string
}
| /* tag name (only C?) */
{ s = NewSymbol(str, CurrentScope, TAG, currnam); }
'T' tag_name(s)
'T' type_name(&(s->sy_type), s)
{ if (! s->sy_type->ty_sym) s->sy_type->ty_sym = s;
if (s->sy_type->ty_class != T_CROSS) {
resolve_cross(s->sy_type);
}
}
| /* end scope */
'E' INTEGER
{ close_scope(); }
@ -105,6 +109,7 @@ debugger_string
{ s = Lookup(findidf(str), FileScope, VAR);
if (s) {
tmp = s->sy_type;
s->sy_type = 0;
} else s = NewSymbol(str, FileScope, VAR, currnam);
}
'G' type(&(s->sy_type), (int *) 0, s)
@ -224,25 +229,21 @@ string_const
type_name(p_type *t; p_symbol sy;)
{ int type_index[2]; p_type *p; }
:
type_index(type_index)
type_index(type_index) { p = tp_lookup(type_index); }
[
'='
type(t, type_index, sy)
{ p = tp_lookup(type_index);
if (*p && *p != incomplete_type) {
if ((*p)->ty_class != T_CROSS)
error("Redefining (%d,%d) %d",
type_index[0],
type_index[1],
(*p)->ty_class);
if (*t && *p != *t) free_type(*p);
{ if (*p && (*p)->ty_class != 0 &&
(*p)->ty_class != T_CROSS) {
error("Redefining (%d,%d) %d",
type_index[0],
type_index[1],
(*p)->ty_class);
}
if (*t) *p = *t;
}
'='
type(p, type_index, sy)
|
{ p = tp_lookup(type_index); }
]
{ if (*p == 0) *p = incomplete_type;
{ if (*p == 0) *p = new_type();
*t = *p;
}
;
@ -261,33 +262,6 @@ type_index(int *type_index;)
}
;
tag_name(p_symbol t;)
{ int type_index[2]; p_type *p; }
:
type_index(type_index)
'='
type(&(t->sy_type), type_index, t)
{ p = tp_lookup(type_index);
if (*p && *p != incomplete_type) {
if ((*p)->ty_class != 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;
if (t->sy_type &&
t->sy_type->ty_class == T_ENUM &&
currnam->on_desc != 0) {
t->sy_type->ty_size = currnam->on_desc;
}
}
;
function(p_symbol p;)
:
{ p->sy_type = new_type();
@ -335,14 +309,14 @@ routine(p_symbol p;)
;
type(p_type *ptp; int *type_index; p_symbol sy;)
{ register p_type tp = 0;
p_type t1, t2;
{ register p_type tp = *ptp ? *ptp : new_type();
p_type t1 = 0, t2 = 0;
long ic1, ic2;
int A_used = 0;
int tclass;
char *str;
}
: { *ptp = 0; }
:
[
/* type cross reference */
/* these are used in C for references to a struct, union or
@ -362,13 +336,14 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
if (sy &&
(sy->sy_type->ty_class == tclass ||
sy->sy_type->ty_class == T_CROSS)) {
if (tp != *ptp) free_type(tp);
tp = sy->sy_type;
}
else {
tp = new_type();
tp->ty_class = T_CROSS;
tp->ty_tag = str;
tp->ty_size = tclass;
sy = NewSymbol(str, CurrentScope, TAG, (struct outname *) 0);
sy->sy_type = tp;
}
}
|
@ -388,7 +363,8 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
[ 'A' integer_const(&ic2) { A_used |= 2; }
| integer_const(&ic2)
]
{ *ptp = subrange_type(A_used,
{ if (tp != *ptp) free_type(tp);
tp = subrange_type(A_used,
last_index,
ic1,
ic2,
@ -399,28 +375,30 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
* is element type
*/
'a' type(&t1, (int *) 0, (p_symbol) 0) ';' type(&t2, (int *) 0, (p_symbol) 0)
{ *ptp = array_type(t1, t2); }
{ if (tp != *ptp) free_type(tp);
tp = array_type(t1, t2);
}
|
/* structure type */
's' { tp = new_type(); tp->ty_class = T_STRUCT; }
's' { tp->ty_class = T_STRUCT; }
structure_type(tp, sy)
|
/* union type */
'u' { tp = new_type(); tp->ty_class = T_UNION; }
'u' { tp->ty_class = T_UNION; }
structure_type(tp, sy)
|
/* enumeration type */
'e' { tp = new_type(); tp->ty_class = T_ENUM; }
'e' { tp->ty_class = T_ENUM; }
enum_type(tp)
|
/* pointer type */
'*' { tp = new_type(); tp->ty_class =T_POINTER;
'*' { tp->ty_class = T_POINTER;
tp->ty_size = pointer_size;
}
type(&(tp->ty_ptrto), (int *) 0, (p_symbol) 0)
|
/* function type */
'f' { tp = new_type(); tp->ty_class = T_PROCEDURE;
'f' { tp->ty_class = T_PROCEDURE;
tp->ty_size = pointer_size;
}
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
@ -432,14 +410,14 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
*/
|
/* procedure type */
'Q' { tp = new_type(); tp->ty_class = T_PROCEDURE;
'Q' { tp->ty_class = T_PROCEDURE;
tp->ty_size = pointer_size;
}
type(&(tp->ty_retval), (int *) 0, (p_symbol) 0)
',' param_list(tp)
|
/* another procedure type */
'p' { tp = new_type(); tp->ty_class = T_PROCEDURE;
'p' { tp->ty_class = T_PROCEDURE;
tp->ty_size = pointer_size;
tp->ty_retval = void_type;
}
@ -449,7 +427,7 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
/* 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; }
'S' { tp->ty_class = T_SET; }
type(&(tp->ty_setbase), (int *) 0, (p_symbol) 0) ';'
[
integer_const(&(tp->ty_size)) ';'
@ -459,19 +437,23 @@ type(p_type *ptp; int *type_index; p_symbol sy;)
]
|
/* file type of Pascal */
'L' { tp = new_type(); tp->ty_class = T_FILE; }
'L' { tp->ty_class = T_FILE; }
type(&(tp->ty_fileof), (int *) 0, (p_symbol) 0)
|
type_name(ptp, (p_symbol) 0)
{ if (type_index &&
*ptp == incomplete_type &&
(*ptp)->ty_class == 0 &&
type_index[0] == last_index[0] &&
type_index[1] == last_index[1]) {
*ptp = void_type;
**ptp = *void_type;
if (*ptp != tp) free_type(tp);
}
tp = *ptp;
}
]
{ if (! *ptp) *ptp = tp; }
{ if (*ptp && *ptp != tp) **ptp = *tp;
else *ptp = tp;
}
;
structure_type(register p_type tp; p_symbol sy;)
@ -676,6 +658,7 @@ get_field_space(tp, s)
}
p = &tp->ty_fields[tp->ty_nfields++];
p->fld_name = s;
p->fld_type = 0;
sy = NewSymbol(s, CurrentScope, FIELD, currnam);
sy->sy_field = p;
return p;

View file

@ -188,6 +188,7 @@ DbxRead(f)
}
close_scope();
add_position_addr((char *) 0, (struct outname *) 0);
clean_tp_tab();
rd_close();
return (h.oh_magic == O_CONVERTED);
}

View file

@ -16,8 +16,11 @@ extern p_tree get_from_item_list();
struct dump {
char *globals, *stack;
struct message_hdr mglobal, mstack;
struct dump *next;
};
static struct dump *last_dump;
/* dumping and restoring of child process.
*/
do_dump(p)
@ -36,6 +39,8 @@ do_dump(p)
p->t_args[0] = (struct tree *) d;
p->t_address = (t_addr) get_int(d->mglobal.m_buf+PC_OFF*pointer_size, pointer_size, T_UNSIGNED);
add_to_item_list(p);
d->next = last_dump;
last_dump = d;
}
/* dumping and restoring of child process.
@ -45,16 +50,22 @@ do_restore(p)
{
struct dump *d;
p = get_from_item_list((int) p->t_ival);
if (!p || p->t_oper != OP_DUMP) {
error("no such dump");
if (p->t_args[0]) {
p = get_from_item_list((int) p->t_args[0]->t_ival);
if (!p || p->t_oper != OP_DUMP) {
error("no such dump");
return;
}
d = (struct dump *) p->t_args[0];
}
else d = last_dump;
if (! d) {
error("no dumps");
return;
}
d = (struct dump *) p->t_args[0];
if (! put_dump(&d->mglobal, d->globals, &d->mstack, d->stack)) {
error("no debuggee");
}
do_items();
}
@ -66,5 +77,12 @@ free_dump(p)
free(d->globals);
free(d->stack);
if (d == last_dump) last_dump = d->next;
else {
register struct dump *d1 = last_dump;
while (d1->next != d) d1 = d1->next;
d1->next = d->next;
}
free((char *) d);
}

View file

@ -65,8 +65,9 @@ long
get_int(buf, size, class)
char *buf;
long size;
int class;
{
long l;
register long l;
switch((int)size) {
case sizeof(char):
@ -140,8 +141,8 @@ int
convert(pbuf, psize, ptp, tp, size)
char **pbuf;
long *psize;
p_type *ptp;
p_type tp;
register p_type *ptp;
register p_type tp;
long size;
{
/* Convert the value in pbuf, of size psize and type ptp, to type
@ -318,7 +319,6 @@ do_deref(p, pbuf, psize, ptp)
*pbuf = malloc((unsigned) *psize);
malloc_succeeded(*pbuf);
if (! get_bytes(*psize, addr, *pbuf)) {
error("could not get value");
free(*pbuf);
*pbuf = 0;
return 0;
@ -918,7 +918,6 @@ array_addr(p, paddr, psize, ptp)
}
if ((*ptp)->ty_class == T_POINTER) {
if (! get_bytes(pointer_size, *paddr, (char *) paddr)) {
error("could not get value");
free(buf);
return 0;
}
@ -1021,7 +1020,6 @@ do_select(p, pbuf, psize, ptp)
*pbuf = malloc((unsigned int) *psize);
malloc_succeeded(*pbuf);
if (! get_bytes(*psize, a, *pbuf)) {
error("could not get value");
free(*pbuf);
*pbuf = 0;
return 0;
@ -1105,8 +1103,6 @@ eval_expr(p, pbuf, psize, ptp)
sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR|CONST);
if (! sym) return 0;
if (! get_value(sym, pbuf, psize)) {
print_node(p, 0);
fputs(" currently not available\n", db_out);
break;
}
*ptp = sym->sy_type;
@ -1180,8 +1176,6 @@ eval_desig(p, paddr, psize, ptp)
sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR);
if (! sym) return 0;
if (! (a = get_addr(sym, psize))) {
print_node(p, 0);
fputs(" currently not available\n", db_out);
break;
}
*paddr = a;

View file

@ -11,6 +11,7 @@
extern FILE *db_out;
extern int db_ss;
int stop_reason;
typedef struct item {
struct item *i_next;
@ -51,8 +52,10 @@ pr_item(i)
}
int
item_addr_actions(a, mess_type)
item_addr_actions(a, mess_type, may_stop)
t_addr a;
int mess_type;
int may_stop;
{
/* Perform actions associated with position 'a', and return 1 if we must stop
there, and 0 if not.
@ -60,20 +63,46 @@ item_addr_actions(a, mess_type)
register p_item i = item_list.il_first;
int stopping = 0;
while (i) {
stop_reason = 0;
for (i = item_list.il_first; i != 0; i = i->i_next) {
register p_tree p = i->i_node;
if (! i->i_disabled && (p->t_address == a || p->t_address == NO_ADDR)) {
if (! i->i_disabled
&& (p->t_address == a || p->t_address == NO_ADDR)) {
switch(p->t_oper) {
case OP_TRACE:
case OP_WHEN:
perform(p, a);
break;
case OP_STOP:
if (mess_type != DB_SS && mess_type != OK) break;
if (! p->t_args[1] ||
eval_cond(p->t_args[1])) stopping = 1;
if (! p->t_args[1] || eval_cond(p->t_args[1])) {
if (! stop_reason) stop_reason = i->i_itemno;
stopping = 1;
}
break;
case OP_TRACE:
case OP_WHEN:
case OP_DUMP:
case OP_DISPLAY:
break;
default:
assert(0);
}
}
}
for (i = item_list.il_first; i != 0; i = i->i_next) {
register p_tree p = i->i_node;
if (! i->i_disabled
&& (p->t_address == a || p->t_address == NO_ADDR)) {
switch(p->t_oper) {
case OP_TRACE:
if ((! stopping && mess_type != END_SS)
|| p->t_args[2] || ! may_stop) {
perform(p, a);
}
break;
case OP_WHEN:
perform(p, a);
break;
case OP_STOP:
case OP_DUMP:
case OP_DISPLAY:
break;
@ -81,7 +110,6 @@ item_addr_actions(a, mess_type)
assert(0);
}
}
i = i->i_next;
}
return stopping;
}
@ -107,8 +135,8 @@ add_to_item_list(p)
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 (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;
}
@ -140,8 +168,8 @@ remove_from_item_list(n)
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--;
if (p->t_address == NO_ADDR
&& (p->t_oper != OP_TRACE || ! p->t_args[0])) db_ss--;
free_item(i);
}
return p;
@ -179,8 +207,8 @@ able_item(n, kind)
warning("item %d already %sabled", n, kind ? "dis" : "en");
return;
}
if (p->t_address == NO_ADDR &&
(p->t_oper != OP_TRACE || ! p->t_args[0])) {
if (p->t_address == NO_ADDR
&& (p->t_oper != OP_TRACE || ! p->t_args[0])) {
db_ss += kind == 1 ? (-1) : 1;
}
i->i_disabled = kind;

View file

@ -19,6 +19,7 @@ int debug;
extern struct tokenname tkidf[];
extern char *strindex();
extern int eof_seen;
extern int interrupted;
static struct tokenname shorts[] = {
{LIST, "l"},
@ -113,14 +114,16 @@ error(va_alist)
va_list ap;
char *fmt;
va_start(ap);
{
fmt = va_arg(ap, char *);
fprintf(db_out, "%s: ", progname);
vfprintf(db_out, fmt, ap);
fprintf(db_out, "\n");
if (! interrupted) {
va_start(ap);
{
fmt = va_arg(ap, char *);
fprintf(db_out, "%s: ", progname);
vfprintf(db_out, fmt, ap);
fprintf(db_out, "\n");
}
va_end(ap);
}
va_end(ap);
errorgiven = 1;
}

View file

@ -44,7 +44,7 @@ static struct langdep m2 = {
"%lXH",
"%lu",
"%lXH",
"%G",
"%.14G",
"[",
"]",

View file

@ -9,22 +9,22 @@ OP_REAL 0 0
OP_STRING 0 0
OP_NAME 0 0
OP_AT 0 0
OP_IN 1 0
OP_HELP 0 do_help
OP_IN 2 0
OP_HELP 1 do_help
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_STEP 1 do_step
OP_NEXT 1 do_next
OP_REGS 1 do_regs
OP_WHERE 1 do_where
OP_STATUS 0 print_items
OP_DELETE 1 do_delete
OP_SELECT 2 0
OP_SET 2 do_set
OP_PRINT 1 do_print
OP_DUMP 0 do_dump
OP_RESTORE 0 do_restore
OP_RESTORE 1 do_restore
OP_TRACE 3 do_trace
OP_FIND 1 do_find
OP_DISPLAY 1 add_to_item_list

View file

@ -187,6 +187,13 @@ print_val(tp, tp_sz, addr, compressed, indent, format)
if (indent == 0) indent = 4;
switch(tp->ty_class) {
case T_CROSS:
if (! tp->ty_cross) {
error("unknown type");
break;
}
print_val(tp->ty_cross, tp_sz, addr, compressed, indent, format);
break;
case T_SUBRANGE:
print_val(tp->ty_base, tp_sz, addr, compressed, indent, format);
break;

View file

@ -30,6 +30,8 @@ extern long pointer_size;
extern char *progname;
extern int child_interrupted;
extern int interrupted;
extern int stop_reason;
extern t_lineno currline;
static int child_pid; /* process id of child */
static int to_child, from_child; /* file descriptors for communication */
@ -39,7 +41,6 @@ static int fild1[2], fild2[2]; /* pipe file descriptors */
int disable_intr = 1;
int db_ss;
t_lineno currline;
static int catch_sigpipe();
static int stopped();
@ -64,6 +65,7 @@ init_run()
from_child = fild2[0];
child_pid = 0;
if (currfile) CurrentScope = currfile->sy_file->f_scope;
currline = 0;
return 1;
}
@ -191,7 +193,7 @@ start_child(p)
CurrentScope = get_scope_from_addr(curr_stop);
}
do_items();
if (! restoring && ! item_addr_actions(curr_stop, OK)) {
if (! restoring && ! item_addr_actions(curr_stop, OK, 1)) {
send_cont(1);
}
else if (! restoring) {
@ -225,13 +227,19 @@ ureceive(p, c)
int i;
char buf[0x1000];
if (! child_pid) return 0;
if (! child_pid) {
error("no process");
return 0;
}
if (! p) p = buf;
while (c >= 0x1000) {
i = read(from_child, p, 0x1000);
if (i <= 0) {
if (i == 0) child_pid = 0;
if (i == 0) {
child_pid = 0;
}
else error("read failed");
return 0;
}
if (p != buf) p += i;
@ -240,13 +248,16 @@ ureceive(p, c)
while (c > 0) {
i = read(from_child, p, (int)c);
if (i <= 0) {
if (i == 0) child_pid = 0;
if (i == 0) {
child_pid = 0;
}
else error("read failed");
return 0;
}
p += i;
c -= i;
}
return c == 0;
return 1;
}
static int
@ -256,16 +267,25 @@ usend(p, c)
{
int i;
if (! child_pid) return 0;
if (! child_pid) {
error("no process");
return 0;
}
while (c >= 0x1000) {
i = write(to_child, p, 0x1000);
if (i < 0) return 0;
if (i < 0) {
if (child_pid) error("write failed");
return 0;
}
p += i;
c -= i;
}
while (c > 0) {
i = write(to_child, p, (int)c);
if (i < 0) return 0;
if (i < 0) {
if (child_pid) error("write failed");
return 0;
}
p += i;
c -= i;
}
@ -307,11 +327,15 @@ stopped(s, a)
if (s && a) {
fprintf(db_out, "%s ", s);
pos = print_position(a, 1);
if (stop_reason) {
fprintf(db_out, " (status entry %d)", stop_reason);
}
fputs("\n", db_out);
list_position(pos);
handle_displays();
}
curr_stop = a;
CurrentScope = get_scope_from_addr(a);
return 1;
}
@ -322,82 +346,84 @@ could_send(m, stop_message)
int type;
t_addr a;
static int level = 0;
int child_dead = 0;
level++;
for (;;) {
if (child_pid) {
int child_dead = 0;
if (m->m_type & DB_RUN) disable_intr = 0;
if (!child_interrupted && (! uputm(m) || ! ugetm(&answer))) {
child_dead = 1;
}
disable_intr = 1;
if ((interrupted || child_interrupted) && ! child_dead) {
while (child_interrupted && answer.m_type != INTR) {
if (! ugetm(&answer)) {
child_dead = 1;
break;
}
}
if (interrupted && ! child_dead) {
level--;
if (! level) {
child_interrupted = 0;
CurrentScope = get_scope_from_addr((t_addr) answer.m_size);
interrupted = 0;
stopped("interrupted", (t_addr) answer.m_size);
}
return 1;
if (! child_pid) {
error("no process");
return 0;
}
if (m->m_type & DB_RUN) {
disable_intr = 0;
stop_reason = 0;
}
if (!child_interrupted && (! uputm(m) || ! ugetm(&answer))) {
child_dead = 1;
}
disable_intr = 1;
if ((interrupted || child_interrupted) && ! child_dead) {
while (child_interrupted && answer.m_type != INTR) {
if (! ugetm(&answer)) {
child_dead = 1;
break;
}
}
if (child_dead) {
wait(&child_status);
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);
}
init_run();
if (interrupted && ! child_dead) {
level--;
if (! level) {
child_interrupted = 0;
interrupted = 0;
stopped("interrupted", (t_addr) answer.m_size);
}
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) &&
( 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 (child_dead) {
wait(&child_status);
if (child_status & 0177) {
fprintf(db_out,
"child died with signal %d\n",
child_status & 0177);
}
if (stop_message) {
stopped("stopped", a);
else {
fprintf(db_out,
"child terminated, exit status %d\n",
child_status >> 8);
}
init_run();
level--;
return type;
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, stop_message) &&
( 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;
if (! uputm(m) || ! ugetm(&answer)) return 0;
}
single_stepping = 0;
}
if (stop_message) {
stopped("stopped", a);
}
level--;
return 0;
return 1;
}
/*NOTREACHED*/
}
@ -415,17 +441,22 @@ getbytes(size, from, to, kind)
put_int(m.m_buf, pointer_size, (long)from);
if (! could_send(&m, 0)) {
error("no process");
return 0;
}
if (answer.m_type == FAIL || answer.m_type == INTR) {
switch(answer.m_type) {
case FAIL:
error("could not get value");
return 0;
case INTR:
error("interrupted");
return 0;
case DATA:
return ureceive(to, answer.m_size);
default:
assert(0);
}
assert(answer.m_type == DATA);
return ureceive(to, answer.m_size);
/*NOTREACHED*/
}
int
@ -449,7 +480,6 @@ get_string(size, from, to)
return retval;
}
int
set_bytes(size, from, to)
long size;
char *from;
@ -461,9 +491,21 @@ set_bytes(size, from, to)
m.m_size = size;
put_int(m.m_buf, pointer_size, (long) to);
return uputm(&m) && usend(from, size)
&& ugetm(&m)
&& m.m_type != FAIL;
if (! uputm(&m) || ! usend(from, size) || ! ugetm(&m)) {
return;
}
switch(answer.m_type) {
case FAIL:
error("could not handle this SET request");
break;
case INTR:
error("interrupted");
break;
case OK:
break;
default:
assert(0);
}
}
int
@ -475,16 +517,25 @@ get_dump(globmessage, globbuf, stackmessage, stackbuf)
m.m_type = DUMP;
if (! could_send(&m, 0)) {
error("no process");
return 0;
}
if (answer.m_type == FAIL || answer.m_type == INTR) return 0;
assert(answer.m_type == DGLOB);
switch(answer.m_type) {
case FAIL:
error("request for DUMP failed");
return 0;
case INTR:
error("interrupted");
return 0;
case DGLOB:
break;
default:
assert(0);
}
*globmessage = answer;
*globbuf = malloc((unsigned) answer.m_size);
if (! ureceive(*globbuf, answer.m_size) || ! ugetm(stackmessage)) {
if (*globbuf) free(*globbuf);
error("no process");
return 0;
}
assert(stackmessage->m_type == DSTACK);
@ -492,7 +543,6 @@ get_dump(globmessage, globbuf, stackmessage, stackbuf)
if (! ureceive(*stackbuf, stackmessage->m_size)) {
if (*globbuf) free(*globbuf);
if (*stackbuf) free(*stackbuf);
error("no process");
return 0;
}
put_int(globmessage->m_buf+SP_OFF*pointer_size, pointer_size,
@ -537,10 +587,20 @@ get_EM_regs(level)
m.m_size = level;
if (! could_send(&m, 0)) {
error("no process");
return 0;
}
if (answer.m_type == FAIL || answer.m_type == INTR) return 0;
switch(answer.m_type) {
case FAIL:
error("request for registers failed");
return 0;
case INTR:
error("interrupted");
return 0;
case GETEMREGS:
break;
default:
assert(0);
}
*to++ = (t_addr) get_int(answer.m_buf, pointer_size, T_UNSIGNED);
*to++ = (t_addr) get_int(answer.m_buf+pointer_size, pointer_size, T_UNSIGNED);
*to++ = (t_addr) get_int(answer.m_buf+2*pointer_size, pointer_size, T_UNSIGNED);
@ -558,7 +618,20 @@ set_pc(PC)
m.m_type = SETEMREGS;
m.m_size = 0;
put_int(m.m_buf+PC_OFF*pointer_size, pointer_size, (long)PC);
return could_send(&m, 0) && answer.m_type != FAIL && answer.m_type != INTR;
if (! could_send(&m, 0)) return 0;
switch(answer.m_type) {
case FAIL:
error("could not set PC to %lx", (long) PC);
return 0;
case INTR:
error("interrupted");
return 0;
case OK:
return 1;
default:
assert(0);
}
/*NOTREACHED*/
}
int
@ -569,7 +642,7 @@ send_cont(stop_message)
m.m_type = (CONT | (db_ss ? DB_SS : 0));
m.m_size = 0;
return could_send(&m, stop_message) && answer.m_type != FAIL;
return could_send(&m, stop_message) && child_pid;
}
int
@ -582,9 +655,7 @@ do_single_step(type, count)
m.m_type = type | (db_ss ? DB_SS : 0);
m.m_size = count;
single_stepping = 1;
if (could_send(&m, 1) && answer.m_type != FAIL && answer.m_type != INTR) {
return 1;
}
if (could_send(&m, 1) && child_pid) return 1;
single_stepping = 0;
return 0;
}
@ -596,12 +667,10 @@ set_or_clear_breakpoint(a, 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)) {
if (child_pid && ! could_send(&m, 0)) {
}
return 1;
@ -618,7 +687,8 @@ set_or_clear_trace(start, end, type)
put_int(m.m_buf, pointer_size, (long)start);
put_int(m.m_buf+pointer_size, pointer_size, (long)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)) {
if (child_pid && ! could_send(&m, 0)) {
return 0;
}
return 1;

View file

@ -129,3 +129,19 @@ base_scope(sc)
}
return sc;
}
/* extern int scope_encloses(p_scope scope, from_scope);
Returns 1 if scope encloses from from_scope, 0 otherwise.
*/
int
scope_encloses(scope, from_scope)
p_scope scope, from_scope;
{
register p_scope sc = from_scope;
while (sc) {
if (sc == scope) return 1;
sc = sc->sc_static_encl;
}
return 0;
}

View file

@ -52,3 +52,8 @@ extern p_scope get_next_scope_from_addr();
Returns the closest enclosing scope of 'sc' that has an activation record.
*/
extern p_scope base_scope();
/* extern int scope_encloses(p_scope scope, from_scope);
Returns 1 if scope encloses from from_scope, 0 otherwise.
*/
extern int scope_encloses();

View file

@ -221,14 +221,13 @@ identify(p, class_set)
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);
sym = Lookfromscope(p->t_idf, class_set, CurrentScope);
if (sym) {
/* Found it. */
break;
}
/* We could not find it using scope p->t_sc; now we try to identify
/* We could not find it using the current scope; now we try to identify
it using class_set. If this results in only one definition, we
take this one.
*/
@ -382,3 +381,20 @@ do_which(p)
if ( sym) pr_sym(sym);
}
resolve_cross(tp)
p_type tp;
{
register p_symbol sym = tp->ty_sym->sy_idf->id_def;
while (sym) {
if (sym->sy_class == TAG &&
sym->sy_type->ty_class == T_CROSS &&
sym->sy_type->ty_cross == (p_type) 0 &&
sym->sy_type->ty_size == tp->ty_class &&
scope_encloses(tp->ty_sym->sy_scope, sym->sy_scope)) {
sym->sy_type->ty_cross = tp;
}
sym = sym->sy_next;
}
}

View file

@ -19,11 +19,12 @@
#include "expr.h"
extern FILE *db_out;
extern t_lineno currline;
t_lineno currline;
static t_lineno listline;
extern long pointer_size;
extern char *strrindex();
extern int interrupted;
extern int stop_reason;
p_tree print_command;
@ -59,11 +60,6 @@ mknode(va_alist)
p->t_filename = va_arg(ap, char *);
break;
case OP_INTEGER:
case OP_NEXT:
case OP_STEP:
case OP_REGS:
case OP_RESTORE:
case OP_WHERE:
p->t_ival = va_arg(ap, long);
break;
default:
@ -120,6 +116,25 @@ get_addr_from_node(p)
case OP_IN:
a = get_addr_from_node(p->t_args[0]);
if (p->t_args[1]) {
p_scope sc;
a = get_addr_from_node(p->t_args[1]);
sc = base_scope(get_scope_from_addr(a));
sym = identify(p->t_args[0], FUNCTION|PROC|MODULE);
if (! sym->sy_name.nm_scope ||
! sym->sy_name.nm_scope->sc_bp_opp) {
error("could not determine address of \"%s\"", p->t_str);
a = ILL_ADDR;
break;
}
if (sc->sc_definedby != sym) {
error("inconsistent address");
a = ILL_ADDR;
break;
}
}
p->t_address = a;
break;
@ -209,13 +224,16 @@ print_node(p, top_level)
print_node(p->t_args[0], 0);
break;
case OP_REGS:
fprintf(db_out, "regs %ld", p->t_ival);
fputs("regs ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_NEXT:
fprintf(db_out, "next %ld", p->t_ival);
fputs("next ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_STEP:
fprintf(db_out, "step %ld", p->t_ival);
fputs("step ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_STATUS:
fputs("status", db_out);
@ -225,15 +243,16 @@ print_node(p, top_level)
print_position(p->t_address, 1);
break;
case OP_RESTORE:
fprintf(db_out, "restore %ld", p->t_ival);
fputs("restore ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_WHERE:
fputs("where", db_out);
if (p->t_ival != 0x7fffffff) fprintf(db_out, " %ld", p->t_ival);
fputs("where ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_HELP:
fputs("help", db_out);
if (p->t_str != 0) fprintf(db_out, " %s", p->t_str);
fputs("help ", db_out);
print_node(p->t_args[0], 0);
break;
case OP_CONT:
fputs("cont", db_out);
@ -258,7 +277,7 @@ print_node(p, top_level)
}
p = p->t_args[2];
fputs(" { ", db_out);
while (p->t_oper == OP_LINK) {
while (p && p->t_oper == OP_LINK) {
print_node(p->t_args[0], 0);
fputs("; ", db_out);
p = p->t_args[1];
@ -299,6 +318,8 @@ print_node(p, top_level)
case OP_IN:
fputs("in ", db_out);
print_node(p->t_args[0], 0);
fputs(" ", db_out);
print_node(p->t_args[1], 0);
break;
case OP_SELECT:
print_node(p->t_args[0], 0);
@ -326,6 +347,8 @@ print_node(p, top_level)
case OP_BINOP:
(*currlang->printop)(p);
break;
default:
assert(0);
}
if (top_level) fputs("\n", db_out);
}
@ -342,7 +365,8 @@ repeatable(com)
return 1;
case OP_NEXT:
case OP_STEP:
com->t_ival = 1;
freenode(com->t_args[0]);
com->t_args[0] = 0;
return 1;
case OP_LIST:
freenode(com->t_args[0]);
@ -428,7 +452,14 @@ do_list(p)
do_file(p)
p_tree p;
{
FILE *f;
if (p->t_args[0]) {
if ((f = fopen(p->t_args[0]->t_str, "r")) == NULL) {
error("could not open %s", p->t_args[0]->t_str);
return;
}
fclose(f);
newfile(p->t_args[0]->t_idf);
}
else if (listfile) fprintf(db_out, "%s\n", listfile->sy_idf->id_text);
@ -461,7 +492,6 @@ setstop(p, kind)
p->t_address = a;
if (a != NO_ADDR) {
if (! set_or_clear_breakpoint(a, kind)) {
error("could not %s breakpoint", kind == SETBP ? "set" : "clear");
return 0;
}
}
@ -496,11 +526,7 @@ settrace(p, kind)
if (sc) e = sc->sc_start - 1;
else e = 0xffffffff;
}
if (! set_or_clear_trace(a, e, kind)) {
error("could not %s trace", kind == SETTRACE ? "set" : "clear");
return 0;
}
return 1;
return set_or_clear_trace(a, e, kind);
}
do_trace(p)
@ -518,6 +544,15 @@ able(p, kind)
p_tree p;
int kind;
{
if (!p) {
if (stop_reason) {
able_item(stop_reason, kind);
}
else {
error("no current stopping point");
}
return;
}
switch(p->t_oper) {
case OP_LINK:
able(p->t_args[0], kind);
@ -526,6 +561,8 @@ able(p, kind)
case OP_INTEGER:
able_item((int)p->t_ival, kind);
break;
default:
assert(0);
}
}
@ -545,7 +582,6 @@ do_continue(p)
p_tree p;
{
int count;
int first_time = 1;
if (p) {
count = p->t_args[0]->t_ival;
@ -553,38 +589,41 @@ do_continue(p)
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)) {
if (a == ILL_ADDR || base_scope(sc) != base_scope(CurrentScope)) {
error("cannot continue at line %d",
p->t_args[1]->t_lino);
return;
}
if (! set_pc(a)) {
return;
}
}
}
else count = 1;
while (count--) {
if (! send_cont(count==0)) {
if (first_time) error("no process");
break;
}
first_time = 0;
}
if (count > 0) {
fprintf(db_out, "Only %d breakpoints skipped\n",
p->t_args[0]->t_ival - count);
}
}
do_step(p)
p_tree p;
{
if (! do_single_step(SETSS, p->t_ival)) {
if (! interrupted) error("no process");
p = p->t_args[0];
if (! do_single_step(SETSS, p ? p->t_ival : 1L)) {
}
}
do_next(p)
p_tree p;
{
if (! do_single_step(SETSSF, p->t_ival)) {
if (! interrupted) error("no process");
p = p->t_args[0];
if (! do_single_step(SETSSF, p? p->t_ival : 1L)) {
}
}
@ -594,10 +633,11 @@ do_regs(p)
p_tree p;
{
t_addr *buf;
int n = p->t_ival;
int n = 0;
p = p->t_args[0];
if (p) n = p->t_ival;
if (! (buf = get_EM_regs(n))) {
if (! interrupted) error("no process");
return;
}
fprintf(db_out, "EM registers %d levels back:\n", n);
@ -615,12 +655,13 @@ do_where(p)
{
int i = 0;
unsigned int cnt;
unsigned int maxcnt = p->t_ival;
unsigned int maxcnt = 0xffff;
p_scope sc;
t_addr *buf;
t_addr PC;
if (p->t_ival < 0) {
p = p->t_args[0];
if (p && p->t_ival < 0) {
for (;;) {
buf = get_EM_regs(i++);
if (! buf || ! buf[AB_OFF]) break;
@ -634,6 +675,7 @@ do_where(p)
i -= maxcnt;
if (i < 0) i = 0;
}
else if (p) maxcnt = p->t_ival;
for (cnt = maxcnt; cnt != 0; cnt--) {
t_addr AB;
@ -659,7 +701,16 @@ do_delete(p)
{
switch(p->t_oper) {
case OP_DELETE:
do_delete(p->t_args[0]);
if (! p->t_args[0]) {
if (stop_reason) {
remove_from_item_list(stop_reason);
stop_reason = 0;
}
else {
error("no current stopping point");
}
}
else do_delete(p->t_args[0]);
break;
case OP_LINK:
do_delete(p->t_args[0]);
@ -681,6 +732,8 @@ do_delete(p)
}
freenode(p);
break;
default:
assert(0);
}
}
@ -702,7 +755,7 @@ do_print(p)
}
}
else if (p != print_command) {
freenode(print_command);
/* freenode(print_command); No, could be in when-list */
print_command = p;
}
/* fall through */
@ -746,9 +799,7 @@ do_set(p)
free(buf);
return;
}
if (! set_bytes(size, buf, a)) {
error("could not handle this SET request");
}
set_bytes(size, buf, a);
free(buf);
}
@ -760,13 +811,13 @@ perform(p, a)
case OP_WHEN:
if (p->t_args[1] && ! eval_cond(p->t_args[1])) break;
p = p->t_args[2];
while (p->t_oper == OP_LINK) {
while (p && p->t_oper == OP_LINK) {
if (interrupted) return;
eval(p->t_args[0]);
if (p->t_args[0]) eval(p->t_args[0]);
p = p->t_args[1];
}
if (interrupted) return;
eval(p);
if (p) eval(p);
break;
case OP_TRACE:
if (p->t_args[0] && p->t_args[0]->t_oper == OP_IN) {

View file

@ -13,7 +13,6 @@ typedef struct tree {
struct {
struct idf *tt_idf;
char *tt_str;
struct scope *tt_scope;
} tt_x;
struct tree *tt_args[MAXARGS];
t_position tt_pos;
@ -23,7 +22,6 @@ typedef struct tree {
#define t_fval t_xxxx.tt_fval
#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

View file

@ -15,7 +15,7 @@
p_type int_type, char_type, short_type, long_type, bool_type;
p_type uint_type, uchar_type, ushort_type, ulong_type;
p_type void_type, incomplete_type;
p_type void_type;
p_type float_type, double_type;
p_type string_type, address_type;
@ -257,7 +257,6 @@ init_types()
string_type = basic_type(T_STRING, 0L);
address_type = basic_type(T_POINTER, pointer_size);
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);
@ -324,7 +323,7 @@ clean_tp_tab()
if (j) {
while (--j > 0) {
p_type p = list_row[i].row[j];
if (p == incomplete_type) {
if (p && p->ty_class == 0) {
error("incomplete type (%d,%d) 0x%x", i, j, &list_row[i].row[j]);
}
}

View file

@ -44,8 +44,8 @@ typedef struct type {
struct symbol *ty_sym;
union {
/* cross references */
char *typ_tag;
#define ty_tag ty_v.typ_tag
struct type *typ_cross;
#define ty_cross ty_v.typ_cross
/* procedures/functions: */
struct {
int typ_nparams;
@ -117,6 +117,6 @@ extern long
extern p_type char_type, uchar_type, bool_type, int_type,
long_type, double_type, string_type, address_type;
extern p_type void_type, incomplete_type;
extern p_type void_type;
extern long int_size, pointer_size, long_size, double_size;

View file

@ -5,6 +5,7 @@
#include "position.h"
#include "scope.h"
#include "idf.h"
#include "symbol.h"
#include "type.h"
#include "message.h"
@ -38,7 +39,6 @@ get_addr(sym, psize)
case VAR:
/* exists if child exists; nm_value contains addres */
return (t_addr) sym->sy_name.nm_value;
break;
case VARPAR:
case LOCVAR:
/* first find the stack frame in which it resides */
@ -51,23 +51,21 @@ get_addr(sym, psize)
for (;;) {
sc = 0;
if (! (EM_regs = get_EM_regs(i++))) {
/* no child? */
break;
return 0;
}
if (! EM_regs[AB_OFF]) {
/* no more frames */
break;
error("%s not available", sym->sy_idf->id_text);
return 0;
}
sc = base_scope(get_scope_from_addr(EM_regs[PC_OFF]));
if (! sc || sc->sc_start > EM_regs[PC_OFF]) {
error("%s not available", sym->sy_idf->id_text);
sc = 0;
break;
return 0;
}
if (sc == symsc) break; /* found it */
}
if (! sc) break; /* not found */
if (sym->sy_class == LOCVAR) {
/* Either local variable or value parameter */
return EM_regs[sym->sy_name.nm_value < 0 ? LB_OFF : AB_OFF] +
@ -101,6 +99,7 @@ get_addr(sym, psize)
return a;
}
default:
error("%s is not a variable", sym->sy_idf->id_text);
break;
}
return 0;
@ -162,7 +161,7 @@ get_value(sym, buf, psize)
size = *psize;
*buf = malloc((unsigned) size);
if (! *buf) {
error("Could not allocate enough memory");
error("could not allocate enough memory");
break;
}
if (get_bytes(size, a, *buf)) {