Created
April 3, 2013 05:50
-
-
Save bradtheappguy/5298747 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# | |
# == Synopsis | |
# | |
# ocalc: computes file offset for a given vma address | |
# | |
# == Usage | |
# | |
# ocalc [OPTION] FILENAME ADDRESS | |
# | |
# -h, --help: | |
# show help | |
# | |
# -a [arch], --arch [arch] | |
# calculate for the specified architecture instead of the current (e.g., i386, x86_64, ppc7400) | |
# | |
# FILENAME: the mach-o binary executable to perform calcuations on | |
# ADDRESS: the address to convert to an offset | |
# | |
# == Example | |
# | |
# ocalc --arch i386 /bin/ls 0x33fb | |
require 'getoptlong' | |
require 'pp' | |
require 'rdoc/usage' | |
FatInfo = Struct.new(:offset, :size) | |
def fat_info(target_file) | |
text = `lipo -detailed_info #{target_file}` | |
Hash[*text.scan(/ | |
architecture\s(\w+) | |
.*? | |
offset\s(\d+) | |
.*? | |
size\s(\d+) | |
/mx).collect { |a| [a[0], FatInfo.new(Integer(a[1]), Integer(a[2]))] }.flatten] | |
end | |
SegmentInfo = Struct.new(:sectname, :segname, :addr, :size, :offset) | |
def segment_info(target_file, arch=nil) | |
arch_info = `otool #{arch ? "-arch #{arch} " : ""}-l #{target_file}` | |
arch_info.scan(/ | |
Section | |
.*? | |
sectname\s(\w+) | |
.*? | |
segname\s(\w+) | |
.*? | |
addr\s(0x[0-9a-f]+) | |
.*? | |
size\s(0x[0-9a-f]+) | |
.*? | |
offset\s(\d+) | |
/mx).collect { |a| SegmentInfo.new(a[0], a[1], Integer(a[2]), Integer(a[3]), Integer(a[4])) }.sort { |a, b| a.addr <=> b.addr } | |
end | |
if __FILE__ == $0 | |
opts = GetoptLong.new( | |
[ '--help', '-h', GetoptLong::NO_ARGUMENT ], | |
[ '--verbose', '-v', GetoptLong::NO_ARGUMENT ], | |
[ '--arch', '-a', GetoptLong::OPTIONAL_ARGUMENT ] | |
) | |
opts.each do |opt, arg| | |
case opt | |
when '--help' | |
RDoc::usage | |
when '--verbose' | |
@verbose = true | |
when '--arch' | |
@arch = arg | |
end | |
end | |
if ARGV.length != 2 | |
puts "missing filename and/or offset argument (try --help)" | |
exit 1 | |
end | |
@filename = ARGV.shift | |
@address = Integer(ARGV.shift) | |
fi = fat_info(@filename) | |
pp fi if @verbose | |
fat_offset = if fi.empty? | |
0 | |
else | |
@arch ||= `arch`.chomp | |
raise "unknown architecture: #{@arch}" unless fi.key?(@arch) | |
fi[@arch].offset | |
end | |
si = segment_info(@filename, @arch) | |
pp si if @verbose | |
segment = si.detect { |s| s.addr <= @address && @address < s.addr + s.size } | |
pp segment if @verbose | |
if segment | |
offset = @address - segment.addr + segment.offset + fat_offset | |
puts "0x%x" % [offset] | |
else | |
raise "could not find matching segment for 0x%x" % [@address] | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment