Skip to content

Instantly share code, notes, and snippets.

@bradtheappguy
Created April 3, 2013 05:50
Show Gist options
  • Save bradtheappguy/5298747 to your computer and use it in GitHub Desktop.
Save bradtheappguy/5298747 to your computer and use it in GitHub Desktop.
#!/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