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