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.
- checksums.yaml +4 -4
- data/.editorconfig +4 -0
- data/README.adoc +107 -2
- data/backtracie.gemspec +11 -2
- data/ext/backtracie_native_extension/backtracie.c +235 -75
- data/ext/backtracie_native_extension/extconf.rb +76 -1
- data/ext/backtracie_native_extension/ruby_shards.c +533 -0
- data/ext/backtracie_native_extension/{ruby_3.0.0.c → ruby_shards.h} +81 -107
- data/lib/backtracie/location.rb +12 -1
- data/lib/backtracie/version.rb +1 -1
- data/lib/backtracie.rb +11 -2
- metadata +29 -17
- data/.gitignore +0 -33
- data/.rspec +0 -2
- data/.ruby-version +0 -1
- data/.standard.yml +0 -14
- data/DEVELOPMENT_NOTES.adoc +0 -399
- data/Rakefile +0 -29
- data/bin/console +0 -8
- data/bin/setup +0 -8
- data/ext/backtracie_native_extension/ruby_3.0.0.h +0 -7
- data/gems.rb +0 -15
@@ -78,119 +78,93 @@
|
|
78
78
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
79
79
|
// PURPOSE.
|
80
80
|
|
81
|
-
#
|
81
|
+
#ifndef RUBY_SHARDS_H
|
82
|
+
#define RUBY_SHARDS_H
|
82
83
|
|
83
|
-
|
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
|
-
|
115
|
+
// -----------------------------------------------------------------------------
|
88
116
|
|
89
|
-
|
90
|
-
|
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
|
-
|
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
|
-
}
|
data/lib/backtracie/location.rb
CHANGED
@@ -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
|
data/lib/backtracie/version.rb
CHANGED
data/lib/backtracie.rb
CHANGED
@@ -28,8 +28,17 @@ require "backtracie_native_extension"
|
|
28
28
|
module Backtracie
|
29
29
|
module_function
|
30
30
|
|
31
|
-
|
32
|
-
|
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.
|
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-
|
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/
|
37
|
-
- ext/backtracie_native_extension/
|
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
|
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.
|
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
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
|
data/DEVELOPMENT_NOTES.adoc
DELETED
@@ -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
|