Skip to content

Commit 9fb088e

Browse files
Dave Pachecobnoordhuis
Dave Pacheco
authored andcommitted
dtrace: add missing translator
Add missing translator for node_dtrace_http_*_request_t types. Fixes nodejs#2667.
1 parent 74a2528 commit 9fb088e

File tree

1 file changed

+189
-33
lines changed

1 file changed

+189
-33
lines changed

src/node.d

Lines changed: 189 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -64,96 +64,252 @@ translator node_connection_t <node_dtrace_connection_t *nc> {
6464
&((node_dtrace_connection64_t *)nc)->buffered, sizeof (int32_t));
6565
};
6666

67+
/*
68+
* 32-bit and 64-bit structures received from node for HTTP client request
69+
* probe.
70+
*/
71+
typedef struct {
72+
uint32_t url;
73+
uint32_t method;
74+
} node_dtrace_http_client_request_t;
75+
76+
typedef struct {
77+
uint64_t url;
78+
uint64_t method;
79+
} node_dtrace_http_client_request64_t;
80+
81+
/*
82+
* The following structures are never used directly, but must exist to bind the
83+
* types specified in the provider to the translators defined here.
84+
* Ultimately, they always get cast to a more specific type inside the
85+
* translator. To add to the confusion, the DTrace compiler does not allow
86+
* declaring two translators with the same destination type if the source types
87+
* are structures with the same size (because libctf says they're compatible,
88+
* so dtrace considers them equivalent). Since we must define translators from
89+
* node_dtrace_http_client_request_t (above), node_dtrace_http_request_t, and
90+
* node_dtrace_http_server_request_t (both below), each of these three structs
91+
* must be declared with a different size.
92+
*/
6793
typedef struct {
6894
uint32_t version;
95+
uint64_t dummy1;
6996
} node_dtrace_http_request_t;
7097

98+
typedef struct {
99+
uint32_t version;
100+
uint64_t dummy2;
101+
uint64_t dummy3;
102+
} node_dtrace_http_server_request_t;
103+
104+
/*
105+
* Actual 32-bit and 64-bit, v0 and v1 structures received from node for the
106+
* HTTP server request probe.
107+
*/
71108
typedef struct {
72109
uint32_t url;
73110
uint32_t method;
74-
} node_dtrace_http_request_v0_t;
111+
} node_dtrace_http_server_request_v0_t;
75112

76113
typedef struct {
77114
uint32_t version;
78115
uint32_t url;
79116
uint32_t method;
80117
uint32_t forwardedFor;
81-
} node_dtrace_http_request_v1_t;
118+
} node_dtrace_http_server_request_v1_t;
82119

83120
typedef struct {
84121
uint64_t url;
85122
uint64_t method;
86-
} node_dtrace_http_request64_v0_t;
123+
} node_dtrace_http_server_request64_v0_t;
87124

88125
typedef struct {
89126
uint32_t version;
90127
uint32_t pad;
91128
uint64_t url;
92129
uint64_t method;
93130
uint64_t forwardedFor;
94-
} node_dtrace_http_request64_v1_t;
131+
} node_dtrace_http_server_request64_v1_t;
95132

133+
/*
134+
* In the end, both client and server request probes from both old and new
135+
* binaries translate their arguments to node_http_request_t, which is what the
136+
* user's D script ultimately sees.
137+
*/
96138
typedef struct {
97139
string url;
98140
string method;
99141
string forwardedFor;
100142
} node_http_request_t;
101143

