/******************************************************************************* | |
* Copyright (c) 2009, 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 - remove duplicate child methods (repeating super methods from Scope) | |
*******************************************************************************/ | |
package org.eclipse.cdt.debug.edc.internal.symbols.dwarf; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.List; | |
import org.eclipse.cdt.core.IAddress; | |
import org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope; | |
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeList; | |
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.CompilationUnitHeader; | |
import org.eclipse.cdt.debug.edc.symbols.IFunctionScope; | |
import org.eclipse.cdt.debug.edc.symbols.ILineEntry; | |
import org.eclipse.cdt.debug.edc.symbols.IModuleScope; | |
import org.eclipse.cdt.debug.edc.symbols.IScope; | |
import org.eclipse.cdt.debug.edc.symbols.IVariable; | |
import org.eclipse.core.runtime.IPath; | |
/** | |
* extension of CompileUnitScope that holds<br> | |
* 1) DWARF specific debug info provider<br> | |
* 2) DWARF specific attributes<br> | |
* 3) DWARF sepcific compile unit header<br> | |
* 4) cache flags for previously parsed variables, addresses & types | |
* | |
*/ | |
public class DwarfCompileUnit extends CompileUnitScope { | |
protected DwarfDebugInfoProvider provider; | |
protected AttributeList attributes; | |
private List<IPath> fileList; | |
private boolean rangesDirty; | |
/** computation unit header */ | |
protected final CompilationUnitHeader header; | |
/** whether the computation unit has been parsed to find variables and children with address ranges */ | |
protected boolean parsedForVarsAndAddresses = false; | |
/** whether the computation unit has been parsed to find types */ | |
protected boolean parsedForTypes = false; | |
/** | |
* DwarfCompileUnit holds the provider, attributes and DWARF header | |
* in addition to other member variables of its super, | |
* {@link CompileUnitScope#CompileUnitScope(IPath, IModuleScope, IAddress, IAddress)} | |
* @param provider | |
* @param parent | |
* @param filePath | |
* @param lowAddress | |
* @param highAddress | |
* @param header | |
* @param hasChildren | |
* @param attributes | |
*/ | |
public DwarfCompileUnit(DwarfDebugInfoProvider provider, IModuleScope parent, IPath filePath, | |
IAddress lowAddress, IAddress highAddress, CompilationUnitHeader header, boolean hasChildren, | |
AttributeList attributes) { | |
super(filePath, parent, lowAddress, highAddress); | |
this.provider = provider; | |
this.attributes = attributes; | |
this.header = header; | |
// if there are no children, say the children have been parsed | |
if (!hasChildren) { | |
this.parsedForVarsAndAddresses = true; | |
this.parsedForTypes = true; | |
} | |
} | |
/** | |
* called by {@link CompileUnitScope#hashCode()}. | |
* this implementation further distinguishes the hash-code | |
* by adding the following to the caller hashCode as follows: | |
* <br><code> | |
* (prime+header.debugInfoOffset)*prime+provider.symbolfFile.hashCode() | |
* </code> | |
* @see CompileUnitScope#cuScopeHashCode() | |
*/ | |
protected int cuScopeHashCode() { | |
final int prime = 31; | |
int result = 1; | |
result = prime * result + header.debugInfoOffset; | |
result = prime * result + provider.getSymbolFile().hashCode(); | |
return result; | |
} | |
/** | |
* called by {@link CompileUnitScope#equals(Object)}. | |
* caller will guarantee objects are not identical, non-null, | |
* of same class, with the same scope name. | |
* This implementation further guarantees equality: | |
* <br>(1) if and only if debugInfoOffset values are equal | |
* <br>(2) if and only if provider symbol file values are equal | |
* @see CompileUnitScope#cuScopeEquals(java.lang.Object) | |
*/ | |
protected boolean cuScopeEquals(Object obj) { | |
DwarfCompileUnit other = (DwarfCompileUnit) obj; | |
if (header.debugInfoOffset != other.header.debugInfoOffset) | |
return false; | |
if (!provider.getSymbolFile().equals(other.provider.getSymbolFile())) | |
return false; | |
return true; | |
} | |
/** | |
* @return attributes of this DwarfCompileUnit | |
*/ | |
public AttributeList getAttributeList() { | |
return attributes; | |
} | |
/** | |
* utilize DwarfInfoReader to implement abstract declaration in | |
* {@link CompileUnitScope#parseLineTable()} | |
*/ | |
protected Collection<ILineEntry> parseLineTable() { | |
DwarfInfoReader reader = new DwarfInfoReader(provider); | |
fileList = new ArrayList<IPath>(); | |
return reader.parseLineTable(this, attributes, fileList); | |
} | |
/** fixup ranges and ensure parsed for addresses before calling | |
* super.getFunctionAtAddress() | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#getFunctionAtAddress(org.eclipse.cdt.core.IAddress) | |
*/ | |
@Override | |
public IFunctionScope getFunctionAtAddress(IAddress linkAddress) { | |
if (rangesDirty) { | |
fixupRanges(); | |
} | |
ensureParsedForAddresses(); | |
return super.getFunctionAtAddress(linkAddress); | |
} | |
/** ensure parsed for addresses before calling super.getFunctions | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#getFunctions() | |
*/ | |
@Override | |
public Collection<IFunctionScope> getFunctions() { | |
ensureParsedForAddresses(); | |
return super.getFunctions(); | |
} | |
/** | |
* For compilers that don't generate compile unit scopes, e.g. GCCE with | |
* dlls, this fixes up the low and high addresses of the compile unit based | |
* on the function scopes | |
*/ | |
protected void fixupRanges() { | |
// fix up scope addresses in case compiler doesn't generate them. | |
if (hasEmptyRange() && parsedForVarsAndAddresses) { | |
fixupRanges(provider.getBaseLinkAddress()); | |
} | |
rangesDirty = false; | |
} | |
// Don't override this here. It causes unnecessary parsing | |
// wasting memory & time. | |
// @Override | |
// public Collection<IScope> getChildren() { | |
// ensureParsedForAddresses(); | |
// return super.getChildren(); | |
// } | |
/** | |
* allow the caller to establish an attribute list | |
*/ | |
public void setAttributes(AttributeList attributes) { | |
this.attributes = attributes; | |
} | |
/** | |
* @return whether or not this DwarfCompileUnit has been parsed for addresses | |
*/ | |
public boolean isParsedForAddresses() { | |
return parsedForVarsAndAddresses; | |
} | |
/** | |
* @return whether or not this DwarfCompileUnit has been parsed for variables | |
*/ | |
public boolean isParsedForVariables() { | |
return parsedForVarsAndAddresses; | |
} | |
/** | |
* @return whether or not this DwarfCompileUnit has been parsed for types | |
*/ | |
public boolean isParsedForTypes() { | |
return parsedForTypes; | |
} | |
/** ensure first parsed for variables before calling | |
* {@link CompileUnitScope#getVariables()} | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getVariables() | |
*/ | |
@Override | |
public Collection<IVariable> getVariables() { | |
ensureParsedForVariables(); | |
return super.getVariables(); | |
} | |
/** | |
* allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true | |
* @param parsedForAddresses | |
*/ | |
public void setParsedForAddresses(boolean parsedForAddresses) { | |
this.parsedForVarsAndAddresses = parsedForAddresses; | |
} | |
/** | |
* allow caller to set this DwarfCompileUnit's parsedForVarsAndAddresses flag true | |
* @param parsedForVariables | |
*/ | |
public void setParsedForVariables(boolean parsedForVariables) { | |
this.parsedForVarsAndAddresses = parsedForVariables; | |
} | |
/** | |
* allow caller to set this DwarfCompileUnit's parsedForTypes flag true | |
* @param parsedForTypes | |
*/ | |
public void setParsedForTypes(boolean parsedForTypes) { | |
this.parsedForTypes = parsedForTypes; | |
} | |
private void ensureParsedForAddresses() { | |
if (!parsedForVarsAndAddresses) { | |
DwarfInfoReader reader = new DwarfInfoReader(provider); | |
reader.parseCompilationUnitForAddresses(this); | |
fixupRanges(); | |
} | |
} | |
/** | |
* Get the file path for a file number | |
* @param declFileNum | |
* @return IPath for the file, or <code>null</code> | |
*/ | |
public IPath getFileEntry(int declFileNum) { | |
if (fileList == null) | |
parseLineTable(); | |
if (declFileNum <= 0 || declFileNum > fileList.size()) | |
return null; | |
return fileList.get(declFileNum - 1); | |
} | |
private void ensureParsedForVariables() { | |
if (!parsedForVarsAndAddresses) { | |
DwarfInfoReader reader = new DwarfInfoReader(provider); | |
reader.parseCompilationUnitForAddresses(this); | |
} | |
} | |
/** ensure parsed for addresses before calling super.getScopeAtAddress() | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#getScopeAtAddress(org.eclipse.cdt.core.IAddress) | |
*/ | |
@Override | |
public IScope getScopeAtAddress(IAddress linkAddress) { | |
ensureParsedForAddresses(); | |
return super.getScopeAtAddress(linkAddress); | |
} | |
/** | |
* DwarfCompileUnit specific version of toString():<br> | |
* <code> | |
* [SymFile=, SectionOffset=, lowAddr=, highAddr=, path=, parsedForVarsAndAddress=, parsedForTypes=] | |
* </code> | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.CompileUnitScope#toString() | |
*/ | |
@Override | |
public String toString() { | |
StringBuilder builder = new StringBuilder(); | |
builder.append("DwarfCompileUnit ["); | |
builder.append("SymFile="); | |
builder.append(provider.getSymbolFile().lastSegment()); | |
builder.append(", SectionOffset=0x"); | |
builder.append(Integer.toHexString(header.debugInfoOffset)); | |
builder.append(", lowAddr="); | |
builder.append(lowAddress != null ? lowAddress.toHexAddressString() : null); | |
builder.append(", highAddr="); | |
builder.append(highAddress != null ? highAddress.toHexAddressString() : null); | |
if (filePath != null) { | |
builder.append(", path="); | |
builder.append(filePath.toOSString()); | |
} | |
builder.append(", parsedForVarsAndAddresses="); | |
builder.append(parsedForVarsAndAddresses); | |
builder.append(", parsedForTypes="); | |
builder.append(parsedForTypes); | |
builder.append("]\n"); | |
return builder.toString(); | |
} | |
/** | |
* 1) calls super.addChild() first<br> | |
* 2) checks whether this has an empty range and merges range with passed child scope if not.<br> | |
* 3) adds line info to the passed child scope | |
* @see org.eclipse.cdt.debug.edc.internal.symbols.Scope#addChild(org.eclipse.cdt.debug.edc.symbols.IScope) | |
*/ | |
@Override | |
public void addChild(IScope scope) { | |
super.addChild(scope); | |
// if we don't know our scope yet... | |
if (hasEmptyRange()) { | |
rangesDirty = true; | |
} else { | |
// the CU may have an incomplete idea of its scope; fit the new scope in | |
mergeScopeRange(scope); | |
} | |
addLineInfoToParent(scope); | |
} | |
} |