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 +63 -0
- data/example/c_extension_location.rb +6 -0
- data/example/inbuilt_location.rb +6 -0
- data/ext/c_location.c +1 -104
- data/ext/c_location.h +114 -0
- metadata +5 -3
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.
|
data/ext/c_location.c
CHANGED
@@ -1,15 +1,4 @@
|
|
1
|
-
|
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.
|
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-
|
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:
|