ruby-dtrace 0.0.6 → 0.2.8

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.
Files changed (81) hide show
  1. data/History.txt +21 -0
  2. data/Manifest.txt +86 -19
  3. data/README.txt +48 -6
  4. data/Rakefile +61 -20
  5. data/examples/scsi.rb +1 -1
  6. data/ext/dof/Makefile +154 -0
  7. data/ext/dof/constants.c +57 -0
  8. data/ext/dof/dof.h +56 -0
  9. data/ext/dof/dof_api.c +58 -0
  10. data/ext/dof/dof_helper.c +82 -0
  11. data/ext/dof/extconf.rb +4 -0
  12. data/ext/dof/file.c +90 -0
  13. data/ext/dof/generator.c +9 -0
  14. data/ext/dof/header.c +79 -0
  15. data/ext/dof/mkmf.log +10 -0
  16. data/ext/dof/parser.c +415 -0
  17. data/ext/dof/parser.h +10 -0
  18. data/ext/dof/section.c +312 -0
  19. data/ext/dtrace_aggdata.c +2 -2
  20. data/ext/dtrace_api.c +46 -34
  21. data/ext/dtrace_api.h +31 -7
  22. data/ext/dtrace_bufdata.c +3 -3
  23. data/ext/dtrace_hdl.c +66 -3
  24. data/ext/dtrace_probedata.c +4 -4
  25. data/ext/{dtrace_probe.c → dtrace_probedesc.c} +7 -7
  26. data/ext/extconf.rb +25 -0
  27. data/ext/i386-darwin/dtrace_probe.c +278 -0
  28. data/ext/i386-solaris/dtrace_probe.c +225 -0
  29. data/ext/stubs.txt +78 -0
  30. data/lib/dtrace.rb +34 -13
  31. data/lib/dtrace/aggregate.rb +40 -0
  32. data/lib/dtrace/aggregateset.rb +19 -0
  33. data/lib/dtrace/consumer.rb +174 -0
  34. data/lib/dtrace/data.rb +82 -0
  35. data/lib/dtrace/dof.rb +8 -0
  36. data/lib/dtrace/dof/file.rb +64 -0
  37. data/lib/dtrace/dof/section.rb +75 -0
  38. data/lib/dtrace/dof/section/strtab.rb +28 -0
  39. data/lib/{dtraceprintfrecord.rb → dtrace/printfrecord.rb} +4 -2
  40. data/lib/dtrace/probe.rb +3 -6
  41. data/lib/dtrace/probedata.rb +23 -0
  42. data/lib/dtrace/probedesc.rb +15 -0
  43. data/lib/dtrace/provider.rb +190 -169
  44. data/lib/dtrace/provider/klass.rb +33 -0
  45. data/lib/dtrace/provider/probedef.rb +24 -0
  46. data/lib/{dtracerecord.rb → dtrace/record.rb} +4 -2
  47. data/lib/{dtracestackrecord.rb → dtrace/stackrecord.rb} +10 -8
  48. data/lib/dtrace/version.rb +9 -0
  49. data/lib/dtraceconsumer.rb +3 -167
  50. data/plugin/dtrace/lib/dtracer.rb +4 -4
  51. data/test/apple-dof +0 -0
  52. data/test/disabled_probe_effect.txt +19 -0
  53. data/test/dof +0 -0
  54. data/test/dof2 +0 -0
  55. data/test/test_disabled_probe_effect.rb +56 -0
  56. data/test/test_dof_generator.rb +142 -0
  57. data/test/test_dof_helper.rb +106 -0
  58. data/test/test_dof_parser.rb +27 -0
  59. data/test/test_dof_providers.rb +278 -0
  60. data/test/test_dof_strtabs.rb +98 -0
  61. data/test/test_dtrace.rb +67 -1
  62. data/test/test_dtrace_aggregates.rb +5 -5
  63. data/test/test_dtrace_drops_errors.rb +5 -5
  64. data/test/test_dtrace_probe.rb +385 -0
  65. data/test/test_dtrace_probes.rb +414 -0
  66. data/test/test_dtrace_processes.rb +2 -2
  67. data/test/test_dtrace_profile.rb +12 -12
  68. data/test/test_dtrace_provider.rb +138 -0
  69. data/test/test_dtrace_repeat.rb +1 -1
  70. data/test/test_dtrace_rubyprobe.rb +3 -1
  71. data/test/test_dtrace_typefilter.rb +9 -9
  72. data/test/test_legacy_consumer.rb +56 -0
  73. metadata +112 -71
  74. data/lib/dtrace/provider/osx.rb +0 -25
  75. data/lib/dtrace/provider/solaris.rb +0 -29
  76. data/lib/dtraceaggregate.rb +0 -37
  77. data/lib/dtraceaggregateset.rb +0 -17
  78. data/lib/dtracedata.rb +0 -80
  79. data/lib/dtraceprobe.rb +0 -13
  80. data/lib/dtraceprobedata.rb +0 -21
  81. data/test/test_dynusdt.rb +0 -135
