1 | /* |
2 | * CDDL HEADER START |
3 | * |
4 | * The contents of this file are subject to the terms of the |
5 | * Common Development and Distribution License (the "License"). |
6 | * You may not use this file except in compliance with the License. |
7 | * |
8 | * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
9 | * or http://www.opensolaris.org/os/licensing. |
10 | * See the License for the specific language governing permissions |
11 | * and limitations under the License. |
12 | * |
13 | * When distributing Covered Code, include this CDDL HEADER in each |
14 | * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
15 | * If applicable, add the following below this CDDL HEADER, with the |
16 | * fields enclosed by brackets "[]" replaced with your own identifying |
17 | * information: Portions Copyright [yyyy] [name of copyright owner] |
18 | * |
19 | * CDDL HEADER END |
20 | */ |
21 | |
22 | /* |
23 | * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
24 | * Copyright (c) 2011, 2016 by Delphix. All rights reserved. |
25 | * Copyright (c) 2013, Joyent Inc. All rights reserved. |
26 | * Copyright 2015 Gary Mills |
27 | */ |
28 | |
29 | /* |
30 | * DTrace D Language Compiler |
31 | * |
32 | * The code in this source file implements the main engine for the D language |
33 | * compiler. The driver routine for the compiler is dt_compile(), below. The |
34 | * compiler operates on either stdio FILEs or in-memory strings as its input |
35 | * and can produce either dtrace_prog_t structures from a D program or a single |
36 | * dtrace_difo_t structure from a D expression. Multiple entry points are |
37 | * provided as wrappers around dt_compile() for the various input/output pairs. |
38 | * The compiler itself is implemented across the following source files: |
39 | * |
40 | * dt_lex.l - lex scanner |
41 | * dt_grammar.y - yacc grammar |
42 | * dt_parser.c - parse tree creation and semantic checking |
43 | * dt_decl.c - declaration stack processing |
44 | * dt_xlator.c - D translator lookup and creation |
45 | * dt_ident.c - identifier and symbol table routines |
46 | * dt_pragma.c - #pragma processing and D pragmas |
47 | * dt_printf.c - D printf() and printa() argument checking and processing |
48 | * dt_cc.c - compiler driver and dtrace_prog_t construction |
49 | * dt_cg.c - DIF code generator |
50 | * dt_as.c - DIF assembler |
51 | * dt_dof.c - dtrace_prog_t -> DOF conversion |
52 | * |
53 | * Several other source files provide collections of utility routines used by |
54 | * these major files. The compiler itself is implemented in multiple passes: |
55 | * |
56 | * (1) The input program is scanned and parsed by dt_lex.l and dt_grammar.y |
57 | * and parse tree nodes are constructed using the routines in dt_parser.c. |
58 | * This node construction pass is described further in dt_parser.c. |
59 | * |
60 | * (2) The parse tree is "cooked" by assigning each clause a context (see the |
61 | * routine dt_setcontext(), below) based on its probe description and then |
62 | * recursively descending the tree performing semantic checking. The cook |
63 | * routines are also implemented in dt_parser.c and described there. |
64 | * |
65 | * (3) For actions that are DIF expression statements, the DIF code generator |
66 | * and assembler are invoked to create a finished DIFO for the statement. |
67 | * |
68 | * (4) The dtrace_prog_t data structures for the program clauses and actions |
69 | * are built, containing pointers to any DIFOs created in step (3). |
70 | * |
71 | * (5) The caller invokes a routine in dt_dof.c to convert the finished program |
72 | * into DOF format for use in anonymous tracing or enabling in the kernel. |
73 | * |
74 | * In the implementation, steps 2-4 are intertwined in that they are performed |
75 | * in order for each clause as part of a loop that executes over the clauses. |
76 | * |
77 | * The D compiler currently implements nearly no optimization. The compiler |
78 | * implements integer constant folding as part of pass (1), and a set of very |
79 | * simple peephole optimizations as part of pass (3). As with any C compiler, |
80 | * a large number of optimizations are possible on both the intermediate data |
81 | * structures and the generated DIF code. These possibilities should be |
82 | * investigated in the context of whether they will have any substantive effect |
83 | * on the overall DTrace probe effect before they are undertaken. |
84 | */ |
85 | |
86 | #include <sys/types.h> |
87 | #include <sys/wait.h> |
88 | #include <sys/sysmacros.h> |
89 | |
90 | #include <assert.h> |
91 | #include <string.h> |
92 | #include <strings.h> |
93 | #include <signal.h> |
94 | #include <unistd.h> |
95 | #include <stdlib.h> |
96 | #include <stdio.h> |
97 | #include <errno.h> |
98 | #include <ucontext.h> |
99 | #include <limits.h> |
100 | #include <ctype.h> |
101 | #include <dirent.h> |
102 | #include <dt_module.h> |
103 | #include <dt_program.h> |
104 | #include <dt_provider.h> |
105 | #include <dt_printf.h> |
106 | #include <dt_pid.h> |
107 | #include <dt_grammar.h> |
108 | #include <dt_ident.h> |
109 | #include <dt_string.h> |
110 | #include <dt_impl.h> |
111 | |
112 | static const dtrace_diftype_t dt_void_rtype = { |
113 | DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, 0 |
114 | }; |
115 | |
116 | static const dtrace_diftype_t dt_int_rtype = { |
117 | DIF_TYPE_CTF, CTF_K_INTEGER, 0, 0, sizeof (uint64_t) |
118 | }; |
119 | |
120 | static void *dt_compile(dtrace_hdl_t *, int, dtrace_probespec_t, void *, |
121 | uint_t, int, char *const[], FILE *, const char *); |
122 | |
123 | /*ARGSUSED*/ |
124 | static int |
125 | dt_idreset(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored) |
126 | { |
127 | idp->di_flags &= ~(DT_IDFLG_REF | DT_IDFLG_MOD | |
128 | DT_IDFLG_DIFR | DT_IDFLG_DIFW); |
129 | return (0); |
130 | } |
131 | |
132 | /*ARGSUSED*/ |
133 | static int |
134 | dt_idpragma(dt_idhash_t *dhp, dt_ident_t *idp, void *ignored) |
135 | { |
136 | yylineno = idp->di_lineno; |
137 | xyerror(D_PRAGMA_UNUSED, "unused #pragma %s\n" , (char *)idp->di_iarg); |
138 | return (0); |
139 | } |
140 | |
141 | static dtrace_stmtdesc_t * |
142 | dt_stmt_create(dtrace_hdl_t *dtp, dtrace_ecbdesc_t *edp, |
143 | dtrace_attribute_t descattr, dtrace_attribute_t stmtattr) |
144 | { |
145 | dtrace_stmtdesc_t *sdp = dtrace_stmt_create(dtp, edp); |
146 | |
147 | if (sdp == NULL) |
148 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
149 | |
150 | assert(yypcb->pcb_stmt == NULL); |
151 | yypcb->pcb_stmt = sdp; |
152 | |
153 | sdp->dtsd_descattr = descattr; |
154 | sdp->dtsd_stmtattr = stmtattr; |
155 | |
156 | return (sdp); |
157 | } |
158 | |
159 | static dtrace_actdesc_t * |
160 | dt_stmt_action(dtrace_hdl_t *dtp, dtrace_stmtdesc_t *sdp) |
161 | { |
162 | dtrace_actdesc_t *new; |
163 | |
164 | if ((new = dtrace_stmt_action(dtp, sdp)) == NULL) |
165 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
166 | |
167 | return (new); |
168 | } |
169 | |
170 | /* |
171 | * Utility function to determine if a given action description is destructive. |
172 | * The dtdo_destructive bit is set for us by the DIF assembler (see dt_as.c). |
173 | */ |
174 | static int |
175 | dt_action_destructive(const dtrace_actdesc_t *ap) |
176 | { |
177 | return (DTRACEACT_ISDESTRUCTIVE(ap->dtad_kind) || (ap->dtad_kind == |
178 | DTRACEACT_DIFEXPR && ap->dtad_difo->dtdo_destructive)); |
179 | } |
180 | |
181 | static void |
182 | dt_stmt_append(dtrace_stmtdesc_t *sdp, const dt_node_t *dnp) |
183 | { |
184 | dtrace_ecbdesc_t *edp = sdp->dtsd_ecbdesc; |
185 | dtrace_actdesc_t *ap, *tap; |
186 | int commit = 0; |
187 | int speculate = 0; |
188 | int datarec = 0; |
189 | |
190 | /* |
191 | * Make sure that the new statement jibes with the rest of the ECB. |
192 | */ |
193 | for (ap = edp->dted_action; ap != NULL; ap = ap->dtad_next) { |
194 | if (ap->dtad_kind == DTRACEACT_COMMIT) { |
195 | if (commit) { |
196 | dnerror(dnp, D_COMM_COMM, "commit( ) may " |
197 | "not follow commit( )\n" ); |
198 | } |
199 | |
200 | if (datarec) { |
201 | dnerror(dnp, D_COMM_DREC, "commit( ) may " |
202 | "not follow data-recording action(s)\n" ); |
203 | } |
204 | |
205 | for (tap = ap; tap != NULL; tap = tap->dtad_next) { |
206 | if (!DTRACEACT_ISAGG(tap->dtad_kind)) |
207 | continue; |
208 | |
209 | dnerror(dnp, D_AGG_COMM, "aggregating actions " |
210 | "may not follow commit( )\n" ); |
211 | } |
212 | |
213 | commit = 1; |
214 | continue; |
215 | } |
216 | |
217 | if (ap->dtad_kind == DTRACEACT_SPECULATE) { |
218 | if (speculate) { |
219 | dnerror(dnp, D_SPEC_SPEC, "speculate( ) may " |
220 | "not follow speculate( )\n" ); |
221 | } |
222 | |
223 | if (commit) { |
224 | dnerror(dnp, D_SPEC_COMM, "speculate( ) may " |
225 | "not follow commit( )\n" ); |
226 | } |
227 | |
228 | if (datarec) { |
229 | dnerror(dnp, D_SPEC_DREC, "speculate( ) may " |
230 | "not follow data-recording action(s)\n" ); |
231 | } |
232 | |
233 | speculate = 1; |
234 | continue; |
235 | } |
236 | |
237 | if (DTRACEACT_ISAGG(ap->dtad_kind)) { |
238 | if (speculate) { |
239 | dnerror(dnp, D_AGG_SPEC, "aggregating actions " |
240 | "may not follow speculate( )\n" ); |
241 | } |
242 | |
243 | datarec = 1; |
244 | continue; |
245 | } |
246 | |
247 | if (speculate) { |
248 | if (dt_action_destructive(ap)) { |
249 | dnerror(dnp, D_ACT_SPEC, "destructive actions " |
250 | "may not follow speculate( )\n" ); |
251 | } |
252 | |
253 | if (ap->dtad_kind == DTRACEACT_EXIT) { |
254 | dnerror(dnp, D_EXIT_SPEC, "exit( ) may not " |
255 | "follow speculate( )\n" ); |
256 | } |
257 | } |
258 | |
259 | /* |
260 | * Exclude all non data-recording actions. |
261 | */ |
262 | if (dt_action_destructive(ap) || |
263 | ap->dtad_kind == DTRACEACT_DISCARD) |
264 | continue; |
265 | |
266 | if (ap->dtad_kind == DTRACEACT_DIFEXPR && |
267 | ap->dtad_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_CTF && |
268 | ap->dtad_difo->dtdo_rtype.dtdt_size == 0) |
269 | continue; |
270 | |
271 | if (commit) { |
272 | dnerror(dnp, D_DREC_COMM, "data-recording actions " |
273 | "may not follow commit( )\n" ); |
274 | } |
275 | |
276 | if (!speculate) |
277 | datarec = 1; |
278 | } |
279 | |
280 | if (dtrace_stmt_add(yypcb->pcb_hdl, yypcb->pcb_prog, sdp) != 0) |
281 | longjmp(yypcb->pcb_jmpbuf, dtrace_errno(yypcb->pcb_hdl)); |
282 | |
283 | if (yypcb->pcb_stmt == sdp) |
284 | yypcb->pcb_stmt = NULL; |
285 | } |
286 | |
287 | /* |
288 | * For the first element of an aggregation tuple or for printa(), we create a |
289 | * simple DIF program that simply returns the immediate value that is the ID |
290 | * of the aggregation itself. This could be optimized in the future by |
291 | * creating a new in-kernel dtad_kind that just returns an integer. |
292 | */ |
293 | static void |
294 | dt_action_difconst(dtrace_actdesc_t *ap, uint_t id, dtrace_actkind_t kind) |
295 | { |
296 | dtrace_hdl_t *dtp = yypcb->pcb_hdl; |
297 | dtrace_difo_t *dp = dt_zalloc(dtp, sizeof (dtrace_difo_t)); |
298 | |
299 | if (dp == NULL) |
300 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
301 | |
302 | dp->dtdo_buf = dt_alloc(dtp, sizeof (dif_instr_t) * 2); |
303 | dp->dtdo_inttab = dt_alloc(dtp, sizeof (uint64_t)); |
304 | |
305 | if (dp->dtdo_buf == NULL || dp->dtdo_inttab == NULL) { |
306 | dt_difo_free(dtp, dp); |
307 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
308 | } |
309 | |
310 | dp->dtdo_buf[0] = DIF_INSTR_SETX(0, 1); /* setx DIF_INTEGER[0], %r1 */ |
311 | dp->dtdo_buf[1] = DIF_INSTR_RET(1); /* ret %r1 */ |
312 | dp->dtdo_len = 2; |
313 | dp->dtdo_inttab[0] = id; |
314 | dp->dtdo_intlen = 1; |
315 | dp->dtdo_rtype = dt_int_rtype; |
316 | |
317 | ap->dtad_difo = dp; |
318 | ap->dtad_kind = kind; |
319 | } |
320 | |
321 | static void |
322 | dt_action_clear(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
323 | { |
324 | dt_ident_t *aid; |
325 | dtrace_actdesc_t *ap; |
326 | dt_node_t *anp; |
327 | |
328 | char n[DT_TYPE_NAMELEN]; |
329 | int argc = 0; |
330 | |
331 | for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) |
332 | argc++; /* count up arguments for error messages below */ |
333 | |
334 | if (argc != 1) { |
335 | dnerror(dnp, D_CLEAR_PROTO, |
336 | "%s( ) prototype mismatch: %d args passed, 1 expected\n" , |
337 | dnp->dn_ident->di_name, argc); |
338 | } |
339 | |
340 | anp = dnp->dn_args; |
341 | assert(anp != NULL); |
342 | |
343 | if (anp->dn_kind != DT_NODE_AGG) { |
344 | dnerror(dnp, D_CLEAR_AGGARG, |
345 | "%s( ) argument #1 is incompatible with prototype:\n" |
346 | "\tprototype: aggregation\n\t argument: %s\n" , |
347 | dnp->dn_ident->di_name, |
348 | dt_node_type_name(anp, n, sizeof (n))); |
349 | } |
350 | |
351 | aid = anp->dn_ident; |
352 | |
353 | if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { |
354 | dnerror(dnp, D_CLEAR_AGGBAD, |
355 | "undefined aggregation: @%s\n" , aid->di_name); |
356 | } |
357 | |
358 | ap = dt_stmt_action(dtp, sdp); |
359 | dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); |
360 | ap->dtad_arg = DT_ACT_CLEAR; |
361 | } |
362 | |
363 | static void |
364 | dt_action_normalize(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
365 | { |
366 | dt_ident_t *aid; |
367 | dtrace_actdesc_t *ap; |
368 | dt_node_t *anp, *normal; |
369 | int denormal = (strcmp(dnp->dn_ident->di_name, "denormalize" ) == 0); |
370 | |
371 | char n[DT_TYPE_NAMELEN]; |
372 | int argc = 0; |
373 | |
374 | for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) |
375 | argc++; /* count up arguments for error messages below */ |
376 | |
377 | if ((denormal && argc != 1) || (!denormal && argc != 2)) { |
378 | dnerror(dnp, D_NORMALIZE_PROTO, |
379 | "%s( ) prototype mismatch: %d args passed, %d expected\n" , |
380 | dnp->dn_ident->di_name, argc, denormal ? 1 : 2); |
381 | } |
382 | |
383 | anp = dnp->dn_args; |
384 | assert(anp != NULL); |
385 | |
386 | if (anp->dn_kind != DT_NODE_AGG) { |
387 | dnerror(dnp, D_NORMALIZE_AGGARG, |
388 | "%s( ) argument #1 is incompatible with prototype:\n" |
389 | "\tprototype: aggregation\n\t argument: %s\n" , |
390 | dnp->dn_ident->di_name, |
391 | dt_node_type_name(anp, n, sizeof (n))); |
392 | } |
393 | |
394 | if ((normal = anp->dn_list) != NULL && !dt_node_is_scalar(normal)) { |
395 | dnerror(dnp, D_NORMALIZE_SCALAR, |
396 | "%s( ) argument #2 must be of scalar type\n" , |
397 | dnp->dn_ident->di_name); |
398 | } |
399 | |
400 | aid = anp->dn_ident; |
401 | |
402 | if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { |
403 | dnerror(dnp, D_NORMALIZE_AGGBAD, |
404 | "undefined aggregation: @%s\n" , aid->di_name); |
405 | } |
406 | |
407 | ap = dt_stmt_action(dtp, sdp); |
408 | dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); |
409 | |
410 | if (denormal) { |
411 | ap->dtad_arg = DT_ACT_DENORMALIZE; |
412 | return; |
413 | } |
414 | |
415 | ap->dtad_arg = DT_ACT_NORMALIZE; |
416 | |
417 | assert(normal != NULL); |
418 | ap = dt_stmt_action(dtp, sdp); |
419 | dt_cg(yypcb, normal); |
420 | |
421 | ap->dtad_difo = dt_as(yypcb); |
422 | ap->dtad_kind = DTRACEACT_LIBACT; |
423 | ap->dtad_arg = DT_ACT_NORMALIZE; |
424 | } |
425 | |
426 | static void |
427 | dt_action_trunc(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
428 | { |
429 | dt_ident_t *aid; |
430 | dtrace_actdesc_t *ap; |
431 | dt_node_t *anp, *trunc; |
432 | |
433 | char n[DT_TYPE_NAMELEN]; |
434 | int argc = 0; |
435 | |
436 | for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) |
437 | argc++; /* count up arguments for error messages below */ |
438 | |
439 | if (argc > 2 || argc < 1) { |
440 | dnerror(dnp, D_TRUNC_PROTO, |
441 | "%s( ) prototype mismatch: %d args passed, %s expected\n" , |
442 | dnp->dn_ident->di_name, argc, |
443 | argc < 1 ? "at least 1" : "no more than 2" ); |
444 | } |
445 | |
446 | anp = dnp->dn_args; |
447 | assert(anp != NULL); |
448 | trunc = anp->dn_list; |
449 | |
450 | if (anp->dn_kind != DT_NODE_AGG) { |
451 | dnerror(dnp, D_TRUNC_AGGARG, |
452 | "%s( ) argument #1 is incompatible with prototype:\n" |
453 | "\tprototype: aggregation\n\t argument: %s\n" , |
454 | dnp->dn_ident->di_name, |
455 | dt_node_type_name(anp, n, sizeof (n))); |
456 | } |
457 | |
458 | if (argc == 2) { |
459 | assert(trunc != NULL); |
460 | if (!dt_node_is_scalar(trunc)) { |
461 | dnerror(dnp, D_TRUNC_SCALAR, |
462 | "%s( ) argument #2 must be of scalar type\n" , |
463 | dnp->dn_ident->di_name); |
464 | } |
465 | } |
466 | |
467 | aid = anp->dn_ident; |
468 | |
469 | if (aid->di_gen == dtp->dt_gen && !(aid->di_flags & DT_IDFLG_MOD)) { |
470 | dnerror(dnp, D_TRUNC_AGGBAD, |
471 | "undefined aggregation: @%s\n" , aid->di_name); |
472 | } |
473 | |
474 | ap = dt_stmt_action(dtp, sdp); |
475 | dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_LIBACT); |
476 | ap->dtad_arg = DT_ACT_TRUNC; |
477 | |
478 | ap = dt_stmt_action(dtp, sdp); |
479 | |
480 | if (argc == 1) { |
481 | dt_action_difconst(ap, 0, DTRACEACT_LIBACT); |
482 | } else { |
483 | assert(trunc != NULL); |
484 | dt_cg(yypcb, trunc); |
485 | ap->dtad_difo = dt_as(yypcb); |
486 | ap->dtad_kind = DTRACEACT_LIBACT; |
487 | } |
488 | |
489 | ap->dtad_arg = DT_ACT_TRUNC; |
490 | } |
491 | |
492 | static void |
493 | dt_action_printa(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
494 | { |
495 | dt_ident_t *aid, *fid; |
496 | dtrace_actdesc_t *ap; |
497 | const char *format; |
498 | dt_node_t *anp, *proto = NULL; |
499 | |
500 | char n[DT_TYPE_NAMELEN]; |
501 | int argc = 0, argr = 0; |
502 | |
503 | for (anp = dnp->dn_args; anp != NULL; anp = anp->dn_list) |
504 | argc++; /* count up arguments for error messages below */ |
505 | |
506 | switch (dnp->dn_args->dn_kind) { |
507 | case DT_NODE_STRING: |
508 | format = dnp->dn_args->dn_string; |
509 | anp = dnp->dn_args->dn_list; |
510 | argr = 2; |
511 | break; |
512 | case DT_NODE_AGG: |
513 | format = NULL; |
514 | anp = dnp->dn_args; |
515 | argr = 1; |
516 | break; |
517 | default: |
518 | format = NULL; |
519 | anp = dnp->dn_args; |
520 | argr = 1; |
521 | } |
522 | |
523 | if (argc < argr) { |
524 | dnerror(dnp, D_PRINTA_PROTO, |
525 | "%s( ) prototype mismatch: %d args passed, %d expected\n" , |
526 | dnp->dn_ident->di_name, argc, argr); |
527 | } |
528 | |
529 | assert(anp != NULL); |
530 | |
531 | while (anp != NULL) { |
532 | if (anp->dn_kind != DT_NODE_AGG) { |
533 | dnerror(dnp, D_PRINTA_AGGARG, |
534 | "%s( ) argument #%d is incompatible with " |
535 | "prototype:\n\tprototype: aggregation\n" |
536 | "\t argument: %s\n" , dnp->dn_ident->di_name, argr, |
537 | dt_node_type_name(anp, n, sizeof (n))); |
538 | } |
539 | |
540 | aid = anp->dn_ident; |
541 | fid = aid->di_iarg; |
542 | |
543 | if (aid->di_gen == dtp->dt_gen && |
544 | !(aid->di_flags & DT_IDFLG_MOD)) { |
545 | dnerror(dnp, D_PRINTA_AGGBAD, |
546 | "undefined aggregation: @%s\n" , aid->di_name); |
547 | } |
548 | |
549 | /* |
550 | * If we have multiple aggregations, we must be sure that |
551 | * their key signatures match. |
552 | */ |
553 | if (proto != NULL) { |
554 | dt_printa_validate(proto, anp); |
555 | } else { |
556 | proto = anp; |
557 | } |
558 | |
559 | if (format != NULL) { |
560 | yylineno = dnp->dn_line; |
561 | |
562 | sdp->dtsd_fmtdata = |
563 | dt_printf_create(yypcb->pcb_hdl, format); |
564 | dt_printf_validate(sdp->dtsd_fmtdata, |
565 | DT_PRINTF_AGGREGATION, dnp->dn_ident, 1, |
566 | fid->di_id, ((dt_idsig_t *)aid->di_data)->dis_args); |
567 | format = NULL; |
568 | } |
569 | |
570 | ap = dt_stmt_action(dtp, sdp); |
571 | dt_action_difconst(ap, anp->dn_ident->di_id, DTRACEACT_PRINTA); |
572 | |
573 | anp = anp->dn_list; |
574 | argr++; |
575 | } |
576 | } |
577 | |
578 | static void |
579 | dt_action_printflike(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp, |
580 | dtrace_actkind_t kind) |
581 | { |
582 | dt_node_t *anp, *arg1; |
583 | dtrace_actdesc_t *ap = NULL; |
584 | char n[DT_TYPE_NAMELEN], *str; |
585 | |
586 | assert(DTRACEACT_ISPRINTFLIKE(kind)); |
587 | |
588 | if (dnp->dn_args->dn_kind != DT_NODE_STRING) { |
589 | dnerror(dnp, D_PRINTF_ARG_FMT, |
590 | "%s( ) argument #1 is incompatible with prototype:\n" |
591 | "\tprototype: string constant\n\t argument: %s\n" , |
592 | dnp->dn_ident->di_name, |
593 | dt_node_type_name(dnp->dn_args, n, sizeof (n))); |
594 | } |
595 | |
596 | arg1 = dnp->dn_args->dn_list; |
597 | yylineno = dnp->dn_line; |
598 | str = dnp->dn_args->dn_string; |
599 | |
600 | |
601 | /* |
602 | * If this is an freopen(), we use an empty string to denote that |
603 | * stdout should be restored. For other printf()-like actions, an |
604 | * empty format string is illegal: an empty format string would |
605 | * result in malformed DOF, and the compiler thus flags an empty |
606 | * format string as a compile-time error. To avoid propagating the |
607 | * freopen() special case throughout the system, we simply transpose |
608 | * an empty string into a sentinel string (DT_FREOPEN_RESTORE) that |
609 | * denotes that stdout should be restored. |
610 | */ |
611 | if (kind == DTRACEACT_FREOPEN) { |
612 | if (strcmp(str, DT_FREOPEN_RESTORE) == 0) { |
613 | /* |
614 | * Our sentinel is always an invalid argument to |
615 | * freopen(), but if it's been manually specified, we |
616 | * must fail now instead of when the freopen() is |
617 | * actually evaluated. |
618 | */ |
619 | dnerror(dnp, D_FREOPEN_INVALID, |
620 | "%s( ) argument #1 cannot be \"%s\"\n" , |
621 | dnp->dn_ident->di_name, DT_FREOPEN_RESTORE); |
622 | } |
623 | |
624 | if (str[0] == '\0') |
625 | str = __UNCONST(DT_FREOPEN_RESTORE); |
626 | } |
627 | |
628 | sdp->dtsd_fmtdata = dt_printf_create(dtp, str); |
629 | |
630 | dt_printf_validate(sdp->dtsd_fmtdata, DT_PRINTF_EXACTLEN, |
631 | dnp->dn_ident, 1, DTRACEACT_AGGREGATION, arg1); |
632 | |
633 | if (arg1 == NULL) { |
634 | dif_instr_t *dbuf; |
635 | dtrace_difo_t *dp; |
636 | |
637 | if ((dbuf = dt_alloc(dtp, sizeof (dif_instr_t))) == NULL || |
638 | (dp = dt_zalloc(dtp, sizeof (dtrace_difo_t))) == NULL) { |
639 | dt_free(dtp, dbuf); |
640 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
641 | } |
642 | |
643 | dbuf[0] = DIF_INSTR_RET(DIF_REG_R0); /* ret %r0 */ |
644 | |
645 | dp->dtdo_buf = dbuf; |
646 | dp->dtdo_len = 1; |
647 | dp->dtdo_rtype = dt_int_rtype; |
648 | |
649 | ap = dt_stmt_action(dtp, sdp); |
650 | ap->dtad_difo = dp; |
651 | ap->dtad_kind = kind; |
652 | return; |
653 | } |
654 | |
655 | for (anp = arg1; anp != NULL; anp = anp->dn_list) { |
656 | ap = dt_stmt_action(dtp, sdp); |
657 | dt_cg(yypcb, anp); |
658 | ap->dtad_difo = dt_as(yypcb); |
659 | ap->dtad_kind = kind; |
660 | } |
661 | } |
662 | |
663 | static void |
664 | dt_action_trace(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
665 | { |
666 | int ctflib = 0; // XXX: gcc |
667 | |
668 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
669 | boolean_t istrace = (dnp->dn_ident->di_id == DT_ACT_TRACE); |
670 | const char *act = istrace ? "trace" : "print" ; |
671 | |
672 | if (dt_node_is_void(dnp->dn_args)) { |
673 | dnerror(dnp->dn_args, istrace ? D_TRACE_VOID : D_PRINT_VOID, |
674 | "%s( ) may not be applied to a void expression\n" , act); |
675 | } |
676 | |
677 | if (dt_node_resolve(dnp->dn_args, DT_IDENT_XLPTR) != NULL) { |
678 | dnerror(dnp->dn_args, istrace ? D_TRACE_DYN : D_PRINT_DYN, |
679 | "%s( ) may not be applied to a translated pointer\n" , act); |
680 | } |
681 | |
682 | if (dnp->dn_args->dn_kind == DT_NODE_AGG) { |
683 | dnerror(dnp->dn_args, istrace ? D_TRACE_AGG : D_PRINT_AGG, |
684 | "%s( ) may not be applied to an aggregation%s\n" , act, |
685 | istrace ? "" : " -- did you mean printa()?" ); |
686 | } |
687 | |
688 | dt_cg(yypcb, dnp->dn_args); |
689 | |
690 | /* |
691 | * The print() action behaves identically to trace(), except that it |
692 | * stores the CTF type of the argument (if present) within the DOF for |
693 | * the DIFEXPR action. To do this, we set the 'dtsd_strdata' to point |
694 | * to the fully-qualified CTF type ID for the result of the DIF |
695 | * action. We use the ID instead of the name to handles complex types |
696 | * like arrays and function pointers that can't be resolved by |
697 | * ctf_type_lookup(). This is later processed by dtrace_dof_create() |
698 | * and turned into a reference into the string table so that we can |
699 | * get the type information when we process the data after the fact. In |
700 | * the case where we are referring to userland CTF data, we also need to |
701 | * to identify which ctf container in question we care about and encode |
702 | * that within the name. |
703 | */ |
704 | if (dnp->dn_ident->di_id == DT_ACT_PRINT) { |
705 | dt_node_t *dret; |
706 | size_t n; |
707 | dt_module_t *dmp; |
708 | |
709 | dret = yypcb->pcb_dret; |
710 | dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp); |
711 | |
712 | n = snprintf(NULL, 0, "%s`%ld" , dmp->dm_name, dret->dn_type) + 1; |
713 | if (dmp->dm_pid != 0) { |
714 | ctflib = dt_module_getlibid(dtp, dmp, dret->dn_ctfp); |
715 | assert(ctflib >= 0); |
716 | n = snprintf(NULL, 0, "%s`%d`%ld" , dmp->dm_name, |
717 | ctflib, dret->dn_type) + 1; |
718 | } else { |
719 | n = snprintf(NULL, 0, "%s`%ld" , dmp->dm_name, |
720 | dret->dn_type) + 1; |
721 | } |
722 | sdp->dtsd_strdata = dt_alloc(dtp, n); |
723 | if (sdp->dtsd_strdata == NULL) |
724 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
725 | (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld" , dmp->dm_name, |
726 | dret->dn_type); |
727 | if (dmp->dm_pid != 0) { |
728 | (void) snprintf(sdp->dtsd_strdata, n, "%s`%d`%ld" , |
729 | dmp->dm_name, ctflib, dret->dn_type); |
730 | } else { |
731 | (void) snprintf(sdp->dtsd_strdata, n, "%s`%ld" , |
732 | dmp->dm_name, dret->dn_type); |
733 | } |
734 | } |
735 | |
736 | ap->dtad_difo = dt_as(yypcb); |
737 | ap->dtad_kind = DTRACEACT_DIFEXPR; |
738 | } |
739 | |
740 | static void |
741 | dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
742 | { |
743 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
744 | |
745 | dt_node_t *addr = dnp->dn_args; |
746 | dt_node_t *max = dnp->dn_args->dn_list; |
747 | dt_node_t *size; |
748 | |
749 | char n[DT_TYPE_NAMELEN]; |
750 | |
751 | if (dt_node_is_integer(addr) == 0 && dt_node_is_pointer(addr) == 0) { |
752 | dnerror(addr, D_TRACEMEM_ADDR, |
753 | "tracemem( ) argument #1 is incompatible with " |
754 | "prototype:\n\tprototype: pointer or integer\n" |
755 | "\t argument: %s\n" , |
756 | dt_node_type_name(addr, n, sizeof (n))); |
757 | } |
758 | |
759 | if (dt_node_is_posconst(max) == 0) { |
760 | dnerror(max, D_TRACEMEM_SIZE, "tracemem( ) argument #2 must " |
761 | "be a non-zero positive integral constant expression\n" ); |
762 | } |
763 | |
764 | if ((size = max->dn_list) != NULL) { |
765 | if (size->dn_list != NULL) { |
766 | dnerror(size, D_TRACEMEM_ARGS, "tracemem ( ) prototype " |
767 | "mismatch: expected at most 3 args\n" ); |
768 | } |
769 | |
770 | if (!dt_node_is_scalar(size)) { |
771 | dnerror(size, D_TRACEMEM_DYNSIZE, "tracemem ( ) " |
772 | "dynamic size (argument #3) must be of " |
773 | "scalar type\n" ); |
774 | } |
775 | |
776 | dt_cg(yypcb, size); |
777 | ap->dtad_difo = dt_as(yypcb); |
778 | ap->dtad_difo->dtdo_rtype = dt_int_rtype; |
779 | ap->dtad_kind = DTRACEACT_TRACEMEM_DYNSIZE; |
780 | |
781 | ap = dt_stmt_action(dtp, sdp); |
782 | } |
783 | |
784 | dt_cg(yypcb, addr); |
785 | ap->dtad_difo = dt_as(yypcb); |
786 | ap->dtad_kind = DTRACEACT_TRACEMEM; |
787 | |
788 | ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF; |
789 | ap->dtad_difo->dtdo_rtype.dtdt_size = max->dn_value; |
790 | } |
791 | |
792 | static void |
793 | dt_action_stack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *arg0) |
794 | { |
795 | ap->dtad_kind = DTRACEACT_STACK; |
796 | |
797 | if (dtp->dt_options[DTRACEOPT_STACKFRAMES] != DTRACEOPT_UNSET) { |
798 | ap->dtad_arg = dtp->dt_options[DTRACEOPT_STACKFRAMES]; |
799 | } else { |
800 | ap->dtad_arg = 0; |
801 | } |
802 | |
803 | if (arg0 != NULL) { |
804 | if (arg0->dn_list != NULL) { |
805 | dnerror(arg0, D_STACK_PROTO, "stack( ) prototype " |
806 | "mismatch: too many arguments\n" ); |
807 | } |
808 | |
809 | if (dt_node_is_posconst(arg0) == 0) { |
810 | dnerror(arg0, D_STACK_SIZE, "stack( ) size must be a " |
811 | "non-zero positive integral constant expression\n" ); |
812 | } |
813 | |
814 | ap->dtad_arg = arg0->dn_value; |
815 | } |
816 | } |
817 | |
818 | static void |
819 | dt_action_stack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
820 | { |
821 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
822 | dt_action_stack_args(dtp, ap, dnp->dn_args); |
823 | } |
824 | |
825 | static void |
826 | dt_action_ustack_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, dt_node_t *dnp) |
827 | { |
828 | uint32_t nframes = 0; |
829 | uint32_t strsize = 0; /* default string table size */ |
830 | dt_node_t *arg0 = dnp->dn_args; |
831 | dt_node_t *arg1 = arg0 != NULL ? arg0->dn_list : NULL; |
832 | |
833 | assert(dnp->dn_ident->di_id == DT_ACT_JSTACK || |
834 | dnp->dn_ident->di_id == DT_ACT_USTACK); |
835 | |
836 | if (dnp->dn_ident->di_id == DT_ACT_JSTACK) { |
837 | if (dtp->dt_options[DTRACEOPT_JSTACKFRAMES] != DTRACEOPT_UNSET) |
838 | nframes = dtp->dt_options[DTRACEOPT_JSTACKFRAMES]; |
839 | |
840 | if (dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE] != DTRACEOPT_UNSET) |
841 | strsize = dtp->dt_options[DTRACEOPT_JSTACKSTRSIZE]; |
842 | |
843 | ap->dtad_kind = DTRACEACT_JSTACK; |
844 | } else { |
845 | assert(dnp->dn_ident->di_id == DT_ACT_USTACK); |
846 | |
847 | if (dtp->dt_options[DTRACEOPT_USTACKFRAMES] != DTRACEOPT_UNSET) |
848 | nframes = dtp->dt_options[DTRACEOPT_USTACKFRAMES]; |
849 | |
850 | ap->dtad_kind = DTRACEACT_USTACK; |
851 | } |
852 | |
853 | if (arg0 != NULL) { |
854 | if (!dt_node_is_posconst(arg0)) { |
855 | dnerror(arg0, D_USTACK_FRAMES, "ustack( ) argument #1 " |
856 | "must be a non-zero positive integer constant\n" ); |
857 | } |
858 | nframes = (uint32_t)arg0->dn_value; |
859 | } |
860 | |
861 | if (arg1 != NULL) { |
862 | if (arg1->dn_kind != DT_NODE_INT || |
863 | ((arg1->dn_flags & DT_NF_SIGNED) && |
864 | (int64_t)arg1->dn_value < 0)) { |
865 | dnerror(arg1, D_USTACK_STRSIZE, "ustack( ) argument #2 " |
866 | "must be a positive integer constant\n" ); |
867 | } |
868 | |
869 | if (arg1->dn_list != NULL) { |
870 | dnerror(arg1, D_USTACK_PROTO, "ustack( ) prototype " |
871 | "mismatch: too many arguments\n" ); |
872 | } |
873 | |
874 | strsize = (uint32_t)arg1->dn_value; |
875 | } |
876 | |
877 | ap->dtad_arg = DTRACE_USTACK_ARG(nframes, strsize); |
878 | } |
879 | |
880 | static void |
881 | dt_action_ustack(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
882 | { |
883 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
884 | dt_action_ustack_args(dtp, ap, dnp); |
885 | } |
886 | |
887 | static void |
888 | dt_action_setopt(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
889 | { |
890 | dtrace_actdesc_t *ap; |
891 | dt_node_t *arg0, *arg1; |
892 | |
893 | /* |
894 | * The prototype guarantees that we are called with either one or |
895 | * two arguments, and that any arguments that are present are strings. |
896 | */ |
897 | arg0 = dnp->dn_args; |
898 | arg1 = arg0->dn_list; |
899 | |
900 | ap = dt_stmt_action(dtp, sdp); |
901 | dt_cg(yypcb, arg0); |
902 | ap->dtad_difo = dt_as(yypcb); |
903 | ap->dtad_kind = DTRACEACT_LIBACT; |
904 | ap->dtad_arg = DT_ACT_SETOPT; |
905 | |
906 | ap = dt_stmt_action(dtp, sdp); |
907 | |
908 | if (arg1 == NULL) { |
909 | dt_action_difconst(ap, 0, DTRACEACT_LIBACT); |
910 | } else { |
911 | dt_cg(yypcb, arg1); |
912 | ap->dtad_difo = dt_as(yypcb); |
913 | ap->dtad_kind = DTRACEACT_LIBACT; |
914 | } |
915 | |
916 | ap->dtad_arg = DT_ACT_SETOPT; |
917 | } |
918 | |
919 | /*ARGSUSED*/ |
920 | static void |
921 | dt_action_symmod_args(dtrace_hdl_t *dtp, dtrace_actdesc_t *ap, |
922 | dt_node_t *dnp, dtrace_actkind_t kind) |
923 | { |
924 | assert(kind == DTRACEACT_SYM || kind == DTRACEACT_MOD || |
925 | kind == DTRACEACT_USYM || kind == DTRACEACT_UMOD || |
926 | kind == DTRACEACT_UADDR); |
927 | |
928 | dt_cg(yypcb, dnp); |
929 | ap->dtad_difo = dt_as(yypcb); |
930 | ap->dtad_kind = kind; |
931 | ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (uint64_t); |
932 | } |
933 | |
934 | static void |
935 | dt_action_symmod(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp, |
936 | dtrace_actkind_t kind) |
937 | { |
938 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
939 | dt_action_symmod_args(dtp, ap, dnp->dn_args, kind); |
940 | } |
941 | |
942 | /*ARGSUSED*/ |
943 | static void |
944 | dt_action_ftruncate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
945 | { |
946 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
947 | |
948 | /* |
949 | * Library actions need a DIFO that serves as an argument. As |
950 | * ftruncate() doesn't take an argument, we generate the constant 0 |
951 | * in a DIFO; this constant will be ignored when the ftruncate() is |
952 | * processed. |
953 | */ |
954 | dt_action_difconst(ap, 0, DTRACEACT_LIBACT); |
955 | ap->dtad_arg = DT_ACT_FTRUNCATE; |
956 | } |
957 | |
958 | /*ARGSUSED*/ |
959 | static void |
960 | dt_action_stop(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
961 | { |
962 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
963 | |
964 | ap->dtad_kind = DTRACEACT_STOP; |
965 | ap->dtad_arg = 0; |
966 | } |
967 | |
968 | /*ARGSUSED*/ |
969 | static void |
970 | dt_action_breakpoint(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
971 | { |
972 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
973 | |
974 | ap->dtad_kind = DTRACEACT_BREAKPOINT; |
975 | ap->dtad_arg = 0; |
976 | } |
977 | |
978 | /*ARGSUSED*/ |
979 | static void |
980 | dt_action_panic(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
981 | { |
982 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
983 | |
984 | ap->dtad_kind = DTRACEACT_PANIC; |
985 | ap->dtad_arg = 0; |
986 | } |
987 | |
988 | static void |
989 | dt_action_chill(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
990 | { |
991 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
992 | |
993 | dt_cg(yypcb, dnp->dn_args); |
994 | ap->dtad_difo = dt_as(yypcb); |
995 | ap->dtad_kind = DTRACEACT_CHILL; |
996 | } |
997 | |
998 | static void |
999 | dt_action_raise(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1000 | { |
1001 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1002 | |
1003 | dt_cg(yypcb, dnp->dn_args); |
1004 | ap->dtad_difo = dt_as(yypcb); |
1005 | ap->dtad_kind = DTRACEACT_RAISE; |
1006 | } |
1007 | |
1008 | static void |
1009 | dt_action_exit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1010 | { |
1011 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1012 | |
1013 | dt_cg(yypcb, dnp->dn_args); |
1014 | ap->dtad_difo = dt_as(yypcb); |
1015 | ap->dtad_kind = DTRACEACT_EXIT; |
1016 | ap->dtad_difo->dtdo_rtype.dtdt_size = sizeof (int); |
1017 | } |
1018 | |
1019 | static void |
1020 | dt_action_speculate(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1021 | { |
1022 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1023 | |
1024 | dt_cg(yypcb, dnp->dn_args); |
1025 | ap->dtad_difo = dt_as(yypcb); |
1026 | ap->dtad_kind = DTRACEACT_SPECULATE; |
1027 | } |
1028 | |
1029 | static void |
1030 | dt_action_printm(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1031 | { |
1032 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1033 | |
1034 | dt_node_t *size = dnp->dn_args; |
1035 | dt_node_t *addr = dnp->dn_args->dn_list; |
1036 | |
1037 | char n[DT_TYPE_NAMELEN]; |
1038 | |
1039 | if (dt_node_is_posconst(size) == 0) { |
1040 | dnerror(size, D_PRINTM_SIZE, "printm( ) argument #1 must " |
1041 | "be a non-zero positive integral constant expression\n" ); |
1042 | } |
1043 | |
1044 | if (dt_node_is_pointer(addr) == 0) { |
1045 | dnerror(addr, D_PRINTM_ADDR, |
1046 | "printm( ) argument #2 is incompatible with " |
1047 | "prototype:\n\tprototype: pointer\n" |
1048 | "\t argument: %s\n" , |
1049 | dt_node_type_name(addr, n, sizeof (n))); |
1050 | } |
1051 | |
1052 | dt_cg(yypcb, addr); |
1053 | ap->dtad_difo = dt_as(yypcb); |
1054 | ap->dtad_kind = DTRACEACT_PRINTM; |
1055 | |
1056 | ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF; |
1057 | ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value + sizeof(uintptr_t); |
1058 | } |
1059 | |
1060 | static void |
1061 | dt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1062 | { |
1063 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1064 | |
1065 | dt_cg(yypcb, dnp->dn_args); |
1066 | ap->dtad_difo = dt_as(yypcb); |
1067 | ap->dtad_kind = DTRACEACT_COMMIT; |
1068 | } |
1069 | |
1070 | static void |
1071 | dt_action_discard(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1072 | { |
1073 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1074 | |
1075 | dt_cg(yypcb, dnp->dn_args); |
1076 | ap->dtad_difo = dt_as(yypcb); |
1077 | ap->dtad_kind = DTRACEACT_DISCARD; |
1078 | } |
1079 | |
1080 | static void |
1081 | dt_compile_fun(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1082 | { |
1083 | switch (dnp->dn_expr->dn_ident->di_id) { |
1084 | case DT_ACT_BREAKPOINT: |
1085 | dt_action_breakpoint(dtp, dnp->dn_expr, sdp); |
1086 | break; |
1087 | case DT_ACT_CHILL: |
1088 | dt_action_chill(dtp, dnp->dn_expr, sdp); |
1089 | break; |
1090 | case DT_ACT_CLEAR: |
1091 | dt_action_clear(dtp, dnp->dn_expr, sdp); |
1092 | break; |
1093 | case DT_ACT_COMMIT: |
1094 | dt_action_commit(dtp, dnp->dn_expr, sdp); |
1095 | break; |
1096 | case DT_ACT_DENORMALIZE: |
1097 | dt_action_normalize(dtp, dnp->dn_expr, sdp); |
1098 | break; |
1099 | case DT_ACT_DISCARD: |
1100 | dt_action_discard(dtp, dnp->dn_expr, sdp); |
1101 | break; |
1102 | case DT_ACT_EXIT: |
1103 | dt_action_exit(dtp, dnp->dn_expr, sdp); |
1104 | break; |
1105 | case DT_ACT_FREOPEN: |
1106 | dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_FREOPEN); |
1107 | break; |
1108 | case DT_ACT_FTRUNCATE: |
1109 | dt_action_ftruncate(dtp, dnp->dn_expr, sdp); |
1110 | break; |
1111 | case DT_ACT_MOD: |
1112 | dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_MOD); |
1113 | break; |
1114 | case DT_ACT_NORMALIZE: |
1115 | dt_action_normalize(dtp, dnp->dn_expr, sdp); |
1116 | break; |
1117 | case DT_ACT_PANIC: |
1118 | dt_action_panic(dtp, dnp->dn_expr, sdp); |
1119 | break; |
1120 | case DT_ACT_PRINT: |
1121 | dt_action_trace(dtp, dnp->dn_expr, sdp); |
1122 | break; |
1123 | case DT_ACT_PRINTA: |
1124 | dt_action_printa(dtp, dnp->dn_expr, sdp); |
1125 | break; |
1126 | case DT_ACT_PRINTF: |
1127 | dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_PRINTF); |
1128 | break; |
1129 | case DT_ACT_PRINTM: |
1130 | dt_action_printm(dtp, dnp->dn_expr, sdp); |
1131 | break; |
1132 | case DT_ACT_RAISE: |
1133 | dt_action_raise(dtp, dnp->dn_expr, sdp); |
1134 | break; |
1135 | case DT_ACT_SETOPT: |
1136 | dt_action_setopt(dtp, dnp->dn_expr, sdp); |
1137 | break; |
1138 | case DT_ACT_SPECULATE: |
1139 | dt_action_speculate(dtp, dnp->dn_expr, sdp); |
1140 | break; |
1141 | case DT_ACT_STACK: |
1142 | dt_action_stack(dtp, dnp->dn_expr, sdp); |
1143 | break; |
1144 | case DT_ACT_STOP: |
1145 | dt_action_stop(dtp, dnp->dn_expr, sdp); |
1146 | break; |
1147 | case DT_ACT_SYM: |
1148 | dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_SYM); |
1149 | break; |
1150 | case DT_ACT_SYSTEM: |
1151 | dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_SYSTEM); |
1152 | break; |
1153 | case DT_ACT_TRACE: |
1154 | dt_action_trace(dtp, dnp->dn_expr, sdp); |
1155 | break; |
1156 | case DT_ACT_TRACEMEM: |
1157 | dt_action_tracemem(dtp, dnp->dn_expr, sdp); |
1158 | break; |
1159 | case DT_ACT_TRUNC: |
1160 | dt_action_trunc(dtp, dnp->dn_expr, sdp); |
1161 | break; |
1162 | case DT_ACT_UADDR: |
1163 | dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UADDR); |
1164 | break; |
1165 | case DT_ACT_UMOD: |
1166 | dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_UMOD); |
1167 | break; |
1168 | case DT_ACT_USYM: |
1169 | dt_action_symmod(dtp, dnp->dn_expr, sdp, DTRACEACT_USYM); |
1170 | break; |
1171 | case DT_ACT_USTACK: |
1172 | case DT_ACT_JSTACK: |
1173 | dt_action_ustack(dtp, dnp->dn_expr, sdp); |
1174 | break; |
1175 | default: |
1176 | dnerror(dnp->dn_expr, D_UNKNOWN, "tracing function %s( ) is " |
1177 | "not yet supported\n" , dnp->dn_expr->dn_ident->di_name); |
1178 | } |
1179 | } |
1180 | |
1181 | static void |
1182 | dt_compile_exp(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1183 | { |
1184 | dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp); |
1185 | |
1186 | dt_cg(yypcb, dnp->dn_expr); |
1187 | ap->dtad_difo = dt_as(yypcb); |
1188 | ap->dtad_difo->dtdo_rtype = dt_void_rtype; |
1189 | ap->dtad_kind = DTRACEACT_DIFEXPR; |
1190 | } |
1191 | |
1192 | static void |
1193 | dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) |
1194 | { |
1195 | dt_ident_t *aid, *fid; |
1196 | dt_node_t *anp, *incr = NULL; |
1197 | dtrace_actdesc_t *ap; |
1198 | uint_t n = 1, argmax; |
1199 | uint64_t arg = 0; |
1200 | |
1201 | /* |
1202 | * If the aggregation has no aggregating function applied to it, then |
1203 | * this statement has no effect. Flag this as a programming error. |
1204 | */ |
1205 | if (dnp->dn_aggfun == NULL) { |
1206 | dnerror(dnp, D_AGG_NULL, "expression has null effect: @%s\n" , |
1207 | dnp->dn_ident->di_name); |
1208 | } |
1209 | |
1210 | aid = dnp->dn_ident; |
1211 | fid = dnp->dn_aggfun->dn_ident; |
1212 | |
1213 | if (dnp->dn_aggfun->dn_args != NULL && |
1214 | dt_node_is_scalar(dnp->dn_aggfun->dn_args) == 0) { |
1215 | dnerror(dnp->dn_aggfun, D_AGG_SCALAR, "%s( ) argument #1 must " |
1216 | "be of scalar type\n" , fid->di_name); |
1217 | } |
1218 | |
1219 | /* |
1220 | * The ID of the aggregation itself is implicitly recorded as the first |
1221 | * member of each aggregation tuple so we can distinguish them later. |
1222 | */ |
1223 | ap = dt_stmt_action(dtp, sdp); |
1224 | dt_action_difconst(ap, aid->di_id, DTRACEACT_DIFEXPR); |
1225 | |
1226 | for (anp = dnp->dn_aggtup; anp != NULL; anp = anp->dn_list) { |
1227 | ap = dt_stmt_action(dtp, sdp); |
1228 | n++; |
1229 | |
1230 | if (anp->dn_kind == DT_NODE_FUNC) { |
1231 | if (anp->dn_ident->di_id == DT_ACT_STACK) { |
1232 | dt_action_stack_args(dtp, ap, anp->dn_args); |
1233 | continue; |
1234 | } |
1235 | |
1236 | if (anp->dn_ident->di_id == DT_ACT_USTACK || |
1237 | anp->dn_ident->di_id == DT_ACT_JSTACK) { |
1238 | dt_action_ustack_args(dtp, ap, anp); |
1239 | continue; |
1240 | } |
1241 | |
1242 | switch (anp->dn_ident->di_id) { |
1243 | case DT_ACT_UADDR: |
1244 | dt_action_symmod_args(dtp, ap, |
1245 | anp->dn_args, DTRACEACT_UADDR); |
1246 | continue; |
1247 | |
1248 | case DT_ACT_USYM: |
1249 | dt_action_symmod_args(dtp, ap, |
1250 | anp->dn_args, DTRACEACT_USYM); |
1251 | continue; |
1252 | |
1253 | case DT_ACT_UMOD: |
1254 | dt_action_symmod_args(dtp, ap, |
1255 | anp->dn_args, DTRACEACT_UMOD); |
1256 | continue; |
1257 | |
1258 | case DT_ACT_SYM: |
1259 | dt_action_symmod_args(dtp, ap, |
1260 | anp->dn_args, DTRACEACT_SYM); |
1261 | continue; |
1262 | |
1263 | case DT_ACT_MOD: |
1264 | dt_action_symmod_args(dtp, ap, |
1265 | anp->dn_args, DTRACEACT_MOD); |
1266 | continue; |
1267 | |
1268 | default: |
1269 | break; |
1270 | } |
1271 | } |
1272 | |
1273 | dt_cg(yypcb, anp); |
1274 | ap->dtad_difo = dt_as(yypcb); |
1275 | ap->dtad_kind = DTRACEACT_DIFEXPR; |
1276 | } |
1277 | |
1278 | if (fid->di_id == DTRACEAGG_LQUANTIZE) { |
1279 | /* |
1280 | * For linear quantization, we have between two and four |
1281 | * arguments in addition to the expression: |
1282 | * |
1283 | * arg1 => Base value |
1284 | * arg2 => Limit value |
1285 | * arg3 => Quantization level step size (defaults to 1) |
1286 | * arg4 => Quantization increment value (defaults to 1) |
1287 | */ |
1288 | dt_node_t *arg1 = dnp->dn_aggfun->dn_args->dn_list; |
1289 | dt_node_t *arg2 = arg1->dn_list; |
1290 | dt_node_t *arg3 = arg2->dn_list; |
1291 | dt_idsig_t *isp; |
1292 | uint64_t nlevels, step = 1, oarg; |
1293 | int64_t baseval, limitval; |
1294 | |
1295 | if (arg1->dn_kind != DT_NODE_INT) { |
1296 | dnerror(arg1, D_LQUANT_BASETYPE, "lquantize( ) " |
1297 | "argument #1 must be an integer constant\n" ); |
1298 | } |
1299 | |
1300 | baseval = (int64_t)arg1->dn_value; |
1301 | |
1302 | if (baseval < INT32_MIN || baseval > INT32_MAX) { |
1303 | dnerror(arg1, D_LQUANT_BASEVAL, "lquantize( ) " |
1304 | "argument #1 must be a 32-bit quantity\n" ); |
1305 | } |
1306 | |
1307 | if (arg2->dn_kind != DT_NODE_INT) { |
1308 | dnerror(arg2, D_LQUANT_LIMTYPE, "lquantize( ) " |
1309 | "argument #2 must be an integer constant\n" ); |
1310 | } |
1311 | |
1312 | limitval = (int64_t)arg2->dn_value; |
1313 | |
1314 | if (limitval < INT32_MIN || limitval > INT32_MAX) { |
1315 | dnerror(arg2, D_LQUANT_LIMVAL, "lquantize( ) " |
1316 | "argument #2 must be a 32-bit quantity\n" ); |
1317 | } |
1318 | |
1319 | if (limitval < baseval) { |
1320 | dnerror(dnp, D_LQUANT_MISMATCH, |
1321 | "lquantize( ) base (argument #1) must be less " |
1322 | "than limit (argument #2)\n" ); |
1323 | } |
1324 | |
1325 | if (arg3 != NULL) { |
1326 | if (!dt_node_is_posconst(arg3)) { |
1327 | dnerror(arg3, D_LQUANT_STEPTYPE, "lquantize( ) " |
1328 | "argument #3 must be a non-zero positive " |
1329 | "integer constant\n" ); |
1330 | } |
1331 | |
1332 | if ((step = arg3->dn_value) > UINT16_MAX) { |
1333 | dnerror(arg3, D_LQUANT_STEPVAL, "lquantize( ) " |
1334 | "argument #3 must be a 16-bit quantity\n" ); |
1335 | } |
1336 | } |
1337 | |
1338 | nlevels = (limitval - baseval) / step; |
1339 | |
1340 | if (nlevels == 0) { |
1341 | dnerror(dnp, D_LQUANT_STEPLARGE, |
1342 | "lquantize( ) step (argument #3) too large: must " |
1343 | "have at least one quantization level\n" ); |
1344 | } |
1345 | |
1346 | if (nlevels > UINT16_MAX) { |
1347 | dnerror(dnp, D_LQUANT_STEPSMALL, "lquantize( ) step " |
1348 | "(argument #3) too small: number of quantization " |
1349 | "levels must be a 16-bit quantity\n" ); |
1350 | } |
1351 | |
1352 | arg = (step << DTRACE_LQUANTIZE_STEPSHIFT) | |
1353 | (nlevels << DTRACE_LQUANTIZE_LEVELSHIFT) | |
1354 | ((baseval << DTRACE_LQUANTIZE_BASESHIFT) & |
1355 | DTRACE_LQUANTIZE_BASEMASK); |
1356 | |
1357 | assert(arg != 0); |
1358 | |
1359 | isp = (dt_idsig_t *)aid->di_data; |
1360 | |
1361 | if (isp->dis_auxinfo == 0) { |
1362 | /* |
1363 | * This is the first time we've seen an lquantize() |
1364 | * for this aggregation; we'll store our argument |
1365 | * as the auxiliary signature information. |
1366 | */ |
1367 | isp->dis_auxinfo = arg; |
1368 | } else if ((oarg = isp->dis_auxinfo) != arg) { |
1369 | /* |
1370 | * If we have seen this lquantize() before and the |
1371 | * argument doesn't match the original argument, pick |
1372 | * the original argument apart to concisely report the |
1373 | * mismatch. |
1374 | */ |
1375 | int obaseval = DTRACE_LQUANTIZE_BASE(oarg); |
1376 | int onlevels = DTRACE_LQUANTIZE_LEVELS(oarg); |
1377 | int ostep = DTRACE_LQUANTIZE_STEP(oarg); |
1378 | |
1379 | if (obaseval != baseval) { |
1380 | dnerror(dnp, D_LQUANT_MATCHBASE, "lquantize( ) " |
1381 | "base (argument #1) doesn't match previous " |
1382 | "declaration: expected %d, found %d\n" , |
1383 | obaseval, (int)baseval); |
1384 | } |
1385 | |
1386 | if (onlevels * ostep != nlevels * step) { |
1387 | dnerror(dnp, D_LQUANT_MATCHLIM, "lquantize( ) " |
1388 | "limit (argument #2) doesn't match previous" |
1389 | " declaration: expected %d, found %d\n" , |
1390 | obaseval + onlevels * ostep, |
1391 | (int)baseval + (int)nlevels * (int)step); |
1392 | } |
1393 | |
1394 | if (ostep != step) { |
1395 | dnerror(dnp, D_LQUANT_MATCHSTEP, "lquantize( ) " |
1396 | "step (argument #3) doesn't match previous " |
1397 | "declaration: expected %d, found %d\n" , |
1398 | ostep, (int)step); |
1399 | } |
1400 | |
1401 | /* |
1402 | * We shouldn't be able to get here -- one of the |
1403 | * parameters must be mismatched if the arguments |
1404 | * didn't match. |
1405 | */ |
1406 | assert(0); |
1407 | } |
1408 | |
1409 | incr = arg3 != NULL ? arg3->dn_list : NULL; |
1410 | argmax = 5; |
1411 | } |
1412 | |
1413 | if (fid->di_id == DTRACEAGG_LLQUANTIZE) { |
1414 | /* |
1415 | * For log/linear quantizations, we have between one and five |
1416 | * arguments in addition to the expression: |
1417 | * |
1418 | * arg1 => Factor |
1419 | * arg2 => Low magnitude |
1420 | * arg3 => High magnitude |
1421 | * arg4 => Number of steps per magnitude |
1422 | * arg5 => Quantization increment value (defaults to 1) |
1423 | */ |
1424 | dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list; |
1425 | uint64_t oarg, order, v; |
1426 | dt_idsig_t *isp; |
1427 | int i; |
1428 | |
1429 | struct { |
1430 | char *str; /* string identifier */ |
1431 | int badtype; /* error on bad type */ |
1432 | int badval; /* error on bad value */ |
1433 | int mismatch; /* error on bad match */ |
1434 | int shift; /* shift value */ |
1435 | uint16_t value; /* value itself */ |
1436 | } args[] = { |
1437 | { "factor" , D_LLQUANT_FACTORTYPE, |
1438 | D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH, |
1439 | DTRACE_LLQUANTIZE_FACTORSHIFT }, |
1440 | { "low magnitude" , D_LLQUANT_LOWTYPE, |
1441 | D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH, |
1442 | DTRACE_LLQUANTIZE_LOWSHIFT }, |
1443 | { "high magnitude" , D_LLQUANT_HIGHTYPE, |
1444 | D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH, |
1445 | DTRACE_LLQUANTIZE_HIGHSHIFT }, |
1446 | { "linear steps per magnitude" , D_LLQUANT_NSTEPTYPE, |
1447 | D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH, |
1448 | DTRACE_LLQUANTIZE_NSTEPSHIFT }, |
1449 | { NULL } |
1450 | }; |
1451 | |
1452 | assert(arg == 0); |
1453 | |
1454 | for (i = 0; args[i].str != NULL; i++) { |
1455 | if (llarg->dn_kind != DT_NODE_INT) { |
1456 | dnerror(llarg, args[i].badtype, "llquantize( ) " |
1457 | "argument #%d (%s) must be an " |
1458 | "integer constant\n" , i + 1, args[i].str); |
1459 | } |
1460 | |
1461 | if ((uint64_t)llarg->dn_value > UINT16_MAX) { |
1462 | dnerror(llarg, args[i].badval, "llquantize( ) " |
1463 | "argument #%d (%s) must be an unsigned " |
1464 | "16-bit quantity\n" , i + 1, args[i].str); |
1465 | } |
1466 | |
1467 | args[i].value = (uint16_t)llarg->dn_value; |
1468 | |
1469 | assert(!(arg & ((uint64_t)UINT16_MAX << |
1470 | args[i].shift))); |
1471 | arg |= ((uint64_t)args[i].value << args[i].shift); |
1472 | llarg = llarg->dn_list; |
1473 | } |
1474 | |
1475 | assert(arg != 0); |
1476 | |
1477 | if (args[0].value < 2) { |
1478 | dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) " |
1479 | "factor (argument #1) must be two or more\n" ); |
1480 | } |
1481 | |
1482 | if (args[1].value >= args[2].value) { |
1483 | dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) " |
1484 | "high magnitude (argument #3) must be greater " |
1485 | "than low magnitude (argument #2)\n" ); |
1486 | } |
1487 | |
1488 | if (args[3].value < args[0].value) { |
1489 | dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) " |
1490 | "factor (argument #1) must be less than or " |
1491 | "equal to the number of linear steps per " |
1492 | "magnitude (argument #4)\n" ); |
1493 | } |
1494 | |
1495 | for (v = args[0].value; v < args[3].value; v *= args[0].value) |
1496 | continue; |
1497 | |
1498 | if ((args[3].value % args[0].value) || (v % args[3].value)) { |
1499 | dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) " |
1500 | "factor (argument #1) must evenly divide the " |
1501 | "number of steps per magnitude (argument #4), " |
1502 | "and the number of steps per magnitude must evenly " |
1503 | "divide a power of the factor\n" ); |
1504 | } |
1505 | |
1506 | for (i = 0, order = 1; i < args[2].value; i++) { |
1507 | if (order * args[0].value > order) { |
1508 | order *= args[0].value; |
1509 | continue; |
1510 | } |
1511 | |
1512 | dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) " |
1513 | "factor (%d) raised to power of high magnitude " |
1514 | "(%d) overflows 64-bits\n" , args[0].value, |
1515 | args[2].value); |
1516 | } |
1517 | |
1518 | isp = (dt_idsig_t *)aid->di_data; |
1519 | |
1520 | if (isp->dis_auxinfo == 0) { |
1521 | /* |
1522 | * This is the first time we've seen an llquantize() |
1523 | * for this aggregation; we'll store our argument |
1524 | * as the auxiliary signature information. |
1525 | */ |
1526 | isp->dis_auxinfo = arg; |
1527 | } else if ((oarg = isp->dis_auxinfo) != arg) { |
1528 | /* |
1529 | * If we have seen this llquantize() before and the |
1530 | * argument doesn't match the original argument, pick |
1531 | * the original argument apart to concisely report the |
1532 | * mismatch. |
1533 | */ |
1534 | int expected = 0, found = 0; |
1535 | |
1536 | for (i = 0; expected == found; i++) { |
1537 | assert(args[i].str != NULL); |
1538 | |
1539 | expected = (oarg >> args[i].shift) & UINT16_MAX; |
1540 | found = (arg >> args[i].shift) & UINT16_MAX; |
1541 | } |
1542 | |
1543 | dnerror(dnp, args[i - 1].mismatch, "llquantize( ) " |
1544 | "%s (argument #%d) doesn't match previous " |
1545 | "declaration: expected %d, found %d\n" , |
1546 | args[i - 1].str, i, expected, found); |
1547 | } |
1548 | |
1549 | incr = llarg; |
1550 | argmax = 6; |
1551 | } |
1552 | |
1553 | if (fid->di_id == DTRACEAGG_QUANTIZE) { |
1554 | incr = dnp->dn_aggfun->dn_args->dn_list; |
1555 | argmax = 2; |
1556 | } |
1557 | |
1558 | if (incr != NULL) { |
1559 | if (!dt_node_is_scalar(incr)) { |
1560 | dnerror(dnp, D_PROTO_ARG, "%s( ) increment value " |
1561 | "(argument #%d) must be of scalar type\n" , |
1562 | fid->di_name, argmax); |
1563 | } |
1564 | |
1565 | if ((anp = incr->dn_list) != NULL) { |
1566 | int argc = argmax; |
1567 | |
1568 | for (; anp != NULL; anp = anp->dn_list) |
1569 | argc++; |
1570 | |
1571 | dnerror(incr, D_PROTO_LEN, "%s( ) prototype " |
1572 | "mismatch: %d args passed, at most %d expected" , |
1573 | fid->di_name, argc, argmax); |
1574 | } |
1575 | |
1576 | ap = dt_stmt_action(dtp, sdp); |
1577 | n++; |
1578 | |
1579 | dt_cg(yypcb, incr); |
1580 | ap->dtad_difo = dt_as(yypcb); |
1581 | ap->dtad_difo->dtdo_rtype = dt_void_rtype; |
1582 | ap->dtad_kind = DTRACEACT_DIFEXPR; |
1583 | } |
1584 | |
1585 | assert(sdp->dtsd_aggdata == NULL); |
1586 | sdp->dtsd_aggdata = aid; |
1587 | |
1588 | ap = dt_stmt_action(dtp, sdp); |
1589 | assert(fid->di_kind == DT_IDENT_AGGFUNC); |
1590 | assert(DTRACEACT_ISAGG(fid->di_id)); |
1591 | ap->dtad_kind = fid->di_id; |
1592 | ap->dtad_ntuple = n; |
1593 | ap->dtad_arg = arg; |
1594 | |
1595 | if (dnp->dn_aggfun->dn_args != NULL) { |
1596 | dt_cg(yypcb, dnp->dn_aggfun->dn_args); |
1597 | ap->dtad_difo = dt_as(yypcb); |
1598 | } |
1599 | } |
1600 | |
1601 | static void |
1602 | dt_compile_one_clause(dtrace_hdl_t *dtp, dt_node_t *cnp, dt_node_t *pnp) |
1603 | { |
1604 | dtrace_ecbdesc_t *edp; |
1605 | dtrace_stmtdesc_t *sdp; |
1606 | dt_node_t *dnp; |
1607 | |
1608 | yylineno = pnp->dn_line; |
1609 | dt_setcontext(dtp, pnp->dn_desc); |
1610 | (void) dt_node_cook(cnp, DT_IDFLG_REF); |
1611 | |
1612 | if (DT_TREEDUMP_PASS(dtp, 2)) |
1613 | dt_node_printr(cnp, stderr, 0); |
1614 | |
1615 | if ((edp = dt_ecbdesc_create(dtp, pnp->dn_desc)) == NULL) |
1616 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
1617 | |
1618 | assert(yypcb->pcb_ecbdesc == NULL); |
1619 | yypcb->pcb_ecbdesc = edp; |
1620 | |
1621 | if (cnp->dn_pred != NULL) { |
1622 | dt_cg(yypcb, cnp->dn_pred); |
1623 | edp->dted_pred.dtpdd_difo = dt_as(yypcb); |
1624 | } |
1625 | |
1626 | if (cnp->dn_acts == NULL) { |
1627 | dt_stmt_append(dt_stmt_create(dtp, edp, |
1628 | cnp->dn_ctxattr, _dtrace_defattr), cnp); |
1629 | } |
1630 | |
1631 | for (dnp = cnp->dn_acts; dnp != NULL; dnp = dnp->dn_list) { |
1632 | assert(yypcb->pcb_stmt == NULL); |
1633 | sdp = dt_stmt_create(dtp, edp, cnp->dn_ctxattr, cnp->dn_attr); |
1634 | |
1635 | switch (dnp->dn_kind) { |
1636 | case DT_NODE_DEXPR: |
1637 | if (dnp->dn_expr->dn_kind == DT_NODE_AGG) |
1638 | dt_compile_agg(dtp, dnp->dn_expr, sdp); |
1639 | else |
1640 | dt_compile_exp(dtp, dnp, sdp); |
1641 | break; |
1642 | case DT_NODE_DFUNC: |
1643 | dt_compile_fun(dtp, dnp, sdp); |
1644 | break; |
1645 | case DT_NODE_AGG: |
1646 | dt_compile_agg(dtp, dnp, sdp); |
1647 | break; |
1648 | default: |
1649 | dnerror(dnp, D_UNKNOWN, "internal error -- node kind " |
1650 | "%u is not a valid statement\n" , dnp->dn_kind); |
1651 | } |
1652 | |
1653 | assert(yypcb->pcb_stmt == sdp); |
1654 | dt_stmt_append(sdp, dnp); |
1655 | } |
1656 | |
1657 | assert(yypcb->pcb_ecbdesc == edp); |
1658 | dt_ecbdesc_release(dtp, edp); |
1659 | dt_endcontext(dtp); |
1660 | yypcb->pcb_ecbdesc = NULL; |
1661 | } |
1662 | |
1663 | static void |
1664 | dt_compile_clause(dtrace_hdl_t *dtp, dt_node_t *cnp) |
1665 | { |
1666 | dt_node_t *pnp; |
1667 | |
1668 | for (pnp = cnp->dn_pdescs; pnp != NULL; pnp = pnp->dn_list) |
1669 | dt_compile_one_clause(dtp, cnp, pnp); |
1670 | } |
1671 | |
1672 | static void |
1673 | dt_compile_xlator(dt_node_t *dnp) |
1674 | { |
1675 | dt_xlator_t *dxp = dnp->dn_xlator; |
1676 | dt_node_t *mnp; |
1677 | |
1678 | for (mnp = dnp->dn_members; mnp != NULL; mnp = mnp->dn_list) { |
1679 | assert(dxp->dx_membdif[mnp->dn_membid] == NULL); |
1680 | dt_cg(yypcb, mnp); |
1681 | dxp->dx_membdif[mnp->dn_membid] = dt_as(yypcb); |
1682 | } |
1683 | } |
1684 | |
1685 | void |
1686 | dt_setcontext(dtrace_hdl_t *dtp, dtrace_probedesc_t *pdp) |
1687 | { |
1688 | const dtrace_pattr_t *pap; |
1689 | dt_probe_t *prp; |
1690 | dt_provider_t *pvp; |
1691 | dt_ident_t *idp; |
1692 | char attrstr[8]; |
1693 | int err; |
1694 | |
1695 | /* |
1696 | * Both kernel and pid based providers are allowed to have names |
1697 | * ending with what could be interpreted as a number. We assume it's |
1698 | * a pid and that we may need to dynamically create probes for |
1699 | * that process if: |
1700 | * |
1701 | * (1) The provider doesn't exist, or, |
1702 | * (2) The provider exists and has DTRACE_PRIV_PROC privilege. |
1703 | * |
1704 | * On an error, dt_pid_create_probes() will set the error message |
1705 | * and tag -- we just have to longjmp() out of here. |
1706 | */ |
1707 | if (isdigit((unsigned char)pdp->dtpd_provider[strlen(pdp->dtpd_provider) - 1]) && |
1708 | ((pvp = dt_provider_lookup(dtp, pdp->dtpd_provider)) == NULL || |
1709 | pvp->pv_desc.dtvd_priv.dtpp_flags & DTRACE_PRIV_PROC) && |
1710 | dt_pid_create_probes(pdp, dtp, yypcb) != 0) { |
1711 | longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER); |
1712 | } |
1713 | |
1714 | /* |
1715 | * Call dt_probe_info() to get the probe arguments and attributes. If |
1716 | * a representative probe is found, set 'pap' to the probe provider's |
1717 | * attributes. Otherwise set 'pap' to default Unstable attributes. |
1718 | */ |
1719 | if ((prp = dt_probe_info(dtp, pdp, &yypcb->pcb_pinfo)) == NULL) { |
1720 | pap = &_dtrace_prvdesc; |
1721 | err = dtrace_errno(dtp); |
1722 | bzero(&yypcb->pcb_pinfo, sizeof (dtrace_probeinfo_t)); |
1723 | yypcb->pcb_pinfo.dtp_attr = pap->dtpa_provider; |
1724 | yypcb->pcb_pinfo.dtp_arga = pap->dtpa_args; |
1725 | } else { |
1726 | pap = &prp->pr_pvp->pv_desc.dtvd_attr; |
1727 | err = 0; |
1728 | } |
1729 | |
1730 | if (err == EDT_NOPROBE && !(yypcb->pcb_cflags & DTRACE_C_ZDEFS)) { |
1731 | xyerror(D_PDESC_ZERO, "probe description %s:%s:%s:%s does not " |
1732 | "match any probes\n" , pdp->dtpd_provider, pdp->dtpd_mod, |
1733 | pdp->dtpd_func, pdp->dtpd_name); |
1734 | } |
1735 | |
1736 | if (err != EDT_NOPROBE && err != EDT_UNSTABLE && err != 0) |
1737 | xyerror(D_PDESC_INVAL, "%s\n" , dtrace_errmsg(dtp, err)); |
1738 | |
1739 | dt_dprintf("set context to %s:%s:%s:%s [%u] prp=%p attr=%s argc=%d\n" , |
1740 | pdp->dtpd_provider, pdp->dtpd_mod, pdp->dtpd_func, pdp->dtpd_name, |
1741 | pdp->dtpd_id, (void *)prp, dt_attr_str(yypcb->pcb_pinfo.dtp_attr, |
1742 | attrstr, sizeof (attrstr)), yypcb->pcb_pinfo.dtp_argc); |
1743 | |
1744 | /* |
1745 | * Reset the stability attributes of D global variables that vary |
1746 | * based on the attributes of the provider and context itself. |
1747 | */ |
1748 | if ((idp = dt_idhash_lookup(dtp->dt_globals, "probeprov" )) != NULL) |
1749 | idp->di_attr = pap->dtpa_provider; |
1750 | if ((idp = dt_idhash_lookup(dtp->dt_globals, "probemod" )) != NULL) |
1751 | idp->di_attr = pap->dtpa_mod; |
1752 | if ((idp = dt_idhash_lookup(dtp->dt_globals, "probefunc" )) != NULL) |
1753 | idp->di_attr = pap->dtpa_func; |
1754 | if ((idp = dt_idhash_lookup(dtp->dt_globals, "probename" )) != NULL) |
1755 | idp->di_attr = pap->dtpa_name; |
1756 | if ((idp = dt_idhash_lookup(dtp->dt_globals, "args" )) != NULL) |
1757 | idp->di_attr = pap->dtpa_args; |
1758 | |
1759 | yypcb->pcb_pdesc = pdp; |
1760 | yypcb->pcb_probe = prp; |
1761 | } |
1762 | |
1763 | /* |
1764 | * Reset context-dependent variables and state at the end of cooking a D probe |
1765 | * definition clause. This ensures that external declarations between clauses |
1766 | * do not reference any stale context-dependent data from the previous clause. |
1767 | */ |
1768 | void |
1769 | dt_endcontext(dtrace_hdl_t *dtp) |
1770 | { |
1771 | static const char *const cvars[] = { |
1772 | "probeprov" , "probemod" , "probefunc" , "probename" , "args" , NULL |
1773 | }; |
1774 | |
1775 | dt_ident_t *idp; |
1776 | int i; |
1777 | |
1778 | for (i = 0; cvars[i] != NULL; i++) { |
1779 | if ((idp = dt_idhash_lookup(dtp->dt_globals, cvars[i])) != NULL) |
1780 | idp->di_attr = _dtrace_defattr; |
1781 | } |
1782 | |
1783 | yypcb->pcb_pdesc = NULL; |
1784 | yypcb->pcb_probe = NULL; |
1785 | } |
1786 | |
1787 | static int |
1788 | dt_reduceid(dt_idhash_t *dhp, dt_ident_t *idp, dtrace_hdl_t *dtp) |
1789 | { |
1790 | if (idp->di_vers != 0 && idp->di_vers > dtp->dt_vmax) |
1791 | dt_idhash_delete(dhp, idp); |
1792 | |
1793 | return (0); |
1794 | } |
1795 | |
1796 | /* |
1797 | * When dtrace_setopt() is called for "version", it calls dt_reduce() to remove |
1798 | * any identifiers or translators that have been previously defined as bound to |
1799 | * a version greater than the specified version. Therefore, in our current |
1800 | * version implementation, establishing a binding is a one-way transformation. |
1801 | * In addition, no versioning is currently provided for types as our .d library |
1802 | * files do not define any types and we reserve prefixes DTRACE_ and dtrace_ |
1803 | * for our exclusive use. If required, type versioning will require more work. |
1804 | */ |
1805 | int |
1806 | dt_reduce(dtrace_hdl_t *dtp, dt_version_t v) |
1807 | { |
1808 | char s[DT_VERSION_STRMAX]; |
1809 | dt_xlator_t *dxp, *nxp; |
1810 | |
1811 | if (v > dtp->dt_vmax) |
1812 | return (dt_set_errno(dtp, EDT_VERSREDUCED)); |
1813 | else if (v == dtp->dt_vmax) |
1814 | return (0); /* no reduction necessary */ |
1815 | |
1816 | dt_dprintf("reducing api version to %s\n" , |
1817 | dt_version_num2str(v, s, sizeof (s))); |
1818 | |
1819 | dtp->dt_vmax = v; |
1820 | |
1821 | for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL; dxp = nxp) { |
1822 | nxp = dt_list_next(dxp); |
1823 | if ((dxp->dx_souid.di_vers != 0 && dxp->dx_souid.di_vers > v) || |
1824 | (dxp->dx_ptrid.di_vers != 0 && dxp->dx_ptrid.di_vers > v)) |
1825 | dt_list_delete(&dtp->dt_xlators, dxp); |
1826 | } |
1827 | |
1828 | (void) dt_idhash_iter(dtp->dt_macros, (dt_idhash_f *)dt_reduceid, dtp); |
1829 | (void) dt_idhash_iter(dtp->dt_aggs, (dt_idhash_f *)dt_reduceid, dtp); |
1830 | (void) dt_idhash_iter(dtp->dt_globals, (dt_idhash_f *)dt_reduceid, dtp); |
1831 | (void) dt_idhash_iter(dtp->dt_tls, (dt_idhash_f *)dt_reduceid, dtp); |
1832 | |
1833 | return (0); |
1834 | } |
1835 | |
1836 | /* |
1837 | * Fork and exec the cpp(1) preprocessor to run over the specified input file, |
1838 | * and return a FILE handle for the cpp output. We use the /dev/fd filesystem |
1839 | * here to simplify the code by leveraging file descriptor inheritance. |
1840 | */ |
1841 | static FILE * |
1842 | dt_preproc(dtrace_hdl_t *dtp, FILE *ifp) |
1843 | { |
1844 | int argc = dtp->dt_cpp_argc; |
1845 | char **argv = malloc(sizeof (char *) * (argc + 5)); |
1846 | FILE *ofp = tmpfile(); |
1847 | |
1848 | #ifdef illumos |
1849 | char ipath[20], opath[20]; /* big enough for /dev/fd/ + INT_MAX + \0 */ |
1850 | #endif |
1851 | char verdef[32]; /* big enough for -D__SUNW_D_VERSION=0x%08x + \0 */ |
1852 | |
1853 | struct sigaction act, oact; |
1854 | sigset_t mask, omask; |
1855 | |
1856 | int wstat, estat; |
1857 | pid_t pid; |
1858 | #ifdef illumos |
1859 | off64_t off; |
1860 | #else |
1861 | off_t off = 0; |
1862 | #endif |
1863 | int c; |
1864 | |
1865 | if (argv == NULL || ofp == NULL) { |
1866 | (void) dt_set_errno(dtp, errno); |
1867 | goto err; |
1868 | } |
1869 | |
1870 | /* |
1871 | * If the input is a seekable file, see if it is an interpreter file. |
1872 | * If we see #!, seek past the first line because cpp will choke on it. |
1873 | * We start cpp just prior to the \n at the end of this line so that |
1874 | * it still sees the newline, ensuring that #line values are correct. |
1875 | */ |
1876 | if (isatty(fileno(ifp)) == 0 && (off = ftello64(ifp)) != -1) { |
1877 | if ((c = fgetc(ifp)) == '#' && (c = fgetc(ifp)) == '!') { |
1878 | for (off += 2; c != '\n'; off++) { |
1879 | if ((c = fgetc(ifp)) == EOF) |
1880 | break; |
1881 | } |
1882 | if (c == '\n') |
1883 | off--; /* start cpp just prior to \n */ |
1884 | } |
1885 | (void) fflush(ifp); |
1886 | (void) fseeko64(ifp, off, SEEK_SET); |
1887 | } |
1888 | |
1889 | #ifdef illumos |
1890 | (void) snprintf(ipath, sizeof (ipath), "/dev/fd/%d" , fileno(ifp)); |
1891 | (void) snprintf(opath, sizeof (opath), "/dev/fd/%d" , fileno(ofp)); |
1892 | #endif |
1893 | |
1894 | bcopy(dtp->dt_cpp_argv, argv, sizeof (char *) * argc); |
1895 | |
1896 | (void) snprintf(verdef, sizeof (verdef), |
1897 | "-D__SUNW_D_VERSION=0x%08x" , dtp->dt_vmax); |
1898 | argv[argc++] = verdef; |
1899 | |
1900 | #ifdef illumos |
1901 | switch (dtp->dt_stdcmode) { |
1902 | case DT_STDC_XA: |
1903 | case DT_STDC_XT: |
1904 | argv[argc++] = "-D__STDC__=0" ; |
1905 | break; |
1906 | case DT_STDC_XC: |
1907 | argv[argc++] = "-D__STDC__=1" ; |
1908 | break; |
1909 | } |
1910 | |
1911 | argv[argc++] = ipath; |
1912 | argv[argc++] = opath; |
1913 | #else |
1914 | argv[argc++] = "-P" ; |
1915 | #endif |
1916 | argv[argc] = NULL; |
1917 | |
1918 | /* |
1919 | * libdtrace must be able to be embedded in other programs that may |
1920 | * include application-specific signal handlers. Therefore, if we |
1921 | * need to fork to run cpp(1), we must avoid generating a SIGCHLD |
1922 | * that could confuse the containing application. To do this, |
1923 | * we block SIGCHLD and reset its disposition to SIG_DFL. |
1924 | * We restore our signal state once we are done. |
1925 | */ |
1926 | (void) sigemptyset(&mask); |
1927 | (void) sigaddset(&mask, SIGCHLD); |
1928 | (void) sigprocmask(SIG_BLOCK, &mask, &omask); |
1929 | |
1930 | bzero(&act, sizeof (act)); |
1931 | act.sa_handler = SIG_DFL; |
1932 | (void) sigaction(SIGCHLD, &act, &oact); |
1933 | |
1934 | if ((pid = fork1()) == -1) { |
1935 | (void) sigaction(SIGCHLD, &oact, NULL); |
1936 | (void) sigprocmask(SIG_SETMASK, &omask, NULL); |
1937 | (void) dt_set_errno(dtp, EDT_CPPFORK); |
1938 | goto err; |
1939 | } |
1940 | |
1941 | if (pid == 0) { |
1942 | #ifndef illumos |
1943 | if (isatty(fileno(ifp)) == 0) |
1944 | lseek(fileno(ifp), off, SEEK_SET); |
1945 | dup2(fileno(ifp), 0); |
1946 | dup2(fileno(ofp), 1); |
1947 | #endif |
1948 | (void) execvp(dtp->dt_cpp_path, argv); |
1949 | _exit(errno == ENOENT ? 127 : 126); |
1950 | } |
1951 | |
1952 | do { |
1953 | dt_dprintf("waiting for %s (PID %d)\n" , dtp->dt_cpp_path, |
1954 | (int)pid); |
1955 | } while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR); |
1956 | |
1957 | (void) sigaction(SIGCHLD, &oact, NULL); |
1958 | (void) sigprocmask(SIG_SETMASK, &omask, NULL); |
1959 | |
1960 | dt_dprintf("%s returned exit status 0x%x\n" , dtp->dt_cpp_path, wstat); |
1961 | estat = WIFEXITED(wstat) ? WEXITSTATUS(wstat) : -1; |
1962 | |
1963 | if (estat != 0) { |
1964 | switch (estat) { |
1965 | case 126: |
1966 | (void) dt_set_errno(dtp, EDT_CPPEXEC); |
1967 | break; |
1968 | case 127: |
1969 | (void) dt_set_errno(dtp, EDT_CPPENT); |
1970 | break; |
1971 | default: |
1972 | (void) dt_set_errno(dtp, EDT_CPPERR); |
1973 | } |
1974 | goto err; |
1975 | } |
1976 | |
1977 | free(argv); |
1978 | (void) fflush(ofp); |
1979 | (void) fseek(ofp, 0, SEEK_SET); |
1980 | return (ofp); |
1981 | |
1982 | err: |
1983 | free(argv); |
1984 | (void) fclose(ofp); |
1985 | return (NULL); |
1986 | } |
1987 | |
1988 | static void |
1989 | dt_lib_depend_error(dtrace_hdl_t *dtp, const char *format, ...) |
1990 | { |
1991 | va_list ap; |
1992 | |
1993 | va_start(ap, format); |
1994 | dt_set_errmsg(dtp, NULL, NULL, NULL, 0, format, ap); |
1995 | va_end(ap); |
1996 | } |
1997 | |
1998 | int |
1999 | dt_lib_depend_add(dtrace_hdl_t *dtp, dt_list_t *dlp, const char *arg) |
2000 | { |
2001 | dt_lib_depend_t *dld; |
2002 | const char *end; |
2003 | |
2004 | assert(arg != NULL); |
2005 | |
2006 | if ((end = strrchr(arg, '/')) == NULL) |
2007 | return (dt_set_errno(dtp, EINVAL)); |
2008 | |
2009 | if ((dld = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL) |
2010 | return (-1); |
2011 | |
2012 | if ((dld->dtld_libpath = dt_alloc(dtp, MAXPATHLEN)) == NULL) { |
2013 | dt_free(dtp, dld); |
2014 | return (-1); |
2015 | } |
2016 | |
2017 | (void) strlcpy(dld->dtld_libpath, arg, end - arg + 2); |
2018 | if ((dld->dtld_library = strdup(arg)) == NULL) { |
2019 | dt_free(dtp, dld->dtld_libpath); |
2020 | dt_free(dtp, dld); |
2021 | return (dt_set_errno(dtp, EDT_NOMEM)); |
2022 | } |
2023 | |
2024 | dt_list_append(dlp, dld); |
2025 | return (0); |
2026 | } |
2027 | |
2028 | dt_lib_depend_t * |
2029 | dt_lib_depend_lookup(dt_list_t *dld, const char *arg) |
2030 | { |
2031 | dt_lib_depend_t *dldn; |
2032 | |
2033 | for (dldn = dt_list_next(dld); dldn != NULL; |
2034 | dldn = dt_list_next(dldn)) { |
2035 | if (strcmp(dldn->dtld_library, arg) == 0) |
2036 | return (dldn); |
2037 | } |
2038 | |
2039 | return (NULL); |
2040 | } |
2041 | |
2042 | /* |
2043 | * Go through all the library files, and, if any library dependencies exist for |
2044 | * that file, add it to that node's list of dependents. The result of this |
2045 | * will be a graph which can then be topologically sorted to produce a |
2046 | * compilation order. |
2047 | */ |
2048 | static int |
2049 | dt_lib_build_graph(dtrace_hdl_t *dtp) |
2050 | { |
2051 | dt_lib_depend_t *dld, *dpld; |
2052 | |
2053 | for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL; |
2054 | dld = dt_list_next(dld)) { |
2055 | char *library = dld->dtld_library; |
2056 | |
2057 | for (dpld = dt_list_next(&dld->dtld_dependencies); dpld != NULL; |
2058 | dpld = dt_list_next(dpld)) { |
2059 | dt_lib_depend_t *dlda; |
2060 | |
2061 | if ((dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep, |
2062 | dpld->dtld_library)) == NULL) { |
2063 | dt_lib_depend_error(dtp, |
2064 | "Invalid library dependency in %s: %s\n" , |
2065 | dld->dtld_library, dpld->dtld_library); |
2066 | |
2067 | return (dt_set_errno(dtp, EDT_COMPILER)); |
2068 | } |
2069 | |
2070 | if ((dt_lib_depend_add(dtp, &dlda->dtld_dependents, |
2071 | library)) != 0) { |
2072 | return (-1); /* preserve dt_errno */ |
2073 | } |
2074 | } |
2075 | } |
2076 | return (0); |
2077 | } |
2078 | |
2079 | static int |
2080 | dt_topo_sort(dtrace_hdl_t *dtp, dt_lib_depend_t *dld, int *count) |
2081 | { |
2082 | dt_lib_depend_t *dpld, *dlda, *new; |
2083 | |
2084 | dld->dtld_start = ++(*count); |
2085 | |
2086 | for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL; |
2087 | dpld = dt_list_next(dpld)) { |
2088 | dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep, |
2089 | dpld->dtld_library); |
2090 | assert(dlda != NULL); |
2091 | |
2092 | if (dlda->dtld_start == 0 && |
2093 | dt_topo_sort(dtp, dlda, count) == -1) |
2094 | return (-1); |
2095 | } |
2096 | |
2097 | if ((new = dt_zalloc(dtp, sizeof (dt_lib_depend_t))) == NULL) |
2098 | return (-1); |
2099 | |
2100 | if ((new->dtld_library = strdup(dld->dtld_library)) == NULL) { |
2101 | dt_free(dtp, new); |
2102 | return (dt_set_errno(dtp, EDT_NOMEM)); |
2103 | } |
2104 | |
2105 | new->dtld_start = dld->dtld_start; |
2106 | new->dtld_finish = dld->dtld_finish = ++(*count); |
2107 | dt_list_prepend(&dtp->dt_lib_dep_sorted, new); |
2108 | |
2109 | dt_dprintf("library %s sorted (%d/%d)\n" , new->dtld_library, |
2110 | new->dtld_start, new->dtld_finish); |
2111 | |
2112 | return (0); |
2113 | } |
2114 | |
2115 | static int |
2116 | dt_lib_depend_sort(dtrace_hdl_t *dtp) |
2117 | { |
2118 | dt_lib_depend_t *dld, *dpld, *dlda; |
2119 | int count = 0; |
2120 | |
2121 | if (dt_lib_build_graph(dtp) == -1) |
2122 | return (-1); /* preserve dt_errno */ |
2123 | |
2124 | /* |
2125 | * Perform a topological sort of the graph that hangs off |
2126 | * dtp->dt_lib_dep. The result of this process will be a |
2127 | * dependency ordered list located at dtp->dt_lib_dep_sorted. |
2128 | */ |
2129 | for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL; |
2130 | dld = dt_list_next(dld)) { |
2131 | if (dld->dtld_start == 0 && |
2132 | dt_topo_sort(dtp, dld, &count) == -1) |
2133 | return (-1); /* preserve dt_errno */; |
2134 | } |
2135 | |
2136 | /* |
2137 | * Check the graph for cycles. If an ancestor's finishing time is |
2138 | * less than any of its dependent's finishing times then a back edge |
2139 | * exists in the graph and this is a cycle. |
2140 | */ |
2141 | for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL; |
2142 | dld = dt_list_next(dld)) { |
2143 | for (dpld = dt_list_next(&dld->dtld_dependents); dpld != NULL; |
2144 | dpld = dt_list_next(dpld)) { |
2145 | dlda = dt_lib_depend_lookup(&dtp->dt_lib_dep_sorted, |
2146 | dpld->dtld_library); |
2147 | assert(dlda != NULL); |
2148 | |
2149 | if (dlda->dtld_finish > dld->dtld_finish) { |
2150 | dt_lib_depend_error(dtp, |
2151 | "Cyclic dependency detected: %s => %s\n" , |
2152 | dld->dtld_library, dpld->dtld_library); |
2153 | |
2154 | return (dt_set_errno(dtp, EDT_COMPILER)); |
2155 | } |
2156 | } |
2157 | } |
2158 | |
2159 | return (0); |
2160 | } |
2161 | |
2162 | static void |
2163 | dt_lib_depend_free(dtrace_hdl_t *dtp) |
2164 | { |
2165 | dt_lib_depend_t *dld, *dlda; |
2166 | |
2167 | while ((dld = dt_list_next(&dtp->dt_lib_dep)) != NULL) { |
2168 | while ((dlda = dt_list_next(&dld->dtld_dependencies)) != NULL) { |
2169 | dt_list_delete(&dld->dtld_dependencies, dlda); |
2170 | dt_free(dtp, dlda->dtld_library); |
2171 | dt_free(dtp, dlda->dtld_libpath); |
2172 | dt_free(dtp, dlda); |
2173 | } |
2174 | while ((dlda = dt_list_next(&dld->dtld_dependents)) != NULL) { |
2175 | dt_list_delete(&dld->dtld_dependents, dlda); |
2176 | dt_free(dtp, dlda->dtld_library); |
2177 | dt_free(dtp, dlda->dtld_libpath); |
2178 | dt_free(dtp, dlda); |
2179 | } |
2180 | dt_list_delete(&dtp->dt_lib_dep, dld); |
2181 | dt_free(dtp, dld->dtld_library); |
2182 | dt_free(dtp, dld->dtld_libpath); |
2183 | dt_free(dtp, dld); |
2184 | } |
2185 | |
2186 | while ((dld = dt_list_next(&dtp->dt_lib_dep_sorted)) != NULL) { |
2187 | dt_list_delete(&dtp->dt_lib_dep_sorted, dld); |
2188 | dt_free(dtp, dld->dtld_library); |
2189 | dt_free(dtp, dld); |
2190 | } |
2191 | } |
2192 | |
2193 | /* |
2194 | * Open all the .d library files found in the specified directory and |
2195 | * compile each one of them. We silently ignore any missing directories and |
2196 | * other files found therein. We only fail (and thereby fail dt_load_libs()) if |
2197 | * we fail to compile a library and the error is something other than #pragma D |
2198 | * depends_on. Dependency errors are silently ignored to permit a library |
2199 | * directory to contain libraries which may not be accessible depending on our |
2200 | * privileges. |
2201 | */ |
2202 | static int |
2203 | dt_load_libs_dir(dtrace_hdl_t *dtp, const char *path) |
2204 | { |
2205 | struct dirent *dp; |
2206 | const char *p, *end; |
2207 | DIR *dirp; |
2208 | |
2209 | char fname[PATH_MAX]; |
2210 | FILE *fp; |
2211 | void *rv; |
2212 | dt_lib_depend_t *dld; |
2213 | |
2214 | if ((dirp = opendir(path)) == NULL) { |
2215 | dt_dprintf("skipping lib dir %s: %s\n" , path, strerror(errno)); |
2216 | return (0); |
2217 | } |
2218 | |
2219 | /* First, parse each file for library dependencies. */ |
2220 | while ((dp = readdir(dirp)) != NULL) { |
2221 | if ((p = strrchr(dp->d_name, '.')) == NULL || strcmp(p, ".d" )) |
2222 | continue; /* skip any filename not ending in .d */ |
2223 | |
2224 | (void) snprintf(fname, sizeof (fname), |
2225 | "%s/%s" , path, dp->d_name); |
2226 | |
2227 | if ((fp = fopen(fname, "r" )) == NULL) { |
2228 | dt_dprintf("skipping library %s: %s\n" , |
2229 | fname, strerror(errno)); |
2230 | continue; |
2231 | } |
2232 | |
2233 | /* |
2234 | * Skip files whose name match an already processed library |
2235 | */ |
2236 | for (dld = dt_list_next(&dtp->dt_lib_dep); dld != NULL; |
2237 | dld = dt_list_next(dld)) { |
2238 | end = strrchr(dld->dtld_library, '/'); |
2239 | /* dt_lib_depend_add ensures this */ |
2240 | assert(end != NULL); |
2241 | if (strcmp(end + 1, dp->d_name) == 0) |
2242 | break; |
2243 | } |
2244 | |
2245 | if (dld != NULL) { |
2246 | dt_dprintf("skipping library %s, already processed " |
2247 | "library with the same name: %s" , dp->d_name, |
2248 | dld->dtld_library); |
2249 | (void) fclose(fp); |
2250 | continue; |
2251 | } |
2252 | |
2253 | dtp->dt_filetag = fname; |
2254 | if (dt_lib_depend_add(dtp, &dtp->dt_lib_dep, fname) != 0) { |
2255 | (void) fclose(fp); |
2256 | return (-1); /* preserve dt_errno */ |
2257 | } |
2258 | |
2259 | rv = dt_compile(dtp, DT_CTX_DPROG, |
2260 | DTRACE_PROBESPEC_NAME, NULL, |
2261 | DTRACE_C_EMPTY | DTRACE_C_CTL, 0, NULL, fp, NULL); |
2262 | |
2263 | if (rv != NULL && dtp->dt_errno && |
2264 | (dtp->dt_errno != EDT_COMPILER || |
2265 | dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) { |
2266 | (void) fclose(fp); |
2267 | return (-1); /* preserve dt_errno */ |
2268 | } |
2269 | |
2270 | if (dtp->dt_errno) |
2271 | dt_dprintf("error parsing library %s: %s\n" , |
2272 | fname, dtrace_errmsg(dtp, dtrace_errno(dtp))); |
2273 | |
2274 | (void) fclose(fp); |
2275 | dtp->dt_filetag = NULL; |
2276 | } |
2277 | |
2278 | (void) closedir(dirp); |
2279 | |
2280 | return (0); |
2281 | } |
2282 | |
2283 | /* |
2284 | * Perform a topological sorting of all the libraries found across the entire |
2285 | * dt_lib_path. Once sorted, compile each one in topological order to cache its |
2286 | * inlines and translators, etc. We silently ignore any missing directories and |
2287 | * other files found therein. We only fail (and thereby fail dt_load_libs()) if |
2288 | * we fail to compile a library and the error is something other than #pragma D |
2289 | * depends_on. Dependency errors are silently ignored to permit a library |
2290 | * directory to contain libraries which may not be accessible depending on our |
2291 | * privileges. |
2292 | */ |
2293 | static int |
2294 | dt_load_libs_sort(dtrace_hdl_t *dtp) |
2295 | { |
2296 | dtrace_prog_t *pgp; |
2297 | FILE *fp; |
2298 | dt_lib_depend_t *dld; |
2299 | |
2300 | /* |
2301 | * Finish building the graph containing the library dependencies |
2302 | * and perform a topological sort to generate an ordered list |
2303 | * for compilation. |
2304 | */ |
2305 | if (dt_lib_depend_sort(dtp) == -1) |
2306 | goto err; |
2307 | |
2308 | for (dld = dt_list_next(&dtp->dt_lib_dep_sorted); dld != NULL; |
2309 | dld = dt_list_next(dld)) { |
2310 | |
2311 | if ((fp = fopen(dld->dtld_library, "r" )) == NULL) { |
2312 | dt_dprintf("skipping library %s: %s\n" , |
2313 | dld->dtld_library, strerror(errno)); |
2314 | continue; |
2315 | } |
2316 | |
2317 | dtp->dt_filetag = dld->dtld_library; |
2318 | pgp = dtrace_program_fcompile(dtp, fp, DTRACE_C_EMPTY, 0, NULL); |
2319 | (void) fclose(fp); |
2320 | dtp->dt_filetag = NULL; |
2321 | |
2322 | if (pgp == NULL && (dtp->dt_errno != EDT_COMPILER || |
2323 | dtp->dt_errtag != dt_errtag(D_PRAGMA_DEPEND))) |
2324 | goto err; |
2325 | |
2326 | if (pgp == NULL) { |
2327 | dt_dprintf("skipping library %s: %s\n" , |
2328 | dld->dtld_library, |
2329 | dtrace_errmsg(dtp, dtrace_errno(dtp))); |
2330 | } else { |
2331 | dld->dtld_loaded = B_TRUE; |
2332 | dt_program_destroy(dtp, pgp); |
2333 | } |
2334 | } |
2335 | |
2336 | dt_lib_depend_free(dtp); |
2337 | return (0); |
2338 | |
2339 | err: |
2340 | dt_lib_depend_free(dtp); |
2341 | return (-1); /* preserve dt_errno */ |
2342 | } |
2343 | |
2344 | /* |
2345 | * Load the contents of any appropriate DTrace .d library files. These files |
2346 | * contain inlines and translators that will be cached by the compiler. We |
2347 | * defer this activity until the first compile to permit libdtrace clients to |
2348 | * add their own library directories and so that we can properly report errors. |
2349 | */ |
2350 | static int |
2351 | dt_load_libs(dtrace_hdl_t *dtp) |
2352 | { |
2353 | dt_dirpath_t *dirp; |
2354 | |
2355 | if (dtp->dt_cflags & DTRACE_C_NOLIBS) |
2356 | return (0); /* libraries already processed */ |
2357 | |
2358 | dtp->dt_cflags |= DTRACE_C_NOLIBS; |
2359 | |
2360 | /* |
2361 | * /usr/lib/dtrace is always at the head of the list. The rest of the |
2362 | * list is specified in the precedence order the user requested. Process |
2363 | * everything other than the head first. DTRACE_C_NOLIBS has already |
2364 | * been spcified so dt_vopen will ensure that there is always one entry |
2365 | * in dt_lib_path. |
2366 | */ |
2367 | for (dirp = dt_list_next(dt_list_next(&dtp->dt_lib_path)); |
2368 | dirp != NULL; dirp = dt_list_next(dirp)) { |
2369 | if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) { |
2370 | dtp->dt_cflags &= ~DTRACE_C_NOLIBS; |
2371 | return (-1); /* errno is set for us */ |
2372 | } |
2373 | } |
2374 | |
2375 | /* Handle /usr/lib/dtrace */ |
2376 | dirp = dt_list_next(&dtp->dt_lib_path); |
2377 | if (dt_load_libs_dir(dtp, dirp->dir_path) != 0) { |
2378 | dtp->dt_cflags &= ~DTRACE_C_NOLIBS; |
2379 | return (-1); /* errno is set for us */ |
2380 | } |
2381 | |
2382 | if (dt_load_libs_sort(dtp) < 0) |
2383 | return (-1); /* errno is set for us */ |
2384 | |
2385 | return (0); |
2386 | } |
2387 | |
2388 | static void * |
2389 | dt_compile(dtrace_hdl_t *dtp, int context, dtrace_probespec_t pspec, void *arg, |
2390 | uint_t cflags, int argc, char *const argv[], FILE *fp, const char *s) |
2391 | { |
2392 | dt_node_t *dnp; |
2393 | dt_decl_t *ddp; |
2394 | dt_pcb_t pcb; |
2395 | void *volatile rv; |
2396 | int err; |
2397 | |
2398 | if ((fp == NULL && s == NULL) || (cflags & ~DTRACE_C_MASK) != 0) { |
2399 | (void) dt_set_errno(dtp, EINVAL); |
2400 | return (NULL); |
2401 | } |
2402 | |
2403 | if (dt_list_next(&dtp->dt_lib_path) != NULL && dt_load_libs(dtp) != 0) |
2404 | return (NULL); /* errno is set for us */ |
2405 | |
2406 | if (dtp->dt_globals->dh_nelems != 0) |
2407 | (void) dt_idhash_iter(dtp->dt_globals, dt_idreset, NULL); |
2408 | |
2409 | if (dtp->dt_tls->dh_nelems != 0) |
2410 | (void) dt_idhash_iter(dtp->dt_tls, dt_idreset, NULL); |
2411 | |
2412 | if (fp && (cflags & DTRACE_C_CPP) && (fp = dt_preproc(dtp, fp)) == NULL) |
2413 | return (NULL); /* errno is set for us */ |
2414 | |
2415 | dt_pcb_push(dtp, &pcb); |
2416 | |
2417 | pcb.pcb_fileptr = fp; |
2418 | pcb.pcb_string = s; |
2419 | pcb.pcb_strptr = s; |
2420 | pcb.pcb_strlen = s ? strlen(s) : 0; |
2421 | pcb.pcb_sargc = argc; |
2422 | pcb.pcb_sargv = argv; |
2423 | pcb.pcb_sflagv = argc ? calloc(argc, sizeof (ushort_t)) : NULL; |
2424 | pcb.pcb_pspec = pspec; |
2425 | pcb.pcb_cflags = dtp->dt_cflags | cflags; |
2426 | pcb.pcb_amin = dtp->dt_amin; |
2427 | pcb.pcb_yystate = -1; |
2428 | pcb.pcb_context = context; |
2429 | pcb.pcb_token = context; |
2430 | |
2431 | if (context != DT_CTX_DPROG) |
2432 | yybegin(YYS_EXPR); |
2433 | else if (cflags & DTRACE_C_CTL) |
2434 | yybegin(YYS_CONTROL); |
2435 | else |
2436 | yybegin(YYS_CLAUSE); |
2437 | |
2438 | if ((err = setjmp(yypcb->pcb_jmpbuf)) != 0) |
2439 | goto out; |
2440 | |
2441 | if (yypcb->pcb_sargc != 0 && yypcb->pcb_sflagv == NULL) |
2442 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
2443 | |
2444 | yypcb->pcb_idents = dt_idhash_create("ambiguous" , NULL, 0, 0); |
2445 | yypcb->pcb_locals = dt_idhash_create("clause local" , NULL, |
2446 | DIF_VAR_OTHER_UBASE, DIF_VAR_OTHER_MAX); |
2447 | |
2448 | if (yypcb->pcb_idents == NULL || yypcb->pcb_locals == NULL) |
2449 | longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); |
2450 | |
2451 | /* |
2452 | * Invoke the parser to evaluate the D source code. If any errors |
2453 | * occur during parsing, an error function will be called and we |
2454 | * will longjmp back to pcb_jmpbuf to abort. If parsing succeeds, |
2455 | * we optionally display the parse tree if debugging is enabled. |
2456 | */ |
2457 | if (yyparse() != 0 || yypcb->pcb_root == NULL) |
2458 | xyerror(D_EMPTY, "empty D program translation unit\n" ); |
2459 | |
2460 | yybegin(YYS_DONE); |
2461 | |
2462 | if (cflags & DTRACE_C_CTL) |
2463 | goto out; |
2464 | |
2465 | if (context != DT_CTX_DTYPE && DT_TREEDUMP_PASS(dtp, 1)) |
2466 | dt_node_printr(yypcb->pcb_root, stderr, 0); |
2467 | |
2468 | if (yypcb->pcb_pragmas != NULL) |
2469 | (void) dt_idhash_iter(yypcb->pcb_pragmas, dt_idpragma, NULL); |
2470 | |
2471 | if (argc > 1 && !(yypcb->pcb_cflags & DTRACE_C_ARGREF) && |
2472 | !(yypcb->pcb_sflagv[argc - 1] & DT_IDFLG_REF)) { |
2473 | xyerror(D_MACRO_UNUSED, "extraneous argument '%s' ($%d is " |
2474 | "not referenced)\n" , yypcb->pcb_sargv[argc - 1], argc - 1); |
2475 | } |
2476 | |
2477 | /* |
2478 | * Perform sugar transformations (for "if" / "else") and replace the |
2479 | * existing clause chain with the new one. |
2480 | */ |
2481 | if (context == DT_CTX_DPROG) { |
2482 | dt_node_t *dnp, *next_dnp; |
2483 | dt_node_t *new_list = NULL; |
2484 | |
2485 | for (dnp = yypcb->pcb_root->dn_list; |
2486 | dnp != NULL; dnp = next_dnp) { |
2487 | /* remove this node from the list */ |
2488 | next_dnp = dnp->dn_list; |
2489 | dnp->dn_list = NULL; |
2490 | |
2491 | if (dnp->dn_kind == DT_NODE_CLAUSE) |
2492 | dnp = dt_compile_sugar(dtp, dnp); |
2493 | /* append node to the new list */ |
2494 | new_list = dt_node_link(new_list, dnp); |
2495 | } |
2496 | yypcb->pcb_root->dn_list = new_list; |
2497 | } |
2498 | |
2499 | /* |
2500 | * If we have successfully created a parse tree for a D program, loop |
2501 | * over the clauses and actions and instantiate the corresponding |
2502 | * libdtrace program. If we are parsing a D expression, then we |
2503 | * simply run the code generator and assembler on the resulting tree. |
2504 | */ |
2505 | switch (context) { |
2506 | case DT_CTX_DPROG: |
2507 | assert(yypcb->pcb_root->dn_kind == DT_NODE_PROG); |
2508 | |
2509 | if ((dnp = yypcb->pcb_root->dn_list) == NULL && |
2510 | !(yypcb->pcb_cflags & DTRACE_C_EMPTY)) |
2511 | xyerror(D_EMPTY, "empty D program translation unit\n" ); |
2512 | |
2513 | if ((yypcb->pcb_prog = dt_program_create(dtp)) == NULL) |
2514 | longjmp(yypcb->pcb_jmpbuf, dtrace_errno(dtp)); |
2515 | |
2516 | for (; dnp != NULL; dnp = dnp->dn_list) { |
2517 | switch (dnp->dn_kind) { |
2518 | case DT_NODE_CLAUSE: |
2519 | if (DT_TREEDUMP_PASS(dtp, 4)) |
2520 | dt_printd(dnp, stderr, 0); |
2521 | dt_compile_clause(dtp, dnp); |
2522 | break; |
2523 | case DT_NODE_XLATOR: |
2524 | if (dtp->dt_xlatemode == DT_XL_DYNAMIC) |
2525 | dt_compile_xlator(dnp); |
2526 | break; |
2527 | case DT_NODE_PROVIDER: |
2528 | (void) dt_node_cook(dnp, DT_IDFLG_REF); |
2529 | break; |
2530 | } |
2531 | } |
2532 | |
2533 | yypcb->pcb_prog->dp_xrefs = yypcb->pcb_asxrefs; |
2534 | yypcb->pcb_prog->dp_xrefslen = yypcb->pcb_asxreflen; |
2535 | yypcb->pcb_asxrefs = NULL; |
2536 | yypcb->pcb_asxreflen = 0; |
2537 | |
2538 | rv = yypcb->pcb_prog; |
2539 | break; |
2540 | |
2541 | case DT_CTX_DEXPR: |
2542 | (void) dt_node_cook(yypcb->pcb_root, DT_IDFLG_REF); |
2543 | dt_cg(yypcb, yypcb->pcb_root); |
2544 | rv = dt_as(yypcb); |
2545 | break; |
2546 | |
2547 | case DT_CTX_DTYPE: |
2548 | ddp = (dt_decl_t *)yypcb->pcb_root; /* root is really a decl */ |
2549 | err = dt_decl_type(ddp, arg); |
2550 | dt_decl_free(ddp); |
2551 | |
2552 | if (err != 0) |
2553 | longjmp(yypcb->pcb_jmpbuf, EDT_COMPILER); |
2554 | |
2555 | rv = NULL; |
2556 | break; |
2557 | } |
2558 | |
2559 | out: |
2560 | if (context != DT_CTX_DTYPE && yypcb->pcb_root != NULL && |
2561 | DT_TREEDUMP_PASS(dtp, 3)) |
2562 | dt_node_printr(yypcb->pcb_root, stderr, 0); |
2563 | |
2564 | if (dtp->dt_cdefs_fd != -1 && (ftruncate64(dtp->dt_cdefs_fd, 0) == -1 || |
2565 | lseek64(dtp->dt_cdefs_fd, 0, SEEK_SET) == -1 || |
2566 | ctf_write(dtp->dt_cdefs->dm_ctfp, dtp->dt_cdefs_fd) == CTF_ERR)) |
2567 | dt_dprintf("failed to update CTF cache: %s\n" , strerror(errno)); |
2568 | |
2569 | if (dtp->dt_ddefs_fd != -1 && (ftruncate64(dtp->dt_ddefs_fd, 0) == -1 || |
2570 | lseek64(dtp->dt_ddefs_fd, 0, SEEK_SET) == -1 || |
2571 | ctf_write(dtp->dt_ddefs->dm_ctfp, dtp->dt_ddefs_fd) == CTF_ERR)) |
2572 | dt_dprintf("failed to update CTF cache: %s\n" , strerror(errno)); |
2573 | |
2574 | if (yypcb->pcb_fileptr && (cflags & DTRACE_C_CPP)) |
2575 | (void) fclose(yypcb->pcb_fileptr); /* close dt_preproc() file */ |
2576 | |
2577 | dt_pcb_pop(dtp, err); |
2578 | (void) dt_set_errno(dtp, err); |
2579 | return (err ? NULL : rv); |
2580 | } |
2581 | |
2582 | dtrace_prog_t * |
2583 | dtrace_program_strcompile(dtrace_hdl_t *dtp, const char *s, |
2584 | dtrace_probespec_t spec, uint_t cflags, int argc, char *const argv[]) |
2585 | { |
2586 | return (dt_compile(dtp, DT_CTX_DPROG, |
2587 | spec, NULL, cflags, argc, argv, NULL, s)); |
2588 | } |
2589 | |
2590 | dtrace_prog_t * |
2591 | dtrace_program_fcompile(dtrace_hdl_t *dtp, FILE *fp, |
2592 | uint_t cflags, int argc, char *const argv[]) |
2593 | { |
2594 | return (dt_compile(dtp, DT_CTX_DPROG, |
2595 | DTRACE_PROBESPEC_NAME, NULL, cflags, argc, argv, fp, NULL)); |
2596 | } |
2597 | |
2598 | int |
2599 | dtrace_type_strcompile(dtrace_hdl_t *dtp, const char *s, dtrace_typeinfo_t *dtt) |
2600 | { |
2601 | (void) dt_compile(dtp, DT_CTX_DTYPE, |
2602 | DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, NULL, s); |
2603 | return (dtp->dt_errno ? -1 : 0); |
2604 | } |
2605 | |
2606 | int |
2607 | dtrace_type_fcompile(dtrace_hdl_t *dtp, FILE *fp, dtrace_typeinfo_t *dtt) |
2608 | { |
2609 | (void) dt_compile(dtp, DT_CTX_DTYPE, |
2610 | DTRACE_PROBESPEC_NONE, dtt, 0, 0, NULL, fp, NULL); |
2611 | return (dtp->dt_errno ? -1 : 0); |
2612 | } |
2613 | |