📄 events.c
字号:
/*@(#)events.c 4.2 Ultrix 11/9/90*//************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//************************************************************************ * * * Modification History * * * * 005 - Added support for vectors. * * (L Miller, 18JAN90) * * * * 004 - Merged in 4.3 changes. * * (vjh, April 29, 1986) * * * * 003 - Fixed *many* bugs/problems in trace (search for 003). * * (vjh, July 23, 1985) * * * * 002 - Updated all calls to findlanguage() to call with * * LanguageName constant, rather than with a filename * * suffix. * * (vjh, June 22, 1985) * * * * 001 - Added routine delallevents() for use with the * * "delete *" command. * * (Victoria Holt, April 25, 1985) * * * ************************************************************************//* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */#ifndef lintstatic char sccsid[] = "@(#)events.c 5.1 (Berkeley) 5/31/85";#endif not lintstatic char rcsid[] = "$Header: events.c,v 1.5 84/12/26 10:39:26 linton Exp $";/* * Event/breakpoint managment. */#include "defs.h"#include "events.h"#include "languages.h"#include "main.h"#include "symbols.h"#include "tree.h"#include "eval.h"#include "source.h"#include "mappings.h"#include "runtime.h"#include "process.h"#include "machine.h"#include "lists.h"#ifndef publictypedef struct Event *Event;typedef struct Breakpoint *Breakpoint;Boolean inst_tracing;Boolean single_stepping;Boolean isstopped;#include "symbols.h"Symbol linesym;Symbol procsym;Symbol pcsym;Symbol retaddrsym;#define addevent(cond, cmdlist) event_alloc(false, cond, cmdlist)#define event_once(cond, cmdlist) event_alloc(true, cond, cmdlist)#endifstruct Event { unsigned int id; Boolean temporary; Node condition; Cmdlist actions;};struct Breakpoint { Event event; Address bpaddr; Lineno bpline; Cmdlist actions; Boolean temporary;};typedef List Eventlist;typedef List Bplist;#define eventlist_append(event, el) list_append(list_item(event), nil, el)#define bplist_append(bp, bl) list_append(list_item(bp), nil, bl)private Eventlist eventlist; /* list of active events */private Bplist bplist; /* list of active breakpoints */private Event curevent; /* most recently created event */private integer eventid; /* id number of current event */private integer trid; /* id number of current trace */typedef struct Trcmd { Integer trid; Event event; Cmdlist cmdlist;} *Trcmd;private List eachline; /* commands to execute after each line */private List eachinst; /* commands to execute after each instruction */private Breakpoint bp_alloc();/* * Initialize breakpoint information. */private Symbol builtinsym(str, class, type)String str;Symclass class;Symbol type;{ Symbol s; s = insert(identname(str, true)); s->language = findlanguage(ASSEMBLER); s->class = class; s->type = type; return s;}public bpinit(flag)Boolean flag;{ linesym = builtinsym("$line", VAR, t_int); procsym = builtinsym("$proc", PROC, nil); pcsym = lookup(identname("$pc", true)); if (pcsym == nil) { panic("can't find $pc"); } retaddrsym = builtinsym("$retaddr", VAR, t_int); if(!flag) { eventlist = list_alloc(); bplist = list_alloc(); eachline = list_alloc(); eachinst = list_alloc(); }}/* Allocates a new event. Adds the event to the eventlist. Traps the * event (in translate()); when this trap is encountered, the commands * in cmdlist will be executed. * * "curevent" must be assigned the new event before calling translate() * in case translate() calls evalcmdlist() with the new event. * This is part of a fix for the "missing trid" panic. (003 - vjh) */public Event event_alloc(istmp, econd, cmdlist)boolean istmp;Node econd;Cmdlist cmdlist;{ register Event e; e = new(Event); ++eventid; e->id = eventid; e->temporary = istmp; e->condition = econd; e->actions = cmdlist; eventlist_append(e, eventlist); curevent = e; translate(e); return e;}/* Routine to indiscriminately remove all break/tracepoints. * Since this routine is invoked by the user (with delete *), * it only removes user defined eventpoints (ie. leaves temporaries). * Used to remove all of them, which would cause "program unexpecdly * exited" message (breakpoint on _exit() was deleted; see resume() in * process.c). (003 - vjh) */public boolean delallevents(){ Event e; Breakpoint bp; Trcmd t; foreach (Event, e, eventlist) if (not e->temporary) { foreach (Breakpoint, bp, bplist) if (bp->event == e) { if (tracebpts) { printf("deleting breakpoint at 0x%x\n", bp->bpaddr); fflush(stdout); } list_delete(list_curitem(bplist), bplist); } endfor list_delete(list_curitem(eventlist), eventlist); } 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 if (list_size(eachinst) == 0) { inst_tracing = false; if (list_size(eachline) == 0) { single_stepping = false; } }}/* * Delete the event with the given id. * Returns whether it's successful or not. */public boolean delevent(id)unsigned int id;{ Event e; Breakpoint bp; Trcmd t; boolean found; found = false; foreach (Event, e, eventlist) if (e->id == id) { found = true; foreach (Breakpoint, bp, bplist) if (bp->event == e) { if (tracebpts) { printf("deleting breakpoint at 0x%x\n", bp->bpaddr); fflush(stdout); } list_delete(list_curitem(bplist), bplist); } endfor list_delete(list_curitem(eventlist), eventlist); break; } endfor foreach (Trcmd, t, eachline) if (t->event->id == id) { found = true; printrmtr(t); list_delete(list_curitem(eachline), eachline); } endfor foreach (Trcmd, t, eachinst) if (t->event->id == id) { found = true; printrmtr(t); list_delete(list_curitem(eachinst), eachinst); } endfor if (list_size(eachinst) == 0) { inst_tracing = false; if (list_size(eachline) == 0) { single_stepping = false; } } return found;}/* Translate an event into the appropriate breakpoints and actions. * While we're at it, turn on the breakpoints if the condition is true. * Added a check for presence of a coredump, so that condition doesn't * appear to be true when it really isn't (ie. reading corefile sets * pc to be routine in which the program died; could be Symbol s). * (003 - vjh) */private translate(e)Event e;{ Breakpoint bp; Symbol s; Node place; Lineno line; Address addr; checkref(e->condition); switch (e->condition->op) { case O_EQ: if (e->condition->value.arg[0]->op == O_SYM) { s = e->condition->value.arg[0]->value.sym; place = e->condition->value.arg[1]; if (s == linesym) { if (place->op == O_QLINE) { line = place->value.arg[1]->value.lcon; addr = objaddr(line, place->value.arg[0]->value.scon); } else { eval(place); line = pop(long); addr = objaddr(line, cursource); } if (addr == NOADDR || addr == ADDRNOEXEC) { if (not delevent(e->id)) { printf("!! dbx.translate: can't undo event %d?\n", e->id); } beginerrmsg(); if (addr == NOADDR) fprintf(stderr, "beyond end of file at line "); else fprintf(stderr, "no executable code found at line "); prtree(stderr, place); enderrmsg(); } bp = bp_alloc(e, addr, line, e->actions); } else if (s == procsym) { eval(place); s = pop(Symbol); bp = bp_alloc(e, codeloc(s), 0, e->actions); if ((not coredump) and isactive(s) /* (003 - vjh) */ and pc != codeloc(program)) { evalcmdlist(bp->actions); } } else if (s == pcsym) { eval(place); bp = bp_alloc(e, pop(Address), 0, e->actions); } else { condbp(e); } } else { condbp(e); } break; /* * These should be handled specially. * But for now I'm ignoring the problem. */ case O_AND: case O_OR: default: condbp(e); break; }}/* * Create a breakpoint for a condition that cannot be pinpointed * to happening at a particular address, but one for which we * must single step and check the condition after each statement. */private condbp(e)Event e;{ Symbol p; Breakpoint bp; Cmdlist actions; p = tcontainer(e->condition); if (p == nil) { p = program; } actions = buildcmdlist(build(O_IF, e->condition, e->actions)); actions = buildcmdlist(build(O_TRACEON, false, actions)); bp = bp_alloc(e, codeloc(p), 0, actions);}/* * Determine the deepest nested subprogram that still contains * all elements in the given expression. */public Symbol tcontainer(exp)Node exp;{ Integer i; Symbol s, t, u, v; checkref(exp); s = nil; if (exp->op == O_SYM) { s = container(exp->value.sym); } else if (not isleaf(exp->op)) { for (i = 0; i < nargs(exp->op); i++) { t = tcontainer(exp->value.arg[i]); if (t != nil) { if (s == nil) { s = t; } else { u = s; v = t; while (u != v and u != nil) { u = container(u); v = container(v); } if (u == nil) { panic("bad ancestry for \"%s\"", symname(s)); } else { s = u; } } } } } return s;}/* * Determine if the given function can be executed at full speed. * This can only be done if there are no breakpoints within the function. */public Boolean canskip(f)Symbol f;{ Breakpoint p; Boolean ok; ok = true; foreach (Breakpoint, p, bplist) if (whatblock(p->bpaddr) == f) { ok = false; break; } endfor return ok;}/* * Print out what's currently being traced by looking at * the currently active events. * * Some convolution here to translate internal representation * of events back into something more palatable. */public status(){ Event e; if(vectorcapable) { fprintf(stderr, "machine is currently vector capable\n"); } else { fprintf(stderr, "machine is currently NOT vector capable\n"); } is_vector_capable(); foreach (Event, e, eventlist) if (not e->temporary) { printevent(e); } endfor}public printevent(e)Event e;{ Command cmd; if (not isredirected()) { printeventid(e->id); } cmd = list_element(Command, list_head(e->actions)); if (cmd->op == O_PRINTCALL) { printf("trace "); printname(stdout, cmd->value.sym); } else { if (list_size(e->actions) > 1) { printf("{ "); } foreach (Command, cmd, e->actions) printcmd(stdout, cmd); if (not list_islast()) { printf("; "); } endfor if (list_size(e->actions) > 1) { printf(" }"); } printcond(e->condition); } printf("\n");}private printeventid (id)integer id;{ printf("[%d] ", id);}/* * Print out a condition. */private printcond(cond)Node cond;{ Symbol s; Node place; if (cond->op == O_EQ and cond->value.arg[0]->op == O_SYM) { s = cond->value.arg[0]->value.sym; place = cond->value.arg[1]; if (s == procsym) { if (place->value.sym != program) { printf(" in "); printname(stdout, place->value.sym); } } else if (s == linesym) { printf(" at "); prtree(stdout, place); } else if (s == pcsym or s == retaddrsym) { printf(" i at "); prtree(stdout, place); } else { printf(" when "); prtree(stdout, cond); } } else { printf(" when "); prtree(stdout, cond); }}/* * Add a breakpoint to the breakpoint list, and return it. */private Breakpoint bp_alloc(e, addr, line, actions)Event e;Address addr;Lineno line;Cmdlist actions;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -