123b5c241Stomee /*
223b5c241Stomee  * CDDL HEADER START
323b5c241Stomee  *
423b5c241Stomee  * The contents of this file are subject to the terms of the
523b5c241Stomee  * Common Development and Distribution License (the "License").
623b5c241Stomee  * You may not use this file except in compliance with the License.
723b5c241Stomee  *
823b5c241Stomee  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
923b5c241Stomee  * or http://www.opensolaris.org/os/licensing.
1023b5c241Stomee  * See the License for the specific language governing permissions
1123b5c241Stomee  * and limitations under the License.
1223b5c241Stomee  *
1323b5c241Stomee  * When distributing Covered Code, include this CDDL HEADER in each
1423b5c241Stomee  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1523b5c241Stomee  * If applicable, add the following below this CDDL HEADER, with the
1623b5c241Stomee  * fields enclosed by brackets "[]" replaced with your own identifying
1723b5c241Stomee  * information: Portions Copyright [yyyy] [name of copyright owner]
1823b5c241Stomee  *
1923b5c241Stomee  * CDDL HEADER END
2023b5c241Stomee  */
2123b5c241Stomee 
2223b5c241Stomee /*
23e77b06d2Stomee  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2423b5c241Stomee  * Use is subject to license terms.
2523b5c241Stomee  *
2623b5c241Stomee  */
2723b5c241Stomee import org.opensolaris.os.dtrace.*;
2823b5c241Stomee import java.io.*;
2923b5c241Stomee import java.util.*;
3023b5c241Stomee import java.util.logging.*;
3123b5c241Stomee 
3223b5c241Stomee /**
33*bbf21555SRichard Lowe  * Emulates {@code dtrace(8)} using the Java DTrace API.
3423b5c241Stomee  */
3523b5c241Stomee public class JDTrace {
3623b5c241Stomee     static Logger logger = Logger.getLogger(JDTrace.class.getName());
3723b5c241Stomee 
3823b5c241Stomee     static Consumer dtrace;
3923b5c241Stomee 
4023b5c241Stomee     static {
4123b5c241Stomee 	Handler handler = new ConsoleHandler();
4223b5c241Stomee 	handler.setLevel(Level.ALL);
4323b5c241Stomee 	logger.addHandler(handler);
4423b5c241Stomee     }
4523b5c241Stomee 
4623b5c241Stomee     static final String CLASSNAME = "JDTrace";
4723b5c241Stomee     static final String OPTSTR =
4823b5c241Stomee 	    "3:6:b:c:CD:ef:Fi:I:lL:m:n:o:p:P:qs:U:vVwx:X:Z";
4923b5c241Stomee     static boolean heading = false;
5023b5c241Stomee     static boolean quiet = false;
5123b5c241Stomee     static boolean flow = false;
5223b5c241Stomee     static int stackindent = 14;
5323b5c241Stomee     static int exitStatus = 0;
5423b5c241Stomee     static boolean started;
5523b5c241Stomee     static boolean stopped;
5623b5c241Stomee     static PrintStream out = System.out;
5723b5c241Stomee     static final String ATS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
5823b5c241Stomee     static final String SPACES = "                                        ";
5923b5c241Stomee     static final int QUANTIZE_ZERO_BUCKET = 63;
6023b5c241Stomee 
6123b5c241Stomee     enum Mode {
6223b5c241Stomee 	EXEC,
6323b5c241Stomee 	INFO,
6423b5c241Stomee 	LIST,
6523b5c241Stomee 	VERSION
6623b5c241Stomee     }
6723b5c241Stomee 
6823b5c241Stomee     enum ProgramType {
6923b5c241Stomee 	STRING,
7023b5c241Stomee 	FILE
7123b5c241Stomee     }
7223b5c241Stomee 
7323b5c241Stomee     static class CompileRequest {
7423b5c241Stomee 	String s;
7523b5c241Stomee 	ProgramType type;
7623b5c241Stomee 	ProbeDescription.Spec probespec;
7723b5c241Stomee     }
7823b5c241Stomee 
7923b5c241Stomee     // Modify program string by expanding an incomplete probe
8023b5c241Stomee     // description according to the requested probespec.
8123b5c241Stomee     static void
applyProbespec(CompileRequest req)8223b5c241Stomee     applyProbespec(CompileRequest req)
8323b5c241Stomee     {
8423b5c241Stomee 	ProbeDescription.Spec spec = ((req.probespec == null)
8523b5c241Stomee 		? ProbeDescription.Spec.NAME
8623b5c241Stomee 		: req.probespec);
8723b5c241Stomee 
8823b5c241Stomee 	int colons = 0;
8923b5c241Stomee 	switch (req.probespec) {
9023b5c241Stomee 	    case PROVIDER:
9123b5c241Stomee 		colons = 3;
9223b5c241Stomee 		break;
9323b5c241Stomee 	    case MODULE:
9423b5c241Stomee 		colons = 2;
9523b5c241Stomee 		break;
9623b5c241Stomee 	    case FUNCTION:
9723b5c241Stomee 		colons = 1;
9823b5c241Stomee 		break;
9923b5c241Stomee 	}
10023b5c241Stomee 
10123b5c241Stomee 	StringBuffer buf = new StringBuffer();
10223b5c241Stomee 	if (colons > 0) {
10323b5c241Stomee 	    char ch;
10423b5c241Stomee 	    int len = req.s.length();
10523b5c241Stomee 
10623b5c241Stomee 	    int i = 0;
10723b5c241Stomee 	    // Find first whitespace character not including leading
10823b5c241Stomee 	    // whitespace (end of first token).  Ignore whitespace
10923b5c241Stomee 	    // inside a block if the block is concatenated with the
11023b5c241Stomee 	    // probe description.
11123b5c241Stomee 	    for (; (i < len) && Character.isWhitespace(req.s.charAt(i)); ++i);
11223b5c241Stomee 	    int npos = i;
11323b5c241Stomee 	    boolean inBlock = false;
11423b5c241Stomee 	    for (; (npos < len) &&
11523b5c241Stomee 		    (!Character.isWhitespace(ch = req.s.charAt(npos)) ||
11623b5c241Stomee 		    inBlock); ++npos) {
11723b5c241Stomee 		if (ch == '{') {
11823b5c241Stomee 		    inBlock = true;
11923b5c241Stomee 		} else if (ch == '}') {
12023b5c241Stomee 		    inBlock = false;
12123b5c241Stomee 		}
12223b5c241Stomee 	    }
12323b5c241Stomee 
12423b5c241Stomee 	    // libdtrace lets you concatenate multiple probe
12523b5c241Stomee 	    // descriptions separated by code blocks in curly braces,
12623b5c241Stomee 	    // for example genunix::'{printf("FOUND");}'::entry, as long
12723b5c241Stomee 	    // as the concatenated probe descriptions begin with ':' and
12823b5c241Stomee 	    // not a specific field such as 'syscall'.  So to expand the
12923b5c241Stomee 	    // possibly multiple probe descriptions, we need to insert
13023b5c241Stomee 	    // colons before each open curly brace, and again at the end
13123b5c241Stomee 	    // only if there is at least one non-whitespace (probe
13223b5c241Stomee 	    // specifying) character after the last closing curly brace.
13323b5c241Stomee 
13423b5c241Stomee 	    int prev_i = 0;
13523b5c241Stomee 	    while (i < npos) {
13623b5c241Stomee 		for (; (i < npos) && (req.s.charAt(i) != '{'); ++i);
13723b5c241Stomee 		buf.append(req.s.substring(prev_i, i));
13823b5c241Stomee 		if ((i < npos) || ((i > 0) && (req.s.charAt(i - 1) != '}'))) {
13923b5c241Stomee 		    for (int c = 0; c < colons; ++c) {
14023b5c241Stomee 			buf.append(':');
14123b5c241Stomee 		    }
14223b5c241Stomee 		}
14323b5c241Stomee 		if (i < npos) {
14423b5c241Stomee 		    buf.append(req.s.charAt(i++));
14523b5c241Stomee 		}
14623b5c241Stomee 		prev_i = i;
14723b5c241Stomee 	    }
14823b5c241Stomee 
14923b5c241Stomee 	    // append remainder of program text
15023b5c241Stomee 	    buf.append(req.s.substring(i));
15123b5c241Stomee 
15223b5c241Stomee 	    req.s = buf.toString();
15323b5c241Stomee 	}
15423b5c241Stomee     }
15523b5c241Stomee 
15623b5c241Stomee     static void
printValue(Object value, int bytes, String stringFormat)15723b5c241Stomee     printValue(Object value, int bytes, String stringFormat)
15823b5c241Stomee     {
15923b5c241Stomee 	if (value instanceof Integer) {
16023b5c241Stomee 	    if (bytes == 1) {
16123b5c241Stomee 		out.printf(" %3d", (Integer)value);
16223b5c241Stomee 	    } else if (bytes == 2) {
16323b5c241Stomee 		out.printf(" %5d", (Integer)value);
16423b5c241Stomee 	    } else {
16523b5c241Stomee 		out.printf(" %8d", (Integer)value);
16623b5c241Stomee 	    }
16723b5c241Stomee 	} else if (value instanceof Long) {
16823b5c241Stomee 	    out.printf(" %16d", (Long)value);
16923b5c241Stomee 	} else {
17023b5c241Stomee 	    out.printf(stringFormat, value.toString());
17123b5c241Stomee 	}
17223b5c241Stomee     }
17323b5c241Stomee 
17423b5c241Stomee     static void
consumeProbeData(ProbeData data)17523b5c241Stomee     consumeProbeData(ProbeData data)
17623b5c241Stomee     {
17723b5c241Stomee 	if (logger.isLoggable(Level.FINER)) {
17823b5c241Stomee 	    logger.finer(data.toString());
17923b5c241Stomee 	}
18023b5c241Stomee 
18123b5c241Stomee 	if (!heading) {
18223b5c241Stomee 	    if (flow) {
18323b5c241Stomee 		out.printf("%3s %-41s\n", "CPU", "FUNCTION");
18423b5c241Stomee 	    } else {
18523b5c241Stomee 		if (!quiet) {
18623b5c241Stomee 		    out.printf("%3s %6s %32s\n",
18723b5c241Stomee 			    "CPU", "ID", "FUNCTION:NAME");
18823b5c241Stomee 		}
18923b5c241Stomee 	    }
19023b5c241Stomee 	    heading = true;
19123b5c241Stomee 	}
19223b5c241Stomee 	ProbeDescription probe = data.getEnabledProbeDescription();
19323b5c241Stomee 	if (flow) {
19423b5c241Stomee 	    Flow flow = data.getFlow();
19523b5c241Stomee 	    int indent = (flow.getDepth() * 2);
19623b5c241Stomee 	    StringBuffer buf = new StringBuffer();
19723b5c241Stomee 	    // indent
19823b5c241Stomee 	    buf.append(' ');
19923b5c241Stomee 	    for (int i = 0; i < indent; ++i) {
20023b5c241Stomee 		buf.append(' ');
20123b5c241Stomee 	    }
20223b5c241Stomee 	    // prefix
20323b5c241Stomee 	    switch (flow.getKind()) {
20423b5c241Stomee 		case ENTRY:
20523b5c241Stomee 		    if (indent == 0) {
20623b5c241Stomee 			buf.append("=> ");
20723b5c241Stomee 		    } else {
20823b5c241Stomee 			buf.append("-> ");
20923b5c241Stomee 		    }
21023b5c241Stomee 		    break;
21123b5c241Stomee 		case RETURN:
21223b5c241Stomee 		    if (indent == 0) {
21323b5c241Stomee 			buf.append("<= ");
21423b5c241Stomee 		    } else {
21523b5c241Stomee 			buf.append("<- ");
21623b5c241Stomee 		    }
21723b5c241Stomee 		    break;
21823b5c241Stomee 	    }
21923b5c241Stomee 
22023b5c241Stomee 	    switch (flow.getKind()) {
22123b5c241Stomee 		case NONE:
22223b5c241Stomee 		    buf.append(probe.getFunction());
22323b5c241Stomee 		    buf.append(':');
22423b5c241Stomee 		    buf.append(probe.getName());
22523b5c241Stomee 		    break;
22623b5c241Stomee 		default:
22723b5c241Stomee 		    buf.append(probe.getFunction());
22823b5c241Stomee 	    }
22923b5c241Stomee 
23023b5c241Stomee 	    out.printf("%3s %-41s ", data.getCPU(),
23123b5c241Stomee 		    buf.toString());
23223b5c241Stomee 	} else {
23323b5c241Stomee 	    if (!quiet) {
23423b5c241Stomee 		StringBuffer buf = new StringBuffer();
23523b5c241Stomee 		buf.append(probe.getFunction());
23623b5c241Stomee 		buf.append(':');
23723b5c241Stomee 		buf.append(probe.getName());
23823b5c241Stomee 		out.printf("%3s %6s %32s ",
23923b5c241Stomee 			data.getCPU(), probe.getID(),
24023b5c241Stomee 			buf.toString());
24123b5c241Stomee 	    }
24223b5c241Stomee 	}
24323b5c241Stomee 	Record record = null;
24423b5c241Stomee 	Object value;
24523b5c241Stomee 	List <Record> records = data.getRecords();
24623b5c241Stomee 	Iterator <Record> itr = records.iterator();
24723b5c241Stomee 	while (itr.hasNext()) {
24823b5c241Stomee 	    record = itr.next();
24923b5c241Stomee 
25023b5c241Stomee 	    if (record instanceof ExitRecord) {
25123b5c241Stomee 		exitStatus = ((ExitRecord)record).getStatus();
25223b5c241Stomee 	    } else if (record instanceof ScalarRecord) {
25323b5c241Stomee 		ScalarRecord scalar = (ScalarRecord)record;
25423b5c241Stomee 		value = scalar.getValue();
25523b5c241Stomee 		if (value instanceof byte[]) {
25623b5c241Stomee 		    out.print(record.toString());
25723b5c241Stomee 		} else {
25823b5c241Stomee 		    if (quiet) {
25923b5c241Stomee 			out.print(value);
26023b5c241Stomee 		    } else {
26123b5c241Stomee 			printValue(value, scalar.getNumberOfBytes(),
26223b5c241Stomee 				"  %-33s");
26323b5c241Stomee 		    }
26423b5c241Stomee 		}
26523b5c241Stomee 	    } else if (record instanceof PrintfRecord) {
26623b5c241Stomee 		out.print(record);
26723b5c241Stomee 	    } else if (record instanceof PrintaRecord) {
26823b5c241Stomee 		PrintaRecord printa = (PrintaRecord)record;
26923b5c241Stomee 		List <Tuple> tuples = printa.getTuples();
27023b5c241Stomee 		if (tuples.isEmpty()) {
27123b5c241Stomee 		    out.print(printa.getOutput());
27223b5c241Stomee 		} else {
27323b5c241Stomee 		    for (Tuple t : tuples) {
27423b5c241Stomee 			out.print(printa.getFormattedString(t));
27523b5c241Stomee 		    }
27623b5c241Stomee 		}
27723b5c241Stomee 
27823b5c241Stomee 		if (logger.isLoggable(Level.FINE)) {
27923b5c241Stomee 		    logger.fine(printa.toString());
28023b5c241Stomee 		}
28123b5c241Stomee 	    } else if (record instanceof StackValueRecord) {
28223b5c241Stomee 		printStack((StackValueRecord)record);
28323b5c241Stomee 	    }
28423b5c241Stomee 	}
28523b5c241Stomee 	if (!quiet) {
28623b5c241Stomee 	    out.println();
28723b5c241Stomee 	}
28823b5c241Stomee     }
28923b5c241Stomee 
29023b5c241Stomee     static void
printDistribution(Distribution d)29123b5c241Stomee     printDistribution(Distribution d)
29223b5c241Stomee     {
29323b5c241Stomee 	out.printf("\n%16s %41s %-9s\n", "value",
29423b5c241Stomee 		"------------- Distribution -------------",
29523b5c241Stomee 		"count");
29623b5c241Stomee 	long v; // bucket frequency (value)
29723b5c241Stomee 	long b; // lower bound of bucket range
29823b5c241Stomee 	double total = 0;
29923b5c241Stomee 	boolean positives = false;
30023b5c241Stomee 	boolean negatives = false;
30123b5c241Stomee 
30223b5c241Stomee 	Distribution.Bucket bucket;
30323b5c241Stomee 	int b1 = 0; // first displayed bucket
30423b5c241Stomee 	int b2 = d.size() - 1; // last displayed bucket
305ae94d716SRichard Lowe 
30623b5c241Stomee 	for (; (b1 <= b2) && (d.get(b1).getFrequency() == 0); ++b1);
30723b5c241Stomee 	// If possible, get one bucket before the first non-zero
30823b5c241Stomee 	// bucket and one bucket after the last.
30923b5c241Stomee 	if (b1 > b2) {
31023b5c241Stomee 	    // There isn't any data.  This is possible if (and only if)
31123b5c241Stomee 	    // negative increment values have been used.  In this case,
31223b5c241Stomee 	    // print the buckets around the base.
31323b5c241Stomee 	    if (d instanceof LinearDistribution) {
31423b5c241Stomee 		b1 = 0;
31523b5c241Stomee 		b2 = 2;
31623b5c241Stomee 	    } else {
31723b5c241Stomee 		b1 = QUANTIZE_ZERO_BUCKET - 1;
31823b5c241Stomee 		b2 = QUANTIZE_ZERO_BUCKET + 1;
31923b5c241Stomee 	    }
32023b5c241Stomee 	} else {
32123b5c241Stomee 	    if (b1 > 0) --b1;
32223b5c241Stomee 	    for (; (b2 > 0) && (d.get(b2).getFrequency() == 0); --b2);
32323b5c241Stomee 	    if (b2 < (d.size() - 1)) ++b2;
32423b5c241Stomee 	}
32523b5c241Stomee 	for (int i = b1; i <= b2; ++i) {
32623b5c241Stomee 	    v = d.get(i).getFrequency();
32723b5c241Stomee 	    if (v > 0) {
32823b5c241Stomee 		positives = true;
32923b5c241Stomee 	    }
33023b5c241Stomee 	    if (v < 0) {
33123b5c241Stomee 		negatives = true;
33223b5c241Stomee 	    }
33323b5c241Stomee 	    total += Math.abs((double)v);
33423b5c241Stomee 	}
33523b5c241Stomee 	for (int i = b1; i <= b2; ++i) {
33623b5c241Stomee 	    bucket = d.get(i);
33723b5c241Stomee 	    v = bucket.getFrequency();
33823b5c241Stomee 	    b = bucket.getMin();
33923b5c241Stomee 
340ae94d716SRichard Lowe 	    if ((d instanceof LinearDistribution) ||
341ae94d716SRichard Lowe 		(d instanceof LogLinearDistribution)) {
34223b5c241Stomee 		if (b == Long.MIN_VALUE) {
343ae94d716SRichard Lowe 		    String lt;
344ae94d716SRichard Lowe 		    if (d instanceof LinearDistribution)
345ae94d716SRichard Lowe 			lt = "< " + ((LinearDistribution)d).getBase();
346ae94d716SRichard Lowe 		    else
347ae94d716SRichard Lowe 			lt = "< " + ((LogLinearDistribution)d).getBase();
34823b5c241Stomee 		    out.printf("%16s ", lt);
34923b5c241Stomee 		} else if (bucket.getMax() == Long.MAX_VALUE) {
35023b5c241Stomee 		    String ge = ">= " + b;
35123b5c241Stomee 		    out.printf("%16s ", ge);
35223b5c241Stomee 		} else {
35323b5c241Stomee 		    out.printf("%16d ", b);
35423b5c241Stomee 		}
35523b5c241Stomee 	    } else {
35623b5c241Stomee 		out.printf("%16d ", b);
35723b5c241Stomee 	    }
35823b5c241Stomee 
35923b5c241Stomee 	    printDistributionLine(v, total, positives, negatives);
36023b5c241Stomee 	}
36123b5c241Stomee     }
36223b5c241Stomee 
36323b5c241Stomee     static void
printDistributionLine(long val, double total, boolean positives, boolean negatives)36423b5c241Stomee     printDistributionLine(long val, double total, boolean positives,
36523b5c241Stomee 	    boolean negatives)
36623b5c241Stomee     {
36723b5c241Stomee 	double f;
36823b5c241Stomee 	int depth, len = 40;
36923b5c241Stomee 
37023b5c241Stomee 	assert (ATS.length() == len && SPACES.length() == len);
37123b5c241Stomee 	assert (!(total == 0 && (positives || negatives)));
37223b5c241Stomee 	assert (!(val < 0 && !negatives));
37323b5c241Stomee 	assert (!(val > 0 && !positives));
37423b5c241Stomee 	assert (!(val != 0 && total == 0));
37523b5c241Stomee 
37623b5c241Stomee 	if (!negatives) {
37723b5c241Stomee 	    if (positives) {
37823b5c241Stomee 		f = (Math.abs((double)val) * (double)len) / total;
37923b5c241Stomee 		    depth = (int)(f + 0.5);
38023b5c241Stomee 	    } else {
38123b5c241Stomee 		depth = 0;
38223b5c241Stomee 	    }
38323b5c241Stomee 
38423b5c241Stomee 	    out.printf("|%s%s %-9d\n", ATS.substring(len - depth),
38523b5c241Stomee 		    SPACES.substring(depth), val);
38623b5c241Stomee 	    return;
38723b5c241Stomee 	}
38823b5c241Stomee 
38923b5c241Stomee 	if (!positives) {
39023b5c241Stomee 	    f = (Math.abs((double)val) * (double)len) / total;
39123b5c241Stomee 	    depth = (int)(f + 0.5);
39223b5c241Stomee 
39323b5c241Stomee 	    out.printf("%s%s| %-9d\n", SPACES.substring(depth),
39423b5c241Stomee 		    ATS.substring(len - depth), val);
39523b5c241Stomee 	    return;
39623b5c241Stomee 	}
39723b5c241Stomee 
39823b5c241Stomee 	/*
39923b5c241Stomee 	 * If we're here, we have both positive and negative bucket values.
40023b5c241Stomee 	 * To express this graphically, we're going to generate both positive
40123b5c241Stomee 	 * and negative bars separated by a centerline.  These bars are half
40223b5c241Stomee 	 * the size of normal quantize()/lquantize() bars, so we divide the
40323b5c241Stomee 	 * length in half before calculating the bar length.
40423b5c241Stomee 	 */
40523b5c241Stomee 	len /= 2;
40623b5c241Stomee 	String ats = ATS.substring(len);
40723b5c241Stomee 	String spaces = SPACES.substring(len);
40823b5c241Stomee 
40923b5c241Stomee 	f = (Math.abs((double)val) * (double)len) / total;
41023b5c241Stomee 	depth = (int)(f + 0.5);
41123b5c241Stomee 
41223b5c241Stomee 	if (val <= 0) {
41323b5c241Stomee 	    out.printf("%s%s|%s %-9d\n", spaces.substring(depth),
41423b5c241Stomee 		    ats.substring(len - depth), repeat(" ", len), val);
41523b5c241Stomee 	    return;
41623b5c241Stomee 	} else {
41723b5c241Stomee 	    out.printf("%20s|%s%s %-9d\n", "", ats.substring(len - depth),
41823b5c241Stomee 		    spaces.substring(depth), val);
41923b5c241Stomee 	}
42023b5c241Stomee     }
42123b5c241Stomee 
42223b5c241Stomee     public static String
repeat(String s, int n)42323b5c241Stomee     repeat(String s, int n)
42423b5c241Stomee     {
42523b5c241Stomee         StringBuffer buf = new StringBuffer();
42623b5c241Stomee         for (int i = 0; i < n; ++i) {
42723b5c241Stomee             buf.append(s);
42823b5c241Stomee         }
42923b5c241Stomee         return buf.toString();
43023b5c241Stomee     }
43123b5c241Stomee 
43223b5c241Stomee     static void
printStack(StackValueRecord rec)43323b5c241Stomee     printStack(StackValueRecord rec)
43423b5c241Stomee     {
43523b5c241Stomee 	StackFrame[] frames = rec.getStackFrames();
43623b5c241Stomee 	int i;
43723b5c241Stomee 	out.println();
43823b5c241Stomee 	String s;
43923b5c241Stomee 	for (StackFrame f : frames) {
44023b5c241Stomee 	    for (i = 0; i < stackindent; ++i) {
44123b5c241Stomee 		out.print(' ');
44223b5c241Stomee 	    }
44323b5c241Stomee 	    s = f.getFrame();
44423b5c241Stomee 	    if (s.indexOf('[') == 0) {
44523b5c241Stomee 		out.print("  ");
44623b5c241Stomee 	    }
44723b5c241Stomee 	    out.println(s);
44823b5c241Stomee 	}
44923b5c241Stomee     }
45023b5c241Stomee 
45123b5c241Stomee     static void
printAggregate(Aggregate aggregate)45223b5c241Stomee     printAggregate(Aggregate aggregate)
45323b5c241Stomee     {
454e77b06d2Stomee 	printAggregationRecords(aggregate.getOrderedRecords());
45523b5c241Stomee     }
45623b5c241Stomee 
45723b5c241Stomee     static void
printAggregationRecords(List <AggregationRecord> list)45823b5c241Stomee     printAggregationRecords(List <AggregationRecord> list)
45923b5c241Stomee     {
46023b5c241Stomee 	Tuple tuple;
46123b5c241Stomee 	AggregationValue value;
46223b5c241Stomee 	ValueRecord tupleRecord;
46323b5c241Stomee 	int i;
46423b5c241Stomee 	int len;
46523b5c241Stomee 	for (AggregationRecord r : list) {
46623b5c241Stomee 	    tuple = r.getTuple();
46723b5c241Stomee 	    value = r.getValue();
46823b5c241Stomee 	    len = tuple.size();
46923b5c241Stomee 	    for (i = 0; i < len; ++i) {
47023b5c241Stomee 		tupleRecord = tuple.get(i);
47123b5c241Stomee 		if (tupleRecord instanceof StackValueRecord) {
47223b5c241Stomee 		    printStack((StackValueRecord)tupleRecord);
47323b5c241Stomee 		} else if (tupleRecord instanceof SymbolValueRecord) {
47423b5c241Stomee 		    printValue(tupleRecord.toString(), -1, "  %-50s");
47523b5c241Stomee 		} else {
47623b5c241Stomee 		    printValue(tupleRecord.getValue(),
47723b5c241Stomee 			    ((ScalarRecord)tupleRecord).getNumberOfBytes(),
47823b5c241Stomee 			    "  %-50s");
47923b5c241Stomee 		}
48023b5c241Stomee 	    }
48123b5c241Stomee 	    if (value instanceof Distribution) {
48223b5c241Stomee 		Distribution d = (Distribution)value;
48323b5c241Stomee 		printDistribution(d);
48423b5c241Stomee 	    } else {
48523b5c241Stomee 		Number v = value.getValue();
48623b5c241Stomee 		printValue(v, -1, "  %-50s");
48723b5c241Stomee 	    }
48823b5c241Stomee 	    out.println();
48923b5c241Stomee 	}
49023b5c241Stomee     }
49123b5c241Stomee 
49223b5c241Stomee     static void
exit(int status)49323b5c241Stomee     exit(int status)
49423b5c241Stomee     {
49523b5c241Stomee 	out.flush();
49623b5c241Stomee 	System.err.flush();
49723b5c241Stomee 	if (status == 0) {
49823b5c241Stomee 	    status = exitStatus;
49923b5c241Stomee 	}
50023b5c241Stomee 	System.exit(status);
50123b5c241Stomee     }
50223b5c241Stomee 
50323b5c241Stomee     static void
usage()50423b5c241Stomee     usage()
50523b5c241Stomee     {
50623b5c241Stomee 	String predact = "[[ predicate ] action ]";
50723b5c241Stomee 	System.err.printf("Usage: java %s [-32|-64] [-CeFlqvVwZ] " +
50823b5c241Stomee 	    "[-b bufsz] [-c cmd] [-D name[=def]]\n\t[-I path] [-L path] " +
50923b5c241Stomee 	    "[-o output] [-p pid] [-s script] [-U name]\n\t" +
51023b5c241Stomee 	    "[-x opt[=val]] [-X a|c|s|t]\n\n" +
51123b5c241Stomee 	    "\t[-P provider %s]\n" +
51223b5c241Stomee 	    "\t[-m [ provider: ] module %s]\n" +
51323b5c241Stomee 	    "\t[-f [[ provider: ] module: ] func %s]\n" +
51423b5c241Stomee 	    "\t[-n [[[ provider: ] module: ] func: ] name %s]\n" +
51523b5c241Stomee 	    "\t[-i probe-id %s] [ args ... ]\n\n", CLASSNAME,
51623b5c241Stomee 	    predact, predact, predact, predact, predact);
51723b5c241Stomee 	System.err.printf("\tpredicate -> '/' D-expression '/'\n");
51823b5c241Stomee 	System.err.printf("\t   action -> '{' D-statements '}'\n");
51923b5c241Stomee 	System.err.printf("\n" +
52023b5c241Stomee 	    "\t-32 generate 32-bit D programs\n" +
52123b5c241Stomee 	    "\t-64 generate 64-bit D programs\n\n" +
52223b5c241Stomee 	    "\t-b  set trace buffer size\n" +
52323b5c241Stomee 	    "\t-c  run specified command and exit upon its completion\n" +
52423b5c241Stomee 	    "\t-C  run cpp(1) preprocessor on script files\n" +
52523b5c241Stomee 	    "\t-D  define symbol when invoking preprocessor\n" +
52623b5c241Stomee 	    "\t-e  exit after compiling request but prior to enabling " +
52723b5c241Stomee 		    "probes\n" +
52823b5c241Stomee 	    "\t-f  enable or list probes matching the specified " +
52923b5c241Stomee 		    "function name\n" +
53023b5c241Stomee 	    "\t-F  coalesce trace output by function\n" +
53123b5c241Stomee 	    "\t-i  enable or list probes matching the specified probe id\n" +
53223b5c241Stomee 	    "\t-I  add include directory to preprocessor search path\n" +
53323b5c241Stomee 	    "\t-l  list probes matching specified criteria\n" +
53423b5c241Stomee 	    "\t-L  add library directory to library search path\n" +
53523b5c241Stomee 	    "\t-m  enable or list probes matching the specified " +
53623b5c241Stomee 		    "module name\n" +
53723b5c241Stomee 	    "\t-n  enable or list probes matching the specified probe name\n" +
53823b5c241Stomee 	    "\t-o  set output file\n" +
53923b5c241Stomee 	    "\t-p  grab specified process-ID and cache its symbol tables\n" +
54023b5c241Stomee 	    "\t-P  enable or list probes matching the specified " +
54123b5c241Stomee 		    "provider name\n" +
54223b5c241Stomee 	    "\t-q  set quiet mode (only output explicitly traced data)\n" +
54323b5c241Stomee 	    "\t-s  enable or list probes according to the specified " +
54423b5c241Stomee 		    "D script\n" +
54523b5c241Stomee 	    "\t-U  undefine symbol when invoking preprocessor\n" +
54623b5c241Stomee 	    "\t-v  set verbose mode (report stability attributes, " +
54723b5c241Stomee 		    "arguments)\n" +
54823b5c241Stomee 	    "\t-V  report DTrace API version\n" +
54923b5c241Stomee 	    "\t-w  permit destructive actions\n" +
55023b5c241Stomee 	    "\t-x  enable or modify compiler and tracing options\n" +
55123b5c241Stomee 	    "\t-X  specify ISO C conformance settings for preprocessor\n" +
55223b5c241Stomee 	    "\t-Z  permit probe descriptions that match zero probes\n" +
55323b5c241Stomee 	    "\n" +
55423b5c241Stomee 	    "\tTo log PrintaRecord, set this environment variable:\n" +
55523b5c241Stomee 	    "\t\tJDTRACE_LOGGING_LEVEL=FINE\n" +
55623b5c241Stomee 	    "\tTo log ProbeData, set JDTRACE_LOGGING_LEVEL=FINER\n");
55723b5c241Stomee 	exit(2);
55823b5c241Stomee     }
55923b5c241Stomee 
56023b5c241Stomee     static void
printProgramStability(String programType, String programDescription, ProgramInfo info)56123b5c241Stomee     printProgramStability(String programType, String programDescription,
56223b5c241Stomee 	    ProgramInfo info)
56323b5c241Stomee     {
56423b5c241Stomee 	out.println();
56523b5c241Stomee 	out.printf("Stability data for %s %s:\n\n",
56623b5c241Stomee 		programType, programDescription);
56723b5c241Stomee 	InterfaceAttributes a;
56823b5c241Stomee 	out.println("\tMinimum probe description " +
56923b5c241Stomee 		"attributes");
57023b5c241Stomee 	a = info.getMinimumProbeAttributes();
57123b5c241Stomee 	out.printf("\t\tIdentifier Names: %s\n",
57223b5c241Stomee 		a.getNameStability());
57323b5c241Stomee 	out.printf("\t\tData Semantics:   %s\n",
57423b5c241Stomee 		a.getDataStability());
57523b5c241Stomee 	out.printf("\t\tDependency Class: %s\n",
57623b5c241Stomee 		a.getDependencyClass());
57723b5c241Stomee 	out.println("\tMinimum probe statement attributes");
57823b5c241Stomee 	a = info.getMinimumStatementAttributes();
57923b5c241Stomee 	out.printf("\t\tIdentifier Names: %s\n",
58023b5c241Stomee 		a.getNameStability());
58123b5c241Stomee 	out.printf("\t\tData Semantics:   %s\n",
58223b5c241Stomee 		a.getDataStability());
58323b5c241Stomee 	out.printf("\t\tDependency Class: %s\n",
58423b5c241Stomee 		a.getDependencyClass());
58523b5c241Stomee     }
58623b5c241Stomee 
58723b5c241Stomee     static void
printProbeDescription(ProbeDescription p)58823b5c241Stomee     printProbeDescription(ProbeDescription p)
58923b5c241Stomee     {
59023b5c241Stomee 	out.printf("%5d %10s %17s %33s %s\n", p.getID(),
59123b5c241Stomee 	    p.getProvider(), p.getModule(),
59223b5c241Stomee 	    p.getFunction(), p.getName());
59323b5c241Stomee     }
59423b5c241Stomee 
59523b5c241Stomee     static void
printProbeInfo(ProbeInfo p)59623b5c241Stomee     printProbeInfo(ProbeInfo p)
59723b5c241Stomee     {
59823b5c241Stomee 	InterfaceAttributes a;
59923b5c241Stomee 	out.println("\n\tProbe Description Attributes");
60023b5c241Stomee 
60123b5c241Stomee 	a = p.getProbeAttributes();
60223b5c241Stomee 	out.printf("\t\tIdentifier Names: %s\n",
60323b5c241Stomee 	    a.getNameStability());
60423b5c241Stomee 	out.printf("\t\tData Semantics:   %s\n",
60523b5c241Stomee 	    a.getDataStability());
60623b5c241Stomee 	out.printf("\t\tDependency Class: %s\n",
60723b5c241Stomee 	    a.getDependencyClass());
60823b5c241Stomee 
60923b5c241Stomee 	out.println("\n\tArgument Attributes");
61023b5c241Stomee 
61123b5c241Stomee 	a = p.getArgumentAttributes();
61223b5c241Stomee 	out.printf("\t\tIdentifier Names: %s\n",
61323b5c241Stomee 	    a.getNameStability());
61423b5c241Stomee 	out.printf("\t\tData Semantics:   %s\n",
61523b5c241Stomee 	    a.getDataStability());
61623b5c241Stomee 	out.printf("\t\tDependency Class: %s\n",
61723b5c241Stomee 	    a.getDependencyClass());
61823b5c241Stomee 
61923b5c241Stomee 	// Argument types unsupported for now.
62023b5c241Stomee 
62123b5c241Stomee 	out.println();
62223b5c241Stomee     }
62323b5c241Stomee 
62423b5c241Stomee     public static void
main(String[] args)62523b5c241Stomee     main(String[] args)
62623b5c241Stomee     {
62723b5c241Stomee 	String loggingLevel = System.getenv().get("JDTRACE_LOGGING_LEVEL");
62823b5c241Stomee 	try {
62923b5c241Stomee 	    logger.setLevel(Level.parse(loggingLevel));
63023b5c241Stomee 	} catch (Exception e) {
63123b5c241Stomee 	    logger.setLevel(Level.OFF);
63223b5c241Stomee 	}
63323b5c241Stomee 
63423b5c241Stomee 	if (args.length == 0) {
63523b5c241Stomee 	    usage();
63623b5c241Stomee 	}
63723b5c241Stomee 
63823b5c241Stomee 	List <CompileRequest> compileRequests = new LinkedList
63923b5c241Stomee 		<CompileRequest> ();
64023b5c241Stomee 	List <Program> programList = new LinkedList <Program> ();
64123b5c241Stomee 	boolean verbose = false;
64223b5c241Stomee 	Mode mode = Mode.EXEC;
64323b5c241Stomee 
64423b5c241Stomee 	final ExceptionHandler exceptionHandler = new ExceptionHandler() {
64523b5c241Stomee 	    public void handleException(Throwable e) {
64623b5c241Stomee 		if (e instanceof DTraceException) {
64723b5c241Stomee 		    DTraceException de = (DTraceException)e;
64823b5c241Stomee 		    System.err.printf("dtrace: %s\n", de.getMessage());
64923b5c241Stomee 		} else if (e instanceof ConsumerException) {
65023b5c241Stomee 		    ConsumerException ce = (ConsumerException)e;
65123b5c241Stomee 		    Object msg = ce.getNotificationObject();
65223b5c241Stomee 		    if ((msg instanceof org.opensolaris.os.dtrace.Error) ||
65323b5c241Stomee 			(msg instanceof Drop)) {
65423b5c241Stomee 			System.err.printf("dtrace: %s\n", ce.getMessage());
65523b5c241Stomee 		    } else {
65623b5c241Stomee 			ce.printStackTrace();
65723b5c241Stomee 		    }
65823b5c241Stomee 		} else {
65923b5c241Stomee 		    e.printStackTrace();
66023b5c241Stomee 		}
66123b5c241Stomee 		exit(1);
66223b5c241Stomee 	    }
66323b5c241Stomee 	};
66423b5c241Stomee 
66523b5c241Stomee 	Getopt g = new Getopt(CLASSNAME, args, OPTSTR);
66623b5c241Stomee 	int c = 0;
66723b5c241Stomee 
66823b5c241Stomee 	List <Consumer.OpenFlag> openFlags =
66923b5c241Stomee 		new ArrayList <Consumer.OpenFlag> ();
67023b5c241Stomee 
67123b5c241Stomee 	while ((c = g.getopt()) != -1) {
67223b5c241Stomee 	    switch (c) {
67323b5c241Stomee 		case '3': {
67423b5c241Stomee 		    String s = g.getOptarg();
67523b5c241Stomee 		    if (!s.equals("2")) {
67623b5c241Stomee 			System.err.println("dtrace: illegal option -- 3" + s);
67723b5c241Stomee 			usage();
67823b5c241Stomee 		    }
67923b5c241Stomee 		    openFlags.add(Consumer.OpenFlag.ILP32);
68023b5c241Stomee 		    break;
68123b5c241Stomee 		}
68223b5c241Stomee 		case '6': {
68323b5c241Stomee 		    String s = g.getOptarg();
68423b5c241Stomee 		    if (!s.equals("4")) {
68523b5c241Stomee 			System.err.println("dtrace: illegal option -- 6" + s);
68623b5c241Stomee 			usage();
68723b5c241Stomee 		    }
68823b5c241Stomee 		    openFlags.add(Consumer.OpenFlag.LP64);
68923b5c241Stomee 		    break;
69023b5c241Stomee 		}
69123b5c241Stomee 	    }
69223b5c241Stomee 	}
69323b5c241Stomee 
69423b5c241Stomee 	Consumer.OpenFlag[] oflags = new Consumer.OpenFlag[openFlags.size()];
695e77b06d2Stomee 	oflags = openFlags.toArray(oflags);
69623b5c241Stomee 
69723b5c241Stomee 	dtrace = new LocalConsumer() {
69823b5c241Stomee 	    protected Thread createThread() {
69923b5c241Stomee 		Thread t = super.createThread();
70023b5c241Stomee 		t.setDaemon(false);
70123b5c241Stomee 		t.setPriority(Thread.MIN_PRIORITY);
70223b5c241Stomee 		return t;
70323b5c241Stomee 	    }
70423b5c241Stomee 	};
70523b5c241Stomee 
70623b5c241Stomee 	g = new Getopt(CLASSNAME, args, OPTSTR);
70723b5c241Stomee 	c = 0;
70823b5c241Stomee 
70923b5c241Stomee 	try {
71023b5c241Stomee 	    dtrace.open(oflags);
71123b5c241Stomee 
71223b5c241Stomee 	    // Set default options that may be overriden by options or #pragma
71323b5c241Stomee 	    dtrace.setOption(Option.bufsize, Option.mb(4));
71423b5c241Stomee 	    dtrace.setOption(Option.aggsize, Option.mb(4));
71523b5c241Stomee 
71623b5c241Stomee 	    CompileRequest r;
71723b5c241Stomee 	    while ((c = g.getopt()) != -1) {
71823b5c241Stomee 		switch (c) {
71923b5c241Stomee 		    case 'b':
72023b5c241Stomee 			dtrace.setOption(Option.bufsize, g.getOptarg());
72123b5c241Stomee 			break;
72223b5c241Stomee 		    case 'c':
72323b5c241Stomee 			dtrace.createProcess(g.getOptarg());
72423b5c241Stomee 			break;
72523b5c241Stomee 		    case 'C':
72623b5c241Stomee 			dtrace.setOption(Option.cpp);
72723b5c241Stomee 			break;
72823b5c241Stomee 		    case 'D':
72923b5c241Stomee 			dtrace.setOption(Option.define, g.getOptarg());
73023b5c241Stomee 			break;
73123b5c241Stomee 		    case 'e':
73223b5c241Stomee 			mode = Mode.INFO;
73323b5c241Stomee 			break;
73423b5c241Stomee 		    case 'f':
73523b5c241Stomee 			r = new CompileRequest();
73623b5c241Stomee 			r.s = g.getOptarg();
73723b5c241Stomee 			r.type = ProgramType.STRING;
73823b5c241Stomee 			r.probespec = ProbeDescription.Spec.FUNCTION;
73923b5c241Stomee 			compileRequests.add(r);
74023b5c241Stomee 			break;
74123b5c241Stomee 		    case 'F':
74223b5c241Stomee 			dtrace.setOption(Option.flowindent);
74323b5c241Stomee 			break;
74423b5c241Stomee 		    case 'i':
74523b5c241Stomee 			r = new CompileRequest();
74623b5c241Stomee 			r.s = g.getOptarg();
74723b5c241Stomee 			r.type = ProgramType.STRING;
74823b5c241Stomee 			r.probespec = ProbeDescription.Spec.NAME;
74923b5c241Stomee 			compileRequests.add(r);
75023b5c241Stomee 			break;
75123b5c241Stomee 		    case 'I':
75223b5c241Stomee 			dtrace.setOption(Option.incdir, g.getOptarg());
75323b5c241Stomee 			break;
75423b5c241Stomee 		    case 'l':
75523b5c241Stomee 			mode = Mode.LIST;
75623b5c241Stomee 			dtrace.setOption(Option.zdefs); // -l implies -Z
75723b5c241Stomee 			break;
75823b5c241Stomee 		    case 'L':
75923b5c241Stomee 			dtrace.setOption(Option.libdir, g.getOptarg());
76023b5c241Stomee 			break;
76123b5c241Stomee 		    case 'm':
76223b5c241Stomee 			r = new CompileRequest();
76323b5c241Stomee 			r.s = g.getOptarg();
76423b5c241Stomee 			r.type = ProgramType.STRING;
76523b5c241Stomee 			r.probespec = ProbeDescription.Spec.MODULE;
76623b5c241Stomee 			compileRequests.add(r);
76723b5c241Stomee 			break;
76823b5c241Stomee 		    case 'n':
76923b5c241Stomee 			r = new CompileRequest();
77023b5c241Stomee 			r.s = g.getOptarg();
77123b5c241Stomee 			r.type = ProgramType.STRING;
77223b5c241Stomee 			r.probespec = ProbeDescription.Spec.NAME;
77323b5c241Stomee 			compileRequests.add(r);
77423b5c241Stomee 			break;
77523b5c241Stomee 		    case 'o':
77623b5c241Stomee 			String outFileName = g.getOptarg();
77723b5c241Stomee 			File outFile = new File(outFileName);
77823b5c241Stomee 			try {
77923b5c241Stomee 			    FileOutputStream fos = new FileOutputStream(
78023b5c241Stomee 				    outFile, true);
78123b5c241Stomee 			    out = new PrintStream(fos);
78223b5c241Stomee 			} catch (FileNotFoundException e) {
78323b5c241Stomee 			    System.err.println("failed to open " +
78423b5c241Stomee 				outFileName + " in write mode");
78523b5c241Stomee 			    exit(1);
78623b5c241Stomee 			} catch (SecurityException e) {
78723b5c241Stomee 			    System.err.println("failed to open " +
78823b5c241Stomee 				outFileName);
78923b5c241Stomee 			    exit(1);
79023b5c241Stomee 			}
79123b5c241Stomee 			break;
79223b5c241Stomee 		    case 'p':
79323b5c241Stomee 			String pidstr = g.getOptarg();
79423b5c241Stomee 			int pid = -1;
79523b5c241Stomee 			try {
79623b5c241Stomee 			    pid = Integer.parseInt(pidstr);
79723b5c241Stomee 			} catch (NumberFormatException e) {
79823b5c241Stomee 			    System.err.println("invalid pid: " + pidstr);
79923b5c241Stomee 			    exit(1);
80023b5c241Stomee 			}
80123b5c241Stomee 			dtrace.grabProcess(pid);
80223b5c241Stomee 			break;
80323b5c241Stomee 		    case 'P':
80423b5c241Stomee 			r = new CompileRequest();
80523b5c241Stomee 			r.s = g.getOptarg();
80623b5c241Stomee 			r.type = ProgramType.STRING;
80723b5c241Stomee 			r.probespec = ProbeDescription.Spec.PROVIDER;
80823b5c241Stomee 			compileRequests.add(r);
80923b5c241Stomee 			break;
81023b5c241Stomee 		    case 'q':
81123b5c241Stomee 			dtrace.setOption(Option.quiet);
81223b5c241Stomee 			break;
81323b5c241Stomee 		    case 's':
81423b5c241Stomee 			r = new CompileRequest();
81523b5c241Stomee 			r.s = g.getOptarg();
81623b5c241Stomee 			r.type = ProgramType.FILE;
81723b5c241Stomee 			compileRequests.add(r);
81823b5c241Stomee 			break;
81923b5c241Stomee 		    case 'U':
82023b5c241Stomee 			dtrace.setOption(Option.undef, g.getOptarg());
82123b5c241Stomee 			break;
82223b5c241Stomee 		    case 'v':
82323b5c241Stomee 			verbose = true;
82423b5c241Stomee 			break;
82523b5c241Stomee 		    case 'V':
82623b5c241Stomee 			mode = Mode.VERSION;
82723b5c241Stomee 			break;
82823b5c241Stomee 		    case 'w':
82923b5c241Stomee 			dtrace.setOption(Option.destructive);
83023b5c241Stomee 			break;
83123b5c241Stomee 		    case 'x':
83223b5c241Stomee 			String[] xarg = g.getOptarg().split("=", 2);
83323b5c241Stomee 			if (xarg.length > 1) {
83423b5c241Stomee 			    dtrace.setOption(xarg[0], xarg[1]);
83523b5c241Stomee 			} else if (xarg.length == 1) {
83623b5c241Stomee 			    dtrace.setOption(xarg[0]);
83723b5c241Stomee 			}
83823b5c241Stomee 			break;
83923b5c241Stomee 		    case 'X':
84023b5c241Stomee 			dtrace.setOption(Option.stdc, g.getOptarg());
84123b5c241Stomee 			break;
84223b5c241Stomee 		    case 'Z':
84323b5c241Stomee 			dtrace.setOption(Option.zdefs);
84423b5c241Stomee 			break;
84523b5c241Stomee 		    case '?':
84623b5c241Stomee 			usage(); // getopt() already printed an error
84723b5c241Stomee 			break;
84823b5c241Stomee 		    default:
84923b5c241Stomee 			System.err.print("getopt() returned " + c + "\n");
85023b5c241Stomee 			c = 0;
85123b5c241Stomee 		 }
85223b5c241Stomee 	    }
85323b5c241Stomee 	    c = 0;
85423b5c241Stomee 	    List <String> argList = new LinkedList <String> ();
85523b5c241Stomee 	    for (int i = g.getOptind(); i < args.length; ++i) {
85623b5c241Stomee 		argList.add(args[i]);
85723b5c241Stomee 	    }
85823b5c241Stomee 
85923b5c241Stomee 	    if (mode == Mode.VERSION) {
86023b5c241Stomee 		out.printf("dtrace: %s\n", dtrace.getVersion());
86123b5c241Stomee 		dtrace.close();
86223b5c241Stomee 		exit(0);
86323b5c241Stomee 	    }
86423b5c241Stomee 
86523b5c241Stomee 	    String[] compileArgs = new String[argList.size()];
866e77b06d2Stomee 	    compileArgs = argList.toArray(compileArgs);
86723b5c241Stomee 
86823b5c241Stomee 	    Program program;
86923b5c241Stomee 	    for (CompileRequest req : compileRequests) {
87023b5c241Stomee 		switch (req.type) {
87123b5c241Stomee 		    case STRING:
87223b5c241Stomee 			applyProbespec(req);
87323b5c241Stomee 			program = dtrace.compile(req.s, compileArgs);
87423b5c241Stomee 			break;
87523b5c241Stomee 		    case FILE:
87623b5c241Stomee 			File file = new File(req.s);
87723b5c241Stomee 			program = dtrace.compile(file, compileArgs);
87823b5c241Stomee 			break;
87923b5c241Stomee 		    default:
88023b5c241Stomee 			throw new IllegalArgumentException(
88123b5c241Stomee 				"Unexpected program type: " + req.type);
88223b5c241Stomee 		}
88323b5c241Stomee 
88423b5c241Stomee 		programList.add(program);
88523b5c241Stomee 	    }
88623b5c241Stomee 
88723b5c241Stomee 	    // Get options set by #pragmas in compiled program
88823b5c241Stomee 	    long optval;
88923b5c241Stomee 	    quiet = (dtrace.getOption(Option.quiet) != Option.UNSET);
89023b5c241Stomee 	    flow = (dtrace.getOption(Option.flowindent) != Option.UNSET);
89123b5c241Stomee 	    optval = dtrace.getOption("stackindent");
89223b5c241Stomee 	    if (optval != Option.UNSET) {
89323b5c241Stomee 		stackindent = (int)optval;
89423b5c241Stomee 	    }
89523b5c241Stomee 
89623b5c241Stomee 	    if (mode == Mode.LIST) {
89723b5c241Stomee 		out.printf("%5s %10s %17s %33s %s\n",
89823b5c241Stomee 		    "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
89923b5c241Stomee 
90023b5c241Stomee 		if (verbose) {
90123b5c241Stomee 		    List <List <Probe>> lists =
90223b5c241Stomee 			    new LinkedList <List <Probe>> ();
90323b5c241Stomee 		    for (Program p : programList) {
90423b5c241Stomee 			lists.add(dtrace.listProgramProbeDetail(p));
90523b5c241Stomee 		    }
90623b5c241Stomee 		    ProbeDescription p;
90723b5c241Stomee 		    ProbeInfo pinfo;
90823b5c241Stomee 		    for (List <Probe> list : lists) {
90923b5c241Stomee 			for (Probe probe : list) {
91023b5c241Stomee 			    p = probe.getDescription();
91123b5c241Stomee 			    pinfo = probe.getInfo();
91223b5c241Stomee 			    printProbeDescription(p);
91323b5c241Stomee 			    printProbeInfo(pinfo);
91423b5c241Stomee 			}
91523b5c241Stomee 		    }
91623b5c241Stomee 		} else {
91723b5c241Stomee 		    List <List <ProbeDescription>> lists =
91823b5c241Stomee 			    new LinkedList <List <ProbeDescription>> ();
91923b5c241Stomee 		    for (Program p : programList) {
92023b5c241Stomee 			lists.add(dtrace.listProgramProbes(p));
92123b5c241Stomee 		    }
92223b5c241Stomee 		    for (List <ProbeDescription> list : lists) {
92323b5c241Stomee 			for (ProbeDescription p : list) {
92423b5c241Stomee 			    printProbeDescription(p);
92523b5c241Stomee 			}
92623b5c241Stomee 		    }
92723b5c241Stomee 		}
92823b5c241Stomee 		exit(0);
92923b5c241Stomee 	    }
93023b5c241Stomee 
93123b5c241Stomee 	    String programType;
93223b5c241Stomee 	    String programDescription;
93323b5c241Stomee 	    ProgramInfo info;
93423b5c241Stomee 	    for (Program p : programList) {
93523b5c241Stomee 		if (p instanceof Program.File) {
93623b5c241Stomee 		    Program.File pf = (Program.File)p;
93723b5c241Stomee 		    programType = "script";
93823b5c241Stomee 		    programDescription = pf.getFile().getPath();
93923b5c241Stomee 		} else {
94023b5c241Stomee 		    programType = "description";
94123b5c241Stomee 		    programDescription =
94223b5c241Stomee 			p.getContents().split("[/{;]", 2)[0];
94323b5c241Stomee 		}
94423b5c241Stomee 
94523b5c241Stomee 		if (mode == Mode.EXEC) {
94623b5c241Stomee 		    dtrace.enable(p);
94723b5c241Stomee 		} else {
94823b5c241Stomee 		    dtrace.getProgramInfo(p);
94923b5c241Stomee 		}
95023b5c241Stomee 		info = p.getInfo();
951e77b06d2Stomee 		if ((mode == Mode.EXEC) && !quiet) {
95223b5c241Stomee 		    System.err.printf("dtrace: %s '%s' matched %d probe%s\n",
95323b5c241Stomee 			    programType, programDescription,
95423b5c241Stomee 			    info.getMatchingProbeCount(),
95523b5c241Stomee 			    info.getMatchingProbeCount() == 1 ? "" : "s");
95623b5c241Stomee 		}
95723b5c241Stomee 		if (verbose) {
95823b5c241Stomee 		    printProgramStability(programType,
95923b5c241Stomee 			    programDescription, info);
96023b5c241Stomee 		}
96123b5c241Stomee 	    }
96223b5c241Stomee 	    if (mode != Mode.EXEC) {
96323b5c241Stomee 		exit(0);
96423b5c241Stomee 	    }
96523b5c241Stomee 	    dtrace.addConsumerListener(new ConsumerAdapter() {
96623b5c241Stomee 		public void consumerStarted(ConsumerEvent e) {
96723b5c241Stomee 		    started = true;
96823b5c241Stomee 		}
96923b5c241Stomee 		public void consumerStopped(ConsumerEvent e) {
97023b5c241Stomee 		    stopped = true;
97123b5c241Stomee 		    out.println();
97223b5c241Stomee 		    try {
97323b5c241Stomee 			Aggregate aggregate = dtrace.getAggregate();
97423b5c241Stomee 			if (aggregate != null) {
97523b5c241Stomee 			    printAggregate(aggregate);
97623b5c241Stomee 			}
97723b5c241Stomee 			dtrace.close();
97823b5c241Stomee 		    } catch (Throwable x) {
97923b5c241Stomee 			exceptionHandler.handleException(x);
98023b5c241Stomee 		    }
98123b5c241Stomee 		    exit(0);
98223b5c241Stomee 		}
98323b5c241Stomee 		public void dataDropped(DropEvent e) {
98423b5c241Stomee 		    System.err.printf("dtrace: %s",
98523b5c241Stomee 			    e.getDrop().getDefaultMessage());
98623b5c241Stomee 		}
98723b5c241Stomee 		public void errorEncountered(ErrorEvent e)
98823b5c241Stomee 			throws ConsumerException {
98923b5c241Stomee 		    org.opensolaris.os.dtrace.Error error = e.getError();
99023b5c241Stomee 		    if (logger.isLoggable(Level.FINE)) {
99123b5c241Stomee 			logger.fine(error.toString());
99223b5c241Stomee 		    }
99323b5c241Stomee 		    System.err.printf("dtrace: %s",
99423b5c241Stomee 			    error.getDefaultMessage());
99523b5c241Stomee 		}
99623b5c241Stomee 		public void dataReceived(DataEvent e)
99723b5c241Stomee 			throws ConsumerException {
99823b5c241Stomee 		    consumeProbeData(e.getProbeData());
99923b5c241Stomee 		}
100023b5c241Stomee 		public void processStateChanged(ProcessEvent e)
100123b5c241Stomee 			throws ConsumerException {
100223b5c241Stomee 		    if (logger.isLoggable(Level.FINE)) {
100323b5c241Stomee 			logger.fine(e.getProcessState().toString());
100423b5c241Stomee 		    }
100523b5c241Stomee 		}
100623b5c241Stomee 	    });
100723b5c241Stomee 	    // Print unprinted aggregations after Ctrl-C
100823b5c241Stomee 	    Runtime.getRuntime().addShutdownHook(new Thread() {
100923b5c241Stomee 		public void run() {
101023b5c241Stomee 		    if (stopped || !started) {
101123b5c241Stomee 			return;
101223b5c241Stomee 		    }
101323b5c241Stomee 
101423b5c241Stomee 		    try {
101523b5c241Stomee 			Aggregate aggregate = dtrace.getAggregate();
101623b5c241Stomee 			if (aggregate != null) {
101723b5c241Stomee 			    out.println();
101823b5c241Stomee 			    out.println();
101923b5c241Stomee 			    printAggregate(aggregate);
102023b5c241Stomee 			}
102123b5c241Stomee 		    } catch (Throwable x) {
102223b5c241Stomee 			exceptionHandler.handleException(x);
102323b5c241Stomee 		    }
102423b5c241Stomee 		}
102523b5c241Stomee 	    });
102623b5c241Stomee 	    dtrace.go(exceptionHandler);
102723b5c241Stomee 	} catch (DTraceException e) {
102823b5c241Stomee 	    if (c > 0) {
102923b5c241Stomee 		// set option error
103023b5c241Stomee 		if (g.getOptarg() == null) {
103123b5c241Stomee 		    System.err.printf("dtrace: failed to set -%c: %s\n",
103223b5c241Stomee 			c, e.getMessage());
103323b5c241Stomee 		} else {
103423b5c241Stomee 		    System.err.printf("dtrace: failed to set -%c %s: %s\n",
103523b5c241Stomee 			c, g.getOptarg(), e.getMessage());
103623b5c241Stomee 		}
103723b5c241Stomee 	    } else {
103823b5c241Stomee 		// any other error
103923b5c241Stomee 		System.err.printf("dtrace: %s\n", e.getMessage());
104023b5c241Stomee 	    }
104123b5c241Stomee 	    exit(1);
104223b5c241Stomee 	} catch (Exception e) {
104323b5c241Stomee 	    e.printStackTrace();
104423b5c241Stomee 	    exit(1);
104523b5c241Stomee 	}
104623b5c241Stomee     }
104723b5c241Stomee }
1048