@@ -0,0 +1,278 @@
1
+ /* Ruby-Dtrace
2
+ * (c) 2008 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ #include <errno.h>
8
+ #include <stdlib.h>
9
+ #include <sys/mman.h>
10
+
11
+ RUBY_EXTERN VALUE eDtraceException;
12
+
13
+ #define FUNC_SIZE 128 /* 32 bytes of is_enabled, plus then good for 16
14
+ arguments: 16 + 7 * argc */
15
+ #define IS_ENABLED_FUNC_LEN 32
16
+
17
+ /* :nodoc: */
18
+ VALUE
19
+ dtraceprobe_init(VALUE self, VALUE rargc)
20
+ {
21
+ dtrace_probe_t *probe;
22
+ uint8_t *ip;
23
+ int i;
24
+ int argc = FIX2INT(rargc);
25
+
26
+ Data_Get_Struct(self, dtrace_probe_t, probe);
27
+
28
+ /* First initialise the is_enabled tracepoint */
29
+ uint8_t insns[FUNC_SIZE] = {
30
+ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08,
31
+ 0x33, 0xc0,
32
+ 0x90, 0x90, 0x90,
33
+ 0xc9, 0xc3
34
+ };
35
+
36
+ #define OP_PUSHL_EBP 0x55
37
+ #define OP_MOVL_ESP_EBP_U 0x89
38
+ #define OP_MOVL_ESP_EBP_L 0xe5
39
+ #define OP_SUBL_N_ESP_U 0x83
40
+ #define OP_SUBL_N_ESP_L 0xec
41
+ #define OP_PUSHL_N_EBP_U 0xff
42
+ #define OP_PUSHL_N_EBP_L 0x75
43
+ #define OP_NOP 0x90
44
+ #define OP_ADDL_ESP_U 0x83
45
+ #define OP_ADDL_ESP_L 0xc4
46
+ #define OP_LEAVE 0xc9
47
+ #define OP_RET 0xc3
48
+ #define OP_MOVL_EAX_U 0x8b
49
+ #define OP_MOVL_EAX_L 0x45
50
+ #define OP_MOVL_ESP 0x89
51
+
52
+ /* Set up probe function */
53
+ ip = insns + IS_ENABLED_FUNC_LEN;
54
+
55
+ *ip++ = OP_PUSHL_EBP;
56
+ *ip++ = OP_MOVL_ESP_EBP_U;
57
+ *ip++ = OP_MOVL_ESP_EBP_L;
58
+ *ip++ = OP_SUBL_N_ESP_U;
59
+ *ip++ = OP_SUBL_N_ESP_L;
60
+
61
+ switch(argc) {
62
+ case 0:
63
+ case 1:
64
+ case 2:
65
+ case 3:
66
+ case 4:
67
+ case 5:
68
+ case 6:
69
+ *ip++ = 0x18;
70
+ break;
71
+ case 7:
72
+ case 8:
73
+ *ip++ = 0x28;
74
+ break;
75
+ }
76
+
77
+ /* args */
78
+ for (i = (4*argc - 4); i >= 0; i -= 4) {
79
+ /* mov 0xN(%ebp),%eax */
80
+ *ip++ = OP_MOVL_EAX_U;
81
+ *ip++ = OP_MOVL_EAX_L;
82
+ *ip++ = i + 8;
83
+ /* mov %eax,N(%esp) */
84
+ *ip++ = OP_MOVL_ESP;
85
+ if (i > 0) {
86
+ *ip++ = 0x44;
87
+ *ip++ = 0x24;
88
+ *ip++ = i;
89
+ }
90
+ else {
91
+ *ip++ = 0x04;
92
+ *ip++ = 0x24;
93
+ }
94
+ }
95
+
96
+ /* tracepoint */
97
+ *ip++ = 0x90;
98
+ *ip++ = 0x0f;
99
+ *ip++ = 0x1f;
100
+ *ip++ = 0x40;
101
+ *ip++ = 0x00;
102
+
103
+ /* ret */
104
+ *ip++ = OP_LEAVE;
105
+ *ip++ = OP_RET;
106
+
107
+ /* allocate memory on a page boundary, for mprotect */
108
+ probe->func = (void *)valloc(FUNC_SIZE);
109
+ if (probe->func < 0) {
110
+ rb_raise(eDtraceException, "malloc failed: %s\n", strerror(errno));
111
+ return Qnil;
112
+ }
113
+
114
+ if ((mprotect((void *)probe->func, FUNC_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) < 0) {
115
+ rb_raise(eDtraceException, "mprotect failed: %s\n", strerror(errno));
116
+ return Qnil;
117
+ }
118
+
119
+ if ((memcpy(probe->func, insns, FUNC_SIZE)) < 0) {
120
+ rb_raise(eDtraceException, "memcpy failed: %s\n", strerror(errno));
121
+ return Qnil;
122
+ }
123
+
124
+ return self;
125
+ }
126
+
127
+ VALUE dtraceprobe_free(void *arg)
128
+ {
129
+ dtrace_probe_t *probe = (dtrace_probe_t *)arg;
130
+
131
+ if (probe) {
132
+ free(probe->func);
133
+ free(probe);
134
+ }
135
+ }
136
+
137
+ VALUE dtraceprobe_alloc(VALUE klass)
138
+ {
139
+ VALUE obj;
140
+ dtrace_probe_t *probe;
141
+
142
+ probe = ALLOC(dtrace_probe_t);
143
+ if (!probe) {
144
+ rb_raise(eDtraceException, "alloc failed");
145
+ return Qnil;
146
+ }
147
+
148
+ /* no mark function: no ruby objects hung off this struct */
149
+ obj = Data_Wrap_Struct(klass, NULL, dtraceprobe_free, probe);
150
+ return obj;
151
+ }
152
+
153
+ /*
154
+ * Returns the address of the probe's generated code.
155
+ */
156
+ VALUE dtraceprobe_addr(VALUE self)
157
+ {
158
+ dtrace_probe_t *probe;
159
+
160
+ Data_Get_Struct(self, dtrace_probe_t, probe);
161
+ return INT2FIX(probe->func);
162
+ }
163
+
164
+ /*
165
+ * Returns whether or not this probe is currently enabled, by invoking
166
+ * the is-enabled tracepoint attached to the probe.
167
+ */
168
+ VALUE dtraceprobe_is_enabled(VALUE self)
169
+ {
170
+ dtrace_probe_t *probe;
171
+
172
+ Data_Get_Struct(self, dtrace_probe_t, probe);
173
+ return ((int)(*probe->func)()) ? Qtrue : Qfalse;
174
+ }
175
+
176
+ /*
177
+ * Fires the probe, converting arguments based on the data provided -
178
+ * no validation is done against the probe's declared types.
179
+ */
180
+ VALUE dtraceprobe_fire(int argc, VALUE *ruby_argv, VALUE self) {
181
+ dtrace_probe_t *probe;
182
+ int i;
183
+ void *argv[8]; // probe argc max for now.
184
+ void (*func)();
185
+
186
+ Data_Get_Struct(self, dtrace_probe_t, probe);
187
+
188
+ /* munge Ruby values to either char *s or ints. */
189
+ for (i = 0; i < argc; i++) {
190
+ switch (TYPE(ruby_argv[i])) {
191
+ case T_STRING:
192
+ argv[i] = (void *)RSTRING(ruby_argv[i])->ptr;
193
+ break;
194
+ case T_FIXNUM:
195
+ argv[i] = (void *)FIX2INT(ruby_argv[i]);
196
+ break;
197
+ default:
198
+ rb_raise(eDtraceException, "type of arg[%d] is not string or fixnum", i);
199
+ break;
200
+ }
201
+ }
202
+
203
+ func = (void (*)())(probe->func + IS_ENABLED_FUNC_LEN);
204
+
205
+ switch (argc) {
206
+ case 0:
207
+ (void)(*func)();
208
+ break;
209
+ case 1:
210
+ (void)(*func)(argv[0]);
211
+ break;
212
+ case 2:
213
+ (void)(*func)(argv[0], argv[1]);
214
+ break;
215
+ case 3:
216
+ (void)(*func)(argv[0], argv[1], argv[2]);
217
+ break;
218
+ case 4:
219
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3]);
220
+ break;
221
+ case 5:
222
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
223
+ argv[4]);
224
+ break;
225
+ case 6:
226
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
227
+ argv[4], argv[5]);
228
+ break;
229
+ case 7:
230
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
231
+ argv[4], argv[5], argv[6]);
232
+ break;
233
+ case 8:
234
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
235
+ argv[4], argv[5], argv[6], argv[7]);
236
+ break;
237
+ default:
238
+ rb_raise(eDtraceException, "probe argc max is 8");
239
+ break;
240
+ }
241
+
242
+ return Qnil;
243
+ }
244
+
245
+ /*
246
+ * Returns the offset for this probe in the PROFFS section, based on
247
+ * the location of the DOF, and the location of this probe.
248
+ */
249
+ VALUE dtraceprobe_probe_offset(VALUE self, VALUE file_addr, VALUE argc)
250
+ {
251
+ void *probe_addr;
252
+ int offset;
253
+ probe_addr = (void *)FIX2INT(rb_funcall(self, rb_intern("addr"), 0));
254
+ switch FIX2INT(argc) {
255
+ case 0:
256
+ offset = 40; /* 32 + 6 + 2 */
257
+ break;
258
+ case 1:
259
+ offset = 46; /* 32 + 6 + 6 + 2 */
260
+ break;
261
+ default:
262
+ offset = 46 + (FIX2INT(argc)-1) * 7; /* 32 + 6 + 6 + 7 per subsequent arg + 2 */
263
+ break;
264
+ }
265
+ return INT2FIX((int)probe_addr - (int)FIX2INT(file_addr) + offset);
266
+ }
267
+
268
+ /*
269
+ * Returns the offset for this probe's is-enabled tracepoint in the
270
+ * PRENOFFS section, based on the location of the DOF, and the
271
+ * location of this probe.
272
+ */
273
+ VALUE dtraceprobe_is_enabled_offset(VALUE self, VALUE file_addr)
274
+ {
275
+ void *probe_addr;
276
+ probe_addr = (void *)FIX2INT(rb_funcall(self, rb_intern("addr"), 0));
277
+ return INT2FIX((int)probe_addr - (int)FIX2INT(file_addr) + 8);
278
+ }
@@ -0,0 +1,225 @@
1
+ /* Ruby-Dtrace
2
+ * (c) 2008 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ #include <errno.h>
8
+ #include <stdlib.h>
9
+ #include <sys/mman.h>
10
+
11
+ RUBY_EXTERN VALUE eDtraceException;
12
+
13
+ #define FUNC_SIZE 96 /* 32 bytes of is_enabled, plus then good for 16
14
+ arguments: 16 + 3 * argc */
15
+ #define IS_ENABLED_FUNC_LEN 32
16
+
17
+ /* :nodoc: */
18
+ VALUE dtraceprobe_init(VALUE self, VALUE rargc)
19
+ {
20
+ dtrace_probe_t *probe;
21
+ uint8_t *ip;
22
+ int i;
23
+ int argc = FIX2INT(rargc);
24
+
25
+ Data_Get_Struct(self, dtrace_probe_t, probe);
26
+
27
+ /* First initialise the is_enabled tracepoint */
28
+ uint8_t insns[FUNC_SIZE] = {
29
+ 0x55, 0x89, 0xe5, 0x83, 0xec, 0x08,
30
+ 0x33, 0xc0,
31
+ 0x90, 0x90, 0x90,
32
+ 0x89, 0x45, 0xfc, 0x83, 0x7d, 0xfc,
33
+ 0x00, 0x0f, 0x95, 0xc0, 0x0f, 0xb6,
34
+ 0xc0, 0x89, 0x45, 0xfc, 0x8b, 0x45,
35
+ 0xfc,
36
+ 0xc9, 0xc3
37
+ };
38
+
39
+ #define OP_PUSHL_EBP 0x55
40
+ #define OP_MOVL_ESP_EBP 0x89, 0xe5
41
+ #define OP_SUBL_N_ESP 0x83, 0xec
42
+ #define OP_PUSHL_N_EBP_U 0xff
43
+ #define OP_PUSHL_N_EBP_L 0x75
44
+ #define OP_NOP 0x90
45
+ #define OP_ADDL_ESP_U 0x83
46
+ #define OP_ADDL_ESP_L 0xc4
47
+ #define OP_LEAVE 0xc9
48
+ #define OP_RET 0xc3
49
+
50
+ /* Set up probe function */
51
+ ip = insns + IS_ENABLED_FUNC_LEN;
52
+
53
+ uint8_t func_in[7] = {
54
+ OP_PUSHL_EBP, OP_MOVL_ESP_EBP, OP_SUBL_N_ESP, 0x08, NULL
55
+
56
+ };
57
+
58
+ uint8_t func_out[3] = {
59
+ OP_LEAVE, OP_RET, NULL
60
+ };
61
+
62
+ for (i = 0; func_in[i]; i++)
63
+ *ip++ = func_in[i];
64
+
65
+ for (i = (4 + 4*argc); i >= 0x08; i -= 4) {
66
+ *ip++ = OP_PUSHL_N_EBP_U;
67
+ *ip++ = OP_PUSHL_N_EBP_L;
68
+ *ip++ = i;
69
+ }
70
+
71
+ for (i = 0; i <=5; i++)
72
+ *ip++ = OP_NOP;
73
+
74
+ *ip++ = OP_ADDL_ESP_U;
75
+ *ip++ = OP_ADDL_ESP_L;
76
+ *ip++ = argc * 4;
77
+
78
+ for (i = 0; func_out[i]; i++)
79
+ *ip++ = func_out[i];
80
+
81
+ /* allocate memory on a page boundary, for mprotect */
82
+ probe->func = (void *)memalign(PAGESIZE, FUNC_SIZE);
83
+ if (probe->func < 0) {
84
+ rb_raise(eDtraceException, "malloc failed: %s\n", strerror(errno));
85
+ return Qnil;
86
+ }
87
+
88
+ if ((mprotect((void *)probe->func, FUNC_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) < 0) {
89
+ rb_raise(eDtraceException, "mprotect failed: %s\n", strerror(errno));
90
+ return Qnil;
91
+ }
92
+
93
+ if ((memcpy(probe->func, insns, FUNC_SIZE)) < 0) {
94
+ rb_raise(eDtraceException, "memcpy failed: %s\n", strerror(errno));
95
+ return Qnil;
96
+ }
97
+
98
+ return self;
99
+ }
100
+
101
+ VALUE dtraceprobe_free(void *arg)
102
+ {
103
+ dtrace_probe_t *probe = (dtrace_probe_t *)arg;
104
+
105
+ if (probe) {
106
+ free(probe);
107
+ }
108
+ }
109
+
110
+ VALUE dtraceprobe_alloc(VALUE klass)
111
+ {
112
+ VALUE obj;
113
+ dtrace_probe_t *probe;
114
+
115
+ probe = ALLOC(dtrace_probe_t);
116
+ if (!probe) {
117
+ rb_raise(eDtraceException, "alloc failed");
118
+ return Qnil;
119
+ }
120
+
121
+ /* no mark function: no ruby objects hung off this struct */
122
+ obj = Data_Wrap_Struct(klass, NULL, dtraceprobe_free, probe);
123
+ return obj;
124
+ }
125
+
126
+ VALUE dtraceprobe_addr(VALUE self)
127
+ {
128
+ dtrace_probe_t *probe;
129
+
130
+ Data_Get_Struct(self, dtrace_probe_t, probe);
131
+ return INT2FIX(probe->func);
132
+ }
133
+
134
+ VALUE dtraceprobe_is_enabled(VALUE self)
135
+ {
136
+ dtrace_probe_t *probe;
137
+
138
+ Data_Get_Struct(self, dtrace_probe_t, probe);
139
+ return ((int)(*probe->func)()) ? Qtrue : Qfalse;
140
+ }
141
+
142
+ VALUE dtraceprobe_fire(int argc, VALUE *ruby_argv, VALUE self) {
143
+ dtrace_probe_t *probe;
144
+ int i;
145
+ void *argv[8]; // probe argc max for now.
146
+ void (*func)();
147
+
148
+ Data_Get_Struct(self, dtrace_probe_t, probe);
149
+
150
+ /* munge Ruby values to either char *s or ints. */
151
+ for (i = 0; i < argc; i++) {
152
+ switch (TYPE(ruby_argv[i])) {
153
+ case T_STRING:
154
+ argv[i] = (void *)RSTRING(ruby_argv[i])->ptr;
155
+ break;
156
+ case T_FIXNUM:
157
+ argv[i] = (void *)FIX2INT(ruby_argv[i]);
158
+ break;
159
+ default:
160
+ rb_raise(eDtraceException, "type of arg[%d] is not string or fixnum", i);
161
+ break;
162
+ }
163
+ }
164
+
165
+ func = (void (*)())(probe->func + IS_ENABLED_FUNC_LEN);
166
+
167
+ switch (argc) {
168
+ case 0:
169
+ (void)(*func)();
170
+ break;
171
+ case 1:
172
+ (void)(*func)(argv[0]);
173
+ break;
174
+ case 2:
175
+ (void)(*func)(argv[0], argv[1]);
176
+ break;
177
+ case 3:
178
+ (void)(*func)(argv[0], argv[1], argv[2]);
179
+ break;
180
+ case 4:
181
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3]);
182
+ break;
183
+ case 5:
184
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
185
+ argv[4]);
186
+ break;
187
+ case 6:
188
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
189
+ argv[4], argv[5]);
190
+ break;
191
+ case 7:
192
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
193
+ argv[4], argv[5], argv[6]);
194
+ break;
195
+ case 8:
196
+ (void)(*func)(argv[0], argv[1], argv[2], argv[3],
197
+ argv[4], argv[5], argv[6], argv[7]);
198
+ break;
199
+ default:
200
+ rb_raise(eDtraceException, "probe argc max is 8");
201
+ break;
202
+ }
203
+
204
+ return Qnil;
205
+ }
206
+
207
+ VALUE dtraceprobe_probe_offset(VALUE self, VALUE rfile, VALUE argc)
208
+ {
209
+ /*
210
+ * compute offset into stub: see dtrace_probe.c
211
+ *
212
+ * 32 bytes - length of is_enabled function
213
+ * +
214
+ * 6 bytes - function entry
215
+ * +
216
+ * 3 bytes per argument - arg->stack push
217
+ *
218
+ */
219
+ return INT2FIX(32 + 6 + FIX2INT(argc) * 3);
220
+ }
221
+
222
+ VALUE dtraceprobe_is_enabled_offset(VALUE self, VALUE rfile)
223
+ {
224
+ return INT2FIX(8);
225
+ }