backtracie 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.adoc ADDED
@@ -0,0 +1,66 @@
1
+ = `backtracie`
2
+ :toc:
3
+ :toc-placement: macro
4
+ :toclevels: 4
5
+ :toc-title:
6
+
7
+ image:https://img.shields.io/badge/Contributor%20Covenant-2.0-4baaaa.svg["Contributor Covenant", link="CODE_OF_CONDUCT.adoc"]
8
+ image:https://badge.fury.io/rb/backtracie.svg["Gem Version", link="https://badge.fury.io/rb/backtracie"]
9
+
10
+ [discrete]
11
+ == Contents
12
+
13
+ toc::[]
14
+
15
+ == Installation
16
+
17
+ Add this line to your application's `gems.rb` or `Gemfile`:
18
+
19
+ [source,ruby]
20
+ ----
21
+ gem 'backtracie'
22
+ ----
23
+
24
+ And then execute:
25
+
26
+ [source,bash]
27
+ ----
28
+ $ bundle install
29
+ ----
30
+
31
+ Or install it yourself as:
32
+
33
+ [source,bash]
34
+ ----
35
+ $ gem install backtracie
36
+ ----
37
+
38
+ This gem is versioned according to http://semver.org/spec/v2.0.0.html[Semantic Versioning].
39
+
40
+ == Usage
41
+
42
+ TODO
43
+
44
+ == Development
45
+
46
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `rake spec` to run the tests.
47
+
48
+ To open a console with the gem loaded, run `bundle console`.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to https://rubygems.org[rubygems.org].
51
+
52
+ == Feedback and success stories
53
+
54
+ Your feedback is welcome!
55
+
56
+ == Contributing
57
+
58
+ Bug reports and pull requests are welcome on GitLab at https://github.com/ivoanjo/backtracie.
59
+
60
+ This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
61
+
62
+ Maintained with ❤️ by https://ivoanjo.me/[Ivo Anjo].
63
+
64
+ == Code of Conduct
65
+
66
+ Everyone interacting in the backtracie project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the link:CODE_OF_CONDUCT.adoc[code of conduct].
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # backtracie: Ruby gem for beautiful backtraces
4
+ # Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
5
+ #
6
+ # This file is part of backtracie.
7
+ #
8
+ # backtracie is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Lesser General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # backtracie is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public License
19
+ # along with backtracie. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ require "bundler/gem_tasks"
22
+ require "rspec/core/rake_task"
23
+ require "standard/rake"
24
+ require "rake/extensiontask"
25
+
26
+ RSpec::Core::RakeTask.new(:spec)
27
+ Rake::ExtensionTask.new("backtracie_native_extension")
28
+
29
+ task default: [:compile, :spec, :'standard:fix']
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # backtracie: Ruby gem for beautiful backtraces
4
+ # Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
5
+ #
6
+ # This file is part of backtracie.
7
+ #
8
+ # backtracie is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Lesser General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # backtracie is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public License
19
+ # along with backtracie. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ lib = File.expand_path("../lib", __FILE__)
22
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
23
+ require "backtracie/version"
24
+
25
+ Gem::Specification.new do |spec|
26
+ spec.name = "backtracie"
27
+ spec.version = Backtracie::VERSION
28
+ spec.authors = ["Ivo Anjo"]
29
+ spec.email = ["ivo@ivoanjo.me"]
30
+
31
+ spec.summary = "Ruby gem for beautiful backtraces"
32
+ spec.description = "Ruby gem for beautiful backtraces"
33
+ spec.homepage = "https://github.com/ivoanjo/backtracie"
34
+ spec.license = "LGPL-3.0+"
35
+ spec.required_ruby_version = ">= 3.0.0"
36
+
37
+ # Specify which files should be added to the gem when it is released.
38
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
39
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
40
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
41
+ end
42
+ spec.require_paths = ["lib", "ext"]
43
+ end
data/bin/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "backtracie"
6
+
7
+ require "pry"
8
+ Pry.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,185 @@
1
+ // backtracie: Ruby gem for beautiful backtraces
2
+ // Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
3
+ //
4
+ // This file is part of backtracie.
5
+ //
6
+ // backtracie is free software: you can redistribute it and/or modify
7
+ // it under the terms of the GNU Lesser General Public License as published by
8
+ // the Free Software Foundation, either version 3 of the License, or
9
+ // (at your option) any later version.
10
+ //
11
+ // backtracie is distributed in the hope that it will be useful,
12
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ // GNU Lesser General Public License for more details.
15
+ //
16
+ // You should have received a copy of the GNU Lesser General Public License
17
+ // along with backtracie. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ #include "ruby/ruby.h"
20
+ #include "ruby/debug.h"
21
+
22
+ #include "extconf.h"
23
+
24
+ #include "ruby_3.0.0.h"
25
+
26
+ // Constants
27
+
28
+ #define MAX_STACK_DEPTH 2000 // FIXME: Need to handle when this is not enough
29
+
30
+ // Globals
31
+
32
+ static VALUE backtracie_module = Qnil;
33
+ static VALUE backtracie_location_class = Qnil;
34
+
35
+ // Function headers
36
+
37
+ static VALUE primitive_caller_locations(VALUE self);
38
+ static VALUE primitive_backtrace_locations(VALUE self, VALUE thread);
39
+ static VALUE caller_locations(VALUE self, VALUE thread, int ignored_stack_top_frames);
40
+ inline static VALUE new_location(VALUE absolute_path, VALUE base_label, VALUE label, VALUE lineno, VALUE path, VALUE debug);
41
+ static bool is_ruby_frame(VALUE ruby_frame);
42
+ static VALUE ruby_frame_to_location(VALUE frame, VALUE last_ruby_line, VALUE correct_label);
43
+ static VALUE cfunc_frame_to_location(VALUE frame, VALUE last_ruby_frame, VALUE last_ruby_line);
44
+ static VALUE debug_frame(VALUE frame, VALUE type);
45
+
46
+ // Macros
47
+
48
+ #define VALUE_COUNT(array) (sizeof(array) / sizeof(VALUE))
49
+
50
+ void Init_backtracie_native_extension(void) {
51
+ backtracie_module = rb_const_get(rb_cObject, rb_intern("Backtracie"));
52
+ rb_global_variable(&backtracie_module);
53
+
54
+ rb_define_module_function(backtracie_module, "backtrace_locations", primitive_backtrace_locations, 1);
55
+
56
+ // We need to keep a reference to Backtracie::Locations around, to create new instances
57
+ backtracie_location_class = rb_const_get(backtracie_module, rb_intern("Location"));
58
+ rb_global_variable(&backtracie_location_class);
59
+
60
+ VALUE backtracie_primitive_module = rb_define_module_under(backtracie_module, "Primitive");
61
+
62
+ rb_define_module_function(backtracie_primitive_module, "caller_locations", primitive_caller_locations, 0);
63
+ }
64
+
65
+ // Get array of Backtracie::Locations for a given thread; if thread is nil, returns for the current thread
66
+ static VALUE caller_locations(VALUE self, VALUE thread, int ignored_stack_top_frames) {
67
+ int stack_depth = 0;
68
+ VALUE frames[MAX_STACK_DEPTH];
69
+ VALUE correct_labels[MAX_STACK_DEPTH];
70
+ int lines[MAX_STACK_DEPTH];
71
+
72
+ if (thread == Qnil) {
73
+ // Get for own thread
74
+ stack_depth = modified_rb_profile_frames(0, MAX_STACK_DEPTH, frames, correct_labels, lines);
75
+ } else {
76
+ stack_depth = modified_rb_profile_frames_for_thread(thread, 0, MAX_STACK_DEPTH, frames, correct_labels, lines);
77
+ }
78
+
79
+ // Ignore the last frame -- seems to be an uninteresting VM frame. MRI itself seems to ignore the last frame in
80
+ // the implementation of backtrace_collect()
81
+ int ignored_stack_bottom_frames = 1;
82
+
83
+ stack_depth -= ignored_stack_bottom_frames;
84
+
85
+ VALUE locations = rb_ary_new_capa(stack_depth - ignored_stack_top_frames);
86
+
87
+ // MRI does not give us the path or line number for frames implemented using C code. The convention in
88
+ // Kernel#caller_locations is to instead use the path and line number of the last Ruby frame seen.
89
+ // Thus, we keep that frame here to able to replicate that behavior.
90
+ // (This is why we also iterate the frames array backwards below -- so that it's easier to keep the last_ruby_frame)
91
+ VALUE last_ruby_frame = Qnil;
92
+ VALUE last_ruby_line = Qnil;
93
+
94
+ for (int i = stack_depth - 1; i >= ignored_stack_top_frames; i--) {
95
+ VALUE frame = frames[i];
96
+ int line = lines[i];
97
+
98
+ VALUE location = Qnil;
99
+
100
+ if (is_ruby_frame(frame)) {
101
+ last_ruby_frame = frame;
102
+ last_ruby_line = INT2FIX(line);
103
+
104
+ location = ruby_frame_to_location(frame, last_ruby_line, correct_labels[i]);
105
+ } else {
106
+ location = cfunc_frame_to_location(frame, last_ruby_frame, last_ruby_line);
107
+ }
108
+
109
+ rb_ary_store(locations, i - ignored_stack_top_frames, location);
110
+ }
111
+
112
+ return locations;
113
+ }
114
+
115
+ static VALUE primitive_caller_locations(VALUE self) {
116
+ // Ignore:
117
+ // * the current stack frame (native)
118
+ // * the Backtracie.caller_locations that called us
119
+ // * the frame from the caller itself (since we're replicating the semantics of Kernel#caller_locations)
120
+ int ignored_stack_top_frames = 3;
121
+
122
+ return caller_locations(self, Qnil, ignored_stack_top_frames);
123
+ }
124
+
125
+ static VALUE primitive_backtrace_locations(VALUE self, VALUE thread) {
126
+ rb_funcall(backtracie_module, rb_intern("ensure_object_is_thread"), 1, thread);
127
+
128
+ int ignored_stack_top_frames = 0;
129
+
130
+ return caller_locations(self, thread, ignored_stack_top_frames);
131
+ }
132
+
133
+ inline static VALUE new_location(VALUE absolute_path, VALUE base_label, VALUE label, VALUE lineno, VALUE path, VALUE debug) {
134
+ VALUE arguments[] = { absolute_path, base_label, label, lineno, path, debug };
135
+ return rb_class_new_instance(VALUE_COUNT(arguments), arguments, backtracie_location_class);
136
+ }
137
+
138
+ static bool is_ruby_frame(VALUE frame) {
139
+ VALUE absolute_path = rb_profile_frame_absolute_path(frame);
140
+
141
+ return (rb_profile_frame_path(frame) != Qnil || absolute_path != Qnil) &&
142
+ (rb_funcall(absolute_path, rb_intern("=="), 1, rb_str_new2("<cfunc>")) == Qfalse);
143
+ }
144
+
145
+ static VALUE ruby_frame_to_location(VALUE frame, VALUE last_ruby_line, VALUE correct_label) {
146
+ return new_location(
147
+ rb_profile_frame_absolute_path(frame),
148
+ rb_profile_frame_base_label(frame),
149
+ rb_profile_frame_label(correct_label),
150
+ last_ruby_line,
151
+ rb_profile_frame_path(frame),
152
+ debug_frame(frame, rb_str_new2("ruby_frame"))
153
+ );
154
+ }
155
+
156
+ static VALUE cfunc_frame_to_location(VALUE frame, VALUE last_ruby_frame, VALUE last_ruby_line) {
157
+ VALUE method_name = rb_profile_frame_method_name(frame); // Replaces label and base_label in cfuncs
158
+
159
+ return new_location(
160
+ last_ruby_frame != Qnil ? rb_profile_frame_absolute_path(last_ruby_frame) : Qnil,
161
+ method_name,
162
+ method_name,
163
+ last_ruby_line,
164
+ last_ruby_frame != Qnil ? rb_profile_frame_path(last_ruby_frame) : Qnil,
165
+ debug_frame(frame, rb_str_new2("cfunc_frame"))
166
+ );
167
+ }
168
+
169
+ // Used to dump all the things we get from the rb_profile_frames API, for debugging
170
+ static VALUE debug_frame(VALUE frame, VALUE type) {
171
+ VALUE arguments[] = {
172
+ rb_profile_frame_path(frame),
173
+ rb_profile_frame_absolute_path(frame),
174
+ rb_profile_frame_label(frame),
175
+ rb_profile_frame_base_label(frame),
176
+ rb_profile_frame_full_label(frame),
177
+ rb_profile_frame_first_lineno(frame),
178
+ rb_profile_frame_classpath(frame),
179
+ rb_profile_frame_singleton_method_p(frame),
180
+ rb_profile_frame_method_name(frame),
181
+ rb_profile_frame_qualified_method_name(frame),
182
+ type
183
+ };
184
+ return rb_ary_new_from_values(VALUE_COUNT(arguments), arguments);
185
+ }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # backtracie: Ruby gem for beautiful backtraces
4
+ # Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
5
+ #
6
+ # This file is part of backtracie.
7
+ #
8
+ # backtracie is free software: you can redistribute it and/or modify
9
+ # it under the terms of the GNU Lesser General Public License as published by
10
+ # the Free Software Foundation, either version 3 of the License, or
11
+ # (at your option) any later version.
12
+ #
13
+ # backtracie is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ # GNU Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public License
19
+ # along with backtracie. If not, see <http://www.gnu.org/licenses/>.
20
+
21
+ require "mkmf"
22
+
23
+ # This warning gets really annoying when we include the Ruby mjit header file,
24
+ # let's omit it
25
+ $CFLAGS << " " << "-Wno-unused-function"
26
+
27
+ create_header
28
+ create_makefile "backtracie_native_extension"
@@ -0,0 +1,196 @@
1
+ // backtracie: Ruby gem for beautiful backtraces
2
+ // Copyright (C) 2021 Ivo Anjo <ivo@ivoanjo.me>
3
+ //
4
+ // This file is part of backtracie.
5
+ //
6
+ // backtracie is free software: you can redistribute it and/or modify
7
+ // it under the terms of the GNU Lesser General Public License as published by
8
+ // the Free Software Foundation, either version 3 of the License, or
9
+ // (at your option) any later version.
10
+ //
11
+ // backtracie is distributed in the hope that it will be useful,
12
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ // GNU Lesser General Public License for more details.
15
+ //
16
+ // You should have received a copy of the GNU Lesser General Public License
17
+ // along with backtracie. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ // -----------------------------------------------------------------------------
20
+ // The file below has modified versions of code extracted from the Ruby project.
21
+ // The Ruby project copyright and license follow:
22
+ // -----------------------------------------------------------------------------
23
+
24
+ // Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
25
+ // You can redistribute it and/or modify it under either the terms of the
26
+ // 2-clause BSDL (see the file BSDL), or the conditions below:
27
+
28
+ // 1. You may make and give away verbatim copies of the source form of the
29
+ // software without restriction, provided that you duplicate all of the
30
+ // original copyright notices and associated disclaimers.
31
+
32
+ // 2. You may modify your copy of the software in any way, provided that
33
+ // you do at least ONE of the following:
34
+
35
+ // a. place your modifications in the Public Domain or otherwise
36
+ // make them Freely Available, such as by posting said
37
+ // modifications to Usenet or an equivalent medium, or by allowing
38
+ // the author to include your modifications in the software.
39
+
40
+ // b. use the modified software only within your corporation or
41
+ // organization.
42
+
43
+ // c. give non-standard binaries non-standard names, with
44
+ // instructions on where to get the original software distribution.
45
+
46
+ // d. make other distribution arrangements with the author.
47
+
48
+ // 3. You may distribute the software in object code or binary form,
49
+ // provided that you do at least ONE of the following:
50
+
51
+ // a. distribute the binaries and library files of the software,
52
+ // together with instructions (in the manual page or equivalent)
53
+ // on where to get the original distribution.
54
+
55
+ // b. accompany the distribution with the machine-readable source of
56
+ // the software.
57
+
58
+ // c. give non-standard binaries non-standard names, with
59
+ // instructions on where to get the original software distribution.
60
+
61
+ // d. make other distribution arrangements with the author.
62
+
63
+ // 4. You may modify and include the part of the software into any other
64
+ // software (possibly commercial). But some files in the distribution
65
+ // are not written by the author, so that they are not under these terms.
66
+
67
+ // For the list of those files and their copying conditions, see the
68
+ // file LEGAL.
69
+
70
+ // 5. The scripts and library files supplied as input to or produced as
71
+ // output from the software do not automatically fall under the
72
+ // copyright of the software, but belong to whomever generated them,
73
+ // and may be sold commercially, and may be aggregated with this
74
+ // software.
75
+
76
+ // 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
77
+ // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
78
+ // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
79
+ // PURPOSE.
80
+
81
+ #include "rb_mjit_min_header-3.0.0.h"
82
+
83
+ #include "ruby_3.0.0.h"
84
+
85
+ /**********************************************************************
86
+
87
+ vm_backtrace.c -
88
+
89
+ $Author: ko1 $
90
+ created at: Sun Jun 03 00:14:20 2012
91
+
92
+ Copyright (C) 1993-2012 Yukihiro Matsumoto
93
+
94
+ **********************************************************************/
95
+
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
+ #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
+ }