Skip to content

Commit 94eafa4

Browse files
author
Chris Andrews
committed
Add initial powerpc-darwin port (probes with 0 or 1 arg work, as does is_enabled)
1 parent 405623a commit 94eafa4

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed

ext/powerpc-darwin/dtrace_probe.c

+326
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
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 256
14+
#define IS_ENABLED_FUNC_LEN 32
15+
16+
void install_insns(uint8_t *probe_insns, uint8_t *insns, int count)
17+
{
18+
int i,j;
19+
uint8_t *ip;
20+
ip = insns;
21+
for (j = 1; j <= count; j++) {
22+
for (i = 0; i < 4; i++) {
23+
*ip++ = *probe_insns++;
24+
}
25+
}
26+
}
27+
28+
/* :nodoc: */
29+
VALUE dtraceprobe_init(VALUE self, VALUE rargc)
30+
{
31+
dtrace_probe_t *probe;
32+
uint8_t *ip;
33+
int i;
34+
int argc = FIX2INT(rargc);
35+
uint8_t probe_insns[FUNC_SIZE];
36+
37+
Data_Get_Struct(self, dtrace_probe_t, probe);
38+
39+
/* First initialise the is_enabled tracepoint */
40+
uint8_t insns[FUNC_SIZE] = {
41+
/* stmw r30,0xfff8(r1) */
42+
0xbf, 0xc1, 0xff, 0xf8,
43+
/* stwu r1,0xffd0(r1) */
44+
0x94, 0x21, 0xff, 0xd0,
45+
/* or r30,r1,r1 */
46+
0x7c, 0x3e, 0x0b, 0x78,
47+
/* li r0,0x0 */
48+
0x38, 0x00, 0x00, 0x00,
49+
/* or r3,r0,r0 */
50+
0x7c, 0x03, 0x03, 0x78,
51+
/* lwz r1,0x0(r1) */
52+
0x80, 0x21, 0x00, 0x00,
53+
/* lmw r30,0xfff8(r1) */
54+
0xbb, 0xc1, 0xff, 0xf8,
55+
/* blr */
56+
0x4e, 0x80, 0x00, 0x20
57+
};
58+
59+
/* Now build probe tracepoint */
60+
switch (argc) {
61+
62+
case 0:
63+
{
64+
uint8_t probe_insns[FUNC_SIZE] = {
65+
/* stmw r30,0xfff8(r1) */
66+
0xbf, 0xc1, 0xff, 0xf8,
67+
/* stwu r1,0xffd0(r1) */
68+
0x94, 0x21, 0xff, 0xd0,
69+
/* or r30,r1,r1 */
70+
0x7c, 0x3e, 0x0b, 0x78,
71+
/* lwz r1,0x0(r1) */
72+
0x80, 0x21, 0x00, 0x00,
73+
/* lmw r30,0xfff8(r1) */
74+
0xbb, 0xc1, 0xff, 0xf8,
75+
/* blr */
76+
0x4e, 0x80, 0x00, 0x20
77+
};
78+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 6);
79+
}
80+
break;
81+
82+
case 1:
83+
{
84+
uint8_t probe_insns[FUNC_SIZE] = {
85+
/* stmw r30,0xfff8(r1) */
86+
0xbf, 0xc1, 0xff, 0xf8,
87+
/* stwu r1,0xffd0(r1) */
88+
0x94, 0x21, 0xff, 0xd0,
89+
/* or r30,r1,r1 */
90+
0x7c, 0x3e, 0x0b, 0x78,
91+
/* stw r3,0x48(r30) */
92+
0x90, 0x7e, 0x00, 0x48,
93+
/* lwz r1,0x0(r1) */
94+
0x80, 0x21, 0x00, 0x00,
95+
/* lmw r30,0xfff8(r1) */
96+
0xbb, 0xc1, 0xff, 0xf8,
97+
/* blr */
98+
0x4e, 0x80, 0x00, 0x20
99+
};
100+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 7);
101+
}
102+
break;
103+
104+
case 2:
105+
{
106+
uint8_t probe_insns[FUNC_SIZE] = {
107+
};
108+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 12);
109+
}
110+
break;
111+
112+
case 3:
113+
{
114+
uint8_t probe_insns[FUNC_SIZE] = {
115+
};
116+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 16);
117+
}
118+
break;
119+
120+
case 4:
121+
{
122+
uint8_t probe_insns[FUNC_SIZE] = {
123+
};
124+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 16);
125+
}
126+
break;
127+
128+
case 5:
129+
{
130+
uint8_t probe_insns[FUNC_SIZE] = {
131+
};
132+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 20);
133+
}
134+
break;
135+
136+
case 6:
137+
{
138+
uint8_t probe_insns[FUNC_SIZE] = {
139+
};
140+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 24);
141+
}
142+
break;
143+
144+
case 7:
145+
{
146+
uint8_t probe_insns[FUNC_SIZE] = {
147+
};
148+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 28);
149+
}
150+
break;
151+
152+
case 8:
153+
{
154+
uint8_t probe_insns[FUNC_SIZE] = {
155+
};
156+
install_insns(probe_insns, &insns[IS_ENABLED_FUNC_LEN], 32);
157+
}
158+
break;
159+
160+
default:
161+
rb_raise(eDtraceException, "probe argc max is 8");
162+
return Qnil;
163+
break;
164+
}
165+
166+
/* allocate memory on a page boundary, for mprotect */
167+
probe->func = (void *)valloc(FUNC_SIZE);
168+
if (probe->func < 0) {
169+
rb_raise(eDtraceException, "malloc failed: %s\n", strerror(errno));
170+
return Qnil;
171+
}
172+
173+
if ((mprotect((void *)probe->func, FUNC_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) < 0) {
174+
rb_raise(eDtraceException, "mprotect failed: %s\n", strerror(errno));
175+
return Qnil;
176+
}
177+
178+
if ((memcpy(probe->func, insns, FUNC_SIZE)) < 0) {
179+
rb_raise(eDtraceException, "memcpy failed: %s\n", strerror(errno));
180+
return Qnil;
181+
}
182+
183+
return self;
184+
}
185+
186+
VALUE dtraceprobe_free(void *arg)
187+
{
188+
dtrace_probe_t *probe = (dtrace_probe_t *)arg;
189+
190+
if (probe) {
191+
free(probe);
192+
}
193+
}
194+
195+
VALUE dtraceprobe_alloc(VALUE klass)
196+
{
197+
VALUE obj;
198+
dtrace_probe_t *probe;
199+
200+
probe = ALLOC(dtrace_probe_t);
201+
if (!probe) {
202+
rb_raise(eDtraceException, "alloc failed");
203+
return Qnil;
204+
}
205+
206+
/* no mark function: no ruby objects hung off this struct */
207+
obj = Data_Wrap_Struct(klass, NULL, dtraceprobe_free, probe);
208+
return obj;
209+
}
210+
211+
VALUE dtraceprobe_addr(VALUE self)
212+
{
213+
dtrace_probe_t *probe;
214+
215+
Data_Get_Struct(self, dtrace_probe_t, probe);
216+
return INT2FIX(probe->func);
217+
}
218+
219+
VALUE dtraceprobe_is_enabled(VALUE self)
220+
{
221+
dtrace_probe_t *probe;
222+
223+
Data_Get_Struct(self, dtrace_probe_t, probe);
224+
return ((int)(*probe->func)()) ? Qtrue : Qfalse;
225+
}
226+
227+
VALUE dtraceprobe_fire(int argc, VALUE *ruby_argv, VALUE self) {
228+
dtrace_probe_t *probe;
229+
int i;
230+
void *argv[8]; // probe argc max for now.
231+
void (*func)();
232+
233+
Data_Get_Struct(self, dtrace_probe_t, probe);
234+
235+
/* munge Ruby values to either char *s or ints. */
236+
for (i = 0; i < argc; i++) {
237+
switch (TYPE(ruby_argv[i])) {
238+
case T_STRING:
239+
argv[i] = (void *)RSTRING(ruby_argv[i])->ptr;
240+
break;
241+
case T_FIXNUM:
242+
argv[i] = (void *)FIX2INT(ruby_argv[i]);
243+
break;
244+
default:
245+
rb_raise(eDtraceException, "type of arg[%d] is not string or fixnum", i);
246+
break;
247+
}
248+
}
249+
250+
func = (void (*)())(probe->func + IS_ENABLED_FUNC_LEN);
251+
252+
switch (argc) {
253+
case 0:
254+
(void)(*func)();
255+
break;
256+
case 1:
257+
(void)(*func)(argv[0]);
258+
break;
259+
case 2:
260+
(void)(*func)(argv[0], argv[1]);
261+
break;
262+
case 3:
263+
(void)(*func)(argv[0], argv[1], argv[2]);
264+
break;
265+
case 4:
266+
(void)(*func)(argv[0], argv[1], argv[2], argv[3]);
267+
break;
268+
case 5:
269+
(void)(*func)(argv[0], argv[1], argv[2], argv[3],
270+
argv[4]);
271+
break;
272+
case 6:
273+
(void)(*func)(argv[0], argv[1], argv[2], argv[3],
274+
argv[4], argv[5]);
275+
break;
276+
case 7:
277+
(void)(*func)(argv[0], argv[1], argv[2], argv[3],
278+
argv[4], argv[5], argv[6]);
279+
break;
280+
case 8:
281+
(void)(*func)(argv[0], argv[1], argv[2], argv[3],
282+
argv[4], argv[5], argv[6], argv[7]);
283+
break;
284+
default:
285+
rb_raise(eDtraceException, "probe argc max is 8");
286+
break;
287+
}
288+
289+
return Qnil;
290+
}
291+
292+
293+
/*
294+
* Returns the offset for this probe in the PROFFS section, based on
295+
* the location of the DOF, and the location of this probe.
296+
*/
297+
VALUE dtraceprobe_probe_offset(VALUE self, VALUE file_addr, VALUE argc)
298+
{
299+
void *probe_addr;
300+
int offset;
301+
probe_addr = (void *)FIX2INT(rb_funcall(self, rb_intern("addr"), 0));
302+
switch FIX2INT(argc) {
303+
case 0:
304+
offset = 40; /* 32 + 6 + 2 */
305+
break;
306+
case 1:
307+
offset = 46; /* 32 + 6 + 6 + 2 */
308+
break;
309+
default:
310+
offset = 46 + (FIX2INT(argc)-1) * 7; /* 32 + 6 + 6 + 7 per subsequent arg + 2 */
311+
break;
312+
}
313+
return INT2FIX((int)probe_addr - (int)FIX2INT(file_addr) + offset);
314+
}
315+
316+
/*
317+
* Returns the offset for this probe's is-enabled tracepoint in the
318+
* PRENOFFS section, based on the location of the DOF, and the
319+
* location of this probe.
320+
*/
321+
VALUE dtraceprobe_is_enabled_offset(VALUE self, VALUE file_addr)
322+
{
323+
void *probe_addr;
324+
probe_addr = (void *)FIX2INT(rb_funcall(self, rb_intern("addr"), 0));
325+
return INT2FIX((int)probe_addr - (int)FIX2INT(file_addr) + 12);
326+
}

0 commit comments

Comments
 (0)