1 /*
   2  * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.tools;
  26 
  27 import java.io.PrintStream;
  28 import java.util.Hashtable;
  29 
  30 import sun.jvm.hotspot.*;
  31 import sun.jvm.hotspot.runtime.*;
  32 import sun.jvm.hotspot.debugger.*;
  33 
  34 // generic command line or GUI tool.
  35 // override run & code main as shown below.
  36 
  37 public abstract class Tool implements Runnable {
  38    private HotSpotAgent agent;
  39    private JVMDebugger jvmDebugger;
  40    private int debugeeType;
  41 
  42    // debugeeType is one of constants below
  43    protected static final int DEBUGEE_PID    = 0;
  44    protected static final int DEBUGEE_CORE   = 1;
  45    protected static final int DEBUGEE_REMOTE = 2;
  46 
  47    public Tool() {
  48    }
  49 
  50    public Tool(JVMDebugger d) {
  51       jvmDebugger = d;
  52    }
  53 
  54    public String getName() {
  55       return getClass().getName();
  56    }
  57 
  58    protected boolean needsJavaPrefix() {
  59       return true;
  60    }
  61 
  62    protected void setAgent(HotSpotAgent a) {
  63       agent = a;
  64    }
  65 
  66    protected void setDebugeeType(int dt) {
  67       debugeeType = dt;
  68    }
  69 
  70    protected HotSpotAgent getAgent() {
  71       return agent;
  72    }
  73 
  74    protected int getDebugeeType() {
  75       return debugeeType;
  76    }
  77 
  78    protected void printUsage() {
  79       String name = null;
  80       if (needsJavaPrefix()) {
  81          name = "java " + getName();
  82       } else {
  83          name = getName();
  84       }
  85       System.out.println("Usage: " + name + " [option] <pid>");
  86       System.out.println("\t\t(to connect to a live java process)");
  87       System.out.println("   or " + name + " [option] <executable> <core>");
  88       System.out.println("\t\t(to connect to a core file)");
  89       System.out.println("   or " + name + " [option] [server_id@]<remote server IP or hostname>");
  90       System.out.println("\t\t(to connect to a remote debug server)");
  91       System.out.println();
  92       System.out.println("where option must be one of:");
  93       printFlagsUsage();
  94    }
  95 
  96    protected void printFlagsUsage() {
  97        System.out.println("    -h | -help\tto print this help message");
  98    }
  99 
 100    protected void usage() {
 101       printUsage();
 102    }
 103 
 104    /*
 105       Derived class main should be of the following form:
 106 
 107       public static void main(String[] args) {
 108          <derived class> obj = new <derived class>;
 109          obj.execute(args);
 110       }
 111 
 112    */
 113 
 114    protected void execute(String[] args) {
 115        int returnStatus = 1;
 116 
 117        try {
 118            returnStatus = start(args);
 119        } finally {
 120            stop();
 121        }
 122 
 123        // Exit with 0 or 1
 124        System.exit(returnStatus);
 125    }
 126 
 127    public void stop() {
 128       if (agent != null) {
 129          agent.detach();
 130       }
 131    }
 132 
 133    private int start(String[] args) {
 134 
 135       if ((args.length < 1) || (args.length > 2)) {
 136          usage();
 137          return 1;
 138       }
 139 
 140       // Attempt to handle -h or -help or some invalid flag
 141       if (args[0].startsWith("-h")) {
 142           usage();
 143           return 0;
 144       } else if (args[0].startsWith("-")) {
 145           usage();
 146           return 1;
 147       }
 148 
 149       PrintStream err = System.err;
 150 
 151       int pid = 0;
 152       String coreFileName   = null;
 153       String executableName = null;
 154       String remoteServer   = null;
 155 
 156       switch (args.length) {
 157         case 1:
 158            try {
 159               pid = Integer.parseInt(args[0]);
 160               debugeeType = DEBUGEE_PID;
 161            } catch (NumberFormatException e) {
 162               // try remote server
 163               remoteServer = args[0];
 164               debugeeType  = DEBUGEE_REMOTE;
 165            }
 166            break;
 167 
 168         case 2:
 169            executableName = args[0];
 170            coreFileName   = args[1];
 171            debugeeType    = DEBUGEE_CORE;
 172            break;
 173 
 174         default:
 175            usage();
 176            return 1;
 177       }
 178 
 179       agent = new HotSpotAgent();
 180       try {
 181         switch (debugeeType) {
 182           case DEBUGEE_PID:
 183              err.println("Attaching to process ID " + pid + ", please wait...");
 184              agent.attach(pid);
 185              break;
 186 
 187           case DEBUGEE_CORE:
 188              err.println("Attaching to core " + coreFileName +
 189                          " from executable " + executableName + ", please wait...");
 190              agent.attach(executableName, coreFileName);
 191              break;
 192 
 193           case DEBUGEE_REMOTE:
 194              err.println("Attaching to remote server " + remoteServer + ", please wait...");
 195              agent.attach(remoteServer);
 196              break;
 197         }
 198       }
 199       catch (DebuggerException e) {
 200         switch (debugeeType) {
 201           case DEBUGEE_PID:
 202              err.print("Error attaching to process: ");
 203              break;
 204 
 205           case DEBUGEE_CORE:
 206              err.print("Error attaching to core file: ");
 207              break;
 208 
 209           case DEBUGEE_REMOTE:
 210              err.print("Error attaching to remote server: ");
 211              break;
 212         }
 213         if (e.getMessage() != null) {
 214           err.println(e.getMessage());
 215           e.printStackTrace();
 216         }
 217         err.println();
 218         return 1;
 219       }
 220 
 221       err.println("Debugger attached successfully.");
 222       startInternal();
 223       return 0;
 224    }
 225 
 226    // When using an existing JVMDebugger.
 227    public void start() {
 228 
 229       if (jvmDebugger == null) {
 230          throw new RuntimeException("Tool.start() called with no JVMDebugger set.");
 231       }
 232       agent = new HotSpotAgent();
 233       agent.attach(jvmDebugger);
 234       startInternal();
 235    }
 236 
 237    // Remains of the start mechanism, common to both start methods.
 238    private void startInternal() {
 239 
 240       PrintStream err = System.err;
 241       VM vm = VM.getVM();
 242       if (vm.isCore()) {
 243         err.println("Core build detected.");
 244       } else if (vm.isClientCompiler()) {
 245         err.println("Client compiler detected.");
 246       } else if (vm.isServerCompiler()) {
 247         err.println("Server compiler detected.");
 248       } else {
 249         throw new RuntimeException("Fatal error: "
 250             + "should have been able to detect core/C1/C2 build");
 251       }
 252 
 253       String version = vm.getVMRelease();
 254       if (version != null) {
 255         err.print("JVM version is ");
 256         err.println(version);
 257       }
 258 
 259       run();
 260    }
 261 }