blob: 6db3025a47dd31caa49c9573c0fba88a7fc736e0 [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 - use newly created top-level ForwardReference type
*
* Description:
*
*************************************************************************/
package org.eclipse.cdt.debug.edc.tests;
import java.math.BigInteger;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.debug.edc.arm.IARMSymbol;
import org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.PathUtils;
import org.eclipse.cdt.debug.edc.internal.services.dsf.EDCSymbolReader;
import org.eclipse.cdt.debug.edc.internal.services.dsf.Symbols;
import org.eclipse.cdt.debug.edc.internal.symbols.ArrayType;
import org.eclipse.cdt.debug.edc.internal.symbols.ConstType;
import org.eclipse.cdt.debug.edc.internal.symbols.FieldType;
import org.eclipse.cdt.debug.edc.internal.symbols.IArrayBoundType;
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.IEnumeration;
import org.eclipse.cdt.debug.edc.internal.symbols.IField;
import org.eclipse.cdt.debug.edc.internal.symbols.IForwardTypeReference;
import org.eclipse.cdt.debug.edc.internal.symbols.IInheritance;
import org.eclipse.cdt.debug.edc.internal.symbols.ILexicalBlockScope;
import org.eclipse.cdt.debug.edc.internal.symbols.IMayBeQualifedType;
import org.eclipse.cdt.debug.edc.internal.symbols.IPointerType;
import org.eclipse.cdt.debug.edc.internal.symbols.IQualifierType;
import org.eclipse.cdt.debug.edc.internal.symbols.ITemplateParam;
import org.eclipse.cdt.debug.edc.internal.symbols.ITypedef;
import org.eclipse.cdt.debug.edc.internal.symbols.InheritanceType;
import org.eclipse.cdt.debug.edc.internal.symbols.SubroutineType;
import org.eclipse.cdt.debug.edc.internal.symbols.TypedefType;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfCompileUnit;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.AttributeList;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfDebugInfoProvider.PublicNameInfo;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.DefCFAExpressionInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.DefCFAInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.ExpressionInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.FrameDescriptionEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.InstructionState;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.NopInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.RegisterInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.RememberStateInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.RestoreInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.RestoreStateInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.SameValueInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.UndefinedInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.ValueExpressionInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfFrameRegisterProvider.ValueOffsetInstruction;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfInfoReader;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfMessages;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.DwarfVariable;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.ForwardTypeReference;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.LocationEntry;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.LocationExpression;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.LocationList;
import org.eclipse.cdt.debug.edc.internal.symbols.dwarf.RangeList;
import org.eclipse.cdt.debug.edc.internal.symbols.files.ExecutableSymbolicsReaderFactory;
import org.eclipse.cdt.debug.edc.internal.symbols.files.FileStatistics;
import org.eclipse.cdt.debug.edc.launch.EDCLaunch;
import org.eclipse.cdt.debug.edc.services.EDCServicesTracker;
import org.eclipse.cdt.debug.edc.symbols.ICompileUnitScope;
import org.eclipse.cdt.debug.edc.symbols.IEDCSymbolReader;
import org.eclipse.cdt.debug.edc.symbols.IEnumerator;
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.ILocationProvider;
import org.eclipse.cdt.debug.edc.symbols.IModuleScope;
import org.eclipse.cdt.debug.edc.symbols.IScope;
import org.eclipse.cdt.debug.edc.symbols.ISymbol;
import org.eclipse.cdt.debug.edc.symbols.IType;
import org.eclipse.cdt.debug.edc.symbols.IVariable;
import org.eclipse.cdt.debug.edc.symbols.TypeUtils;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.utils.Addr32;
import org.eclipse.cdt.utils.Addr64;
import org.eclipse.core.runtime.IPath;
import org.junit.Assert;
import org.junit.Test;
/**
*
*/
public class TestDwarfReader extends AbstractDwarfReaderTest {
private static class DwarfFrameRegisterAlbum extends SimpleDebuggerTest {
/* (non-Javadoc)
* @see org.eclipse.cdt.debug.edc.debugger.tests.SimpleDebuggerTest#getRequiredLaunchConfigurationType()
*/
@Override
protected String getRequiredLaunchConfigurationType() {
return "com.nokia.cdt.debug.launch.systemTRKLaunch";
}
@Override
public String getAlbumName() {
return "RegisterFrameTestsBlackFlagRVCT.dsa";
}
public EDCLaunch getLaunch() {
return launch;
}
public DsfSession getSession() {
return session;
}
static DwarfFrameRegisterAlbum openAlbum() {
return new DwarfFrameRegisterAlbum();
}
}
private DwarfFrameRegisterAlbum dwarfAlbum;
@Test
public void testSymFromExeDetect() throws Exception {
for (TestInfo info : testInfos.values()) {
if (info.exeFile == null) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.exeFile);
assertNotNull(symbolReader);
System.out.println("Sym for exe " + info.exeFile + " is " + symbolReader.getSymbolFile());
assertEquals(info.symFile, symbolReader.getSymbolFile());
assertNotNull(symbolReader.getExecutableSections());
IExecutableSection dsect = symbolReader.findExecutableSection(DwarfInfoReader.DWARF_DEBUG_INFO);
assertNotNull(dsect);
assertEquals(".debug_info", dsect.getName());
System.out.println(" Dwarf section: " + dsect.toString());
dsect.dispose();
}
}
/**
* This should be a quick check, not a slow one
* @throws Exception
*/
@Test
public void testSymDetect() throws Exception {
long time = System.currentTimeMillis();
_testSymDetect();
long span = System.currentTimeMillis() - time;
System.out.println(span + " ms (testSymDetect)");
}
private void _testSymDetect() {
for (TestInfo info : testInfos.values()) {
System.out.println("Checking sym for " + info.symFile);
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
assertNotNull(info.symFile.lastSegment(), symbolReader);
assertTrue(info.symFile.lastSegment(), symbolReader.hasRecognizedDebugInformation());
}
}
@Test
public void testSourceFiles() throws Exception {
long time = System.currentTimeMillis();
_testSourceFiles();
long span = System.currentTimeMillis() - time;
System.out.println(span + " ms (testSourceFiles)");
}
private void _testSourceFiles() {
for (TestInfo info : testInfos.values()) {
if (info.numberOfSources == 0) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
String[] sources= symbolReader.getSourceFiles();
assertNotNull(sources);
//System.out.println(info.symFile.lastSegment() + " : " + sources.length);
assertEquals(info.symFile.lastSegment(), info.numberOfSources, sources.length);
}
}
@Test
public void testCompileUnits() throws Exception {
long time = System.currentTimeMillis();
_testCompileUnits();
long span = System.currentTimeMillis() - time;
System.out.println(span + " ms (testCompileUnits)");
// This is for information.
new FileStatistics(); // nothing but for code coverage.
FileStatistics.dump();
}
private void _testCompileUnits() {
for (TestInfo info : testInfos.values()) {
if (info.numberOfModuleScopeChildren == 0) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
Collection<IScope> scopes= symbolReader.getModuleScope().getChildren();
assertNotNull(scopes);
//System.out.println(info.symFile.lastSegment() + ": " + scopes.size());
//for (IScope kid : scopes)
// System.out.println("\t" + kid.getName());
assertEquals(info.symFile.lastSegment(), info.numberOfModuleScopeChildren, scopes.size());
}
}
@Test
public void testGlobalVariables() throws Exception {
long time = System.currentTimeMillis();
_testGlobalVariables();
long span = System.currentTimeMillis() - time;
System.out.println(span + " ms (testGlobalVariables)");
}
private void _testGlobalVariables() {
for (TestInfo info : testInfos.values()) {
if (info.numberOfVariables == 0) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
Collection<IVariable> variables = symbolReader.getModuleScope().getVariables();
assertNotNull(variables);
//System.out.println(info.symFile.lastSegment() + ": " + variables.size());
assertEquals(info.symFile.lastSegment(), info.numberOfVariables, variables.size());
}
}
/**
* Test that we can find and get types for globals in compilation units
* @throws Exception
*/
@Test
public void testPerCUGlobals() throws Exception {
long time = System.currentTimeMillis();
_testPerCUGlobals();
long span = System.currentTimeMillis() - time;
System.out.println(span + " ms (testPerCUGlobals)");
}
private void _testPerCUGlobals() {
// check all globals
for (TestInfo info : testInfos.values()) {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
boolean discover = false;
if (discover) {
// DISCOVERY (rerun if reader gets better and paste into static block at top)
//System.out.println(info.symFile);
boolean any = false;
for (String srcFile : symbolReader.getSourceFiles()) {
List<ICompileUnitScope> cusList = symbolReader.getModuleScope().getCompileUnitsForFile(PathUtils.createPath(srcFile));
any = true;
for (ICompileUnitScope cus : cusList) {
Collection<IVariable> vars = cus.getVariables();
if (!vars.isEmpty()) {
//System.out.println(srcFile +" : # vars = " + vars.size());
for (IVariable var : vars) {
//System.out.println(var.getName() + " : " + getTypeName(var.getType()));
System.out.println(MessageFormat.format(
"setCUVariableInfo(\"{0}\", \"{1}\", \"{2}\", \"{3}\");",
info.symFile.lastSegment(),
srcFile,
var.getName(),
getTypeName(var.getType())));
}
}
}
}
assertTrue("Any CUs in " + info.symFile, any);
} else {
if (info.cuVarMap == null)
continue;
for (Map.Entry<String, Map<String, VariableInfo>> entry : info.cuVarMap.entrySet()) {
String cu = entry.getKey();
List<ICompileUnitScope> cusList = symbolReader.getModuleScope().getCompileUnitsForFile(PathUtils.createPath(cu));
assertNotNull(info.symFile + " : " + cu, cusList);
for (Map.Entry<String, VariableInfo> varEntry : entry.getValue().entrySet()) {
// TODO: getter by name
boolean found = false;
for (ICompileUnitScope cus : cusList) {
for (IVariable var : cus.getVariables()) {
if (var.getName().equals(varEntry.getKey())) {
found = true;
VariableInfo varInfo = varEntry.getValue();
assertNotNull(var.getType());
String theTypeName = getTypeName(var.getType());
System.out.println(info.symFile + " : " + cu + " : " + var.getName() + " = " + theTypeName);
assertEquals(info.symFile + " : " + cu + " : " + var.getName(),
varInfo.typeName, theTypeName);
}
}
}
assertTrue(info.symFile + " : " + cu + " : " + entry.getKey(), found);
}
}
}
}
}
/**
* Test that we can find and resolve all types. The lazy type evaluator only
* is lazy as far as dereferenced types go, so we don't check anything but names
* and type trees here.
*
* This test isn't exhaustive; it just ferrets out assertion errors and null pointer references.
* @throws Exception
*/
@Test
public void testTypes() throws Exception {
for (TestInfo info : testInfos.values()) {
if (info.numberOfTypes == 0) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
boolean discover = false;
if (discover) {
// DISCOVERY
//System.out.println(info.symFile);
int cnt = symbolReader.getModuleScope().getTypes().size();
//for (IType type : symbolReader.getModuleScope().getTypes()) {
// System.out.println(getTypeName(type));
//}
System.out.println(info.symFile + " : " + cnt);
}
else {
Collection<IType> types = symbolReader.getModuleScope().getTypes();
assertNotNull(types);
System.out.println("Initial: " + types.size());
// this should trigger expansion of subtypes
int idx = 1;
for (IType type : types) {
doTestType(idx, type);
idx++;
}
types = symbolReader.getModuleScope().getTypes();
System.out.println("After: " + types.size());
assertEquals(info.symFile.lastSegment(), info.numberOfTypes, types.size());
// now, ensure the types are still there in a new reader
symbolReader = Symbols.getSymbolReader(info.symFile);
assertEquals(info.symFile.lastSegment(), info.numberOfTypes, symbolReader.getModuleScope().getTypes().size());
}
}
}
/**
* @param idx
* @param type
*/
private void doTestType(int idx, IType type) {
String name = getTypeName(type);
if (type.getByteSize() == 0) {
IType checkType = type;
while (checkType != null) {
if (checkType instanceof IQualifierType || checkType instanceof TypedefType)
checkType = checkType.getType();
else
break;
}
if (checkType == null)
return;
if (checkType instanceof ICompositeType) {
return; // this is allowed, even though the spec says it should be here.
// we can't fix it up, because even if we sum up the field sizes, we can't predict the extra space used by alignment
}
if (checkType instanceof SubroutineType || checkType instanceof InheritanceType)
return; // this is allowed
if (checkType instanceof FieldType) {
doTestType(idx, ((FieldType) checkType).getType());
return;
}
if (checkType instanceof ArrayType) {
for (IArrayBoundType bound : ((ArrayType) checkType).getBounds()) {
if (bound.getElementCount() == 0)
return;
}
// else, should have more
}
if (checkType == ForwardTypeReference.NULL_TYPE_ENTRY)
return; // should not get here, but something else tests this
if (checkType instanceof ICPPBasicType && ((ICPPBasicType) checkType).getBaseType() == ICPPBasicType.t_void)
return; // yup
if (checkType instanceof ITemplateParam) {
if (checkType.getType().getName().equals("class TModelEntry")) {
assertNull(((ITemplateParam)checkType).getProperties());
assertNull(((ITemplateParam)checkType).getScope());
assertTrue(((ITemplateParam)checkType).getType() instanceof ICompositeType);
// following is not quite meaningful but to beef up method coverage.
checkType.setType(null);
checkType.dispose();
}
return; // no inherent size
}
if (checkType instanceof IArrayBoundType)
return; // no inherent size
fail(name + " has zero size");
}
if (idx % 1000 == 0) System.out.print(".");
}
/**
* This method is useful for dumping the types actually parsed and comparing them with each other.
*/
/*
public void testTypesXX() throws Exception {
for (TestInfo info : testInfos.values()) {
if (!info.symFile.lastSegment().contains("gcce"))
continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
Collection<IType> types = symbolReader.getModuleScope().getTypes();
assertNotNull(types);
// force expansion
for (IType type : types) {
//String name =
getTypeName(type);
}
// start again
types = symbolReader.getModuleScope().getTypes();
List<String> names = new ArrayList<String>();
for (IType type : types) {
names.add(getTypeName(type));
}
//Collections.sort(names);
String fname = "true".equals(System.getProperty(Symbols.DWARF_USE_NEW_READER)) ? "new.txt" : "old.txt";
PrintStream dump = new PrintStream(new File("/tmp/" + fname));
for (String name : names) {
dump.println(name);
}
dump.close();
}
}
*/
/**
* Test case(s) for specific type parses
* @throws Exception
*/
@Test
public void testSpecificTypes1a() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
List<ICompileUnitScope> cuList = getCompileUnitsFor(symbolReader, "dbg_multipleInheritance.cpp");
if (cuList.isEmpty())
cuList = getCompileUnitsFor(symbolReader, "dbg_multipleinheritance.cpp");
assertFalse(cuList.isEmpty());
List<ICompileUnitScope> cuhList = getCompileUnitsFor(symbolReader, "dbg_multipleInheritance.h");
assertFalse(cuhList.isEmpty());
// multipleInheritance
IFunctionScope function = null;
for (ICompileUnitScope cu : cuList) {
function = cu.getFunctionAtAddress(new Addr32(0xa940));
if (function != null)
break;
}
assertNotNull(function);
assertEquals("multipleInheritance", function.getName());
for (IVariable var : function.getVariablesInTree()) {
if (var.getName().equals("pdv1")) {
// check forward reference behavior
if ( var instanceof DwarfVariable
&& (((DwarfVariable)var).getRawType() instanceof IForwardTypeReference)) {
IForwardTypeReference forward = (IForwardTypeReference)(((DwarfVariable)var).getRawType());
assertEquals("", forward.getName());
assertEquals(4, forward.getByteSize());
assertNull(forward.getProperties());
assertNotNull(forward.getScope());
IType resolvedType = forward.getType();
assertEquals("class Derv1", resolvedType.getName());
forward.setType(resolvedType);
assertEquals("class Derv1", forward.getType().getName());
}
IType type = var.getType();
assertFalse(type instanceof IForwardTypeReference); // should not peek through interface
assertNotNull(type);
assertEquals(function, var.getScope());
_testSpecificTypePointerToDerv1(type);
}
}
// okay place to check accessibility of base link address & provider string
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
// ensure placeholder null type has correct fields
IType nullEntryType = ForwardTypeReference.NULL_TYPE_ENTRY;
assertEquals(0, nullEntryType.getByteSize());
assertEquals(DwarfMessages.DwarfDebugInfoProvider_UnhandledType, nullEntryType.getName());
assertEquals(0, nullEntryType.getProperties().size());
assertNull(nullEntryType.getScope());
assertNull(nullEntryType.getType());
boolean throwException = false;
try {
nullEntryType.setType(null);
} catch (IllegalStateException ise) {
throwException = true;
}
assertTrue(throwException);
nullEntryType.dispose(); // should do nothing
assertEquals(0, nullEntryType.getProperties().size()); // still alive
assertEquals(provider.getBaseLinkAddress().toString(), "32768");
IModuleScope moduleScope = provider.getModuleScope();
assertNotNull(moduleScope);
assertTrue(moduleScope.getEnumerators().size() == 0);
assertTrue(moduleScope.getSymbolFile().toPortableString().contains("BlackFlag_rvct.sym"));
ICompileUnitScope cuScope = provider.getCompileUnitForAddress(new Addr64("32768"));
assertNotNull(cuScope);
assertTrue(cuScope instanceof DwarfCompileUnit);
DwarfCompileUnit cu = (DwarfCompileUnit)cuScope;
cu.setParsedForVariables(false);
assertFalse(cu.isParsedForVariables());
cu.setParsedForVariables(true);
assertTrue(cu.isParsedForVariables());
AttributeList attrList = cu.getAttributeList();
cu.setAttributes(null);
assertNull(cu.getAttributeList());
cu.setAttributes(attrList);
assertNotNull(cu.getAttributeList());
assertNotNull(cu.toString());
assertNotNull(provider.toString());
}
/**
* Test case(s) for specific type parses, from a focused parse
* @throws Exception
*/
@Test
public void testSpecificTypes1b() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
// DW_TAG_pointer_type -> Derv1
IType type = provider.readType(0x1cb139);
_testSpecificTypePointerToDerv1(type);
}
/**
* @param type
*/
private void _testSpecificTypePointerToDerv1(IType type) {
assertTrue(type.getName(), type instanceof IPointerType);
IType derv1 = ((IPointerType) type).getType();
assertFalse(derv1 instanceof IForwardTypeReference); // should not peek through interface
assertNotNull(derv1);
assertTrue(derv1.getName(), derv1 instanceof ICompositeType);
ICompositeType derv1Comp = (ICompositeType) derv1;
assertEquals("class Derv1", derv1Comp.getName());
assertEquals(1, derv1Comp.fieldCount());
assertEquals(2, derv1Comp.inheritanceCount());
IField vptrField = derv1Comp.findFields("__vptr")[0];
assertNotNull("__vptr", vptrField);
assertEquals(0, derv1Comp.getTemplateParams().length);
assertEquals(ICompositeType.k_class, derv1Comp.getKey());
// inherited fields also visible
IField xField = derv1Comp.findFields("x")[0];
assertNotNull("x", xField);
// x is in an inherited type
IInheritance[] inhs = derv1Comp.getInheritances();
assertEquals(2, inhs.length);
IType base1 = inhs[1].getType();
assertNotNull(base1);
assertEquals("class Base1", base1.getName());
assertTrue(base1.getName(), base1 instanceof ICompositeType);
ICompositeType base1Comp = (ICompositeType) base1;
assertEquals(1, base1Comp.fieldCount());
assertEquals(0, base1Comp.inheritanceCount());
xField = base1Comp.findFields("x")[0];
assertNotNull("x", xField);
IType base2 = inhs[0].getType();
assertNotNull(base2);
assertEquals("class Base2", base2.getName());
assertTrue(base2.getName(), base2 instanceof ICompositeType);
ICompositeType base2Comp = (ICompositeType) base2;
assertEquals(0, base2Comp.fieldCount());
assertEquals(0, base2Comp.inheritanceCount());
// watch for side effects (late adding of inherited fields)
assertEquals(1, derv1Comp.fieldCount());
assertEquals(2, derv1Comp.inheritanceCount());
assertEquals(1, base1Comp.fieldCount());
assertEquals(0, base1Comp.inheritanceCount());
assertEquals(0, base2Comp.fieldCount());
assertEquals(0, base2Comp.inheritanceCount());
// the class is in the header
IScope classScope = ((IPointerType)type).getType().getScope();
assertTrue(classScope instanceof ICompileUnitScope);
IPath path = ((ICompileUnitScope) classScope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equalsIgnoreCase("dbg_multipleInheritance.h"));
// the pointer type is declared in a function (either "show3", due to "this", or the one we looked in)
assertTrue(type.getScope() instanceof IFunctionScope);
//assertEquals(((IFunctionScope) type.getScope()).getName(), "show3");
IScope fileScope = type.getScope().getParent();
assertTrue(fileScope instanceof ICompileUnitScope);
path = ((ICompileUnitScope) fileScope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equalsIgnoreCase("dbg_multipleInheritance.cpp"));
}
/**
* Test case(s) for specific type parses
* @throws Exception
*/
@Test
public void testSpecificTypes2() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
List<ICompileUnitScope> cuList = getCompileUnitsFor(symbolReader, "dbg_multipleInheritance.cpp");
if (cuList.isEmpty())
cuList = getCompileUnitsFor(symbolReader, "dbg_multipleinheritance.cpp");
assertFalse(cuList.isEmpty());
List<ICompileUnitScope> cuhList = getCompileUnitsFor(symbolReader, "dbg_multipleInheritance.h");
assertFalse(cuhList.isEmpty());
// Base2::show2
IFunctionScope function = null;
for (ICompileUnitScope cu : cuList) {
function = cu.getFunctionAtAddress(new Addr32(0xa916));
if (function != null)
break;
}
if (function == null)
for (ICompileUnitScope cu : cuhList) {
function = cu.getFunctionAtAddress(new Addr32(0xa916));
if (function != null)
break;
}
assertNotNull(function);
assertEquals("show2", function.getName());
for (IVariable var : function.getVariablesInTree()) {
if (var.getName().equals("Base2Show"))
_testSpecificTypeCharArray(function, cuhList.get(0), var);
}
}
/**
* @param function
* @param headerScope
* @param var
*/
private void _testSpecificTypeCharArray(IFunctionScope function, ICompileUnitScope headerScope, IVariable var) {
IType type = var.getType();
assertFalse(type instanceof IForwardTypeReference); // should not peek through interface
assertNotNull(type);
assertTrue(type.getName(), type instanceof IArrayType);
assertEquals(function, var.getScope());
IType baseType = ((IArrayType) type).getType();
assertNotNull(baseType);
assertTrue(baseType.getName(), baseType instanceof IBasicType);
// FIXME: this should be null for a primitive type, but is the previous function in the old reader
//assertEquals(randomFunction, baseType.getScope());
IBasicType charType = (IBasicType) baseType;
assertEquals("char", charType.getName());
assertEquals(1, charType.getByteSize());
}
/**
* Test case(s) for specific type parses, from the whole module scope
* @throws Exception
*/
@Test
public void testSpecificTypes3a() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlagMinGW.exe"));
List<ICompileUnitScope> cuList = getCompileUnitsFor(symbolReader, "dbg_expressions.cpp");
// TODO: lookup by name
for (ICompileUnitScope cu : cuList) {
for (IVariable var : cu.getVariables()) {
if (var.getName().equals("genum")) {
assertEquals(cu, var.getScope());
_testSpecificTypeEnum(var.getType(), "dbg_typedefs.h");
break;
}
}
}
////////
symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
cuList = getCompileUnitsFor(symbolReader, "dbg_typedefs.h");
// TODO: lookup by name
for (ICompileUnitScope cu : cuList) {
for (IVariable var : cu.getVariables()) {
if (var.getName().equals("genum")) {
assertEquals(cu, var.getScope());
_testSpecificTypeEnum(var.getType(), "dbg_typedefs.h");
break;
}
}
}
}
/**
* Test case(s) for specific type parses, from a focused scope
* @throws Exception
*/
@Test
public void testSpecificTypes3b() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlagMinGW.exe"));
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
// DW_TAG_enumeration_type : enum_type
IType type = provider.readType(0x6a65);
_testSpecificTypeEnum(type, "dbg_expressions.cpp");
///////
// defined in different place here
symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
// DW_TAG_enumeration_type : enum_type
type = provider.readType(0x1a6a3d);
_testSpecificTypeEnum(type, "dbg_typedefs.h");
}
private void _testSpecificTypeEnum(IType type, String file) {
assertTrue(getTypeName(type), type instanceof IEnumeration);
IEnumeration enumType = (IEnumeration) type;
assertEquals("enum_type", enumType.getName());
assertEquals(5, enumType.enumeratorCount());
assertEquals("zero", enumType.getEnumerators()[0].getName());
assertEquals("one", enumType.getEnumerators()[1].getName());
assertEquals("two", enumType.getEnumerators()[2].getName());
assertEquals("three", enumType.getEnumerators()[3].getName());
assertEquals("four", enumType.getEnumerators()[4].getName());
IScope scope = type.getScope();
assertTrue(scope instanceof ICompileUnitScope);
ICompileUnitScope cus = (ICompileUnitScope) scope;
assertTrue(cus.getFilePath().toString(), cus.getFilePath().lastSegment().equals(file));
}
@Test
public void testStaticLocals1() throws Exception {
for (TestInfo info : testInfos.values()) {
if (info.blackFlagMainFilePath != null) {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
List<ICompileUnitScope> cuList = getCompileUnitsFor(symbolReader, info.blackFlagMainFilePath.lastSegment());
assertFalse(cuList.isEmpty());
for (ICompileUnitScope cu : cuList) {
for (IFunctionScope func : cu.getFunctions()) {
if (func.getName().equals("doExampleL")) {
for (IVariable var : func.getVariablesInTree()) {
if (var.getName().equals("KHelloWorldText")) {
IScope vScope = var.getScope();
if (vScope instanceof ILexicalBlockScope)
vScope = vScope.getParent();
assertEquals(func, vScope);
_testStaticLocal(var.getType());
}
}
}
}
}
}
}
}
@Test
public void testStaticLocals2() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_gcce.sym"));
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
IType type = provider.readType(0x7e11);
_testStaticLocal(type);
///////////
symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
type = provider.readType(0x1dc89a);
_testStaticLocal(type);
}
/**
* @param type
*/
private void _testStaticLocal(IType type) {
assertTrue(getTypeName(type), type instanceof ConstType);
type = type.getType();
assertTrue(getTypeName(type), type instanceof ICompositeType);
ICompositeType comp = (ICompositeType) type;
// differs in RVCT and GCCE
assertTrue(getTypeName(type), "struct TLitC<14>".equals(comp.getName())
|| "class TLitC".equals(comp.getName()));
assertEquals(2, comp.fieldCount());
assertEquals(0, comp.inheritanceCount());
IField f = comp.getFields()[0];
assertEquals("iTypeLength", f.getName());
assertTrue(getTypeName(f.getType()), f.getType() instanceof ITypedef);
type = f.getType().getType();
assertTrue(getTypeName(type), type instanceof IBasicType);
f = comp.getFields()[1];
assertEquals("iBuf", f.getName());
assertTrue(getTypeName(f.getType()), f.getType() instanceof IArrayType);
IArrayType arr = (IArrayType) f.getType();
assertNotNull(arr.getBounds());
assertEquals(1, arr.getBoundsCount());
IArrayBoundType bound = arr.getBound(0);
assertEquals(0, bound.getDimensionIndex());
assertEquals(14, bound.getBoundCount());
assertEquals(1, bound.getElementCount());
type = arr.getType();
assertTrue(getTypeName(type), type instanceof ITypedef);
type = type.getType();
assertTrue(getTypeName(type), type instanceof ICPPBasicType);
assertEquals(8, ((ICPPBasicType)type).getQualifierBits());
assertTrue(((ICPPBasicType)type).isUnsigned());
assertTrue(type instanceof IMayBeQualifedType);
assertFalse(((IMayBeQualifedType)type).isConst());
assertFalse(((IMayBeQualifedType)type).isVolatile());
}
/**
* Discovered while testing GCC-E
* @throws Exception
*/
@Test
public void testSpecificTypes4() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_gcce.sym"));
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
IType type = provider.readType(0x36104);
_testSpecificTypeGCCEDerv1(type);
}
/**
* @param type
*/
private void _testSpecificTypeGCCEDerv1(IType type) {
assertTrue(type.getName(), type instanceof ICompositeType);
ICompositeType derv1Comp = (ICompositeType) type;
assertEquals("struct Derv1", derv1Comp.getName());
assertEquals(1, derv1Comp.fieldCount());
assertEquals(2, derv1Comp.inheritanceCount());
IField vptrField = derv1Comp.findFields("_vptr$Derv1")[0]; // renamed by parser to avoid having an invalid expression-like field
assertNotNull("_vptr$Derv1", vptrField);
// inherited fields also visible
IField xField = derv1Comp.findFields("x")[0];
assertNotNull("x", xField);
// x is in an inherited type
IInheritance[] inhs = derv1Comp.getInheritances();
assertEquals(2, inhs.length);
IType base1 = inhs[1].getType();
assertNotNull(base1);
assertEquals("struct Base1", base1.getName());
assertTrue(base1.getName(), base1 instanceof ICompositeType);
ICompositeType base1Comp = (ICompositeType) base1;
assertEquals(1, base1Comp.fieldCount());
assertEquals(0, base1Comp.inheritanceCount());
xField = base1Comp.findFields("x")[0];
assertNotNull("x", xField);
IType base2 = inhs[0].getType();
assertNotNull(base2);
assertEquals("struct Base2", base2.getName());
assertTrue(base2.getName(), base2 instanceof ICompositeType);
ICompositeType base2Comp = (ICompositeType) base2;
assertEquals(0, base2Comp.fieldCount());
assertEquals(0, base2Comp.inheritanceCount());
// watch for side effects (late adding of inherited fields)
assertEquals(1, derv1Comp.fieldCount());
assertEquals(2, derv1Comp.inheritanceCount());
assertEquals(1, base1Comp.fieldCount());
assertEquals(0, base1Comp.inheritanceCount());
assertEquals(0, base2Comp.fieldCount());
assertEquals(0, base2Comp.inheritanceCount());
IScope scope = type.getScope();
assertTrue(scope instanceof ICompileUnitScope);
IPath path = ((ICompileUnitScope) scope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equalsIgnoreCase("dbg_multipleInheritance.cpp"));
}
private boolean isExecutable(ISymbol symbol) {
Boolean executable = (Boolean)symbol.getProperties().get(ISymbol.PROPERTY_EXECUTABLE);
// for testing purposes, if the property doesn't exist, assume true
return executable == null || executable;
}
/**
* Test that we do not have multiple entries for the same symbol with a zero size.
* @throws Exception
*/
@Test
public void testSymbols() throws Exception {
for (TestInfo info : testInfos.values()) {
if (info.numberOfSymbols == 0) continue;
IEDCSymbolReader reader = Symbols.getSymbolReader(info.symFile);
Collection<ISymbol> symbols = reader.getSymbols();
int numSymbols = symbols.size();
//System.out.println(info.symFile.lastSegment() + " : " + numSymbols);
assertEquals(info.symFile.lastSegment(), info.numberOfSymbols, numSymbols);
Map<IAddress, List<ISymbol>> zeroSymbols = new HashMap<IAddress, List<ISymbol>>();
for (ISymbol symbol : symbols) {
if (symbol.getSize() == 0) {
IAddress symAddr = symbol.getAddress();
List<ISymbol> sameAddrList = zeroSymbols.get(symAddr);
if (sameAddrList != null && !symAddr.getValue().equals(BigInteger.ZERO)) {
// with the addition of multiple zero-sized symbols,
// the criterion is that there should not now be
// duplicate executable symbols at the same address
if (isExecutable(symbol)) {
for (ISymbol sameAddr : sameAddrList) {
if (symbol.getClass().equals(sameAddr) && isExecutable(sameAddr)) {
if (symbol instanceof IARMSymbol) {
// you may have more than one zero-sized executable
// symbol at the same address in ARM. But they should
// not be the same mode, e.g. both ARM or both Thumb.
assertFalse("multiple zero-size symbols" + symbol.getName() + " & "+ sameAddr.getName(),
((IARMSymbol)symbol).isThumbAddress() == ((IARMSymbol)sameAddr).isThumbAddress());
} else {
assertFalse("multiple zero-size symbols" + symbol.getName() + " & "+ sameAddr.getName(), true);
}
}
}
}
} else {
sameAddrList = new ArrayList<ISymbol>();
}
sameAddrList.add(symbol);
zeroSymbols.put(symbol.getAddress(), sameAddrList);
}
}
}
}
/**
* Test some type lookup edge cases
*/
@Test
public void testSpecificTypes4a() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
List<ICompileUnitScope> scopes = getCompileUnitsFor(symbolReader, "dbg_multipleInheritance.cpp");
if (scopes.isEmpty())
scopes = getCompileUnitsFor(symbolReader, "dbg_multipleinheritance.cpp");
assertFalse(scopes.isEmpty());
/*
if (Symbols.useNewReader())
// TODO: along with other filepath lookup issues:
// what happens here is, there are three CUs for dbg_multipleInheritance.cpp,
// but one has no DW_AT_comp_dir. All of their names are \BlackFlags\SRC\dbg_multipleInheritance.cpp,
// which (once canonicalized) looks like an absolute path in Linux, thus comes in as
// three distinct CUs for the same path. In Win32, though, the comp dir is prepended
// in two cases, since the name is not considered absolute.
assertEquals(HostOS.IS_WIN32 ? 2 : 3, scopes.size());
else
assertEquals(1, scopes.size());
*/
IFunctionScope functionScope = null;
for (ICompileUnitScope scope : scopes) {
functionScope = scope.getFunctionAtAddress(new Addr32(0xaa4e));
if (functionScope != null)
break;
}
assertNotNull(functionScope);
Collection<IVariable> vars = functionScope.getVariablesInTree();
assertEquals(2, vars.size());
java.util.Iterator<IVariable> vit = vars.iterator();
assertEquals("FromBase2", vit.next().getName());
assertEquals("a", vit.next().getName());
vars = functionScope.getParameters();
assertEquals(1, vars.size());
vit = vars.iterator();
IVariable thisVar = vit.next();
assertEquals("this", thisVar.getName());
assertNotNull(thisVar.getType());
_testSpecificTypes4(thisVar.getType());
}
/**
* Test some type lookup edge cases
*/
@Test
public void testSpecificTypes4b() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
DwarfDebugInfoProvider provider = getDwarfDebugInfoProvider(symbolReader);
if (provider == null)
return;
// 0x1cb0c6: subprogram
// 0x1cb0de: this
// 0x1cb098: Base2*
IType type = provider.readType(0x1cb098);
assertNotNull(type);
_testSpecificTypes4(type);
}
/**
* @param type
*/
private void _testSpecificTypes4(IType type) {
assertTrue(type.getName(), type instanceof IPointerType);
IType base2 = ((IPointerType) type).getType();
assertFalse(base2 instanceof IForwardTypeReference); // should not peek through interface
assertNotNull(base2);
assertTrue(base2.getName(), base2 instanceof ICompositeType);
ICompositeType base2Comp = (ICompositeType) base2;
assertEquals("class Base2", base2Comp.getName());
assertEquals(0, base2Comp.fieldCount());
assertEquals(0, base2Comp.inheritanceCount());
// the class is in the header
IScope classScope = ((IPointerType)type).getType().getScope();
assertTrue(classScope instanceof ICompileUnitScope);
IPath path = ((ICompileUnitScope) classScope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equalsIgnoreCase("dbg_multipleInheritance.h"));
// the pointer type is declared in a function
assertTrue(type.getScope() instanceof IFunctionScope);
IScope fileScope = type.getScope().getParent();
assertTrue(fileScope instanceof ICompileUnitScope);
path = ((ICompileUnitScope) fileScope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equalsIgnoreCase("dbg_multipleInheritance.cpp"));
}
/**
* Test some type lookup edge cases
*/
@Test
public void testSpecificTypes5a() throws Exception {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_rvct.sym"));
// inlined Der1::Der1()
IScope scope = symbolReader.getModuleScope().getScopeAtAddress(new Addr32(0x8cda));
assertTrue(scope instanceof IFunctionScope);
IFunctionScope functionScope = (IFunctionScope) scope;
// two locals __func_local__0 and __result are optimized out
Collection<IVariable> vars = functionScope.getVariablesInTree();
assertEquals(0, vars.size());
java.util.Iterator<IVariable> vit;
/*
vit = vars.iterator();
IVariable var = vit.next();
assertEquals("__func_local__0", var.getName());
var = vit.next();
assertEquals("__result", var.getName());
*/
vars = functionScope.getParameters();
assertEquals(1, vars.size());
vit = vars.iterator();
IVariable thisVar = vit.next();
assertEquals("this", thisVar.getName());
assertNotNull(thisVar.getType());
_testSpecificTypes5(thisVar.getType());
}
/**
* @param type
*/
private void _testSpecificTypes5(IType type) {
assertTrue(type.getName(), type instanceof IPointerType);
IType der1 = ((IPointerType) type).getType();
assertFalse(der1 instanceof IForwardTypeReference); // should not peek through interface
assertNotNull(der1);
assertTrue(der1.getName(), der1 instanceof ICompositeType);
ICompositeType der1Comp = (ICompositeType) der1;
assertEquals("struct Der1", der1Comp.getName());
assertEquals(1, der1Comp.fieldCount());
assertEquals(1, der1Comp.inheritanceCount());
IField field = der1Comp.findFields("b1")[0];
assertNotNull("b1", field);
field = der1Comp.findFields("__vptr")[0];
assertNotNull("__vptr", field);
// inherited fields also visible
field = der1Comp.findFields("a")[0];
assertNotNull("a", field);
// x is in an inherited type
IInheritance[] inhs = der1Comp.getInheritances();
assertEquals(1, inhs.length);
IType base01 = inhs[0].getType();
assertNotNull(base01);
assertEquals("struct Base01", base01.getName());
assertTrue(base01.getName(), base01 instanceof ICompositeType);
ICompositeType base01Comp = (ICompositeType) base01;
assertEquals(2, base01Comp.fieldCount());
assertEquals(0, base01Comp.inheritanceCount());
field = base01Comp.findFields("a")[0];
assertNotNull("a", field);
field = der1Comp.findFields("__vptr")[0];
assertNotNull("__vptr", field);
// the class is in the header
IScope classScope = ((IPointerType)type).getType().getScope();
assertTrue(classScope instanceof ICompileUnitScope);
IPath path = ((ICompileUnitScope) classScope).getFilePath();
assertTrue(path.toString(), path.lastSegment().equals("dbg_rtti.cpp"));
// the pointer type is declared in a function
assertTrue(type.getScope() instanceof ICompileUnitScope);
path = ((ICompileUnitScope) type.getScope()).getFilePath();
assertTrue(path.toString(), path.lastSegment().equals("dbg_rtti.cpp"));
}
/**
* Look for DWARF files with bad scopes and make sure we fix them up properly.
* Use full scanning to populate the content.
*/
@Test
public void testScopes1a() {
for (TestInfo info : testInfos.values()) {
System.out.println("Scopes for " + info.symFile.lastSegment());
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
if (symbolReader != null) {
readFully(symbolReader);
doTestScopes(symbolReader);
}
}
}
/**
* Look for DWARF files with bad scopes and make sure we fix them up properly.
* Use random scanning to populate the content.
*/
@Test
public void testScopes1b() {
for (TestInfo info : testInfos.values()) {
System.out.println("Scopes for " + info.symFile.lastSegment());
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
if (symbolReader != null) {
readRandomly(symbolReader);
doTestScopes(symbolReader);
}
}
}
/**
* @param symbolReader
*/
private void doTestScopes(IEDCSymbolReader symbolReader) {
IModuleScope moduleScope = symbolReader.getModuleScope();
IAddress low = moduleScope.getLowAddress();
IAddress high = moduleScope.getHighAddress();
assertTrue(low.compareTo(high) < 0);
checkChildScopes(moduleScope, low, high);
}
/**
* @param scope
* @param low
* @param high
*/
private void checkChildScopes(IScope scope, IAddress low, IAddress high) {
for (IScope kid : scope.getChildren()) {
IAddress kidlo = kid.getLowAddress();
IAddress kidhi = kid.getHighAddress();
if (!kid.hasEmptyRange()) {
if (!(kidlo.compareTo(kidhi) <= 0)) {
fail(describeScope(kid));
}
if (!(low.compareTo(kidlo) <= 0)) {
fail(describeScope(kid));
}
if (!(kidhi.compareTo(high) <= 0)) {
fail(describeScope(kid));
}
}
if (!(kid instanceof ILexicalBlockScope) && !(scope instanceof ILexicalBlockScope)) {
checkChildScopes(kid, kidlo, kidhi);
} else {
// lexical blocks are not constrained to be within other lexical blocks,
// but they should be within the function.
checkChildScopes(kid, low, high);
}
}
}
/**
* Make sure our fixing up of CU scopes makes sense. In old GCC-E (e.g. 3.4.3), the
* compile units do not have low_pc and high_pc, which makes it hard to find functions.
*/
@Test
public void testScopes3() {
for (TestInfo info : testInfos.values()) {
String label = info.symFile.lastSegment();
System.out.println("Address->Function mapping for "+ label);
// explicitly read the functions
IExecutableSymbolicsReader exeReader = ExecutableSymbolicsReaderFactory.createFor(info.symFile);
if (exeReader == null)
continue;
DwarfDebugInfoProvider debugInfoProvider = new DwarfDebugInfoProvider(exeReader);
IEDCSymbolReader explicitSymbolReader = new EDCSymbolReader(
exeReader,
debugInfoProvider);
// this is NOT guaranteed: GCC-E at link time will share function definitions among CUs,
// so two CUs can "overlap" if you consider only their raw Lo and Hi PCs.
/*
// make sure the CUs are proper
ArrayList<IScope> cuList= new ArrayList<IScope>(explicitSymbolReader.getModuleScope().getChildren());
Collections.sort(cuList);
long low = 0, high = 0;
for (IScope cu : cuList) {
String culabel = label + ":" + cu;
long start = cu.getLowAddress().getValue().longValue();
long end = cu.getHighAddress().getValue().longValue();
if (start != end) {
assertTrue(culabel, start < end);
assertTrue(culabel, start >= low);
if (high > 0)
assertTrue(culabel, end > high);
high = end;
}
}
*/
// remember all the functions
List<IFunctionScope> allFuncs = new ArrayList<IFunctionScope>(
explicitSymbolReader.getModuleScope().getFunctionsByName(null));
assertTrue(allFuncs.size() >= 10);
debugInfoProvider.dispose();
// now, make sure we can find all those functions with a random scan
debugInfoProvider = new DwarfDebugInfoProvider(exeReader);
IEDCSymbolReader testSymbolReader = new EDCSymbolReader(
exeReader,
debugInfoProvider);
StringBuilder missing = new StringBuilder();
Random random = new Random(0x12145895);
int count = allFuncs.size();
while (count-- > 0) {
IFunctionScope allFunc = allFuncs.get(random.nextInt(allFuncs.size()));
doTestScope3Func(label, missing, testSymbolReader, allFunc);
}
debugInfoProvider.dispose();
if(missing.length() > 0)
fail(missing.toString());
}
// as good a place as any to test the fields of the static EDCSymbolReader.EMPTY_MODULE_SCOPE
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.compareTo(new Object()) == 0);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.equals(new Object()) == false);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getChildren().isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getCompileUnitForAddress(null) == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getCompileUnitsForFile(null).isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getEnumerators().isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getFrameRegisterProvider() == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getFunctionsByName(null).isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getHighAddress().isZero());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getLowAddress().isZero());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getModuleLineEntryProvider() != null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getName().length() == 0);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getParent() == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getRangeList() == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getScopeAtAddress(null) == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getSymbolFile() == null);
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getTypes().isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getVariables().isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getVariablesByName(null, false).isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.getVariablesByName(null, true).isEmpty());
assertTrue(EDCSymbolReader.EMPTY_MODULE_SCOPE.hasEmptyRange());
}
/**
* Make sure our fixing up of CU scopes makes sense. In old GCC-E (e.g. 3.4.3), the
* compile units do not have low_pc and high_pc, which makes it hard to find functions.
*/
@Test
public void testScopes3b() {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(getFile("BlackFlag_gcce_343.sym"));
IScope scope = symbolReader.getModuleScope().getScopeAtAddress(new Addr32(0xad32));
assertTrue(scope instanceof IFunctionScope || scope instanceof ILexicalBlockScope);
}
/**
* @param label
* @param missing
* @param symbolReader
* @param allFunc
*/
private void doTestScope3Func(String label, StringBuilder missing,
IEDCSymbolReader symbolReader, IFunctionScope allFunc) {
IScope scope1 = symbolReader.getModuleScope().getScopeAtAddress(allFunc.getLowAddress().add(1));
IScope scope2 = symbolReader.getModuleScope().getScopeAtAddress(allFunc.getHighAddress().add(-1));
if (scope1 == null || scope2 == null) {
missing.append(label + ":"+ allFunc +" missing\n");
}
// skip if the function is defined over a range, because this may mean interleaved runtime code
else if (allFunc.getRangeList() == null){
// one of both may be inlined
while (scope1 instanceof ILexicalBlockScope || scope1.getParent() instanceof IFunctionScope)
scope1 = scope1.getParent();
while (scope2 instanceof ILexicalBlockScope || scope2.getParent() instanceof IFunctionScope)
scope2 = scope2.getParent();
if (scope1 != scope2) {
missing.append(label + ":"+ allFunc +" did not find same function at low and high: " + scope1 + " / "+ scope2 + "\n");
}
}
}
@Test
public void testRangeList() {
TestInfo info = testInfos.get("BlackFlagMinGW.exe");
// explicitly read the functions
IExecutableSymbolicsReader exeReader = ExecutableSymbolicsReaderFactory.createFor(info.symFile);
DwarfDebugInfoProvider debugInfoProvider = new DwarfDebugInfoProvider(exeReader);
IEDCSymbolReader reader = new EDCSymbolReader(exeReader, debugInfoProvider);
List<ICompileUnitScope> scopes = new ArrayList<ICompileUnitScope>();
for (IScope scope : reader.getModuleScope().getChildren()) {
if (scope instanceof ICompileUnitScope) {
scopes.add((ICompileUnitScope) scope);
}
}
// check and manipulate range list
for (ICompileUnitScope cuScope : scopes) {
if (cuScope.getRangeList() != null) {
RangeList rangeList = (RangeList) cuScope.getRangeList();
long low = rangeList.getLowAddress();
long high = rangeList.getHighAddress();
rangeList.addLowRange(low - 1);
rangeList.addHighRange(high + 1);
assertTrue(rangeList.isInRange(low));
assertTrue(low > rangeList.getLowAddress());
assertTrue(high < rangeList.getHighAddress());
assertTrue(rangeList.toString().
contains(Long.toHexString(rangeList.getLowAddress())));
break;
}
}
}
@Test
public void testFrameRegInstructions() {
EDCServicesTracker edcTracker = null;
try {
TestUtils.showDebugPerspective();
dwarfAlbum = DwarfFrameRegisterAlbum.openAlbum();
dwarfAlbum.launchAndWaitForSuspendedContext();
if (dwarfAlbum.getLaunch() == null) return;
edcTracker = new EDCServicesTracker(EDCDebugger.getBundleContext(), dwarfAlbum.getSession().getId());
Assert.assertNotNull(edcTracker);
} catch (Exception e) {
Assert.fail(e.getLocalizedMessage());
}
TestInfo info = testInfos.get("BlackFlag_rvct.sym");
// explicitly read the types to parse the file
IExecutableSymbolicsReader exeReader = ExecutableSymbolicsReaderFactory.createFor(info.symFile);
DwarfDebugInfoProvider provider = new DwarfDebugInfoProvider(exeReader);
provider.getTypes();
FrameDescriptionEntry fde = provider.findFrameDescriptionEntry(new Addr64("32768"));
InstructionState dummyState;
// Can remove try blocks when all AbstractInstruction#applyInstruction()'s are implemented
dummyState = new InstructionState(edcTracker, null, null, fde);
try {
DefCFAExpressionInstruction defCFAEI = new DefCFAExpressionInstruction(null);
assertNotNull(defCFAEI.toString());
defCFAEI.applyInstruction(dummyState);
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// save an expression
ExpressionInstruction ei = new ExpressionInstruction(0, null);
assertNotNull(ei.toString());
ei.applyInstruction(dummyState);
assertTrue(dummyState.regRules.containsKey(0));
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// save a register
RegisterInstruction re = new RegisterInstruction(0, 1);
assertNotNull(re.toString());
re.applyInstruction(dummyState);
assertTrue(dummyState.regRules.containsKey(0));
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// nop
NopInstruction nop = new NopInstruction();
assertNotNull(nop.toString());
int hash = dummyState.hashCode();
nop.applyInstruction(dummyState);
assertTrue(dummyState.hashCode() == hash);
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// save an expression for a register
ValueExpressionInstruction vei = new ValueExpressionInstruction(0, null);
assertNotNull(vei.toString());
vei.applyInstruction(dummyState);
assertTrue(dummyState.regRules.containsKey(0));
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// save a register offset
ValueOffsetInstruction voi = new ValueOffsetInstruction(0, 12);
assertNotNull(voi.toString());
voi.applyInstruction(dummyState);
assertTrue(dummyState.regRules.containsKey(0));
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// push a state on the state stack
RememberStateInstruction rsi = new RememberStateInstruction();
assertNotNull(rsi.toString());
int i = dummyState.stateStack.size();
rsi.applyInstruction(dummyState);
assertTrue(dummyState.stateStack.size() == i + 1);
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
// remove rule for instruction
RestoreInstruction ri = new RestoreInstruction(0);
assertNotNull(ri.toString());
ri.applyInstruction(dummyState);
assertFalse(dummyState.regRules.containsKey(0));
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
RememberStateInstruction rsi1 = new RememberStateInstruction();
rsi1.applyInstruction(dummyState);
// remove rule for instruction
RestoreStateInstruction rsi = new RestoreStateInstruction();
assertNotNull(rsi.toString());
rsi.applyInstruction(dummyState);
assertFalse(dummyState.regRules.isEmpty());
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
DefCFAInstruction defCFA = new DefCFAInstruction(0, 12);
assertNotNull(defCFA.toString());
defCFA.applyInstruction(dummyState);
assertTrue(dummyState.getCFARegister() == 0);
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
SameValueInstruction svi = new SameValueInstruction(0);
assertNotNull(svi.toString());
svi.applyInstruction(dummyState);
assertFalse(dummyState.regRules.isEmpty());
} catch (Throwable t) {
}
dummyState = new InstructionState(null, null, null, fde);
try {
UndefinedInstruction svi = new UndefinedInstruction(0);
assertNotNull(svi.toString());
svi.applyInstruction(dummyState);
assertFalse(dummyState.regRules.isEmpty());
} catch (Throwable t) {
}
}
@Test
public void testModuleScopeStartEnd() {
for (TestInfo info : testInfos.values()) {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
assertNotNull(symbolReader);
IScope moduleScope = symbolReader.getModuleScope();
if (info.lowAddress != null) {
assertEquals(info.lowAddress, moduleScope.getLowAddress());
assertEquals(info.highAddress, moduleScope.getHighAddress());
}
}
}
@Test
public void testPubnames1() {
for (TestInfo info : testInfos.values()) {
if (info.numberOfPubFuncNames == 0) continue;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
DwarfDebugInfoProvider debugInfoProvider = (DwarfDebugInfoProvider) ((EDCSymbolReader) symbolReader).getDebugInfoProvider();
Map<String, List<PublicNameInfo>> pubs;
pubs = debugInfoProvider.getPublicFunctions();
boolean discover = false;
int total = 0;
for (String pub : pubs.keySet()) {
total += pubs.get(pub).size();
}
if (discover) {
System.out.println(info.symFile + ": " + pubs.size() + " / "+ total);
} else {
assertEquals(info.numberOfPubFuncNames, pubs.size());
assertEquals(info.numberOfPubFuncEntries, total);
}
pubs = debugInfoProvider.getPublicVariables();
total = 0;
for (String pub : pubs.keySet()) {
total += pubs.get(pub).size();
}
if (discover) {
System.out.println(info.symFile + ": " + pubs.size() + " / "+ total);
} else {
assertEquals(info.numberOfPubVarNames, pubs.size());
assertEquals(info.numberOfPubVarEntries, total);
}
}
}
@Test
public void testPubnames2() {
for (TestInfo info : testInfos.values()) {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
for (String name : info.pubFuncs) {
String simpleName = stripName(name);
Collection<IFunctionScope> funcs = symbolReader.getModuleScope().getFunctionsByName(simpleName);
assertNotNull(info.symFile.lastSegment() + ":" + name, funcs);
assertTrue(info.symFile.lastSegment() + ":" + name, !funcs.isEmpty());
for (IFunctionScope func : funcs) {
assertEquals(func.getName(), simpleName);
}
}
for (String name : info.pubVars) {
String simpleName = stripName(name);
Collection<IVariable> vars = symbolReader.getModuleScope().getVariablesByName(simpleName, false);
assertNotNull(info.symFile.lastSegment() + ":" + name, vars);
assertTrue(info.symFile.lastSegment() + ":" + name, !vars.isEmpty());
for (IVariable var : vars) {
assertEquals(var.getName(), simpleName);
}
}
}
}
/**
* Test that, for a given PC, we know which locals are in scope.
*/
@Test
public void testLocalScopes1() {
StringBuilder errors = new StringBuilder();
for (TestInfo info : testInfos.values()) {
for (String key : info.scopeInfos.keySet()) {
String[] split = key.split("\\|");
String file = split[0];
String func = split[1];
String className = split[2];
if (className.equals("null"))
className = null;
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
List<ICompileUnitScope> cuList = getCompileUnitsFor(symbolReader, file);
boolean found = false;
for (ICompileUnitScope cu : cuList) {
for (IFunctionScope scope : cu.getFunctions()) {
if (scope.getName().equals(func)) {
if (className != null) {
String theClassName = getClassFor(scope);
if (!theClassName.matches("(class|struct) " +className + "(<.*>)?"))
continue;
}
found = true;
String label = info.symFile.lastSegment() + ":" + file + (className!= null ? ":" + className : "") + ":" + func;
boolean discover = false;
if (discover) {
System.out.println(label);
Collection<IVariable> vars = scope.getVariables();
for (IVariable var : vars) System.out.println(var.getName());
vars = scope.getParameters();
for (IVariable var : vars) System.out.println(var.getName());
} else {
doTestLocalScopes1(errors, label, info.scopeInfos.get(key), scope);
}
}
}
}
assertTrue(info.symFile.lastSegment() + ":" + key, found);
}
}
if (errors.length() > 0)
fail(errors.toString());
}
/**
* @param errors
* @param scopeInfos
* @param scope
*/
private void doTestLocalScopes1(StringBuilder errors, String label, List<ScopeInfo> scopeInfos, IFunctionScope scope) {
// TODO: watch out for template functions, which are named the same
Addr32 startAddr = new Addr32(scopeInfos.get(0).address);
if (scope.getLowAddress().compareTo(startAddr) > 0
|| scope.getHighAddress().compareTo(startAddr) <= 0) {
return;
}
for (ScopeInfo scopeInfo : scopeInfos) {
try {
doTestScopeInfo(label, scope, scopeInfo);
} catch (AssertionError e) {
errors.append(e.getMessage());
errors.append('\n');
}
}
}
private void doTestScopeInfo(String label, IFunctionScope scope,
ScopeInfo scopeInfo) {
label += ":" + Integer.toHexString(scopeInfo.address);
Collection<IVariable> vars = scope.getScopedVariables(new Addr32(scopeInfo.address));
StringBuilder missing = new StringBuilder();
for (String name : scopeInfo.names) {
boolean found = false;
for (IVariable var : vars) {
if (var.getName().equals(name)) {
found = true;
break;
}
}
if (!found)
missing.append(name + ", ");
}
if (missing.length() > 0)
fail(label + ": missing "+ missing);
StringBuilder extra = new StringBuilder();
for (IVariable var : vars) {
boolean found = false;
for (String name : scopeInfo.names) {
if (name.equals(var.getName())) {
found = true;
break;
}
}
if (!found) {
extra.append(var.getName());
extra.append(", ");
}
}
if (extra.length() > 0)
fail(label +": found extra variables: " + extra);
}
/**
* Test that, for a given PC, we know which locals are in scope.
*/
@Test
public void testLocalLocations() {
StringBuilder errors = new StringBuilder();
for (TestInfo info : testInfos.values()) {
IEDCSymbolReader symbolReader = Symbols.getSymbolReader(info.symFile);
for (IScope cuscope : symbolReader.getModuleScope().getChildren()) {
ICompileUnitScope cu = (ICompileUnitScope) cuscope;
for (IFunctionScope scope : cu.getFunctions()) {
String label = info.symFile.lastSegment() + ":" + scope;
for (IVariable var : scope.getVariablesInTree()) {
checkVariableLocation(errors, label, scope, var);
}
}
}
}
if (errors.length() > 0)
fail(errors.toString());
}
/**
* @param errors
* @param label
* @param scope
* @param var
*/
private void checkVariableLocation(StringBuilder errors, String label,
IScope scope, IVariable var) {
ILocationProvider locationProvider = var.getLocationProvider();
if (locationProvider instanceof LocationExpression) {
LocationExpression expr = (LocationExpression) locationProvider;
IScope varScope = expr.getScope();
while (varScope instanceof ILexicalBlockScope ||
(varScope != null && varScope.getParent() instanceof IFunctionScope))
varScope = varScope.getParent();
if (!(varScope instanceof IFunctionScope)) {
errors.append("Wrong scope for " + var + ": " + varScope + "\n");
}
}
}
/**
* Be sure we zero extend when reading short DWARF attributes.
* One place this is quite important is in array bounds.
* Other cases in the reader are line tables, scope ranges, etc. which
* are unsigned. Enum values, though, must remain signed.
* @throws Exception
*/
@Test
public void testAttributePromotion() throws Exception {
// In here, we have a tmp[256] array, with DW_AT_upper_bound == 255.
// This validates some lazy code that always cast this stuff to a long
// without considering the sign extension.
// (BTW, this bug was logged for something else, and is not the bug being tested here)
IEDCSymbolReader reader = Symbols.getSymbolReader(getFile("bug303066.exe"));
assertNotNull(reader);
Collection<IFunctionScope> scopes = reader.getModuleScope().getFunctionsByName("main");
assertNotNull(scopes);
assertEquals(1, scopes.size());
boolean found = false;
int enumcnt = 0;
for (IVariable var : scopes.iterator().next().getVariables()) {
if (var.getName().equals("tmp")) {
IType type = var.getType();
assertTrue(type instanceof IArrayType);
IArrayBoundType bound = ((IArrayType) type).getBound(0);
assertEquals(256, bound.getBoundCount());
found = true;
}
// these attributes *should* be sign extended
if (var.getName().equals("val")) {
IType type = TypeUtils.getBaseType(var.getType());
for (IEnumerator enumr : ((IEnumeration)type).getEnumerators()) {
if (enumr.getName().equals("Val1")) {
assertEquals(255, enumr.getValue());
enumcnt++;
} else if (enumr.getName().equals("Val2")) {
assertEquals(65535, enumr.getValue());
enumcnt++;
} else if (enumr.getName().equals("Val3")) {
assertEquals(-255, enumr.getValue());
enumcnt++;
} else if (enumr.getName().equals("Val4")) {
assertEquals(-65535, enumr.getValue());
enumcnt++;
}
}
}
}
assertEquals("Found all Val enums", 4, enumcnt);
assertTrue("Did not find 'tmp'", found);
found = false;
for (IVariable var : reader.getModuleScope().getVariablesByName("bigbuffer", false)) {
IType type = var.getType();
assertTrue(type instanceof IArrayType);
IArrayBoundType bound = ((IArrayType) type).getBound(0);
assertEquals(65536, bound.getBoundCount());
found = true;
break;
}
assertTrue("Did not find 'bigbuffer'", found);
}
/**
* RVCT generates location lists with two duplicate address ranges, where
* the latter is the one to trust. Be sure we filter out the earlier ones.
* @throws Exception
*/
@Test
public void testBrokenLocationLists() throws Exception {
IPath file = getFile("BlackFlag_rvct.sym");
IEDCSymbolReader reader = Symbols.getSymbolReader(file);
// show_Const_Arguments
IFunctionScope func = (IFunctionScope) reader.getModuleScope().getScopeAtAddress(new Addr32(0x9648));
Collection<IVariable> variables = func.getParameters();
boolean found = false;
for (IVariable var : variables) {
if (var.getName().equals("aArg1")) {
found = true;
LocationEntry[] entries = ((LocationList)var.getLocationProvider()).getLocationEntries();
assertEquals(2, entries.length);
assertEquals(0x9648, entries[0].getLowPC());
assertEquals(1, entries[0].getBytes().length);
assertEquals((byte)0x50, entries[0].getBytes()[0]);
assertEquals("LocationEntry [bytes=[80], highPC=38474, lowPC=38472]", entries[0].toString());
break;
}
}
assertTrue(found);
}
}