blob: 674f4c55eac572de46a5c63f8d2f0d4da4dad30e [file] [log] [blame]
/**
* Copyright (c) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
* Broadcom - Refactored ForwardTypeReference to separate top-level class
* - optimized Variable list
*
* Description:
*
*/
package org.eclipse.cdt.debug.edc.internal.symbols.dwarf;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.TreeMap;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.edc.IStreamBuffer;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.EDCTrace;
import org.eclipse.cdt.debug.edc.internal.MemoryStreamBuffer;
import org.eclipse.cdt.debug.edc.internal.PathUtils;
import org.eclipse.cdt.debug.edc.internal.symbols.ArrayBoundType;
import org.eclipse.cdt.debug.edc.internal.symbols.ArrayType;
import org.eclipse.cdt.debug.edc.internal.symbols.CPPBasicType;
import org.eclipse.cdt.debug.edc.internal.symbols.ClassType;
import org.eclipse.cdt.debug.edc.internal.symbols.ConstType;
import org.eclipse.cdt.debug.edc.internal.symbols.Enumeration;
import org.eclipse.cdt.debug.edc.internal.symbols.Enumerator;
import org.eclipse.cdt.debug.edc.internal.symbols.FieldType;
import org.eclipse.cdt.debug.edc.internal.symbols.FunctionScope;
import org.eclipse.cdt.debug.edc.internal.symbols.IArrayType;
import org.eclipse.cdt.debug.edc.internal.symbols.IBasicType;
import org.eclipse.cdt.debug.edc.internal.symbols.ICPPBasicType;
import org.eclipse.cdt.debug.edc.internal.symbols.ICompositeType;
import org.eclipse.cdt.debug.edc.internal.symbols.IForwardTypeReference;
import org.eclipse.cdt.debug.edc.internal.symbols.ISection;
import org.eclipse.cdt.debug.edc.internal.symbols.InheritanceType;
import org.eclipse.cdt.debug.edc.internal.symbols.LexicalBlockScope;
import org.eclipse.cdt.debug.edc.internal.symbols.LineEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.PointerType;
import org.eclipse.cdt.debug.edc.internal.symbols.ReferenceType;
import org.eclipse.cdt.debug.edc.internal.symbols.Scope;
import org.eclipse.cdt.debug.edc.internal.symbols.StructType;
import org.eclipse.cdt.debug.edc.internal.symbols.SubroutineType;
import org.eclipse.cdt.debug.edc.internal.symbols.TemplateParamType;
import org.eclipse.cdt.debug.edc.internal.symbols.TypedefType;
import org.eclipse.cdt.debug.edc.internal.symbols.UnionType;
import org.eclipse.cdt.debug.edc.internal.symbols.VolatileType;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AbbreviationEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.Attribute;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeList;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeValue;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.CompilationUnitHeader;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.PublicNameInfo;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.CommonInformationEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.FrameDescriptionEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.files.BaseExecutableSymbolicsReader;
import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglerEABI;
import org.eclipse.cdt.debug.edc.internal.symbols.files.UnmanglingException;
import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
import org.eclipse.cdt.debug.edc.symbols.IExecutableSection;
import org.eclipse.cdt.debug.edc.symbols.IExecutableSymbolicsReader;
import org.eclipse.cdt.debug.edc.symbols.IFunctionScope;
import org.eclipse.cdt.debug.edc.symbols.ILineEntry;
import org.eclipse.cdt.debug.edc.symbols.ILocationProvider;
import org.eclipse.cdt.debug.edc.symbols.IRangeList;
import org.eclipse.cdt.debug.edc.symbols.IScope;
import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.symbols.IUnmangler;
import org.eclipse.cdt.debug.edc.symbols.IVariable;
import org.eclipse.cdt.utils.Addr32;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
/**
* Handle restartable parsing of Dwarf information from a single module.
* This class may be instantiated multiple times to parse specific subsets
* of the Dwarf data. The {@link DwarfDebugInfoProvider}
* holds the global state of everything parsed so far.
*/
public class DwarfInfoReader {
private class BaseAndScopedNames {
public String baseName; // e.g., "bar"
public String nameWithScope; // e.g., "foo::bar"
}
private BaseAndScopedNames baseAndScopedNames = new BaseAndScopedNames();
// These are only for developer of the reader.
//
private static boolean DEBUG = false;
private static String dumpFileName = "C:\\temp\\_EDC_DwarfReaderDump.txt"; //$NON-NLS-1$
// TODO 64-bit Dwarf currently unsupported
/* Section names. */
public final static String DWARF_DEBUG_INFO = ".debug_info"; //$NON-NLS-1$
public final static String DWARF_DEBUG_RANGES = ".debug_ranges"; //$NON-NLS-1$
public final static String DWARF_DEBUG_ABBREV = ".debug_abbrev"; //$NON-NLS-1$
public final static String DWARF_DEBUG_ARANGES = ".debug_aranges"; //$NON-NLS-1$
public final static String DWARF_DEBUG_LINE = ".debug_line"; //$NON-NLS-1$
public final static String DWARF_DEBUG_FRAME = ".debug_frame"; //$NON-NLS-1$
public final static String DWARF_EH_FRAME = ".eh_frame"; //$NON-NLS-1$
public final static String DWARF_DEBUG_LOC = ".debug_loc"; //$NON-NLS-1$
public final static String DWARF_DEBUG_PUBNAMES = ".debug_pubnames"; //$NON-NLS-1$
public final static String DWARF_DEBUG_STR = ".debug_str"; //$NON-NLS-1$
public final static String DWARF_DEBUG_FUNCNAMES = ".debug_funcnames"; //$NON-NLS-1$
public final static String DWARF_DEBUG_TYPENAMES = ".debug_typenames"; //$NON-NLS-1$
public final static String DWARF_DEBUG_VARNAMES = ".debug_varnames"; //$NON-NLS-1$
public final static String DWARF_DEBUG_WEAKNAMES = ".debug_weaknames"; //$NON-NLS-1$
public final static String DWARF_DEBUG_MACINFO = ".debug_macinfo"; //$NON-NLS-1$
private Map<Long, Collection<LocationEntry>> locationEntriesByOffset = Collections.synchronizedMap(new HashMap<Long, Collection<LocationEntry>>());
// the target for all the reading
private DwarfDebugInfoProvider provider;
private IExecutableSymbolicsReader exeReader;
private DwarfModuleScope moduleScope;
private IPath symbolFilePath;
private IExecutableSection debugInfoSection;
private IExecutableSection publicNamesSection;
private CompilationUnitHeader currentCUHeader;
private Map<IType, IType> typeToParentMap = Collections.synchronizedMap(new HashMap<IType, IType>());
private IType currentParentType;
private Scope currentParentScope;
private DwarfCompileUnit currentCompileUnitScope;
private DwarfFileHelper fileHelper;
private RangeList codeRanges;
private ICPPBasicType voidType = null;
private IUnmangler unmangler;
// comparator for sorting and searching based on compilation unit low address
private static Comparator<DwarfCompileUnit> sComparatorByLowAddress = new Comparator<DwarfCompileUnit>() {
public int compare(DwarfCompileUnit o1, DwarfCompileUnit o2) {
return (o1.getLowAddress().compareTo(o2.getLowAddress()));
}};
/**
* Create a reader for the provider. This constructor and any methods
* on this reader class will incrementally update the provider.
* @param provider
*/
public DwarfInfoReader(DwarfDebugInfoProvider provider) {
this.provider = provider;
exeReader = provider.getExecutableSymbolicsReader();
if (exeReader instanceof BaseExecutableSymbolicsReader)
unmangler = ((BaseExecutableSymbolicsReader) exeReader).getUnmangler();
if (unmangler == null)
unmangler = new UnmanglerEABI();
symbolFilePath = provider.getSymbolFile();
fileHelper = provider.fileHelper;
moduleScope = (DwarfModuleScope) provider.getModuleScope();
debugInfoSection = exeReader.findExecutableSection(DWARF_DEBUG_INFO);
publicNamesSection = exeReader.findExecutableSection(DWARF_DEBUG_PUBNAMES);
codeRanges = getCodeRanges();
}
private String unmangle(String name) {
if (!unmangler.isMangled(name))
return name;
try {
name = unmangler.unmangle(name);
} catch (UnmanglingException ue) {
}
return name;
}
private String unmangleType(String name) {
if (!unmangler.isMangled(name))
return name;
try {
name = unmangler.unmangleType(name);
} catch (UnmanglingException ue) {
}
return name;
}
/**
* @return
*/
private RangeList getCodeRanges() {
RangeList codeRanges = new RangeList();
for (ISection section : exeReader.getSections()) {
if (section.getProperties().get(ISection.PROPERTY_NAME).equals(ISection.NAME_TEXT)) {
long start = section.getLinkAddress().getValue().longValue();
long size = section.getSize();
codeRanges.addRange(start, start + size);
}
}
return codeRanges;
}
protected IStreamBuffer getDwarfSection(String sectionName) {
// the exe reader and section already handle caching this
IStreamBuffer buffer = null;
IExecutableSection section = exeReader.findExecutableSection(sectionName);
if (section != null) {
buffer = section.getBuffer();
}
return buffer;
}
/**
* Parse top-level debugging information about compilation units and globally
* visible objects, but do not expand or gather data about other objects in
* compilation units.
*/
public void parseInitial() {
Job parseInitialJob = new Job(DwarfMessages.DwarfInfoReader_ReadingSymbolInfo + symbolFilePath) {
@Override
protected IStatus run(IProgressMonitor monitor) {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceInitialParseFor + symbolFilePath)); }
synchronized (provider) {
parseCUDebugInfo(monitor);
parsePublicNames();
}
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedInitialParse)); }
return Status.OK_STATUS;
}
};
try {
parseInitialJob.schedule();
parseInitialJob.join();
} catch (InterruptedException e) {
EDCDebugger.getMessageLogger().logError(null, e);
}
}
/**
* Parse all compilation units for addresses
*
* @param includeCUWithoutCode
* whether to parse compile units without code. For variable
* info, we need to look into those CUs, whereas for scope
* info, we don't.
*/
public void parseForAddresses(boolean includeCUWithoutCode) {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressesParseFor + symbolFilePath)); }
synchronized (provider) {
for (DwarfCompileUnit compileUnit : provider.compileUnits) {
if (DEBUG) {
// For internal check.
if (compileUnit.getHighAddress().isZero())
assert(compileUnit.getChildren().size() == 0);
else
assert(compileUnit.getChildren().size() >= 0);
}
if (includeCUWithoutCode || // parse every CU
! compileUnit.getHighAddress().isZero()) // parse only those with code.
{
parseCompilationUnitForAddresses(compileUnit);
}
}
}
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedAddressesParse)); }
moduleScope.fixupRanges(Addr32.ZERO);
if (DEBUG) {
dumpSymbols();
}
}
/**
* Parse compilation unit corresponding to address
*
* @param linkAddress
* address in a compile unit that contains code
*/
public void parseForAddress(IAddress linkAddress) {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressParseFor + symbolFilePath)); }
// find compilation unit containing address, and parse it
synchronized (provider) {
DwarfCompileUnit cu = new DwarfCompileUnit(provider, null, null, linkAddress, linkAddress, null, false, null);
int index = Collections.binarySearch (provider.sortedCompileUnitsWithCode, cu, sComparatorByLowAddress);
if (index >= 0) {
cu = provider.sortedCompileUnitsWithCode.get(index);
parseCompilationUnitForAddresses(cu);
} else if (index < -1 && -index - 2 < provider.sortedCompileUnitsWithCode.size()) {
cu = provider.sortedCompileUnitsWithCode.get(-index - 2);
if (cu.getLowAddress().compareTo(linkAddress) <= 0 && cu.getHighAddress().compareTo(linkAddress) >= 0)
parseCompilationUnitForAddresses(cu);
} else {
return;
}
if (moduleScope.getLowAddress().compareTo(cu.getLowAddress()) > 0)
moduleScope.setLowAddress(cu.getLowAddress());
if (moduleScope.getHighAddress().compareTo(cu.getHighAddress()) < 0)
moduleScope.setHighAddress(cu.getHighAddress());
}
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedAddressParse)); }
}
/**
* Parse names in the .debug_pubnames section
*/
private void parsePublicNames() {
if (publicNamesSection == null || debugInfoSection == null) { // no public names and/or debug info
return;
}
IStreamBuffer bufferPublicNames = publicNamesSection.getBuffer();
if (bufferPublicNames == null)
return;
IStreamBuffer bufferDebuginfo = debugInfoSection.getBuffer();
if (bufferDebuginfo == null)
return;
long fileIndex = 0;
long fileEndIndex = bufferPublicNames.capacity();
// parse all the sets in the .debug_pubnames section
while (fileIndex < fileEndIndex) {
fileIndex = parsePublicNamesSet(bufferPublicNames, fileIndex, bufferDebuginfo);
}
}
/**
* Parse one set of global objects and functions
*/
private long parsePublicNamesSet(IStreamBuffer bufferPublicNames, long fileIndex, IStreamBuffer bufferDebugInfo) {
bufferPublicNames.position(fileIndex);
// get the set's data length
int setLength = bufferPublicNames.getInt();
// get the entire set
IStreamBuffer dataPublicNames = bufferPublicNames.wrapSubsection(setLength);
// get header info for set of public names
// skip over Dwarf version
dataPublicNames.position(2);
int debugInfoOffset = dataPublicNames.getInt();
int debugInfoLength = dataPublicNames.getInt();
try {
// read the entire compile unit
bufferDebugInfo.position(debugInfoOffset);
IStreamBuffer dataInfoBytes = bufferDebugInfo.wrapSubsection(debugInfoLength);
CompilationUnitHeader header = provider.debugOffsetsToCompileUnits.get(Long.valueOf(debugInfoOffset));
// get stored abbrev table, or read and parse an abbrev table
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
// read names and corresponding types
// ignore the 4 bytes of 0 at the end of the set
while (dataPublicNames.remaining() > 4) {
// read the object offset and name
int objectOffset = dataPublicNames.getInt();
String name = readString(dataPublicNames);
// read the type of object
dataInfoBytes.position(objectOffset);
long code = read_unsigned_leb128(dataInfoBytes);
AbbreviationEntry entry = abbrevs.get(new Long(code));
// ignore empty names, names without debug info, and
// compiler-generated special symbols
if (entry != null && name.length() > 0 && !name.startsWith("<")) {
// if the name is mangled, unmangle it
name = unmangle(name);
String baseName = name;
int baseStart = name.lastIndexOf("::"); //$NON-NLS-1$
if (baseStart != -1)
baseName = name.substring(baseStart + 2);
if (entry.tag == DwarfConstants.DW_TAG_variable) {
List<PublicNameInfo> variables = provider.publicVariables.get(baseName);
if (variables == null) {
variables = new ArrayList<PublicNameInfo>();
}
variables.add(new PublicNameInfo(name, header, entry.tag));
provider.publicVariables.put(baseName, variables);
} else if (entry.tag == DwarfConstants.DW_TAG_subprogram) {
List<PublicNameInfo> functions = provider.publicFunctions.get(baseName);
if (functions == null) {
functions = new ArrayList<PublicNameInfo>();
functions.add(new PublicNameInfo(name, header, entry.tag));
} else {
// we don't store debug info offsets, so polymorphic functions for a compilation
// unit have identical PublicNameInfo fields; throw all but one away
ArrayList<PublicNameInfo> arrayList = (ArrayList<PublicNameInfo>)functions;
boolean found = false;
for (int i = arrayList.size() - 1;
!found && (i >= 0) && (arrayList.get(i).cuHeader == header); i--)
found = arrayList.get(i).nameWithNameSpace.equals(name);
if (!found)
functions.add(new PublicNameInfo(name, header, entry.tag));
}
provider.publicFunctions.put(baseName, functions);
}
}
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(null, t);
}
return fileIndex + setLength + 4;
}
/**
* Parse all compilation units for types
*/
public void parseForTypes() {
synchronized (provider) {
for (DwarfCompileUnit compileUnit : provider.compileUnits) {
parseCompilationUnitForTypes(compileUnit);
}
}
}
/**
* Parse compilation unit headers and top-level info in the .debug_info section
* @param monitor
*/
private void parseCUDebugInfo(IProgressMonitor monitor) {
if (debugInfoSection == null) { // no Dwarf data.
return;
}
// if we haven't built the referenced files list from a quick parse yet,
// flag it here so we can build the file list as we parse.
if (provider.referencedFiles.isEmpty()) {
provider.buildReferencedFilesList = true;
}
IStreamBuffer buffer = debugInfoSection.getBuffer();
IStreamBuffer debugStrings = getDebugStrings();
boolean havePubNames = publicNamesSection != null && publicNamesSection.getBuffer() != null;
int totalWork = (int) (buffer.capacity() / 1024);
monitor.beginTask(DwarfMessages.DwarfInfoReader_ReadDebugInfo, totalWork);
try {
if (buffer != null) {
long fileIndex = 0;
long fileEndIndex = buffer.capacity();
while (fileIndex < fileEndIndex) {
long oldIndex = fileIndex;
fileIndex = parseCompilationUnitForNames(buffer, fileIndex, debugStrings, fileEndIndex, havePubNames);
monitor.worked((int) ((fileIndex - oldIndex) / 1024));
}
}
} finally {
monitor.done();
}
provider.compileUnits.trimToSize();
// sort by low address the list of compilation units with code
provider.sortedCompileUnitsWithCode.trimToSize();
Collections.sort(provider.sortedCompileUnitsWithCode, sComparatorByLowAddress);
provider.buildReferencedFilesList = false;
}
/**
* Parse the compile unit quickly looking for variables that are globally visible
*
* @return offset of next compilation unit
*/
private long parseCompilationUnitForNames(IStreamBuffer buffer, long fileIndex, IStreamBuffer debugStrings, long fileEndIndex, boolean havePubNames) {
buffer.position(fileIndex);
currentCUHeader = new CompilationUnitHeader();
currentCUHeader.length = buffer.getInt();
currentCUHeader.version = buffer.getShort();
currentCUHeader.abbreviationOffset = buffer.getInt();
currentCUHeader.addressSize = buffer.get();
currentCUHeader.debugInfoOffset = (int) fileIndex;
/*
* With certain GCC-E 3.x compilers, some subset of compile unit headers can have unit
* lengths 4 bytes too long. Before reading compile unit data, make sure there is a
* valid compile unit header right after this unit's data. Adjust the length if needed.
* To validate, check that the DWARF version and the address size are
* the same as the previous compile unit's.
*/
if (fileIndex + currentCUHeader.length + 8 < fileEndIndex) {
// try good case
short nextVersion;
byte nextAddrSize;
buffer.position(fileIndex + currentCUHeader.length + 8); // to next version
nextVersion = buffer.getShort();
buffer.position(fileIndex + currentCUHeader.length + 14); // to next address size
nextAddrSize = buffer.get();
if (currentCUHeader.version != nextVersion || currentCUHeader.addressSize != nextAddrSize) {
// try adjusting back by 4 bytes
buffer.position(fileIndex + currentCUHeader.length + 4); // to next version
nextVersion = buffer.getShort();
buffer.position(fileIndex + currentCUHeader.length + 10); // to next address size
nextAddrSize = buffer.get();
if (currentCUHeader.version == nextVersion && currentCUHeader.addressSize == nextAddrSize) {
// all this work to adjust the length...
currentCUHeader.length -= 4;
}
}
}
// now read the whole compile unit into memory. note that we're
// reading the whole section including the size that we already
// read because other code will use the offset of the buffer as
// the offset of the section to store things by offset (types,
// function declarations, etc).
buffer.position(fileIndex);
IStreamBuffer in = buffer.wrapSubsection(currentCUHeader.length + 4);
// skip over the header info we already read
in.position(11);
try {
// get stored abbrev table, or read and parse an abbrev table
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(currentCUHeader.abbreviationOffset);
// read the compile unit's attribute list
long code = read_unsigned_leb128(in);
AbbreviationEntry entry = abbrevs.get(Long.valueOf(code));
AttributeList attributeList = new AttributeList(entry, in, currentCUHeader.addressSize, debugStrings);
processCompileUnit(currentCUHeader, entry.hasChildren, attributeList);
if (!havePubNames) {
// record file scope variables
byte addressSize = currentCUHeader.addressSize;
while (in.remaining() > 0) {
code = read_unsigned_leb128(in);
if (code != 0) {
entry = abbrevs.get(Long.valueOf(code));
switch (entry.tag) {
// record names of interest, but not other Dwarf attributes
case DwarfConstants.DW_TAG_variable:
{
// get variable names at the compile unit scope level
parseAttributesForNames(true, baseAndScopedNames, entry, in, addressSize, debugStrings);
if (baseAndScopedNames.baseName != null)
storePublicNames(provider.publicVariables, baseAndScopedNames, currentCUHeader, (short) DwarfConstants.DW_TAG_variable);
break;
}
case DwarfConstants.DW_TAG_imported_declaration: // for possible namespace alias
case DwarfConstants.DW_TAG_namespace:
case DwarfConstants.DW_TAG_subprogram:
case DwarfConstants.DW_TAG_enumerator:
case DwarfConstants.DW_TAG_class_type:
case DwarfConstants.DW_TAG_structure_type:
case DwarfConstants.DW_TAG_array_type:
case DwarfConstants.DW_TAG_base_type:
case DwarfConstants.DW_TAG_enumeration_type:
case DwarfConstants.DW_TAG_pointer_type:
case DwarfConstants.DW_TAG_ptr_to_member_type:
case DwarfConstants.DW_TAG_subroutine_type:
case DwarfConstants.DW_TAG_typedef:
case DwarfConstants.DW_TAG_union_type:
case DwarfConstants.DW_TAG_access_declaration:
case DwarfConstants.DW_TAG_catch_block:
case DwarfConstants.DW_TAG_common_block:
case DwarfConstants.DW_TAG_common_inclusion:
case DwarfConstants.DW_TAG_condition:
case DwarfConstants.DW_TAG_const_type:
case DwarfConstants.DW_TAG_constant:
case DwarfConstants.DW_TAG_entry_point:
case DwarfConstants.DW_TAG_file_type:
case DwarfConstants.DW_TAG_formal_parameter:
case DwarfConstants.DW_TAG_friend:
case DwarfConstants.DW_TAG_imported_module:
case DwarfConstants.DW_TAG_inheritance:
case DwarfConstants.DW_TAG_inlined_subroutine:
case DwarfConstants.DW_TAG_interface_type:
case DwarfConstants.DW_TAG_label:
case DwarfConstants.DW_TAG_lexical_block:
case DwarfConstants.DW_TAG_member:
case DwarfConstants.DW_TAG_module:
case DwarfConstants.DW_TAG_namelist:
case DwarfConstants.DW_TAG_namelist_item:
case DwarfConstants.DW_TAG_packed_type:
case DwarfConstants.DW_TAG_reference_type:
case DwarfConstants.DW_TAG_restrict_type:
case DwarfConstants.DW_TAG_set_type:
case DwarfConstants.DW_TAG_shared_type:
case DwarfConstants.DW_TAG_string_type:
case DwarfConstants.DW_TAG_subrange_type:
case DwarfConstants.DW_TAG_template_type_param:
case DwarfConstants.DW_TAG_template_value_param:
case DwarfConstants.DW_TAG_thrown_type:
case DwarfConstants.DW_TAG_try_block:
case DwarfConstants.DW_TAG_unspecified_parameters:
case DwarfConstants.DW_TAG_variant:
case DwarfConstants.DW_TAG_variant_part:
case DwarfConstants.DW_TAG_volatile_type:
case DwarfConstants.DW_TAG_with_stmt:
{
AttributeValue.skipAttributesToSibling(entry, in, addressSize);
break;
}
// case DwarfConstants.DW_TAG_compile_unit:
// case DwarfConstants.DW_TAG_partial_unit:
// case DwarfConstants.DW_TAG_unspecified_type:
default:
// skip entire entries
AttributeList.skipAttributes(entry, in, addressSize);
break;
}
}
}
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1
+ debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
}
// skip past the compile unit. note that the
// currentCUHeader.length does not include
// the size of the unit length itself
fileIndex += currentCUHeader.length + 4;
return fileIndex;
}
/**
* Parse attributes, returning names
*
* @param onlyExternal only return names if they have external visibility
* @param names array to hold up to two names
* @param entry debug info entry
* @param in buffer stream of debug info
* @param addressSize
* @param debugStrings
* @return DW_AT_name value in names[0], unmangled DW_AT_MIPS_linkage_name value in
* names[1], or nulls
*/
private void parseAttributesForNames(boolean onlyExternal, BaseAndScopedNames baseAndScopedNames, AbbreviationEntry entry, IStreamBuffer in,
byte addressSize, IStreamBuffer debugStrings) {
String name = null;
baseAndScopedNames.baseName = null;
baseAndScopedNames.nameWithScope = null;
boolean isExternal = false;
// go through the attributes and throw away everything except the names
int len = entry.attributes.size();
for (int i = 0; i < len; i++) {
Attribute attr = entry.attributes.get(i);
try {
if ( attr.tag == DwarfConstants.DW_AT_name
|| attr.tag == DwarfConstants.DW_AT_MIPS_linkage_name) {
// names should be DW_FORM_string or DW_FORM_strp
if (attr.form == DwarfConstants.DW_FORM_string) {
int c;
StringBuffer sb = new StringBuffer();
while ((c = (in.get() & 0xff)) != -1) {
if (c == 0) {
break;
}
sb.append((char) c);
}
name = sb.toString();
} else if (attr.form == DwarfConstants.DW_FORM_strp) {
int debugStringOffset = in.getInt();
if ( debugStrings != null
&& debugStringOffset >= 0
&& debugStringOffset < debugStrings.capacity()) {
debugStrings.position(debugStringOffset);
name = DwarfInfoReader.readString(debugStrings);
}
}
if (name != null) {
if (attr.tag == DwarfConstants.DW_AT_name) {
baseAndScopedNames.baseName = name;
baseAndScopedNames.nameWithScope = name;
} else {
if (exeReader instanceof BaseExecutableSymbolicsReader) {
try {
baseAndScopedNames.nameWithScope = unmangler.unmangle(unmangler.undecorate(name));
} catch(UnmanglingException ue) {
}
}
}
name = null;
}
} else if (attr.tag == DwarfConstants.DW_AT_external) {
if (attr.form == DwarfConstants.DW_FORM_flag) {
isExternal = in.get() != 0;
} else {
AttributeValue.skipAttributeValue(attr.form, in, addressSize);
}
} else {
AttributeValue.skipAttributeValue(attr.form, in, addressSize);
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(null, t);
break;
}
}
// if only looking for externals, throw away internals
if (onlyExternal && !isExternal) {
baseAndScopedNames.baseName = null;
baseAndScopedNames.nameWithScope = null;
} else {
// if only have the scoped name, derive the base name
if (baseAndScopedNames.nameWithScope != null && baseAndScopedNames.baseName == null) {
int baseStart = baseAndScopedNames.nameWithScope.lastIndexOf("::"); //$NON-NLS-1$
if (baseStart != -1)
baseAndScopedNames.baseName = baseAndScopedNames.nameWithScope.substring(baseStart + 2);
else
baseAndScopedNames.baseName = baseAndScopedNames.nameWithScope;
}
}
}
/**
* Store compilation unit level names from Dwarf .debug_info
*
* @param namesStore
* @param names
* @param offset
*/
private void storePublicNames(Map<String, List<PublicNameInfo>> namesStore, BaseAndScopedNames baseAndScopedNames,
CompilationUnitHeader cuHeader, short tag) {
List<PublicNameInfo> currentNames = namesStore.get(baseAndScopedNames.baseName);
if (currentNames == null) {
currentNames = new ArrayList<PublicNameInfo>();
namesStore.put(baseAndScopedNames.baseName, currentNames);
}
currentNames.add(new PublicNameInfo(baseAndScopedNames.nameWithScope, cuHeader, tag));
}
private synchronized void parseCompilationUnitForAddressesPrivate(DwarfCompileUnit compileUnit, IProgressMonitor monitor)
{
synchronized (compileUnit) {
if (compileUnit.isParsedForAddresses())
return;
compileUnit.setParsedForAddresses(true);
CompilationUnitHeader header = compileUnit.header;
if (header == null)
return;
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceAddressParse1 + Integer.toHexString(header.debugInfoOffset) + DwarfMessages.DwarfInfoReader_TraceAddressParse2 + header.scope.getFilePath())); }
IStreamBuffer buffer = debugInfoSection.getBuffer();
if (buffer == null)
return;
int fileIndex = header.debugInfoOffset;
// read the compile unit debug info into memory
buffer.position(fileIndex);
IStreamBuffer data = buffer.wrapSubsection(header.length + 4);
// skip over the header, since we've already read it
data.position(11); // unit length + version + abbrev table offset + address size
currentCompileUnitScope = compileUnit;
currentParentScope = compileUnit;
registerScope(header.debugInfoOffset, compileUnit);
currentCUHeader = header;
try {
// get stored abbrev table, or read and parse an abbrev table
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
parseForAddresses(data, abbrevs, header, new Stack<Scope>(), monitor);
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1
+ debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
}
}
}
/**
* Given compilation unit, parse to get variables and all children that have address ranges.
*
* @param compileUnit
*/
public void parseCompilationUnitForAddresses(final DwarfCompileUnit compileUnit) {
synchronized (provider) {
synchronized (compileUnit) {
if (compileUnit.isParsedForAddresses())
return;
}
parseCompilationUnitForAddressesPrivate(compileUnit, new NullProgressMonitor());
}
}
synchronized public void parseCompilationUnitForTypes(DwarfCompileUnit compileUnit) {
synchronized (provider) {
synchronized(compileUnit) {
if (compileUnit.isParsedForTypes())
return;
compileUnit.setParsedForTypes(true);
CompilationUnitHeader header = compileUnit.header;
if (header == null)
return;
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceTypeParse1 + Integer.toHexString(header.debugInfoOffset) + DwarfMessages.DwarfInfoReader_TraceTypeParse2 + header.scope.getFilePath())); }
IStreamBuffer buffer = debugInfoSection.getBuffer();
if (buffer == null)
return;
int fileIndex = header.debugInfoOffset;
// read the compile unit debug info into memory
buffer.position(fileIndex);
IStreamBuffer data = buffer.wrapSubsection(header.length + 4);
// skip over the header, since we've already read it
data.position(11); // unit length + version + abbrev table offset + address size
currentCompileUnitScope = compileUnit;
currentParentScope = compileUnit;
registerScope(header.debugInfoOffset, compileUnit);
currentCUHeader = header;
try {
// get stored abbrev table, or read and parse an abbrev table
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(header.abbreviationOffset);
parseForTypes(data, abbrevs, header, new Stack<Scope>());
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseTraceInfoSectionFailed1
+ debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseTraceInfoSectionFailed2 + symbolFilePath, t);
}
}
}
}
public void quickParseDebugInfo(IProgressMonitor monitor) {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceQuickParse + symbolFilePath)); }
synchronized (provider) {
doQuickParseDebugInfo(monitor);
}
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceFinishedQuickParse)); }
}
/**
* Does a quick parse of the .debug_info section just to get a list of
* referenced files from the compile units.
*/
private void doQuickParseDebugInfo(IProgressMonitor monitor) {
if (debugInfoSection == null) { // no Dwarf data.
return;
}
// get the compile units out of the .debug_info section
IStreamBuffer buffer = debugInfoSection.getBuffer();
if (buffer == null)
return;
try {
long fileIndex = 0;
long fileEndIndex = buffer.capacity();
monitor.beginTask(DwarfMessages.DwarfInfoReader_ReadDebugInfo, (int) (fileEndIndex / 1024));
buffer.position(0);
while (fileIndex < fileEndIndex) {
buffer.position(fileIndex);
int unit_length = buffer.getInt();
short version = buffer.getShort();
int debug_abbrev_offset = buffer.getInt();
byte address_size = buffer.get();
/*
* With certain GCC-E 3.x compilers, some subset of compile unit headers can have unit
* lengths 4 bytes too long. So before reading this unit's data, make sure there is a
* valid compile unit header right after this unit's data. Adjust the length if needed.
* To validate, check that the DWARF version and the address size are
* the same as the previous compile unit's.
*/
if (fileIndex + unit_length + 8 < fileEndIndex) {
// try good case
short nextVersion;
byte nextAddrSize;
buffer.position(fileIndex + unit_length + 8); // to next version
nextVersion = buffer.getShort();
buffer.position(fileIndex + unit_length + 14); // to next address size
nextAddrSize = buffer.get();
if (version != nextVersion || address_size != nextAddrSize) {
// try adjusting back by 4 bytes
buffer.position(fileIndex + unit_length + 4); // to next version
nextVersion = buffer.getShort();
buffer.position(fileIndex + unit_length + 10); // to next address size
nextAddrSize = buffer.get();
if (version == nextVersion && address_size == nextAddrSize) {
unit_length -= 4;
} // otherwise, just let things bomb
}
}
buffer.position(fileIndex + 4);
IStreamBuffer data = buffer.wrapSubsection(unit_length);
data.position(7); // skip header info already read
// get the abbreviation entry for the compile unit
// find the offset to the
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(debug_abbrev_offset);
long code = read_unsigned_leb128(data);
AbbreviationEntry entry = abbrevs.get(Long.valueOf(code));
AttributeList attributeList = new AttributeList(entry, data, address_size, getDebugStrings());
// get comp_dir and name and figure out the path
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
String compDir = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
IPath filePath = fileHelper.normalizeFilePath(compDir, name);
provider.referencedFiles.add(filePath.toOSString());
// do a quick parse of the line table to get any other
// referenced files
AttributeValue a = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
if (a != null) {
int stmtList = a.getValueAsInt();
quickParseLineInfo(stmtList, compDir);
}
// skip past the compile unit. note that the unit_length does
// not include the size of the unit length itself
long oldIndex = fileIndex;
fileIndex += unit_length + 4;
monitor.worked((int) ((fileIndex - oldIndex) / 1024));
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseSectionSourceFilesFailed1
+ debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseSectionSourceFilesFailed2 + symbolFilePath, t);
} finally {
monitor.done();
}
}
/**
* Get the .debug_strings section.
* @return ByteBuffer or <code>null</code>
*/
private IStreamBuffer getDebugStrings() {
return getDwarfSection(DWARF_DEBUG_STR);
}
/**
* Does a quick parse of the .debug_line section just to get a list of
* referenced files from the line table.
*/
private void quickParseLineInfo(int lineTableOffset, String compileUnitDirectory) {
IPath compileUnitDirectoryPath = PathUtils.createPath(compileUnitDirectory);
try {
// do a quick parse of the line table just to get referenced files
IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LINE);
if (data != null) {
data.position(lineTableOffset);
/*
* Skip past the bytes of the header that we don't care about:
* unit_length (4 bytes), version (2 bytes), header_length (4 bytes),
* minimum_instruction_length (1 byte), default_is_stmt (1 byte),
* line_base (1 byte), line_range (1 byte)
*/
data.position(data.position() + 14);
// we need to get this value so we can skip over
// standard_opcode_lengths
int opcode_base = data.get() & 0xff;
data.position(data.position() + opcode_base - 1);
// include_directories
ArrayList<String> dirList = new ArrayList<String>();
// add the compilation directory of the CU as the first
// directory
dirList.add(compileUnitDirectory);
while (true) {
String str = readString(data);
if (str.length() == 0)
break;
// if the directory is relative, append it to the CU dir
IPath dir = PathUtils.createPath(str);
if (!dir.isAbsolute() && dir.getDevice() == null) {
dir = compileUnitDirectoryPath.append(str);
}
dirList.add(dir.toString());
}
while (true) {
String fileName = readString(data);
if (fileName.length() == 0) // no more file entry
break;
// dir index
long leb128 = DwarfInfoReader.read_unsigned_leb128(data);
IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) leb128), fileName);
if (fullPath != null) {
provider.referencedFiles.add(fullPath.toOSString());
}
// skip the modification time and file size
leb128 = read_unsigned_leb128(data);
leb128 = read_unsigned_leb128(data);
}
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(null, t);
}
}
/**
* Parse the line table for a given compile unit
* @param attributes
* @param fileList list for file entries
* @return new array of ILineEntry
*/
public Collection<ILineEntry> parseLineTable(IScope scope, AttributeList attributes, List<IPath> fileList) {
synchronized (provider) {
List<ILineEntry> lineEntries = new ArrayList<ILineEntry>();
try {
IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LINE);
AttributeValue a = attributes.getAttribute(DwarfConstants.DW_AT_stmt_list);
if (data != null && a != null) {
int stmtList = a.getValueAsInt();
data.position(stmtList);
/*
* Read line table header:
*
* total_length: 4 bytes (excluding itself)
* version: 2
* prologue length: 4
* minimum_instruction_len: 1
* default_is_stmt: 0 or 1
* line_base: 1
* line_range: 1
* opcode_base: 1
* standard_opcode_lengths: (value of opcode_base)
*/
// Remember the CU line tables we've parsed.
int length = data.getInt() + 4;
// Skip the following till "opcode_base"
@SuppressWarnings("unused")
int version = data.getShort();
@SuppressWarnings("unused")
int prologue_length = data.getInt();
int minimum_instruction_length = data.get() & 0xff;
boolean default_is_stmt = data.get() > 0;
int line_base = data.get(); // signed
int line_range = data.get() & 0xff;
int opcode_base = data.get() & 0xff;
byte[] opcodes = new byte[opcode_base - 1];
data.get(opcodes);
// Read in directories.
//
ArrayList<String> dirList = new ArrayList<String>();
// Put the compilation directory of the CU as the first dir
String compDir = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
dirList.add(compDir);
IPath compDirPath = PathUtils.createPath(compDir);
String str, fileName;
while (true) {
str = readString(data);
if (str.length() == 0)
break;
// If the directory is relative, append it to the CU dir
IPath dir = PathUtils.createPath(str);
if (!dir.isAbsolute() && dir.getDevice() == null) {
dir = compDirPath.append(str);
}
dirList.add(dir.toString());
}
// Read file names
//
long leb128;
while (true) {
fileName = readString(data);
if (fileName.length() == 0) // no more file entry
break;
// dir index
leb128 = read_unsigned_leb128(data);
IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) leb128), fileName);
// add a null as a placeholder when the filename is enclosed in '<' & '>' (e.g., "<stdin>")
fileList.add(fullPath);
// Skip the following
//
// modification time
leb128 = read_unsigned_leb128(data);
// file size in bytes
leb128 = read_unsigned_leb128(data);
}
long info_address = 0;
long info_file = 1;
int info_line = 1;
int info_column = 0;
boolean is_stmt = default_is_stmt;
@SuppressWarnings("unused")
int info_flags = 0;
@SuppressWarnings("unused")
long info_ISA = 0;
long lineInfoEnd = stmtList + length;
while (data.position() < lineInfoEnd) {
byte opcodeB = data.get();
int opcode = 0xFF & opcodeB;
if (opcode >= opcode_base) {
info_line += (((opcode - opcode_base) % line_range) + line_base);
info_address += (opcode - opcode_base) / line_range * minimum_instruction_length;
if (is_stmt && fileList.size() > 0) {
IPath path = fileList.get((int) info_file - 1);
// added a null as a placeholder when the filename was enclosed in '<' & '>' (e.g., "<stdin>")
if (path != null)
lineEntries.add(new LineEntry(path, info_line, info_column, new Addr32(info_address), null));
}
info_flags &= ~(DwarfConstants.LINE_BasicBlock | DwarfConstants.LINE_PrologueEnd | DwarfConstants.LINE_EpilogueBegin);
} else if (opcode == 0) {
long op_size = read_unsigned_leb128(data);
long op_pos = data.position();
int code = data.get() & 0xff;
switch (code) {
case DwarfConstants.DW_LNE_define_file: {
fileName = readString(data);
long dir = read_unsigned_leb128(data);
@SuppressWarnings("unused")
long modTime = read_unsigned_leb128(data);
@SuppressWarnings("unused")
long fileSize = read_unsigned_leb128(data);
IPath fullPath = fileHelper.normalizeFilePath(dirList.get((int) dir), fileName);
if (fullPath != null) {
fileList.add(fullPath);
}
break;
}
case DwarfConstants.DW_LNE_end_sequence:
info_flags |= DwarfConstants.LINE_EndSequence;
if (lineEntries.size() > 0) {
// this just marks the end of a line number
// program sequence. use
// its address to set the high address of the
// last line entry
lineEntries.get(lineEntries.size() - 1).setHighAddress(new Addr32(info_address));
}
// it also resets the state machine
info_address = 0;
info_file = 1;
info_line = 1;
info_column = 0;
is_stmt = default_is_stmt;
info_flags = 0;
info_ISA = 0;
break;
case DwarfConstants.DW_LNE_set_address:
info_address = data.getInt();
break;
default:
data.position((int) (data.position() + op_size - 1));
break;
}
assert (data.position() == op_pos + op_size);
} else {
switch (opcode) {
case DwarfConstants.DW_LNS_copy:
if (is_stmt && fileList.size() > 0) {
lineEntries.add(new LineEntry(fileList.get((int) info_file - 1), info_line,
info_column, new Addr32(info_address), null));
}
info_flags &= ~(DwarfConstants.LINE_BasicBlock | DwarfConstants.LINE_PrologueEnd | DwarfConstants.LINE_EpilogueBegin);
break;
case DwarfConstants.DW_LNS_advance_pc:
info_address += read_unsigned_leb128(data) * minimum_instruction_length;
break;
case DwarfConstants.DW_LNS_advance_line:
info_line += read_signed_leb128(data);
break;
case DwarfConstants.DW_LNS_set_file:
info_file = read_unsigned_leb128(data);
break;
case DwarfConstants.DW_LNS_set_column:
info_column = (int) read_unsigned_leb128(data);
break;
case DwarfConstants.DW_LNS_negate_stmt:
is_stmt = !is_stmt;
break;
case DwarfConstants.DW_LNS_set_basic_block:
info_flags |= DwarfConstants.LINE_BasicBlock;
break;
case DwarfConstants.DW_LNS_const_add_pc:
info_address += (255 - opcode_base) / line_range * minimum_instruction_length;
break;
case DwarfConstants.DW_LNS_fixed_advance_pc:
info_address += data.getShort();
break;
case DwarfConstants.DW_LNS_set_prologue_end:
info_flags |= DwarfConstants.LINE_PrologueEnd;
break;
case DwarfConstants.DW_LNS_set_epilogue_begin:
info_flags |= DwarfConstants.LINE_EpilogueBegin;
break;
case DwarfConstants.DW_LNS_set_isa:
info_ISA = read_unsigned_leb128(data);
break;
default:
break;
}
}
}
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(null, t);
}
// sort by start address
Collections.sort(lineEntries);
// fill in the end addresses as needed
ILineEntry previousEntry = null;
for (ILineEntry line : lineEntries) {
if (previousEntry != null && previousEntry.getHighAddress() == null) {
previousEntry.setHighAddress(line.getLowAddress());
}
previousEntry = line;
}
// the last line entry
if (previousEntry != null) {
IAddress prevHigh = previousEntry.getHighAddress();
if (prevHigh == null)
previousEntry.setHighAddress(scope.getHighAddress());
// FIXME: the following is causing JUnit tests to fail
// else if (prevHigh != null && prevHigh.compareTo(scope.getHighAddress()) > 0)
// previousEntry.setHighAddress(scope.getHighAddress());
}
return lineEntries;
}
}
private void parseForAddresses(IStreamBuffer in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header,
Stack<Scope> nestingStack, IProgressMonitor monitor)
throws IOException {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceScopeAddressParse1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceScopeAddressParse2 + Long.toHexString(header.debugInfoOffset))); }
try {
long startWork = in.remaining();
long lastWork = startWork;
int workChunk = (int)(startWork / Integer.MAX_VALUE) + 1;
int work = (int)(startWork / workChunk);
monitor.beginTask(DwarfMessages.DwarfInfoReader_TraceScopeAddressParse1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceScopeAddressParse2 + Long.toHexString(header.debugInfoOffset), work);
while (in.remaining() > 0) {
work = (int)((lastWork - in.remaining()) / workChunk);
monitor.worked(work);
lastWork = in.remaining();
long offset = in.position() + currentCUHeader.debugInfoOffset;
long code = read_unsigned_leb128(in);
if (code != 0) {
AbbreviationEntry entry = abbrevs.get(new Long(code));
if (entry == null) {
assert false;
continue;
}
if (entry.hasChildren) {
nestingStack.push(currentParentScope);
}
if (isDebugInfoEntryWithAddressRange(entry.tag)) {
AttributeList attributeList = new AttributeList(entry, in, header.addressSize, getDebugStrings());
processDebugInfoEntry(offset, entry, attributeList, header);
// if we didn't create a scope for a routine or lexical block, then ignore its innards
switch (entry.tag) {
case DwarfConstants.DW_TAG_subprogram:
case DwarfConstants.DW_TAG_inlined_subroutine:
case DwarfConstants.DW_TAG_lexical_block:
if (entry.hasChildren && (provider.scopesByOffset.get(offset) == null)) {
// because some versions of GCC-E 3.x produce invalid sibling offsets,
// always read entry attributes, rather than skipping using siblings
// keep track of nesting just like in parseForTypes()
int nesting = 1;
while ((nesting > 0) && (in.remaining() > 0)) {
offset = in.position() + currentCUHeader.debugInfoOffset;
code = read_unsigned_leb128(in);
if (code != 0) {
entry = abbrevs.get(new Long(code));
if (entry == null) {
assert false;
continue;
}
if (entry.hasChildren)
nesting++;
// skip the attributes we're not reading...
AttributeList.skipAttributes(entry, in, header.addressSize);
} else {
nesting--;
}
}
// nesting loop ends after reading 0 code of skipped entry
if (nestingStack.isEmpty()) {
// FIXME
currentParentScope = null;
} else {
currentParentScope = nestingStack.pop();
}
}
break;
}
} else {
// skip the attributes we're not reading...
AttributeList.skipAttributes(entry, in, header.addressSize);
}
} else {
if (code == 0) {
if (nestingStack.isEmpty()) {
// FIXME
currentParentScope = null;
} else {
currentParentScope = nestingStack.pop();
}
}
}
}
} catch (IOException e) {
throw e;
} finally {
monitor.done();
}
}
private void parseForTypes(IStreamBuffer in, Map<Long, AbbreviationEntry> abbrevs, CompilationUnitHeader header,
Stack<Scope> nestingStack)
throws IOException {
if (EDCTrace.SYMBOL_READER_TRACE_ON) { EDCTrace.getTrace().trace(null, EDCTrace.fixArg(DwarfMessages.DwarfInfoReader_TraceParseTypes1 + header.scope.getName() + DwarfMessages.DwarfInfoReader_TraceParseTypes2 + Long.toHexString(header.debugInfoOffset))); }
Stack<IType> typeStack = new Stack<IType>();
typeToParentMap.clear();
currentParentScope = currentCompileUnitScope;
while (in.remaining() > 0) {
long offset = in.position() + currentCUHeader.debugInfoOffset;
long code = read_unsigned_leb128(in);
if (code != 0) {
AbbreviationEntry entry = abbrevs.get(new Long(code));
if (entry == null) {
assert false;
continue;
}
if (entry.hasChildren) {
nestingStack.push(currentParentScope);
typeStack.push(currentParentType);
}
if (isForwardTypeTag(entry.tag) || isForwardTypeChildTag(entry.tag)) {
processDebugInfoEntry(offset, entry,
new AttributeList(entry, in, header.addressSize, getDebugStrings()),
header);
} else {
switch (entry.tag) {
case DwarfConstants.DW_TAG_subprogram:
case DwarfConstants.DW_TAG_inlined_subroutine:
case DwarfConstants.DW_TAG_lexical_block: {
Scope scope = provider.scopesByOffset.get(offset); // may be null
if (scope != null)
currentParentScope = scope;
break;
}
}
// skip the attributes we're not reading...
AttributeList.skipAttributes(entry, in, header.addressSize);
}
} else {
// code == 0
if (nestingStack.isEmpty()) {
// FIXME
currentParentType = null;
currentParentScope = null;
} else {
currentParentScope = nestingStack.pop();
currentParentType = typeStack.pop();
}
}
}
}
/**
* Tell if a tag will be parsed on-demand to generate an IType, and will
* be accessible via provider.getType() or provider.readType().
* <p>
* Note: DW_TAG_member is usually considered a child of struct/class/etc., but
* a static class variable contains a reference to it, so we must be able to
* locate it.
* @param tag
* @return true if type is parsed and should have a ForwardDwarfDefinition
*/
private boolean isForwardTypeTag(short tag) {
switch (tag) {
case DwarfConstants.DW_TAG_array_type:
case DwarfConstants.DW_TAG_class_type:
case DwarfConstants.DW_TAG_enumeration_type:
case DwarfConstants.DW_TAG_member:
case DwarfConstants.DW_TAG_pointer_type:
case DwarfConstants.DW_TAG_reference_type:
case DwarfConstants.DW_TAG_structure_type:
case DwarfConstants.DW_TAG_subroutine_type:
case DwarfConstants.DW_TAG_typedef:
case DwarfConstants.DW_TAG_union_type:
//case DwarfConstants.DW_TAG_unspecified_parameters:
case DwarfConstants.DW_TAG_inheritance:
case DwarfConstants.DW_TAG_ptr_to_member_type:
//case DwarfConstants.DW_TAG_with_stmt:
case DwarfConstants.DW_TAG_base_type:
//case DwarfConstants.DW_TAG_catch_block:
case DwarfConstants.DW_TAG_const_type:
//case DwarfConstants.DW_TAG_enumerator:
//case DwarfConstants.DW_TAG_file_type:
//case DwarfConstants.DW_TAG_friend:
case DwarfConstants.DW_TAG_template_type_param:
//case DwarfConstants.DW_TAG_template_value_param:
//case DwarfConstants.DW_TAG_thrown_type:
//case DwarfConstants.DW_TAG_try_block:
case DwarfConstants.DW_TAG_volatile_type:
case DwarfConstants.DW_TAG_subrange_type:
return true;
}
return false;
}
/**
* Tell if a tag is a parsed child of an IType. This should not be explicitly
* referenced in provider.typesByOffset or .forwardDwarfDefinitions but as
* children of other ForwardDwarfDefinitions parsed on demand.
*<p>
* Note: DW_TAG_member is usually considered a child of struct/class/etc., but
* a static class variable contains a reference to it, so we must be able to
* locate it. Thus, it is not listed here.
* @param tag
* @return true if component is parsed and a child of a forward definition
*/
private boolean isForwardTypeChildTag(short tag) {
switch (tag) {
//case DwarfConstants.DW_TAG_unspecified_parameters:
case DwarfConstants.DW_TAG_inheritance:
case DwarfConstants.DW_TAG_enumerator:
case DwarfConstants.DW_TAG_member:
case DwarfConstants.DW_TAG_subrange_type:
//case DwarfConstants.DW_TAG_friend:
//case DwarfConstants.DW_TAG_template_type_param:
//case DwarfConstants.DW_TAG_template_value_param:
//case DwarfConstants.DW_TAG_thrown_type:
return true;
}
return false;
}
/**
* Fully parse any debug info entry.
* @param offset
* @param entry
* @param attributeList
* @param header
* @param compositeNesting
*/
private void processDebugInfoEntry(long offset, AbbreviationEntry entry, AttributeList attributeList,
CompilationUnitHeader header) {
//System.out.println("Handling " + entry.tag + " at " + Long.toHexString(offset));
short tag = entry.tag;
// We are only interested in certain tags.
switch (tag) {
case DwarfConstants.DW_TAG_array_type:
processArrayType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_class_type:
processClassType(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_enumeration_type:
processEnumType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_formal_parameter:
processVariable(offset, attributeList, true);
break;
case DwarfConstants.DW_TAG_lexical_block:
processLexicalBlock(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_member:
processField(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_pointer_type:
processPointerType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_reference_type:
processReferenceType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_structure_type:
processStructType(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_subroutine_type:
processSubroutineType(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_typedef:
processTypeDef(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_union_type:
processUnionType(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_unspecified_parameters:
break;
case DwarfConstants.DW_TAG_inheritance:
processInheritance(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_ptr_to_member_type:
processPtrToMemberType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_with_stmt:
break;
case DwarfConstants.DW_TAG_base_type:
processBasicType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_catch_block:
break;
case DwarfConstants.DW_TAG_const_type:
processConstType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_enumerator:
processEnumerator(offset, attributeList);
break;
case DwarfConstants.DW_TAG_file_type:
break;
case DwarfConstants.DW_TAG_friend:
break;
case DwarfConstants.DW_TAG_subprogram:
processSubprogram(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_inlined_subroutine:
processInlinedSubroutine(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_template_type_param:
processTemplateTypeParam(offset, attributeList, header, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_template_value_param:
break;
case DwarfConstants.DW_TAG_thrown_type:
break;
case DwarfConstants.DW_TAG_try_block:
break;
case DwarfConstants.DW_TAG_variable:
processVariable(offset, attributeList, false);
break;
case DwarfConstants.DW_TAG_volatile_type:
processVolatileType(offset, attributeList, entry.hasChildren);
break;
case DwarfConstants.DW_TAG_subrange_type:
processArrayBoundType(offset, attributeList, entry.hasChildren);
break;
}
}
/**
* Tell whether a tag has or may have content with an address range
*
* Note: tag DW_TAG_compile_unit was parsed in the initial parse
*
* @param tag
* @return
*/
private boolean isDebugInfoEntryWithAddressRange(short tag) {
switch (tag) {
// tags allowed to have both DW_AT_low_pc and DW_AT_high_pc or DW_at_ranges
case DwarfConstants.DW_TAG_catch_block:
case DwarfConstants.DW_TAG_inlined_subroutine:
case DwarfConstants.DW_TAG_lexical_block:
case DwarfConstants.DW_TAG_module:
case DwarfConstants.DW_TAG_partial_unit:
case DwarfConstants.DW_TAG_subprogram:
case DwarfConstants.DW_TAG_try_block:
case DwarfConstants.DW_TAG_with_stmt:
return true;
// TODO: take DW_TAG_variable out of here?
case DwarfConstants.DW_TAG_variable:
case DwarfConstants.DW_TAG_formal_parameter:
return true;
}
return false;
}
static long readAddress(IStreamBuffer in, int addressSize) throws IOException {
long value = 0;
switch (addressSize) {
case 2:
value = in.getShort();
break;
case 4:
value = in.getInt();
break;
case 8:
value = in.getLong();
break;
default:
// ????
}
return value;
}
/* unsigned */
static long read_unsigned_leb128(IStreamBuffer in) throws IOException {
/* unsigned */
long result = 0;
int shift = 0;
byte b;
while (true) {
if (!in.hasRemaining())
break; // throw new IOException("no more data");
b = in.get();
result |= ((long) (b & 0x7f) << shift);
if ((b & 0x80) == 0) {
break;
}
shift += 7;
}
return result;
}
/* signed */
public static long read_signed_leb128(IStreamBuffer in) throws IOException {
/* unsigned */
long result = 0;
int shift = 0;
int size = 32;
byte b;
while (true) {
if (!in.hasRemaining())
throw new IOException(CCorePlugin.getResourceString("Util.exception.noData")); //$NON-NLS-1$
b = in.get();
result |= ((long) (b & 0x7f) << shift);
shift += 7;
if ((b & 0x80) == 0) {
break;
}
}
if ((shift < size) && (b & 0x40) != 0) {
result |= -(1 << shift);
}
return result;
}
/**
* Read a null-ended string from the given "data" stream. data : IN, byte
* buffer
*/
public static String readString(IStreamBuffer data) {
String str;
StringBuilder sb = new StringBuilder();
while (data.hasRemaining()) {
byte c = data.get();
if (c == 0) {
break;
}
sb.append((char) c);
}
str = sb.toString();
return str;
}
private Collection<LocationEntry> getLocationRecord(long offset) {
// first check the cache
Collection<LocationEntry> entries = locationEntriesByOffset.get(offset);
if (entries == null) {
// not found so try to get the entries from the offset
// note: some compilers generate MULTIPLE ENTRIES for the same location,
// and the last one tends to be more correct... use a map here when reading
TreeMap<IRangeList.Entry, LocationEntry> entryMap = new TreeMap<IRangeList.Entry, LocationEntry>();
try {
IStreamBuffer data = getDwarfSection(DWARF_DEBUG_LOC);
if (data != null) {
data.position(offset);
boolean first = true;
long base = 0;
while (data.hasRemaining()) {
long lowPC = readAddress(data, currentCUHeader.addressSize);
long highPC = readAddress(data, currentCUHeader.addressSize);
if (lowPC == 0 && highPC == 0) {
// end of list entry
break;
} else if (first) {
first = false;
long maxaddress = currentCUHeader.addressSize == 4 ? Integer.MAX_VALUE : Long.MAX_VALUE;
if (lowPC == maxaddress) {
// base address selection entry
base = highPC;
continue;
} else if (currentCompileUnitScope.getRangeList() == null) {
// if the compilation unit has a contiguous range, no implicit base is needed
base = currentCompileUnitScope.getLowAddress().getValue().longValue();
}
}
// location list entry
int numOpCodes = data.getShort();
byte[] bytes = new byte[numOpCodes];
data.get(bytes);
LocationEntry entry = new LocationEntry(lowPC + base, highPC + base, bytes);
entryMap.put(new IRangeList.Entry(lowPC + base, highPC + base), entry);
}
entries = entryMap.values();
locationEntriesByOffset.put(offset, entries);
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(null, t);
}
}
return entries;
}
private Map<Long, AbbreviationEntry> parseDebugAbbreviation(int abbreviationOffset) throws IOException {
Integer key = Integer.valueOf(abbreviationOffset);
Map<Long, AbbreviationEntry> abbrevs = provider.abbreviationMaps.get(key);
if (abbrevs == null) {
abbrevs = new HashMap<Long, AbbreviationEntry>();
provider.abbreviationMaps.put(key, abbrevs);
IStreamBuffer data = getDwarfSection(DWARF_DEBUG_ABBREV);
if (data != null) {
data.position(abbreviationOffset);
while (data.remaining() > 0) {
long code = read_unsigned_leb128(data);
if (code == 0) {
break;
}
short tag = (short) read_unsigned_leb128(data);
boolean hasChildren = data.get() == DwarfConstants.DW_CHILDREN_yes;
AbbreviationEntry entry = new AbbreviationEntry(code, tag, hasChildren);
// attributes
short name = 0;
byte form = 0;
do {
name = (short) read_unsigned_leb128(data);
form = (byte) read_unsigned_leb128(data);
if (name != 0) {
entry.attributes.add(new Attribute(name, form));
}
} while (name != 0 && form != 0);
entry.attributes.trimToSize();
abbrevs.put(Long.valueOf(code), entry);
}
}
}
return abbrevs;
}
private void registerType(long offset, IType type, boolean hasChildren) {
provider.typesByOffset.put(offset, type);
provider.referenceTypesByOffset.remove(offset);
typeToParentMap.put(type, currentParentType);
if (hasChildren)
currentParentType = type;
if (DEBUG) {
if (type != null) {
System.out.print(DwarfMessages.DwarfInfoReader_ReadType + type.getName());
while (type.getType() != null) {
type = type.getType();
System.out.print(" " + type.getName()); //$NON-NLS-1$
}
System.out.println();
}
}
}
private void registerScope(long offset, Scope scope) {
provider.scopesByOffset.put(offset, scope);
}
/**
* Read a range list referenced from a code scope.
* @param offset
* @param base the specified DW_AT_low_pc value (or 0)
* @return a new RangeList
*/
public RangeList readRangeList(int offset, AttributeValue baseValue) {
synchronized (provider) {
IStreamBuffer data = getDwarfSection(DWARF_DEBUG_RANGES);
if (data == null) {
return null;
}
try {
data.position(offset);
/*
* Read range list entry:
*
* start: DW_FORM_addr
* end: DW_FORM_addr
*
* When start == all ones, it is a base address selection entry,
* and end is the base address. The base address does not need to
* be specified, and is the compialtion unit's base address by default.
*
* When start == end == 0, this is the end of the list.
*/
RangeList list = new RangeList();
//Whether the list actually got anything added - otherwise we should return null
boolean listAddedTo = false;
long base = 0;
long start = data.getInt();
long end = data.getInt();
if (start == -1) {
base = end;
start = data.getInt();
end = data.getInt();
} else if (baseValue != null) {
base = baseValue.getValueAsLong();
} else if (currentCompileUnitScope != null && currentCompileUnitScope.getRangeList() == null) {
base = currentCompileUnitScope.getLowAddress().getValue().longValue();
}
do {
if (start == 0 && end == 0) {
break;
} else if (start != end) {
// ignore bogus entries: GCC-E sometimes generates these buggily (for artifical non-inlined functions)
if (base + start >= codeRanges.getLowAddress()) {
list.addRange(base + start, base + end);
listAddedTo = true;
}
}
start = data.getInt();
end = data.getInt();
} while (true);
return (listAddedTo) ? list : null;
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_RangeReadFailed, t);
return null;
}
}
}
/**
* Set up the address range for a scope by using its DW_AT_low_pc/DW_AT_high_pc
* or DW_AT_ranges attributes, or DW_AT_stmt_list in a pinch
* @param attributeList
* @param scope
*/
private void setupAddresses(AttributeList attributeList, Scope scope) {
// get the high and low pc from the attributes list
AttributeValue value
= attributeList.getAttribute(DwarfConstants.DW_AT_high_pc);
if (value != null) {
IAddress low = new Addr32(attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_low_pc));
scope.setLowAddress(low);
IAddress high = new Addr32(attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_high_pc));
IScope parent = scope.getParent();
if (low.compareTo(high) <= 0) {
if (parent instanceof DwarfFunctionScope) {
IAddress parentHigh = parent.getHighAddress();
if (parentHigh != null && high.compareTo(parentHigh) > 0) {
((Scope)parent).setHighAddress(high);
}
}
} else {
// relying on the following to confirm that this is an RVCT inline DWARF generation bug
if (scope instanceof DwarfFunctionScope && parent instanceof DwarfFunctionScope) {
high = fix_Dwarf_InlineHighAddress_Problem(scope);
if (high == null)
// at least prevent ecl.bz Bug 329324 from happening
high = parent.getHighAddress();
// wow, RVCT, you're neat... I think you mean, point to the high PC of the parent
} else if (parent != null && parent.getHighAddress() != null) {
high = parent.getHighAddress();
// may still be bogus, check again next
}
if (low.compareTo(high) > 0) {
scope.setLowAddress(high);
high = low;
}
}
scope.setHighAddress(high);
return;
}
// look for a range
value = attributeList.getAttribute(DwarfConstants.DW_AT_ranges);
if (value != null) {
AttributeValue baseValue = attributeList.getAttribute(DwarfConstants.DW_AT_low_pc);
RangeList ranges = readRangeList(value.getValueAsInt(), baseValue);
if (ranges != null) {
scope.setRangeList(ranges);
// if the range list high and low pc extend outside the parent's
// high/low range, adjust the parent (found in GCC-E)
if (ranges.getLowAddress() < scope.getParent().getLowAddress().getValue().longValue()) {
if (scope.getParent() instanceof Scope)
((Scope)scope.getParent()).setLowAddress(new Addr32(ranges.getLowAddress()));
}
if (ranges.getHighAddress() > scope.getParent().getHighAddress().getValue().longValue()) {
if (scope.getParent() instanceof Scope)
((Scope)scope.getParent()).setHighAddress(new Addr32(ranges.getHighAddress()));
}
return;
}
}
// in a CU, GCC-E may have only generated this, so we need to dig into the line table
if (scope instanceof ICompileUnitScope) {
value = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
if (value != null) {
RangeList ranges = new RangeList();
for (ILineEntry entry : ((ICompileUnitScope) scope).getLineEntries()) {
// ignore (for now) entries that seem far out of range
if (entry.getLowAddress().getValue().longValue() >= codeRanges.getLowAddress()) {
ranges.addRange(entry.getLowAddress().getValue().longValue(),
entry.getHighAddress().getValue().longValue());
}
}
scope.setRangeList(ranges);
scope.fixupRanges(provider.getBaseLinkAddress());
return;
}
}
// no code, apparently
scope.setLowAddress(new Addr32(0));
scope.setHighAddress(new Addr32(0));
}
/**
* for cases where the compiler generates an incorrect high-address,
* the line entry provider can give information about the current and
* subsequent lines within an inline.
* <br>
* caveats: this is not meant to handle nested broken inlines. the
* algorithm assumes
* - an outer inline nesting another inline will use set of ranges, not a high-low
* - an inline function will likely be in another file
* - if not, it will likely be prior to the function that inlines it
* - and if not, it will likely be more than 32 lines after the function that inlines it
* @param scope
* @return high address if determined, or null if prerequisites for finding it aren't met.
*/
private IAddress fix_Dwarf_InlineHighAddress_Problem(Scope scope) {
IAddress low = scope.getLowAddress();
IAddress highest = scope.getParent().getHighAddress();
Iterator<ILineEntry> lineEntries
= currentCompileUnitScope.getLineEntries().iterator();
ILineEntry entry = null;
do {
if (lineEntries.hasNext())
entry = lineEntries.next();
else
return null;
if (entry == null)
return null;
} while (low.compareTo(entry.getHighAddress()) > 0);
IAddress high = null;
IPath actualPath = entry.getFilePath(), otherPath = null;
int actualLine = entry.getLineNumber();
int thisLine = actualLine, lastLine = 0; // XXX false positive on uninitialized variable below causes needless initialization of lastLine = 0
boolean jumpedBack = false, jumpedAway = false;
OUTER:do {
IAddress nextHigh = entry.getHighAddress();
if (highest != null && nextHigh != null && highest.compareTo(nextHigh) < 0) {
nextHigh = entry.getLowAddress();
if (high == null || nextHigh.compareTo(high) < 0)
high = nextHigh;
break;
}
high = nextHigh;
if (!jumpedAway && otherPath == null)
lastLine = thisLine;
if (high == null)
break OUTER;
do {
if (lineEntries.hasNext())
entry = lineEntries.next();
else
return null;
if (entry == null)
break OUTER;
} while (high.equals(entry.getHighAddress()));
if (otherPath != null) {
if (entry.getFilePath().equals(actualPath)) // done with nesting
break;
} else if (!entry.getFilePath().equals(actualPath)) {// easiest test for done with inline
otherPath = entry.getFilePath();
} else {
thisLine = entry.getLineNumber();
if (!jumpedBack && !jumpedAway) {
if (thisLine < actualLine) {
jumpedBack = true;
} else if (thisLine > lastLine + 24) { // XXX false positive here causes needless init of lastLine = 0 above
jumpedAway = true;
}
} else if (jumpedBack) {
if (thisLine > actualLine) // jumped back ahead; done
break;
} else if (jumpedAway) {
if (thisLine < actualLine
|| thisLine < lastLine
|| thisLine > lastLine + 24)
break;
}
}
} while (entry != null);
return high;
}
/**
* Process a compile unit
*
* @param attributeList
* @param childrenPosition
*/
private void processCompileUnit(CompilationUnitHeader header, boolean hasChildren, AttributeList attributeList) {
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
String compDir = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_comp_dir);
//System.out.println("processing compile unit: " + Integer.toHexString(header.debugInfoOffset) + ": " + name);
IPath filePath = fileHelper.normalizeFilePath(compDir, name);
currentCompileUnitScope = new DwarfCompileUnit(provider, moduleScope, filePath, null, null, header, hasChildren, attributeList);
header.scope = currentCompileUnitScope;
currentParentScope = currentCompileUnitScope;
// Needs to be registered before setupAddresses.
provider.registerCompileUnitHeader(currentCUHeader.debugInfoOffset, currentCUHeader);
setupAddresses(attributeList, currentCompileUnitScope);
// some compilers (RVCT) may generate multiple compile units for the
// same file.
List<ICompileUnitScope> matchingCompileUnits = provider.compileUnitsPerFile.get(filePath);
if (matchingCompileUnits == null) {
// first one. create it now.
matchingCompileUnits = new ArrayList<ICompileUnitScope>();
}
matchingCompileUnits.add(currentCompileUnitScope);
provider.compileUnitsPerFile.put(filePath, matchingCompileUnits);
provider.compileUnits.add(currentCompileUnitScope);
if (!currentCompileUnitScope.getHighAddress().isZero()) // has code
provider.sortedCompileUnitsWithCode.add(currentCompileUnitScope);
moduleScope.addChild(currentCompileUnitScope);
if (provider.buildReferencedFilesList) {
provider.referencedFiles.add(filePath.toOSString());
// do a quick parse of the line table to get any other referenced files.
// note that even the full parse doesn't parse the line table information.
// that is calculated (and then cached) on demand
AttributeValue a = attributeList.getAttribute(DwarfConstants.DW_AT_stmt_list);
if (a != null) {
int stmtList = a.getValueAsInt();
quickParseLineInfo(stmtList, compDir);
}
}
// remove unused attributes
attributeList.attributeMap.remove(DwarfConstants.DW_AT_name);
//attributeList.attributeMap.remove(DwarfConstants.DW_AT_comp_dir); // needed later
attributeList.attributeMap.remove(DwarfConstants.DW_AT_low_pc);
attributeList.attributeMap.remove(DwarfConstants.DW_AT_high_pc);
attributeList.attributeMap.remove(DwarfConstants.DW_AT_ranges);
}
private void processLexicalBlock(long offset, AttributeList attributeList, boolean hasChildren) {
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
if (!attributeList.hasCodeRangeAttributes()) {
// ignore any that don't have a valid range
return;
}
LexicalBlockScope lb = new LexicalBlockScope(name, currentParentScope, null, null);
setupAddresses(attributeList, lb);
currentParentScope.addChild(lb);
registerScope(offset, lb);
if (hasChildren)
currentParentScope = lb;
}
static class DereferencedAttributes {
public CompilationUnitHeader header;
public AttributeList attributeList;
public DereferencedAttributes(CompilationUnitHeader header,
AttributeList attributeList) {
this.header = header;
this.attributeList = attributeList;
}
}
/**
* DW_AT_abstract_origin and DW_AT_specification can refer to types in other
* compilation units. This will dynamically parse that CU if needed in order
* to get the attributes for the type.
*
* @param debugInfoOffset
* @return AttributeList or <code>null</code> (should not happen)
*/
private DereferencedAttributes getDereferencedAttributes(AttributeList attributeList, short tag) {
CompilationUnitHeader providingCU = currentCUHeader;
AttributeValue derefLocation = attributeList.getAttribute(tag);
if (derefLocation == null)
return null;
// get the offset into the .debug_info section
long debugInfoOffset = derefLocation.getValueAsLong();
if (derefLocation.getActualForm() == DwarfConstants.DW_FORM_ref_addr) {
// this is already relative to the .debug_info section
} else {
// relative to the CU
debugInfoOffset += providingCU.debugInfoOffset;
}
AttributeList attributes = provider.functionsByOffset.get(debugInfoOffset);
if (attributes == null) {
// dereferenced function does not exist yet
providingCU = provider.fetchCompileUnitHeader(debugInfoOffset);
attributes = provider.functionsByOffset.get(debugInfoOffset);
if (attributes == null) {
// dereferenced entry is not parsed yet, perhaps because it's
// later in the current compile unit (despite Dwarf 3 spec saying
// that's not allowed)
IStreamBuffer buffer = getDwarfSection(DWARF_DEBUG_INFO);
if (buffer != null) {
buffer.position(debugInfoOffset);
try {
// get stored abbrev table, or read and parse an abbrev table
Map<Long, AbbreviationEntry> abbrevs = parseDebugAbbreviation(providingCU.abbreviationOffset);
long code = read_unsigned_leb128(buffer);
if (code != 0) {
AbbreviationEntry entry = abbrevs.get(new Long(code));
if (entry != null) {
attributes = new AttributeList(entry, buffer, providingCU.addressSize, getDebugStrings());
}
}
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed1
+ debugInfoSection.getName() + DwarfMessages.DwarfInfoReader_ParseDebugInfoSectionFailed2 + symbolFilePath, t);
}
}
}
} else {
providingCU = provider.fetchCompileUnitHeader(debugInfoOffset);
if (providingCU == null) {
assert(false);
return null;
}
}
if (attributes == null)
return null;
return new DereferencedAttributes(providingCU, attributes);
}
private void processSubprogram(long offset, AttributeList attributeList, boolean hasChildren) {
// if it's a declaration just add to the offsets map for later lookup
if (attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_declaration) > 0) {
provider.functionsByOffset.put(offset, attributeList);
return;
}
// functions with no high/low pc aren't real functions. just treat them
// as declarations as they will be pointed to by abstract_origin from
// another subprogram tag
if (!attributeList.hasCodeRangeAttributes()) {
provider.functionsByOffset.put(offset, attributeList);
return;
}
CompilationUnitHeader otherCU = null;
boolean isArtificial = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_artificial) > 0;
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
if (name.length() == 0) {
// no name. see if we can get it from a declaration
DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin);
if (deref != null) {
// this should either have a name or point to another
// declaration
otherCU = deref.header;
AttributeList attributes = deref.attributeList;
name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
isArtificial |= attributes.getAttributeValueAsInt(DwarfConstants. DW_AT_artificial) > 0;
if (name.length() == 0) {
deref = getDereferencedAttributes(attributes, DwarfConstants.DW_AT_specification);
if (deref != null) {
// this should either have a name or point to another
// declaration
otherCU = deref.header;
attributes = deref.attributeList;
name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
isArtificial |= attributes.getAttributeValueAsInt(DwarfConstants. DW_AT_artificial) > 0;
}
}
}
}
if (name.length() == 0) {
DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_specification);
if (deref != null) {
// this should either have a name or point to another
// declaration
otherCU = deref.header;
AttributeList attributes = deref.attributeList;
name = attributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
}
}
if (name.length() == 0) {
// the name should either be an attribute of the compile unit, or be
// in the declaration which according to the spec will always be
// before its definition in the Dwarf.
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_SubprogramNameNotFound1 + Long.toHexString(offset) +
DwarfMessages.DwarfInfoReader_SubprogramNameNotFound2, null);
return;
}
DwarfFunctionScope function = new DwarfFunctionScope(name, currentCompileUnitScope, null, null, null);
setupAddresses(attributeList, function);
Scope originalParentScope = currentParentScope;
registerScope(offset, function);
currentParentScope = function; // needed for getLocationProvider(), etc.
AttributeValue frameBaseAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_frame_base);
ILocationProvider locationProvider = getLocationProvider(frameBaseAttribute);
function.setLocationProvider(locationProvider);
// Note: we may still have cases where DW_AT_low_pc and/or DW_AT_high_pc are 0x0
// (some "ignored inlined" functions in GCC). We want to keep track of their scope
// (though not store them in the CU), because child tag parses expect to find a parent into
// which to write their formal parameters and locals.
if (!function.getLowAddress().isZero() && !function.getHighAddress().isZero() && !isArtificial) {
// find the declaration location
int declLine = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_line);
int declColumn = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_column);
int declFileNum = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
if (otherCU != null)
function.setDeclFile(otherCU.scope.getFileEntry(declFileNum));
else
function.setDeclFileNum(declFileNum);
function.setDeclLine(declLine);
function.setDeclColumn(declColumn);
currentCompileUnitScope.addChild(function);
// keep track of all functions by name for faster lookup
List<IFunctionScope> functions = provider.functionsByName.get(name);
if (functions == null) {
functions = new ArrayList<IFunctionScope>();
provider.functionsByName.put(name, functions);
}
functions.add(function);
}
// if the entry has no children, then restore the original parent scope
if (!hasChildren)
currentParentScope = originalParentScope;
}
/**
* Get the already-parsed or forward reference to a type from a DW_AT_type attribute, if present
* @param attributeMap the map of Long, AttributeValue from AttributeList or Object, Object from Type
* @return offset to referenced type or 0 if no type attribute
*/
private IType getTypeOrReference(AttributeList attributeList, CompilationUnitHeader header) {
AttributeValue typeAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_type);
if (typeAttribute == null)
return null;
return getTypeOrReference(typeAttribute, header);
}
/**
* Get the already-parsed or forward reference to a type from a DW_AT_type attribute, if present
* @param attributeMap the map of Long, AttributeValue from AttributeList or Object, Object from Type
* @return offset to referenced type or 0 if no type attribute
*/
private IType getTypeOrReference(AttributeValue typeAttribute, CompilationUnitHeader header) {
if (typeAttribute == null)
return null;
// get the offset into the .debug_info section
long debugInfoOffset = typeAttribute.getValueAsLong();
if (typeAttribute.getActualForm() == DwarfConstants.DW_FORM_ref_addr) {
// this is already relative to the .debug_info section
} else {
debugInfoOffset += header.debugInfoOffset;
}
IType type = provider.typesByOffset.get(debugInfoOffset);
if (type == null) {
// So that we only create one ForwardTypeReference per type we want to reference.
IForwardTypeReference refType = provider.referenceTypesByOffset.get(debugInfoOffset);
if (type == null) {
refType = new ForwardTypeReference(provider, debugInfoOffset);
provider.referenceTypesByOffset.put(Long.valueOf(debugInfoOffset), refType);
}
type = refType;
}
return type;
}
private void processInlinedSubroutine(long offset, AttributeList attributeList, boolean hasChildren) {
// functions with no high/low pc aren't real (probably an error)
if (!attributeList.hasCodeRangeAttributes()) {
return;
}
DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin);
if (deref == null) {
if (attributeList.getAttribute(DwarfConstants.DW_AT_abstract_origin) != null) {
// TODO: GCC-E can reference forward tags (!) so we need to handle these another way
} else {
assert(false);
}
return;
}
CompilationUnitHeader otherCU = deref.header;
AttributeList origAttributes = deref.attributeList;
// this should either have a name or point to another
// declaration
String name = origAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
if (name.length() == 0) {
deref = getDereferencedAttributes(origAttributes, DwarfConstants.DW_AT_specification);
if (deref != null) {
// this should either have a name or point to another
// declaration
//otherCU = deref.header;
AttributeList declarationAttributes = deref.attributeList;
name = declarationAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
}
}
if (name.length() == 0) {
// the name should either be an attribute of the compile unit, or be
// in the declaration which according to the spec will always be
// before its definition in the Dwarf.
return;
}
// find the declaration location
int declLine = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_line);
int declColumn = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_column);
int declFileNum = origAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
if (declFileNum == 0) {
assert(false);
return;
}
DwarfFunctionScope function = new DwarfFunctionScope(name, currentParentScope, null, null, null);
setupAddresses(attributeList, function);
function.setDeclFile(otherCU.scope.getFileEntry(declFileNum));
function.setDeclLine(declLine);
function.setDeclColumn(declColumn);
currentParentScope.addChild(function);
registerScope(offset, function);
if (hasChildren)
currentParentScope = function;
// keep track of all functions by name for faster lookup
List<IFunctionScope> functions = provider.functionsByName.get(name);
if (functions == null) {
functions = new ArrayList<IFunctionScope>();
provider.functionsByName.put(name, functions);
}
functions.add(function);
}
private void processSubroutineType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
SubroutineType type = new SubroutineType(currentParentScope, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
// TODO: associate parameters with this type in child tag parse
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processClassType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// if the name is mangled, unmangle it
name = unmangleType(name);
// GCC may put the template parameter of an inherited class at the end of the name,
// so strip that off
// TODO: support template parameters at end of name or as separate DW_TAG_template_value_param
if (name.endsWith(">")) {
int templateStart = name.indexOf("<");
if (templateStart != -1)
name = name.substring(0, templateStart);
}
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
ClassType type = new ClassType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processStructType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// if the name is mangled, unmangle it
name = unmangleType(name);
StructType type = new StructType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processUnionType(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// if the name is mangled, unmangle it
name = unmangleType(name);
UnionType type = new UnionType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
/*
* For an anonymous union, which has members accessible by methods in a class, ARM RVCT
* does not create an unnamed class member so you know the offset of the union's members.
* Instead, it just gives the anonymous union's type a name of the form "__C" followed
* by a number. And it places the union's DWARF info after all class member and inherited
* member DWARF info.
*
* E.g., when you have 2 named members and 2 anonymous unions in this order:
* 4-byte union <anonymous 1>
* 4-byte long long1
* 4-byte union <anonymous 2>
* 4-byte long long2
* ARM RVCT DWARF info says the class has 2 members:
* long1 at offset 4
* long2 at offset 12
* ARM RVCT DWARF info is in the order:
* member long1
* member long2
* type union <anonymous 1>
* type union <anonymous 2>
* So the rules for handling anonymous unions in RVCT DWARF are:
* 1st read offsets and sizes of non-anonymous members, which leaves offset holes
* for anonymous unions
* 2nd read anonymous union type info, which have compiler-generated names of
* "__C" following by a number, and assign unnamed members to offset holes
*/
boolean isRVCTAnonymousUnion = false;
try {
isRVCTAnonymousUnion = name.startsWith("__C") && (name.length() > 3) && //$NON-NLS-1$
(name.charAt(3) != '-') && (Long.parseLong(name.substring(3)) > -1);
} catch (NumberFormatException nfe) {}
// if needed, create an "unnamed" member field with an offset to be determined later
if (isRVCTAnonymousUnion && getCompositeParent(typeToParentMap.get(currentParentType)) != null) {
ICompositeType compositeType = getCompositeParent(typeToParentMap.get(currentParentType));
// unnamed member accessibility depends on the enclosing composite's type -
// public for a struct or union, private for a class
int accessibility = ICompositeType.ACCESS_PUBLIC;
if (compositeType instanceof ClassType)
accessibility = ICompositeType.ACCESS_PRIVATE;
// empty field names confuse the expressions service
String fieldName = "$unnamed$" + (compositeType.fieldCount() + 1); //$NON-NLS-1$
// since we're generating a field, give it a -1 offset. We cannot tell the real
// offset until we determine offsets of all previously defined members - which
// may include inherited types not yet read in Dwarf info
FieldType fieldType = new FieldType(fieldName, currentParentScope, compositeType, -1, 0, 0,
byteSize, accessibility, null);
fieldType.setType(type);
// add the member to the deepest nested (last added) compositeNesting
// member
compositeType.addField(fieldType);
registerType(offset, fieldType, false);
}
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processInheritance(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
ICompositeType compositeType = getCompositeParent();
// The allowed attributes are DW_AT_type, DW_AT_data_member_location,
// and DW_AT_accessibility
long fieldsOffset = 0;
byte[] offsetBlock = attributeList.getAttributeValueAsBytes(DwarfConstants.DW_AT_data_member_location);
// unsigned LEB128 encoding
if (offsetBlock.length > 0 && offsetBlock[0] == DwarfConstants.DW_OP_plus_uconst) {
for (int i = 1, shift = 0; i < offsetBlock.length; i++) {
fieldsOffset += (offsetBlock[i] & 0x7f) << shift;
shift += 7;
}
}
// default accessibility is private
int accessibility = ICompositeType.ACCESS_PRIVATE;
if (attributeList.getAttribute(DwarfConstants.DW_AT_accessibility) != null) {
accessibility = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_accessibility);
if (accessibility == DwarfConstants.DW_ACCESS_public)
accessibility = ICompositeType.ACCESS_PUBLIC;
else if (accessibility == DwarfConstants.DW_ACCESS_private)
accessibility = ICompositeType.ACCESS_PRIVATE;
else
accessibility = ICompositeType.ACCESS_PROTECTED;
}
InheritanceType type = new InheritanceType(currentParentScope, accessibility, fieldsOffset, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
// add the member to the deepest nested (last added) compositeNesting
// member
if (compositeType != null)
compositeType.addInheritance(type);
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processField(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// GCC-E has fields like "_vptr.BaseClass" which will be a problem for us
// (since '.' is an operator); rename these here
name = name.replace('.', '$');
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
int bitSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_bit_size);
int bitOffset = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_bit_offset);
long fieldOffset = 0;
byte[] offsetBlock = attributeList.getAttributeValueAsBytes(DwarfConstants.DW_AT_data_member_location);
// unsigned LEB128 encoding
if (offsetBlock.length > 0 && offsetBlock[0] == DwarfConstants.DW_OP_plus_uconst) {
for (int i = 1, shift = 0; i < offsetBlock.length; i++) {
fieldOffset += (offsetBlock[i] & 0x7f) << shift;
shift += 7;
}
}
ICompositeType compositeType = getCompositeParent();
// default accessibility depends on the composite type -
// public for a struct or union, private for a class
int accessibility = ICompositeType.ACCESS_PUBLIC;
if (attributeList.getAttribute(DwarfConstants.DW_AT_accessibility) != null) {
accessibility = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_accessibility);
if (accessibility == DwarfConstants.DW_ACCESS_public)
accessibility = ICompositeType.ACCESS_PUBLIC;
else if (accessibility == DwarfConstants.DW_ACCESS_private)
accessibility = ICompositeType.ACCESS_PRIVATE;
else
accessibility = ICompositeType.ACCESS_PROTECTED;
} else if (compositeType != null && compositeType instanceof ClassType)
accessibility = ICompositeType.ACCESS_PRIVATE;
// Empty fields confuse the expressions service (#10369)
if (name.length() == 0) {
if (compositeType != null) {
name = "$unnamed$" + (compositeType.fieldCount() + 1); //$NON-NLS-1$
} else {
name = "$unnamed$"; //$NON-NLS-1$
}
}
FieldType type = new FieldType(name, currentParentScope, compositeType, fieldOffset, bitSize, bitOffset,
byteSize, accessibility, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
// add the member to the deepest nested (last added) compositeNesting
// member
if (compositeType != null)
compositeType.addField(type);
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processTemplateTypeParam(long offset, AttributeList attributeList, CompilationUnitHeader header, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
IType paramType = getTypeOrReference(attributeList.getAttribute(DwarfConstants.DW_AT_type), currentCUHeader);
TemplateParamType type = new TemplateParamType(name, paramType);
ICompositeType compositeType = getCompositeParent();
// add the template param to the deepest nested (last added) compositeNesting
// member
if (compositeType != null)
compositeType.addTemplateParam(type);
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private ICompositeType getCompositeParent() {
return getCompositeParent(currentParentType);
}
private ICompositeType getCompositeParent(IType parent) {
while (parent != null) {
if (parent instanceof ICompositeType)
return ((ICompositeType) parent);
parent = typeToParentMap.get(parent);
}
return null;
}
private void processArrayType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
ArrayType type = new ArrayType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private IArrayType getArrayParent() {
IType parent = currentParentType;
while (parent != null) {
if (parent instanceof IArrayType)
return ((IArrayType) parent);
parent = typeToParentMap.get(parent);
}
return null;
}
private void processArrayBoundType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
long arrayBound = 0;
if (attributeList.getAttribute(DwarfConstants.DW_AT_upper_bound) != null)
arrayBound = attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_upper_bound) + 1;
ArrayBoundType type = new ArrayBoundType(currentParentScope, arrayBound);
IArrayType array = getArrayParent();
if (array == null)
throw new IllegalStateException();
array.addBound(type);
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processReferenceType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
if (byteSize == 0)
byteSize = currentCUHeader.addressSize;
ReferenceType type = new ReferenceType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processPointerType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
if (byteSize == 0)
byteSize = currentCUHeader.addressSize;
PointerType type = new PointerType(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReferenceOrVoid(attributeList));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processPtrToMemberType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// unnamed data types don't get stored by name
if (name.length() == 0)
name = "" + offset;
PointerType type = new PointerType(name, currentParentScope, currentCUHeader.addressSize, null);
type.setType(getTypeOrReferenceOrVoid(attributeList));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processConstType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
ConstType type = new ConstType(currentParentScope, null);
type.setType(getTypeOrReferenceOrVoid(attributeList));
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processVolatileType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
VolatileType type = new VolatileType(currentParentScope, null);
type.setType(getTypeOrReferenceOrVoid(attributeList));
registerType(offset, type, hasChildren);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
// for void pointers, GCC will produce qualifiers and pointers without types or references,
// so create a void to be qualified or pointed to
private IType getTypeOrReferenceOrVoid(AttributeList attributeList) {
IType typeOrReference = getTypeOrReference(attributeList, currentCUHeader);
if (typeOrReference != null)
return typeOrReference;
if (moduleScope != null && voidType == null) {
voidType = new CPPBasicType("void", moduleScope, IBasicType.t_void, 0, 0, null);
}
if (voidType != null)
return voidType;
return new CPPBasicType("void", currentParentScope, IBasicType.t_void, 0, 0, null);
}
private void processEnumType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// if the name is mangled, unmangle it
name = unmangleType(name);
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
Enumeration type = new Enumeration(name, currentParentScope, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private Enumeration getEnumerationParent() {
IType parent = currentParentType;
while (parent != null) {
if (parent instanceof Enumeration)
return ((Enumeration) parent);
parent = typeToParentMap.get(parent);
}
return null;
}
private void processEnumerator(long offset, AttributeList attributeList) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
if (unmangler.isMangled(name)) {
try {
name = unmangler.unmangle(name);
} catch (UnmanglingException ue) {
}
}
long value = attributeList.getAttributeValueAsSignedLong(DwarfConstants.DW_AT_const_value);
Enumerator enumerator = new Enumerator(name, value);
Enumeration enumeration = getEnumerationParent();
if (enumeration == null)
throw new IllegalStateException();
enumeration.addEnumerator(enumerator);
((Scope)enumeration.getScope()).addEnumerator(enumerator);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(enumerator)); }
}
private void processTypeDef(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
// if the name is mangled, unmangle it
name = unmangleType(name);
TypedefType type = new TypedefType(name, currentParentScope, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processBasicType(long offset, AttributeList attributeList, boolean hasChildren) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(offset)); }
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
int byteSize = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_byte_size);
int baseType = IBasicType.t_unspecified;
int qualifierBits = 0;
int encoding = attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_encoding);
switch (encoding) {
case DwarfConstants.DW_ATE_boolean:
baseType = ICPPBasicType.t_bool;
break;
case DwarfConstants.DW_ATE_float:
if (name.contains("float")) { //$NON-NLS-1$
baseType = IBasicType.t_float;
} else if (name.contains("long double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
qualifierBits |= ICPPBasicType.IS_LONG;
} else if (name.contains("double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
}
break;
case DwarfConstants.DW_ATE_signed:
baseType = IBasicType.t_int;
qualifierBits |= ICPPBasicType.IS_SIGNED;
if (name.contains("short")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_SHORT;
} else if (name.contains("long long")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_LONG_LONG;
} else if (name.contains("long")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_LONG;
}
break;
case DwarfConstants.DW_ATE_signed_char:
baseType = IBasicType.t_char;
qualifierBits |= ICPPBasicType.IS_SIGNED;
break;
case DwarfConstants.DW_ATE_unsigned:
baseType = IBasicType.t_int;
qualifierBits |= ICPPBasicType.IS_UNSIGNED;
if (name.contains("short")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_SHORT;
} else if (name.contains("long long")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_LONG_LONG;
} else if (name.contains("long")) { //$NON-NLS-1$
qualifierBits |= ICPPBasicType.IS_LONG;
}
break;
case DwarfConstants.DW_ATE_unsigned_char:
baseType = IBasicType.t_char;
qualifierBits |= ICPPBasicType.IS_UNSIGNED;
break;
case DwarfConstants.DW_ATE_complex_float:
qualifierBits |= ICPPBasicType.IS_COMPLEX;
if (name.contains("float")) { //$NON-NLS-1$
baseType = IBasicType.t_float;
} else if (name.contains("long double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
qualifierBits |= ICPPBasicType.IS_LONG;
} else if (name.contains("double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
}
break;
case DwarfConstants.DW_ATE_imaginary_float:
qualifierBits |= ICPPBasicType.IS_IMAGINARY;
if (name.contains("float")) { //$NON-NLS-1$
baseType = IBasicType.t_float;
} else if (name.contains("long double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
qualifierBits |= ICPPBasicType.IS_LONG;
} else if (name.contains("double")) { //$NON-NLS-1$
baseType = IBasicType.t_double;
}
break;
case DwarfConstants.DW_ATE_void:
baseType = IBasicType.t_void;
break;
case DwarfConstants.DW_ATE_address:
case DwarfConstants.DW_ATE_packed_decimal:
case DwarfConstants.DW_ATE_numeric_string:
case DwarfConstants.DW_ATE_edited:
case DwarfConstants.DW_ATE_signed_fixed:
case DwarfConstants.DW_ATE_unsigned_fixed:
case DwarfConstants.DW_ATE_decimal_float:
default:
break;
}
// RVCT has interesting conceptions about "encoding" here. Be sure not to get confused later.
if (name.equals("void") && byteSize == 0) //$NON-NLS-1$
baseType = IBasicType.t_void;
CPPBasicType type = new CPPBasicType(name, currentParentScope, baseType, qualifierBits, byteSize, null);
type.setType(getTypeOrReference(attributeList, currentCUHeader));
registerType(offset, type, hasChildren);
storeTypeByName(name, type);
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(type)); }
}
private void processVariable(long offset, AttributeList attributeList, boolean isParameter) {
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceEntry(null, EDCTrace.fixArg(attributeList)); }
AttributeValue locationAttribute = attributeList.getAttribute(DwarfConstants.DW_AT_location);
ILocationProvider locationProvider = getLocationProvider(locationAttribute);
if (locationProvider == null) {
// No location means either this is a placeholder (in a subprogram declaration)
// or it may have been optimized out. See section
// 2.6 of the Dwarf3 spec. for now we're ignoring it but we may be able
// to show it in the view with some special decoration to indicate that
// it's been optimized out
// assume it is a forward reference if we're inside a function (formal_parameter or local)...
provider.functionsByOffset.put(offset, attributeList);
return;
}
// variables can have abstract origins with most of their contents
CompilationUnitHeader otherCU = currentCUHeader;
AttributeList otherAttributes = attributeList;
String name = attributeList.getAttributeValueAsString(DwarfConstants.DW_AT_name);
if (name.length() == 0) {
// no name.
// if there is a DW_AT_specification or DW_AT_abstract_origin attribute, use it to get variable attributes
DereferencedAttributes deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_specification);
if (deref == null)
deref = getDereferencedAttributes(attributeList, DwarfConstants.DW_AT_abstract_origin);
if (deref != null) {
// this should either have a name or point to another
// declaration
otherCU = deref.header;
otherAttributes = deref.attributeList;
name = otherAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_name);
}
}
boolean global = (otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_external) == 1);
// if the name is mangled, unmangle it
if (name.startsWith("_Z")) {
name = unmangle(name);
} else if (global) {
// GCCE uses DW_AT_MIPS_linkage_name for the mangled name of an externally visible variable
String mangledName = otherAttributes.getAttributeValueAsString(DwarfConstants.DW_AT_MIPS_linkage_name);
if (unmangler.isMangled(mangledName)) {
try {
name = unmangler.unmangle(mangledName);
} catch (UnmanglingException ue) {
}
}
}
IType type = getTypeOrReference(otherAttributes.getAttribute(DwarfConstants.DW_AT_type), otherCU);
if (type != null) {
long startScope = attributeList.getAttributeValueAsLong(DwarfConstants.DW_AT_start_scope);
boolean isDeclared = otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_artificial) <= 0;
int definingFileNum = otherAttributes.getAttributeValueAsInt(DwarfConstants.DW_AT_decl_file);
if (definingFileNum > 0 && attributeList.getAttributeValueAsInt(DwarfConstants.DW_AT_declaration) > 0) {
// variable is declared here, but not defined here
definingFileNum = 0;
}
IPath definingFile = null;
// find the file it's defined in
if (definingFileNum > 0) {
// find the enclosing compile unit to get access to its list of
// .debug_line file names
IScope cuScope = currentParentScope;
while (cuScope != null && !(cuScope instanceof DwarfCompileUnit))
cuScope = cuScope.getParent();
if (cuScope != null) {
definingFile = ((DwarfCompileUnit) cuScope).getFileEntry(definingFileNum);
}
}
DwarfVariable variable = new DwarfVariable(name,
global ? moduleScope : currentParentScope,
locationProvider,
type,
isDeclared,
definingFile);
variable.setStartScope(startScope);
if (isParameter) {
if (currentParentScope instanceof FunctionScope) {
((FunctionScope) currentParentScope).addParameter(variable);
} else {
assert (false);
}
} else {
if (global) {
// add global variables to the module scope
moduleScope.addVariable(variable);
// AND to the CU scope
if (currentCompileUnitScope != null) {
currentCompileUnitScope.addVariable(variable);
}
} else {
// the parent scope could be compile unit, function or
// lexical block
currentParentScope.addVariable(variable);
}
// keep track of all variables by name for faster lookup
List<IVariable> variables = provider.variablesByName.get(name);
if (variables == null) {
variables = new ArrayList<IVariable>();
provider.variablesByName.put(name, variables);
}
if (!variables.contains(variable)) {
variables.add(variable);
}
}
if (EDCTrace.SYMBOL_READER_VERBOSE_TRACE_ON) { EDCTrace.getTrace().traceExit(null, EDCTrace.fixArg(variable)); }
}
}
private ILocationProvider getLocationProvider(AttributeValue locationValue) {
if (locationValue != null) {
byte actualForm = locationValue.getActualForm();
if (actualForm == DwarfConstants.DW_FORM_data4) {
// location list
Collection<LocationEntry> entryList = getLocationRecord(locationValue.getValueAsLong());
if (entryList != null) {
return new LocationList(entryList.toArray(new LocationEntry[entryList.size()]),
exeReader.getByteOrder(),
currentCUHeader.addressSize, currentParentScope);
}
} else if (actualForm == DwarfConstants.DW_FORM_block
|| actualForm == DwarfConstants.DW_FORM_block1
|| actualForm == DwarfConstants.DW_FORM_block2
|| actualForm == DwarfConstants.DW_FORM_block4) {
// location expression
IStreamBuffer locationData = new MemoryStreamBuffer(locationValue.getValueAsBytes(), exeReader.getByteOrder());
return new LocationExpression(locationData,
currentCUHeader.addressSize,
currentParentScope);
} else {
// should not happen according to the spec
assert (false);
}
}
return null;
}
private void dumpSymbols() {
if (DEBUG) {
PrintStream out = null;
try {
out = new PrintStream(new File(dumpFileName));
} catch (FileNotFoundException e) {
System.out.println(DwarfMessages.DwarfInfoReader_DumpFileOpenOrCreateFailed + dumpFileName);
return;
}
// If to write to console
// PrintStream out = System.out;
out.println("Module - " + symbolFilePath);
out.println(" Variables - " + moduleScope.getVariables().size());
out.println(" Compile units - " + moduleScope.getChildren().size());
out.println();
for (IScope cu : moduleScope.getChildren()) {
out.println(" Compile unit - " + cu.toString());
out.println(" Variables - " + cu.getVariables().size());
out.println(" Functions - " + cu.getChildren().size());
out.println();
for (IScope func : cu.getChildren()) {
out.println(" Function - " + func.toString());
out.println(" Variables - " + func.getVariables().size());
out.println(" Parameters - " + ((IFunctionScope) func).getParameters().size());
out.println(" Lexical blocks - " + func.getChildren().size());
out.println();
// not accurate: can contain IFunctionScope too!
for (IScope block : func.getChildren()) {
out.println(" Lexical block - " + block.toString());
out.println(" Variables - " + block.getVariables().size());
out.println();
}
}
}
out.close();
}
}
public void parseForFrameIndices() {
synchronized (provider) {
if (!provider.frameDescEntries.isEmpty())
return;
IExecutableSection frameSection = exeReader.findExecutableSection(DWARF_DEBUG_FRAME);
if (frameSection == null)
return;
IStreamBuffer buffer = frameSection.getBuffer();
buffer.position(0);
int addressSize = 4; // TODO: 64-bit Dwarf
long cie_id = addressSize == 4 ? 0xffffffff : ~0L;
// in the first pass, just get a mapping of PC ranges to FDEs,
// so we can locate entries quickly (don't pre-parse CIEs or decompile FDE instructions yet)
while (buffer.position() < buffer.capacity()) {
try {
long fdePtr = buffer.position();
long headerLength = readAddress(buffer, addressSize);
long nextPosition = buffer.position() + headerLength;
long ciePtr = readAddress(buffer, addressSize);
if (ciePtr != cie_id) {
long initialLocation = readAddress(buffer, addressSize);
long addressRange = readAddress(buffer, addressSize);
IStreamBuffer instructions = buffer.wrapSubsection(nextPosition - buffer.position());
IRangeList.Entry entry = new IRangeList.Entry(initialLocation, initialLocation + addressRange);
FrameDescriptionEntry fde = new FrameDescriptionEntry(fdePtr, ciePtr,
entry.low, entry.high,
instructions, addressSize);
provider.frameDescEntries.put(entry, fde);
}
buffer.position(nextPosition);
} catch (Throwable t) {
EDCDebugger.getMessageLogger().logError(DwarfMessages.DwarfInfoReader_FrameIndicesReadFailed, t);
break;
}
}
}
}
/**
* Parse a CIE
* @param ciePtr
* @param addressSize
* @param framePC
* @return the CIE or <code>null</code> in case of error
*/
public CommonInformationEntry parseCommonInfoEntry(Long ciePtr, int addressSize, IAddress framePC) throws IOException {
synchronized (provider) {
IExecutableSection frameSection = exeReader.findExecutableSection(DWARF_DEBUG_FRAME);
if (frameSection == null)
return null;
IStreamBuffer buffer = frameSection.getBuffer();
buffer.position(ciePtr);
long headerLength = readAddress(buffer, addressSize);
if (headerLength > buffer.capacity()) {
assert(false);
return null;
}
long nextPosition = buffer.position() + headerLength;
/* cie_id = */ readAddress(buffer, addressSize);
byte version = buffer.get();
String augmentation = readString(buffer);
long codeAlignmentFactor = read_unsigned_leb128(buffer);
long dataAlignmentFactor = read_signed_leb128(buffer);
int returnAddressRegister = version < 3 ? buffer.get() & 0xff : (int) read_unsigned_leb128(buffer);
IStreamBuffer instructions = buffer.wrapSubsection(nextPosition - buffer.position());
String producer = null;
ICompileUnitScope cuScope = provider.getCompileUnitForAddress(framePC);
if (cuScope instanceof DwarfCompileUnit)
producer = ((DwarfCompileUnit) cuScope).getAttributeList().getAttributeValueAsString(DwarfConstants.DW_AT_producer);
return new CommonInformationEntry(codeAlignmentFactor, dataAlignmentFactor,
returnAddressRegister, version, instructions, addressSize,
producer, augmentation);
}
}
private void storeTypeByName(String name, IType type) {
if (name.length() == 0)
return;
// Don't store opaque types as they are not useful in user-defined
// type casting nor in opaque type resolution. And storing it would
// screw up opaque type resolution.
if (type instanceof ICompositeType && ((ICompositeType)type).isOpaque())
return;
List<IType> typeList = provider.typesByName.get(name);
if (typeList == null) {
typeList = new ArrayList<IType>();
// for a template, remove extra spaces and composite type names (e.g., "class")
if (name.indexOf('<') != -1) {
while (name.contains(" ")) //$NON-NLS-1$
name = name.replaceAll(" ", " "); //$NON-NLS-1$ //$NON-NLS-2$
name = name.replaceAll(", ", ","); //$NON-NLS-1$ //$NON-NLS-2$
name = name.replaceAll("class ", ""); //$NON-NLS-1$ //$NON-NLS-2$
name = name.replaceAll("struct ", ""); //$NON-NLS-1$ //$NON-NLS-2$
name = name.replaceAll("union ", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
provider.typesByName.put(name, typeList);
}
typeList.add(type);
}
}