Module: HeapInfo::Helper

Defined in:
lib/heapinfo/helper.rb

Overview

Some helper functions.

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

Class Method Summary collapse

Class Method Details

.auxv_of(pid) ⇒ String

Fetch the content of /proc/+pid+/auxv.

Parameters:

  • pid (Integer)

    The process id.

Returns:

  • (String)

    The file content.



# File 'lib/heapinfo/helper.rb', line 13

.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.



170
171
172
# File 'lib/heapinfo/helper.rb', line 170

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?) (defaults to: nil)

    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.



112
113
114
115
116
117
118
119
120
121
122
# File 'lib/heapinfo/helper.rb', line 112

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

.color_hex(num) ⇒ String

Combines hex and color.

Parameters:

  • num (Integer)

    An integer.

Returns:

  • (String)

    Returns hex string wrapped with color code.



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

def color_hex(num)
  color(hex(num))
end

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

Safe-eval using dentaku.

Parameters:

  • formula (String)

    Formula to be eval.

  • store (Hash{Symbol => Integer}) (defaults to: {})

    Predefined values.

Returns:

  • (Integer)

    Evaluate result.



194
195
196
197
198
# File 'lib/heapinfo/helper.rb', line 194

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

.exe_of(pid) ⇒ String

Fetch the content of /proc/+pid+/exe.

Parameters:

  • pid (Integer)

    The process id.

Returns:

  • (String)

    The file content.



# File 'lib/heapinfo/helper.rb', line 13

.hex(num) ⇒ String

Convert number in hex format.

Examples:

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

Parameters:

  • num (Integer)

    An integer.

Returns:

  • (String)

    number in hex format.



146
147
148
149
150
# File 'lib/heapinfo/helper.rb', line 146

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.



184
185
186
187
188
# File 'lib/heapinfo/helper.rb', line 184

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

.maps_of(pid) ⇒ String

Fetch the content of /proc/+pid+/maps.

Parameters:

  • pid (Integer)

    The process id.

Returns:

  • (String)

    The file content.



# File 'lib/heapinfo/helper.rb', line 13

.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.



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/heapinfo/helper.rb', line 65

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[3] ||= '' # some segments don't have a name
    s
  end.compact
end

.parsed_maps(pid) ⇒ Array

Combines parse_maps and maps_of.

Parameters:

  • pid (Integer)

Returns:

  • (Array)

    The same return type as parse_maps's.

See Also:



85
86
87
# File 'lib/heapinfo/helper.rb', line 85

def parsed_maps(pid)
  parse_maps(maps_of(pid))
end

.pidof(prog) ⇒ Integer

Get the process id from program name.

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

Parameters:

  • prog (String)

    The request process name.

Returns:

  • (Integer)

    Process id.



42
43
44
45
46
47
48
49
50
# File 'lib/heapinfo/helper.rb', line 42

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.last
end

.tempfile(name) ⇒ String

Get temp filename.

Parameters:

  • name (String)

    Filename.

Returns:

  • (String)

    Temp filename.



203
204
205
# File 'lib/heapinfo/helper.rb', line 203

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) (defaults to: false)

    Enable or not.



92
93
94
# File 'lib/heapinfo/helper.rb', line 92

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.



136
137
138
# File 'lib/heapinfo/helper.rb', line 136

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