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 35package com.sun.tools.example.debug.tty; 36 37import com.sun.jdi.*; 38import com.sun.jdi.request.StepRequest; 39import com.sun.jdi.request.MethodEntryRequest; 40import com.sun.jdi.request.MethodExitRequest; 41import java.util.*; 42import java.io.*; 43 44 45class 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 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 67 static VMConnection connection() { 68 return connection; 69 } 70 71 static VirtualMachine vm() { 72 return connection.vm(); 73 } 74 75 static void shutdown() { 76 shutdown(null); 77 } 78 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 95 static void setSourcePath(String srcPath) { 96 sourceMapper = new SourceMapper(srcPath); 97 sourceCache.clear(); 98 } 99 100 static void setSourcePath(List<String> srcList) { 101 sourceMapper = new SourceMapper(srcList); 102 sourceCache.clear(); 103 } 104 105 static String getSourcePath() { 106 return sourceMapper.getSourcePath(); 107 } 108 109 static private List<String> excludes() { 110 if (excludes == null) { 111 setExcludes("java.*, javax.*, sun.*, com.sun.*"); 112 } 113 return excludes; 114 } 115 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 125 static void addExcludes(StepRequest request) { 126 for (String pattern : excludes()) { 127 request.addClassExclusionFilter(pattern); 128 } 129 } 130 131 static void addExcludes(MethodEntryRequest request) { 132 for (String pattern : excludes()) { 133 request.addClassExclusionFilter(pattern); 134 } 135 } 136 137 static void addExcludes(MethodExitRequest request) { 138 for (String pattern : excludes()) { 139 request.addClassExclusionFilter(pattern); 140 } 141 } 142 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 152 static Method atExitMethod() { 153 return atExitMethod; 154 } 155 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 */ 165 static BufferedReader sourceReader(Location location) { 166 return sourceMapper.sourceReader(location); 167 } 168 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. */ 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. */ 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. */ 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 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 289 static Set<String> getSaveKeys() { 290 return savedValues.keySet(); 291 } 292 293 static Value getSavedValue(String key) { 294 return savedValues.get(key); 295 } 296 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 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 318 String fileName() { 319 return fileName; 320 } 321 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