mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
82 lines
2.5 KiB
Ruby
Executable File
82 lines
2.5 KiB
Ruby
Executable File
#!/usr/bin/env ruby -wKU
|
||
#
|
||
# http://developer.apple.com/library/mac/#technotes/tn2004/tn2123.html
|
||
require "fileutils"
|
||
require "shellwords"
|
||
|
||
DSYM_ARCHIVE_DIR = "#{ENV['HOME']}/build/TextMate/Applications/TextMate/dsym"
|
||
DSYM_CACHE_DIR = "#{ENV['HOME']}/Library/Caches/com.macromates.TextMate/dsym"
|
||
|
||
BinaryImage = Struct.new(:first, :last, :name, :file)
|
||
|
||
def find_dsym(process, version)
|
||
path = File.expand_path("#{process}_#{version}", DSYM_CACHE_DIR)
|
||
return path if File.directory?(path)
|
||
|
||
archive = File.expand_path("#{process}_#{version}.tbz", DSYM_ARCHIVE_DIR)
|
||
return nil unless File.file?(archive)
|
||
|
||
FileUtils.mkdir_p(path)
|
||
STDERR << "Extracting dsym to ‘#{path}’…\n"
|
||
%x{ tar -jxf #{archive.shellescape} -C #{path.shellescape} }
|
||
|
||
path
|
||
end
|
||
|
||
class BinaryImages
|
||
def initialize(files, report)
|
||
uuid_to_file = { }
|
||
files.each do |file|
|
||
res = %x{dwarfdump -u "#{file}"}
|
||
file = file.sub(%r{([^/]+?)(\.(app|framework))?\.dSYM$}, "\\0/Contents/Resources/DWARF/\\1") if File.directory? file
|
||
uuid_to_file[$1.gsub(/-/, '')] = file if res =~ /UUID: ([0-9A-F\-]*)/
|
||
end
|
||
|
||
@images = [ ]
|
||
|
||
if report =~ /^Binary Images:\n((?:\s*0x[[:xdigit:]]+ - \s*0x[[:xdigit:]]+.*\n)+)/i
|
||
$1.scan(/(0x[[:xdigit:]]+) - \s*(0x[[:xdigit:]]+)\s+\+?(\S+).*?<([0-9a-fA-F\-]+)>/).each do |arr|
|
||
first, last, name, uuid = *arr
|
||
uuid = uuid.gsub(/-/, '').upcase
|
||
@images << BinaryImage.new(first.to_i(16), last.to_i(16), name, uuid_to_file[uuid]) if uuid_to_file.member? uuid
|
||
end
|
||
end
|
||
end
|
||
|
||
def lookup(addr)
|
||
@images.each do |image|
|
||
next unless image.first <= addr && addr < image.last
|
||
res = %x{xcrun atos 2>/dev/null -o #{image.file} -l 0x#{image.first.to_s(16)} 0x#{addr.to_s(16)}}.chomp
|
||
res.gsub!(/ \(in #{File.basename image.file}\)/, '')
|
||
return res
|
||
end
|
||
nil
|
||
end
|
||
end
|
||
|
||
report = STDIN.read
|
||
|
||
process = $1 if report =~ /^Process:\s+(\w+)\s+\[\d+\]$/
|
||
version = $1 if report =~ /^Version:\s+(\S+) \(.*\)$/
|
||
|
||
dsym_dir = find_dsym(process, version)
|
||
abort "No dsym information for #{process} #{version}." if dsym_dir.nil?
|
||
|
||
images = BinaryImages.new(Dir["#{dsym_dir}/*"], report)
|
||
|
||
symbolicated = report.gsub(/^(Thread \d+(?: Crashed)?:.*)\n(?m:(.*?))\n\n/) do
|
||
threadName, stackDump = $1, $2
|
||
|
||
stackDump = stackDump.gsub(/^(.*?\s)(0x[[:xdigit:]]+)\s(.*)$/) do
|
||
left, addr, right = $1, $2, $3
|
||
if info = images.lookup(addr.to_i(16))
|
||
right = info
|
||
end
|
||
"#{left}#{addr} #{right}"
|
||
end
|
||
|
||
"#{threadName}\n#{stackDump}\n\n"
|
||
end
|
||
|
||
puts symbolicated
|