102144
/*
103-
* This translator is even filthier than usual owing to our attempts to
104-
* maintain backwards compatibility. Previous versions of node used an
105-
* http_request struct that had fields for "url" and "method". The current
106-
* version also provides a "forwardedFor" field. To distinguish the binary
107-
* representations of these structs, the new version also prepends a "version"
108-
* member (where the old one has a "url" pointer). So each field that we're
109-
* translating below first switches on the value of this "version" field: if
110-
* it's larger than 4096, we know we must be looking at the "url" pointer of
111-
* the older structure version. Otherwise, we must be looking at the new
112-
* version. Besides this, we have the usual switch based on the userland
113-
* process data model. This would all be simpler with macros, but those aren't
114-
* available in delivered D library files since that would make DTrace
115-
* dependent on cpp, which isn't always available.
145+
* The following translators are particularly filthy for reasons of backwards
146+
* compatibility. Stable versions of node prior to 0.6 used a single
147+
* http_request struct with fields for "url" and "method" for both client and
148+
* server probes. 0.6 added a "forwardedFor" field intended for the server
149+
* probe only, and the http_request struct passed by the application was split
150+
* first into client_http_request and server_http_request and the latter was
151+
* again split for v0 (the old struct) and v1.
152+
*
153+
* To distinguish the binary representations of the two versions of these
154+
* structs, the new version prepends a "version" member (where the old one has
155+
* a "url" pointer). Each field that we're translating below first switches on
156+
* the value of this "version" field: if it's larger than 4096, we know we must
157+
* be looking at the "url" pointer of the older structure version. Otherwise,
158+
* we must be looking at the new version. Besides this, we have the usual
159+
* switch based on the userland process data model. This would all be simpler
160+
* with macros, but those aren't available in D library files since we cannot
161+
* rely on cpp being present at runtime.
162+
*
163+
* In retrospect, the versioning bit might have been unnecessary since the type
164+
* of the object passed in should allow DTrace to select which translator to
165+
* use. However, DTrace does sometimes use translators whose source types
166+
* don't quite match, and since we know this versioning logic works, we just
167+
* leave it alone. Each of the translators below is functionally identical
168+
* (except that the client -> client translator doesn't bother translating
169+
* forwardedFor) and should actually work with any version of any of the client
170+
* or server structs transmitted by the application up to this point.
116171
*/
117-
translator node_http_request_t <node_dtrace_http_request_t *nd> {
118-
url = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ?
172+
173+
/*
174+
* Translate from node_dtrace_http_server_request_t (received from node 0.6 and
175+
* later versions) to node_http_request_t.
176+
*/
177+
translator node_http_request_t <node_dtrace_http_server_request_t *nd> {
178+
url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
179+
sizeof (uint32_t))) >= 4096 ?
180+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
181+
copyinstr(*(uint32_t *)copyin((uintptr_t)
182+
&((node_dtrace_http_server_request_v0_t *)nd)->url,
183+
sizeof (uint32_t))) :
184+
copyinstr(*(uint64_t *)copyin((uintptr_t)
185+
&((node_dtrace_http_server_request64_v0_t *)nd)->url,
186+
sizeof (uint64_t)))) :
187+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
188+
copyinstr(*(uint32_t *)copyin((uintptr_t)
189+
&((node_dtrace_http_server_request_v1_t *)nd)->url,
190+
sizeof (uint32_t))) :
191+
copyinstr(*(uint64_t *)copyin((uintptr_t)
192+
&((node_dtrace_http_server_request64_v1_t *)nd)->url,
193+
sizeof (uint64_t))));
194+
195+
method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
196+
sizeof (uint32_t))) >= 4096 ?
197+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
198+
copyinstr(*(uint32_t *)copyin((uintptr_t)
199+
&((node_dtrace_http_server_request_v0_t *)nd)->method,
200+
sizeof (uint32_t))) :
201+
copyinstr(*(uint64_t *)copyin((uintptr_t)
202+
&((node_dtrace_http_server_request64_v0_t *)nd)->method,
203+
sizeof (uint64_t)))) :
119204
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
120205
copyinstr(*(uint32_t *)copyin((uintptr_t)
121-
&((node_dtrace_http_request_v0_t *)nd)->url,
206+
&((node_dtrace_http_server_request_v1_t *)nd)->method,
122207
sizeof (uint32_t))) :
123208
copyinstr(*(uint64_t *)copyin((uintptr_t)
124-
&((node_dtrace_http_request64_v0_t *)nd)->url,
209+
&((node_dtrace_http_server_request64_v1_t *)nd)->method,
210+
sizeof (uint64_t))));
211+
212+
forwardedFor = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
213+
sizeof (uint32_t))) >= 4096 ? "" :
214+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
215+
copyinstr(*(uint32_t *)copyin((uintptr_t)
216+
&((node_dtrace_http_server_request_v1_t *)nd)->forwardedFor,
217+
sizeof (uint32_t))) :
218+
copyinstr(*(uint64_t *)copyin((uintptr_t)
219+
&((node_dtrace_http_server_request64_v1_t *)nd)->
220+
forwardedFor, sizeof (uint64_t))));
221+
};
222+
223+
/*
224+
* Translate from node_dtrace_http_client_request_t (received from node 0.6 and
225+
* later versions) to node_http_request_t.
226+
*/
227+
translator node_http_request_t <node_dtrace_http_client_request_t *nd> {
228+
url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
229+
sizeof (uint32_t))) >= 4096 ?
230+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
231+
copyinstr(*(uint32_t *)copyin((uintptr_t)
232+
&((node_dtrace_http_server_request_v0_t *)nd)->url,
233+
sizeof (uint32_t))) :
234+
copyinstr(*(uint64_t *)copyin((uintptr_t)
235+
&((node_dtrace_http_server_request64_v0_t *)nd)->url,
125236
sizeof (uint64_t)))) :
126237
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
127238
copyinstr(*(uint32_t *)copyin((uintptr_t)
128-
&((node_dtrace_http_request_v1_t *)nd)->url,
239+
&((node_dtrace_http_server_request_v1_t *)nd)->url,
129240
sizeof (uint32_t))) :
130241
copyinstr(*(uint64_t *)copyin((uintptr_t)
131-
&((node_dtrace_http_request64_v1_t *)nd)->url,
242+
&((node_dtrace_http_server_request64_v1_t *)nd)->url,
132243
sizeof (uint64_t))));
133244

