c_location 0.1 → 0.2

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.
data/README.md CHANGED
@@ -0,0 +1,63 @@
1
+ Given various assumptions about your setup, provides `Method#c_location`, which is the
2
+ equivalent of `Method#source_location` for methods that were written in C.
3
+
4
+ Requirements
5
+ ============
6
+
7
+ On Mac OS X, you will need the `nm` tool that's bundled with Xcode; and the `gobjdump`
8
+ tool that you can get with `brew install binutils`.
9
+
10
+ On Linux you'll need the `objdump` tool, on Debian/Ubuntu it's obtainable with `apt-get install
11
+ binutils`, I assume other distros are similar.
12
+
13
+ On all systems you'll need your Rubies compiled with debug information (seems to be the
14
+ default on Linux). If you're using `rvm` add `export rvm_configure_flags="CFLAGS=-g"` to
15
+ `~/.rvmrc`.
16
+
17
+ If it still doesn't work — try running the commands that are found in
18
+ `lib/c_location/resolver.rb` manually, and see where the problem is.
19
+
20
+
21
+ How does this even work?!
22
+ =========================
23
+
24
+ 1. Find a pointer to the C function that's behind a ruby method (most of the code in
25
+ `ext/c_location.c` deals with doing this for various versions of Ruby — it's certainly
26
+ not exposed in the API!)
27
+
28
+ 2. Find the shared object file that contains this C function, and the offset in that file
29
+ that the function's compiled code resides. This is done using the non-standard (but
30
+ widespread) `dladdr()` function. (See man `dladdr`).
31
+
32
+ 3. (Mac OS X only). Use `nm` to find the original library that the shared object file was
33
+ built from. (This is because `.bundle` files don't contain the debugging information
34
+ directly).
35
+
36
+ 4. use `objdump` to read the DWARF data embedded in the shared object file when it was
37
+ compiled with the `-g` flag.
38
+
39
+ 5. Use some heuristics to guess the directories that might include that file based on the
40
+ location of the object file on disk, and look for a correctly named file there.
41
+
42
+ (In short, lots and lots of string).
43
+
44
+
45
+ TODO
46
+ ====
47
+
48
+ If possible, it'd be nice to have fewer external calls. Perhaps the data we're using `nm`
49
+ for could be done in Ruby without too much help; we could even try bundling `libdwarf` to
50
+ avoid the dependency on `objdump`.
51
+
52
+ It'd be really cool to make the Pry `edit-method` command work for C extensions. I think
53
+ this is just a matter of writing more code: have `edit-method` work as normal, and then
54
+ after closing the editor run `make` in the right directory; then copy the `.so` file into
55
+ a new directory and then require it. (the Init_foo method should then just overwrite all
56
+ the existing setup).
57
+
58
+ Meta-fu
59
+ =======
60
+
61
+ Released under the MIT License. Bug reports and pull requests welcome.
62
+
63
+ Do not use this in production :p.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'c_location'
5
+
6
+ puts CompiledLocation.instance_method(:compiled_location).c_location.inspect
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'c_location'
5
+
6
+ puts Math.method(:sin).c_location.inspect
data/ext/c_location.c CHANGED
@@ -1,15 +1,4 @@
1
- /* Load dladdr() function */
2
- #include <dlfcn.h>
3
-
4
- #include "ruby.h"
5
-
6
- // TODO: why is it necessary to define this here? It ought to be in <dlfcn.h>
7
- typedef struct {
8
- const char *dli_fname; /* Pathname of shared object that contains address */
9
- void *dli_fbase; /* Address at which shared object is loaded */
10
- const char *dli_sname; /* Name of nearest symbol with address lower than addr */
11
- void *dli_saddr; /* Exact address of symbol named in dli_sname */
12
- } Dl2_info;
1
+ #include "c_location.h"
13
2
 
