128219Smsmith/* 228219Smsmith * CDDL HEADER START 328219Smsmith * 428219Smsmith * The contents of this file are subject to the terms of the 528219Smsmith * Common Development and Distribution License (the "License"). 628219Smsmith * You may not use this file except in compliance with the License. 728219Smsmith * 828219Smsmith * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 928219Smsmith * or http://www.opensolaris.org/os/licensing. 1028219Smsmith * See the License for the specific language governing permissions 1128219Smsmith * and limitations under the License. 1228219Smsmith * 1328219Smsmith * When distributing Covered Code, include this CDDL HEADER in each 1428219Smsmith * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1528219Smsmith * If applicable, add the following below this CDDL HEADER, with the 1628219Smsmith * fields enclosed by brackets "[]" replaced with your own identifying 1728219Smsmith * information: Portions Copyright [yyyy] [name of copyright owner] 1828219Smsmith * 1928219Smsmith * CDDL HEADER END 2028219Smsmith */ 2128219Smsmith 2228219Smsmith/* 2328219Smsmith * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2428219Smsmith * Use is subject to license terms. 2528219Smsmith * 2628257Smsmith * ident "%Z%%M% %I% %E% SMI" 2728219Smsmith */ 2828219Smsmithimport org.opensolaris.os.dtrace.*; 2928219Smsmithimport java.io.*; 3028219Smsmithimport java.util.*; 3128219Smsmithimport java.util.logging.*; 3228219Smsmith 3328257Smsmith/** 3428257Smsmith * Emulates {@code dtrace(1M)} using the Java DTrace API. 3528257Smsmith */ 3628257Smsmithpublic class JDTrace { 3728257Smsmith static Logger logger = Logger.getLogger(JDTrace.class.getName()); 3828219Smsmith 3928219Smsmith static Consumer dtrace; 4028219Smsmith 4128219Smsmith static { 4228219Smsmith Handler handler = new ConsoleHandler(); 4328219Smsmith handler.setLevel(Level.ALL); 4428219Smsmith logger.addHandler(handler); 4528219Smsmith } 4628219Smsmith 4728219Smsmith static final String CLASSNAME = "JDTrace"; 4828219Smsmith static final String OPTSTR = 4928219Smsmith "3:6:b:c:CD:ef:Fi:I:lL:m:n:o:p:P:qs:U:vVwx:X:Z"; 5028219Smsmith static boolean heading = false; 5128219Smsmith static boolean quiet = false; 5228219Smsmith static boolean flow = false; 5328219Smsmith static int stackindent = 14; 5428219Smsmith static int exitStatus = 0; 5528219Smsmith static boolean started; 5628219Smsmith static boolean stopped; 5728219Smsmith static PrintStream out = System.out; 5828219Smsmith static final String ATS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"; 5928219Smsmith static final String SPACES = " "; 6028219Smsmith static final int QUANTIZE_ZERO_BUCKET = 63; 6128219Smsmith 6228219Smsmith enum Mode { 6328219Smsmith EXEC, 6428219Smsmith INFO, 6528219Smsmith LIST, 6628219Smsmith VERSION 6728219Smsmith } 6828219Smsmith 6928219Smsmith enum ProgramType { 7028219Smsmith STRING, 7128219Smsmith FILE 7228219Smsmith } 7328219Smsmith 7428219Smsmith static class CompileRequest { 7528219Smsmith String s; 7628219Smsmith ProgramType type; 7728219Smsmith ProbeDescription.Spec probespec; 7828219Smsmith } 7928219Smsmith 8028219Smsmith // Modify program string by expanding an incomplete probe 8128219Smsmith // description according to the requested probespec. 8228219Smsmith static void 8328219Smsmith applyProbespec(CompileRequest req) 8428219Smsmith { 8528219Smsmith ProbeDescription.Spec spec = ((req.probespec == null) 8628219Smsmith ? ProbeDescription.Spec.NAME 8728219Smsmith : req.probespec); 8828219Smsmith 8928219Smsmith int colons = 0; 9028219Smsmith switch (req.probespec) { 9128219Smsmith case PROVIDER: 9228219Smsmith colons = 3; 9328219Smsmith break; 9428219Smsmith case MODULE: 9528219Smsmith colons = 2; 9628219Smsmith break; 9728219Smsmith case FUNCTION: 9828219Smsmith colons = 1; 9928219Smsmith break; 10028219Smsmith } 10128219Smsmith 10228219Smsmith StringBuffer buf = new StringBuffer(); 10328219Smsmith if (colons > 0) { 10428219Smsmith char ch; 10528219Smsmith int len = req.s.length(); 10628219Smsmith 10728219Smsmith int i = 0; 10828219Smsmith // Find first whitespace character not including leading 10928219Smsmith // whitespace (end of first token). Ignore whitespace 11028219Smsmith // inside a block if the block is concatenated with the 11128219Smsmith // probe description. 11228219Smsmith for (; (i < len) && Character.isWhitespace(req.s.charAt(i)); ++i); 11328219Smsmith int npos = i; 11428219Smsmith boolean inBlock = false; 11528219Smsmith for (; (npos < len) && 11628219Smsmith (!Character.isWhitespace(ch = req.s.charAt(npos)) || 11728219Smsmith inBlock); ++npos) { 11828219Smsmith if (ch == '{') { 11928219Smsmith inBlock = true; 12028219Smsmith } else if (ch == '}') { 12128219Smsmith inBlock = false; 12228219Smsmith } 12328219Smsmith } 12428219Smsmith 12528219Smsmith // libdtrace lets you concatenate multiple probe 12628219Smsmith // descriptions separated by code blocks in curly braces, 12728219Smsmith // for example genunix::'{printf("FOUND");}'::entry, as long 12828219Smsmith // as the concatenated probe descriptions begin with ':' and 12928219Smsmith // not a specific field such as 'syscall'. So to expand the 13028219Smsmith // possibly multiple probe descriptions, we need to insert 13128219Smsmith // colons before each open curly brace, and again at the end 13228219Smsmith // only if there is at least one non-whitespace (probe 13328219Smsmith // specifying) character after the last closing curly brace. 13428219Smsmith 13528219Smsmith int prev_i = 0; 13628219Smsmith while (i < npos) { 13728219Smsmith for (; (i < npos) && (req.s.charAt(i) != '{'); ++i); 13828219Smsmith buf.append(req.s.substring(prev_i, i)); 13928219Smsmith if ((i < npos) || ((i > 0) && (req.s.charAt(i - 1) != '}'))) { 14028219Smsmith for (int c = 0; c < colons; ++c) { 14128219Smsmith buf.append(':'); 14228219Smsmith } 14328219Smsmith } 14428219Smsmith if (i < npos) { 14528219Smsmith buf.append(req.s.charAt(i++)); 14628219Smsmith } 14728219Smsmith prev_i = i; 14828257Smsmith } 14928219Smsmith 15028219Smsmith // append remainder of program text 15128219Smsmith buf.append(req.s.substring(i)); 15228219Smsmith 15328219Smsmith req.s = buf.toString(); 15428219Smsmith } 15528219Smsmith } 15628219Smsmith 15728219Smsmith static void 15828219Smsmith printValue(Object value, int bytes, String stringFormat) 15928219Smsmith { 16028219Smsmith if (value instanceof Integer) { 16128219Smsmith if (bytes == 1) { 16228257Smsmith out.printf(" %3d", (Integer)value); 16328257Smsmith } else if (bytes == 2) { 16428257Smsmith out.printf(" %5d", (Integer)value); 16528257Smsmith } else { 16628257Smsmith out.printf(" %8d", (Integer)value); 16728219Smsmith } 16828219Smsmith } else if (value instanceof Long) { 16928219Smsmith out.printf(" %16d", (Long)value); 17028219Smsmith } else { 17128257Smsmith out.printf(stringFormat, value.toString()); 17228257Smsmith } 17328257Smsmith } 17428257Smsmith 17528257Smsmith static void 17628257Smsmith consumeProbeData(ProbeData data) 17728257Smsmith { 17828257Smsmith if (logger.isLoggable(Level.FINER)) { 17928257Smsmith logger.finer(data.toString()); 18028257Smsmith } 18128257Smsmith 18228257Smsmith if (!heading) { 18328257Smsmith if (flow) { 18428219Smsmith out.printf("%3s %-41s\n", "CPU", "FUNCTION"); 18528219Smsmith } else { 18628219Smsmith if (!quiet) { 18728219Smsmith out.printf("%3s %6s %32s\n", 18828219Smsmith "CPU", "ID", "FUNCTION:NAME"); 18928219Smsmith } 19028219Smsmith } 19128219Smsmith heading = true; 19228219Smsmith } 19328219Smsmith ProbeDescription probe = data.getEnabledProbeDescription(); 19428219Smsmith if (flow) { 19528219Smsmith Flow flow = data.getFlow(); 19628219Smsmith int indent = (flow.getDepth() * 2); 19728219Smsmith StringBuffer buf = new StringBuffer(); 19828219Smsmith // indent 19928219Smsmith buf.append(' '); 20028219Smsmith for (int i = 0; i < indent; ++i) { 20128219Smsmith buf.append(' '); 20228219Smsmith } 20328257Smsmith // prefix 20428257Smsmith switch (flow.getKind()) { 20528257Smsmith case ENTRY: 20628257Smsmith if (indent == 0) { 20728257Smsmith buf.append("=> "); 20828219Smsmith } else { 20928257Smsmith buf.append("-> "); 21028219Smsmith } 21128219Smsmith break; 21228257Smsmith case RETURN: 21328219Smsmith if (indent == 0) { 21428219Smsmith buf.append("<= "); 21528257Smsmith } else { 21628257Smsmith buf.append("<- "); 21728219Smsmith } 21828219Smsmith break; 21928219Smsmith } 22028219Smsmith 22128219Smsmith switch (flow.getKind()) { 22228219Smsmith case NONE: 22328219Smsmith buf.append(probe.getFunction()); 22428219Smsmith buf.append(':'); 22528219Smsmith buf.append(probe.getName()); 22628219Smsmith break; 22728219Smsmith default: 22828219Smsmith buf.append(probe.getFunction()); 22928219Smsmith } 23028219Smsmith 23128219Smsmith out.printf("%3s %-41s ", data.getCPU(), 23228219Smsmith buf.toString()); 23328219Smsmith } else { 23428219Smsmith if (!quiet) { 23528219Smsmith StringBuffer buf = new StringBuffer(); 23628219Smsmith buf.append(probe.getFunction()); 23728219Smsmith buf.append(':'); 23828219Smsmith buf.append(probe.getName()); 23928219Smsmith out.printf("%3s %6s %32s ", 24028219Smsmith data.getCPU(), probe.getID(), 24128219Smsmith buf.toString()); 24228219Smsmith } 24328219Smsmith } 24428219Smsmith Record record = null; 24528219Smsmith Object value; 24628219Smsmith List <Record> records = data.getRecords(); 24728219Smsmith Iterator <Record> itr = records.iterator(); 24828219Smsmith while (itr.hasNext()) { 24928219Smsmith record = itr.next(); 25028219Smsmith 25128219Smsmith if (record instanceof ExitRecord) { 25228219Smsmith exitStatus = ((ExitRecord)record).getStatus(); 25328219Smsmith } else if (record instanceof ScalarRecord) { 25428219Smsmith ScalarRecord scalar = (ScalarRecord)record; 25528219Smsmith value = scalar.getValue(); 25628219Smsmith if (value instanceof byte[]) { 25728219Smsmith out.print(record.toString()); 25828219Smsmith } else { 25928219Smsmith if (quiet) { 26028219Smsmith out.print(value); 26128219Smsmith } else { 26228219Smsmith printValue(value, scalar.getNumberOfBytes(), 26328219Smsmith " %-33s"); 26428219Smsmith } 26528219Smsmith } 26628219Smsmith } else if (record instanceof PrintfRecord) { 26728219Smsmith out.print(record); 26828219Smsmith } else if (record instanceof PrintaRecord) { 26928219Smsmith PrintaRecord printa = (PrintaRecord)record; 27028219Smsmith List <Tuple> tuples = printa.getTuples(); 27128219Smsmith if (tuples.isEmpty()) { 27228219Smsmith 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} 1043