backtracie 0.1.0 → 0.3.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.
@@ -78,119 +78,93 @@
78
78
  // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
79
79
  // PURPOSE.
80
80
 
81
- #include "rb_mjit_min_header-3.0.0.h"
81
+ #ifndef RUBY_SHARDS_H
82
+ #define RUBY_SHARDS_H
82
83
 
83
- #include "ruby_3.0.0.h"
84
+ // -----------------------------------------------------------------------------
84
85
 
85
86
  /**********************************************************************
87
+ method.h -
88
+ created at: Wed Jul 15 20:02:33 2009
89
+ Copyright (C) 2009 Koichi Sasada
90
+ **********************************************************************/
91
+
92
+ #ifdef PRE_MJIT_RUBY
93
+ #include <stdbool.h>
94
+ #include <vm_core.h>
95
+ #include <method.h>
96
+ #else
97
+ #ifndef RUBY_MJIT_HEADER_INCLUDED
98
+ typedef enum {
99
+ VM_METHOD_TYPE_ISEQ, /*!< Ruby method */
100
+ VM_METHOD_TYPE_CFUNC, /*!< C method */
101
+ VM_METHOD_TYPE_ATTRSET, /*!< attr_writer or attr_accessor */
102
+ VM_METHOD_TYPE_IVAR, /*!< attr_reader or attr_accessor */
103
+ VM_METHOD_TYPE_BMETHOD,
104
+ VM_METHOD_TYPE_ZSUPER,
105
+ VM_METHOD_TYPE_ALIAS,
106
+ VM_METHOD_TYPE_UNDEF,
107
+ VM_METHOD_TYPE_NOTIMPLEMENTED,
108
+ VM_METHOD_TYPE_OPTIMIZED, /*!< Kernel#send, Proc#call, etc */
109
+ VM_METHOD_TYPE_MISSING, /*!< wrapper for method_missing(id) */
110
+ VM_METHOD_TYPE_REFINED, /*!< refinement */
111
+ } rb_method_type_t;
112
+ #endif
113
+ #endif
86
114
 
87
- vm_backtrace.c -
115
+ // -----------------------------------------------------------------------------
88
116
 
89
- $Author: ko1 $
90
- created at: Sun Jun 03 00:14:20 2012
117
+ typedef struct {
118
+ unsigned int is_ruby_frame : 1; // 1 -> ruby frame / 0 -> cfunc frame
119
+
120
+ // for ruby frames where the callable_method_entry is not of type VM_METHOD_TYPE_ISEQ, most of the metadata we
121
+ // want can be found by querying the iseq, and there may not even be an callable_method_entry
122
+ unsigned int should_use_iseq : 1;
123
+
124
+ rb_method_type_t vm_method_type;
125
+ int line_number;
126
+ VALUE iseq;
127
+ VALUE callable_method_entry;
128
+ VALUE self;
129
+ VALUE original_id;
130
+ } raw_location;
131
+
132
+ int backtracie_rb_profile_frames(int limit, raw_location *raw_locations);
133
+ int backtracie_rb_profile_frames_for_thread(VALUE thread, int limit, raw_location *raw_locations);
134
+ bool backtracie_is_thread_alive(VALUE thread);
135
+ VALUE backtracie_called_id(raw_location *the_location);
136
+ VALUE backtracie_defined_class(raw_location *the_location);
137
+ bool backtracie_iseq_is_block(raw_location *the_location);
138
+ bool backtracie_iseq_is_eval(raw_location *the_location);
139
+ VALUE backtracie_refinement_name(raw_location *the_location);
91
140
 
92
- Copyright (C) 1993-2012 Yukihiro Matsumoto
141
+ // -----------------------------------------------------------------------------
93
142
 