134-
method = (*(uint32_t *)copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ?
245+
method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
246+
sizeof (uint32_t))) >= 4096 ?
135247
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
136248
copyinstr(*(uint32_t *)copyin((uintptr_t)
137-
&((node_dtrace_http_request_v0_t *)nd)->method,
249+
&((node_dtrace_http_server_request_v0_t *)nd)->method,
138250
sizeof (uint32_t))) :
139251
copyinstr(*(uint64_t *)copyin((uintptr_t)
140-
&((node_dtrace_http_request64_v0_t *)nd)->method,
252+
&((node_dtrace_http_server_request64_v0_t *)nd)->method,
141253
sizeof (uint64_t)))) :
142254
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
143255
copyinstr(*(uint32_t *)copyin((uintptr_t)
144-
&((node_dtrace_http_request_v1_t *)nd)->method,
256+
&((node_dtrace_http_server_request_v1_t *)nd)->method,
145257
sizeof (uint32_t))) :
146258
copyinstr(*(uint64_t *)copyin((uintptr_t)
147-
&((node_dtrace_http_request64_v1_t *)nd)->method,
259+
&((node_dtrace_http_server_request64_v1_t *)nd)->method,
148260
sizeof (uint64_t))));
149-
150-
forwardedFor = (*(uint32_t *)
151-
copyin((uintptr_t)&nd->version, sizeof (uint32_t))) >= 4096 ? "" :
261+
262+
forwardedFor = "";
263+
};
264+
265+
/*
266+
* Translate from node_dtrace_http_request_t (received from versions of node
267+
* prior to 0.6) to node_http_request_t. This is used for both the server and
268+
* client probes since these versions of node didn't distinguish between the
269+
* types used in these probes.
270+
*/
271+
translator node_http_request_t <node_dtrace_http_request_t *nd> {
272+
url = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
273+
sizeof (uint32_t))) >= 4096 ?
152274
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
153275
copyinstr(*(uint32_t *)copyin((uintptr_t)
154-
&((node_dtrace_http_request_v1_t *)nd)->forwardedFor,
276+
&((node_dtrace_http_server_request_v0_t *)nd)->url,
155277
sizeof (uint32_t))) :
156278
copyinstr(*(uint64_t *)copyin((uintptr_t)
157-
&((node_dtrace_http_request64_v1_t *)nd)->forwardedFor,
279+
&((node_dtrace_http_server_request64_v0_t *)nd)->url,
280+
sizeof (uint64_t)))) :
281+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
282+
copyinstr(*(uint32_t *)copyin((uintptr_t)
283+
&((node_dtrace_http_server_request_v1_t *)nd)->url,
284+
sizeof (uint32_t))) :
285+
copyinstr(*(uint64_t *)copyin((uintptr_t)
286+
&((node_dtrace_http_server_request64_v1_t *)nd)->url,
287+
sizeof (uint64_t))));
288+
289+
method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
290+
sizeof (uint32_t))) >= 4096 ?
291+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
292+
copyinstr(*(uint32_t *)copyin((uintptr_t)
293+
&((node_dtrace_http_server_request_v0_t *)nd)->method,
294+
sizeof (uint32_t))) :
295+
copyinstr(*(uint64_t *)copyin((uintptr_t)
296+
&((node_dtrace_http_server_request64_v0_t *)nd)->method,
297+
sizeof (uint64_t)))) :
298+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
299+
copyinstr(*(uint32_t *)copyin((uintptr_t)
300+
&((node_dtrace_http_server_request_v1_t *)nd)->method,
301+
sizeof (uint32_t))) :
302+
copyinstr(*(uint64_t *)copyin((uintptr_t)
303+
&((node_dtrace_http_server_request64_v1_t *)nd)->method,
158304
sizeof (uint64_t))));
305+
306+
forwardedFor = (*(uint32_t *) copyin((uintptr_t)(uint32_t *)nd,
307+
sizeof (uint32_t))) >= 4096 ? "" :
308+
(curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
309+
copyinstr(*(uint32_t *)copyin((uintptr_t)
310+
&((node_dtrace_http_server_request_v1_t *)nd)->forwardedFor,
311+
sizeof (uint32_t))) :
312+
copyinstr(*(uint64_t *)copyin((uintptr_t)
313+
&((node_dtrace_http_server_request64_v1_t *)nd)->
314+
forwardedFor, sizeof (uint64_t))));
159315
};

0 commit comments

Comments
 (0)