ruby-dtrace 0.0.2 → 0.0.3

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.
@@ -16,92 +16,225 @@ VALUE dtraceprobedata_init(VALUE self)
16
16
  return self;
17
17
  }
18
18
 
19
- VALUE dtraceprobedata_probedesc(VALUE self)
19
+ static VALUE _handle_ustack_record(dtrace_hdl_t *handle, caddr_t addr, const dtrace_recdesc_t *rec)
20
20
  {
21
+ VALUE stack;
22
+ stack = rb_ary_new();
23
+
24
+ /* TODO, apple and solaris ustack */
25
+ return stack;
26
+ }
27
+
28
+ static VALUE _handle_stack_record(dtrace_hdl_t *handle, caddr_t addr, const dtrace_recdesc_t *rec)
29
+ {
30
+ VALUE stack = Qnil;
31
+ int size, i;
32
+ int depth;
33
+ uint64_t pc;
34
+ dtrace_syminfo_t dts;
35
+ char c[PATH_MAX * 2];
36
+
37
+ #ifdef __APPLE__
38
+ __GElf_Sym sym;
39
+ #else
40
+ GElf_Sym sym;
41
+ #endif
42
+
43
+ size = rec->dtrd_size / rec->dtrd_arg;
44
+ depth = rec->dtrd_arg;
45
+
46
+ stack = rb_ary_new();
47
+
48
+ for (i = 0; i < depth; i++) {
49
+
50
+ switch (size) {
51
+ case sizeof (uint32_t):
52
+ pc = *((uint32_t *)addr);
53
+ break;
54
+
55
+ case sizeof (uint64_t):
56
+ pc = *((uint64_t *)addr);
57
+ break;
58
+
59
+ default:
60
+ rb_raise(eDtraceException, "bad stack pc");
61
+ return Qnil;
62
+ }
63
+
64
+ if (pc == (uint64_t)NULL)
65
+ break;
66
+
67
+ addr += size;
68
+
69
+ if (dtrace_lookup_by_addr(handle, pc, &sym, &dts) == 0) {
70
+ if (pc > sym.st_value) {
71
+ (void) snprintf(c, sizeof (c), "%s`%s+0x%llx",
72
+ dts.dts_object, dts.dts_name,
73
+ pc - sym.st_value);
74
+ }
75
+ else {
76
+ (void) snprintf(c, sizeof (c), "%s`%s",
77
+ dts.dts_object, dts.dts_name);
78
+ }
79
+ }
80
+ else {
81
+ if (dtrace_lookup_by_addr(handle, pc, NULL, &dts) == 0) {
82
+ (void) snprintf(c, sizeof (c), "%s`0x%llx",
83
+ dts.dts_object, pc);
84
+ }
85
+ else {
86
+ (void) snprintf(c, sizeof (c), "0x%llx", pc);
87
+ }
88
+ }
89
+
90
+ rb_ary_push(stack, rb_str_new2(c));
91
+ }
92
+
93
+ return stack;
94
+ }
95
+
96
+ /*
97
+ * Returns the enabled probe id which generated this data
98
+ */
99
+ VALUE dtraceprobedata_epid(VALUE self)
100
+ {
101
+ dtrace_probedata_t *data;
102
+
103
+ Data_Get_Struct(self, dtrace_probedata_t, data);
104
+ return INT2FIX(data->dtpda_edesc->dtepd_epid);
105
+ }
106
+
107
+ /*
108
+ * Returns the DtraceProbe for the probe which generated this data
109
+ */
110
+ VALUE dtraceprobedata_probe(VALUE self)
111
+ {
112
+ VALUE dtraceprobe;
21
113
  dtrace_probedata_t *data;
22
- dtrace_probedesc_t *pdp;
23
- VALUE probe;
114
+ dtrace_probedesc_t *pd;
24
115
 
25
116
  Data_Get_Struct(self, dtrace_probedata_t, data);
117
+ pd = data->dtpda_pdesc;
26
118
 
27
- pdp = data->dtpda_pdesc;
28
- probe = Data_Wrap_Struct(cDtraceProbe, 0, NULL, (dtrace_probedesc_t *)pdp);
119
+ if (pd) {
120
+ dtraceprobe = Data_Wrap_Struct(cDtraceProbe, 0, NULL, (dtrace_probedesc_t *)pd);
121
+ return dtraceprobe;
122
+ }
29
123
 
30
- return probe;
124
+ return Qnil;
31
125
  }
