Skip to content

Instantly share code, notes, and snippets.

@kbinani
Created October 17, 2013 02:22
Show Gist options
  • Save kbinani/7018332 to your computer and use it in GitHub Desktop.
Save kbinani/7018332 to your computer and use it in GitHub Desktop.
Get actual symbol names from a stack trace generated by`strip(1)`ped binary.
#!/usr/bin/env ruby
require 'optparse'
def create_symbol_list(binary_path, arch)
temp = `mktemp -t tmp`
`nm -arch #{arch} "#{binary_path}" 2>/dev/null \
| awk '$3 != "" { print $0 }' \
| sort \
> "#{temp}"`
result = []
open(temp) { |file|
file.each.map { |line|
address, type, func = line.split(" ", 3)
[address.hex, func.chomp]
}.each { |params|
result << params
}
}
return result
end
def find_function(symbol_list, offset)
last_params = nil
symbol_list.each { |params|
address, func = params
break if offset <= address
last_params = params
}
last_params
end
opts = {
:binary => nil,
:arch => "x86_64",
}
OptionParser.new { |parser|
parser.instance_eval {
self.banner = <<-EOS.gsub(/^\t+/, "")
Usage: #{$0} [opts] < [input stack trace]
EOS
separator "Options:"
on("-i", "--input [BINARY_PATH]", "unstripped binary path") { |input|
opts[:binary] = input
}
on("-arch [ARCH=#{opts[:arch]}]", "target architecture") { |arch|
opts[:arch] = arch
}
parse!(ARGV)
if opts[:binary].nil? then
raise OptionParser::MissingArgument, "no '--input' option specified"
end
}
}
target_path = opts[:binary]
arch = opts[:arch]
target_dylib = File.basename(target_path)
symbols = create_symbol_list(target_path, arch)
STDIN.read.split("\n").each { |line|
trace_number, dylib, address, base, plus, offset = line.split(" ")
if dylib == target_dylib then
offset = offset.to_i
address, func = find_function(symbols, offset)
puts line + " => " + `echo #{func} | c++filt`.chomp + " + 0x" + (offset - address).to_s(16)
else
puts line
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment