class HeapInfo::Chunk
The object of a heap chunk
Attributes
@return [Integer] Base address of this chunk
@return [String] chunk data
@return [Integer] previous chunk size
@return [Integer] 4 or 8 according to 32bit or 64bit, respectively.
Public Class Methods
Instantiate a {HeapInfo::Chunk} object
@param [Integer] size_t
4 or 8 @param [Integer] base Start address of this chunk @param [Proc] dumper For dump more information of this chunk @param [Boolean] head
For specific if is fake chunk in +arena+. If +head+ is +true+, will not load +size+ and +prev_size+ (since it's meaningless)
@example
HeapInfo::Chunk.new 8, 0x602000, ->(addr, len) { [0,0x21, 0xda4a].pack('Q*')[addr-0x602000, len] } # create a chunk with chunk size 0x21
# File lib/heapinfo/chunk.rb, line 26 def initialize(size_t, base, dumper, head: false) raise ArgumentError, 'size_t can be either 4 or 8' unless [4, 8].include?(size_t) self.class.__send__(:define_method, :dump) { |*args| dumper.call(*args) } @size_t = size_t @base = base sz = dump(@base, size_t * 2) if head # no need to read size if is bin @data = dump(@base + size_t * 2, size_t * 4) return end @prev_size = Helper.unpack(size_t, sz[0, size_t]) @size = Helper.unpack(size_t, sz[size_t..-1]) r_size = [size - size_t * 2, size_t * 4].min # don't read too much data r_size = [r_size, 0].max # prevent negative size @data = dump(@base + size_t * 2, r_size) end
Public Instance Methods
Bin type of this chunk @return [Symbol] Bin type is simply determined according to #size
@example
[c.size, c.size_t] #=> [80, 8] c.bintype #=> :fast
@example
[c.size, c.size_t] #=> [80, 4] c.bintype #=> :small
@example
c.size #=> 135168 c.bintype #=> :mmap
# File lib/heapinfo/chunk.rb, line 113 def bintype sz = size return :unknown if sz < @size_t * 4 return :fast if sz <= @size_t * 16 return :small if sz <= @size_t * 0x7e return :large if sz <= @size_t * 0x3ffe # is this correct? :mmap end
The chunk flags record in low three bits of size @return [Array<Symbol>] flags of chunk @example
c = [0, 0x25].pack("Q*").to_chunk c.flags # [:non_main_arena, :prev_inuse]
# File lib/heapinfo/chunk.rb, line 60 def flags mask = @size - size flag = [] flag << :non_main_arena unless (mask & 4).zero? flag << :mmapped unless (mask & 2).zero? flag << :prev_inuse unless (mask & 1).zero? flag end
Ask if chunk is mmapped.
@return [Boolean] +true|false+ if chunk is mmapped
# File lib/heapinfo/chunk.rb, line 79 def mmapped? flags.include? :mmapped end
Ask if chunk not belongs to main arena.
@return [Boolean] +true|false+ if chunk not belongs to main arena
# File lib/heapinfo/chunk.rb, line 72 def non_main_arena? flags.include? :non_main_arena end
Ask if chunk has set the prev-inuse bit.
@return [Boolean] +true|false+ if the prev_inuse
bit has been set
# File lib/heapinfo/chunk.rb, line 86 def prev_inuse? flags.include? :prev_inuse end
Size of chunk @return [Integer] The chunk size without flag masks
# File lib/heapinfo/chunk.rb, line 92 def size @size & -8 end
Hook #to_s
for pretty printing @return [String]
# File lib/heapinfo/chunk.rb, line 45 def to_s ret = Helper.color(format("#<%s:%#x>\n", self.class.to_s, @base), sev: :klass) ret += "flags = [#{flags.map { |f| Helper.color(":#{f}", sev: :sym) }.join(',')}]\n" ret += "size = #{Helper.color(format('%#x', size))} (#{bintype})\n" ret += "prev_size = #{Helper.color(format('%#x', @prev_size))}\n" unless flags.include? :prev_inuse ret += "data = #{Helper.color(@data.inspect)}#{'...' if @data.length < size - size_t * 2}\n" ret end