Module: MemoryIO::Util

Defined in:
lib/memory_io/util.rb

Overview

Defines utility methods.

Class Method Summary collapse

Class Method Details

.file_permission(file) ⇒ #readable?, ...

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Struct with two boolean method. nil for file not exists or is inaccessible.

Parameters:

  • file (String)

    File name.

Returns:

  • (#readable?, #writable?, nil)

    Struct with two boolean method. nil for file not exists or is inaccessible.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/memory_io/util.rb', line 45

def file_permission(file)
  return nil unless File.file?(file)

  stat = File.stat(file)
  # we do a trick here because /proc/[pid]/mem might be marked as readable but fails at sysopen.
  os = OpenStruct.new(readable?: stat.readable_real?, writable?: stat.writable_real?)
  begin
    os.readable? && File.open(file, 'rb').close
  rescue Errno::EACCES
    os[:readable?] = false
  end
  begin
    os.writable? && File.open(file, 'wb').close
  rescue Errno::EACCES
    os[:writable?] = false
  end
  os
end

.pack(val, b) ⇒ String

Pack an integer into b bytes. Little endian is used.

Examples:

Util.pack(0x123, 4)
#=> "\x23\x01\x00\x00"

Parameters:

  • val (Integer)

    The integer to pack. If val contains more than b bytes, only lower b bytes in val will be packed.

  • b (Integer)

Returns:

  • (String)

    Packing result with length b.



119
120
121
# File 'lib/memory_io/util.rb', line 119

def pack(val, b)
  Array.new(b) { |i| (val >> (i * 8)) & 0xff }.pack('C*')
end

.safe_eval(str, **vars) ⇒ Integer

Evaluate string safely.

Examples:

Util.safe_eval('heap + 0x10 * pp', heap: 0xde00, pp: 8)
#=> 56960 # 0xde80

Parameters:

  • str (String)

    String to be evaluated.

  • vars ({Symbol => Integer})

    Predefined variables

Returns:

  • (Integer)

    Result.



77
78
79
80
81
82
83
# File 'lib/memory_io/util.rb', line 77

def safe_eval(str, **vars)
  return str if str.is_a?(Integer)

  # dentaku 2 doesn't support hex
  str = str.gsub(/0x[0-9a-zA-Z]+/) { |c| c.to_i(16) }
  Dentaku::Calculator.new.store(vars).evaluate(str)
end

.trim_libname(name) ⇒ String

Remove extension name (.so) and version in library name.

Examples:

Util.trim_libname('libc-2.24.so')
#=> 'libc'
Util.trim_libname('libcrypto.so.1.0.0')
#=> 'libcrypto'
Util.trim_libname('not_a_so')
#=> 'not_a_so'

Parameters:

  • name (String)

    Original library filename.

Returns:

  • (String)

    Name without version and ‘.so’.



138
139
140
141
142
# File 'lib/memory_io/util.rb', line 138

def trim_libname(name)
  type1 = '(-[\d.]+)?\.so$'
  type2 = '\.so.\d+[\d.]+$'
  name.sub(/#{type1}|#{type2}/, '')
end

.underscore(str) ⇒ String

Convert input into snake-case.

This method also converts ‘::’ to ‘/’.

Examples:

Util.underscore('MemoryIO')
#=> 'memory_io'

Util.underscore('MyModule::MyClass')
#=> 'my_module/my_class'

Parameters:

  • str (String)

    String to be converted.

Returns:

  • (String)

    Converted string.



27
28
29
30
31
32
33
34
35
# File 'lib/memory_io/util.rb', line 27

def underscore(str)
  return '' if str.empty?

  str = str.gsub('::', '/')
  str.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
  str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
  str.downcase!
  str
end

.unpack(str) ⇒ Integer

Unpack a string into an integer. Little endian is used.

Examples:

Util.unpack("\xff")
#=> 255
Util.unpack("@\xE2\x01\x00")
#=> 123456

Parameters:

  • str (String)

    String.

Returns:

  • (Integer)

    Result.



99
100
101
# File 'lib/memory_io/util.rb', line 99

def unpack(str)
  str.bytes.reverse.reduce(0) { |s, c| s * 256 + c }
end