ruby_ext_backtrace 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ruby_ext_backtrace.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Vasily Fedoseyev
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ # RubyExtBacktrace
2
+
3
+ Provides extended backtrace for ruby, including method parameters values.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'ruby_ext_backtrace'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install ruby_ext_backtrace
18
+
19
+ ## Usage
20
+
21
+ Once loaded, gem provides global method caller_ext, similar to `Kernel#caller`, but returning an array of hashes.
22
+
23
+ ```ruby
24
+
25
+ require 'pp'
26
+ require 'ruby_ext_backtrace'
27
+
28
+ def some_method2 param
29
+ pp caller(0); puts; pp caller_ext(0)
30
+ end
31
+
32
+ def some_method param1, param2=nil, &blk
33
+ yield "block_param0", "block_param1"
34
+ end
35
+
36
+ some_method(1111){|bp1,bp2|
37
+ some_method2 "some_method2_param"
38
+ }
39
+ ```
40
+
41
+ this outputs:
42
+
43
+ ```ruby
44
+
45
+ ["./test.rb:10:in `meth'",
46
+ "./test.rb:17:in `some_method2'",
47
+ "./test.rb:25:in `block in <main>'",
48
+ "./test.rb:21:in `some_method'",
49
+ "./test.rb:24:in `<main>'"]
50
+
51
+ [{:file=>"./test.rb",
52
+ :line=>10,
53
+ :method=>"meth",
54
+ :argc=>1,
55
+ 0=>"default_meth_param"},
56
+ {:file=>"./test.rb",
57
+ :line=>17,
58
+ :method=>"some_method2",
59
+ :argc=>1,
60
+ 0=>"some_method2_param"},
61
+ {:file=>"./test.rb",
62
+ :line=>25,
63
+ :method=>"block in <main>",
64
+ :argc=>2,
65
+ 0=>"block_param0",
66
+ 1=>"block_param1"},
67
+ {:file=>"./test.rb",
68
+ :line=>21,
69
+ :method=>"some_method",
70
+ :argc=>3,
71
+ 0=>1111,
72
+ 1=>nil,
73
+ 2=>#<Proc:0x007f8c5b02fff0@./test.rb:24>},
74
+ {:file=>"./test.rb", :line=>24, :method=>"<main>", :argc=>0}]
75
+ ```
76
+
77
+ Note that fetching parameters for CFUNCs with variable parameters (argc&lt;0) is not supported.
78
+ Also instead of "&lt;ruby&gt;" `:file` can be `nil`, so does `:method` for unknown methods.
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create new Pull Request
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/extensiontask'
3
+
4
+ Rake::ExtensionTask.new('ruby_ext_backtrace')
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: utf-8
3
+
4
+ require 'mkmf'
5
+ require 'debugger/ruby_core_source'
6
+
7
+ hdrs = proc {
8
+ have_header("vm_core.h") # and have_header("iseq.h")
9
+ }
10
+
11
+ dir_config("ruby") # allow user to pass in non-standard core include directory
12
+
13
+ if !Debugger::RubyCoreSource::create_makefile_with_core(hdrs, "ruby_ext_backtrace")
14
+ exit(1)
15
+ end
@@ -0,0 +1,117 @@
1
+ #include <ruby.h>
2
+
3
+ #define TRUE 1
4
+ #define FALSE 0
5
+
6
+ #ifdef RUBY_VM
7
+ #include "vm_core.h"
8
+ //#include "eval_intern.h"
9
+ #else
10
+ #error Need RubyVM, use another ruby
11
+ #endif
12
+
13
+ typedef int (rb_backtrace_iter_ext_func)(void *arg, VALUE file, int line, VALUE method_name, int argc, VALUE* argv);
14
+
15
+ static int
16
+ vm_backtrace_each_ext(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_ext_func *iter, void *arg)
17
+ {
18
+ const rb_control_frame_t *limit_cfp = th->cfp;
19
+ const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
20
+ VALUE file = Qnil;
21
+ int line_no = 0;
22
+
23
+ cfp -= 2;
24
+ //skip lev frames:
25
+ while (lev-- >= 0) {
26
+ if (++limit_cfp > cfp)
27
+ return FALSE;
28
+ }
29
+
30
+ if (init) (*init)(arg);
31
+
32
+ limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp);
33
+ if (th->vm->progname) file = th->vm->progname;
34
+
35
+ while (cfp > limit_cfp) {
36
+ if (cfp->iseq != 0) {
37
+ if (cfp->pc != 0) {
38
+ rb_iseq_t *iseq = cfp->iseq;
39
+
40
+ line_no = rb_vm_get_sourceline(cfp);
41
+ file = iseq->filename;
42
+
43
+ //arguments pushed this way: *reg_cfp->sp++ = recv; for (i = 0; i < argc; i++) *reg_cfp->sp++ = argv[i];
44
+ //local vars = cfp->iseq->local_size - cfp->iseq->arg_size;
45
+ //in memory: receiver params locals (bp(incremented))
46
+ VALUE* argv = &cfp->bp[- cfp->iseq->local_size - 1];
47
+ if ((*iter)(arg, file, line_no, iseq->name, cfp->iseq->arg_size, argv)) break;
48
+ }
49
+ } else
50
+ if (RUBYVM_CFUNC_FRAME_P(cfp)) {
51
+ ID id = cfp->me->def? cfp->me->def->original_id : cfp->me->called_id;
52
+ extern VALUE ruby_engine_name;
53
+ if (NIL_P(file)) file = ruby_engine_name;
54
+
55
+ if (id != ID_ALLOCATOR){
56
+ VALUE* argv = NULL;
57
+ // when argc==-1/-2(variable length params without/with splat) - the cfp has no info on params count :(
58
+ //TODO: infere from somewhere ex. find self in stack? (not guaranted btw, for example: obj.method(obj, 123, obj) - will find last param instead of self)
59
+ if(cfp->me->def->body.cfunc.argc >= 0){ //only fixed args
60
+ argv = &cfp->bp[- cfp->me->def->body.cfunc.argc - 2]; // args+self, bp was incremented thus minus 2
61
+ }
62
+ //file+line no from previous iseq frame
63
+ if((*iter)(arg, file, line_no, rb_id2str(id), cfp->me->def->body.cfunc.argc, argv)) break;
64
+ }
65
+ }
66
+ cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp);
67
+ }
68
+ return TRUE;
69
+ }
70
+
71
+ VALUE sym_file, sym_line, sym_method, sym_argc;
72
+
73
+ static int backtrace_iter(void *arg, VALUE file, int line, VALUE method_name, int argc, VALUE* argv)
74
+ {
75
+ VALUE arr = (VALUE)arg;
76
+
77
+ const char *filename = NIL_P(file) ? "ruby" : RSTRING_PTR(file);
78
+ VALUE hash = rb_hash_new();
79
+ rb_hash_aset(hash, sym_file, file); //may be nil
80
+ rb_hash_aset(hash, sym_line, INT2FIX(line));
81
+ rb_hash_aset(hash, sym_method, method_name); //may be nil
82
+ rb_hash_aset(hash, sym_argc, INT2FIX(argc));
83
+
84
+ int i;
85
+ for(i = 0; i < argc; i++){
86
+ rb_hash_aset(hash, INT2FIX(i), argv[i]);
87
+ }
88
+ rb_ary_unshift(arr, hash);
89
+ return FALSE;
90
+ }
91
+
92
+ // trim(1 by default, but may pass 0 to include current method in trace)
93
+ // like in 'Kernel#caller'
94
+ static VALUE rb_caller_ext(int argc, VALUE argv[], VALUE self){
95
+ int trim = 1;
96
+ if(argc > 1)
97
+ rb_raise(rb_eArgError, "wrong number of arguments(%d for 0-1)", argc);
98
+ if(argc > 0){
99
+ trim = FIX2INT(argv[0]);
100
+ }
101
+
102
+ rb_thread_t *th = GET_THREAD();
103
+ //we know frames count, thus array size is known too, eliminate relocations
104
+ int frames = (int)((rb_control_frame_t*)(th->stack + th->stack_size) - th->cfp - 3 - trim);
105
+
106
+ VALUE res = rb_ary_new2(frames);
107
+ vm_backtrace_each_ext(th, trim, NULL/*init func*/, backtrace_iter, (void*)res /*param*/);
108
+ return res;
109
+ }
110
+
111
+ void Init_ruby_ext_backtrace(){
112
+ sym_file = ID2SYM(rb_intern("file"));
113
+ sym_line = ID2SYM(rb_intern("line"));
114
+ sym_method = ID2SYM(rb_intern("method"));
115
+ sym_argc = ID2SYM(rb_intern("argc"));
116
+ rb_define_global_function("caller_ext", rb_caller_ext, -1);
117
+ }
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: utf-8
3
+
4
+ $:.unshift(File.dirname(__FILE__))
5
+
6
+ require 'pp'
7
+ require 'ruby_ext_backtrace'
8
+
9
+ def some_method2 param
10
+ pp caller(0); puts; pp caller_ext(0)
11
+ end
12
+
13
+ def some_method param1, param2=nil, &blk
14
+ yield "block_param0", "block_param1"
15
+ end
16
+
17
+ some_method(1111){|bp1,bp2|
18
+ some_method2 "some_method2_param"
19
+ }
@@ -0,0 +1,8 @@
1
+ require "ruby_ext_backtrace/version"
2
+
3
+ require 'rbconfig'
4
+ require "ruby_ext_backtrace.#{RbConfig::CONFIG['DLEXT']}"
5
+
6
+ module RubyExtBacktrace
7
+ # Everything is in extension atm
8
+ end
@@ -0,0 +1,3 @@
1
+ module RubyExtBacktrace
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ruby_ext_backtrace/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "ruby_ext_backtrace"
8
+ gem.version = RubyExtBacktrace::VERSION
9
+ gem.authors = ["Vasily Fedoseyev"]
10
+ gem.email = ["vasilyfedoseyev@gmail.com"]
11
+ gem.description = %q{Extended backtrace for ruby}
12
+ gem.summary = %q{have you ever wanted to see method parameters in backtrace?}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.extensions = "ext/ruby_ext_backtrace/extconf.rb"
21
+
22
+ gem.add_dependency "debugger-ruby_core_source"
23
+ gem.add_development_dependency('rake-compiler')
24
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby_ext_backtrace
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Vasily Fedoseyev
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: debugger-ruby_core_source
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake-compiler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Extended backtrace for ruby
47
+ email:
48
+ - vasilyfedoseyev@gmail.com
49
+ executables: []
50
+ extensions:
51
+ - ext/ruby_ext_backtrace/extconf.rb
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - Gemfile
56
+ - LICENSE.txt
57
+ - README.md
58
+ - Rakefile
59
+ - ext/ruby_ext_backtrace/extconf.rb
60
+ - ext/ruby_ext_backtrace/ruby_ext_backtrace.c
61
+ - ext/ruby_ext_backtrace/test.rb
62
+ - lib/ruby_ext_backtrace.rb
63
+ - lib/ruby_ext_backtrace/version.rb
64
+ - ruby_ext_backtrace.gemspec
65
+ homepage: ''
66
+ licenses: []
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ segments:
78
+ - 0
79
+ hash: -835126318862271968
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ segments:
87
+ - 0
88
+ hash: -835126318862271968
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.24
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: have you ever wanted to see method parameters in backtrace?
95
+ test_files: []