satyr 0.1

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.
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