📄 events.c
字号:
{ register Breakpoint p; p = new(Breakpoint); p->event = e; p->bpaddr = addr; p->bpline = line; p->actions = actions; p->temporary = false; if (tracebpts) { if (e == nil) { printf("new bp at 0x%x for event ??\n", addr, e->id); } else { printf("new bp at 0x%x for event %d\n", addr, e->id); } fflush(stdout); } bplist_append(p, bplist); return p;}/* * Free all storage in the event and breakpoint tables. */public bpfree(){ register Event e; fixbps(); foreach (Event, e, eventlist) if (not delevent(e->id)) { printf("!! dbx.bpfree: can't delete event %d\n", e->id); } list_delete(list_curitem(eventlist), eventlist); endfor}/* * Determine if the program stopped at a known breakpoint * and if so do the associated commands. */public boolean bpact(){ register Breakpoint p; Boolean found; integer eventId; found = false; foreach (Breakpoint, p, bplist) if (p->bpaddr == pc) { if (tracebpts) { printf("breakpoint for event %d found at location 0x%x\n", p->event->id, pc); } found = true; if (p->event->temporary) { if (not delevent(p->event->id)) { printf("!! dbx.bpact: can't find event %d\n", p->event->id); } } /* See if this breakpoint is associated with a trace event * that has just completed (eg. see traceoff() ). If so, * delete the associated breakpoint. (Didn't do this before - * main source of "missing trid" panic: breakpoint would be * encountered again, but the trcmd associated with it had * been deleted in traceoff() ). */ if (p->temporary) { list_delete(list_curitem(bplist), bplist); } else { evalcmdlist(p->actions); if (isstopped) { eventId = p->event->id; } } } endfor if (isstopped) { if (found) { printeventid(eventId); } printstatus(); } fflush(stdout); return found;}/* Sets up a single step context (ie. global single_stepping = true). * As long as this is true, dbx will step by source line * (instruction if first arg. is true) until traceoff() is called. * If tracing by source line, the commands that are to be executed * after each line are appended to eachline. Otherwise, they are * appended to eachinst list. After stepping each line, printnews() is * called, and the commands in eachline (eachinst) are executed. * * A breakpoint is set at the end of the current procedure to * automatically turn off the given tracing with traceoff(). */public traceon(inst, event, cmdlist)Boolean inst;Event event;Cmdlist cmdlist;{ register Trcmd trcmd; Breakpoint bp; Cmdlist actions; Address ret; Event e; if (event == nil) { e = curevent; } else { e = event; } trcmd = new(Trcmd); ++trid; trcmd->trid = trid; trcmd->event = e; trcmd->cmdlist = cmdlist; single_stepping = true; if (inst) { inst_tracing = true; list_append(list_item(trcmd), nil, eachinst); } else { list_append(list_item(trcmd), nil, eachline); } ret = return_addr(); if (ret != 0) { /* ret is 0 if tracing entire program. */ actions = buildcmdlist(build(O_TRACEOFF, trcmd->trid)); bp = bp_alloc(e, (Address) ret, 0, actions); bp->temporary = true; } if (tracebpts) { printf("adding trace %d for event %d\n", trcmd->trid, e->id); }}/* Turn off some kind of tracing. * Strictly an internal command, this cannot be invoked by the user. * First search for and remove the commands listed in eachline (or * eachinst) that are associated with this trid. If trid not found, * panic. * >>> Next, REMOVE THE BREAKPOINT ASSOCIATED WITH THE * >>> EVENT: This is now done in bpact(). * Finally, reset inst_tracing and single_stepping flags when there is * no more inst/line tracing in effect. * * Note - this does not delete the event itself, only the trace * associated with the event. In this way, if the user says "run" * again, the trace corresponding to this event will be reconstructed. */public traceoff(id)Integer id;{ register Trcmd t; register Boolean found; register Event e; register Breakpoint bp; found = false; foreach (Trcmd, t, eachline) if (t->trid == id) { printrmtr(t); list_delete(list_curitem(eachline), eachline); found = true; break; } endfor if (not found) { foreach (Trcmd, t, eachinst) if (t->trid == id) { printrmtr(t); list_delete(list_curitem(eachinst), eachinst); found = true; break; } endfor if (not found) { beginerrmsg(); fprintf(stderr, "[internal error: trace id %d not found]\n", id); } } /* Delete associated breakpoints. This is now done in bpact(), * by making use of the "temporary" field in the Breakpoint struct. * foreach (Event, e, eventlist) if (t->event->id == e->id) { foreach (Breakpoint, bp, bplist) if (bp->event == e and bp->bpaddr == pc) { if (tracebpts) { printf("deleting breakpoint at 0x%x", bp->bpaddr); printf(" associated with event %d\n", e->id); fflush(stdout); } list_delete(list_curitem(bplist), bplist); } endfor } endfor */ /* Reset flags if no more inst/line tracing in effect. */ if (list_size(eachinst) == 0) { inst_tracing = false; if (list_size(eachline) == 0) { single_stepping = false; } }}/* * If breakpoints are being traced, note that a Trcmd is being deleted. */private printrmtr(t)Trcmd t;{ if (tracebpts) { printf("removing trace %d", t->trid); if (t->event != nil) { printf(" for event %d", t->event->id); } printf("\n"); }}/* Print out news during single step tracing. * This routine has a pretty bad hack in it. Because each trace is * stored and maintained independently from any other, one trace cannot * be aware of what another is doing. This is expecially evident in * recursive routines. Traceon() is called repeatedly each time the * start address of the routine is encountered (where there is a bkpt * associated with the event). Traceon() will add the same command(s) * to the eachline list at each invocation of the routine (eg. * O_PRINTSRCPOS). The case statement in this routine prevents a * source line from being displayed as many times as the routine has * called itself. (003 - vjh) */public printnews(){ register Trcmd t; register Command cmd; register Boolean noprint; noprint = true; foreach (Trcmd, t, eachline) foreach(Command, cmd, t->cmdlist) /* This case statement checks to see if we have already * displayed a source line or a return. It prevents printing * the same line/return over & over in a recursively called * routine. (003 - vjh) */ switch (cmd->op) { case O_PRINTSRCPOS: if (noprint) { evalcmd(cmd); noprint = false; } break; default: evalcmd(cmd); break; } endfor endfor noprint = true; foreach (Trcmd, t, eachinst) foreach(Command, cmd, t->cmdlist) switch (cmd->op) { case O_PRINTSRCPOS: if (noprint) { evalcmd(cmd); noprint = false; } break; default: evalcmd(cmd); break; } endfor endfor bpact();}/* * A procedure call/return has occurred while single-stepping, * note it if we're tracing lines. */private Boolean chklist();public callnews(iscall)Boolean iscall;{ if (not chklist(eachline, iscall)) { chklist(eachinst, iscall); }}private Boolean chklist(list, iscall)List list;Boolean iscall;{ register Trcmd t; register Command cmd; setcurfunc(whatblock(pc)); foreach (Trcmd, t, list) foreach (Command, cmd, t->cmdlist) if (cmd->op == O_PRINTSRCPOS and (cmd->value.arg[0] == nil or cmd->value.arg[0]->op == O_QLINE)) { if (iscall) { printentry(curfunc); } else { printexit(curfunc); } return true; } endfor endfor return false;}/* * When tracing variables we keep a copy of their most recent value * and compare it to the current one each time a breakpoint occurs. */#define TRBUFFSIZE 512 /* Used to be MAXTRSIZE - now no max (vjh) *//* * List of variables being watched. */typedef struct Trinfo *Trinfo;struct Trinfo { Node variable; Address traddr; Symbol trblock; char *trvalue;};private List trinfolist;/* * Find the trace information record associated with the given record. * If there isn't one then create it and add it to the list. * Made this work in recursive routines: checks tp->traddr == addr * as well. (003 - vjh) */private Trinfo findtrinfo(p)Node p;{ register Trinfo tp; Boolean isnew; Address addr; isnew = true; addr = lval(p); if (trinfolist == nil) { trinfolist = list_alloc(); } else { foreach (Trinfo, tp, trinfolist) if (tp->variable == p and tp->traddr == addr) { isnew = false; break; } endfor } if (isnew) { if (tracebpts) { printf("adding trinfo for \""); prtree(stdout, p); printf("\"\n"); } tp = new(Trinfo); tp->variable = p; tp->traddr = addr; tp->trvalue = nil; list_append(list_item(tp), nil, trinfolist); } return tp;}/* * Print out the value of a variable if it has changed since the * last time we checked. * Took away size limitations. Now, if data is > TRBUFFSIZE, malloc() * a large enough buffer. (003 - vjh) */public printifchanged(p)Node p;{ register Trinfo tp; register int n; char sbuff[TRBUFFSIZE]; char *buff; Filename curfile; static Lineno prevline; static Filename prevfile; tp = findtrinfo(p); n = size(p->nodetype); if (n > TRBUFFSIZE) { buff = newarr(char, n); } else { buff = sbuff; } dread(buff, tp->traddr, n); curfile = srcfilename(pc); if (tp->trvalue == nil) { tp->trvalue = newarr(char, n); mov(buff, tp->trvalue, n); mov(buff, sp, n); sp += n; printf("initially (at line %d in \"%s\"):\t", curline, curfile); prtree(stdout, p); printf(" = "); printval(p->nodetype); putchar('\n'); } else if (cmp(tp->trvalue, buff, n) != 0) { mov(buff, tp->trvalue, n); mov(buff, sp, n); sp += n; printf("after line %d in \"%s\":\t", prevline, prevfile); prtree(stdout, p); printf(" = "); printval(p->nodetype); putchar('\n'); } prevline = curline; prevfile = curfile; if (buff != sbuff) { dispose(buff); }}/* * Stop if the value of the given expression has changed. * Took away size limitations. Now, if data is > TRBUFFSIZE, malloc() * a large enough buffer. (003 - vjh) */public stopifchanged(p)Node p;{ register Trinfo tp; register int n; char sbuff[TRBUFFSIZE]; char *buff; static Lineno prevline; tp = findtrinfo(p); n = size(p->nodetype); if (n > TRBUFFSIZE) { buff = newarr(char, n); } else { buff = sbuff; } dread(buff, tp->traddr, n); if (tp->trvalue == nil) { tp->trvalue = newarr(char, n); mov(buff, tp->trvalue, n); isstopped = true; } else if (cmp(tp->trvalue, buff, n) != 0) { mov(buff, tp->trvalue, n); mov(buff, sp, n); sp += n; printf("after line %d:\t", prevline); prtree(stdout, p); printf(" = "); printval(p->nodetype); putchar('\n'); isstopped = true; } prevline = curline; if (buff != sbuff) { dispose(buff); }}/* * Free the tracing table. */public trfree(){ register Trinfo tp; foreach (Trinfo, tp, trinfolist) dispose(tp->trvalue); dispose(tp); list_delete(list_curitem(trinfolist), trinfolist); endfor}/* * Fix up breakpoint information before continuing execution. * * It's necessary to destroy events and breakpoints that were created * temporarily and still exist because the program terminated abnormally. */public fixbps(){ register Event e; register Trcmd t; single_stepping = false; inst_tracing = false; trfree(); foreach (Event, e, eventlist) if (e->temporary) { if (not delevent(e->id)) { printf("!! dbx.fixbps: can't find event %d\n", e->id); } } endfor foreach (Trcmd, t, eachline) printrmtr(t); list_delete(list_curitem(eachline), eachline); endfor foreach (Trcmd, t, eachinst) printrmtr(t); list_delete(list_curitem(eachinst), eachinst); endfor trid = 0;}/* * Set all breakpoints in object code. */public setallbps(){ register Breakpoint p; foreach (Breakpoint, p, bplist) setbp(p->bpaddr); endfor}/* * Undo damage done by "setallbps". */public unsetallbps(){ register Breakpoint p; foreach (Breakpoint, p, bplist) unsetbp(p->bpaddr); endfor}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -