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