blob: 640981063253a46986f9fc66b8703a3246317556 [file] [log] [blame]
/*******************************************************************************
* 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.getChildren
* @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;
}
/** ensure parsed for addresses before calling super.getChildren()
* @return children of this compile unit after it has been parsed for addresses
*/
@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);
}
}