/******************************************************************************* | |
* 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; | |
} | |
} |