Predator  [unstable] git snapshot
symtrace.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Kamil Dudka <kdudka@redhat.com>
3  *
4  * This file is part of predator.
5  *
6  * predator is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * any later version.
10  *
11  * predator is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with predator. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef H_GUARD_SYM_TRACE_H
21 #define H_GUARD_SYM_TRACE_H
22 
23 /**
24  * @file symtrace.hh
25  * directed acyclic graph of the symbolic execution trace, see namespace Trace
26  */
27 
28 #include "config.h"
29 
30 #include "id_mapper.hh"
31 #include "join_status.hh"
32 #include "symbt.hh" // needed for EMsgLevel
33 #include "symheap.hh" // needed for EObjKind
34 
35 #include <vector>
36 #include <string>
37 
38 struct cl_loc;
39 
40 class SymState;
41 
42 namespace CodeStorage {
43  struct Fnc;
44  struct Insn;
45 }
46 
47 /// directed acyclic graph of the symbolic execution trace
48 namespace Trace {
49 
50 class Node;
51 
52 struct TracePlotter;
53 
54 typedef const struct cl_loc *TLoc;
55 typedef const CodeStorage::Fnc *TFnc;
56 typedef const CodeStorage::Insn *TInsn;
57 
58 typedef std::vector<Node *> TNodeList;
59 
60 // TODO: should we use a more generic ID type?
62 typedef std::vector<TIdMapper> TIdMapperList;
63 
64 std::string insnToLabel(const TInsn insn);
65 
66 /// an abstract base for Node and NodeHandle (externally not much useful)
67 class NodeBase {
68  protected:
69  /// list of all (0..n) parent nodes
71 
72  /// this is an abstract class, its instantiation is @b not allowed
73  NodeBase() { }
74 
75  /// construct Node with exactly one parent, can be extended later
76  NodeBase(Node *node):
77  parents_(1, node)
78  {
79  }
80 
81  public:
82  /// force virtual destructor
83  virtual ~NodeBase();
84 
85  /// this can be called only on nodes with exactly one parent
86  virtual Node* parent() const;
87 
88  /// reference to list of parents (containing 0..n pointers)
89  const TNodeList& parents() const { return parents_; }
90 
91  private:
92  virtual void replaceParent(Node *parentOld, Node *parentNew);
93  friend void replaceNode(Node *tr, Node *by);
94 };
95 
96 /// an abstract node of the symbolic execution trace graph
97 class Node: public NodeBase {
98  private:
99  /// birth notification from a child node
100  void notifyBirth(NodeBase *child);
101 
102  /// death notification from a child node
103  void notifyDeath(NodeBase *child);
104 
105  friend class NodeBase;
106  friend class NodeHandle;
107 
108  protected:
109  /// this is an abstract class, its instantiation is @b not allowed
110  Node():
111  alive_(true)
112  {
113  }
114 
115  /// constructor for nodes with exactly one parent
116  Node(Node *ref):
117  NodeBase(ref),
118  alive_(true)
119  {
120  idMapperList_.resize(1U);
121  ref->notifyBirth(this);
122  }
123 
124  /// constructor for nodes with exactly two parents
125  Node(Node *ref1, Node *ref2):
126  NodeBase(ref1),
127  alive_(true)
128  {
129  parents_.push_back(ref2);
130  idMapperList_.resize(2U);
131  ref1->notifyBirth(this);
132  ref2->notifyBirth(this);
133  }
134 
135  virtual ~Node();
136 
137  /// serialize this node to the given plot (externally not much useful)
138  virtual void plotNode(TracePlotter &) const = 0;
139 
140  friend void plotTraceCore(TracePlotter &);
141 
142  public:
143  /// used to store a list of child nodes
144  typedef std::vector<NodeBase *> TBaseList;
145 
146  /// reference to list of child nodes (containing 0..n pointers)
147  const TBaseList& children() const { return children_; }
148 
149  /// print the node in a human-readable format if considered interesting
150  virtual Node* /* selected predecessor */ printNode() const {
151  return this->parent();
152  }
153 
154  public:
155  /// return the ID mapping describing the operation behind the trace node
157 
158  /// return the ID mapping describing the operation behind the trace node
159  const TIdMapperList& idMapperList() const;
160 
161  /// return the ID mapping describing the operation behind the trace node
162  TIdMapper& idMapper();
163 
164  /// return the ID mapping describing the operation behind the trace node
165  const TIdMapper& idMapper() const;
166 
167  private:
168  // copying NOT allowed
169  Node(const Node &);
170  Node& operator=(const Node &);
171 
172  protected:
174 
175  private:
177  bool alive_;
178 };
179 
180 void replaceNode(Node *tr, Node *by);
181 
182 /// useful to prevent a trace sub-graph from being destroyed too early
183 class NodeHandle: public NodeBase {
184  public:
185  /// initialize the handle with the given node, can be reset later
187  NodeBase(ref)
188  {
189  ref->notifyBirth(this);
190  }
191 
192  /// return the node stored within this handle
193  Node* node() const {
194  return this->parent();
195  }
196 
197  /// release the old node and re-initialize the handle with the new one
198  void reset(Node *);
199 
200  /// overridden copy constructor keeping the semantics of a handle
201  NodeHandle(const NodeHandle &tpl):
202  NodeBase(tpl.node())
203  {
204  this->parent()->notifyBirth(this);
205  }
206 
207  /// overridden assignment operator keeping the semantics of a handle
209  this->reset(tpl.node());
210  return *this;
211  }
212 };
213 
214 /// used to explicitly highlight trace graph nodes that should not be reachable
215 class TransientNode: public Node {
216  public:
217  /// @param origin describe where the unreachable node originates from
218  TransientNode(const char *origin):
219  origin_(origin)
220  {
221  }
222 
223  virtual Node* printNode() const;
224 
225  protected:
226  void virtual plotNode(TracePlotter &) const;
227 
228  private:
229  const char *origin_;
230 };
231 
232 /// root node of the trace graph (usually a call of the root function)
233 class RootNode: public Node {
234  private:
235  const TFnc rootFnc_;
236 
237  public:
238  /// @param rootFnc a CodeStorage::Fnc object used for the root call
239  RootNode(const TFnc rootFnc):
240  rootFnc_(rootFnc)
241  {
242  }
243 
244  virtual Node* printNode() const;
245 
246  protected:
247  void virtual plotNode(TracePlotter &) const;
248 };
249 
250 /// a trace graph node that represents a non-terminal instruction
251 class InsnNode: public Node {
252  private:
253  const TInsn insn_;
254  const bool isBuiltin_;
255 
256  public:
257  /**
258  * @param ref a reference to a trace leading to this instruction
259  * @param insn a CodeStorage::Insn object representing the instruction
260  * @param isBuiltin true, if the instruction is recognized as a built-in
261  */
262  InsnNode(Node *ref, TInsn insn, const bool isBuiltin):
263  Node(ref),
264  insn_(insn),
265  isBuiltin_(isBuiltin)
266  {
268  }
269 
270  virtual Node* printNode() const;
271 
272  protected:
273  void virtual plotNode(TracePlotter &) const;
274 };
275 
276 /// a trace graph node that represents a conditional insn being traversed
277 class CondNode: public Node {
278  private:
279  const TInsn inCmp_;
280  const TInsn inCnd_;
281  const bool determ_;
282  const bool branch_;
283 
284  public:
285  /**
286  * @param ref a reference to a trace leading to this instruction
287  * @param inCmp a comparison instruction occurring prior to inCnd
288  * @param inCnd a conditional jump instruction being traversed
289  * @param determ true if the branch being taken was known in advance
290  * @param branch true if the 'then' branch was taken, false for 'else'
291  */
292  CondNode(Node *ref, TInsn inCmp, TInsn inCnd, bool determ, bool branch):
293  Node(ref),
294  inCmp_(inCmp),
295  inCnd_(inCnd),
296  determ_(determ),
297  branch_(branch)
298  {
300  }
301 
302  virtual Node* printNode() const;
303 
304  protected:
305  void virtual plotNode(TracePlotter &) const;
306 };
307 
308 /// a trace graph node that represents a @b single abstraction step
309 class AbstractionNode: public Node {
310  private:
312  std::string name_;
313 
314  public:
315  /**
316  * @param ref a trace leading to this abstraction step
317  * @param kind the kind of abstraction step being performed
318  */
320  Node(ref),
321  kind_(kind)
322  {
323  }
324 
325  /// @param name name of the corresponding debug plot (empty if unused)
326  void setPlotName(const std::string &name) {
327  name_ = name;
328  }
329 
330  protected:
331  void virtual plotNode(TracePlotter &) const;
332 };
333 
334 /// a trace graph node that represents a @b single concretization step
335 class ConcretizationNode: public Node {
336  private:
338  const std::string name_;
339 
340  public:
341  /**
342  * @param ref a trace leading to this concretization step
343  * @param kind the kind of concretization step being performed
344  * @param name name of the corresponding debug plot (empty if unused)
345  */
346  ConcretizationNode(Node *ref, EObjKind kind, const std::string &name):
347  Node(ref),
348  kind_(kind),
349  name_(name)
350  {
351  }
352 
353  protected:
354  void virtual plotNode(TracePlotter &) const;
355 };
356 
357 /// a trace graph node that represents a @b single splice-out operation
358 class SpliceOutNode: public Node {
359  private:
360  const bool len_;
361 
362  public:
363  /**
364  * @param ref a trace leading to this splice-out operation
365  * @param len count of successfully spliced-out segments
366  */
367  SpliceOutNode(Node *ref, const int len = 1):
368  Node(ref),
369  len_(len)
370  {
372  }
373 
374  protected:
375  void virtual plotNode(TracePlotter &) const;
376 };
377 
378 /// a trace graph node that represents a @b single join operation
379 class JoinNode: public Node {
380  public:
381  /// takes references to both traces being joined by this operation
382  JoinNode(Node *ref1, Node *ref2, const EJoinStatus status):
383  Node(ref1, ref2),
384  status_(status)
385  {
386  idMapperList_[0].setNotFoundAction(TIdMapper::NFA_RETURN_NOTHING);
387  idMapperList_[1].setNotFoundAction(TIdMapper::NFA_RETURN_NOTHING);
388  }
389 
390  virtual Node* parent() const;
391 
392  virtual Node* printNode() const;
393 
394  protected:
395  void virtual plotNode(TracePlotter &) const;
396 
397  private:
399 };
400 
401 /// trace graph nodes inserted automatically per each SymHeap clone operation
402 class CloneNode: public Node {
403  public:
405  Node(ref)
406  {
407  }
408 
409  virtual Node* printNode() const;
410 
411  protected:
412  void virtual plotNode(TracePlotter &) const;
413 };
414 
415 /// trace graph node representing a call entry point
416 class CallEntryNode: public Node {
417  private:
418  const TInsn insn_;
419 
420  public:
421  /**
422  * @param ref trace representing the call entry as seen by the @b caller
423  * @param insn a CodeStorage::Insn object representing the call
424  */
425  CallEntryNode(Node *ref, const TInsn insn):
426  Node(ref),
427  insn_(insn)
428  {
429  }
430 
431  virtual Node* printNode() const;
432 
433  protected:
434  void virtual plotNode(TracePlotter &) const;
435 };
436 
437 /// trace graph node representing a cached call result
438 class CallCacheHitNode: public Node {
439  private:
440  const TFnc fnc_;
441 
442  public:
443  /**
444  * @param entry trace representing the call cache entry
445  * @param result trace representing a cached call result (without frame)
446  * @param fnc a CodeStorage::Fnc fld representing the called function
447  */
448  CallCacheHitNode(Node *entry, Node *result, const TFnc fnc):
449  Node(entry, result),
450  fnc_(fnc)
451  {
452  }
453 
454  virtual Node* printNode() const;
455 
456  protected:
457  void virtual plotNode(TracePlotter &) const;
458 };
459 
460 /// trace graph node representing a call frame
461 class CallFrameNode: public Node {
462  private:
463  const TInsn insn_;
464 
465  public:
466  /**
467  * @param ref trace representing the call entry as seen by the @b caller
468  * @param insn a CodeStorage::Insn object representing the call
469  */
470  CallFrameNode(Node *ref, const TInsn insn):
471  Node(ref),
472  insn_(insn)
473  {
474  }
475 
476  virtual Node* printNode() const;
477 
478  protected:
479  void virtual plotNode(TracePlotter &) const;
480 };
481 
482 /// trace graph node representing a call result
483 class CallDoneNode: public Node {
484  private:
485  const TFnc fnc_;
486 
487  public:
488  /**
489  * @param result trace representing the result as seen by the @b callee
490  * @param fnc a CodeStorage::Fnc fld representing the called function
491  */
492  CallDoneNode(Node *result, const TFnc fnc):
493  Node(result),
494  fnc_(fnc)
495  {
496  }
497 
498  /**
499  * @param result trace representing the result as seen by the @b callee
500  * @param callFrame trace representing the call frame of the call
501  * @param fnc a CodeStorage::Fnc fld representing the called function
502  */
503  CallDoneNode(Node *result, Node *callFrame, const TFnc fnc):
504  Node(result, callFrame),
505  fnc_(fnc)
506  {
507  }
508 
509  virtual Node* printNode() const;
510 
511  protected:
512  void virtual plotNode(TracePlotter &) const;
513 };
514 
515 /// a trace graph node that represents a @b single call of importGlVar()
516 class ImportGlVarNode: public Node {
517  private:
518  const std::string varString_;
519 
520  public:
521  /**
522  * @param ref a trace leading to this concretization step
523  * @param varString describing the global variable being imported
524  */
525  ImportGlVarNode(Node *ref, const std::string &varString):
526  Node(ref),
527  varString_(varString)
528  {
529  }
530 
531  protected:
532  void virtual plotNode(TracePlotter &) const;
533 };
534 
535 /// trace graph node representing an error/warning message
536 class MsgNode: public Node {
537  private:
539  const TLoc loc_;
540 
541  public:
542  /**
543  * @param ref a trace leading to this error/warning message
544  * @param level classification of the message (error, warning, ...)
545  * @param loc a location info the message was emitted with
546  */
547  MsgNode(Node *ref, const EMsgLevel level, const TLoc loc):
548  Node(ref),
549  level_(level),
550  loc_(loc)
551  {
553  }
554 
555  protected:
556  void virtual plotNode(TracePlotter &) const;
557 };
558 
559 /// trace graph node representing something important for the user
560 class UserNode: public Node {
561  private:
562  const TInsn insn_;
563  const std::string label_;
564 
565  public:
566  /**
567  * @param ref a trace leading to this use node
568  * @param insn a CodeStorage::Insn object that caused the node to appear
569  * @param label a label describing what this node actually means
570  */
571  UserNode(Node *ref, const TInsn insn, const char *label):
572  Node(ref),
573  insn_(insn),
574  label_(label)
575  {
577  }
578 
579  virtual Node* printNode() const;
580 
581  protected:
582  void virtual plotNode(TracePlotter &) const;
583 };
584 
585 /// resolve composite ID mapping from trSrc to trDst
586 void resolveIdMapping(TIdMapper *pDst, const Node *trSrc, const Node *trDst);
587 
588 /// plot a trace graph named "name-NNNN.dot" leading to the given node
589 bool plotTrace(Node *endPoint, const std::string &name, std::string *pName = 0);
590 
591 /// print a human-readable trace using the Code Listener messaging API
592 void printTrace(Node *endPoint);
593 
594 /// this runs in the debug build only
595 bool chkTraceGraphConsistency(Node *const from);
596 
597 /// a container maintaining a set of trace graph end-points
599  public:
602 
603  /// insert a new trace graph end-point
604  bool /* any change */ insert(Node *);
605 
606  /// plot a common graph leading to all end-points inside the container
607  bool plotAll(const std::string &name);
608 
609  private:
610  // copying NOT allowed
613 
614  private:
615  struct Private;
616  Private *d;
617 };
618 
619 /// a container maintaining a set of trace graphs being built on the fly
620 class GraphProxy {
621  public:
622  GraphProxy();
623  ~GraphProxy();
624 
625  /// insert a new trace graph end-point into the specified trace graph
626  bool /* any change */ insert(Node *, const std::string &graphName);
627 
628  /// plot the specified graph
629  bool plotGraph(const std::string &name);
630 
631  /// plot all graphs being maintained by this proxy
632  bool plotAll();
633 
634  private:
635  // copying NOT allowed
636  GraphProxy(const GraphProxy &);
637  GraphProxy& operator=(const GraphProxy &);
638 
639  private:
640  struct Private;
641  Private *d;
642 };
643 
644 /// a singleton holding global GraphProxy (may be extended later)
645 class Globals {
646  private:
648  static Globals *inst_;
649 
650  public:
651  static bool alive() {
652  return !!inst_;
653  }
654 
655  static Globals* instance() {
656  return (alive())
657  ? (inst_)
658  : (inst_ = new Globals);
659  }
660 
662  return &glProxy_;
663  }
664 
665  static void cleanup() {
666  delete inst_;
667  inst_ = 0;
668  }
669 };
670 
671 /// mark the just completed @b clone operation as @b intended and unimportant
672 void waiveCloneOperation(SymHeap &sh);
673 
674 /// mark the just completed @b clone operation as @b intended and unimportant
676 
677 } // namespace Trace
678 
679 #endif /* H_GUARD_SYM_TRACE_H */