14
3
  /* Given the pointer to a C function (called "name" for error handling)
15
4
  * return the filename and offset of the compiled byte code for that function.
@@ -50,78 +39,8 @@ Init_c_location()
50
39
 
51
40
  #ifdef RUBY_19
52
41
 
53
- typedef enum {
54
- NOEX_PUBLIC = 0x00,
55
- NOEX_NOSUPER = 0x01,
56
- NOEX_PRIVATE = 0x02,
57
- NOEX_PROTECTED = 0x04,
58
- NOEX_MASK = 0x06,
59
- NOEX_BASIC = 0x08,
60
- NOEX_UNDEF = NOEX_NOSUPER,
61
- NOEX_MODFUNC = 0x12,
62
- NOEX_SUPER = 0x20,
63
- NOEX_VCALL = 0x40,
64
- NOEX_RESPONDS = 0x80
65
- } rb_method_flag_t;
66
-
67
- typedef enum {
68
- VM_METHOD_TYPE_ISEQ,
69
- VM_METHOD_TYPE_CFUNC,
70
- VM_METHOD_TYPE_ATTRSET,
71
- VM_METHOD_TYPE_IVAR,
72
- VM_METHOD_TYPE_BMETHOD,
73
- VM_METHOD_TYPE_ZSUPER,
74
- VM_METHOD_TYPE_UNDEF,
75
- VM_METHOD_TYPE_NOTIMPLEMENTED,
76
- VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
77
- VM_METHOD_TYPE_MISSING /* wrapper for method_missing(id) */
78
- } rb_method_type_t;
79
-
80
- typedef struct rb_method_cfunc_struct {
81
- VALUE (*func)(ANYARGS);
82
- int argc;
83
- } rb_method_cfunc_t;
84
-
85
- typedef struct rb_method_attr_struct {
86
- ID id;
87
- VALUE location;
88
- } rb_method_attr_t;
89
-
90
- typedef struct rb_iseq_struct rb_iseq_t;
91
- typedef struct rb_method_definition_struct {
92
- rb_method_type_t type; /* method type */
93
- ID original_id;
94
- union {
95
- rb_iseq_t *iseq; /* should be mark */
96
- rb_method_cfunc_t cfunc;
97
- rb_method_attr_t attr;
98
- VALUE proc; /* should be mark */
99
- enum method_optimized_type {
100
- OPTIMIZED_METHOD_TYPE_SEND,
101
- OPTIMIZED_METHOD_TYPE_CALL
102
- } optimize_type;
103
- } body;
104
- int alias_count;
105
- } rb_method_definition_t;
106
-
107
- typedef struct rb_method_entry_struct {
108
- rb_method_flag_t flag;
109
- char mark;
110
- rb_method_definition_t *def;
111
- ID called_id;
112
- VALUE klass; /* should be mark */
113
- } rb_method_entry_t;
114
-
115
42
  #ifdef RUBY_193
116
43
 
117
- struct METHOD {
118
- VALUE recv;
119
- VALUE rclass;
120
- ID id;
121
- rb_method_entry_t *me;
122
- struct unlinked_method_entry_list_entry *ume;
123
- };
124
-
125
44
  static VALUE compiled_location(VALUE self)
