From c6de9dc49301da57d3d7a572b64667bef7213139 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Fri, 19 Mar 2021 14:12:06 -0400 Subject: [PATCH] GP-743 fix DWARF handling of empty compile units and older gcc dwarf info --- .../util/bin/format/dwarf4/DIEAggregate.java | 27 +++++++++- .../bin/format/dwarf4/DWARFCompileUnit.java | 5 +- .../next/DWARFStaticVarImporterTest.java | 54 +++++++++++++++++++ .../util/bin/format/dwarf4/DIECreator.java | 18 +++++-- .../util/bin/format/dwarf4/DWARFTestBase.java | 26 ++++++++- .../dwarf4/MockDWARFCompilationUnit.java | 10 +++- 6 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java index 888e101975..35893f8ff8 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java @@ -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. + *
+ * This indicates an empty range, in which case the caller may want to take + * special steps to avoid issues with Ghidra ranges. + *
+ * 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.
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java
index 2b46c53442..3c8bd88929 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java
@@ -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();
}
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java
new file mode 100644
index 0000000000..331946e691
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java
@@ -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);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java
index ada4b7453f..506f22a8ad 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java
@@ -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;
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java
index a27508aace..6db58b90a1 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java
@@ -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);
+ }
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java
index b6b1c6643f..d254b9b52a 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java
@@ -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