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