blob: 7edb0485f14960928eab96baa6391f49f5a21cab [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2011 Nokia and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nokia - Initial API and implementation
* Broadcom - executableSectionsList optimization
*******************************************************************************/
package org.eclipse.cdt.debug.edc.internal.symbols.files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
import org.eclipse.cdt.debug.edc.symbols.ISymbol;
import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
import org.eclipse.core.runtime.IPath;
/**
* Base implementation of a symbolics reader. Subclasses populate sections and symbols
* on construction.
*/
public abstract class BaseExecutableSymbolicsReader implements IExecutableSymbolicsReader {
protected final IPath binaryFile;
protected Map<String, IExecutableSection> executableSections = new HashMap<String, IExecutableSection>();
protected List<IExecutableSection> executableSectionsList = new ArrayList<IExecutableSection>();
protected List<ISection> sections = new ArrayList<ISection>();
protected SortedMap<IAddress,List<ISymbol>> symbols = new TreeMap<IAddress,List<ISymbol>>();
protected IAddress exeBaseAddress;
protected long modificationDate;
protected ISectionMapper sectionMapper;
protected IUnmangler unmangler;
/**
* must be set using storeSymbol() and retrieved using getSymbols()
*/
private List<ISymbol> symbolsList = new ArrayList<ISymbol>();
/**
* @param binaryFile
*/
public BaseExecutableSymbolicsReader(IPath binaryFile) {
this.binaryFile = binaryFile;
}
/**
* Each symbol must be stored using this method
* @param symbol the symbol to store
* @param linkAddress the address of the (start of the) symbol
*/
protected void storeSymbol(ISymbol symbol, IAddress linkAddress){
List<ISymbol> symbolsAtAddress = symbols.get(linkAddress);
if (symbolsAtAddress == null) {
symbolsAtAddress = new ArrayList<ISymbol>(1);
symbols.put(linkAddress, symbolsAtAddress);
}
symbolsAtAddress.add(symbol);
symbolsList.add(symbol);
}
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.edc.internal.symbols.exe.IExecutableSymbolicsReader#dispose()
*/
public void dispose() {
if (sectionMapper != null) {
sectionMapper.dispose();
sectionMapper = null;
}
sections.clear();
symbols.clear();
symbolsList.clear();
}
public IPath getSymbolFile() {
return binaryFile;
}
public Collection<IExecutableSection> getExecutableSections() {
return Collections.unmodifiableCollection(executableSectionsList);
}
public IExecutableSection findExecutableSection(String sectionName) {
return executableSections.get(sectionName);
}
public Collection<ISection> getSections() {
return Collections.unmodifiableCollection(sections);
}
public Collection<ISymbol> getSymbols() {
return Collections.unmodifiableCollection(symbolsList);
}
/**
* @return the first symbol at that address unless the first one is zero
* sized and there is another non-zero sized one - in that case
* return the non-zero sized one. Null if there is no symbol at this address.
* @see #getSymbolsAtAddress(IAddress)
*/
public ISymbol getSymbolAtAddress(IAddress linkAddress) {
Collection<ISymbol> symbolsAtAddress = getSymbolsAtAddress(linkAddress);
ISymbol first = null;
for (ISymbol symbol : symbolsAtAddress) {
if (!symbol.hasEmptyRange())
return symbol;
if (null == first)
first = symbol;
}
return first;
}
public Collection<ISymbol> getSymbolsAtAddress(IAddress linkAddress) {
{// Try for an exact match
SortedMap<IAddress, List<ISymbol>> tail = symbols.tailMap(linkAddress);
if (!tail.isEmpty()) {
IAddress firstKey = tail.firstKey();
if (firstKey.equals(linkAddress)) {
// We have an exact match
return Collections.unmodifiableCollection(tail.get(firstKey));
}
}
}
// No exact match
{
// we need to try entries before linkAddress which might be large
// enough
SortedMap<IAddress, List<ISymbol>> head = symbols.headMap(linkAddress);
if (!head.isEmpty()) {
IAddress lastKey = head.lastKey();
List<ISymbol> lastList = head.get(lastKey);
List<ISymbol> validList = new ArrayList<ISymbol>(lastList.size());
for (ISymbol symbol : lastList) {
if (linkAddress.compareTo(symbol.getAddress().add(symbol.getSize())) < 0) {
validList.add(symbol);
}
}
return validList;
}
}
return Collections.emptyList();
}
public IAddress getBaseLinkAddress() {
return exeBaseAddress;
}
public long getModificationDate() {
return modificationDate;
}
public Collection<ISymbol> findSymbols(String name) {
List<ISymbol> matchSymbols = new ArrayList<ISymbol>();
// look for exact symbols
for (ISymbol symbol : symbolsList) {
String symName = symbol.getName();
if (symName.equals(name)) {
matchSymbols.add(symbol);
}
}
if (!matchSymbols.isEmpty())
return matchSymbols;
// try for a decorated symbol if no match
if (unmangler != null) {
for (ISymbol symbol : symbolsList) {
String symName = unmangler.undecorate(symbol.getName());
if (symName.equals(name)) {
matchSymbols.add(symbol);
}
}
}
return matchSymbols;
}
public Collection<ISymbol> findUnmangledSymbols(String name) {
List<ISymbol> matchSymbols = new ArrayList<ISymbol>();
if (unmangler != null) {
name = unmangler.undecorate(name);
String nameNoSpaces = name.replaceAll("\\s", "");
// remove full qualifier
if (nameNoSpaces.startsWith("::"))
nameNoSpaces = nameNoSpaces.substring(2);
boolean nameNoArguments = !nameNoSpaces.endsWith(")");
// avoid unmangling a lot of irrelevant symbols by filtering out symbols not containing the base name
String undecoratedBase = nameNoSpaces;
int idx = undecoratedBase.lastIndexOf(':');
if (idx >= 0)
undecoratedBase = undecoratedBase.substring(idx+1);
idx = undecoratedBase.indexOf('(');
if (idx >= 0)
undecoratedBase = undecoratedBase.substring(0, idx);
for (ISymbol symbol : symbolsList) {
String symName = symbol.getName();
if (!symName.contains(undecoratedBase))
continue;
try {
String unmangled = unmangler.unmangle(unmangler.undecorate(symName));
if (unmangled != null) {
String unmangledNoSpaces;
// remove any 'const' which is in front of '(' for now
unmangledNoSpaces = unmangled.replaceAll("\\bconst\\s*(?=\\()", "");
unmangledNoSpaces = unmangledNoSpaces.replaceAll("\\s", "");
// remove full qualifier
if (unmangledNoSpaces.startsWith("::"))
unmangledNoSpaces = unmangledNoSpaces.substring(2);
if (nameNoSpaces.equals(unmangledNoSpaces)) {
matchSymbols.add(symbol);
} else if (nameNoArguments) {
// try to match the name against a function
idx = unmangledNoSpaces.lastIndexOf('(');
if (idx >= 0) {
String unmangledNoArguments = unmangledNoSpaces.substring(0, idx);
if (unmangledNoArguments.equals(nameNoSpaces)) {
matchSymbols.add(symbol);
}
}
}
}
} catch (UnmanglingException e) {
// nope
}
}
if (!matchSymbols.isEmpty())
return matchSymbols;
}
return matchSymbols;
}
public IUnmangler getUnmangler() {
return unmangler;
}
}