94
- **********************************************************************/
143
+ // Ruby 3.0 finally added support for showing "cfunc frames" (frames for methods written in C) in stack traces:
144
+ // https://github.com/ruby/ruby/pull/3299/files
145
+ //
146
+ // The diff is rather trivial, and it makes a world of difference, given how most of Ruby's core classes are written in C.
147
+ // Thus, the methods below are copied from that PR so that we can make use of this functionality on older Ruby versions.
148
+ #ifdef CFUNC_FRAMES_BACKPORT_NEEDED
149
+ #define backtracie_rb_profile_frame_method_name backported_rb_profile_frame_method_name
150
+
151
+ VALUE backported_rb_profile_frame_method_name(VALUE frame);
152
+ #else // Ruby > 3.0, just use the stock functionality
153
+ #define backtracie_rb_profile_frame_method_name rb_profile_frame_method_name
154
+ #endif
155
+
156
+ // Backport https://github.com/ruby/ruby/pull/3084 (present in 2.7 and 3.0) to Ruby <= 2.6
157
+ // The interesting bit is actually the fix to rb_profile_frame_classpath BUT since rb_profile_frame_qualified_method_name
158
+ // internally relies on rb_profile_frame_classpath we also need to add a copy of that one as well.
159
+ #ifdef CLASSPATH_BACKPORT_NEEDED
160
+ #define backtracie_rb_profile_frame_classpath backported_rb_profile_frame_classpath
161
+ #define backtracie_rb_profile_frame_qualified_method_name backported_rb_profile_frame_qualified_method_name
162
+
163
+ VALUE backported_rb_profile_frame_classpath(VALUE frame);
164
+ VALUE backported_rb_profile_frame_qualified_method_name(VALUE frame);
165
+ #else
166
+ #define backtracie_rb_profile_frame_classpath rb_profile_frame_classpath
167
+ #define backtracie_rb_profile_frame_qualified_method_name rb_profile_frame_qualified_method_name
168
+ #endif
95
169
 
96
- inline static int
97
- calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
98
- {
99
- VM_ASSERT(iseq);
100
- VM_ASSERT(iseq->body);
101
- VM_ASSERT(iseq->body->iseq_encoded);
102
- VM_ASSERT(iseq->body->iseq_size);
103
- if (! pc) {
104
- /* This can happen during VM bootup. */
105
- VM_ASSERT(iseq->body->type == ISEQ_TYPE_TOP);
106
- VM_ASSERT(! iseq->body->local_table);
107
- VM_ASSERT(! iseq->body->local_table_size);
108
- return 0;
109
- }
110
- else {
111
- ptrdiff_t n = pc - iseq->body->iseq_encoded;
112
- VM_ASSERT(n <= iseq->body->iseq_size);
113
- VM_ASSERT(n >= 0);
114
- ASSUME(n >= 0);
115
- size_t pos = n; /* no overflow */
116
- if (LIKELY(pos)) {
117
- /* use pos-1 because PC points next instruction at the beginning of instruction */
118
- pos--;
119
- }
120
- #if VMDEBUG && defined(HAVE_BUILTIN___BUILTIN_TRAP)
121
- else {
122
- /* SDR() is not possible; that causes infinite loop. */
123
- rb_print_backtrace();
124
- __builtin_trap();
125
- }
126
170
  #endif
127
- return rb_iseq_line_no(iseq, pos);
128
- }
129
- }
130
-
131
- int modified_rb_profile_frames_for_execution_context(
132
- rb_execution_context_t *ec,
133
- int start,
134
- int limit,
135
- VALUE *buff,
136
- VALUE *correct_labels,
137
- int *lines
138
- ) {
139
- int i;
140
- const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);
141
- const rb_callable_method_entry_t *cme;
142
-
143
- for (i=0; i<limit && cfp != end_cfp;) {
144
- if (VM_FRAME_RUBYFRAME_P(cfp)) {
145
- if (start > 0) {
146
- start--;
147
- continue;
148
- }
149
-
150
- // Stash the iseq so we can use it for the label. Otherwise ./spec/unit/backtracie_spec.rb:53 used to fail with
151
- // expected: "block (3 levels) in fetch_or_store"
152
- // got: "fetch_or_store"
153
- // ...but works with this hack.
154
- correct_labels[i] = (VALUE) cfp->iseq;
155
-
156
- /* record frame info */
157
- cme = rb_vm_frame_method_entry(cfp);
158
- if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
159
- buff[i] = (VALUE)cme;
160
- }
161
- else {
162
- buff[i] = (VALUE)cfp->iseq;
163
- }
164
-
165
- if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
166
-
167
- i++;
168
- }
169
- else {
170
- cme = rb_vm_frame_method_entry(cfp);
171
- if (cme && cme->def->type == VM_METHOD_TYPE_CFUNC) {
172
- buff[i] = (VALUE)cme;
173
- if (lines) lines[i] = 0;
174
- i++;
175
- }
176
- }
177
-
178
- cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
179
- }
180
-
181
- return i;
182
- }
183
-
184
- int modified_rb_profile_frames(int start, int limit, VALUE *buff, VALUE *correct_labels, int *lines) {
185
- return modified_rb_profile_frames_for_execution_context(GET_EC(), start, limit, buff, correct_labels, lines);
186
- }
187
-
188
- int modified_rb_profile_frames_for_thread(VALUE thread, int start, int limit, VALUE *buff, VALUE *correct_labels, int *lines) {
189
- // In here we're assuming that what we got is really a Thread or its subclass. This assumption NEEDS to be verified by
190
- // the caller, otherwise I see a segfault in your future.
191
- rb_thread_t *thread_pointer = (rb_thread_t*) DATA_PTR(thread);
192
-
193
- if (thread_pointer->to_kill || thread_pointer->status == THREAD_KILLED) return Qnil;
194
-
195
- return modified_rb_profile_frames_for_execution_context(thread_pointer->ec, start, limit, buff, correct_labels, lines);
196
- }
@@ -26,15 +26,17 @@ module Backtracie
26
26
  attr_accessor :label