126
45
  {
127
46
  struct METHOD *data;
@@ -142,14 +61,6 @@ static VALUE compiled_location(VALUE self)
142
61
 
143
62
  #else /* RUBY_192 */
144
63
 
145
- struct METHOD {
146
- VALUE recv;
147
- VALUE rclass;
148
- ID id;
149
- rb_method_entry_t me;
150
- struct unlinked_method_entry_list_entry *ume;
151
- };
152
-
153
64
  static VALUE compiled_location(VALUE self)
154
65
  {
155
66
  struct METHOD *data;
@@ -170,20 +81,8 @@ static VALUE compiled_location(VALUE self)
170
81
 
171
82
 
172
83
  #endif
173
-
174
84
  #else /* RUBY18 */
175
85
 
176
- #include "node.h"
177
-
178
- /* Copy-pasted out of Ruby 1.8.7, not part of the official C API.*/
179
- struct METHOD {
180
- VALUE klass, rklass;
181
- VALUE recv;
182
- ID id, oid;
183
- int safe_level;
184
- NODE *body;
185
- };
186
-
187
86
  static VALUE compiled_location(VALUE self)
188
87
  {
189
88
  struct METHOD *data;
@@ -197,6 +96,4 @@ static VALUE compiled_location(VALUE self)
197
96
 
198
97
  return file_and_offset(*data->body->nd_cfnc, StringValueCStr(name));
199
98
  }
200
-
201
-
202
99
  #endif
data/ext/c_location.h ADDED
@@ -0,0 +1,114 @@
1
+ /* Load dladdr() function */
2
+ #include <dlfcn.h>
3
+
4
+ #include "ruby.h"
5
+
6
+ // TODO: why is it necessary to define this here? It ought to be in <dlfcn.h>
7
+ typedef struct {
8
+ const char *dli_fname; /* Pathname of shared object that contains address */
9
+ void *dli_fbase; /* Address at which shared object is loaded */
10
+ const char *dli_sname; /* Name of nearest symbol with address lower than addr */
11
+ void *dli_saddr; /* Exact address of symbol named in dli_sname */
12
+ } Dl2_info;
13
+
14
+
15
+ #ifdef RUBY_19
16
+
17
+ typedef enum {
18
+ NOEX_PUBLIC = 0x00,
19
+ NOEX_NOSUPER = 0x01,
20
+ NOEX_PRIVATE = 0x02,
21
+ NOEX_PROTECTED = 0x04,
22
+ NOEX_MASK = 0x06,
23
+ NOEX_BASIC = 0x08,
24
+ NOEX_UNDEF = NOEX_NOSUPER,
25
+ NOEX_MODFUNC = 0x12,
26
+ NOEX_SUPER = 0x20,
27
+ NOEX_VCALL = 0x40,
28
+ NOEX_RESPONDS = 0x80
29
+ } rb_method_flag_t;
30
+
31
+ typedef enum {
32
+ VM_METHOD_TYPE_ISEQ,
33
+ VM_METHOD_TYPE_CFUNC,
34
+ VM_METHOD_TYPE_ATTRSET,
35
+ VM_METHOD_TYPE_IVAR,
36
+ VM_METHOD_TYPE_BMETHOD,
37
+ VM_METHOD_TYPE_ZSUPER,
38
+ VM_METHOD_TYPE_UNDEF,
39
+ VM_METHOD_TYPE_NOTIMPLEMENTED,
40
+ VM_METHOD_TYPE_OPTIMIZED, /* Kernel#send, Proc#call, etc */
41
+ VM_METHOD_TYPE_MISSING /* wrapper for method_missing(id) */
42
+ } rb_method_type_t;
43
+
44
+ typedef struct rb_method_cfunc_struct {
45
+ VALUE (*func)(ANYARGS);
46
+ int argc;
47
+ } rb_method_cfunc_t;
48
+
49
+ typedef struct rb_method_attr_struct {
50
+ ID id;
51
+ VALUE location;
52
+ } rb_method_attr_t;
53
+
54
+ typedef struct rb_iseq_struct rb_iseq_t;
55
+ typedef struct rb_method_definition_struct {
56
+ rb_method_type_t type; /* method type */
57
+ ID original_id;
58
+ union {
59
+ rb_iseq_t *iseq; /* should be mark */
60
+ rb_method_cfunc_t cfunc;
61
+ rb_method_attr_t attr;
62
+ VALUE proc; /* should be mark */
63
+ enum method_optimized_type {
64
+ OPTIMIZED_METHOD_TYPE_SEND,
65
+ OPTIMIZED_METHOD_TYPE_CALL
66
+ } optimize_type;
67
+ } body;
68
+ int alias_count;
69
+ } rb_method_definition_t;
70
+
71
+ typedef struct rb_method_entry_struct {
72
+ rb_method_flag_t flag;
73
+ char mark;
74
+ rb_method_definition_t *def;
75
+ ID called_id;
76
+ VALUE klass; /* should be mark */
77
+ } rb_method_entry_t;
78
+
79
+ #ifdef RUBY_193
80
+
81
+ struct METHOD {
82
+ VALUE recv;
83
+ VALUE rclass;
84
+ ID id;
85
+ rb_method_entry_t *me;
86
+ struct unlinked_method_entry_list_entry *ume;
87
+ };
88
+
89
+ #else /* RUBY_192 */
90
+
91
+ struct METHOD {
92
+ VALUE recv;
93
+ VALUE rclass;
94
+ ID id;
95
+ rb_method_entry_t me;
96
+ struct unlinked_method_entry_list_entry *ume;
97
+ };
98
+
99
+ #endif
100
+
101
+ #else /* RUBY18 */
102
+
103
+ #include "node.h"
104
+
105
+ /* Copy-pasted out of Ruby 1.8.7, not part of the official C API.*/
106
+ struct METHOD {
107
+ VALUE klass, rklass;
108
+ VALUE recv;
109
+ ID id, oid;
110
+ int safe_level;
111
+ NODE *body;
112
+ };
113
+
114
+ #endif
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: c_location
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-08 00:00:00.000000000Z
12
+ date: 2012-04-09 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: Allows you to find the source location of methods written in C
15
15
  email: conrad.irwin@gmail.com
@@ -22,6 +22,9 @@ files:
22
22
  - lib/c_location/resolver.rb
23
23
  - ext/extconf.rb
24
24
  - ext/c_location.c
25
+ - ext/c_location.h
26
+ - example/c_extension_location.rb
27
+ - example/inbuilt_location.rb
25
28
  - README.md
26
29
  - LICENSE.MIT
27
30
  homepage: http://github.com/ConradIrwin/c_location
@@ -50,4 +53,3 @@ signing_key:
50
53
  specification_version: 3
51
54
  summary: ! 'Adds a #c_location to Method and UnboundMethod objects.'
52
55
  test_files: []
53
- has_rdoc: