class HeapInfo::ProcessInfo
For {Process} to record basic process information.
{Process} has a process_info
object iff the process exists (pid not nil
). Mainly records segments' base.
Constants
- EXPORT
Methods to be transparent to
process
. e.g.process.libc
alias toprocess.info.libc
.
Attributes
@return [Hash{Symbol => Integer}] The parsed auxv hash. @example
auxv #=> {:ld_base => 4152033280, :random => 4294374299}
@return [Integer] 32 or 64.
@return [HeapInfo::Segment]
@return [HeapInfo::Segment]
@return [HeapInfo::Libc]
@return [HeapInfo::Segment]
@return [HeapInfo::Segment]
Public Class Methods
Instantiate a {ProcessInfo} object.
@param [HeapInfo::Process] process Load information from maps/memory for process
.
# File lib/heapinfo/process_info.rb, line 39 def initialize(process) @pid = process.pid options = process.instance_variable_get(:@options) maps = load_maps @bits = bits_of(Helper.exe_of(@pid)) @program = Segment.find(maps, File.readlink("/proc/#{@pid}/exe")) # well.. stack is a strange case because it will grow in runtime.. # should i detect stack base growing..? @stack = Segment.find(maps, '[stack]') @auxv = parse_auxv(Helper.auxv_of(@pid)) ld_seg = maps.find { |m| m[0] == @auxv[:ld_base] } # nil if static-linked elf @ld = ld_seg.nil? ? Nil.new : Segment.new(@auxv[:ld_base], ld_seg.last) @libc = Libc.find( maps, match_maps(maps, options[:libc]), bits: @bits, ld_name: @ld.name, dumper: ->(*args) { process.dump(*args) }, method_heap: method(:heap) ) end
Public Instance Methods
Heap will not be mmapped if the process not use heap yet, so create a lazy loading method. Will re-read maps when heap segment not found yet.
Special handling here because heap might not be initialized in the beginning.
@return [HeapInfo::Segment] The {Segment} of heap.
# File lib/heapinfo/process_info.rb, line 66 def heap @heap ||= Segment.find(load_maps, '[heap]') end
Return segemnts load currently. @return [Hash{Symbol => Segment}] The segments in hash format.
# File lib/heapinfo/process_info.rb, line 72 def segments EXPORT.map do |sym| seg = __send__(sym) [sym, seg] if seg.is_a?(Segment) end.compact.to_h end
Convert symbol to segment.
@return [HeapInfo::Segment?]
The segment object.
# File lib/heapinfo/process_info.rb, line 83 def to_segment(sym) return nil unless EXPORT.include?(sym) seg = __send__(sym) return nil unless seg.is_a?(Segment) seg end
Private Instance Methods
# File lib/heapinfo/process_info.rb, line 112 def bits_of(elf) elf[4] == "\x01" ? 32 : 64 end
# File lib/heapinfo/process_info.rb, line 92 def load_maps Helper.parse_maps(Helper.maps_of(@pid)) end
# File lib/heapinfo/process_info.rb, line 116 def match_maps(maps, pattern) maps.map { |s| s[3] }.find { |seg| pattern.is_a?(Regexp) ? seg =~ pattern : seg.include?(pattern) } end
# File lib/heapinfo/process_info.rb, line 96 def parse_auxv(str) auxv = {} sio = StringIO.new(str) fetch = -> { Helper.unpack(@bits / 8, sio.read(@bits / 8)) } loop do type = fetch.call val = fetch.call case type when 7 then auxv[:ld_base] = val # AT_BASE when 25 then auxv[:random] = val # AT_RANDOM end break if type.zero? end auxv end