1 /*
   2  * Copyright (c) 2002, 2013, 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.jcore;
  26 
  27 import java.io.*;
  28 import java.lang.reflect.Constructor;
  29 import java.util.jar.JarOutputStream;
  30 import java.util.jar.JarEntry;
  31 import java.util.jar.Manifest;
  32 import sun.jvm.hotspot.memory.*;
  33 import sun.jvm.hotspot.oops.*;
  34 import sun.jvm.hotspot.debugger.*;
  35 import sun.jvm.hotspot.runtime.*;
  36 import sun.jvm.hotspot.tools.*;
  37 
  38 public class ClassDump extends Tool {
  39     private ClassFilter classFilter;
  40     private String      outputDirectory;
  41     private JarOutputStream jarStream;
  42     private String      pkgList;
  43 
  44     public ClassDump() {
  45         super();
  46     }
  47 
  48     public ClassDump(JVMDebugger d, String pkgList) {
  49         super(d);
  50         this.pkgList = pkgList;
  51     }
  52 
  53     public void setClassFilter(ClassFilter cf) {
  54         classFilter = cf;
  55     }
  56 
  57     public void setOutputDirectory(String od) {
  58         outputDirectory = od;
  59         if (jarStream != null) {
  60             try {
  61                 jarStream.close();
  62             } catch (IOException ioe) {
  63                 ioe.printStackTrace();
  64             }
  65         }
  66         jarStream = null;
  67     }
  68 
  69     public void setJarOutput(String jarFileName) throws IOException {
  70         jarStream = new JarOutputStream(new FileOutputStream(jarFileName), new Manifest());
  71         outputDirectory = null;
  72     }
  73 
  74     public void run() {
  75         // Ready to go with the database...
  76         try {
  77             if (classFilter == null) {
  78                 // If not already set, the name of the filter comes from a System property.
  79                 // If we have a pkgList, pass it, otherwise let the filter read
  80                 // its own System property for the list of classes.
  81                 String filterClassName = System.getProperty("sun.jvm.hotspot.tools.jcore.filter",
  82                                                             "sun.jvm.hotspot.tools.jcore.PackageNameFilter");
  83                 try {
  84                     Class filterClass = Class.forName(filterClassName);
  85                     if (pkgList == null) {
  86                         classFilter = (ClassFilter) filterClass.newInstance();
  87                     } else {
  88                         Constructor con = filterClass.getConstructor(String.class);
  89                         classFilter = (ClassFilter) con.newInstance(pkgList);
  90                     }
  91                 } catch(Exception exp) {
  92                     System.err.println("Warning: Can not create class filter!");
  93                 }
  94             }
  95 
  96             // outputDirectory and jarStream are alternatives: setting one closes the other.
  97             // If neither is set, use outputDirectory from the System property:
  98             if (outputDirectory == null && jarStream == null) {
  99                 String dirName = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", ".");
 100                 setOutputDirectory(dirName);
 101             }
 102       
 103             // walk through the system dictionary
 104             SystemDictionary dict = VM.getVM().getSystemDictionary();
 105             dict.classesDo(new SystemDictionary.ClassVisitor() {
 106                     public void visit(Klass k) {
 107                         if (k instanceof InstanceKlass) {
 108                             try {
 109                                 dumpKlass((InstanceKlass) k);
 110                             } catch (Exception e) {
 111                                 System.out.println(k.getName().asString());
 112                                 e.printStackTrace();
 113                             }
 114                         }
 115                     }
 116                 });
 117         }
 118         catch (AddressException e) {
 119             System.err.println("Error accessing address 0x"
 120                                + Long.toHexString(e.getAddress()));
 121             e.printStackTrace();
 122         }
 123         if (jarStream != null) {
 124             try {
 125                 jarStream.close();
 126             } catch (IOException ioe) {
 127                 ioe.printStackTrace();
 128             }
 129             jarStream = null;
 130         }
 131     }
 132 
 133     public String getName() {
 134         return "jcore";
 135     }
 136 
 137     private void dumpKlass(InstanceKlass kls) {
 138         if (classFilter != null && ! classFilter.canInclude(kls) ) {
 139             return;
 140         }
 141 
 142         String klassName = kls.getName().asString();
 143         klassName = klassName.replace('/', File.separatorChar);
 144         try {
 145             OutputStream os = null;
 146             if (jarStream != null) {
 147                 jarStream.putNextEntry(new JarEntry(klassName + ".class"));
 148                 os = jarStream;
 149             } else {
 150                 int index = klassName.lastIndexOf(File.separatorChar);
 151                 File dir = null;
 152                 if (index != -1) {
 153                     String dirName = klassName.substring(0, index);
 154                     dir = new File(outputDirectory,  dirName);
 155                 } else {
 156                     dir = new File(outputDirectory);
 157                 }
 158 
 159                 dir.mkdirs();
 160                 File f = new File(dir, klassName.substring(index + 1) + ".class");
 161                 f.createNewFile();
 162                 os = new BufferedOutputStream(new FileOutputStream(f));
 163             }
 164             try {
 165                 ClassWriter cw = new ClassWriter(kls, os);
 166                 cw.write();
 167             } finally {
 168                 if (os != jarStream) {
 169                     os.close();
 170                 }
 171             }
 172         } catch(IOException exp) {
 173             exp.printStackTrace();
 174         }
 175     }
 176 
 177     public static void main(String[] args) {
 178 
 179         ClassDump cd = new ClassDump();
 180         cd.start(args);
 181         cd.stop();
 182     }
 183 }