1 /*
2  * Copyright (c) 1998, 2011, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This source code is provided to illustrate the usage of a given feature
28  * or technique and has been deliberately simplified. Additional steps
29  * required for a production-quality application, such as security checks,
30  * input validation and proper error handling, might not be present in
31  * this sample code.
32  */
33 
34 
35 package com.sun.tools.example.debug.tty;
36 
37 import com.sun.jdi.*;
38 import com.sun.jdi.request.StepRequest;
39 import com.sun.jdi.request.MethodEntryRequest;
40 import com.sun.jdi.request.MethodExitRequest;
41 import java.util.*;
42 import java.io.*;
43 
44 
45 class Env {
46 
47     static EventRequestSpecList specList = new EventRequestSpecList();
48 
49     private static VMConnection connection;
50 
51     private static SourceMapper sourceMapper = new SourceMapper("");
52     private static List<String> excludes;
53 
54     private static final int SOURCE_CACHE_SIZE = 5;
55     private static List<SourceCode> sourceCache = new LinkedList<SourceCode>();
56 
57     private static HashMap<String, Value> savedValues = new HashMap<String, Value>();
58     private static Method atExitMethod;
59 
init(String connectSpec, boolean openNow, int flags)60     static void init(String connectSpec, boolean openNow, int flags) {
61         connection = new VMConnection(connectSpec, flags);
62         if (!connection.isLaunch() || openNow) {
63             connection.open();
64         }
65     }
66 
connection()67     static VMConnection connection() {
68         return connection;
69     }
70 
vm()71     static VirtualMachine vm() {
72         return connection.vm();
73     }
74 
shutdown()75     static void shutdown() {
76         shutdown(null);
77     }
78 
shutdown(String message)79     static void shutdown(String message) {
80         if (connection != null) {
81             try {
82                 connection.disposeVM();
83             } catch (VMDisconnectedException e) {
84                 // Shutting down after the VM has gone away. This is
85                 // not an error, and we just ignore it.
86             }
87         }
88         if (message != null) {
89             MessageOutput.lnprint(message);
90             MessageOutput.println();
91         }
92         System.exit(0);
93     }
94 
setSourcePath(String srcPath)95     static void setSourcePath(String srcPath) {
96         sourceMapper = new SourceMapper(srcPath);
97         sourceCache.clear();
98     }
99 
setSourcePath(List<String> srcList)100     static void setSourcePath(List<String> srcList) {
101         sourceMapper = new SourceMapper(srcList);
102         sourceCache.clear();
103     }
104 
getSourcePath()105     static String getSourcePath() {
106         return sourceMapper.getSourcePath();
107     }
108 
excludes()109     static private List<String> excludes() {
110         if (excludes == null) {
111             setExcludes("java.*, javax.*, sun.*, com.sun.*");
112         }
113         return excludes;
114     }
115 
excludesString()116     static String excludesString() {
117         StringBuilder sb = new StringBuilder();
118         for (String pattern : excludes()) {
119             sb.append(pattern);
120             sb.append(",");
121         }
122         return sb.toString();
123     }
124 
addExcludes(StepRequest request)125     static void addExcludes(StepRequest request) {
126         for (String pattern : excludes()) {
127             request.addClassExclusionFilter(pattern);
128         }
129     }
130 
addExcludes(MethodEntryRequest request)131     static void addExcludes(MethodEntryRequest request) {
132         for (String pattern : excludes()) {
133             request.addClassExclusionFilter(pattern);
134         }
135     }
136 
addExcludes(MethodExitRequest request)137     static void addExcludes(MethodExitRequest request) {
138         for (String pattern : excludes()) {
139             request.addClassExclusionFilter(pattern);
140         }
141     }
142 
setExcludes(String excludeString)143     static void setExcludes(String excludeString) {
144         StringTokenizer t = new StringTokenizer(excludeString, " ,;");
145         List<String> list = new ArrayList<String>();
146         while (t.hasMoreTokens()) {
147             list.add(t.nextToken());
148         }
149         excludes = list;
150     }
151 
atExitMethod()152     static Method atExitMethod() {
153         return atExitMethod;
154     }
155 
setAtExitMethod(Method mmm)156     static void setAtExitMethod(Method mmm) {
157         atExitMethod = mmm;
158     }
159 
160     /**
161      * Return a Reader cooresponding to the source of this location.
162      * Return null if not available.
163      * Note: returned reader must be closed.
164      */
sourceReader(Location location)165     static BufferedReader sourceReader(Location location) {
166         return sourceMapper.sourceReader(location);
167     }
168 
sourceLine(Location location, int lineNumber)169     static synchronized String sourceLine(Location location, int lineNumber)
170                                           throws IOException {
171         if (lineNumber == -1) {
172             throw new IllegalArgumentException();
173         }
174 
175         try {
176             String fileName = location.sourceName();
177 
178             Iterator<SourceCode> iter = sourceCache.iterator();
179             SourceCode code = null;
180             while (iter.hasNext()) {
181                 SourceCode candidate = iter.next();
182                 if (candidate.fileName().equals(fileName)) {
183                     code = candidate;
184                     iter.remove();
185                     break;
186                 }
187             }
188             if (code == null) {
189                 BufferedReader reader = sourceReader(location);
190                 if (reader == null) {
191                     throw new FileNotFoundException(fileName);
192                 }
193                 code = new SourceCode(fileName, reader);
194                 if (sourceCache.size() == SOURCE_CACHE_SIZE) {
195                     sourceCache.remove(sourceCache.size() - 1);
196                 }
197             }
198             sourceCache.add(0, code);
199             return code.sourceLine(lineNumber);
200         } catch (AbsentInformationException e) {
201             throw new IllegalArgumentException();
202         }
203     }
204 
205     /** Return a description of an object. */
description(ObjectReference ref)206     static String description(ObjectReference ref) {
207         ReferenceType clazz = ref.referenceType();
208         long id = ref.uniqueID();
209         if (clazz == null) {
210             return toHex(id);
211         } else {
212             return MessageOutput.format("object description and hex id",
213                                         new Object [] {clazz.name(),
214                                                        toHex(id)});
215         }
216     }
217 
218     /** Convert a long to a hexadecimal string. */
toHex(long n)219     static String toHex(long n) {
220         char s1[] = new char[16];
221         char s2[] = new char[18];
222 
223         /* Store digits in reverse order. */
224         int i = 0;
225         do {
226             long d = n & 0xf;
227             s1[i++] = (char)((d < 10) ? ('0' + d) : ('a' + d - 10));
228         } while ((n >>>= 4) > 0);
229 
230         /* Now reverse the array. */
231         s2[0] = '0';
232         s2[1] = 'x';
233         int j = 2;
234         while (--i >= 0) {
235             s2[j++] = s1[i];
236         }
237         return new String(s2, 0, j);
238     }
239 
240     /** Convert hexadecimal strings to longs. */
fromHex(String hexStr)241     static long fromHex(String hexStr) {
242         String str = hexStr.startsWith("0x") ?
243             hexStr.substring(2).toLowerCase() : hexStr.toLowerCase();
244         if (hexStr.length() == 0) {
245             throw new NumberFormatException();
246         }
247 
248         long ret = 0;
249         for (int i = 0; i < str.length(); i++) {
250             int c = str.charAt(i);
251             if (c >= '0' && c <= '9') {
252                 ret = (ret * 16) + (c - '0');
253             } else if (c >= 'a' && c <= 'f') {
254                 ret = (ret * 16) + (c - 'a' + 10);
255             } else {
256                 throw new NumberFormatException();
257             }
258         }
259         return ret;
260     }
261 
getReferenceTypeFromToken(String idToken)262     static ReferenceType getReferenceTypeFromToken(String idToken) {
263         ReferenceType cls = null;
264         if (Character.isDigit(idToken.charAt(0))) {
265             cls = null;
266         } else if (idToken.startsWith("*.")) {
267         // This notation saves typing by letting the user omit leading
268         // package names. The first
269         // loaded class whose name matches this limited regular
270         // expression is selected.
271         idToken = idToken.substring(1);
272         for (ReferenceType type : Env.vm().allClasses()) {
273             if (type.name().endsWith(idToken)) {
274                 cls = type;
275                 break;
276             }
277         }
278     } else {
279             // It's a class name
280             List<ReferenceType> classes = Env.vm().classesByName(idToken);
281             if (classes.size() > 0) {
282                 // TO DO: handle multiples
283                 cls = classes.get(0);
284             }
285         }
286         return cls;
287     }
288 
getSaveKeys()289     static Set<String> getSaveKeys() {
290         return savedValues.keySet();
291     }
292 
getSavedValue(String key)293     static Value getSavedValue(String key) {
294         return savedValues.get(key);
295     }
296 
setSavedValue(String key, Value value)297     static void setSavedValue(String key, Value value) {
298         savedValues.put(key, value);
299     }
300 
301     static class SourceCode {
302         private String fileName;
303         private List<String> sourceLines = new ArrayList<String>();
304 
SourceCode(String fileName, BufferedReader reader)305         SourceCode(String fileName, BufferedReader reader)  throws IOException {
306             this.fileName = fileName;
307             try {
308                 String line = reader.readLine();
309                 while (line != null) {
310                     sourceLines.add(line);
311                     line = reader.readLine();
312                 }
313             } finally {
314                 reader.close();
315             }
316         }
317 
fileName()318         String fileName() {
319             return fileName;
320         }
321 
sourceLine(int number)322         String sourceLine(int number) {
323             int index = number - 1; // list is 0-indexed
324             if (index >= sourceLines.size()) {
325                 return null;
326             } else {
327                 return sourceLines.get(index);
328             }
329         }
330     }
331 }
332