| /* |
| * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.tools.example.debug.tty; |
| |
| import com.sun.jdi.*; |
| import com.sun.jdi.request.StepRequest; |
| import com.sun.jdi.request.MethodEntryRequest; |
| import com.sun.jdi.request.MethodExitRequest; |
| import com.sun.tools.jdi.*; |
| import java.util.*; |
| import java.io.*; |
| |
| |
| class Env { |
| |
| static EventRequestSpecList specList = new EventRequestSpecList(); |
| |
| private static VMConnection connection; |
| |
| private static SourceMapper sourceMapper = new SourceMapper(""); |
| private static List<String> excludes; |
| |
| private static final int SOURCE_CACHE_SIZE = 5; |
| private static List<SourceCode> sourceCache = new LinkedList<SourceCode>(); |
| |
| private static HashMap<String, Value> savedValues = new HashMap<String, Value>(); |
| private static Method atExitMethod; |
| |
| static void init(String connectSpec, boolean openNow, int flags) { |
| connection = new VMConnection(connectSpec, flags); |
| if (!connection.isLaunch() || openNow) { |
| connection.open(); |
| } |
| } |
| |
| static VMConnection connection() { |
| return connection; |
| } |
| |
| static VirtualMachine vm() { |
| return connection.vm(); |
| } |
| |
| static void shutdown() { |
| shutdown(null); |
| } |
| |
| static void shutdown(String message) { |
| if (connection != null) { |
| try { |
| connection.disposeVM(); |
| } catch (VMDisconnectedException e) { |
| // Shutting down after the VM has gone away. This is |
| // not an error, and we just ignore it. |
| } |
| } |
| if (message != null) { |
| MessageOutput.lnprint(message); |
| MessageOutput.println(); |
| } |
| System.exit(0); |
| } |
| |
| static void setSourcePath(String srcPath) { |
| sourceMapper = new SourceMapper(srcPath); |
| sourceCache.clear(); |
| } |
| |
| static void setSourcePath(List<String> srcList) { |
| sourceMapper = new SourceMapper(srcList); |
| sourceCache.clear(); |
| } |
| |
| static String getSourcePath() { |
| return sourceMapper.getSourcePath(); |
| } |
| |
| static private List<String> excludes() { |
| if (excludes == null) { |
| setExcludes("java.*, javax.*, sun.*, com.sun.*"); |
| } |
| return excludes; |
| } |
| |
| static String excludesString() { |
| StringBuffer buffer = new StringBuffer(); |
| for (String pattern : excludes()) { |
| buffer.append(pattern); |
| buffer.append(","); |
| } |
| return buffer.toString(); |
| } |
| |
| static void addExcludes(StepRequest request) { |
| for (String pattern : excludes()) { |
| request.addClassExclusionFilter(pattern); |
| } |
| } |
| |
| static void addExcludes(MethodEntryRequest request) { |
| for (String pattern : excludes()) { |
| request.addClassExclusionFilter(pattern); |
| } |
| } |
| |
| static void addExcludes(MethodExitRequest request) { |
| for (String pattern : excludes()) { |
| request.addClassExclusionFilter(pattern); |
| } |
| } |
| |
| static void setExcludes(String excludeString) { |
| StringTokenizer t = new StringTokenizer(excludeString, " ,;"); |
| List<String> list = new ArrayList<String>(); |
| while (t.hasMoreTokens()) { |
| list.add(t.nextToken()); |
| } |
| excludes = list; |
| } |
| |
| static Method atExitMethod() { |
| return atExitMethod; |
| } |
| |
| static void setAtExitMethod(Method mmm) { |
| atExitMethod = mmm; |
| } |
| |
| /** |
| * Return a Reader cooresponding to the source of this location. |
| * Return null if not available. |
| * Note: returned reader must be closed. |
| */ |
| static BufferedReader sourceReader(Location location) { |
| return sourceMapper.sourceReader(location); |
| } |
| |
| static synchronized String sourceLine(Location location, int lineNumber) |
| throws IOException { |
| if (lineNumber == -1) { |
| throw new IllegalArgumentException(); |
| } |
| |
| try { |
| String fileName = location.sourceName(); |
| |
| Iterator<SourceCode> iter = sourceCache.iterator(); |
| SourceCode code = null; |
| while (iter.hasNext()) { |
| SourceCode candidate = iter.next(); |
| if (candidate.fileName().equals(fileName)) { |
| code = candidate; |
| iter.remove(); |
| break; |
| } |
| } |
| if (code == null) { |
| BufferedReader reader = sourceReader(location); |
| if (reader == null) { |
| throw new FileNotFoundException(fileName); |
| } |
| code = new SourceCode(fileName, reader); |
| if (sourceCache.size() == SOURCE_CACHE_SIZE) { |
| sourceCache.remove(sourceCache.size() - 1); |
| } |
| } |
| sourceCache.add(0, code); |
| return code.sourceLine(lineNumber); |
| } catch (AbsentInformationException e) { |
| throw new IllegalArgumentException(); |
| } |
| } |
| |
| /** Return a description of an object. */ |
| static String description(ObjectReference ref) { |
| ReferenceType clazz = ref.referenceType(); |
| long id = ref.uniqueID(); |
| if (clazz == null) { |
| return toHex(id); |
| } else { |
| return MessageOutput.format("object description and hex id", |
| new Object [] {clazz.name(), |
| toHex(id)}); |
| } |
| } |
| |
| /** Convert a long to a hexadecimal string. */ |
| static String toHex(long n) { |
| char s1[] = new char[16]; |
| char s2[] = new char[18]; |
| |
| /* Store digits in reverse order. */ |
| int i = 0; |
| do { |
| long d = n & 0xf; |
| s1[i++] = (char)((d < 10) ? ('0' + d) : ('a' + d - 10)); |
| } while ((n >>>= 4) > 0); |
| |
| /* Now reverse the array. */ |
| s2[0] = '0'; |
| s2[1] = 'x'; |
| int j = 2; |
| while (--i >= 0) { |
| s2[j++] = s1[i]; |
| } |
| return new String(s2, 0, j); |
| } |
| |
| /** Convert hexadecimal strings to longs. */ |
| static long fromHex(String hexStr) { |
| String str = hexStr.startsWith("0x") ? |
| hexStr.substring(2).toLowerCase() : hexStr.toLowerCase(); |
| if (hexStr.length() == 0) { |
| throw new NumberFormatException(); |
| } |
| |
| long ret = 0; |
| for (int i = 0; i < str.length(); i++) { |
| int c = str.charAt(i); |
| if (c >= '0' && c <= '9') { |
| ret = (ret * 16) + (c - '0'); |
| } else if (c >= 'a' && c <= 'f') { |
| ret = (ret * 16) + (c - 'a' + 10); |
| } else { |
| throw new NumberFormatException(); |
| } |
| } |
| return ret; |
| } |
| |
| static ReferenceType getReferenceTypeFromToken(String idToken) { |
| ReferenceType cls = null; |
| if (Character.isDigit(idToken.charAt(0))) { |
| cls = null; |
| } else if (idToken.startsWith("*.")) { |
| // This notation saves typing by letting the user omit leading |
| // package names. The first |
| // loaded class whose name matches this limited regular |
| // expression is selected. |
| idToken = idToken.substring(1); |
| for (ReferenceType type : Env.vm().allClasses()) { |
| if (type.name().endsWith(idToken)) { |
| cls = type; |
| break; |
| } |
| } |
| } else { |
| // It's a class name |
| List<ReferenceType> classes = Env.vm().classesByName(idToken); |
| if (classes.size() > 0) { |
| // TO DO: handle multiples |
| cls = classes.get(0); |
| } |
| } |
| return cls; |
| } |
| |
| static Set<String> getSaveKeys() { |
| return savedValues.keySet(); |
| } |
| |
| static Value getSavedValue(String key) { |
| return savedValues.get(key); |
| } |
| |
| static void setSavedValue(String key, Value value) { |
| savedValues.put(key, value); |
| } |
| |
| static class SourceCode { |
| private String fileName; |
| private List<String> sourceLines = new ArrayList<String>(); |
| |
| SourceCode(String fileName, BufferedReader reader) throws IOException { |
| this.fileName = fileName; |
| try { |
| String line = reader.readLine(); |
| while (line != null) { |
| sourceLines.add(line); |
| line = reader.readLine(); |
| } |
| } finally { |
| reader.close(); |
| } |
| } |
| |
| String fileName() { |
| return fileName; |
| } |
| |
| String sourceLine(int number) { |
| int index = number - 1; // list is 0-indexed |
| if (index >= sourceLines.size()) { |
| return null; |
| } else { |
| return sourceLines.get(index); |
| } |
| } |
| } |
| } |