27
27
  attr_accessor :lineno
28
28
  attr_accessor :path
29
+ attr_accessor :qualified_method_name
29
30
 
30
31
  # Note: The order of arguments is hardcoded in the native extension in the `new_location` function --
31
32
  # keep them in sync
32
- def initialize(absolute_path, base_label, label, lineno, path, debug)
33
+ def initialize(absolute_path, base_label, label, lineno, path, qualified_method_name, debug)
33
34
  @absolute_path = absolute_path
34
35
  @base_label = base_label
35
36
  @label = label
36
37
  @lineno = lineno
37
38
  @path = path
39
+ @qualified_method_name = qualified_method_name
38
40
  @debug = debug
39
41
 
40
42
  freeze
@@ -47,5 +49,14 @@ module Backtracie
47
49
  "#{@path}:in `#{@label}'"
48
50
  end
49
51
  end
52
+
53
+ # Still WIP
54
+ def fancy_to_s
55
+ if @lineno != 0
56
+ "#{@path}:#{@lineno}:in #{@qualified_method_name}"
57
+ else
58
+ "#{@path}:in #{@qualified_method_name}"
59
+ end
60
+ end
50
61
  end
51
62
  end
@@ -19,5 +19,5 @@
19
19
  # along with backtracie. If not, see <http://www.gnu.org/licenses/>.
20
20
 
21
21
  module Backtracie
22
- VERSION = "0.1.0"
22
+ VERSION = "0.3.0"
23
23
  end
data/lib/backtracie.rb CHANGED
@@ -28,8 +28,17 @@ require "backtracie_native_extension"
28
28
  module Backtracie
29
29
  module_function
30
30
 
31
- def caller_locations
32
- Primitive.caller_locations
31
+ if RUBY_VERSION < "2.5"
32
+ def caller_locations
33
+ # FIXME: We're having some trouble getting the current thread on older Rubies, see the FIXME on
34
+ # backtracie_rb_profile_frames. A workaround is to just pass in the reference to the current thread explicitly
35
+ # (and slice off a few frames, since caller_locations is supposed to start from the caller of our caller)
36
+ backtrace_locations(Thread.current)[3..-1]
37
+ end
38
+ else
39
+ def caller_locations
40
+ Primitive.caller_locations
41
+ end
33
42
  end
34
43
 
35
44
  # Defined via native code only; not redirecting via Primitive to avoid an extra stack frame on the stack
