symsym 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +15 -0
- data/LICENSE.txt +20 -0
- data/README.md +42 -0
- data/README.rdoc +25 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/bin/symsym +63 -0
- data/lib/symsym.rb +150 -0
- metadata +93 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "jeweler", "~> 1.6.0"
|
10
|
+
end
|
data/Gemfile.lock
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ulrich Zurucker
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# symsym Crashreport Desymbolizer for Mac OS X
|
2
|
+
|
3
|
+
symsym is a tool for Mac OS X that allows to de-symbolize crashlogs.
|
4
|
+
|
5
|
+
### Install
|
6
|
+
|
7
|
+
sudo gem install symsym
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
symsym will look for a dSYM bundle that matches the bundle identifier, version and short version string found in the crashreport. It will run gdb to desymbolize the addresses in the given crashlog.
|
12
|
+
The crashlog can be read from a file or from the Mac OS X pasteboard.
|
13
|
+
Output can be to a file, the OS X pasteboard or stdout
|
14
|
+
|
15
|
+
Use symsym from the command line:
|
16
|
+
|
17
|
+
* -i read crashreport from given file
|
18
|
+
* -o write de-symbolized crashreport to given file
|
19
|
+
* -p read crashreport from pasteboard
|
20
|
+
* -c write de-symbolized crashreport to pasteboard
|
21
|
+
* -d The path where symsym will look for a matching .dSYM bundle - and of course in all subfolders of this path
|
22
|
+
|
23
|
+
So when you want to replace the crashreport in your pasteboard with the de-symbolized version, go to a directory that contains your dSYM bundles, type
|
24
|
+
|
25
|
+
symsym -p -c
|
26
|
+
|
27
|
+
and you are done!
|
28
|
+
|
29
|
+
_Note:_ gdb needs the application bundle next to the dSYM bundle to be able to desymbolize the crashlog.
|
30
|
+
|
31
|
+
## Issues/TODO
|
32
|
+
|
33
|
+
* Read the architecture from the crashreport
|
34
|
+
|
35
|
+
## Contribute
|
36
|
+
|
37
|
+
* fork me on Github - [https://github.com/sononum/symsym](https://github.com/sononum/symsym)
|
38
|
+
* send a pull request
|
39
|
+
|
40
|
+
## Copyright
|
41
|
+
|
42
|
+
Copyright (c) 2011 Ulrich Zurucker. See LICENSE.txt for further details.
|
data/README.rdoc
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
= symsym
|
2
|
+
|
3
|
+
symsym is a tool for Mac OS X that allows to de-symbolize crashlogs.
|
4
|
+
|
5
|
+
=== Usage
|
6
|
+
symsym will look for a dSYM bundle that matches the bundle identifier, version and short version string found in the crashreport. It will run gdb to desymbolize the addresses in the given crashlog.
|
7
|
+
The crashlog can be read from a file or from the Mac OS X pasteboard.
|
8
|
+
Output can be to a file, the OS X pasteboard or stdout
|
9
|
+
|
10
|
+
Use symsym from the command line:
|
11
|
+
-i read crashreport from given file
|
12
|
+
-o write de-symbolized crashreport to given file
|
13
|
+
-p read crashreport from pasteboard
|
14
|
+
-c write de-symbolized crashreport to pasteboard
|
15
|
+
-d The path where symsym will look for a matching .dSYM bundle - and of course in all subfolders of this path
|
16
|
+
|
17
|
+
== Issues/TODO
|
18
|
+
|
19
|
+
* Read the architecture from the crashreport
|
20
|
+
|
21
|
+
== Copyright
|
22
|
+
|
23
|
+
Copyright (c) 2011 Ulrich Zurucker. See LICENSE.txt for
|
24
|
+
further details.
|
25
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "symsym"
|
18
|
+
gem.homepage = "http://github.com/sononum/symsym"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Crashlog symbolizer for Mac OS X}
|
21
|
+
gem.description = %Q{symsym can be used to symbolize crashlogs from dSYM files}
|
22
|
+
gem.email = "ulizurucker@googlemail.com"
|
23
|
+
gem.authors = ["Ulrich Zurucker"]
|
24
|
+
gem.executables = ["symsym"]
|
25
|
+
gem.default_executable = 'symsym'
|
26
|
+
# dependencies defined in Gemfile
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
|
31
|
+
require 'rake/rdoctask'
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
34
|
+
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "symsym #{version}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.8.0
|
data/bin/symsym
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'symsym'
|
7
|
+
|
8
|
+
dsymsearchpath = nil
|
9
|
+
|
10
|
+
options = {}
|
11
|
+
options[:dsymsearchpath] = "."
|
12
|
+
options[:reportfile] = nil
|
13
|
+
options[:copypasteboard] = false
|
14
|
+
options[:outputfile] = nil
|
15
|
+
report = nil
|
16
|
+
|
17
|
+
optparse = OptionParser.new do|opts|
|
18
|
+
opts.on('-h', '--help', 'Display this screen' ) do
|
19
|
+
puts opts
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
opts.on('-i FILE', "Read crashlog from FILE" ) do |p|
|
23
|
+
options[:reportfile] = p
|
24
|
+
end
|
25
|
+
opts.on('-o FILE', "Write symbolized crashlog to FILE") do |p|
|
26
|
+
options[:outputfile] = p
|
27
|
+
end
|
28
|
+
opts.on('-d FILE', "dSYM Search Path - the path where symsym should look for a matching dSYM bundle. If not given, look in ." ) do |p|
|
29
|
+
options[:dsymsearchpath] = p
|
30
|
+
end
|
31
|
+
opts.on('-p', '--pasteboard', "Use pasteboard content as report input") do
|
32
|
+
report = `pbpaste`
|
33
|
+
end
|
34
|
+
opts.on('-c', '--copypasteboard', "Copy the symbolized crashlog to pasteboard") do
|
35
|
+
options[:copypasteboard] = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
optparse.parse!
|
40
|
+
|
41
|
+
unless report
|
42
|
+
reportfile = options[:reportfile]
|
43
|
+
if reportfile && File.exist?(reportfile)
|
44
|
+
report = File.new(reportfile).read
|
45
|
+
else
|
46
|
+
puts "No input crashlog given. Use --help for usage."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
exit(1) unless report
|
51
|
+
|
52
|
+
report = Crashreport.new(report, options[:dsymsearchpath])
|
53
|
+
report.symbolicate!
|
54
|
+
|
55
|
+
if (options[:copypasteboard])
|
56
|
+
IO.popen('pbcopy', 'r+').puts report.report
|
57
|
+
end
|
58
|
+
|
59
|
+
if (options[:outputfile])
|
60
|
+
File.new(options[:outputfile], 'w+').puts report.report
|
61
|
+
end
|
62
|
+
|
63
|
+
puts report.report unless options[:copypasteboard] || options[:outputfile]
|
data/lib/symsym.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'osx/cocoa'
|
2
|
+
require 'find'
|
3
|
+
|
4
|
+
# DsymFile - wrapper around a .dSYM bundle
|
5
|
+
#
|
6
|
+
#
|
7
|
+
class DsymFile
|
8
|
+
attr_reader :identifier, :version, :shortversionstring
|
9
|
+
|
10
|
+
# Initializes a DsymFile with a path to a dSYM Bundle
|
11
|
+
#
|
12
|
+
# Extracts CFBundleIdentifier, CFBundleVersion and CFBundleShortVersionString from the Info.plist file inside the bundle
|
13
|
+
def initialize(filename)
|
14
|
+
@info_plist = OSX::NSDictionary.dictionaryWithContentsOfFile(File.join(filename, 'Contents/Info.plist'))
|
15
|
+
return unless @info_plist
|
16
|
+
@identifier = @info_plist['CFBundleIdentifier'].to_s
|
17
|
+
@version = @info_plist['CFBundleVersion'].to_s
|
18
|
+
@shortversionstring = @info_plist['CFBundleShortVersionString'].to_s
|
19
|
+
@filename = filename
|
20
|
+
end # initialize
|
21
|
+
|
22
|
+
# Matches Report?
|
23
|
+
#
|
24
|
+
# Checks if the Bundle Identifier, Bundle Version and Bundle Short Version String of a given Crashreport matches to this dSYM Bundle
|
25
|
+
def matches_report?(report)
|
26
|
+
false
|
27
|
+
true if @identifier =~ /#{report.identifier}/ && @version == report.version && @shortversionstring == report.shortversion
|
28
|
+
end
|
29
|
+
|
30
|
+
# return the filename
|
31
|
+
def to_s
|
32
|
+
@filename
|
33
|
+
end
|
34
|
+
end # class DsymFile
|
35
|
+
|
36
|
+
# Symbolized
|
37
|
+
#
|
38
|
+
# A symbol of the Crashreport that has been desymbolized with gdb
|
39
|
+
class Symbolized
|
40
|
+
attr_reader :startaddress, :endaddress, :line, :symbol, :filename
|
41
|
+
# Initialize with an output line from gdb. This will extract the addresses, linenumber and source-file
|
42
|
+
def initialize(s)
|
43
|
+
s.gsub(/Line (\d*) of "(.*)" starts at address (0x[0-9a-f]*) <(.*)> and ends at (0x[0-9a-f]*)/).to_a
|
44
|
+
@line = $1
|
45
|
+
@filename = $2
|
46
|
+
@startaddress = $3.hex if $3
|
47
|
+
@symbol = $4
|
48
|
+
@endaddress = $5.hex if $3
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# A class representing a crashreport
|
53
|
+
#
|
54
|
+
# This must be initialized with the crashreport as plain text, a path where to look for .dSYM bundlles can be given.
|
55
|
+
# The report can be de-symbolized with symbolicate!
|
56
|
+
class Crashreport
|
57
|
+
|
58
|
+
@addresses = nil
|
59
|
+
@dsymfile = nil
|
60
|
+
@isSymbolicated = false;
|
61
|
+
@cmdfilepath = nil;
|
62
|
+
|
63
|
+
attr_reader :identifier, :version, :shortversion, :report
|
64
|
+
|
65
|
+
# Extracts the address from a crashreport-line
|
66
|
+
def self.address_from_report_line(s)
|
67
|
+
a = s[/(0x[0-9a-f]+)/, 1]
|
68
|
+
return a.hex if a
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
# Creates a new Crashreport object
|
73
|
+
#
|
74
|
+
# r is the crash report as string. dsymfile is a path where this object will look for a matching .dSYM bundle
|
75
|
+
def initialize(r, dsymfile=nil)
|
76
|
+
@report = r
|
77
|
+
@dsymfile = dsymfile
|
78
|
+
@identifier = @report[/Identifier: (.*)/, 1]
|
79
|
+
@shortversion = @report[/Version: (.*) \((.*)\)/, 1]
|
80
|
+
@version = @report[/Version: (.*) \((.*)\)/, 2]
|
81
|
+
findDysmFile(dsymfile)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Find dSYM Bundle
|
85
|
+
#
|
86
|
+
# Look for a matching dSYM bundle. Use the current directory when nil
|
87
|
+
def findDysmFile(searchpath)
|
88
|
+
Find.find(searchpath || '.') do |f|
|
89
|
+
if f =~ /.dSYM/
|
90
|
+
dsymfile = DsymFile.new(f)
|
91
|
+
if dsymfile.matches_report? self
|
92
|
+
@dsymfile = dsymfile
|
93
|
+
return
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# returns an array of all adresses found in the crashreport
|
100
|
+
def addresses
|
101
|
+
return @addresses if @addresses
|
102
|
+
@addresses = []
|
103
|
+
@report.lines.each do |l|
|
104
|
+
a = Crashreport.address_from_report_line(l)
|
105
|
+
@addresses << a if a
|
106
|
+
end
|
107
|
+
@addresses
|
108
|
+
end
|
109
|
+
|
110
|
+
# de-symbolizes the crashreport
|
111
|
+
#
|
112
|
+
# The get the report with .report aftwards
|
113
|
+
def symbolicate!
|
114
|
+
return if @isSymbolicated
|
115
|
+
buildgdbcommandfile
|
116
|
+
gdbout = rungdb
|
117
|
+
@symbols = []
|
118
|
+
gdbout.lines.each do |l|
|
119
|
+
@symbols << Symbolized.new(l)
|
120
|
+
end
|
121
|
+
|
122
|
+
addresses.each do |a|
|
123
|
+
@symbols.each do |s|
|
124
|
+
if s.startaddress && a >= s.startaddress && a <= s.endaddress
|
125
|
+
report.gsub!(/(0x.*#{a.to_s(16)}) (.*)/, "#{$1} #{s.symbol} (#{s.filename}:#{s.line})")
|
126
|
+
end # address matches
|
127
|
+
end # @symbols.each
|
128
|
+
end# addresses.each
|
129
|
+
@isSymbolicated = true
|
130
|
+
end # symbolicate!
|
131
|
+
|
132
|
+
private
|
133
|
+
# runs gdb with the command file created by buildgdbcommandfile
|
134
|
+
def rungdb
|
135
|
+
gdbcmd = "gdb --batch --quiet -x \"#{@cmdfilepath}\" \"#{@dsymfile}\""
|
136
|
+
gdbout = `#{gdbcmd}`
|
137
|
+
gdbout
|
138
|
+
end
|
139
|
+
|
140
|
+
# build a command-file for gdb
|
141
|
+
def buildgdbcommandfile
|
142
|
+
return if @cmdfilepath
|
143
|
+
@cmdfilepath = '/tmp/symsymcmd.txt'
|
144
|
+
cmdfile = File.new(@cmdfilepath, 'w+')
|
145
|
+
self.addresses.each do |l|
|
146
|
+
cmdfile << "info line *#{l}\n"
|
147
|
+
end
|
148
|
+
cmdfile.close
|
149
|
+
end # buildgdbcommandfile
|
150
|
+
end # class Crashreport
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: symsym
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 63
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 0
|
10
|
+
version: 0.8.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Ulrich Zurucker
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-09 00:00:00 +02:00
|
19
|
+
default_executable: symsym
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
type: :development
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 6
|
33
|
+
- 0
|
34
|
+
version: 1.6.0
|
35
|
+
name: jeweler
|
36
|
+
version_requirements: *id001
|
37
|
+
description: symsym can be used to symbolize crashlogs from dSYM files
|
38
|
+
email: ulizurucker@googlemail.com
|
39
|
+
executables:
|
40
|
+
- symsym
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- LICENSE.txt
|
45
|
+
- README.md
|
46
|
+
- README.rdoc
|
47
|
+
files:
|
48
|
+
- .document
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- README.rdoc
|
54
|
+
- Rakefile
|
55
|
+
- VERSION
|
56
|
+
- bin/symsym
|
57
|
+
- lib/symsym.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: http://github.com/sononum/symsym
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.5.2
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Crashlog symbolizer for Mac OS X
|
92
|
+
test_files: []
|
93
|
+
|