1 /*
2  * Copyright (c) 1998, 2019, 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 
setTraceFlags(int flags)67     static void setTraceFlags(int flags) {
68         connection.setTraceFlags(flags);
69     }
70 
connection()71     static VMConnection connection() {
72         return connection;
73     }
74 
vm()75     static VirtualMachine vm() {
76         return connection.vm();
77     }
78 
shutdown()79     static void shutdown() {
80         shutdown(null);
81     }
82 
shutdown(String message)83     static void shutdown(String message) {
84         if (connection != null) {
85             try {
86                 connection.disposeVM();
87             } catch (VMDisconnectedException e) {
88                 // Shutting down after the VM has gone away. This is
89                 // not an error, and we just ignore it.
90             }
91         }
92         if (message != null) {
93             MessageOutput.lnprint(message);
94             MessageOutput.println();
95         }
96         System.exit(0);
97     }
98 
setSourcePath(String srcPath)99     static void setSourcePath(String srcPath) {
100         sourceMapper = new SourceMapper(srcPath);
101         sourceCache.clear();
102     }
103 
setSourcePath(List<String> srcList)104     static void setSourcePath(List<String> srcList) {
105         sourceMapper = new SourceMapper(srcList);
106         sourceCache.clear();
107     }
108 
getSourcePath()109     static String getSourcePath() {
110         return sourceMapper.getSourcePath();
111     }
112 
excludes()113     static private List<String> excludes() {
114         if (excludes == null) {
115             setExcludes("java.*, javax.*, sun.*, com.sun.*, jdk.*");
116         }
117         return excludes;
118     }
119 
excludesString()120     static String excludesString() {
121         StringBuilder sb = new StringBuilder();
122         for (String pattern : excludes()) {
123             sb.append(pattern);
124             sb.append(",");
125         }
126         return sb.toString();
127     }
128 
addExcludes(StepRequest request)129     static void addExcludes(StepRequest request) {
130         for (String pattern : excludes()) {
131             request.addClassExclusionFilter(pattern);
132         }
133     }
134 
addExcludes(MethodEntryRequest request)135     static void addExcludes(MethodEntryRequest request) {
136         for (String pattern : excludes()) {
137             request.addClassExclusionFilter(pattern);
138         }
139     }
140 
addExcludes(MethodExitRequest request)141     static void addExcludes(MethodExitRequest request) {
142         for (String pattern : excludes()) {
143             request.addClassExclusionFilter(pattern);
144         }
145     }
146 
setExcludes(String excludeString)147     static void setExcludes(String excludeString) {
148         StringTokenizer t = new StringTokenizer(excludeString, " ,;");
149         List<String> list = new ArrayList<String>();
150         while (t.hasMoreTokens()) {
151             list.add(t.nextToken());
152         }
153         excludes = list;
154     }
155 
atExitMethod()156     static Method atExitMethod() {
157         return atExitMethod;
158     }
159 
setAtExitMethod(Method mmm)160     static void setAtExitMethod(Method mmm) {
161         atExitMethod = mmm;
162     }
163 
164     /**
165      * Return a Reader cooresponding to the source of this location.
166      * Return null if not available.
167      * Note: returned reader must be closed.
168      */
sourceReader(Location location)169     static BufferedReader sourceReader(Location location) {
170         return sourceMapper.sourceReader(location);
171     }
172 
sourceLine(Location location, int lineNumber)173     static synchronized String sourceLine(Location location, int lineNumber)
174                                           throws IOException {
175         if (lineNumber == -1) {
176             throw new IllegalArgumentException();
177         }
178 
179         try {
180             String fileName = location.sourceName();
181 
182             Iterator<SourceCode> iter = sourceCache.iterator();
183             SourceCode code = null;
184             while (iter.hasNext()) {
185                 SourceCode candidate = iter.next();
186                 if (candidate.fileName().equals(fileName)) {
187                     code = candidate;
188                     iter.remove();
189                     break;
190                 }
191             }
192             if (code == null) {
193                 BufferedReader reader = sourceReader(location);
194                 if (reader == null) {
195                     throw new FileNotFoundException(fileName);
196                 }
197                 code = new SourceCode(fileName, reader);
198                 if (sourceCache.size() == SOURCE_CACHE_SIZE) {
199                     sourceCache.remove(sourceCache.size() - 1);
200                 }
201             }
202             sourceCache.add(0, code);
203             return code.sourceLine(lineNumber);
204         } catch (AbsentInformationException e) {
205             throw new IllegalArgumentException();
206         }
207     }
208 
209     /** Return a description of an object. */
description(ObjectReference ref)210     static String description(ObjectReference ref) {
211         ReferenceType clazz = ref.referenceType();
212         long id = ref.uniqueID();
213         if (clazz == null) {
214             return Long.toString(id);
215         } else {
216             return MessageOutput.format("object description and id",
217                                         new Object [] {clazz.name(),
218                                                        Long.toString(id)});
219         }
220     }
221 
getReferenceTypeFromToken(String idToken)222     static ReferenceType getReferenceTypeFromToken(String idToken) {
223         ReferenceType cls = null;
224         if (Character.isDigit(idToken.charAt(0))) {
225             cls = null;
226         } else if (idToken.startsWith("*.")) {
227         // This notation saves typing by letting the user omit leading
228         // package names. The first
229         // loaded class whose name matches this limited regular
230         // expression is selected.
231         idToken = idToken.substring(1);
232         for (ReferenceType type : Env.vm().allClasses()) {
233             if (type.name().endsWith(idToken)) {
234                 cls = type;
235                 break;
236             }
237         }
238     } else {
239             // It's a class name
240             List<ReferenceType> classes = Env.vm().classesByName(idToken);
241             if (classes.size() > 0) {
242                 // TO DO: handle multiples
243                 cls = classes.get(0);
244             }
245         }
246         return cls;
247     }
248 
getSaveKeys()249     static Set<String> getSaveKeys() {
250         return savedValues.keySet();
251     }
252 
getSavedValue(String key)253     static Value getSavedValue(String key) {
254         return savedValues.get(key);
255     }
256 
setSavedValue(String key, Value value)257     static void setSavedValue(String key, Value value) {
258         savedValues.put(key, value);
259     }
260 
261     static class SourceCode {
262         private String fileName;
263         private List<String> sourceLines = new ArrayList<String>();
264 
SourceCode(String fileName, BufferedReader reader)265         SourceCode(String fileName, BufferedReader reader)  throws IOException {
266             this.fileName = fileName;
267             try {
268                 String line = reader.readLine();
269                 while (line != null) {
270                     sourceLines.add(line);
271                     line = reader.readLine();
272                 }
273             } finally {
274                 reader.close();
275             }
276         }
277 
fileName()278         String fileName() {
279             return fileName;
280         }
281 
sourceLine(int number)282         String sourceLine(int number) {
283             int index = number - 1; // list is 0-indexed
284             if (index >= sourceLines.size()) {
285                 return null;
286             } else {
287                 return sourceLines.get(index);
288             }
289         }
290     }
291 }
292