def read(addr, num_elements, **options)
      mem_io(:read) { |io| io.read(num_elements, from: MemoryIO::Util.safe_eval(addr, bases), **options) }
    end
def read(addr, num_elements, **options)
      mem_io(:read) { |io| io.read(num_elements, from: MemoryIO::Util.safe_eval(addr, bases), **options) }
    end
Read from process's memory.

 This method has *almost* same arguements and return types as {IO#read}.
 The only difference is this method needs parameter +addr+ (which
 will be passed to paramter +from+ in {IO#read}).

 @param [Integer, String] addr
   The address start to read.
   When String is given, it will be safe-evaluated.
   You can use variables such as +'heap'/'stack'/'libc'+ in this parameter.
   See examples.
 @param [Integer] num_elements
   Number of elements to read. See {IO#read}.

 @return [String, Object, Array<Object>]
   See {IO#read}.

 @example
   process = MemoryIO.attach(`pidof victim`.to_i)
   puts process.read('heap', 4, as: :u64).map { |c| '0x%016x' % c }
   # 0x0000000000000000
   # 0x0000000000000021
   # 0x00000000deadbeef
   # 0x0000000000000000
   #=> nil
   process.read('heap+0x10', 4, as: :u8).map { |c| '0x%x' % c }
   #=> ['0xef', '0xbe', '0xad', '0xde']

   process.read('libc', 4)
   #=> "\x7fELF"
 @see IO#read