ruby-dtrace 0.0.6 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
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
+ }