• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright Joyent, Inc. and other Node contributors.
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining a
4  * copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to permit
8  * persons to whom the Software is furnished to do so, subject to the
9  * following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17  * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20  * USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * This is the DTrace library file for the node provider, which includes
25  * the necessary translators to get from the args[] to something useful.
26  * Be warned:  the mechanics here are seriously ugly -- and one must always
27  * keep in mind that clean abstractions often require filthy systems.
28  */
29 #pragma D depends_on library procfs.d
30 
31 typedef struct {
32 	int32_t fd;
33 	int32_t port;
34 	uint32_t remote;
35 	uint32_t buffered;
36 } node_dtrace_connection_t;
37 
38 typedef struct {
39 	int32_t fd;
40 	int32_t port;
41 	uint64_t remote;
42 	uint32_t buffered;
43 } node_dtrace_connection64_t;
44 
45 typedef struct {
46 	int fd;
47 	string remoteAddress;
48 	int remotePort;
49 	int bufferSize;
50 } node_connection_t;
51 
52 translator node_connection_t <node_dtrace_connection_t *nc> {
53 	fd = *(int32_t *)copyin((uintptr_t)&nc->fd, sizeof (int32_t));
54 	remotePort =
55 	    *(int32_t *)copyin((uintptr_t)&nc->port, sizeof (int32_t));
56 	remoteAddress = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
57 	    copyinstr((uintptr_t)*(uint32_t *)copyin((uintptr_t)&nc->remote,
58 	    sizeof (int32_t))) :
59 	    copyinstr((uintptr_t)*(uint64_t *)copyin((uintptr_t)
60 	    &((node_dtrace_connection64_t *)nc)->remote, sizeof (int64_t)));
61 	bufferSize = curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
62 	    *(uint32_t *)copyin((uintptr_t)&nc->buffered, sizeof (int32_t)) :
63 	    *(uint32_t *)copyin((uintptr_t)
64 	    &((node_dtrace_connection64_t *)nc)->buffered, sizeof (int32_t));
65 };
66 
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  */
93 typedef struct {
94 	uint32_t version;
95 	uint64_t dummy1;
96 } node_dtrace_http_request_t;
97 
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  */
108 typedef struct {
109 	uint32_t url;
110 	uint32_t method;
111 } node_dtrace_http_server_request_v0_t;
112 
113 typedef struct {
114 	uint32_t version;
115 	uint32_t url;
116 	uint32_t method;
117 	uint32_t forwardedFor;
118 } node_dtrace_http_server_request_v1_t;
119 
120 typedef struct {
121 	uint64_t url;
122 	uint64_t method;
123 } node_dtrace_http_server_request64_v0_t;
124 
125 typedef struct {
126 	uint32_t version;
127 	uint32_t pad;
128 	uint64_t url;
129 	uint64_t method;
130 	uint64_t forwardedFor;
131 } node_dtrace_http_server_request64_v1_t;
132 
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  */
138 typedef struct {
139 	string url;
140 	string method;
141 	string forwardedFor;
142 } node_http_request_t;
143 
144 /*
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.
171  */
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)))) :
204 	    (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
205 		copyinstr(*(uint32_t *)copyin((uintptr_t)
206 		    &((node_dtrace_http_server_request_v1_t *)nd)->method,
207 		    sizeof (uint32_t))) :
208 		copyinstr(*(uint64_t *)copyin((uintptr_t)
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,
236 		    sizeof (uint64_t)))) :
237 	    (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
238 		copyinstr(*(uint32_t *)copyin((uintptr_t)
239 		    &((node_dtrace_http_server_request_v1_t *)nd)->url,
240 		    sizeof (uint32_t))) :
241 		copyinstr(*(uint64_t *)copyin((uintptr_t)
242 		    &((node_dtrace_http_server_request64_v1_t *)nd)->url,
243 		    sizeof (uint64_t))));
244 
245 	method = (*(uint32_t *)copyin((uintptr_t)(uint32_t *)nd,
246 		sizeof (uint32_t))) >= 4096 ?
247 	    (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
248 		copyinstr(*(uint32_t *)copyin((uintptr_t)
249 		    &((node_dtrace_http_server_request_v0_t *)nd)->method,
250 		    sizeof (uint32_t))) :
251 		copyinstr(*(uint64_t *)copyin((uintptr_t)
252 		    &((node_dtrace_http_server_request64_v0_t *)nd)->method,
253 		    sizeof (uint64_t)))) :
254 	    (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
255 		copyinstr(*(uint32_t *)copyin((uintptr_t)
256 		    &((node_dtrace_http_server_request_v1_t *)nd)->method,
257 		    sizeof (uint32_t))) :
258 		copyinstr(*(uint64_t *)copyin((uintptr_t)
259 		    &((node_dtrace_http_server_request64_v1_t *)nd)->method,
260 		    sizeof (uint64_t))));
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 ?
274 	    (curpsinfo->pr_dmodel == PR_MODEL_ILP32 ?
275 		copyinstr(*(uint32_t *)copyin((uintptr_t)
276 		    &((node_dtrace_http_server_request_v0_t *)nd)->url,
277 		    sizeof (uint32_t))) :
278 		copyinstr(*(uint64_t *)copyin((uintptr_t)
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,
304 		    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))));
315 };
316