metadata CHANGED
@@ -1,41 +1,53 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backtracie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivo Anjo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-12 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2021-09-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: debase-ruby_core_source
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.10'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.10.12
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.10'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.10.12
13
33
  description: Ruby gem for beautiful backtraces
14
34
  email:
15
35
  - ivo@ivoanjo.me
16
36
  executables: []
17
- extensions: []
37
+ extensions:
38
+ - ext/backtracie_native_extension/extconf.rb
18
39
  extra_rdoc_files: []
19
40
  files:
20
41
  - ".editorconfig"
21
- - ".gitignore"
22
- - ".rspec"
23
- - ".ruby-version"
24
- - ".standard.yml"
25
42
  - CODE_OF_CONDUCT.adoc
26
43
  - COPYING
27
44
  - COPYING.LESSER
28
- - DEVELOPMENT_NOTES.adoc
29
45
  - README.adoc
30
- - Rakefile
31
46
  - backtracie.gemspec
32
- - bin/console
33
- - bin/setup
34
47
  - ext/backtracie_native_extension/backtracie.c
35
48
  - ext/backtracie_native_extension/extconf.rb
36
- - ext/backtracie_native_extension/ruby_3.0.0.c
37
- - ext/backtracie_native_extension/ruby_3.0.0.h
38
- - gems.rb
49
+ - ext/backtracie_native_extension/ruby_shards.c
50
+ - ext/backtracie_native_extension/ruby_shards.h
39
51
  - lib/backtracie.rb
40
52
  - lib/backtracie/location.rb
41
53
  - lib/backtracie/version.rb
@@ -52,14 +64,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
52
64
  requirements:
53
65
  - - ">="
54
66
  - !ruby/object:Gem::Version
55
- version: 3.0.0
67
+ version: 2.3.0
56
68
  required_rubygems_version: !ruby/object:Gem::Requirement
57
69
  requirements:
58
70
  - - ">="
59
71
  - !ruby/object:Gem::Version
60
72
  version: '0'
61
73
  requirements: []
62
- rubygems_version: 3.2.3
74
+ rubygems_version: 3.1.4
63
75
  signing_key:
64
76
  specification_version: 4
65
77
  summary: Ruby gem for beautiful backtraces
