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