32
126
 
33
- static VALUE _handle_stack_record(const caddr_t addr, const dtrace_recdesc_t *rec)
127
+ /* Returns the CPU which generated this data */
128
+ VALUE dtraceprobedata_cpu(VALUE self)
34
129
  {
35
- dtrace_actkind_t act;
36
- uint64_t *pc;
37
- pid_t pid = -1;
38
- int size; /* size of raw bytes not including trailing zeros */
39
- int i; /* index of last non-zero byte */
40
- VALUE raw;
130
+ dtrace_probedata_t *data;
131
+ processorid_t cpu;
41
132
 
42
- for (i = rec->dtrd_size - 1; (i >= 0) && !addr[i]; --i) {
133
+ Data_Get_Struct(self, dtrace_probedata_t, data);
134
+
135
+ if (data) {
136
+ cpu = data->dtpda_cpu;
137
+ return INT2FIX(cpu);
43
138
  }
44
- size = (i + 1);
139
+ else {
140
+ return Qnil;
141
+ }
142
+ }
143
+
144
+ /* Returns the indent level given to this data by DTrace */
145
+ VALUE dtraceprobedata_indent(VALUE self)
146
+ {
147
+ dtrace_probedata_t *data;
148
+ int indent;
45
149
 
46
- raw = rb_ary_new();
47
- for (i = 0; i < size; i++)
48
- rb_ary_push(raw, INT2FIX(addr[i]));
150
+ Data_Get_Struct(self, dtrace_probedata_t, data);
49
151
 
50
- act = rec->dtrd_action;
51
- switch (act) {
52
- case DTRACEACT_STACK:
53
- break;
54
- case DTRACEACT_USTACK:
55
- case DTRACEACT_JSTACK:
56
- /* Get pid of user process */
57
- pc = (uint64_t *)(uintptr_t)addr;
58
- pid = (pid_t)*pc;
59
- break;
60
- default:
61
- rb_raise(eDtraceException, "Expected stack action, got %d\n", act);
152
+ if (data) {
153
+ indent = data->dtpda_indent;
154
+ return INT2FIX(indent / 2);
62
155
  }
156
+ else {
157
+ return Qnil;
158
+ }
159
+ }
63
160
 
64
- return raw;
161
+ /* Returns the prefix given to this data by DTrace */
162
+ VALUE dtraceprobedata_prefix(VALUE self)
163
+ {
164
+ dtrace_probedata_t *data;
165
+ const char *prefix;
166
+
167
+ Data_Get_Struct(self, dtrace_probedata_t, data);
168
+ prefix = data->dtpda_prefix;
169
+
170
+ if (prefix)
171
+ return rb_str_new2(prefix);
172
+ else
173
+ return Qnil;
65
174
  }
66
175
 
67
- static int
68
- _is_stack_action(dtrace_actkind_t act)
176
+ /* Returns the flow kind given to this data by DTrace */
177
+ VALUE dtraceprobedata_flow(VALUE self)
69
178
  {
70
- int stack_action;
71
- switch (act) {
72
- case DTRACEACT_STACK:
73
- case DTRACEACT_USTACK:
74
- case DTRACEACT_JSTACK:
75
- stack_action = 1;
179
+ dtrace_probedata_t *data;
180
+
181
+ Data_Get_Struct(self, dtrace_probedata_t, data);
182
+
183
+ switch (data->dtpda_flow) {
184
+ case DTRACEFLOW_ENTRY:
185
+ return rb_str_new2("->");
186
+ break;
187
+ case DTRACEFLOW_RETURN:
188
+ return rb_str_new2("<-");
76
189
  break;
77
190
  default:
78
- stack_action = 0;
191
+ return Qnil;
79
192
  }
80
- return (stack_action);
81
193
  }
82
194
 
195
+ /*
196
+ * Yields each record in this DtraceProbedata in turn. Records are
197
+ * yielded as either DtraceRecords or DtraceStackRecords as
198
+ * appropriate for the type of action.
199
+ */
83
200
  VALUE dtraceprobedata_each_record(VALUE self)
84
201
  {
85
202
  dtrace_probedata_t *data;
86
203
  dtrace_eprobedesc_t *eprobe;
87
204
  dtrace_recdesc_t *rec;
205
+ dtrace_hdl_t *handle;
206
+ dtrace_actkind_t act;
88
207
  int i;
208
+ caddr_t addr;
89
209
  VALUE dtracerecord;
210
+ VALUE dtracehandle;
90
211
  VALUE v;
91
- caddr_t addr;
92
212
 
93
213
  Data_Get_Struct(self, dtrace_probedata_t, data);
214
+ dtracehandle = rb_iv_get(self, "@handle");
215
+ Data_Get_Struct(dtracehandle, dtrace_hdl_t, handle);
216
+
94
217
  eprobe = data->dtpda_edesc;
95
218
 
96
219
  for (i = 0; i < eprobe->dtepd_nrecs; i++) {
220
+ v = 0;
97
221
  rec = &eprobe->dtepd_rec[i];
98
222
  if (rec->dtrd_size > 0) {
223
+ act = rec->dtrd_action;
99
224
  addr = data->dtpda_data + rec->dtrd_offset;
100
-
101
- if (_is_stack_action(rec->dtrd_action)) {
102
- v = _handle_stack_record(addr, rec);
103
- }
104
- else {
225
+
226
+ switch (act) {
227
+ case DTRACEACT_STACK:
228
+ case DTRACEACT_USTACK:
229
+ case DTRACEACT_JSTACK:
230
+ /* Stack records come from bufdata */
231
+ /* v = _handle_stack_record(handle, addr, rec); */
232
+ /* v = _handle_ustack_record(handle, addr, rec); */
233
+ break;
234
+ case DTRACEACT_PRINTA:
235
+ /* don't want the probedata record for a printa() action */
236
+ break;
237
+ default:
105
238
  switch (rec->dtrd_size) {
106
239
  case 1:
107
240
  v = INT2FIX((int)(*((uint8_t *)addr)));
@@ -121,9 +254,14 @@ VALUE dtraceprobedata_each_record(VALUE self)
121
254
  }
122
255
  }
123
256
 
124
- dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtraceRecord"));
125
- rb_iv_set(dtracerecord, "@value", v);
126
- rb_yield(dtracerecord);
257
+ if (v) {
258
+ dtracerecord = rb_class_new_instance(0, NULL, rb_path2class("DtraceRecord"));
259
+ rb_iv_set(dtracerecord, "@value", v);
260
+ rb_iv_set(dtracerecord, "@from", rb_str_new2("probedata"));
261
+ rb_iv_set(dtracerecord, "@index", INT2FIX(i));
262
+ rb_iv_set(dtracerecord, "@action", INT2FIX(act));
263
+ rb_yield(dtracerecord);
264
+ }
127
265
  }
128
266
  }
129
267
  }
@@ -0,0 +1,37 @@
1
+ /* Ruby-Dtrace
2
+ * (c) 2007 Chris Andrews <chris@nodnol.org>
3
+ */
4
+
5
+ #include "dtrace_api.h"
6
+
7
+ /* :nodoc: */
8
+ VALUE dtrace_process_init(VALUE self)
9
+ {
10
+ dtrace_process_t *process;
11
+
12
+ Data_Get_Struct(self, dtrace_process_t, process);
13
+ if (process)
14
+ return self;
15
+ else
16
+ return Qnil;
17
+ }
18
+
19
+ /* :nodoc: */
20
+ void dtrace_process_release(dtrace_process_t *process)
21
+ {
22
+ dtrace_proc_release(process->handle, process->proc);
23
+ free(process);
24
+ }
25
+
26
+ /*
27
+ * Start or restart the process. Call this having configured tracing
28
+ * for the process, using $target in the D program.
29
+ */
30
+ VALUE dtrace_process_continue(VALUE self)
31
+ {
32
+ dtrace_process_t *process;
33
+
34
+ Data_Get_Struct(self, dtrace_process_t, process);
35
+ dtrace_proc_continue(process->handle, process->proc);
36
+ }
37
+
data/ext/dtrace_recdesc.c CHANGED
@@ -13,3 +13,34 @@ VALUE dtracerecdesc_init(VALUE self)
13
13
  return self;
14
14
  }
15
15
 
16
+ /*
17
+ * Returns the type of action which generated this recdesc.
18
+ * (exit, printf, printa or "other" for all other actions).
19
+ */
20
+ VALUE dtracerecdesc_action(VALUE self)
21
+ {
22
+ dtrace_recdesc_t *recdesc;
23
+ VALUE v;
24
+ Data_Get_Struct(self, dtrace_recdesc_t, recdesc);
25
+
26
+ if (recdesc){
27
+ switch (recdesc->dtrd_action) {
28
+ case DTRACEACT_EXIT:
29
+ v = rb_str_new2("exit");
30
+ break;
31
+ case DTRACEACT_PRINTF:
32
+ v = rb_str_new2("printf");
33
+ break;
34
+ case DTRACEACT_PRINTA:
35
+ v = rb_str_new2("printa");
36
+ break;
37
+ default:
38
+ v = rb_str_new2("other");
39
+ break;
40
+ }
41
+ return v;
42
+ }
43
+ else {
44
+ return Qnil;
45
+ }
46
+ }
data/lib/dtrace.rb CHANGED
@@ -7,10 +7,62 @@ require 'dtrace_api'
7
7
  require 'dtracerecord'
8
8
  require 'dtraceconsumer'
9
9
  require 'dtraceaggregate'
10
+ require 'dtraceaggregateset'
10
11
  require 'dtraceprobedata'
11
12
  require 'dtraceprobe'
13
+ require 'dtracestackrecord'
14
+ require 'dtraceprintfrecord'
15
+ require 'dtracedata'
16
+
17
+ # A DTrace handle. Provides methods for inspecting available probes,
18
+ # compiling and running programs, and for setting up callbacks to
19
+ # receive trace data.
20
+ #
21
+ # The general structure of a Dtrace-based program is:
22
+ #
23
+ # * Create a handle with Dtrace.new
24
+ # * Set options
25
+ # * Compile the program, possibly inspecting the return DtraceProgramInfo
26
+ # * Execute the program
27
+ # * Start tracing
28
+ # * Consume data, either directly by setting up callbacks, or using a DtraceConsumer.
29
+ # * Stop tracing
30
+ #
31
+ # === Listing probes
32
+ #
33
+ # d.each_probe do |p|
34
+ # puts "#{p.provider}:#{p.mod}:#{p.func}:#{p.name}"
35
+ # end
36
+ #
37
+ # === Setting options
38
+ #
39
+ # d.setopt("bufsize", "8m")
40
+ # d.setopt("aggsize", "4m")
41
+ # d.setopt("stackframes", "5")
42
+ # d.setopt("strsize", "131072")
43
+ #
44
+ # === Compiling a program
45
+ #
46
+ # d.compile "syscall:::entry { trace(execname); stack(); }"
47
+ # d.execute
48
+ #
49
+ # === Setting up callbacks
50
+ #
51
+ # d.buf_consumer(prob {|buf| yield buf })
52
+ # d.work(proc {|probe| yield probe }, proc {|rec| yield rec })
53
+ #
54
+ # === Creating a process
55
+ #
56
+ # p = t.createprocess([ '/usr/bin/true' ])
57
+ # t.go
58
+ # p.continue
59
+ #
60
+ # c = DtraceConsumer.new(t)
61
+ # c.consume do |d|
62
+ # ..
63
+ # end
12
64
 
13
65
  class Dtrace
14
- VERSION = '0.0.2'
66
+ VERSION = '0.0.3'
15
67
  end
16
68
 
@@ -3,11 +3,35 @@
3
3
  # (c) 2007 Chris Andrews <chris@nodnol.org>
4
4
  #
5
5
 
6
+ # Represents an aggregation record built from a series of
7
+ # DtraceAggData records.
8
+ #
9
+ # Intended to to built up by calling +add_record+ repeatedly with
10
+ # DtraceAggData objects until a completed DtraceAggregate is returned.
11
+ # (until a complete record is available, +add_record+ returns nil).
12
+ #
13
+ # See dtraceconsumer.rb for an example of this.
6
14
  class DtraceAggregate
7
- attr_accessor :value, :tuple
15
+ attr_reader :value, :tuple
8
16
 
17
+ # Create an empty DtraceAggregate: use +add_record+ to add data.
9
18
  def initialize
10
19
  @tuple = Array.new
11
20
  end
21
+
22
+ # Add a DtraceAggData record to this aggregate. Returns nil until it
23
+ # receives a record of aggtype "last", when it returns the complete
24
+ # DtraceAggregate.
25
+ def add_record(r)
26
+ case r.aggtype
27
+ when "tuple"
28
+ @tuple << r.value
29
+ when "value"
30
+ @value = r.value
31
+ when "last"
32
+ return self
33
+ end
34
+ nil
35
+ end
12
36
 
13
37
  end