data/.gitignore DELETED
@@ -1,33 +0,0 @@
1
- *.gem
2
- *.rbc
3
- /.config
4
- /coverage/
5
- /InstalledFiles
6
- /pkg/
7
- /spec/reports/
8
- /spec/examples.txt
9
- /test/tmp/
10
- /test/version_tmp/
11
- /tmp/
12
-
13
- # Used by dotenv library to load environment variables.
14
- # .env
15
-
16
- ## Documentation cache and generated files:
17
- /.yardoc/
18
- /_yardoc/
19
- /doc/
20
- /rdoc/
21
-
22
- ## Environment normalization:
23
- /.bundle/
24
- /vendor/bundle
25
- /lib/bundler/man/
26
-
27
- gems.locked
28
- Gemfile.lock
29
-
30
- *.o
31
- *.so
32
- ext/**/extconf.h
33
- ext/**/Makefile
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --require spec_helper
2
- --order defined
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- ruby-3.0.0
data/.standard.yml DELETED
@@ -1,14 +0,0 @@
1
- # Currently we only support >= 3.0.0 but I suspect we'll be able to support as far back as the Ruby version that
2
- # introduced mjit without a lot of trouble, so let's avoid making the code dependent on 3.0-only features
3
- ruby_version: 2.6
4
-
5
- ignore:
6
- - 'spec/unit/interesting_backtrace_helper.rb': # let's just say this file is special
7
- - Lint/UselessTimes
8
- - Style/EvalWithLocation
9
- - Style/GlobalVars
10
- - Style/MissingRespondToMissing
11
- - 'ext/backtracie_native_extension/extconf.rb':
12
- - Style/GlobalVars
13
- - 'spec/unit/backtracie_spec.rb':
14
- - Style/EvalWithLocation
@@ -1,399 +0,0 @@
1
- = Development Notes
2
-
3
- == Ideas to explore
4
-
5
- === Understand why `rb_profile_frames` does not return the correct iseq for a block.
6
-
7
- Given
8
-
9
- [source,ruby]
10
- ----
11
- def run
12
- puts "Backtracie: " + Backtracie.caller_locations.first.label
13
- puts "Ruby: " + caller_locations.first.label
14
- end
15
-
16
- def run2
17
- 1.times do
18
- run
19
- end
20
- end
21
- ----
22
-
23
- the output is
24
-
25
- ----
26
- Backtracie: run2
27
- Ruby: block in run2
28
- ----
29
-
30
- this is because inside `rb_profile_frames` the code goes
31
-
32
- [source,c]
33
- ----
34
- /* record frame info */
35
- cme = rb_vm_frame_method_entry(cfp);
36
- if (cme && cme->def->type == VM_METHOD_TYPE_ISEQ) {
37
- buff[i] = (VALUE)cme;
38
- }
39
- else {
40
- buff[i] = (VALUE)cfp->iseq;
41
- }
42
- ----
43
-
44
- and in this case the first branch is taken (we get the `cme`, not the `cfp->iseq`). I have no idea why.
45
-
46
- ==== Update:
47
-
48
- When using the `cfp->iseq` instead of the `cme`, in many cases, the `full_label`, `classpath`, `qualified_method_name`, `singleton_method_p` and `first_lineno` become less accurate.
49
-
50
- Why "less accurate"? Consider the following slightly compacted diff taken with backtracie and either `cme` or `cfp->iseq usage`, using the `interesting_backtrace_helper.rb`, looking at the output in the debug fields for the `Backtracie::Location` instances:
51
-
52
- [source, diff]
53
- ----
54
- --- cfp->iseq
55
- +++ cme
56
- @@ -6,16 +6,16 @@
57
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
58
- "hello",
59
- "hello",
60
- - "ClassA#hello",
61
- + "hello",
62
- 18,
63
- - "ClassA",
64
- + nil,
65
- false,
66
- "hello",
67
- - "ClassA#hello"],
68
- + "hello"],
69
- @@ -23,16 +23,16 @@
70
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
71
- "hello",
72
- "hello",
73
- - "ModuleB::ClassB#hello",
74
- + "hello",
75
- 27,
76
- - "ModuleB::ClassB",
77
- + nil,
78
- false,
79
- "hello",
80
- - "ModuleB::ClassB#hello"],
81
- + "hello"],
82
- @@ -40,16 +40,16 @@
83
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
84
- "hello",
85
- "hello",
86
- - "ModuleC.hello",
87
- + "hello",
88
- 34,
89
- - "ModuleC",
90
- - true,
91
- + nil,
92
- + false,
93
- "hello",
94
- - "ModuleC.hello"],
95
- + "hello"],
96
- @@ -57,16 +57,16 @@
97
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
98
- "hello",
99
- "hello",
100
- - "ClassWithStaticMethod.hello",
101
- + "hello",
102
- 40,
103
- - "ClassWithStaticMethod",
104
- - true,
105
- + nil,
106
- + false,
107
- "hello",
108
- - "ClassWithStaticMethod.hello"],
109
- + "hello"],
110
- @@ -74,16 +74,16 @@
111
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
112
- "hello",
113
- "hello",
114
- - "ModuleD#hello",
115
- + "hello",
116
- 46,
117
- - "ModuleD",
118
- + nil,
119
- false,
120
- "hello",
121
- - "ModuleD#hello"],
122
- + "hello"],
123
- @@ -125,16 +125,16 @@
124
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
125
- "hello",
126
- "hello",
127
- - "#<ClassD:0x0000556485af28e8>.hello",
128
- + "hello",
129
- 63,
130
- - "#<ClassD:0x0000556485af28e8>",
131
- - true,
132
- + nil,
133
- + false,
134
- "hello",
135
- - "#<ClassD:0x0000556485af28e8>.hello"],
136
- + "hello"],
137
- @@ -142,16 +142,16 @@
138
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
139
- "hello",
140
- "hello",
141
- - "ClassE#hello",
142
- + "hello",
143
- 68,
144
- - "ClassE",
145
- + nil,
146
- false,
147
- "hello",
148
- - "ClassE#hello"],
149
- + "hello"],
150
- @@ -176,16 +176,16 @@
151
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
152
- "hello",
153
- "hello",
154
- - "#<Module:0x0000556485af2140>#hello",
155
- + "hello",
156
- 82,
157
- - "#<Module:0x0000556485af2140>",
158
- + nil,
159
- false,
160
- "hello",
161
- - "#<Module:0x0000556485af2140>#hello"],
162
- + "hello"],
163
- @@ -193,16 +193,16 @@
164
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
165
- "hello",
166
- "hello",
167
- - "ModuleE.hello",
168
- + "hello",
169
- 92,
170
- - "ModuleE",
171
- - true,
172
- + nil,
173
- + false,
174
- "hello",
175
- - "ModuleE.hello"],
176
- + "hello"],
177
- @@ -210,33 +210,33 @@
178
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
179
- "method_missing",
180
- "method_missing",
181
- - "ClassH#method_missing",
182
- + "method_missing",
183
- 98,
184
- - "ClassH",
185
- + nil,
186
- false,
187
- "method_missing",
188
- - "ClassH#method_missing"],
189
- + "method_missing"],
190
- @label="method_missing",
191
- @lineno=101,
192
- @path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb">,
193
- - #<Backtracie::Location:0x0000556486191a00
194
- + #<Backtracie::Location:0x0000563ca3800df0
195
- @absolute_path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
196
- @base_label="hello",
197
- @debug=
198
- ["/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
199
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
200
- + "block in hello",
201
- "hello",
202
- - "hello",
203
- - "ClassF#hello",
204
- - 106,
205
- - "ClassF",
206
- + "block in hello",
207
- + 107,
208
- + nil,
209
- false,
210
- "hello",
211
- - "ClassF#hello"],
212
- - @label="hello",
213
- + "hello"],
214
- + @label="block in hello",
215
- @@ -252,16 +252,16 @@
216
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
217
- "hello",
218
- "hello",
219
- - "ClassF#hello",
220
- + "hello",
221
- 106,
222
- - "ClassF",
223
- + nil,
224
- false,
225
- "hello",
226
- - "ClassF#hello"],
227
- + "hello"],
228
- @@ -286,16 +286,16 @@
229
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
230
- "hello",
231
- "hello",
232
- - "#<Class:0x0000556485af0a70>.hello",
233
- + "hello",
234
- 121,
235
- - "#<Class:0x0000556485af0a70>",
236
- - true,
237
- + nil,
238
- + false,
239
- "hello",
240
- - "#<Class:0x0000556485af0a70>.hello"],
241
- + "hello"],
242
- @@ -303,16 +303,16 @@
243
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
244
- "hello",
245
- "hello",
246
- - "#<Class:0x0000556485af07a0>#hello",
247
- + "hello",
248
- 126,
249
- - "#<Class:0x0000556485af07a0>",
250
- + nil,
251
- false,
252
- "hello",
253
- - "#<Class:0x0000556485af07a0>#hello"],
254
- + "hello"],
255
- @@ -320,16 +320,16 @@
256
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
257
- "hello",
258
- "hello",
259
- - "#<Module:0x0000556485af0430>.hello",
260
- + "hello",
261
- 132,
262
- - "#<Module:0x0000556485af0430>",
263
- - true,
264
- + nil,
265
- + false,
266
- "hello",
267
- - "#<Module:0x0000556485af0430>.hello"],
268
- + "hello"],
269
- @@ -337,33 +337,33 @@
270
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
271
- "method_with_complex_parameters",
272
- "method_with_complex_parameters",
273
- - "Object#method_with_complex_parameters",
274
- + "method_with_complex_parameters",
275
- 137,
276
- - "Object",
277
- + nil,
278
- false,
279
- "method_with_complex_parameters",
280
- - "Object#method_with_complex_parameters"],
281
- + "method_with_complex_parameters"],
282
- @label="method_with_complex_parameters",
283
- @lineno=138,
284
- @path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb">,
285
- - #<Backtracie::Location:0x00005564861925e0
286
- + #<Backtracie::Location:0x0000563ca3801d90
287
- @absolute_path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
288
- @base_label="hello",
289
- @debug=
290
- ["/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
291
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
292
- + "block (2 levels) in hello",
293
- "hello",
294
- - "hello",
295
- - "ClassJ#hello",
296
- - 146,
297
- - "ClassJ",
298
- + "block (2 levels) in hello",
299
- + 148,
300
- + nil,
301
- false,
302
- "hello",
303
- - "ClassJ#hello"],
304
- - @label="hello",
305
- + "hello"],
306
- @@ -371,33 +371,33 @@
307
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
308
- "hello_helper",
309
- "hello_helper",
310
- - "ClassJ#hello_helper",
311
- + "hello_helper",
312
- 142,
313
- - "ClassJ",
314
- + nil,
315
- false,
316
- "hello_helper",
317
- - "ClassJ#hello_helper"],
318
- + "hello_helper"],
319
- @label="hello_helper",
320
- @lineno=143,
321
- @path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb">,
322
- - #<Backtracie::Location:0x0000556486192928
323
- + #<Backtracie::Location:0x0000563ca3801f70
324
- @absolute_path="/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
325
- @base_label="hello",
326
- @debug=
327
- ["/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
328
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
329
- + "block in hello",
330
- "hello",
331
- - "hello",
332
- - "ClassJ#hello",
333
- - 146,
334
- - "ClassJ",
335
- + "block in hello",
336
- + 147,
337
- + nil,
338
- false,
339
- "hello",
340
- - "ClassJ#hello"],
341
- - @label="hello",
342
- + "hello"],
343
- @@ -405,16 +405,16 @@
344
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
345
- "hello_helper",
346
- "hello_helper",
347
- - "ClassJ#hello_helper",
348
- + "hello_helper",
349
- 142,
350
- - "ClassJ",
351
- + nil,
352
- false,
353
- "hello_helper",
354
- - "ClassJ#hello_helper"],
355
- + "hello_helper"],
356
- @@ -422,16 +422,16 @@
357
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
358
- "hello",
359
- "hello",
360
- - "ClassJ#hello",
361
- + "hello",
362
- 146,
363
- - "ClassJ",
364
- + nil,
365
- false,
366
- "hello",
367
- - "ClassJ#hello"],
368
- + "hello"],
369
- @@ -439,16 +439,16 @@
370
- "/ruby/backtracie/spec/unit/interesting_backtrace_helper.rb",
371
- "top_level_hello",
372
- "top_level_hello",
373
- - "Object#top_level_hello",
374
- + "top_level_hello",
375
- 155,
376
- - "Object",
377
- + nil,
378
- false,
379
- "top_level_hello",
380
- - "Object#top_level_hello"],
381
- + "top_level_hello"],
382
- ----
383
-
384
- We can see that we miss the information about module/class names (we only get methods), we lose the singleton info, etc. The `first_lineno` numbers that move (which is not very important since we get the exact line via a different method). The only thing that is correct in the `cfp->iseq` version is getting "block in method" in the few places where we were missing it.
385
-
386
- So clearly the `cme` version in upstream Ruby is correct almost all of the time, except for the `label` missing the "block in method" in a few cases.
387
-
388
- This seems to point to the "block in method" issue either being an implementation bug (I still don't quite understand what the two different objects being used here represent) OR more of a "limitation" -- perhaps it's awkward to provide the correct label on the objects that miss it, and since the current MRI object returns one `VALUE` per stack frame, not two, the slight issue is just ignored.
389
-
390
- == TODO
391
-
392
- * Benchmarking
393
- * Tackle FIXMEs
394
- * Support Ruby < 3.0
395
- * Support showing class name, e.g. https://ivoanjo.me/blog/2020/07/05/ruby-experiment-include-class-names-in-backtraces/
396
- * Go beyond class name, e.g. https://ivoanjo.me/blog/2020/07/19/better-backtraces-in-ruby-using-tracepoint/
397
- * Implement equivalents to `Kernel#caller`, `Thread#backtrace`
398
- * Implement limits (similar to the arguments passed to the regular Ruby APIs)
399
- * User documentation