Class: CompiledLocation::Resolver

Inherits:
Object
  • Object
show all
Defined in:
lib/c_location/resolver.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(shared_library, offset) ⇒ Resolver

Returns a new instance of Resolver.



5
6
7
8
# File 'lib/c_location/resolver.rb', line 5

def initialize(shared_library, offset)
  self.shared_library, self.offset = [shared_library, offset]
  self.shared_library = `which ruby` if self.shared_library == 'ruby'
end

Instance Attribute Details

#offsetObject

Returns the value of attribute offset.



3
4
5
# File 'lib/c_location/resolver.rb', line 3

def offset
  @offset
end

#shared_libraryObject

Returns the value of attribute shared_library.



3
4
5
# File 'lib/c_location/resolver.rb', line 3

def shared_library
  @shared_library
end

Instance Method Details

#absolutify(file, line, shared_library) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/c_location/resolver.rb', line 83

def absolutify(file, line, shared_library)
  if shared_library =~ %r{(.*/(gems|src)/[^/]*)/}
    potentials = Dir["#{$1}/**/#{file}"]
  elsif shared_library =~ %r{(.*/(rubies)/[^/]*)/}
    potentials = Dir["#{$1.sub('/rubies/', '/src/')}/**/#{file}"]
  else
    potentials = Dir["./**/#{file}"]
  end

  if potentials.empty?
    raise "Could not find the `#{file}:#{line}` that was used to build `#{shared_library}`." +
          "If you know where this file is please submit a pull request"
  else
    [potentials.first, line]
  end
end

#nm(shared_library, offset) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/c_location/resolver.rb', line 32

def nm(shared_library, offset)
  command = "#{Shellwords.escape which_nm} -pa #{Shellwords.escape shared_library}"
  output = run(command)

  o_file = nil

  output.lines.each do |line|
    case line
    when /OSO (.*\.o\)?)/
      o_file = $1.sub(%r{(.*)/([^/]*)\((.*)\)}, '\1/\3')
    when /^[01]*#{offset.to_s(16)}.*FUN (.+)/
      raise "Your version of nm seems to not output OSO lines." unless o_file
      return objdump_tt(o_file, $1)
    end
  end

  raise "Could not find #{shared_library}@0x#{offset.to_s(16)} using #{command.inspect}." +
        "This may be because your ruby/extensions are not compiled with -g."
end

#objdump(shared_library, offset) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/c_location/resolver.rb', line 18

def objdump(shared_library, offset)
  command = "#{Shellwords.escape which_objdump} --dwarf=decodedline #{Shellwords.escape shared_library}"
  output = run(command)

  if m = output.lines.detect{ |line| line =~ /\s+0x#{offset.to_s(16)}$/ }
    file, line, address = m.split(/\s+/)

    absolutify(file, line.to_i(10), shared_library)
  else
    raise "Could not find #{shared_library}@0x#{offset.to_s(16)} using #{command.inspect}." +
          "This may be because your ruby/extensions are not compiled with -g."
  end
end

#objdump_tt(shared_library, name) ⇒ Object



52
53
54
55
56
57
58
59
60
# File 'lib/c_location/resolver.rb', line 52

def objdump_tt(shared_library, name)
  output = run("#{Shellwords.escape which_objdump} -tT #{Shellwords.escape shared_library}")

  if output.lines.detect{ |line| line =~ /^([0-9a-f]+).*\.text\s#{Regexp.escape name}$/ }
    objdump(shared_library, $1.to_i(16))
  else
    raise "Could not find #{shared_library}##{name} using #{command.inspect}."
  end
end

#run(command) ⇒ Object



100
101
102
103
104
# File 'lib/c_location/resolver.rb', line 100

def run(command)
  `#{command}`.tap do |output|
    raise "Failed to run #{command.inspect}: #{output}" unless $?.success?
  end
end

#source_locationObject



10
11
12
13
14
15
16
# File 'lib/c_location/resolver.rb', line 10

def source_location
  if RUBY_PLATFORM =~ /darwin/
    nm(shared_library, offset)
  else
    objdump(shared_library, offset)
  end
end

#which_nmObject



74
75
76
77
78
79
80
81
# File 'lib/c_location/resolver.rb', line 74

def which_nm
  nm = `which nm`.chomp
  return nm if $?.success?

  raise "You need to have `nm` installed to use c_location. " +
        "Try installing Xcode from the App Store. (GNU nm from binutils doesn't work unfortunately)"

end

#which_objdumpObject



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/c_location/resolver.rb', line 62

def which_objdump
  objdump = `which gobjdump`.chomp
  return objdump if $?.success?
  objdump = `which objdump`.chomp
  return objdump if $?.success?
  objdump = `which /usr/local/bin/gobjdump`.chomp
  return objdump if $?.success?

  raise "You need to have `objdump` installed to use c_location. " +
        "Try installing the binutils package (apt-get install binutils; brew install binutils)."
end