diff options
Diffstat (limited to 'ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java')
-rw-r--r-- | ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java deleted file mode 100644 index 10799ec..0000000 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/Addr2Line.java +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.ddmuilib; - -import com.android.ddmlib.Log; -import com.android.ddmlib.NativeLibraryMapInfo; -import com.android.ddmlib.NativeStackCallInfo; - -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; - -/** - * Represents an addr2line process to get filename/method information from a - * memory address.<br> - * Each process can only handle one library, which should be provided when - * creating a new process.<br> - * <br> - * The processes take some time to load as they need to parse the library files. - * For this reason, processes cannot be manually started. Instead the class - * keeps an internal list of processes and one asks for a process for a specific - * library, using <code>getProcess(String library)<code>.<br></br> - * Internally, the processes are started in pipe mode to be able to query them - * with multiple addresses. - */ -public class Addr2Line { - private static final String ANDROID_SYMBOLS_ENVVAR = "ANDROID_SYMBOLS"; - - private static final String LIBRARY_NOT_FOUND_MESSAGE_FORMAT = - "Unable to locate library %s on disk. Addresses mapping to this library " - + "will not be resolved. In order to fix this, set the the library search path " - + "in the UI, or set the environment variable " + ANDROID_SYMBOLS_ENVVAR + "."; - - /** - * Loaded processes list. This is also used as a locking object for any - * methods dealing with starting/stopping/creating processes/querying for - * method. - */ - private static final HashMap<String, Addr2Line> sProcessCache = - new HashMap<String, Addr2Line>(); - - /** - * byte array representing a carriage return. Used to push addresses in the - * process pipes. - */ - private static final byte[] sCrLf = { - '\n' - }; - - /** Path to the library */ - private NativeLibraryMapInfo mLibrary; - - /** the command line process */ - private Process mProcess; - - /** buffer to read the result of the command line process from */ - private BufferedReader mResultReader; - - /** - * output stream to provide new addresses to decode to the command line - * process - */ - private BufferedOutputStream mAddressWriter; - - private static final String DEFAULT_LIBRARY_SYMBOLS_FOLDER; - static { - String symbols = System.getenv(ANDROID_SYMBOLS_ENVVAR); - if (symbols == null) { - DEFAULT_LIBRARY_SYMBOLS_FOLDER = DdmUiPreferences.getSymbolDirectory(); - } else { - DEFAULT_LIBRARY_SYMBOLS_FOLDER = symbols; - } - } - - private static List<String> mLibrarySearchPaths = new ArrayList<String>(); - - /** - * Set the search path where libraries should be found. - * @param path search path to use, can be a colon separated list of paths if multiple folders - * should be searched - */ - public static void setSearchPath(String path) { - mLibrarySearchPaths.clear(); - mLibrarySearchPaths.addAll(Arrays.asList(path.split(":"))); - } - - /** - * Returns the instance of a Addr2Line process for the specified library. - * <br>The library should be in a format that makes<br> - * <code>$ANDROID_PRODUCT_OUT + "/symbols" + library</code> a valid file. - * - * @param library the library in which to look for addresses. - * @return a new Addr2Line object representing a started process, ready to - * be queried for addresses. If any error happened when launching a - * new process, <code>null</code> will be returned. - */ - public static Addr2Line getProcess(final NativeLibraryMapInfo library) { - String libName = library.getLibraryName(); - - // synchronize around the hashmap object - if (libName != null) { - synchronized (sProcessCache) { - // look for an existing process - Addr2Line process = sProcessCache.get(libName); - - // if we don't find one, we create it - if (process == null) { - process = new Addr2Line(library); - - // then we start it - boolean status = process.start(); - - if (status) { - // if starting the process worked, then we add it to the - // list. - sProcessCache.put(libName, process); - } else { - // otherwise we just drop the object, to return null - process = null; - } - } - // return the process - return process; - } - } - return null; - } - - /** - * Construct the object with a library name. The library should be present - * in the search path as provided by ANDROID_SYMBOLS, ANDROID_OUT/symbols, or in the user - * provided search path. - * - * @param library the library in which to look for address. - */ - private Addr2Line(final NativeLibraryMapInfo library) { - mLibrary = library; - } - - /** - * Search for the library in the library search path and obtain the full path to where it - * is found. - * @return fully resolved path to the library if found in search path, null otherwise - */ - private String getLibraryPath(String library) { - // first check the symbols folder - String path = DEFAULT_LIBRARY_SYMBOLS_FOLDER + library; - if (new File(path).exists()) { - return path; - } - - for (String p : mLibrarySearchPaths) { - // try appending the full path on device - String fullPath = p + "/" + library; - if (new File(fullPath).exists()) { - return fullPath; - } - - // try appending basename(library) - fullPath = p + "/" + new File(library).getName(); - if (new File(fullPath).exists()) { - return fullPath; - } - } - - return null; - } - - /** - * Starts the command line process. - * - * @return true if the process was started, false if it failed to start, or - * if there was any other errors. - */ - private boolean start() { - // because this is only called from getProcess() we know we don't need - // to synchronize this code. - - String addr2Line = System.getenv("ANDROID_ADDR2LINE"); - if (addr2Line == null) { - addr2Line = DdmUiPreferences.getAddr2Line(); - } - - // build the command line - String[] command = new String[5]; - command[0] = addr2Line; - command[1] = "-C"; - command[2] = "-f"; - command[3] = "-e"; - - String fullPath = getLibraryPath(mLibrary.getLibraryName()); - if (fullPath == null) { - String msg = String.format(LIBRARY_NOT_FOUND_MESSAGE_FORMAT, mLibrary.getLibraryName()); - Log.e("ddm-Addr2Line", msg); - return false; - } - - command[4] = fullPath; - - try { - // attempt to start the process - mProcess = Runtime.getRuntime().exec(command); - - if (mProcess != null) { - // get the result reader - InputStreamReader is = new InputStreamReader(mProcess - .getInputStream()); - mResultReader = new BufferedReader(is); - - // get the outstream to write the addresses - mAddressWriter = new BufferedOutputStream(mProcess - .getOutputStream()); - - // check our streams are here - if (mResultReader == null || mAddressWriter == null) { - // not here? stop the process and return false; - mProcess.destroy(); - mProcess = null; - return false; - } - - // return a success - return true; - } - - } catch (IOException e) { - // log the error - String msg = String.format( - "Error while trying to start %1$s process for library %2$s", - DdmUiPreferences.getAddr2Line(), mLibrary); - Log.e("ddm-Addr2Line", msg); - - // drop the process just in case - if (mProcess != null) { - mProcess.destroy(); - mProcess = null; - } - } - - // we can be here either cause the allocation of mProcess failed, or we - // caught an exception - return false; - } - - /** - * Stops the command line process. - */ - public void stop() { - synchronized (sProcessCache) { - if (mProcess != null) { - // remove the process from the list - sProcessCache.remove(mLibrary); - - // then stops the process - mProcess.destroy(); - - // set the reference to null. - // this allows to make sure another thread calling getAddress() - // will not query a stopped thread - mProcess = null; - } - } - } - - /** - * Stops all current running processes. - */ - public static void stopAll() { - // because of concurrent access (and our use of HashMap.values()), we - // can't rely on the synchronized inside stop(). We need to put one - // around the whole loop. - synchronized (sProcessCache) { - // just a basic loop on all the values in the hashmap and call to - // stop(); - Collection<Addr2Line> col = sProcessCache.values(); - for (Addr2Line a2l : col) { - a2l.stop(); - } - } - } - - /** - * Looks up an address and returns method name, source file name, and line - * number. - * - * @param addr the address to look up - * @return a BacktraceInfo object containing the method/filename/linenumber - * or null if the process we stopped before the query could be - * processed, or if an IO exception happened. - */ - public NativeStackCallInfo getAddress(long addr) { - long offset = addr - mLibrary.getStartAddress(); - - // even though we don't access the hashmap object, we need to - // synchronized on it to prevent - // another thread from stopping the process we're going to query. - synchronized (sProcessCache) { - // check the process is still alive/allocated - if (mProcess != null) { - // prepare to the write the address to the output buffer. - - // first, conversion to a string containing the hex value. - String tmp = Long.toString(offset, 16); - - try { - // write the address to the buffer - mAddressWriter.write(tmp.getBytes()); - - // add CR-LF - mAddressWriter.write(sCrLf); - - // flush it all. - mAddressWriter.flush(); - - // read the result. We need to read 2 lines - String method = mResultReader.readLine(); - String source = mResultReader.readLine(); - - // make the backtrace object and return it - if (method != null && source != null) { - return new NativeStackCallInfo(addr, mLibrary.getLibraryName(), method, source); - } - } catch (IOException e) { - // log the error - Log.e("ddms", - "Error while trying to get information for addr: " - + tmp + " in library: " + mLibrary); - // we'll return null later - } - } - } - return null; - } -} |