module MemDump
Public Class Methods
cleanup_references(dump)
click to toggle source
# File lib/memdump/cleanup_references.rb, line 2 def self.cleanup_references(dump) addresses = Set.new records = Array.new dump.each_record do |r| addr = (r['address'] || r['root']) addresses << addr records << r end records.each do |r| if references = r['references'] references.delete_if { |r| !addresses.include?(r) } end end records end
common_ancestors(dump, class_name, threshold: 0.1)
click to toggle source
# File lib/memdump/common_ancestor.rb, line 2 def self.common_ancestors(dump, class_name, threshold: 0.1) selected_records = Hash.new remaining_records = Array.new dump.each_record do |r| if class_name === r['class'] selected_records[r['address']] = r else remaining_records << r end end remaining_records = Array.new selected_records = Hash.new selected_root = root_address dump.each_record do |r| address = (r['address'] || r['root']) if selected_root == address selected_records[address] = r selected_root = nil; else remaining_records << r end end count = 0 while count != selected_records.size count = selected_records.size remaining_records.delete_if do |r| references = r['references'] if references && references.any? { |a| selected_records.has_key?(a) } address = (r['address'] || r['root']) selected_records[address] = r end end end selected_records.values.reverse.each do |r| if refs = r['references'] refs.delete_if { |a| !selected_records.has_key?(a) } end end end
convert_to_gml(dump, io)
click to toggle source
# File lib/memdump/convert_to_gml.rb, line 2 def self.convert_to_gml(dump, io) io.puts "graph" io.puts "[" edges = [] dump.each_record do |row| address = row['address'] io.puts " node" io.puts " [" io.puts " id #{address}" row.each do |key, value| if value.respond_to?(:to_str) io.puts " #{key} \"#{value}\"" elsif value.kind_of?(Numeric) io.puts " #{key} #{value}" end end io.puts " ]" row['references'].each do |ref_address| edges << address << ref_address end end edges.each_slice(2) do |address, ref_address| io.puts " edge" io.puts " [" io.puts " source #{address}" io.puts " target #{ref_address}" io.puts " ]" end io.puts "]" end
out_degree(dump)
click to toggle source
# File lib/memdump/out_degree.rb, line 2 def self.out_degree(dump) records = dump.each_record.sort_by { |r| (r['references'] || Array.new).size } end
pry(dump)
click to toggle source
# File lib/memdump.rb, line 19 def self.pry(dump) binding.pry end
remove_node(dump, removed_node)
click to toggle source
# File lib/memdump/remove_node.rb, line 2 def self.remove_node(dump, removed_node) remaining_records = Hash.new non_roots = Set.new dump.each_record do |r| address = (r['address'] || r['root']) remaining_records[address] = r if refs = r['references'] refs.each do |ref_address| non_roots << ref_address end end end roots = remaining_records.each_key. find_all { |a| !non_roots.include?(a) } queue = roots.dup selected_records = Hash.new while !queue.empty? address = queue.shift next if address == removed_node if record = remaining_records.delete(address) selected_records[address] = record if refs = record['references'] refs.each do |ref_address| queue << ref_address end end end end selected_records.values.reverse.map do |r| if refs = r['references'] refs.delete_if { |a| !selected_records.has_key?(a) } end r end end
replace_class_address_by_name(dump, add_reference_to_class: false)
click to toggle source
Replace the address in the 'class' attribute by the class name
# File lib/memdump/replace_class_address_by_name.rb, line 3 def self.replace_class_address_by_name(dump, add_reference_to_class: false) class_names = Hash.new iclasses = Hash.new dump.each_record do |row| if row['type'] == 'CLASS' || row['type'] == 'MODULE' class_names[row['address']] = row['name'] elsif row['type'] == 'ICLASS' || row['type'] == "IMEMO" iclasses[row['address']] = row end end iclass_size = 0 while !iclasses.empty? && (iclass_size != iclasses.size) iclass_size = iclasses.size iclasses.delete_if do |_, r| if (klass = r['class']) && (class_name = class_names[klass]) class_names[r['address']] = "I(#{class_name})" r['class'] = class_name r['class_address'] = klass if add_reference_to_class (r['references'] ||= Set.new) << klass end true end end end dump.map do |r| if klass = r['class'] r = r.dup r['class'] = class_names[klass] || klass r['class_address'] = klass if add_reference_to_class (r['references'] ||= Set.new) << klass end end r end end
root_of(dump, root_address)
click to toggle source
# File lib/memdump/root_of.rb, line 2 def self.root_of(dump, root_address) remaining_records = Array.new selected_records = Hash.new selected_root = root_address dump.each_record do |r| address = (r['address'] || r['root']) if selected_root == address selected_records[address] = r selected_root = nil; else remaining_records << r end end count = 0 while count != selected_records.size count = selected_records.size remaining_records.delete_if do |r| references = r['references'] if references && references.any? { |a| selected_records.has_key?(a) } address = (r['address'] || r['root']) selected_records[address] = r end end end selected_records.values.reverse.each do |r| if refs = r['references'] refs.delete_if { |a| !selected_records.has_key?(a) } end end end
subgraph_of(dump, root_address, max_depth: Float::INFINITY)
click to toggle source
# File lib/memdump/subgraph_of.rb, line 2 def self.subgraph_of(dump, root_address, max_depth: Float::INFINITY) remaining_records = Hash.new dump.each_record do |r| address = (r['address'] || r['root']) remaining_records[address] = r end selected_records = Hash.new queue = [[root_address, 0]] while !queue.empty? address, depth = queue.shift if record = remaining_records.delete(address) selected_records[address] = record if (depth < max_depth) && (refs = record['references']) refs.each do |ref_address| queue << [ref_address, depth + 1] end end end end selected_records.values end