Module: HeapInfo::Helper::ClassMethods

Included in:
HeapInfo::Helper
Defined in:
lib/heapinfo/helper.rb

Overview

Define class methods here.

Constant Summary collapse

COLOR_CODE =

Color codes for pretty print.

{
  esc_m: "\e[0m",
  normal_s: "\e[38;5;209m", # red
  integer: "\e[38;5;153m", # light blue
  fatal: "\e[38;5;197m", # dark red
  bin: "\e[38;5;120m", # light green
  klass: "\e[38;5;155m",
  sym: "\e[38;5;230m"
}.freeze

Instance Method Summary collapse

Instance Method Details

#class_name(obj) ⇒ String

Retrieve pure class name(without module) of an object.

Examples:

# suppose obj is an instance of HeapInfo::Chunk
Helper.class_name(obj)
#=> 'Chunk'

Parameters:

  • obj (Object)

    Any instance.

Returns:

  • (String)

    Class name of obj.


127
128
129
# File 'lib/heapinfo/helper.rb', line 127

def class_name(obj)
  obj.class.name.split('::').last || obj.class.name
end

#color(s, sev: nil) ⇒ String

Wrapper color codes for pretty inspect.

Parameters:

  • s (String)

    Contents for wrapper.

  • sev (Symbol?)

    Specific which kind of color want to use, valid symbols are defined in #COLOR_CODE. If this argument is not present, will detect according to the content of s.

Returns:

  • (String)

    wrapper with color codes.


82
83
84
85
86
87
88
89
90
91
# File 'lib/heapinfo/helper.rb', line 82

def color(s, sev: nil)
  s = s.to_s
  return s if @disable_color
  cc = COLOR_CODE
  color = if cc.key?(sev) then cc[sev]
          elsif integer?(s) then cc[:integer] # integers
          else cc[:normal_s] # normal string
          end
  "#{color}#{s.sub(cc[:esc_m], color)}#{cc[:esc_m]}"
end

#evaluate(formula, store: {}) ⇒ Integer

Safe-eval using dentaku.

Parameters:

  • formula (String)

    Formula to be eval.

  • store (Hash{Symbol => Integer})

    Predefined values.

Returns:

  • (Integer)

    Evaluate result.


151
152
153
154
155
# File 'lib/heapinfo/helper.rb', line 151

def evaluate(formula, store: {})
  calc = Dentaku::Calculator.new
  formula = formula.delete(':')
  calc.store(store).evaluate(formula)
end

#hex(num) ⇒ String

Convert number in hex format.

Examples:

HeapInfo::Helper.hex(1000) #=> '0x3e8'

Parameters:

  • num (Integer)

    Non-negative integer.

Returns:

  • (String)

    number in hex format.


115
116
117
118
# File 'lib/heapinfo/helper.rb', line 115

def hex(num)
  return format('0x%x', num) if num >= 0
  format('-0x%x', -num)
end

#integer?(str) ⇒ Boolean

For checking a string is actually an integer.

Examples:

Helper.integer? '1234'
#=> true
Helper.integer? '0x1234'
#=> true
Helper.integer? '0xheapoverflow'
#=> false

Parameters:

  • str (String)

    String to be checked.

Returns:

  • (Boolean)

    If str can be converted into integer.


141
142
143
144
145
# File 'lib/heapinfo/helper.rb', line 141

def integer?(str)
  true if Integer(str)
rescue ArgumentError, TypeError
  false
end

#parse_maps(content) ⇒ Array

Parse the contents of /proc/[pid]/maps.

Examples:

HeapInfo::Helper.parse_maps(<<EOS
  00400000-0040b000 r-xp 00000000 ca:01 271708                             /bin/cat
  00bc4000-00be5000 rw-p 00000000 00:00 0                                  [heap]
  7f2788315000-7f2788316000 r--p 00022000 ca:01 402319                     /lib/x86_64-linux-gnu/ld-2.19.so
  EOS
)
# [[0x400000, 0x40b000, 'r-xp', '/bin/cat'],
# [0xbc4000, 0xbe5000, 'rw-p', '[heap]'],
# [0x7f2788315000, 0x7f2788316000, 'r--p', '/lib/x86_64-linux-gnu/ld-2.19.so']]

Parameters:

  • content (String)

    The file content of /proc/[pid]/maps.

Returns:

  • (Array)

    In form of [[start, end, permission, name], ...]. See examples.


49
50
51
52
53
54
55
56
57
# File 'lib/heapinfo/helper.rb', line 49

def parse_maps(content)
  lines = content.split("\n")
  lines.map do |line|
    s = line.scan(%r{^([0-9a-f]+)-([0-9a-f]+)\s([rwxp-]{4})[^/|\[]*([/|\[].+)$})[0]
    next nil if s.nil?
    s[0], s[1] = s[0, 2].map { |h| h.to_i(16) }
    s
  end.compact
end

#pidof(prog) ⇒ Integer

Get the process id from program name.

When multiple processes exist, the one with lastest start time would be returned.

Parameters:

  • prog (String)

    The request process name.

Returns:

  • (Integer)

    Process id.


26
27
28
29
30
31
32
33
# File 'lib/heapinfo/helper.rb', line 26

def pidof(prog)
  info = %x(ps -o pid=,lstart= --pid `pidof #{Shellwords.escape(prog)}` 2>/dev/null).lines.map do |l|
    pid, time = l.split(' ', 2)
    [Time.parse(time), pid.to_i]
  end
  return nil if info.empty? # process not exists yet
  info.max_by(&:first).last
end

#tempfile(name) ⇒ String

Get temp filename.

Parameters:

  • name (String)

    Filename.

Returns:

  • (String)

    Temp filename.


160
161
162
# File 'lib/heapinfo/helper.rb', line 160

def tempfile(name)
  Dir::Tmpname.create(name, HeapInfo::TMP_DIR) {}
end

#toggle_color(on: false) ⇒ void

This method returns an undefined value.

enable / disable the color function.

Parameters:

  • on (Boolean)

    Enable or not.


62
63
64
# File 'lib/heapinfo/helper.rb', line 62

def toggle_color(on: false)
  @disable_color = !on
end

#unpack(size_t, data) ⇒ Integer

Unpack strings to integer.

Like the p32 and p64 in pwntools.

Examples:

HeapInfo::Helper.unpack(4, "\x12\x34\x56\x78")
# 0x78563412
HeapInfo::Helper.unpack(8, "\x12\x34\x56\x78\xfe\xeb\x90\x90")
# 0x9090ebfe78563412

Parameters:

  • size_t (Integer)

    Either 4 or 8.

  • data (String)

    String to be unpack.

Returns:

  • (Integer)

    Unpacked result.


105
106
107
# File 'lib/heapinfo/helper.rb', line 105

def unpack(size_t, data)
  data.unpack(size_t == 4 ? 'L*' : 'Q*')[0]
end