satyr 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b52e512f3fb48bce3031e8d8b88ee0764fcc8f02
4
+ data.tar.gz: 85e6bef907ae38f51c744df06443402f87f61c83
5
+ SHA512:
6
+ metadata.gz: 9e7150a99c1df538f986fc7150f6c4ddf9b5a4fe7c5b05909211964358098d2dd12efd7780e180cecd23fa79353e84c10d8ccc08e7285c148ad26b7347130bd1
7
+ data.tar.gz: 22f78ab04653c4504f4c9b30b982c450bee87967d43871102f5460200a4635b771b6690d9e1f88c871267c43787f3c1d0e2348b03d1d3c15761994f31a34baf1
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
data/lib/satyr.rb ADDED
@@ -0,0 +1,176 @@
1
+ require 'ffi'
2
+
3
+ # Ruby bindings for libsatyr
4
+ module Satyr
5
+
6
+ # FFI wrappers for C functions. <em>Do not use this module directly</em>
7
+ module FFI
8
+ extend ::FFI::Library
9
+
10
+ ffi_lib 'libsatyr.so.3', ::FFI::Library::LIBC
11
+
12
+ enum :report_type, [ :invalid, 0,
13
+ :core,
14
+ :python,
15
+ :kerneloops,
16
+ :java,
17
+ :gdb ]
18
+
19
+ enum :duphash_flags, [ :normal, 1 << 0,
20
+ :nohash, 1 << 1,
21
+ :nonormalize, 1 << 2,
22
+ :koops_compat, 1 << 3 ]
23
+
24
+ attach_function :sr_report_from_json_text, [:string, :pointer], :pointer
25
+ attach_function :sr_report_free, [:pointer], :void
26
+
27
+ attach_function :sr_stacktrace_find_crash_thread, [:pointer], :pointer
28
+ attach_function :sr_core_stacktrace_dup, [:pointer], :pointer
29
+ attach_function :sr_python_stacktrace_dup, [:pointer], :pointer
30
+ attach_function :sr_koops_stacktrace_dup, [:pointer], :pointer
31
+ attach_function :sr_java_stacktrace_dup, [:pointer], :pointer
32
+ attach_function :sr_gdb_stacktrace_dup, [:pointer], :pointer
33
+ attach_function :sr_stacktrace_free, [:pointer], :void
34
+
35
+ attach_function :sr_thread_dup, [:pointer], :pointer
36
+ attach_function :sr_thread_get_duphash, [:pointer, :int, :string, :duphash_flags], :pointer
37
+ attach_function :sr_thread_free, [:pointer], :void
38
+
39
+ attach_function :free, [:pointer], :void
40
+
41
+ class ReportStruct < ::FFI::ManagedStruct
42
+ layout :version, :uint32,
43
+ :type, :report_type,
44
+ :reporter_name, :string,
45
+ :reporter_version, :string,
46
+ :user_root, :bool,
47
+ :user_local, :bool,
48
+ :operating_system, :pointer,
49
+ :component_name, :string,
50
+ :rpm_packages, :pointer,
51
+ :stacktrace, :pointer
52
+
53
+ def self.release(pointer)
54
+ Satyr::FFI.sr_report_free pointer
55
+ end
56
+ end
57
+
58
+ class StacktraceStruct < ::FFI::ManagedStruct
59
+ layout :type, :report_type
60
+
61
+ def self.release(pointer)
62
+ Satyr::FFI.sr_stacktrace_free pointer
63
+ end
64
+ end
65
+
66
+ class ThreadStruct < ::FFI::ManagedStruct
67
+ layout :type, :report_type
68
+
69
+ def self.release(pointer)
70
+ Satyr::FFI.sr_thread_free pointer
71
+ end
72
+ end
73
+
74
+ end
75
+
76
+ # Exception for errors originating in satyr
77
+ class SatyrError < StandardError
78
+ end
79
+
80
+ # Report containing all data relevant to a software problem
81
+ class Report
82
+
83
+ # Parses given JSON string to create new Report
84
+ def initialize(json)
85
+ error_msg = ::FFI::MemoryPointer.new(:pointer, 1)
86
+ pointer = Satyr::FFI.sr_report_from_json_text json.to_s, error_msg
87
+ error_msg = error_msg.read_pointer
88
+ unless error_msg.null?
89
+ message = error_msg.read_string.force_encoding('UTF-8')
90
+ Satyr::FFI.free error_msg
91
+ raise SatyrError, "Failed to parse JSON: #{message}"
92
+ end
93
+
94
+ # from_json_text should never return NULL without setting error_msg,
95
+ # better err on the safe side though
96
+ raise SatyrError, "Failed to create stacktrace" if pointer.null?
97
+
98
+ @struct = Satyr::FFI::ReportStruct.new pointer
99
+ end
100
+
101
+ # Returns Stacktrace of the report
102
+ def stacktrace
103
+ stacktrace = @struct[:stacktrace]
104
+ return nil if stacktrace.null?
105
+
106
+ # There's no sr_stacktrace_dup in libsatyr.so.3, we've got to find out
107
+ # the type ourselves.
108
+ dup = case @struct[:type]
109
+ when :core
110
+ Satyr::FFI.sr_core_stacktrace_dup(stacktrace)
111
+ when :python
112
+ Satyr::FFI.sr_python_stacktrace_dup(stacktrace)
113
+ when :kerneloops
114
+ Satyr::FFI.sr_koops_stacktrace_dup(stacktrace)
115
+ when :java
116
+ Satyr::FFI.sr_java_stacktrace_dup(stacktrace)
117
+ when :gdb
118
+ Satyr::FFI.sr_gdb_stacktrace_dup(stacktrace)
119
+ else
120
+ raise SatyrError, "Invalid report type"
121
+ end
122
+
123
+ raise SatyrError, "Failed to obtain stacktrace" if dup.null?
124
+
125
+ Stacktrace.send(:new, dup)
126
+ end
127
+ end
128
+
129
+ # Program stack trace, possibly composed of multiple threads
130
+ class Stacktrace
131
+
132
+ # Private constructor - Stacktrace objects are created in Report#stacktrace
133
+ def initialize(pointer)
134
+ raise SatyrError, "Invalid structure" if pointer.null?
135
+ @struct = Satyr::FFI::StacktraceStruct.new pointer
136
+ end
137
+ private_class_method :new
138
+
139
+ # Returns Thread that likely caused the crash that produced this stack
140
+ # trace
141
+ def find_crash_thread
142
+ pointer = Satyr::FFI.sr_stacktrace_find_crash_thread @struct.to_ptr
143
+ raise SatyrError, "Could not find crash thread" if pointer.null?
144
+ dup = Satyr::FFI.sr_thread_dup(pointer)
145
+ raise SatyrError, "Failed to duplicate thread" if dup.null?
146
+
147
+ Thread.send(:new, dup)
148
+ end
149
+ end
150
+
151
+ # Thread in a stack trace containing individual stack frames
152
+ class Thread
153
+
154
+ # Private constructor - Thread objects are returned by Stacktrace methods
155
+ def initialize(pointer)
156
+ raise SatyrError, "Invalid structure" if pointer.null?
157
+ @struct = Satyr::FFI::ThreadStruct.new pointer
158
+ end
159
+ private_class_method :new
160
+
161
+ # Duplication hash for the thread
162
+ # The method takes an option hash with following keys:
163
+ # - +:frames+:: number of frames to use (default 0 means use all)
164
+ # - +:flags+:: bitwise sum of (:normal, :nohash, :nonormalize,
165
+ # :koops_compat)
166
+ # - +:prefix+:: string to be prepended in front of the text before hashing
167
+ def duphash(opts = {})
168
+ opts = {:frames => 0, :flags => :normal, :prefix => ""}.merge(opts)
169
+ str_pointer = Satyr::FFI.sr_thread_get_duphash @struct.to_ptr, opts[:frames], opts[:prefix], opts[:flags]
170
+ raise SatyrError, "Failed to compute duphash" if str_pointer.null?
171
+ hash = str_pointer.read_string.force_encoding('UTF-8')
172
+ Satyr::FFI.free str_pointer
173
+ hash
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,107 @@
1
+ {
2
+ "ureport_version": 2,
3
+
4
+ "reason": "Program /usr/bin/sleep was terminated by signal 11",
5
+
6
+ "os": {
7
+ "name": "fedora",
8
+ "version": "18",
9
+ "architecture": "x86_64"
10
+ },
11
+
12
+ "problem": {
13
+ "type": "core",
14
+
15
+ "executable": "/usr/bin/sleep",
16
+
17
+ "signal": 11,
18
+
19
+ "component": "coreutils",
20
+
21
+ "user": {
22
+ "local": true,
23
+ "root": false
24
+ },
25
+
26
+ "stacktrace": [
27
+ {
28
+ "crash_thread": true,
29
+
30
+ "frames": [
31
+ {
32
+ "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
33
+ "build_id_offset": 767024,
34
+ "file_name": "/lib64/libc.so.6",
35
+ "address": 251315074096,
36
+ "fingerprint": "6c1eb9626919a2a5f6a4fc4c2edc9b21b33b7354",
37
+ "function_name": "__nanosleep"
38
+ },
39
+ {
40
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
41
+ "build_id_offset": 16567,
42
+ "file_name": "/usr/bin/sleep",
43
+ "address": 4210871,
44
+ "fingerprint": "d24433b82a2c751fc580f47154823e0bed641a54",
45
+ "function_name": "close_stdout"
46
+ },
47
+ {
48
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
49
+ "build_id_offset": 16202,
50
+ "file_name": "/usr/bin/sleep",
51
+ "address": 4210506,
52
+ "fingerprint": "562719fb960d1c4dbf30c04b3cff37c82acc3d2d",
53
+ "function_name": "close_stdout"
54
+ },
55
+ {
56
+ "build_id": "cd379d3bb5d07c96d491712e41c34bcd06b2ce32",
57
+ "build_id_offset": 6404,
58
+ "fingerprint": "2e8fb95adafe21d035b9bcb9993810fecf4be657",
59
+ "file_name": "/usr/bin/sleep",
60
+ "address": 4200708
61
+ },
62
+ {
63
+ "build_id": "5f6632d75fd027f5b7b410787f3f06c6bf73eee6",
64
+ "build_id_offset": 137733,
65
+ "file_name": "/lib64/libc.so.6",
66
+ "address": 251314444805,
67
+ "fingerprint": "075acda5d3230e115cf7c88597eaba416bdaa6bb",
68
+ "function_name": "__libc_start_main"
69
+ }
70
+ ]
71
+ }
72
+ ]
73
+ },
74
+
75
+ "packages": [
76
+ {
77
+ "name": "coreutils",
78
+ "epoch": 0,
79
+ "version": "8.17",
80
+ "architecture": "x86_64",
81
+ "package_role": "affected",
82
+ "release": "8.fc18",
83
+ "install_time": 1371464601
84
+ },
85
+ {
86
+ "name": "glibc",
87
+ "epoch": 0,
88
+ "version": "2.16",
89
+ "architecture": "x86_64",
90
+ "release": "31.fc18",
91
+ "install_time": 1371464176
92
+ },
93
+ {
94
+ "name": "glibc-common",
95
+ "epoch": 0,
96
+ "version": "2.16",
97
+ "architecture": "x86_64",
98
+ "release": "31.fc18",
99
+ "install_time": 1371464184
100
+ }
101
+ ],
102
+
103
+ "reporter": {
104
+ "version": "0.3",
105
+ "name": "satyr"
106
+ }
107
+ }
@@ -0,0 +1,43 @@
1
+ require 'test/unit'
2
+ require 'satyr'
3
+
4
+ class SatyrTest < Test::Unit::TestCase
5
+ def test_core_duphash
6
+ path = 'test/data/ureport-1'
7
+ json = IO.read(path)
8
+
9
+ report = Satyr::Report.new json
10
+ stacktrace = report.stacktrace
11
+ thread = stacktrace.find_crash_thread
12
+
13
+ assert_equal 'b9a440a68b6e0f33f6cd989e114d6c4093964e10', thread.duphash
14
+
15
+ expected_out = "Thread\n5f6632d75fd027f5b7b410787f3f06c6bf73eee6+0xbb430\n"
16
+ assert_equal expected_out, thread.duphash(frames: 1, flags: :nohash)
17
+
18
+ expected_out = "a" + expected_out
19
+ assert_equal expected_out, thread.duphash(frames: 1, flags: :nohash, prefix: "a")
20
+ end
21
+
22
+ def test_invalid_report
23
+ assert_raise Satyr::SatyrError do
24
+ report = Satyr::Report.new ""
25
+ end
26
+
27
+ begin
28
+ report = Satyr::Report.new "}"
29
+ rescue Satyr::SatyrError => e
30
+ assert_match /Failed to parse JSON:.*}.*/, e.message
31
+ end
32
+ end
33
+
34
+ def test_private_constructors
35
+ assert_raise NoMethodError do
36
+ s = Satyr::Stacktrace.new nil
37
+ end
38
+
39
+ assert_raise NoMethodError do
40
+ s = Satyr::Thread.new nil
41
+ end
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: satyr
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Martin Milata
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Ruby bindings for satyr, library for working with the uReport problem
28
+ report format.
29
+ email: mmilata@redhat.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - lib/satyr.rb
35
+ - Rakefile
36
+ - test/test_satyr.rb
37
+ - test/data/ureport-1
38
+ homepage: http://github.com/abrt/satyr
39
+ licenses:
40
+ - GPLv2
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.1.11
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Parse uReport bug report format
62
+ test_files:
63
+ - test/test_satyr.rb
64
+ - test/data/ureport-1