0N/A/*
2362N/A * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
4378N/A/*
4378N/A * This source code is provided to illustrate the usage of a given feature
4378N/A * or technique and has been deliberately simplified. Additional steps
4378N/A * required for a production-quality application, such as security checks,
4378N/A * input validation and proper error handling, might not be present in
4378N/A * this sample code.
4378N/A */
4378N/A
4378N/A
0N/Apackage com.sun.tools.example.trace;
0N/A
0N/Aimport com.sun.jdi.VirtualMachine;
0N/Aimport com.sun.jdi.Bootstrap;
0N/Aimport com.sun.jdi.connect.*;
0N/A
0N/Aimport java.util.Map;
0N/Aimport java.util.List;
0N/A
0N/Aimport java.io.PrintWriter;
0N/Aimport java.io.FileWriter;
0N/Aimport java.io.IOException;
0N/A
0N/A/**
0N/A * This program traces the execution of another program.
0N/A * See "java Trace -help".
0N/A * It is a simple example of the use of the Java Debug Interface.
0N/A *
0N/A * @author Robert Field
0N/A */
0N/Apublic class Trace {
0N/A
0N/A // Running remote VM
0N/A private final VirtualMachine vm;
0N/A
0N/A // Thread transferring remote error stream to our error stream
0N/A private Thread errThread = null;
0N/A
0N/A // Thread transferring remote output stream to our output stream
0N/A private Thread outThread = null;
0N/A
0N/A // Mode for tracing the Trace program (default= 0 off)
0N/A private int debugTraceMode = 0;
0N/A
0N/A // Do we want to watch assignments to fields
0N/A private boolean watchFields = false;
0N/A
0N/A // Class patterns for which we don't want events
0N/A private String[] excludes = {"java.*", "javax.*", "sun.*",
0N/A "com.sun.*"};
0N/A
0N/A /**
0N/A * main
0N/A */
0N/A public static void main(String[] args) {
0N/A new Trace(args);
0N/A }
0N/A
0N/A /**
0N/A * Parse the command line arguments.
0N/A * Launch target VM.
0N/A * Generate the trace.
0N/A */
0N/A Trace(String[] args) {
0N/A PrintWriter writer = new PrintWriter(System.out);
0N/A int inx;
0N/A for (inx = 0; inx < args.length; ++inx) {
0N/A String arg = args[inx];
0N/A if (arg.charAt(0) != '-') {
0N/A break;
0N/A }
0N/A if (arg.equals("-output")) {
0N/A try {
0N/A writer = new PrintWriter(new FileWriter(args[++inx]));
0N/A } catch (IOException exc) {
0N/A System.err.println("Cannot open output file: " + args[inx]
0N/A + " - " + exc);
0N/A System.exit(1);
0N/A }
0N/A } else if (arg.equals("-all")) {
0N/A excludes = new String[0];
0N/A } else if (arg.equals("-fields")) {
0N/A watchFields = true;
0N/A } else if (arg.equals("-dbgtrace")) {
0N/A debugTraceMode = Integer.parseInt(args[++inx]);
0N/A } else if (arg.equals("-help")) {
0N/A usage();
0N/A System.exit(0);
0N/A } else {
0N/A System.err.println("No option: " + arg);
0N/A usage();
0N/A System.exit(1);
0N/A }
0N/A }
0N/A if (inx >= args.length) {
0N/A System.err.println("<class> missing");
0N/A usage();
0N/A System.exit(1);
0N/A }
0N/A StringBuffer sb = new StringBuffer();
0N/A sb.append(args[inx]);
0N/A for (++inx; inx < args.length; ++inx) {
0N/A sb.append(' ');
0N/A sb.append(args[inx]);
0N/A }
0N/A vm = launchTarget(sb.toString());
0N/A generateTrace(writer);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Generate the trace.
0N/A * Enable events, start thread to display events,
0N/A * start threads to forward remote error and output streams,
0N/A * resume the remote VM, wait for the final event, and shutdown.
0N/A */
0N/A void generateTrace(PrintWriter writer) {
0N/A vm.setDebugTraceMode(debugTraceMode);
0N/A EventThread eventThread = new EventThread(vm, excludes, writer);
0N/A eventThread.setEventRequests(watchFields);
0N/A eventThread.start();
0N/A redirectOutput();
0N/A vm.resume();
0N/A
0N/A // Shutdown begins when event thread terminates
0N/A try {
0N/A eventThread.join();
0N/A errThread.join(); // Make sure output is forwarded
0N/A outThread.join(); // before we exit
0N/A } catch (InterruptedException exc) {
0N/A // we don't interrupt
0N/A }
0N/A writer.close();
0N/A }
0N/A
0N/A /**
0N/A * Launch target VM.
0N/A * Forward target's output and error.
0N/A */
0N/A VirtualMachine launchTarget(String mainArgs) {
0N/A LaunchingConnector connector = findLaunchingConnector();
4123N/A Map<String, Connector.Argument> arguments =
4123N/A connectorArguments(connector, mainArgs);
0N/A try {
0N/A return connector.launch(arguments);
0N/A } catch (IOException exc) {
0N/A throw new Error("Unable to launch target VM: " + exc);
0N/A } catch (IllegalConnectorArgumentsException exc) {
0N/A throw new Error("Internal error: " + exc);
0N/A } catch (VMStartException exc) {
0N/A throw new Error("Target VM failed to initialize: " +
0N/A exc.getMessage());
0N/A }
0N/A }
0N/A
0N/A void redirectOutput() {
0N/A Process process = vm.process();
0N/A
0N/A // Copy target's output and error to our output and error.
0N/A errThread = new StreamRedirectThread("error reader",
0N/A process.getErrorStream(),
0N/A System.err);
0N/A outThread = new StreamRedirectThread("output reader",
0N/A process.getInputStream(),
0N/A System.out);
0N/A errThread.start();
0N/A outThread.start();
0N/A }
0N/A
0N/A /**
0N/A * Find a com.sun.jdi.CommandLineLaunch connector
0N/A */
0N/A LaunchingConnector findLaunchingConnector() {
4123N/A List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors();
4123N/A for (Connector connector : connectors) {
0N/A if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) {
0N/A return (LaunchingConnector)connector;
0N/A }
0N/A }
0N/A throw new Error("No launching connector");
0N/A }
0N/A
0N/A /**
0N/A * Return the launching connector's arguments.
0N/A */
4123N/A Map<String, Connector.Argument> connectorArguments(LaunchingConnector connector, String mainArgs) {
4123N/A Map<String, Connector.Argument> arguments = connector.defaultArguments();
0N/A Connector.Argument mainArg =
0N/A (Connector.Argument)arguments.get("main");
0N/A if (mainArg == null) {
0N/A throw new Error("Bad launching connector");
0N/A }
0N/A mainArg.setValue(mainArgs);
0N/A
0N/A if (watchFields) {
0N/A // We need a VM that supports watchpoints
0N/A Connector.Argument optionArg =
0N/A (Connector.Argument)arguments.get("options");
0N/A if (optionArg == null) {
0N/A throw new Error("Bad launching connector");
0N/A }
0N/A optionArg.setValue("-classic");
0N/A }
0N/A return arguments;
0N/A }
0N/A
0N/A /**
0N/A * Print command line usage help
0N/A */
0N/A void usage() {
0N/A System.err.println("Usage: java Trace <options> <class> <args>");
0N/A System.err.println("<options> are:");
0N/A System.err.println(
0N/A" -output <filename> Output trace to <filename>");
0N/A System.err.println(
0N/A" -all Include system classes in output");
0N/A System.err.println(
0N/A" -help Print this help message");
0N/A System.err.println("<class> is the program to trace");
0N/A System.err.println("<args> are the arguments to <class>");
0N/A }
0N/A}