]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - cddl/contrib/opensolaris/cmd/dtrace/test/cmd/jdtrace/JDTrace.java
Copy head (r256279) to stable/10 as part of the 10.0-RELEASE cycle.
[FreeBSD/stable/10.git] / cddl / contrib / opensolaris / cmd / dtrace / test / cmd / jdtrace / JDTrace.java
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * ident        "%Z%%M% %I%     %E% SMI"
27  */
28 import org.opensolaris.os.dtrace.*;
29 import java.io.*;
30 import java.util.*;
31 import java.util.logging.*;
32
33 /**
34  * Emulates {@code dtrace(1M)} using the Java DTrace API.
35  */
36 public class JDTrace {
37     static Logger logger = Logger.getLogger(JDTrace.class.getName());
38
39     static Consumer dtrace;
40
41     static {
42         Handler handler = new ConsoleHandler();
43         handler.setLevel(Level.ALL);
44         logger.addHandler(handler);
45     }
46
47     static final String CLASSNAME = "JDTrace";
48     static final String OPTSTR =
49             "3:6:b:c:CD:ef:Fi:I:lL:m:n:o:p:P:qs:U:vVwx:X:Z";
50     static boolean heading = false;
51     static boolean quiet = false;
52     static boolean flow = false;
53     static int stackindent = 14;
54     static int exitStatus = 0;
55     static boolean started;
56     static boolean stopped;
57     static PrintStream out = System.out;
58     static final String ATS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
59     static final String SPACES = "                                        ";
60     static final int QUANTIZE_ZERO_BUCKET = 63;
61
62     enum Mode {
63         EXEC,
64         INFO,
65         LIST,
66         VERSION
67     }
68
69     enum ProgramType {
70         STRING,
71         FILE
72     }
73
74     static class CompileRequest {
75         String s;
76         ProgramType type;
77         ProbeDescription.Spec probespec;
78     }
79
80     // Modify program string by expanding an incomplete probe
81     // description according to the requested probespec.
82     static void
83     applyProbespec(CompileRequest req)
84     {
85         ProbeDescription.Spec spec = ((req.probespec == null)
86                 ? ProbeDescription.Spec.NAME
87                 : req.probespec);
88
89         int colons = 0;
90         switch (req.probespec) {
91             case PROVIDER:
92                 colons = 3;
93                 break;
94             case MODULE:
95                 colons = 2;
96                 break;
97             case FUNCTION:
98                 colons = 1;
99                 break;
100         }
101
102         StringBuffer buf = new StringBuffer();
103         if (colons > 0) {
104             char ch;
105             int len = req.s.length();
106
107             int i = 0;
108             // Find first whitespace character not including leading
109             // whitespace (end of first token).  Ignore whitespace
110             // inside a block if the block is concatenated with the
111             // probe description.
112             for (; (i < len) && Character.isWhitespace(req.s.charAt(i)); ++i);
113             int npos = i;
114             boolean inBlock = false;
115             for (; (npos < len) &&
116                     (!Character.isWhitespace(ch = req.s.charAt(npos)) ||
117                     inBlock); ++npos) {
118                 if (ch == '{') {
119                     inBlock = true;
120                 } else if (ch == '}') {
121                     inBlock = false;
122                 }
123             }
124
125             // libdtrace lets you concatenate multiple probe
126             // descriptions separated by code blocks in curly braces,
127             // for example genunix::'{printf("FOUND");}'::entry, as long
128             // as the concatenated probe descriptions begin with ':' and
129             // not a specific field such as 'syscall'.  So to expand the
130             // possibly multiple probe descriptions, we need to insert
131             // colons before each open curly brace, and again at the end
132             // only if there is at least one non-whitespace (probe
133             // specifying) character after the last closing curly brace.
134
135             int prev_i = 0;
136             while (i < npos) {
137                 for (; (i < npos) && (req.s.charAt(i) != '{'); ++i);
138                 buf.append(req.s.substring(prev_i, i));
139                 if ((i < npos) || ((i > 0) && (req.s.charAt(i - 1) != '}'))) {
140                     for (int c = 0; c < colons; ++c) {
141                         buf.append(':');
142                     }
143                 }
144                 if (i < npos) {
145                     buf.append(req.s.charAt(i++));
146                 }
147                 prev_i = i;
148             }
149
150             // append remainder of program text
151             buf.append(req.s.substring(i));
152
153             req.s = buf.toString();
154         }
155     }
156
157     static void
158     printValue(Object value, int bytes, String stringFormat)
159     {
160         if (value instanceof Integer) {
161             if (bytes == 1) {
162                 out.printf(" %3d", (Integer)value);
163             } else if (bytes == 2) {
164                 out.printf(" %5d", (Integer)value);
165             } else {
166                 out.printf(" %8d", (Integer)value);
167             }
168         } else if (value instanceof Long) {
169             out.printf(" %16d", (Long)value);
170         } else {
171             out.printf(stringFormat, value.toString());
172         }
173     }
174
175     static void
176     consumeProbeData(ProbeData data)
177     {
178         if (logger.isLoggable(Level.FINER)) {
179             logger.finer(data.toString());
180         }
181
182         if (!heading) {
183             if (flow) {
184                 out.printf("%3s %-41s\n", "CPU", "FUNCTION");
185             } else {
186                 if (!quiet) {
187                     out.printf("%3s %6s %32s\n",
188                             "CPU", "ID", "FUNCTION:NAME");
189                 }
190             }
191             heading = true;
192         }
193         ProbeDescription probe = data.getEnabledProbeDescription();
194         if (flow) {
195             Flow flow = data.getFlow();
196             int indent = (flow.getDepth() * 2);
197             StringBuffer buf = new StringBuffer();
198             // indent
199             buf.append(' ');
200             for (int i = 0; i < indent; ++i) {
201                 buf.append(' ');
202             }
203             // prefix
204             switch (flow.getKind()) {
205                 case ENTRY:
206                     if (indent == 0) {
207                         buf.append("=> ");
208                     } else {
209                         buf.append("-> ");
210                     }
211                     break;
212                 case RETURN:
213                     if (indent == 0) {
214                         buf.append("<= ");
215                     } else {
216                         buf.append("<- ");
217                     }
218                     break;
219             }
220
221             switch (flow.getKind()) {
222                 case NONE:
223                     buf.append(probe.getFunction());
224                     buf.append(':');
225                     buf.append(probe.getName());
226                     break;
227                 default:
228                     buf.append(probe.getFunction());
229             }
230
231             out.printf("%3s %-41s ", data.getCPU(),
232                     buf.toString());
233         } else {
234             if (!quiet) {
235                 StringBuffer buf = new StringBuffer();
236                 buf.append(probe.getFunction());
237                 buf.append(':');
238                 buf.append(probe.getName());
239                 out.printf("%3s %6s %32s ",
240                         data.getCPU(), probe.getID(),
241                         buf.toString());
242             }
243         }
244         Record record = null;
245         Object value;
246         List <Record> records = data.getRecords();
247         Iterator <Record> itr = records.iterator();
248         while (itr.hasNext()) {
249             record = itr.next();
250
251             if (record instanceof ExitRecord) {
252                 exitStatus = ((ExitRecord)record).getStatus();
253             } else if (record instanceof ScalarRecord) {
254                 ScalarRecord scalar = (ScalarRecord)record;
255                 value = scalar.getValue();
256                 if (value instanceof byte[]) {
257                     out.print(record.toString());
258                 } else {
259                     if (quiet) {
260                         out.print(value);
261                     } else {
262                         printValue(value, scalar.getNumberOfBytes(),
263                                 "  %-33s");
264                     }
265                 }
266             } else if (record instanceof PrintfRecord) {
267                 out.print(record);
268             } else if (record instanceof PrintaRecord) {
269                 PrintaRecord printa = (PrintaRecord)record;
270                 List <Tuple> tuples = printa.getTuples();
271                 if (tuples.isEmpty()) {
272                     out.print(printa.getOutput());
273                 } else {
274                     for (Tuple t : tuples) {
275                         out.print(printa.getFormattedString(t));
276                     }
277                 }
278
279                 if (logger.isLoggable(Level.FINE)) {
280                     logger.fine(printa.toString());
281                 }
282             } else if (record instanceof StackValueRecord) {
283                 printStack((StackValueRecord)record);
284             }
285         }
286         if (!quiet) {
287             out.println();
288         }
289     }
290
291     static void
292     printDistribution(Distribution d)
293     {
294         out.printf("\n%16s %41s %-9s\n", "value",
295                 "------------- Distribution -------------",
296                 "count");
297         long v; // bucket frequency (value)
298         long b; // lower bound of bucket range
299         double total = 0;
300         boolean positives = false;
301         boolean negatives = false;
302
303         Distribution.Bucket bucket;
304         int b1 = 0; // first displayed bucket
305         int b2 = d.size() - 1; // last displayed bucket
306         for (; (b1 <= b2) && (d.get(b1).getFrequency() == 0); ++b1);
307         // If possible, get one bucket before the first non-zero
308         // bucket and one bucket after the last.
309         if (b1 > b2) {
310             // There isn't any data.  This is possible if (and only if)
311             // negative increment values have been used.  In this case,
312             // print the buckets around the base.
313             if (d instanceof LinearDistribution) {
314                 b1 = 0;
315                 b2 = 2;
316             } else {
317                 b1 = QUANTIZE_ZERO_BUCKET - 1;
318                 b2 = QUANTIZE_ZERO_BUCKET + 1;
319             }
320         } else {
321             if (b1 > 0) --b1;
322             for (; (b2 > 0) && (d.get(b2).getFrequency() == 0); --b2);
323             if (b2 < (d.size() - 1)) ++b2;
324         }
325         for (int i = b1; i <= b2; ++i) {
326             v = d.get(i).getFrequency();
327             if (v > 0) {
328                 positives = true;
329             }
330             if (v < 0) {
331                 negatives = true;
332             }
333             total += Math.abs((double)v);
334         }
335         for (int i = b1; i <= b2; ++i) {
336             bucket = d.get(i);
337             v = bucket.getFrequency();
338             b = bucket.getMin();
339
340             if (d instanceof LinearDistribution) {
341                 if (b == Long.MIN_VALUE) {
342                     String lt = "< " + ((LinearDistribution)d).getBase();
343                     out.printf("%16s ", lt);
344                 } else if (bucket.getMax() == Long.MAX_VALUE) {
345                     String ge = ">= " + b;
346                     out.printf("%16s ", ge);
347                 } else {
348                     out.printf("%16d ", b);
349                 }
350             } else {
351                 out.printf("%16d ", b);
352             }
353
354             printDistributionLine(v, total, positives, negatives);
355         }
356     }
357
358     static void
359     printDistributionLine(long val, double total, boolean positives,
360             boolean negatives)
361     {
362         double f;
363         int depth, len = 40;
364
365         assert (ATS.length() == len && SPACES.length() == len);
366         assert (!(total == 0 && (positives || negatives)));
367         assert (!(val < 0 && !negatives));
368         assert (!(val > 0 && !positives));
369         assert (!(val != 0 && total == 0));
370
371         if (!negatives) {
372             if (positives) {
373                 f = (Math.abs((double)val) * (double)len) / total;
374                     depth = (int)(f + 0.5);
375             } else {
376                 depth = 0;
377             }
378
379             out.printf("|%s%s %-9d\n", ATS.substring(len - depth),
380                     SPACES.substring(depth), val);
381             return;
382         }
383
384         if (!positives) {
385             f = (Math.abs((double)val) * (double)len) / total;
386             depth = (int)(f + 0.5);
387
388             out.printf("%s%s| %-9d\n", SPACES.substring(depth),
389                     ATS.substring(len - depth), val);
390             return;
391         }
392
393         /*
394          * If we're here, we have both positive and negative bucket values.
395          * To express this graphically, we're going to generate both positive
396          * and negative bars separated by a centerline.  These bars are half
397          * the size of normal quantize()/lquantize() bars, so we divide the
398          * length in half before calculating the bar length.
399          */
400         len /= 2;
401         String ats = ATS.substring(len);
402         String spaces = SPACES.substring(len);
403
404         f = (Math.abs((double)val) * (double)len) / total;
405         depth = (int)(f + 0.5);
406
407         if (val <= 0) {
408             out.printf("%s%s|%s %-9d\n", spaces.substring(depth),
409                     ats.substring(len - depth), repeat(" ", len), val);
410             return;
411         } else {
412             out.printf("%20s|%s%s %-9d\n", "", ats.substring(len - depth),
413                     spaces.substring(depth), val);
414         }
415     }
416
417     public static String
418     repeat(String s, int n)
419     {
420         StringBuffer buf = new StringBuffer();
421         for (int i = 0; i < n; ++i) {
422             buf.append(s);
423         }
424         return buf.toString();
425     }
426
427     static void
428     printStack(StackValueRecord rec)
429     {
430         StackFrame[] frames = rec.getStackFrames();
431         int i;
432         out.println();
433         String s;
434         for (StackFrame f : frames) {
435             for (i = 0; i < stackindent; ++i) {
436                 out.print(' ');
437             }
438             s = f.getFrame();
439             if (s.indexOf('[') == 0) {
440                 out.print("  ");
441             }
442             out.println(s);
443         }
444     }
445
446     static void
447     printAggregate(Aggregate aggregate)
448     {
449         printAggregationRecords(aggregate.getOrderedRecords());
450     }
451
452     static void
453     printAggregationRecords(List <AggregationRecord> list)
454     {
455         Tuple tuple;
456         AggregationValue value;
457         ValueRecord tupleRecord;
458         int i;
459         int len;
460         for (AggregationRecord r : list) {
461             tuple = r.getTuple();
462             value = r.getValue();
463             len = tuple.size();
464             for (i = 0; i < len; ++i) {
465                 tupleRecord = tuple.get(i);
466                 if (tupleRecord instanceof StackValueRecord) {
467                     printStack((StackValueRecord)tupleRecord);
468                 } else if (tupleRecord instanceof SymbolValueRecord) {
469                     printValue(tupleRecord.toString(), -1, "  %-50s");
470                 } else {
471                     printValue(tupleRecord.getValue(),
472                             ((ScalarRecord)tupleRecord).getNumberOfBytes(),
473                             "  %-50s");
474                 }
475             }
476             if (value instanceof Distribution) {
477                 Distribution d = (Distribution)value;
478                 printDistribution(d);
479             } else {
480                 Number v = value.getValue();
481                 printValue(v, -1, "  %-50s");
482             }
483             out.println();
484         }
485     }
486
487     static void
488     exit(int status)
489     {
490         out.flush();
491         System.err.flush();
492         if (status == 0) {
493             status = exitStatus;
494         }
495         System.exit(status);
496     }
497
498     static void
499     usage()
500     {
501         String predact = "[[ predicate ] action ]";
502         System.err.printf("Usage: java %s [-32|-64] [-CeFlqvVwZ] " +
503             "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " +
504             "[-o output] [-p pid] [-s script] [-U name]\n\t" +
505             "[-x opt[=val]] [-X a|c|s|t]\n\n" +
506             "\t[-P provider %s]\n" +
507             "\t[-m [ provider: ] module %s]\n" +
508             "\t[-f [[ provider: ] module: ] func %s]\n" +
509             "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" +
510             "\t[-i probe-id %s] [ args ... ]\n\n", CLASSNAME,
511             predact, predact, predact, predact, predact);
512         System.err.printf("\tpredicate -> '/' D-expression '/'\n");
513         System.err.printf("\t   action -> '{' D-statements '}'\n");
514         System.err.printf("\n" +
515             "\t-32 generate 32-bit D programs\n" +
516             "\t-64 generate 64-bit D programs\n\n" +
517             "\t-b  set trace buffer size\n" +
518             "\t-c  run specified command and exit upon its completion\n" +
519             "\t-C  run cpp(1) preprocessor on script files\n" +
520             "\t-D  define symbol when invoking preprocessor\n" +
521             "\t-e  exit after compiling request but prior to enabling " +
522                     "probes\n" +
523             "\t-f  enable or list probes matching the specified " +
524                     "function name\n" +
525             "\t-F  coalesce trace output by function\n" +
526             "\t-i  enable or list probes matching the specified probe id\n" +
527             "\t-I  add include directory to preprocessor search path\n" +
528             "\t-l  list probes matching specified criteria\n" +
529             "\t-L  add library directory to library search path\n" +
530             "\t-m  enable or list probes matching the specified " +
531                     "module name\n" +
532             "\t-n  enable or list probes matching the specified probe name\n" +
533             "\t-o  set output file\n" +
534             "\t-p  grab specified process-ID and cache its symbol tables\n" +
535             "\t-P  enable or list probes matching the specified " +
536                     "provider name\n" +
537             "\t-q  set quiet mode (only output explicitly traced data)\n" +
538             "\t-s  enable or list probes according to the specified " +
539                     "D script\n" +
540             "\t-U  undefine symbol when invoking preprocessor\n" +
541             "\t-v  set verbose mode (report stability attributes, " +
542                     "arguments)\n" +
543             "\t-V  report DTrace API version\n" +
544             "\t-w  permit destructive actions\n" +
545             "\t-x  enable or modify compiler and tracing options\n" +
546             "\t-X  specify ISO C conformance settings for preprocessor\n" +
547             "\t-Z  permit probe descriptions that match zero probes\n" +
548             "\n" +
549             "\tTo log PrintaRecord, set this environment variable:\n" +
550             "\t\tJDTRACE_LOGGING_LEVEL=FINE\n" +
551             "\tTo log ProbeData, set JDTRACE_LOGGING_LEVEL=FINER\n");
552         exit(2);
553     }
554
555     static void
556     printProgramStability(String programType, String programDescription,
557             ProgramInfo info)
558     {
559         out.println();
560         out.printf("Stability data for %s %s:\n\n",
561                 programType, programDescription);
562         InterfaceAttributes a;
563         out.println("\tMinimum probe description " +
564                 "attributes");
565         a = info.getMinimumProbeAttributes();
566         out.printf("\t\tIdentifier Names: %s\n",
567                 a.getNameStability());
568         out.printf("\t\tData Semantics:   %s\n",
569                 a.getDataStability());
570         out.printf("\t\tDependency Class: %s\n",
571                 a.getDependencyClass());
572         out.println("\tMinimum probe statement attributes");
573         a = info.getMinimumStatementAttributes();
574         out.printf("\t\tIdentifier Names: %s\n",
575                 a.getNameStability());
576         out.printf("\t\tData Semantics:   %s\n",
577                 a.getDataStability());
578         out.printf("\t\tDependency Class: %s\n",
579                 a.getDependencyClass());
580     }
581
582     static void
583     printProbeDescription(ProbeDescription p)
584     {
585         out.printf("%5d %10s %17s %33s %s\n", p.getID(),
586             p.getProvider(), p.getModule(),
587             p.getFunction(), p.getName());
588     }
589
590     static void
591     printProbeInfo(ProbeInfo p)
592     {
593         InterfaceAttributes a;
594         out.println("\n\tProbe Description Attributes");
595
596         a = p.getProbeAttributes();
597         out.printf("\t\tIdentifier Names: %s\n",
598             a.getNameStability());
599         out.printf("\t\tData Semantics:   %s\n",
600             a.getDataStability());
601         out.printf("\t\tDependency Class: %s\n",
602             a.getDependencyClass());
603
604         out.println("\n\tArgument Attributes");
605
606         a = p.getArgumentAttributes();
607         out.printf("\t\tIdentifier Names: %s\n",
608             a.getNameStability());
609         out.printf("\t\tData Semantics:   %s\n",
610             a.getDataStability());
611         out.printf("\t\tDependency Class: %s\n",
612             a.getDependencyClass());
613
614         // Argument types unsupported for now.
615
616         out.println();
617     }
618
619     public static void
620     main(String[] args)
621     {
622         String loggingLevel = System.getenv().get("JDTRACE_LOGGING_LEVEL");
623         try {
624             logger.setLevel(Level.parse(loggingLevel));
625         } catch (Exception e) {
626             logger.setLevel(Level.OFF);
627         }
628
629         if (args.length == 0) {
630             usage();
631         }
632
633         List <CompileRequest> compileRequests = new LinkedList
634                 <CompileRequest> ();
635         List <Program> programList = new LinkedList <Program> ();
636         boolean verbose = false;
637         Mode mode = Mode.EXEC;
638
639         final ExceptionHandler exceptionHandler = new ExceptionHandler() {
640             public void handleException(Throwable e) {
641                 if (e instanceof DTraceException) {
642                     DTraceException de = (DTraceException)e;
643                     System.err.printf("dtrace: %s\n", de.getMessage());
644                 } else if (e instanceof ConsumerException) {
645                     ConsumerException ce = (ConsumerException)e;
646                     Object msg = ce.getNotificationObject();
647                     if ((msg instanceof org.opensolaris.os.dtrace.Error) ||
648                         (msg instanceof Drop)) {
649                         System.err.printf("dtrace: %s\n", ce.getMessage());
650                     } else {
651                         ce.printStackTrace();
652                     }
653                 } else {
654                     e.printStackTrace();
655                 }
656                 exit(1);
657             }
658         };
659
660         Getopt g = new Getopt(CLASSNAME, args, OPTSTR);
661         int c = 0;
662
663         List <Consumer.OpenFlag> openFlags =
664                 new ArrayList <Consumer.OpenFlag> ();
665
666         while ((c = g.getopt()) != -1) {
667             switch (c) {
668                 case '3': {
669                     String s = g.getOptarg();
670                     if (!s.equals("2")) {
671                         System.err.println("dtrace: illegal option -- 3" + s);
672                         usage();
673                     }
674                     openFlags.add(Consumer.OpenFlag.ILP32);
675                     break;
676                 }
677                 case '6': {
678                     String s = g.getOptarg();
679                     if (!s.equals("4")) {
680                         System.err.println("dtrace: illegal option -- 6" + s);
681                         usage();
682                     }
683                     openFlags.add(Consumer.OpenFlag.LP64);
684                     break;
685                 }
686             }
687         }
688
689         Consumer.OpenFlag[] oflags = new Consumer.OpenFlag[openFlags.size()];
690         oflags = openFlags.toArray(oflags);
691
692         dtrace = new LocalConsumer() {
693             protected Thread createThread() {
694                 Thread t = super.createThread();
695                 t.setDaemon(false);
696                 t.setPriority(Thread.MIN_PRIORITY);
697                 return t;
698             }
699         };
700
701         g = new Getopt(CLASSNAME, args, OPTSTR);
702         c = 0;
703
704         try {
705             dtrace.open(oflags);
706
707             // Set default options that may be overriden by options or #pragma
708             dtrace.setOption(Option.bufsize, Option.mb(4));
709             dtrace.setOption(Option.aggsize, Option.mb(4));
710
711             CompileRequest r;
712             while ((c = g.getopt()) != -1) {
713                 switch (c) {
714                     case 'b':
715                         dtrace.setOption(Option.bufsize, g.getOptarg());
716                         break;
717                     case 'c':
718                         dtrace.createProcess(g.getOptarg());
719                         break;
720                     case 'C':
721                         dtrace.setOption(Option.cpp);
722                         break;
723                     case 'D':
724                         dtrace.setOption(Option.define, g.getOptarg());
725                         break;
726                     case 'e':
727                         mode = Mode.INFO;
728                         break;
729                     case 'f':
730                         r = new CompileRequest();
731                         r.s = g.getOptarg();
732                         r.type = ProgramType.STRING;
733                         r.probespec = ProbeDescription.Spec.FUNCTION;
734                         compileRequests.add(r);
735                         break;
736                     case 'F':
737                         dtrace.setOption(Option.flowindent);
738                         break;
739                     case 'i':
740                         r = new CompileRequest();
741                         r.s = g.getOptarg();
742                         r.type = ProgramType.STRING;
743                         r.probespec = ProbeDescription.Spec.NAME;
744                         compileRequests.add(r);
745                         break;
746                     case 'I':
747                         dtrace.setOption(Option.incdir, g.getOptarg());
748                         break;
749                     case 'l':
750                         mode = Mode.LIST;
751                         dtrace.setOption(Option.zdefs); // -l implies -Z
752                         break;
753                     case 'L':
754                         dtrace.setOption(Option.libdir, g.getOptarg());
755                         break;
756                     case 'm':
757                         r = new CompileRequest();
758                         r.s = g.getOptarg();
759                         r.type = ProgramType.STRING;
760                         r.probespec = ProbeDescription.Spec.MODULE;
761                         compileRequests.add(r);
762                         break;
763                     case 'n':
764                         r = new CompileRequest();
765                         r.s = g.getOptarg();
766                         r.type = ProgramType.STRING;
767                         r.probespec = ProbeDescription.Spec.NAME;
768                         compileRequests.add(r);
769                         break;
770                     case 'o':
771                         String outFileName = g.getOptarg();
772                         File outFile = new File(outFileName);
773                         try {
774                             FileOutputStream fos = new FileOutputStream(
775                                     outFile, true);
776                             out = new PrintStream(fos);
777                         } catch (FileNotFoundException e) {
778                             System.err.println("failed to open " +
779                                 outFileName + " in write mode");
780                             exit(1);
781                         } catch (SecurityException e) {
782                             System.err.println("failed to open " +
783                                 outFileName);
784                             exit(1);
785                         }
786                         break;
787                     case 'p':
788                         String pidstr = g.getOptarg();
789                         int pid = -1;
790                         try {
791                             pid = Integer.parseInt(pidstr);
792                         } catch (NumberFormatException e) {
793                             System.err.println("invalid pid: " + pidstr);
794                             exit(1);
795                         }
796                         dtrace.grabProcess(pid);
797                         break;
798                     case 'P':
799                         r = new CompileRequest();
800                         r.s = g.getOptarg();
801                         r.type = ProgramType.STRING;
802                         r.probespec = ProbeDescription.Spec.PROVIDER;
803                         compileRequests.add(r);
804                         break;
805                     case 'q':
806                         dtrace.setOption(Option.quiet);
807                         break;
808                     case 's':
809                         r = new CompileRequest();
810                         r.s = g.getOptarg();
811                         r.type = ProgramType.FILE;
812                         compileRequests.add(r);
813                         break;
814                     case 'U':
815                         dtrace.setOption(Option.undef, g.getOptarg());
816                         break;
817                     case 'v':
818                         verbose = true;
819                         break;
820                     case 'V':
821                         mode = Mode.VERSION;
822                         break;
823                     case 'w':
824                         dtrace.setOption(Option.destructive);
825                         break;
826                     case 'x':
827                         String[] xarg = g.getOptarg().split("=", 2);
828                         if (xarg.length > 1) {
829                             dtrace.setOption(xarg[0], xarg[1]);
830                         } else if (xarg.length == 1) {
831                             dtrace.setOption(xarg[0]);
832                         }
833                         break;
834                     case 'X':
835                         dtrace.setOption(Option.stdc, g.getOptarg());
836                         break;
837                     case 'Z':
838                         dtrace.setOption(Option.zdefs);
839                         break;
840                     case '?':
841                         usage(); // getopt() already printed an error
842                         break;
843                     default:
844                         System.err.print("getopt() returned " + c + "\n");
845                         c = 0;
846                  }
847             }
848             c = 0;
849             List <String> argList = new LinkedList <String> ();
850             for (int i = g.getOptind(); i < args.length; ++i) {
851                 argList.add(args[i]);
852             }
853
854             if (mode == Mode.VERSION) {
855                 out.printf("dtrace: %s\n", dtrace.getVersion());
856                 dtrace.close();
857                 exit(0);
858             }
859
860             String[] compileArgs = new String[argList.size()];
861             compileArgs = argList.toArray(compileArgs);
862
863             Program program;
864             for (CompileRequest req : compileRequests) {
865                 switch (req.type) {
866                     case STRING:
867                         applyProbespec(req);
868                         program = dtrace.compile(req.s, compileArgs);
869                         break;
870                     case FILE:
871                         File file = new File(req.s);
872                         program = dtrace.compile(file, compileArgs);
873                         break;
874                     default:
875                         throw new IllegalArgumentException(
876                                 "Unexpected program type: " + req.type);
877                 }
878
879                 programList.add(program);
880             }
881
882             // Get options set by #pragmas in compiled program
883             long optval;
884             quiet = (dtrace.getOption(Option.quiet) != Option.UNSET);
885             flow = (dtrace.getOption(Option.flowindent) != Option.UNSET);
886             optval = dtrace.getOption("stackindent");
887             if (optval != Option.UNSET) {
888                 stackindent = (int)optval;
889             }
890
891             if (mode == Mode.LIST) {
892                 out.printf("%5s %10s %17s %33s %s\n",
893                     "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
894
895                 if (verbose) {
896                     List <List <Probe>> lists =
897                             new LinkedList <List <Probe>> ();
898                     for (Program p : programList) {
899                         lists.add(dtrace.listProgramProbeDetail(p));
900                     }
901                     ProbeDescription p;
902                     ProbeInfo pinfo;
903                     for (List <Probe> list : lists) {
904                         for (Probe probe : list) {
905                             p = probe.getDescription();
906                             pinfo = probe.getInfo();
907                             printProbeDescription(p);
908                             printProbeInfo(pinfo);
909                         }
910                     }
911                 } else {
912                     List <List <ProbeDescription>> lists =
913                             new LinkedList <List <ProbeDescription>> ();
914                     for (Program p : programList) {
915                         lists.add(dtrace.listProgramProbes(p));
916                     }
917                     for (List <ProbeDescription> list : lists) {
918                         for (ProbeDescription p : list) {
919                             printProbeDescription(p);
920                         }
921                     }
922                 }
923                 exit(0);
924             }
925
926             String programType;
927             String programDescription;
928             ProgramInfo info;
929             for (Program p : programList) {
930                 if (p instanceof Program.File) {
931                     Program.File pf = (Program.File)p;
932                     programType = "script";
933                     programDescription = pf.getFile().getPath();
934                 } else {
935                     programType = "description";
936                     programDescription =
937                         p.getContents().split("[/{;]", 2)[0];
938                 }
939
940                 if (mode == Mode.EXEC) {
941                     dtrace.enable(p);
942                 } else {
943                     dtrace.getProgramInfo(p);
944                 }
945                 info = p.getInfo();
946                 if ((mode == Mode.EXEC) && !quiet) {
947                     System.err.printf("dtrace: %s '%s' matched %d probe%s\n",
948                             programType, programDescription,
949                             info.getMatchingProbeCount(),
950                             info.getMatchingProbeCount() == 1 ? "" : "s");
951                 }
952                 if (verbose) {
953                     printProgramStability(programType,
954                             programDescription, info);
955                 }
956             }
957             if (mode != Mode.EXEC) {
958                 exit(0);
959             }
960             dtrace.addConsumerListener(new ConsumerAdapter() {
961                 public void consumerStarted(ConsumerEvent e) {
962                     started = true;
963                 }
964                 public void consumerStopped(ConsumerEvent e) {
965                     stopped = true;
966                     out.println();
967                     try {
968                         Aggregate aggregate = dtrace.getAggregate();
969                         if (aggregate != null) {
970                             printAggregate(aggregate);
971                         }
972                         dtrace.close();
973                     } catch (Throwable x) {
974                         exceptionHandler.handleException(x);
975                     }
976                     exit(0);
977                 }
978                 public void dataDropped(DropEvent e) {
979                     System.err.printf("dtrace: %s",
980                             e.getDrop().getDefaultMessage());
981                 }
982                 public void errorEncountered(ErrorEvent e)
983                         throws ConsumerException {
984                     org.opensolaris.os.dtrace.Error error = e.getError();
985                     if (logger.isLoggable(Level.FINE)) {
986                         logger.fine(error.toString());
987                     }
988                     System.err.printf("dtrace: %s",
989                             error.getDefaultMessage());
990                 }
991                 public void dataReceived(DataEvent e)
992                         throws ConsumerException {
993                     consumeProbeData(e.getProbeData());
994                 }
995                 public void processStateChanged(ProcessEvent e)
996                         throws ConsumerException {
997                     if (logger.isLoggable(Level.FINE)) {
998                         logger.fine(e.getProcessState().toString());
999                     }
1000                 }
1001             });
1002             // Print unprinted aggregations after Ctrl-C
1003             Runtime.getRuntime().addShutdownHook(new Thread() {
1004                 public void run() {
1005                     if (stopped || !started) {
1006                         return;
1007                     }
1008
1009                     try {
1010                         Aggregate aggregate = dtrace.getAggregate();
1011                         if (aggregate != null) {
1012                             out.println();
1013                             out.println();
1014                             printAggregate(aggregate);
1015                         }
1016                     } catch (Throwable x) {
1017                         exceptionHandler.handleException(x);
1018                     }
1019                 }
1020             });
1021             dtrace.go(exceptionHandler);
1022         } catch (DTraceException e) {
1023             if (c > 0) {
1024                 // set option error
1025                 if (g.getOptarg() == null) {
1026                     System.err.printf("dtrace: failed to set -%c: %s\n",
1027                         c, e.getMessage());
1028                 } else {
1029                     System.err.printf("dtrace: failed to set -%c %s: %s\n",
1030                         c, g.getOptarg(), e.getMessage());
1031                 }
1032             } else {
1033                 // any other error
1034                 System.err.printf("dtrace: %s\n", e.getMessage());
1035             }
1036             exit(1);
1037         } catch (Exception e) {
1038             e.printStackTrace();
1039             exit(1);
1040         }
1041     }
1042 }