Class: Necropsy::CallGraph
- Inherits:
-
Object
- Object
- Necropsy::CallGraph
- Defined in:
- lib/necropsy/graph/call_graph.rb
Instance Attribute Summary collapse
-
#call_sites ⇒ Object
readonly
Returns the value of attribute call_sites.
-
#class_infos ⇒ Object
readonly
Returns the value of attribute class_infos.
-
#entry_points ⇒ Object
readonly
Returns the value of attribute entry_points.
-
#entrypoint_hints ⇒ Object
readonly
Returns the value of attribute entrypoint_hints.
-
#instantiated_classes ⇒ Object
readonly
Returns the value of attribute instantiated_classes.
-
#nodes ⇒ Object
readonly
Returns the value of attribute nodes.
-
#observation ⇒ Object
readonly
Returns the value of attribute observation.
-
#profiles ⇒ Object
readonly
Returns the value of attribute profiles.
Instance Method Summary collapse
- #add_alive(node_id, evidence) ⇒ Object
- #add_edge(caller_id, callee_id, evidence) ⇒ Object
- #add_entry_point(node_id, reason) ⇒ Object
- #add_node(node) ⇒ Object
- #add_profile(profile) ⇒ Object
- #alive_evidences(node_id) ⇒ Object
- #apply_result(result) ⇒ Object
- #candidate_nodes(message) ⇒ Object
- #class_info(owner) ⇒ Object
- #descendants_of(owner) ⇒ Object
- #dynamic_alive?(node_id) ⇒ Boolean
- #dynamic_enabled? ⇒ Boolean
- #edges ⇒ Object
- #edges_from(node_id) ⇒ Object
- #incoming_edges(node_id) ⇒ Object
-
#initialize(scan_result) ⇒ CallGraph
constructor
A new instance of CallGraph.
- #method_nodes ⇒ Object
- #modules_for(owner) ⇒ Object
- #resolve_call_site(site, rta: false) ⇒ Object
- #to_h ⇒ Object
- #uncertainties(node_id = nil) ⇒ Object
Constructor Details
#initialize(scan_result) ⇒ CallGraph
Returns a new instance of CallGraph.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/necropsy/graph/call_graph.rb', line 8 def initialize(scan_result) @nodes = {} @edges = Hash.new { |hash, key| hash[key] = {} } @call_sites = scan_result.call_sites @instantiated_classes = scan_result.instantiated_classes.dup @class_infos = scan_result.class_infos.to_h { |info| [info.id, info] } @entrypoint_hints = scan_result.entrypoint_hints @entry_points = [] @profiles = [] @uncertainties = scan_result.uncertainties @dynamic_alive = {} @observation = {} scan_result.nodes.each { |node| add_node(node) } retain_known_instantiated_classes end |
Instance Attribute Details
#call_sites ⇒ Object (readonly)
Returns the value of attribute call_sites.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def call_sites @call_sites end |
#class_infos ⇒ Object (readonly)
Returns the value of attribute class_infos.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def class_infos @class_infos end |
#entry_points ⇒ Object (readonly)
Returns the value of attribute entry_points.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def entry_points @entry_points end |
#entrypoint_hints ⇒ Object (readonly)
Returns the value of attribute entrypoint_hints.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def entrypoint_hints @entrypoint_hints end |
#instantiated_classes ⇒ Object (readonly)
Returns the value of attribute instantiated_classes.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def instantiated_classes @instantiated_classes end |
#nodes ⇒ Object (readonly)
Returns the value of attribute nodes.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def nodes @nodes end |
#observation ⇒ Object (readonly)
Returns the value of attribute observation.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def observation @observation end |
#profiles ⇒ Object (readonly)
Returns the value of attribute profiles.
5 6 7 |
# File 'lib/necropsy/graph/call_graph.rb', line 5 def profiles @profiles end |
Instance Method Details
#add_alive(node_id, evidence) ⇒ Object
53 54 55 56 57 58 |
# File 'lib/necropsy/graph/call_graph.rb', line 53 def add_alive(node_id, evidence) return unless nodes.key?(node_id) @dynamic_alive[node_id] ||= [] @dynamic_alive[node_id] << evidence end |
#add_edge(caller_id, callee_id, evidence) ⇒ Object
46 47 48 49 50 51 |
# File 'lib/necropsy/graph/call_graph.rb', line 46 def add_edge(caller_id, callee_id, evidence) return unless nodes.key?(caller_id) && nodes.key?(callee_id) @edges[caller_id][callee_id] ||= [] @edges[caller_id][callee_id] << evidence end |
#add_entry_point(node_id, reason) ⇒ Object
28 29 30 31 32 33 |
# File 'lib/necropsy/graph/call_graph.rb', line 28 def add_entry_point(node_id, reason) return unless nodes.key?(node_id) entry = EntryPoint.new(node_id: node_id, reason: reason) entry_points << entry unless entry_points.include?(entry) end |
#add_node(node) ⇒ Object
24 25 26 |
# File 'lib/necropsy/graph/call_graph.rb', line 24 def add_node(node) nodes[node.id] ||= node end |
#add_profile(profile) ⇒ Object
42 43 44 |
# File 'lib/necropsy/graph/call_graph.rb', line 42 def add_profile(profile) profiles << profile end |
#alive_evidences(node_id) ⇒ Object
64 65 66 |
# File 'lib/necropsy/graph/call_graph.rb', line 64 def alive_evidences(node_id) @dynamic_alive[node_id] || [] end |
#apply_result(result) ⇒ Object
35 36 37 38 39 40 |
# File 'lib/necropsy/graph/call_graph.rb', line 35 def apply_result(result) result.edge_evidences.each { |edge| add_edge(edge.caller_id, edge.callee_id, edge.evidence) } result.alive_evidences.each { |alive| add_alive(alive.node_id, alive.evidence) } result.uncertainties.each { |node_id, | uncertainties[node_id].concat(Array()) } observation.merge!(result.observation) { |_key, left, right| merge_observation(left, right) } end |
#candidate_nodes(message) ⇒ Object
113 114 115 |
# File 'lib/necropsy/graph/call_graph.rb', line 113 def candidate_nodes() method_nodes.select { |node| node.name == } end |
#class_info(owner) ⇒ Object
98 99 100 |
# File 'lib/necropsy/graph/call_graph.rb', line 98 def class_info(owner) class_infos[owner] end |
#descendants_of(owner) ⇒ Object
102 103 104 |
# File 'lib/necropsy/graph/call_graph.rb', line 102 def descendants_of(owner) class_infos.keys.select { |candidate| candidate == owner || ancestor_chain(candidate).include?(owner) } end |
#dynamic_alive?(node_id) ⇒ Boolean
60 61 62 |
# File 'lib/necropsy/graph/call_graph.rb', line 60 def dynamic_alive?(node_id) @dynamic_alive.key?(node_id) end |
#dynamic_enabled? ⇒ Boolean
68 69 70 |
# File 'lib/necropsy/graph/call_graph.rb', line 68 def dynamic_enabled? @dynamic_alive.any? || observation.any? end |
#edges ⇒ Object
76 77 78 79 80 81 82 |
# File 'lib/necropsy/graph/call_graph.rb', line 76 def edges @edges.flat_map do |caller_id, callees| callees.map do |callee_id, evidences| Edge.new(caller_id: caller_id, callee_id: callee_id, evidences: evidences) end end end |
#edges_from(node_id) ⇒ Object
72 73 74 |
# File 'lib/necropsy/graph/call_graph.rb', line 72 def edges_from(node_id) @edges[node_id] || {} end |
#incoming_edges(node_id) ⇒ Object
84 85 86 |
# File 'lib/necropsy/graph/call_graph.rb', line 84 def incoming_edges(node_id) edges.select { |edge| edge.callee_id == node_id } end |
#method_nodes ⇒ Object
94 95 96 |
# File 'lib/necropsy/graph/call_graph.rb', line 94 def method_nodes nodes.values.select(&:method?) end |
#modules_for(owner) ⇒ Object
106 107 108 109 110 111 |
# File 'lib/necropsy/graph/call_graph.rb', line 106 def modules_for(owner) info = class_info(owner) return [] unless info (info.prepends + info.includes + info.extends).uniq end |
#resolve_call_site(site, rta: false) ⇒ Object
117 118 119 120 121 |
# File 'lib/necropsy/graph/call_graph.rb', line 117 def resolve_call_site(site, rta: false) candidates = candidates_for_receiver(site) candidates = candidates.select { |node| rta_candidate?(node, site) } if rta candidates end |
#to_h ⇒ Object
123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/necropsy/graph/call_graph.rb', line 123 def to_h { 'nodes' => nodes.values.map(&:to_h), 'edges' => edges.map(&:to_h), 'entry_points' => entry_points.map(&:to_h), 'class_infos' => class_infos.values.map(&:to_h), 'instantiated_classes' => instantiated_classes.to_a.sort, 'profiles' => profiles.map(&:to_h), 'observation' => observation } end |
#uncertainties(node_id = nil) ⇒ Object
88 89 90 91 92 |
# File 'lib/necropsy/graph/call_graph.rb', line 88 def uncertainties(node_id = nil) return @uncertainties unless node_id @uncertainties[node_id] || [] end |