GP-743 fix DWARF handling of empty compile units and older gcc dwarf info

This commit is contained in:
dev747368 2021-03-19 14:12:06 -04:00 committed by ghidra1
parent ce056f1ea9
commit c6de9dc493
6 changed files with 133 additions and 7 deletions

View file

@ -15,9 +15,10 @@
*/
package ghidra.app.util.bin.format.dwarf4;
import java.io.IOException;
import java.util.*;
import java.io.IOException;
import org.apache.commons.lang3.ArrayUtils;
import ghidra.app.util.bin.BinaryReader;
@ -884,6 +885,30 @@ public class DIEAggregate {
throw new IOException("Bad/unsupported DW_AT_high_pc attribute value or type");
}
/**
* Returns true if the raw lowPc and highPc values are the same.
* <p>
* This indicates an empty range, in which case the caller may want to take
* special steps to avoid issues with Ghidra ranges.
* <p>
* Only seen in extremely old gcc versions. Typically the low & high
* pc values are omitted if the CU is empty.
*
* @return boolean true if the LowPC and HighPC values are present and equal
*/
public boolean isLowPCEqualHighPC() {
AttrInfo low = findAttribute(DWARFAttribute.DW_AT_low_pc);
AttrInfo high = findAttribute(DWARFAttribute.DW_AT_high_pc);
if (low != null && high != null && low.form == high.form &&
low.attr instanceof DWARFNumericAttribute &&
high.attr instanceof DWARFNumericAttribute) {
DWARFNumericAttribute lowVal = (DWARFNumericAttribute) low.attr;
DWARFNumericAttribute highVal = (DWARFNumericAttribute) high.attr;
return lowVal.getValue() == highVal.getValue();
}
return false;
}
/**
* A simple class used by findAttribute() to return the found attribute, along with
* the DIE it was found in, and the DWARFForm type of the raw attribute.

View file

@ -49,11 +49,14 @@ public class DWARFCompileUnit {
String comp_dir = diea.getString(DWARFAttribute.DW_AT_comp_dir, null);
Number high_pc = null, low_pc = null, language = null, stmt_list = null;
if (diea.hasAttribute(DWARFAttribute.DW_AT_low_pc)) {
low_pc = diea.getLowPC(0);
}
if (diea.hasAttribute(DWARFAttribute.DW_AT_high_pc)) {
// if lowPC and highPC values are the same, don't read the high value
// because Ghidra can't express an empty range.
if (diea.hasAttribute(DWARFAttribute.DW_AT_high_pc) && !diea.isLowPCEqualHighPC()) {
high_pc = diea.getHighPC();
}

View file

@ -0,0 +1,54 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.dwarf4.next;
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes;
import ghidra.program.model.data.IntegerDataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.util.exception.CancelledException;
public class DWARFStaticVarImporterTest extends DWARFTestBase {
@Test
public void testIntStaticVar() throws CancelledException, IOException, DWARFException {
DebugInfoEntry intDIE = addInt(cu);
new DIECreator(DWARFTag.DW_TAG_variable)
.addString(DW_AT_name, "static_var1")
.addRef(DW_AT_type, intDIE)
.addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0,
0, 0)
.create(cu);
importFunctions();
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x410));
assertNotNull(cu);
assertEquals("static_var1", cu.getLabel());
assertEquals(4, cu.getLength());
assertTrue(((Data) cu).getDataType() instanceof IntegerDataType);
}
}

View file

@ -87,6 +87,16 @@ public class DIECreator {
return this;
}
public DIECreator addBlock(int attribute, int... intBytes) {
byte[] bytes = new byte[intBytes.length];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) intBytes[i];
}
attributes.put(attribute,
new AttrInfo(attribute, DWARFForm.DW_FORM_block1, new DWARFBlobAttribute(bytes)));
return this;
}
DWARFAbbreviation createAbbreviation(MockDWARFCompilationUnit cu) {
DWARFAttributeSpecification[] attrSpecs =
new DWARFAttributeSpecification[attributes.size()];
@ -121,13 +131,15 @@ public class DIECreator {
die.addChild(childDIE);
}
cu.addMockEntry(die);
if (parent == null) {
parent = cu.getCompileUnitDIE();
}
if (parent != null) {
die.setParent(parent);
Assert.assertTrue(parent.getCompilationUnit() == cu);
parent.addChild(die);
die.setParent(parent);
}
cu.addMockEntry(die);
return die;
}

View file

@ -32,6 +32,8 @@ import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.NullSectionProvide
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataTypeManager;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
@ -44,7 +46,10 @@ import ghidra.util.task.TaskMonitor;
*/
public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
protected static final long BaseAddress = 0x400;
protected ProgramDB program;
protected AddressSpace space;
protected DataTypeManagerDB dataMgr;
protected DataTypeManager builtInDTM;
protected int transactionID;
@ -62,10 +67,16 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
*/
@Before
public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._X64, this);
space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataTypeManager();
startTransaction();
program.getMemory()
.createInitializedBlock("test", addr(BaseAddress), 500, (byte) 0, TaskMonitor.DUMMY,
false);
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program);
DataTypeManagerService dtms = mgr.getDataTypeManagerService();
builtInDTM = dtms.getBuiltInDataTypesManager();
@ -113,6 +124,16 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
dwarfDTM.importAllDataTypes(monitor);
}
protected void importFunctions() throws CancelledException, IOException, DWARFException {
dwarfProg.checkPreconditions(monitor);
dwarfDTM.importAllDataTypes(monitor);
DWARFImportSummary importSummary = new DWARFImportSummary();
DWARFFunctionImporter dfi =
new DWARFFunctionImporter(dwarfProg, dwarfDTM, importOptions, importSummary, monitor);
dfi.importFunctions();
}
protected DIEAggregate getAggregate(DebugInfoEntry die)
throws CancelledException, IOException, DWARFException {
dwarfProg.setCurrentCompilationUnit(die.getCompilationUnit(), monitor);
@ -278,4 +299,7 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
return arrayType;
}
protected Address addr(long l) {
return space.getAddress(l);
}
}

View file

@ -18,13 +18,14 @@ package ghidra.app.util.bin.format.dwarf4;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFIdentifierCase;
import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.util.task.TaskMonitor;
public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
private List<DebugInfoEntry> mockEntries = new ArrayList<>();
private DebugInfoEntry compUnitDIE;
public MockDWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset,
long length, int format, short version, long abbreviationOffset, byte pointerSize,
@ -35,6 +36,9 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
setCompileUnit(
new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer", "Mock Comp Unit Dir",
0, 0, 0, 0, DWARFIdentifierCase.DW_ID_case_insensitive, false, null));
compUnitDIE = new DIECreator(DWARFTag.DW_TAG_compile_unit)
.addString(DWARFAttribute.DW_AT_name, "MockCompUnit" + compUnitNumber)
.create(this);
}
@Override
@ -42,6 +46,10 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
dies.addAll(mockEntries);
}
public DebugInfoEntry getCompileUnitDIE() {
return compUnitDIE;
}
public void addMockEntry(DebugInfoEntry die) {
mockEntries.add(die);
}