diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARFSetExternalDebugFilesLocationPrescript.java b/Ghidra/Features/Base/ghidra_scripts/DWARFSetExternalDebugFilesLocationPrescript.java
index dbd6b6f34c..dcde006cc2 100644
--- a/Ghidra/Features/Base/ghidra_scripts/DWARFSetExternalDebugFilesLocationPrescript.java
+++ b/Ghidra/Features/Base/ghidra_scripts/DWARFSetExternalDebugFilesLocationPrescript.java
@@ -26,7 +26,7 @@ import java.util.ArrayList;
import java.util.List;
import ghidra.app.script.GhidraScript;
-import ghidra.app.util.bin.format.dwarf4.external.*;
+import ghidra.app.util.bin.format.dwarf.external.*;
import ghidra.util.Msg;
public class DWARFSetExternalDebugFilesLocationPrescript extends GhidraScript {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
index 6ae117201b..3b7ff08aed 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/DWARFAnalyzer.java
@@ -18,9 +18,9 @@ package ghidra.app.plugin.core.analysis;
import java.io.IOException;
import ghidra.app.services.*;
-import ghidra.app.util.bin.format.dwarf4.next.*;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProviderFactory;
+import ghidra.app.util.bin.format.dwarf.*;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProviderFactory;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.AddressSetView;
@@ -94,15 +94,15 @@ public class DWARFAnalyzer extends AbstractAnalyzer {
try {
try (DWARFProgram prog = new DWARFProgram(program, importOptions, monitor, dsp)) {
if (prog.getRegisterMappings() == null && importOptions.isImportFuncs()) {
- log.appendMsg(
- "No DWARF to Ghidra register mappings found for this program's language [%s], function information may be incorrect / incomplete."
+ log.appendMsg("No DWARF to Ghidra register mappings found for this program's " +
+ "language [%s], function information may be incorrect / incomplete."
.formatted(program.getLanguageID().getIdAsString()));
}
prog.init(monitor);
- DWARFParser dp = new DWARFParser(prog, monitor);
- DWARFImportSummary parseResults = dp.parse();
- parseResults.logSummaryResults();
+ DWARFImporter importer = new DWARFImporter(prog, monitor);
+ DWARFImportSummary importResults = importer.performImport();
+ importResults.logSummaryResults();
}
Options propList = program.getOptions(Program.PROGRAM_INFO);
propList.setBoolean(DWARF_LOADED_OPTION_NAME, true);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/LEB128Info.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/LEB128Info.java
index 903a5a7b97..fb0820de88 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/LEB128Info.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/LEB128Info.java
@@ -17,9 +17,7 @@ package ghidra.app.util.bin;
import java.io.IOException;
-import ghidra.program.model.address.Address;
import ghidra.program.model.data.LEB128;
-import ghidra.program.model.listing.Program;
/**
* Class to hold result of reading a {@link LEB128} value, along with size and position metadata.
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/dwarf/DIEAggregate.java
similarity index 54%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEAggregate.java
index 3db7f23d73..94470288aa 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/dwarf/DIEAggregate.java
@@ -13,23 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.util.*;
import org.apache.commons.lang3.ArrayUtils;
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.attribs.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.*;
-import ghidra.app.util.bin.format.dwarf4.expression.*;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.app.util.bin.format.dwarf.expression.*;
import ghidra.util.Msg;
-import ghidra.util.NumericUtilities;
/**
* DIEAggregate groups related {@link DebugInfoEntry} records together in a single interface
@@ -52,8 +48,6 @@ public class DIEAggregate {
*/
private static final int MAX_FRAGMENT_COUNT = 20;
- public static final int[] REF_ATTRS = { DW_AT_abstract_origin, DW_AT_specification };
-
/**
* A list of {@link DebugInfoEntry DIEs} that make up this DWARF program element, with
* the 'head'-most listed first, followed by earlier less specified DIEs, ending with
@@ -119,8 +113,8 @@ public class DIEAggregate {
* Used when a DIEA is composed of a head DIE with a different TAG type than the rest of
* the DIEs. (ie. a dw_tag_call_site -> dw_tag_sub DIEA)
*
- * @param source
- * @return
+ * @param source {@link DIEAggregate} containing fragments
+ * @return {@link DIEAggregate} with the fragments of the source, skipping the first
*/
public static DIEAggregate createSkipHead(DIEAggregate source) {
if (source.fragments.length == 1) {
@@ -137,8 +131,8 @@ public class DIEAggregate {
* Mainly useful early in the {@link DWARFCompilationUnit}'s bootstrapping process
* when it needs to read values from DIEs.
*
- * @param die
- * @return
+ * @param die {@link DebugInfoEntry}
+ * @return {@link DIEAggregate} containing a single DIE
*/
public static DIEAggregate createSingle(DebugInfoEntry die) {
DIEAggregate result = new DIEAggregate(new DebugInfoEntry[] { die });
@@ -149,7 +143,8 @@ public class DIEAggregate {
/**
* Private ctor to force use of the static factory methods {@link #createFromHead(DebugInfoEntry)}
* and {@link #createSingle(DebugInfoEntry)}.
- * @param die
+ *
+ * @param fragments array of DIEs that make this aggregate
*/
private DIEAggregate(DebugInfoEntry[] fragments) {
this.fragments = fragments;
@@ -164,7 +159,7 @@ public class DIEAggregate {
* call {@link #flipFragments()} after the build phase to reverse the order of the
* DIE fragments list so that querying for attribute values will return the correct values.
*
- * @param newDIE
+ * @param newDIE {@link DebugInfoEntry} to add
*/
private void addFragment(DebugInfoEntry newDIE) {
DebugInfoEntry[] tmp = new DebugInfoEntry[fragments.length + 1];
@@ -215,13 +210,13 @@ public class DIEAggregate {
/**
* Returns {@link #getOffset()} as a hex string.
- * @return
+ * @return string hex offset of the head DIE
*/
public String getHexOffset() {
return Long.toHexString(getHeadFragment().getOffset());
}
- public int getTag() {
+ public DWARFTag getTag() {
return getHeadFragment().getTag();
}
@@ -235,7 +230,7 @@ public class DIEAggregate {
/**
* Returns the last {@link DebugInfoEntry DIE} fragment, ie. the decl DIE.
- * @return
+ * @return last DIE of this aggregate
*/
public DebugInfoEntry getLastFragment() {
return fragments[fragments.length - 1];
@@ -244,7 +239,7 @@ public class DIEAggregate {
/**
* Returns the first {@link DebugInfoEntry DIE} fragment, ie. the spec or abstract_origin
* DIE.
- * @return
+ * @return first DIE of this aggregate
*/
public DebugInfoEntry getHeadFragment() {
return fragments[0];
@@ -272,27 +267,18 @@ public class DIEAggregate {
* This value matches the nesting value shown when dumping DWARF
* info using 'readelf'.
*
- * @return
+ * @return depth of this instance, from the root of its head DIE fragment, with 0 indicating
+ * that this instance was already the root of the compUnit
*/
public int getDepth() {
return getProgram().getParentDepth(getHeadFragment().getIndex());
}
- private AttrInfo findAttribute(int attribute) {
+ private FoundAttribute findAttribute(DWARFAttribute attribute) {
for (DebugInfoEntry die : fragments) {
- DWARFAttributeValue[] dieAttrValues = die.getAttributes();
- DWARFAttributeSpecification[] attrDefs = die.getAbbreviation().getAttributes();
- for (int i = 0; i < attrDefs.length; i++) {
- DWARFAttributeSpecification attrDef = attrDefs[i];
- if (attrDef.getAttribute() == attribute) {
- DWARFAttributeValue attrVal = dieAttrValues[i];
- DWARFForm form = attrDef.getAttributeForm();
- if (attrVal instanceof DWARFIndirectAttribute) {
- form = ((DWARFIndirectAttribute) attrVal).getForm();
- attrVal = ((DWARFIndirectAttribute) attrVal).getValue();
- }
- return new AttrInfo(attrVal, die, form);
- }
+ DWARFAttributeValue attrVal = die.findAttribute(attribute);
+ if (attrVal != null) {
+ return new FoundAttribute(attrVal, die);
}
}
return null;
@@ -302,14 +288,14 @@ public class DIEAggregate {
* Return an attribute that is present in this {@link DIEAggregate}, or in any of its
* direct children (of a specific type)
*
- * @param
+ * @param attribute value type
* @param attribute the attribute to find
* @param childTag the type of children to search
* @param clazz type of the attribute to return
* @return attribute value, or null if not found
*/
- public T findAttributeInChildren(int attribute, int childTag,
- Class clazz) {
+ public T findAttributeInChildren(DWARFAttribute attribute,
+ DWARFTag childTag, Class clazz) {
T attributeValue = getAttribute(attribute, clazz);
if (attributeValue != null) {
return attributeValue;
@@ -325,7 +311,7 @@ public class DIEAggregate {
}
/**
- * Finds a {@link DWARFAttributeValue attribute} with a matching {@link DWARFAttribute} type
+ * Finds a {@link DWARFAttributeValue attribute} with a matching {@link DWARFAttribute} id.
*
* Returns null if the attribute does not exist or is wrong java class type.
*
@@ -335,14 +321,27 @@ public class DIEAggregate {
*
* @param attribute See {@link DWARFAttribute}
* @param clazz must be derived from {@link DWARFAttributeValue}
- * @return
+ * @return DWARFAttributeValue or subclass as specified by the clazz, or null if not found
*/
- public T getAttribute(int attribute, Class clazz) {
- AttrInfo attrInfo = findAttribute(attribute);
+ public T getAttribute(DWARFAttribute attribute,
+ Class clazz) {
+ FoundAttribute attrInfo = findAttribute(attribute);
return attrInfo != null ? attrInfo.getValue(clazz) : null;
}
- public DWARFAttributeValue getAttribute(int attribute) {
+ /**
+ * Finds a {@link DWARFAttributeValue attribute} with a matching {@link DWARFAttribute} id.
+ *
+ * Returns null if the attribute does not exist.
+ *
+ * Attributes are searched for in each fragment in this aggregate, starting with the
+ * 'head' fragment, progressing toward the 'decl' fragment.
+ *
+ *
+ * @param attribute See {@link DWARFAttribute}
+ * @return DWARFAttributeValue, or null if not found
+ */
+ public DWARFAttributeValue getAttribute(DWARFAttribute attribute) {
return getAttribute(attribute, DWARFAttributeValue.class);
}
@@ -350,11 +349,11 @@ public class DIEAggregate {
* Returns the value of the requested attribute, or -defaultValue- if the
* attribute is missing.
*
- * @param attribute
- * @param defaultValue
- * @return
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return long value, or the defaultValue if attribute not present
*/
- public long getLong(int attribute, long defaultValue) {
+ public long getLong(DWARFAttribute attribute, long defaultValue) {
DWARFNumericAttribute attr = getAttribute(attribute, DWARFNumericAttribute.class);
return (attr != null) ? attr.getValue() : defaultValue;
}
@@ -363,11 +362,11 @@ public class DIEAggregate {
* Returns the boolean value of the requested attribute, or -defaultValue- if
* the attribute is missing or not the correct type.
*
- * @param attribute
- * @param defaultValue
- * @return
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return boolean value, or the defaultValue if attribute is not present
*/
- public boolean getBool(int attribute, boolean defaultValue) {
+ public boolean getBool(DWARFAttribute attribute, boolean defaultValue) {
DWARFBooleanAttribute val = getAttribute(attribute, DWARFBooleanAttribute.class);
return (val != null) ? val.getValue() : defaultValue;
}
@@ -376,23 +375,26 @@ public class DIEAggregate {
* Returns the string value of the requested attribute, or -defaultValue- if
* the attribute is missing or not the correct type.
*
- * @param attribute
- * @param defaultValue
- * @return
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return String value, or the defaultValue if attribute is not present
*/
- public String getString(int attribute, String defaultValue) {
- DWARFStringAttribute attr = getAttribute(attribute, DWARFStringAttribute.class);
- return (attr != null) ? attr.getValue(getProgram().getDebugStrings()) : defaultValue;
+ public String getString(DWARFAttribute attribute, String defaultValue) {
+ FoundAttribute attrInfo = findAttribute(attribute);
+ if (attrInfo == null || !(attrInfo.attr instanceof DWARFStringAttribute strAttr)) {
+ return defaultValue;
+ }
+ return strAttr.getValue(attrInfo.die.getCompilationUnit());
}
/**
* Returns the string value of the {@link DWARFAttribute#DW_AT_name dw_at_name} attribute,
* or null if it is missing.
*
- * @return
+ * @return name of this DIE aggregate, or null if missing
*/
public String getName() {
- return getString(DWARFAttribute.DW_AT_name, null);
+ return getString(DW_AT_name, null);
}
/**
@@ -403,30 +405,23 @@ public class DIEAggregate {
* the dwarf information (ie. a value with the high bit set is not treated as signed).
*
* The -defaultValue- parameter can accept a negative value.
- * @param attribute
- * @param defaultValue
- * @return
+ *
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return unsigned long value, or the defaultValue if attribute is not present
*/
- public long getUnsignedLong(int attribute, long defaultValue) {
+ public long getUnsignedLong(DWARFAttribute attribute, long defaultValue) {
DWARFNumericAttribute attr = getAttribute(attribute, DWARFNumericAttribute.class);
return (attr != null) ? attr.getUnsignedValue() : defaultValue;
}
- /**
- * Returns the {@link DebugInfoEntry die} instance pointed to by the requested attribute,
- * or null if the attribute does not exist.
- *
- * @param attribute
- * @return
- */
- public DebugInfoEntry getRefDIE(int attribute) {
- AttrInfo attrInfo = findAttribute(attribute);
- if (attrInfo == null) {
+ private DebugInfoEntry getRefDIE(DWARFAttribute attribute) {
+ DWARFNumericAttribute val = getAttribute(attribute, DWARFNumericAttribute.class);
+ if (val == null) {
return null;
}
- DWARFNumericAttribute val = attrInfo.getValue(DWARFNumericAttribute.class);
- long offset = (val != null) ? val.getUnsignedValue() : -1;
+ long offset = val.getUnsignedValue();
DebugInfoEntry result = getProgram().getDIEByOffset(offset);
if (result == null) {
@@ -436,7 +431,14 @@ public class DIEAggregate {
return result;
}
- public DIEAggregate getRef(int attribute) {
+ /**
+ * Returns the {@link DIEAggregate diea} instance pointed to by the requested attribute,
+ * or null if the attribute does not exist.
+ *
+ * @param attribute {@link DWARFAttribute} id
+ * @return {@link DIEAggregate}, or the null if attribute is not present
+ */
+ public DIEAggregate getRef(DWARFAttribute attribute) {
DebugInfoEntry die = getRefDIE(attribute);
return getProgram().getAggregate(die);
}
@@ -447,11 +449,11 @@ public class DIEAggregate {
* @return DIEA pointed to by the DW_AT_containing_type attribute, or null if not present.
*/
public DIEAggregate getContainingTypeRef() {
- return getRef(DWARFAttribute.DW_AT_containing_type);
+ return getRef(DW_AT_containing_type);
}
public DIEAggregate getTypeRef() {
- return getRef(DWARFAttribute.DW_AT_type);
+ return getRef(DW_AT_type);
}
/**
@@ -460,7 +462,7 @@ public class DIEAggregate {
* @return name of file this item was declared in, or null if info not available
*/
public String getSourceFile() {
- AttrInfo attrInfo = findAttribute(DWARFAttribute.DW_AT_decl_file);
+ FoundAttribute attrInfo = findAttribute(DW_AT_decl_file);
if (attrInfo == null) {
return null;
}
@@ -469,10 +471,8 @@ public class DIEAggregate {
return null;
}
int fileNum = (int) attr.getUnsignedValue();
- DWARFCompileUnit dcu = attrInfo.die.getCompilationUnit().getCompileUnit();
- return dcu.isValidFileIndex(fileNum)
- ? dcu.getFileByIndex(fileNum)
- : null;
+ DWARFCompilationUnit cu = attrInfo.die.getCompilationUnit();
+ return cu.isValidFileIndex(fileNum) ? cu.getFileByIndex(fileNum) : null;
}
/**
@@ -481,11 +481,17 @@ public class DIEAggregate {
* @param childTag see {@link DWARFTag DWARFTag DW_TAG_* values}
* @return List of children DIEs that match the specified tag
*/
- public List getChildren(int childTag) {
+ public List getChildren(DWARFTag childTag) {
return getHeadFragment().getChildren(childTag);
}
- public boolean hasAttribute(int attribute) {
+ /**
+ * Returns true if the specified attribute is present.
+ *
+ * @param attribute attribute id
+ * @return boolean true if value is present
+ */
+ public boolean hasAttribute(DWARFAttribute attribute) {
return findAttribute(attribute) != null;
}
@@ -497,12 +503,11 @@ public class DIEAggregate {
* abstract portion
*/
public DIEAggregate getAbstractInstance() {
- AttrInfo aoAttr = findAttribute(DW_AT_abstract_origin);
+ FoundAttribute aoAttr = findAttribute(DW_AT_abstract_origin);
if (aoAttr == null) {
return null;
}
- int aoIndex = 0;
- for (; aoIndex < fragments.length; aoIndex++) {
+ for (int aoIndex = 0; aoIndex < fragments.length; aoIndex++) {
if (fragments[aoIndex] == aoAttr.die) {
DebugInfoEntry[] partialFrags = new DebugInfoEntry[fragments.length - aoIndex - 1];
System.arraycopy(fragments, aoIndex + 1, partialFrags, 0, partialFrags.length);
@@ -516,34 +521,32 @@ public class DIEAggregate {
* Returns the signed integer value of the requested attribute after resolving
* any DWARF expression opcodes.
*
- * @param attribute
- * @param defaultValue
- * @return
- * @throws IOException
- * @throws DWARFExpressionException
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return int value, or the defaultValue if attribute is not present
+ * @throws IOException if error reading value or invalid value type
+ * @throws DWARFExpressionException if error evaluating a DWARF expression
*/
- public int parseInt(int attribute, int defaultValue)
+ public int parseInt(DWARFAttribute attribute, int defaultValue)
throws IOException, DWARFExpressionException {
- AttrInfo attrInfo = findAttribute(attribute);
- if (attrInfo == null) {
+ DWARFAttributeValue attr = getAttribute(attribute);
+ if (attr == null) {
return defaultValue;
}
- DWARFAttributeValue attr = attrInfo.attr;
if (attr instanceof DWARFNumericAttribute dnum) {
return assertValidInt(dnum.getValue());
}
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
- DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
+ DWARFExpressionEvaluator evaluator = new DWARFExpressionEvaluator(getCompilationUnit());
DWARFExpression expr = evaluator.readExpr(exprBytes);
evaluator.evaluate(expr, 0);
return assertValidInt(evaluator.pop());
}
else {
- throw new IOException(
- "DWARF attribute form not valid for integer value: " + attrInfo.form);
+ throw new IOException("Not integer attribute: %s".formatted(attr));
}
}
@@ -551,15 +554,15 @@ public class DIEAggregate {
* Returns the unsigned integer value of the requested attribute after resolving
* any DWARF expression opcodes.
*
- * @param attribute
- * @param defaultValue
- * @return
- * @throws IOException
- * @throws DWARFExpressionException
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return unsigned long value, or the defaultValue if attribute is not present
+ * @throws IOException if error reading value or invalid value type
+ * @throws DWARFExpressionException if error evaluating a DWARF expression
*/
- public long parseUnsignedLong(int attribute, long defaultValue)
+ public long parseUnsignedLong(DWARFAttribute attribute, long defaultValue)
throws IOException, DWARFExpressionException {
- AttrInfo attrInfo = findAttribute(attribute);
+ FoundAttribute attrInfo = findAttribute(attribute);
if (attrInfo == null) {
return defaultValue;
}
@@ -570,15 +573,15 @@ public class DIEAggregate {
}
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
- DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
+ DWARFExpressionEvaluator evaluator =
+ new DWARFExpressionEvaluator(attrInfo.die().getCompilationUnit());
DWARFExpression expr = evaluator.readExpr(exprBytes);
evaluator.evaluate(expr, 0);
return evaluator.pop();
}
else {
- throw new IOException(
- "DWARF attribute form not valid for integer value: " + attrInfo.form);
+ throw new IOException("Not integer attribute: %s".formatted(attr));
}
}
@@ -600,27 +603,26 @@ public class DIEAggregate {
* Returns the unsigned integer value of the requested attribute after resolving
* any DWARF expression opcodes.
*
- * @param attribute
- * @param defaultValue
- * @return
- * @throws DWARFException
- * @throws DWARFExpressionException
+ * @param attribute {@link DWARFAttribute} id
+ * @param defaultValue value to return if attribute is not present
+ * @return unsigned int value, or the defaultValue if attribute is not present
+ * @throws IOException if error reading value or invalid value type
+ * @throws DWARFExpressionException if error evaluating a DWARF expression
*/
- public int parseDataMemberOffset(int attribute, int defaultValue)
- throws DWARFException, DWARFExpressionException {
+ public int parseDataMemberOffset(DWARFAttribute attribute, int defaultValue)
+ throws DWARFExpressionException, IOException {
- AttrInfo attrInfo = findAttribute(attribute);
- if (attrInfo == null) {
+ DWARFAttributeValue attr = getAttribute(attribute);
+ if (attr == null) {
return defaultValue;
}
- DWARFAttributeValue attr = attrInfo.attr;
if (attr instanceof DWARFNumericAttribute dnum) {
- return assertValidUInt(dnum.getUnsignedValue());
+ return dnum.getUnsignedIntExact();
}
else if (attr instanceof DWARFBlobAttribute dblob) {
byte[] exprBytes = dblob.getBytes();
- DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
+ DWARFExpressionEvaluator evaluator = new DWARFExpressionEvaluator(getCompilationUnit());
DWARFExpression expr = evaluator.readExpr(exprBytes);
// DW_AT_data_member_location expects the address of the containing object
@@ -630,138 +632,43 @@ public class DIEAggregate {
return assertValidUInt(evaluator.pop());
}
else {
- throw new DWARFException(
- "DWARF attribute form not valid for data member offset: " + attrInfo.form);
+ throw new DWARFException("DWARF attribute form not valid for data member offset: %s"
+ .formatted(attr.getAttributeForm()));
}
}
/**
- * Returns the location list info specified in the attribute.
- *
- * Numeric attributes are treated as offsets into the debug_loc section.
- *
- * Blob attributes are treated as a single location record for the current CU, using the
- * blob bytes as the DWARF expression of the location record.
- *
- * @param attribute the attribute to evaluate
- * @param range the address range the location covers (may be discarded if the attribute
- * value is a location list with its own range values)
- * @return list of locations, empty if missing, never null
- * @throws IOException
+ * Parses a location attribute value, which can be a single expression that is valid for any
+ * PC, or a list of expressions that are tied to specific ranges.
+ *
+ * @param attribute typically {@link DWARFAttribute#DW_AT_location}
+ * @return a {@link DWARFLocationList}, never null, possibly empty
+ * @throws IOException if error reading data
*/
- public List getAsLocation(int attribute, DWARFRange range) throws IOException {
- AttrInfo attrInfo = findAttribute(attribute);
- if (attrInfo == null) {
- return List.of();
- }
- else if (attrInfo.attr instanceof DWARFNumericAttribute dnum) {
- return readDebugLocList(dnum.getUnsignedValue());
- }
- else if (attrInfo.attr instanceof DWARFBlobAttribute dblob) {
- return _exprBytesAsLocation(dblob, range);
- }
- else {
- throw new UnsupportedOperationException(
- "This method is unsupported for the attribute type " + attrInfo.form + ".");
- }
+ public DWARFLocationList getLocationList(DWARFAttribute attribute) throws IOException {
+ return getProgram().getLocationList(this, attribute);
}
/**
- * Evaluate the DWARFExpression located in the DWARFLocation object in the context of
- * this DIEA.
- *
- * @param location
- * @return
- * @throws IOException
- * @throws DWARFExpressionException
+ * Parses a location attribute value, and returns the {@link DWARFLocation} instance that
+ * covers the specified pc.
+ *
+ * @param attribute typically {@link DWARFAttribute#DW_AT_location}
+ * @param pc program counter
+ * @return a {@link DWARFLocationList}, never null, possibly empty
+ * @throws IOException if error reading data
*/
- public long evaluateLocation(DWARFLocation location)
- throws IOException, DWARFExpressionException {
- DWARFExpressionEvaluator evaluator = DWARFExpressionEvaluator.create(getHeadFragment());
- DWARFExpression expr = evaluator.readExpr(location.getLocation());
-
- evaluator.evaluate(expr);
- return evaluator.pop();
- }
-
- /**
- * Return a list of DWARF locations read from the debug_loc section.
- *
- * The deserialization done here is very similar to {@link #parseDebugRange(int)}, but in this
- * case also contains a blob payload per location.
- *
- * @param offset offset into the debug_loc section
- * @return list of DWARF locations (address range and location expression)
- * @throws IOException if an I/O error occurs
- */
- private List readDebugLocList(long offset) throws IOException {
- BinaryReader debug_loc = getProgram().getDebugLocation();
-
- List results = new ArrayList<>();
- if (debug_loc == null) {
- return results;
- }
-
- debug_loc.setPointerIndex(offset);
- byte pointerSize = getCompilationUnit().getPointerSize();
-
- Number baseAddress = getCompilationUnit().getCompileUnit().getLowPC();
- long baseAddressOffset = (baseAddress != null) ? baseAddress.longValue() : 0;
-
- Number cuLowPC = getCompilationUnit().getCompileUnit().getLowPC();
- long cuBase = (cuLowPC != null) ? cuLowPC.longValue() : Long.MAX_VALUE;
-
- // Loop through the debug_loc entry
- while (debug_loc.getPointerIndex() < debug_loc.length()) {
- long beginning = DWARFUtil.readAddressAsLong(debug_loc, pointerSize);
- long ending = DWARFUtil.readAddressAsLong(debug_loc, pointerSize);
-
- // List end
- if (beginning == 0 && ending == 0) {
- break;
- }
-
- // Check to see if this is a base address entry
- if (beginning == -1 ||
- (pointerSize == 4 && beginning == NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG)) {
- baseAddressOffset = ending;
- continue;
- }
-
- // Size is 2 bytes
- int size = debug_loc.readNextUnsignedShort();
-
- // Read the location description
- byte[] location = debug_loc.readNextByteArray(size);
-
- // Test to see if the 'offset' read from the debug_loc data is already
- // greater-than the compunit's lowpc. This indicates the 'offset' isn't
- // an offset, but already an absolute value. This occurs in some
- // gcc dwarf compilation flag combinations.
- boolean isBadOffset = (beginning > cuBase);
-
- long absStart = beginning;
- long absEnd = ending;
- if (!isBadOffset) {
- absStart += baseAddressOffset;
- absEnd += baseAddressOffset;
- }
-
- // TODO: verify end addr calc with DWARFstd.pdf, inclusive vs exclusive
- results.add(new DWARFLocation(new DWARFRange(absStart, absEnd + 1), location));
- }
- return results;
- }
-
- private List _exprBytesAsLocation(DWARFBlobAttribute attr, DWARFRange range) {
- return List.of(new DWARFLocation(range, attr.getBytes()));
+ public DWARFLocation getLocation(DWARFAttribute attribute, long pc) throws IOException {
+ DWARFLocationList locList = getLocationList(attribute);
+ return locList.getLocationContaining(pc);
}
/**
* Returns true if this DIE has a DW_AT_declaration attribute and
* does NOT have a matching inbound DW_AT_specification reference.
*
- * @return
+ * @return boolean true if this DIE has a DW_AT_declaration attribute and
+ * does NOT have a matching inbound DW_AT_specification reference
*/
public boolean isDanglingDeclaration() {
return isPartialDeclaration() && fragments.length == 1;
@@ -769,80 +676,10 @@ public class DIEAggregate {
/**
* Returns true if this DIE has a DW_AT_declaration attribute.
- * @return
+ * @return true if this DIE has a DW_AT_declaration attribute
*/
public boolean isPartialDeclaration() {
- return hasAttribute(DWARFAttribute.DW_AT_declaration);
- }
-
- public boolean isNamedType() {
- switch (getTag()) {
- case DWARFTag.DW_TAG_base_type:
- case DWARFTag.DW_TAG_typedef:
- case DWARFTag.DW_TAG_namespace:
- case DWARFTag.DW_TAG_subprogram:
- case DWARFTag.DW_TAG_class_type:
- case DWARFTag.DW_TAG_interface_type:
- case DWARFTag.DW_TAG_structure_type:
- case DWARFTag.DW_TAG_union_type:
- case DWARFTag.DW_TAG_enumeration_type:
- case DWARFTag.DW_TAG_subroutine_type:
- case DWARFTag.DW_TAG_unspecified_type:
- return true;
-
- case DWARFTag.DW_TAG_pointer_type:
- case DWARFTag.DW_TAG_reference_type:
- case DWARFTag.DW_TAG_const_type:
- case DWARFTag.DW_TAG_lexical_block:
- default:
- return false;
- }
- }
-
- /**
- * Returns true if the children of this DIE are within a new namespace.
- *
- * Ie. Namespaces, subprogram, class, interface, struct, union, enum
- * @return
- */
- public boolean isNameSpaceContainer() {
- switch (getTag()) {
- case DWARFTag.DW_TAG_namespace:
- case DWARFTag.DW_TAG_subprogram:
- case DWARFTag.DW_TAG_lexical_block:
- case DWARFTag.DW_TAG_class_type:
- case DWARFTag.DW_TAG_interface_type:
- case DWARFTag.DW_TAG_structure_type:
- case DWARFTag.DW_TAG_union_type:
- case DWARFTag.DW_TAG_enumeration_type:
- return true;
- }
- return false;
- }
-
- /**
- * Returns true if this DIE defines a structure-like element (class, struct, interface, union).
- *
- * @return
- */
- public boolean isStructureType() {
- switch (getTag()) {
- case DWARFTag.DW_TAG_class_type:
- case DWARFTag.DW_TAG_interface_type:
- case DWARFTag.DW_TAG_structure_type:
- case DWARFTag.DW_TAG_union_type:
- return true;
- }
- return false;
- }
-
- public boolean isFuncDefType() {
- switch (getTag()) {
- case DWARFTag.DW_TAG_subprogram:
- case DWARFTag.DW_TAG_subroutine_type:
- return true;
- }
- return false;
+ return hasAttribute(DW_AT_declaration);
}
@Override
@@ -850,7 +687,7 @@ public class DIEAggregate {
StringBuilder sb = new StringBuilder();
sb.append("DIEAgregrate of: ");
for (DebugInfoEntry die : fragments) {
- sb.append("DIE [").append(Long.toHexString(die.getOffset())).append("], ");
+ sb.append("DIE [0x%x], ".formatted(die.getOffset()));
}
sb.append("\n");
for (DebugInfoEntry die : fragments) {
@@ -860,137 +697,52 @@ public class DIEAggregate {
}
/**
- * Parses a range list from the debug_ranges section.
- * See DWARF4 Section 2.17.3 (Non-Contiguous Address Ranges).
- *
- * The returned list of ranges is sorted.
+ * Parses a range list.
*
- * @param attribute attribute ie. {@link DWARFAttribute#DW_AT_ranges}
- * @return list of ranges, in order
+ * @param attribute attribute eg {@link DWARFAttribute#DW_AT_ranges}
+ * @return list of ranges, or null if attribute is not present
* @throws IOException if an I/O error occurs
*/
- public List parseDebugRange(int attribute) throws IOException {
- List result = readRange(attribute);
- Collections.sort(result);
- return result;
+ public DWARFRangeList getRangeList(DWARFAttribute attribute) throws IOException {
+ return getProgram().getRangeList(this, attribute);
}
/**
- * Parses a range list from the debug_ranges section.
- * See DWARF4 Section 2.17.3 (Non-Contiguous Address Ranges).
- *
- * The returned list is not sorted.
+ * Return the range specified by the low_pc...high_pc attribute values.
*
- * @param attribute attribute ie. {@link DWARFAttribute#DW_AT_ranges}
- * @return list of ranges
- * @throws IOException if an I/O error occurs
+ * @return {@link DWARFRange} containing low_pc - high_pc, or null if the low_pc is not present
*/
- public List readRange(int attribute) throws IOException {
- byte pointerSize = getCompilationUnit().getPointerSize();
- BinaryReader reader = getProgram().getDebugRanges();
+ public DWARFRange getPCRange() {
+ DWARFNumericAttribute lowPc = getAttribute(DW_AT_low_pc, DWARFNumericAttribute.class);
+ if (lowPc != null) {
+ try {
+ // TODO: previous code excluded lowPc values that were == 0 as invalid.
+ long rawLowPc = lowPc.getUnsignedValue();
+ long lowPcOffset = getProgram().getAddress(lowPc.getAttributeForm(), rawLowPc,
+ getCompilationUnit());
+ long highPcOffset = lowPcOffset + 1;
- long offset = getUnsignedLong(attribute, -1);
- if (offset == -1) {
- throw new IOException("Bad / missing attribute " + attribute);
- }
- reader.setPointerIndex(offset);
- List ranges = new ArrayList<>();
-
- DWARFCompileUnit dcu = getCompilationUnit().getCompileUnit();
- long baseAddress = dcu != null && dcu.getLowPC() != null
- ? dcu.getLowPC().longValue()
- : 0L;
-
- while (reader.hasNext()) {
- // Read the beginning and ending addresses
- long beginning = DWARFUtil.readAddressAsLong(reader, pointerSize);
- long ending = DWARFUtil.readAddressAsLong(reader, pointerSize); // dwarf end addrs are exclusive
-
- // End of the list
- if (beginning == 0 && ending == 0) {
- break;
+ DWARFNumericAttribute highPc =
+ getAttribute(DW_AT_high_pc, DWARFNumericAttribute.class);
+ if (highPc != null) {
+ if (highPc.getAttributeForm() == DWARFForm.DW_FORM_addr) {
+ long baseAddrFixup = getProgram().getProgramBaseAddressFixup();
+ highPcOffset = highPc.getUnsignedValue() + baseAddrFixup;
+ }
+ else {
+ highPcOffset = highPc.getUnsignedValue();
+ if (highPcOffset != 0) {
+ highPcOffset = lowPcOffset + highPcOffset;
+ }
+ }
+ }
+ return new DWARFRange(lowPcOffset, highPcOffset);
}
-
- // Check to see if this is a base address entry
- if (beginning == -1 ||
- (pointerSize == 4 && beginning == NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG)) {
- baseAddress = ending;
- continue;
- }
-
- // Add the range to the list
- ranges.add(new DWARFRange(baseAddress + beginning, baseAddress + ending));
- }
- return ranges;
- }
-
- /**
- * Returns the value of the DW_AT_low_pc attribute, if it exists.
- *
- * @param defaultValue
- * @return
- */
- public long getLowPC(long defaultValue) {
- DWARFNumericAttribute attr =
- getAttribute(DWARFAttribute.DW_AT_low_pc, DWARFNumericAttribute.class);
- return (attr != null) ? attr.getUnsignedValue() + getProgram().getProgramBaseAddressFixup()
- : defaultValue;
- }
-
- /**
- * Returns the value of the DW_AT_high_pc attribute, adjusted
- * if necessary by the value of DW_AT_low_pc.
- *
- * @return
- * @throws IOException if the DW_AT_high_pc attribute isn't a numeric
- * attribute, or if the DW_AT_low_pc value is needed and is not present.
- */
- public long getHighPC() throws IOException {
- AttrInfo high = findAttribute(DWARFAttribute.DW_AT_high_pc);
- if (high != null && high.attr instanceof DWARFNumericAttribute highVal) {
- // if the DWARF attr was a DW_FORM_addr, it doesn't need fixing up
- if (high.form == DWARFForm.DW_FORM_addr) {
- return highVal.getUnsignedValue() + getProgram().getProgramBaseAddressFixup() - 1;
- }
-
- // else it was a DW_FORM_data value and is relative to the lowPC value
- DWARFNumericAttribute low =
- getAttribute(DWARFAttribute.DW_AT_low_pc, DWARFNumericAttribute.class);
-
- long lhighVal = highVal.getUnsignedValue();
- if (lhighVal == 0) {
- lhighVal = 1;
- }
- if (low != null && lhighVal > 0) {
- return low.getUnsignedValue() + getProgram().getProgramBaseAddressFixup() +
- lhighVal - 1;
+ catch (IOException e) {
+ // fall thru, return null
}
}
- 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 and 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 lowVal &&
- high.attr instanceof DWARFNumericAttribute highVal) {
-
- return lowVal.getValue() == highVal.getValue();
-
- }
- return false;
+ return null;
}
/**
@@ -1026,7 +778,7 @@ public class DIEAggregate {
newParams.add(getProgram().getAggregate(paramDIE));
}
}
- if ( !params.isEmpty() ) {
+ if (!params.isEmpty()) {
//Msg.warn(this, "Extra params in concrete DIE instance: " + params);
//Msg.warn(this, this.toString());
newParams.addAll(params);
@@ -1049,18 +801,11 @@ public class DIEAggregate {
/**
* 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.
+ *
+ * @param attr attribute value
+ * @param die DIE the value was found in
*/
- static class AttrInfo {
- DWARFAttributeValue attr;
- DebugInfoEntry die;
- DWARFForm form;
-
- AttrInfo(DWARFAttributeValue attr, DebugInfoEntry die, DWARFForm form) {
- this.attr = attr;
- this.die = die;
- this.form = form;
- }
-
+ record FoundAttribute(DWARFAttributeValue attr, DebugInfoEntry die) {
T getValue(Class clazz) {
if (attr != null && clazz.isAssignableFrom(attr.getClass())) {
return clazz.cast(attr);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java
new file mode 100644
index 0000000000..6be1b256c8
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java
@@ -0,0 +1,206 @@
+/* ###
+ * 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.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+
+import java.io.IOException;
+import java.util.*;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.AttrDef;
+import ghidra.program.model.data.LEB128;
+import ghidra.util.Msg;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * This class represents the 'schema' for a DWARF DIE record.
+ *
+ * A raw DWARF DIE record specifies its abbreviation code (pointing to an instance of
+ * this class) and the corresponding DWARFAbbreviation instance has the information
+ * about how the raw DIE is laid out.
+ */
+public class DWARFAbbreviation {
+ private static final int EOL = 0;
+ private final int abbreviationCode;
+ private final DWARFTag tag;
+ private final int tagId;
+ private final boolean hasChildren;
+ private final AttrDef[] attributes;
+
+ /**
+ * Reads a {@link DWARFAbbreviation} from the stream.
+ *
+ * @param reader {@link BinaryReader} stream
+ * @param prog {@link DWARFProgram}
+ * @param monitor {@link TaskMonitor}
+ * @return {@link DWARFAbbreviation}, or null if the stream was at a end-of-list marker
+ * @throws IOException if error reading
+ * @throws CancelledException if canceled
+ */
+ public static DWARFAbbreviation read(BinaryReader reader, DWARFProgram prog,
+ TaskMonitor monitor) throws IOException, CancelledException {
+
+ int ac = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ if (ac == EOL) {
+ return null;
+ }
+ int tag = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int hasChildren = reader.readNextByte();
+
+ // Read each attribute specification until EOL marker value
+ List tmpAttrSpecs = new ArrayList<>();
+ AttrDef attrSpec;
+ while ((attrSpec = AttrDef.read(reader)) != null) {
+ monitor.checkCancelled();
+ attrSpec = prog.internAttributeSpec(attrSpec);
+ tmpAttrSpecs.add(attrSpec);
+ warnIfMismatchedForms(attrSpec);
+ }
+ AttrDef[] attrSpecArray = tmpAttrSpecs.toArray(new AttrDef[tmpAttrSpecs.size()]);
+
+ DWARFAbbreviation result = new DWARFAbbreviation(ac, tag,
+ hasChildren == DWARFChildren.DW_CHILDREN_yes, attrSpecArray);
+
+ return result;
+ }
+
+ private static void warnIfMismatchedForms(DWARFAttribute.AttrDef attrSpec) {
+ DWARFForm form = attrSpec.getAttributeForm();
+ DWARFAttribute attribute = attrSpec.getAttributeId();
+ if (attribute != null && !form.getFormClasses().isEmpty() &&
+ !attribute.getAttributeClass().isEmpty()) {
+ EnumSet tmp =
+ EnumSet.copyOf(attrSpec.getAttributeForm().getFormClasses());
+ tmp.retainAll(attrSpec.getAttributeId().getAttributeClass());
+ if (tmp.isEmpty()) {
+ Msg.warn(DWARFAbbreviation.class,
+ "Mismatched DWARF Attribute and Form: %s".formatted(attrSpec));
+ }
+ }
+
+ }
+
+ /**
+ * Reads a list of {@link DWARFAbbreviation}, stopping when the end-of-list marker is
+ * encountered.
+ *
+ * @param reader {@link BinaryReader} .debug_abbr stream
+ * @param prog {@link DWARFProgram}
+ * @param monitor {@link TaskMonitor}
+ * @return map of abbrCode -> abbr instance
+ * @throws IOException if error reading
+ * @throws CancelledException if cancelled
+ */
+ public static Map readAbbreviations(BinaryReader reader,
+ DWARFProgram prog, TaskMonitor monitor) throws IOException, CancelledException {
+ Map result = new HashMap<>();
+
+ // Read a list of abbreviations, terminated by a marker value that returns null from read()
+ DWARFAbbreviation abbrev = null;
+ while ((abbrev = DWARFAbbreviation.read(reader, prog, monitor)) != null) {
+ monitor.checkCancelled();
+ result.put(abbrev.getAbbreviationCode(), abbrev);
+ }
+
+ return result;
+ }
+
+ public DWARFAbbreviation(int abbreviationCode, int tagId, boolean hasChildren,
+ AttrDef[] attributes) {
+ this.abbreviationCode = abbreviationCode;
+ this.tagId = tagId;
+ this.tag = DWARFTag.of(tagId);
+ this.hasChildren = hasChildren;
+ this.attributes = attributes;
+ }
+
+ @Override
+ public String toString() {
+ return "%x:%s".formatted(abbreviationCode, getTagName());
+ }
+
+ /**
+ * Get the abbreviation code.
+ * @return the abbreviation code
+ */
+ public int getAbbreviationCode() {
+ return this.abbreviationCode;
+ }
+
+ /**
+ * Get the tag value.
+ * @return the tag value
+ */
+ public DWARFTag getTag() {
+ return this.tag;
+ }
+
+ public String getTagName() {
+ return tag != DW_TAG_UNKNOWN ? tag.name() : "DW_TAG_??? %d".formatted(tagId);
+ }
+
+ /**
+ * Checks to see if this abbreviation has any DIE children.
+ * @return true if this abbreviation has DIE children
+ */
+ public boolean hasChildren() {
+ return this.hasChildren;
+ }
+
+ /**
+ * Return a live list of the attributes.
+ * @return list of attributes
+ */
+ public AttrDef[] getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Return number of attribute values.
+ *
+ * @return number of attribute values
+ */
+ public int getAttributeCount() {
+ return attributes.length;
+ }
+
+ /**
+ * Get the attribute at the given index.
+ * @param index index of the attribute
+ * @return attribute specification
+ */
+ public AttrDef getAttributeAt(int index) {
+ return this.attributes[index];
+ }
+
+ /**
+ * Get the attribute with the given attribute key.
+ * @param attributeId attribute key
+ * @return attribute specification
+ */
+ public AttrDef findAttribute(DWARFAttribute attributeId) {
+ for (AttrDef spec : this.attributes) {
+ if (spec.getAttributeId() == attributeId) {
+ return spec;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAccessibility.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAccessibility.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAccessibility.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAccessibility.java
index 8a0519d42a..3c4963da73 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAccessibility.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAccessibility.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
+package ghidra.app.util.bin.format.dwarf;
import java.util.HashMap;
import java.util.Map;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAddressListHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAddressListHeader.java
new file mode 100644
index 0000000000..b717f49a39
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAddressListHeader.java
@@ -0,0 +1,99 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+
+/**
+ * Header at the beginning of a address list table
+ */
+public class DWARFAddressListHeader extends DWARFIndirectTableHeader {
+
+ /**
+ * Reads a {@link DWARFAddressListHeader} from the stream.
+ *
+ * @param reader {@link BinaryReader} stream
+ * @param defaultIntSize native int size for the binary
+ * @return {@link DWARFAddressListHeader}, or null if end-of-list marker
+ * @throws IOException if error reading
+ */
+ public static DWARFAddressListHeader read(BinaryReader reader, int defaultIntSize)
+ throws IOException {
+ // length : dwarf_length
+ // version : 2 bytes
+ // addr_size : 1 byte
+ // seg_sel_size : 1 byte
+
+ long startOffset = reader.getPointerIndex();
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, defaultIntSize);
+ if (lengthInfo == null) {
+ return null;
+ }
+
+ long endOffset = reader.getPointerIndex() + lengthInfo.length();
+ short version = reader.readNextShort();
+ if (version != 5) {
+ throw new DWARFException("Unsupported DWARF version [%d]".formatted(version));
+ }
+ int addressSize = reader.readNextUnsignedByte();
+ int segmentSelectorSize = reader.readNextUnsignedByte();
+ long firstAddr = reader.getPointerIndex();
+ reader.setPointerIndex(endOffset);
+
+ int count = (int) ((endOffset - firstAddr) / (addressSize + segmentSelectorSize));
+ return new DWARFAddressListHeader(startOffset, endOffset, firstAddr, addressSize,
+ segmentSelectorSize, count);
+ }
+
+ private final int addressSize;
+ private final int segmentSelectorSize;
+ private final int addrCount;
+
+ public DWARFAddressListHeader(long startOffset, long endOffset, long firstElementOffset,
+ int addressSize, int segmentSelectorSize, int addrCount) {
+ super(startOffset, endOffset, firstElementOffset);
+
+ this.addressSize = addressSize;
+ this.segmentSelectorSize = segmentSelectorSize;
+ this.addrCount = addrCount;
+ }
+
+ @Override
+ public long getOffset(int index, BinaryReader reader) throws IOException {
+ if (index < 0 || addrCount <= index) {
+ throw new IOException("Invalid address index: %d".formatted(index));
+ }
+ long offset = firstElementOffset + (addressSize + segmentSelectorSize) * index;
+
+ @SuppressWarnings("unused")
+ long seg =
+ segmentSelectorSize > 0 ? reader.readUnsignedValue(offset, segmentSelectorSize) : 0;
+
+ long addr = reader.readUnsignedValue(offset + segmentSelectorSize, addressSize);
+ return addr;
+ }
+
+ public int getAddressSize() {
+ return addressSize;
+ }
+
+ public int getSegmentSelectorSize() {
+ return segmentSelectorSize;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFChildren.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFChildren.java
new file mode 100644
index 0000000000..c49be56f72
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFChildren.java
@@ -0,0 +1,28 @@
+/* ###
+ * 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.dwarf;
+
+/**
+ * DWARF child determination consts from www.dwarfstd.org/doc/DWARF4.pdf.
+ *
+ * Yes, its a direct equiv to a boolean, but its in the spec.
+ */
+public class DWARFChildren
+{
+ public static final int DW_CHILDREN_no = 0;
+ public static final int DW_CHILDREN_yes = 1;
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java
new file mode 100644
index 0000000000..e2a7fcaee2
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java
@@ -0,0 +1,342 @@
+/* ###
+ * 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.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * A DWARF CompilationUnit is a contiguous block of {@link DebugInfoEntry DIE} records found
+ * in a .debug_info section of an program. The compilation unit block starts with a
+ * header that has a few important values and flags, and is followed by the DIE records.
+ *
+ * The first DIE record must be a DW_TAG_compile_unit.
+ *
+ * DIE records are identified by their byte offset in the .debug_info section.
+ *
+ */
+public class DWARFCompilationUnit extends DWARFUnitHeader {
+ /**
+ * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data
+ * from the debug_info section and the debug_abbr section and its compileUnit DIE (ie.
+ * the first DIE right after the header).
+ *
+ * Returns {@code NULL} if there was an ignorable error while reading the compilation unit (and
+ * leaves the input stream at the next compilation unit to read), otherwise throws
+ * an IOException if there was an unrecoverable error.
+ *
+ * Also returns {@code NULL} (and leaves the stream at EOF) if the remainder of the stream
+ * is filled with null bytes.
+ *
+ * @param partial already read partial unit header
+ * @param reader .debug_info BinaryReader
+ * @param abbrReader .debug_abbr BinaryReader
+ * @param monitor the current task monitor
+ * @return the read compilation unit, or null if the compilation unit was bad/empty and should
+ * be ignored
+ * @throws DWARFException if an invalid or unsupported DWARF version is read.
+ * @throws IOException if the length of the compilation unit is invalid.
+ * @throws CancelledException if the task has been canceled.
+ */
+ public static DWARFCompilationUnit readV4(DWARFUnitHeader partial, BinaryReader reader,
+ BinaryReader abbrReader, TaskMonitor monitor)
+ throws DWARFException, IOException, CancelledException {
+
+ long abbreviationOffset = reader.readNextUnsignedValue(partial.getIntSize());
+ byte pointerSize = reader.readNextByte();
+ long firstDIEOffset = reader.getPointerIndex();
+
+ if (firstDIEOffset > partial.endOffset) {
+ throw new IOException("Invalid length %d for DWARF Compilation Unit at 0x%x"
+ .formatted(partial.endOffset - partial.startOffset, partial.startOffset));
+ }
+ else if (firstDIEOffset == partial.endOffset) {
+ // silently skip this empty compunit
+ return null;
+ }
+
+ abbrReader.setPointerIndex(abbreviationOffset);
+ Map abbrMap =
+ DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor);
+
+ DWARFCompilationUnit cu =
+ new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrMap);
+ return cu;
+ }
+
+ /**
+ * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data
+ * from the debug_info section and the debug_abbr section and its compileUnit DIE (ie.
+ * the first DIE right after the header).
+ *
+ * Returns {@code NULL} if there was an ignorable error while reading the compilation unit (and
+ * leaves the input stream at the next compilation unit to read), otherwise throws
+ * an IOException if there was an unrecoverable error.
+ *
+ * Also returns {@code NULL} (and leaves the stream at EOF) if the remainder of the stream
+ * is filled with null bytes.
+ *
+ * @param partial already read partial unit header
+ * @param reader .debug_info BinaryReader
+ * @param abbrReader .debug_abbr BinaryReader
+ * @param monitor the current task monitor
+ * @return the read compilation unit, or null if the compilation unit was bad/empty and should
+ * be ignored
+ * @throws DWARFException if an invalid or unsupported DWARF version is read.
+ * @throws IOException if the length of the compilation unit is invalid.
+ * @throws CancelledException if the task has been canceled.
+ */
+ public static DWARFCompilationUnit readV5(DWARFUnitHeader partial, BinaryReader reader,
+ BinaryReader abbrReader, TaskMonitor monitor)
+ throws DWARFException, IOException, CancelledException {
+
+ byte pointerSize = reader.readNextByte();
+ long abbreviationOffset = reader.readNextUnsignedValue(partial.getIntSize());
+
+ long firstDIEOffset = reader.getPointerIndex();
+
+ if (firstDIEOffset > partial.endOffset) {
+ throw new IOException("Invalid length %d for DWARF Compilation Unit at 0x%x"
+ .formatted(partial.endOffset - partial.startOffset, partial.startOffset));
+ }
+ else if (firstDIEOffset == partial.endOffset) {
+ // silently skip this empty compunit
+ return null;
+ }
+
+ abbrReader.setPointerIndex(abbreviationOffset);
+ Map abbrMap =
+ DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor);
+
+ DWARFCompilationUnit cu =
+ new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrMap);
+ return cu;
+ }
+
+ /**
+ * Size of pointers that are held in DIEs in this compUnit. (from header)
+ */
+ private final byte pointerSize;
+
+ /**
+ * Offset in the debug_info section of the first DIE of this compUnit.
+ */
+ private final long firstDIEOffset;
+
+ /**
+ * Map of abbrevCode to {@link DWARFAbbreviation} instances.
+ */
+ private final Map codeToAbbreviationMap;
+
+ /**
+ * The contents of the first DIE (that must be a compile unit) in this compUnit.
+ */
+ protected DIEAggregate diea;
+
+ private DWARFLine line;
+
+ private DWARFCompilationUnit(DWARFUnitHeader partial, byte pointerSize, long firstDIEOffset,
+ Map abbrMap) {
+ super(partial);
+
+ this.pointerSize = pointerSize;
+ this.firstDIEOffset = firstDIEOffset;
+ this.codeToAbbreviationMap = (abbrMap != null) ? abbrMap : new HashMap<>();
+ }
+
+ /**
+ * This ctor is public only for junit tests. Do not use directly.
+ *
+ * @param dwarfProgram {@link DWARFProgram}
+ * @param startOffset offset in provider where it starts
+ * @param endOffset offset in provider where it ends
+ * @param length how many bytes following the header the DIEs of this unit take
+ * @param intSize 4 (DWARF_32) or 8 (DWARF_64)
+ * @param dwarfVersion 2-5
+ * @param pointerSize default size of pointers
+ * @param unitNumber this compunits ordinal in the file
+ * @param firstDIEOffset start of DIEs in the provider
+ * @param codeToAbbreviationMap map of abbreviation numbers to {@link DWARFAbbreviation} instances
+ */
+ public DWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset,
+ long length, int intSize, short dwarfVersion, byte pointerSize, int unitNumber,
+ long firstDIEOffset, Map codeToAbbreviationMap) {
+ super(dwarfProgram, startOffset, endOffset, length, intSize, dwarfVersion, unitNumber);
+ this.pointerSize = pointerSize;
+ this.firstDIEOffset = firstDIEOffset;
+ this.codeToAbbreviationMap =
+ (codeToAbbreviationMap != null) ? codeToAbbreviationMap : new HashMap<>();
+ }
+
+ /**
+ * Initializes this compunit with the root DIE (first DIE) of the compunit. This comp unit
+ * isn't usable until this has happened.
+ *
+ * @param rootDIE {@link DebugInfoEntry}
+ * @throws IOException if error reading data from the DIE
+ */
+ public void init(DebugInfoEntry rootDIE) throws IOException {
+ diea = DIEAggregate.createSingle(rootDIE);
+ line = getProgram().getLine(diea, DW_AT_stmt_list);
+ }
+
+ /**
+ * Returns this comp unit's root DIE as a DIE Aggregate.
+ *
+ * @return the aggregate containing the root element of this comp unit
+ */
+ public DIEAggregate getCompUnitDIEA() {
+ return diea;
+ }
+
+ /**
+ * Returns the size of pointers in this compUnit.
+ *
+ * @return the size in bytes of pointers
+ */
+ public byte getPointerSize() {
+ return this.pointerSize;
+ }
+
+ public Map getCodeToAbbreviationMap() {
+ return codeToAbbreviationMap;
+ }
+
+ public DWARFAbbreviation getAbbreviation(int ac) {
+ return codeToAbbreviationMap.get(ac);
+ }
+
+ public long getFirstDIEOffset() {
+ return firstDIEOffset;
+ }
+
+ /**
+ * Get the filename that produced the compile unit
+ *
+ * @return the filename that produced the compile unit
+ */
+ public String getName() {
+ return diea.getString(DW_AT_name, null);
+ }
+
+ /**
+ * Get a file name with the full path included based on a file index.
+ * @param index index of the file
+ * @return file name with full path or null if line information does not exist
+ * @throws IllegalArgumentException if a negative or invalid file index is given
+ */
+ public String getFullFileByIndex(int index) {
+ if (index < 0) {
+ throw new IllegalArgumentException("Negative file index was given.");
+ }
+ if (this.line == null) {
+ return null;
+ }
+
+ return this.line.getFullFile(index, null);
+ }
+
+ /**
+ * Get a file name based on a file index.
+ * @param index index of the file
+ * @return file name or null if line information does not exist
+ * @throws IllegalArgumentException if a negative or invalid file index is given
+ */
+ public String getFileByIndex(int index) {
+ if (index < 0) {
+ throw new IllegalArgumentException("Negative file index was given.");
+ }
+ if (this.line == null) {
+ return null;
+ }
+
+ return this.line.getFile(index, null);
+ }
+
+ /**
+ * Checks validity of a file index number.
+ *
+ * @param index file number, 1..N
+ * @return boolean true if index is a valid file number, false otherwise
+ */
+ public boolean isValidFileIndex(int index) {
+ return line.isValidFileIndex(index);
+ }
+
+ /**
+ * Get the producer of the compile unit
+ * @return the producer of the compile unit
+ */
+ public String getProducer() {
+ return diea.getString(DW_AT_producer, null);
+ }
+
+ /**
+ * Get the compile directory of the compile unit
+ * @return the compile directory of the compile unit
+ */
+ public String getCompileDirectory() {
+ return diea.getString(DW_AT_comp_dir, null);
+ }
+
+ /**
+ * Get the source language of the compile unit.
+ *
+ * See {@link DWARFSourceLanguage} for values.
+ *
+ * @return the source language of the compile unit, or -1 if not set
+ */
+ public int getLanguage() {
+ return (int) diea.getUnsignedLong(DW_AT_language, -1);
+ }
+
+ public boolean hasDWO() {
+ return diea.hasAttribute(DW_AT_GNU_dwo_id) && diea.hasAttribute(DW_AT_GNU_dwo_name);
+ }
+
+ public long getAddrTableBase() {
+ return diea.getUnsignedLong(DW_AT_addr_base, 0);
+ }
+
+ public long getRangeListsBase() {
+ return diea.getUnsignedLong(DW_AT_rnglists_base, 0);
+ }
+
+ public long getLocListsBase() {
+ return diea.getUnsignedLong(DW_AT_loclists_base, 0);
+ }
+
+ public long getStrOffsetsBase() {
+ return diea.getUnsignedLong(DW_AT_str_offsets_base, 0);
+ }
+
+ public DWARFRange getPCRange() {
+ return diea.getPCRange();
+ }
+
+ @Override
+ public String toString() {
+ return "DWARFCompilationUnit @%x, ver %d, pointersize: %d\n".formatted(startOffset,
+ dwarfVersion, pointerSize) + diea.toString().indent(4);
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataInstanceHelper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataInstanceHelper.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataInstanceHelper.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataInstanceHelper.java
index 2b03830c7f..bcfb880ad5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataInstanceHelper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataInstanceHelper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeConflictHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeConflictHandler.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeConflictHandler.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeConflictHandler.java
index 2429b8be40..1b2b171960 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeConflictHandler.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeConflictHandler.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import static ghidra.program.model.data.DataTypeConflictHandler.ConflictResult.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java
index a3a5a096fc..ab62a9af24 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.util.*;
@@ -25,11 +25,8 @@ import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.DataTypeNamingUtil;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFNumericAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFEndianity;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFNumericAttribute;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
import ghidra.app.util.bin.format.golang.rtti.types.GoKind;
import ghidra.program.database.DatabaseObject;
import ghidra.program.database.data.DataTypeUtilities;
@@ -94,7 +91,7 @@ public class DWARFDataTypeImporter {
this.dwarfDTM = dwarfDTM;
this.importOptions = prog.getImportOptions();
this.voidDDT = new DWARFDataType(dwarfDTM.getVoidType(),
- DWARFNameInfo.fromDataType(dwarfDTM.getVoidType()), -1);
+ DWARFName.fromDataType(dwarfDTM.getVoidType()), -1);
}
public DWARFDataType getDDTByInstance(DataType dtInstance) {
@@ -269,14 +266,14 @@ public class DWARFDataTypeImporter {
private DWARFDataType makeDataTypeForFunctionDefinition(DIEAggregate diea)
throws IOException, DWARFExpressionException {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
// push an empty funcdef data type into the lookup cache to prevent recursive loops
FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
DataType dtToAdd = funcDef;
- int cuLang = diea.getCompilationUnit().getCompileUnit().getLanguage();
+ int cuLang = diea.getCompilationUnit().getLanguage();
if (cuLang == DWARFSourceLanguage.DW_LANG_Go) {
if (diea.hasAttribute(DW_AT_byte_size)) {
// if the funcdef has a bytesize attribute, we should convert this data type to a ptr
@@ -358,7 +355,7 @@ public class DWARFDataTypeImporter {
return makeNamedBaseType(prog.getName(diea), diea);
}
- private DWARFDataType makeNamedBaseType(DWARFNameInfo dni, DIEAggregate diea)
+ private DWARFDataType makeNamedBaseType(DWARFName dni, DIEAggregate diea)
throws IOException, DWARFExpressionException {
int dwarfSize = diea.parseInt(DW_AT_byte_size, 0);
int dwarfEncoding = (int) diea.getUnsignedLong(DW_AT_encoding, -1);
@@ -434,7 +431,7 @@ public class DWARFDataTypeImporter {
*/
private DWARFDataType makeDataTypeForEnum(DIEAggregate diea) {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
int enumSize = (int) diea.getUnsignedLong(DW_AT_byte_size, -1);
// in addition to byte_size, enums can have encoding (signed/unsigned) and a basetype, which
// itself might have a signed/unsigned encoding.
@@ -568,7 +565,7 @@ public class DWARFDataTypeImporter {
*/
private DWARFDataType makeDataTypeForStruct(DIEAggregate diea) {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
long structSize = diea.getUnsignedLong(DW_AT_byte_size, 0);
long origStructSize = structSize;
@@ -841,7 +838,7 @@ public class DWARFDataTypeImporter {
}
private void populateStubStruct_worker(DWARFDataType ddt, StructureDataType structure,
- DIEAggregate diea, int childTagType) throws IOException, DWARFExpressionException {
+ DIEAggregate diea, DWARFTag childTagType) throws IOException, DWARFExpressionException {
for (DebugInfoEntry childEntry : diea.getChildren(childTagType)) {
@@ -1206,7 +1203,7 @@ public class DWARFDataTypeImporter {
private DWARFDataType makeDataTypeForPtrToMemberType(DIEAggregate diea)
throws IOException, DWARFExpressionException {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
DIEAggregate type = diea.getTypeRef();
DIEAggregate containingType = diea.getContainingTypeRef();
@@ -1219,7 +1216,11 @@ public class DWARFDataTypeImporter {
DataType offsetType = dwarfDTM.getOffsetType(byteSize);
// create a typedef to the offsetType and put containing type and var type info in the typedef name.
- String x = "offset_in_" + containingType.getName() + "_to_" + type.getName();
+ String targetName = type.getName();
+ if (targetName == null) {
+ targetName = type.getTag().getContainerTypeName();
+ }
+ String x = "offset_in_" + containingType.getName() + "_to_" + targetName;
DataType dt = new TypedefDataType(dni.getParentCP(), x, offsetType, dataTypeManager);
if (!dni.isAnon()) {
@@ -1246,7 +1247,7 @@ public class DWARFDataTypeImporter {
private DWARFDataType makeDataTypeForTypedef(DIEAggregate diea)
throws IOException, DWARFExpressionException {
- DWARFNameInfo typedefDNI = prog.getName(diea);
+ DWARFName typedefDNI = prog.getName(diea);
DIEAggregate refdDIEA = diea.getTypeRef();
if (refdDIEA != null && refdDIEA.getTag() == DW_TAG_base_type) {
@@ -1305,7 +1306,7 @@ public class DWARFDataTypeImporter {
*
*/
private DWARFDataType makeDataTypeForUnspecifiedType(DIEAggregate diea) {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
DataType dt = dwarfDTM.getBaseType(dni.getOriginalName());
if (dt == null) {
return voidDDT;
@@ -1315,17 +1316,17 @@ public class DWARFDataTypeImporter {
static class DWARFDataType {
DataType dataType;
- DWARFNameInfo dni;
+ DWARFName dni;
DWARFSourceInfo dsi;
Set offsets = new HashSet<>();
- DWARFDataType(DataType dataType, DWARFNameInfo dni, long offset) {
+ DWARFDataType(DataType dataType, DWARFName dni, long offset) {
this.dataType = dataType;
this.dni = dni;
this.offsets.add(offset);
}
- DWARFDataType(DataType dataType, DWARFNameInfo dni, Set offsets) {
+ DWARFDataType(DataType dataType, DWARFName dni, Set offsets) {
this.dataType = dataType;
this.dni = dni;
this.offsets.addAll(offsets);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeManager.java
similarity index 92%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeManager.java
index 65fc1c63af..97e9dd9a0f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeManager.java
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.*;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeImporter.DWARFDataType;
+import ghidra.app.util.bin.format.dwarf.DWARFDataTypeImporter.DWARFDataType;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Program;
@@ -41,12 +39,6 @@ import utility.function.Dummy;
*/
public class DWARFDataTypeManager {
- private static final Set TYPE_TAGS = Set.of(DW_TAG_base_type, DW_TAG_array_type,
- DW_TAG_typedef, DW_TAG_class_type, DW_TAG_interface_type, DW_TAG_structure_type,
- DW_TAG_union_type, DW_TAG_enumeration_type, DW_TAG_pointer_type, DW_TAG_reference_type,
- DW_TAG_rvalue_reference_type, DW_TAG_const_type, DW_TAG_volatile_type,
- DW_TAG_ptr_to_member_type, DW_TAG_unspecified_type, DW_TAG_subroutine_type);
-
private final DataTypeManager dataTypeManager;
private final DataTypeManager builtInDTM;
private final DWARFProgram prog;
@@ -185,8 +177,8 @@ public class DWARFDataTypeManager {
}
private boolean isGoodDWARFSourceInfo(DWARFSourceInfo dsi) {
- return dsi.getFilename() != null && !dsi.getFilename().isEmpty() &&
- !dsi.getFilename().contains("built-in");
+ return dsi.filename() != null && !dsi.filename().isEmpty() &&
+ !dsi.filename().contains("built-in");
}
private void cacheOffsetToDataTypeMapping(long dieOffset, DataType dt) {
@@ -558,7 +550,7 @@ public class DWARFDataTypeManager {
monitor.increment();
try {
- if (TYPE_TAGS.contains(diea.getTag())) {
+ if (diea.getTag().isType()) {
doGetDataType(diea);
}
}
@@ -586,24 +578,22 @@ public class DWARFDataTypeManager {
}
private DIEAggregate getFuncDIEA(DIEAggregate diea) {
- switch (diea.getTag()) {
- case DWARFTag.DW_TAG_gnu_call_site:
- case DWARFTag.DW_TAG_call_site:
- case DWARFTag.DW_TAG_inlined_subroutine:
- // these DIEs head elements have a different tag than the rest of the elements
- // in this aggregate, which causes a problem handling this DIEA. Create
- // a new instance skipping the head element. No information is typically
- // lost.
- diea = DIEAggregate.createSkipHead(diea);
- // fall-thru:
- case DWARFTag.DW_TAG_subprogram:
- //case DWARFTag.DW_TAG_subroutine_type:
- // Both of these tag types can be converted to Ghidra func definition data types,
- // but dw_tag_subroutine_type was already handled in importAllDataTypes(),
- // so it is being skipped here.
- return diea;
- }
- return null;
+ return switch (diea.getTag()) {
+ // these DIEs head elements have a different tag than the rest of the elements
+ // in this aggregate, which causes a problem handling this DIEA. Create
+ // a new instance skipping the head element. No information is typically
+ // lost.
+ case DW_TAG_gnu_call_site, DW_TAG_call_site, DW_TAG_inlined_subroutine -> DIEAggregate
+ .createSkipHead(diea);
+
+ case DW_TAG_subprogram -> diea;
+
+ // dw_tag_subroutine_type was already handled in importAllDataTypes(),
+ // so it is being skipped here.
+ //case DW_TAG_subroutine_type -> null
+
+ default -> null;
+ };
}
/**
@@ -617,7 +607,7 @@ public class DWARFDataTypeManager {
public FunctionDefinition getFunctionSignature(DIEAggregate diea) {
diea = getFuncDIEA(diea);
if (diea != null) {
- DWARFNameInfo dni = prog.getName(diea);
+ DWARFName dni = prog.getName(diea);
return createFunctionDefinitionDataType(diea, dni);
}
return null;
@@ -635,7 +625,7 @@ public class DWARFDataTypeManager {
* @return new {@link FunctionDefinitionDataType}.
*/
private FunctionDefinitionDataType createFunctionDefinitionDataType(DIEAggregate diea,
- DWARFNameInfo dni) {
+ DWARFName dni) {
DataType returnDataType = getDataTypeForVariable(diea.getTypeRef());
boolean foundThisParam = false;
List params = new ArrayList<>();
@@ -661,7 +651,7 @@ public class DWARFDataTypeManager {
FunctionDefinitionDataType funcDef =
new FunctionDefinitionDataType(dni.getParentCP(), dni.getName(), dataTypeManager);
funcDef.setReturnType(returnDataType);
- funcDef.setNoReturn(diea.getBool(DWARFAttribute.DW_AT_noreturn, false));
+ funcDef.setNoReturn(diea.getBool(DW_AT_noreturn, false));
funcDef.setArguments(params.toArray(new ParameterDefinition[params.size()]));
if (!diea.getHeadFragment().getChildren(DWARFTag.DW_TAG_unspecified_parameters).isEmpty()) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEncoding.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEncoding.java
similarity index 94%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEncoding.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEncoding.java
index da63554024..7be50ae0ab 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEncoding.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEncoding.java
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
-
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+package ghidra.app.util.bin.format.dwarf;
/**
* DWARF attribute encoding consts from www.dwarfstd.org/doc/DWARF4.pdf
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEndianity.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEndianity.java
similarity index 93%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEndianity.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEndianity.java
index 0a00fcc6b7..8f1f3500a9 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFEndianity.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFEndianity.java
@@ -13,9 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
-
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+package ghidra.app.util.bin.format.dwarf;
/**
* DWARF Endianity consts from www.dwarfstd.org/doc/DWARF4.pdf
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFException.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFException.java
similarity index 95%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFException.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFException.java
index c31d399ff4..ec395b02ef 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFException.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFException.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunction.java
similarity index 82%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunction.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunction.java
index c4769be4ca..646fd0ce89 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunction.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunction.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.util.*;
@@ -24,13 +24,10 @@ import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFNumericAttribute;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
-import ghidra.app.util.bin.format.dwarf4.funcfixup.DWARFFunctionFixup;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
+import ghidra.app.util.bin.format.dwarf.funcfixup.DWARFFunctionFixup;
import ghidra.program.database.function.OverlappingFunctionException;
-import ghidra.program.model.address.Address;
-import ghidra.program.model.address.AddressSet;
+import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
@@ -45,10 +42,10 @@ public class DWARFFunction {
public enum CommitMode { SKIP, FORMAL, STORAGE, }
public DIEAggregate diea;
- public DWARFNameInfo name;
+ public DWARFName name;
public Namespace namespace;
+ private DWARFRangeList dwarfBody;
public Address address;
- public Address highAddress;
public long frameBase; // TODO: change this to preserve the func's frameBase expr instead of value
public Function function; // ghidra function
@@ -80,34 +77,30 @@ public class DWARFFunction {
if (diea.isDanglingDeclaration()) {
return null;
}
- Address funcAddr = getFuncEntry(diea);
- if (funcAddr == null) {
+ DWARFRangeList bodyRanges = getFuncBodyRanges(diea);
+ if (bodyRanges == null || bodyRanges.isEmpty()) {
return null;
}
DWARFProgram prog = diea.getProgram();
DWARFDataTypeManager dwarfDTM = prog.getDwarfDTM();
- DWARFFunction dfunc = new DWARFFunction(diea, prog.getName(diea), funcAddr);
+ DWARFFunction dfunc = new DWARFFunction(diea, prog.getName(diea), bodyRanges);
dfunc.namespace = dfunc.name.getParentNamespace(prog.getGhidraProgram());
dfunc.sourceInfo = DWARFSourceInfo.create(diea);
- dfunc.highAddress =
- diea.hasAttribute(DW_AT_high_pc) ? prog.getCodeAddress(diea.getHighPC()) : null;
-
// Check if the function is an external function
dfunc.isExternal = diea.getBool(DW_AT_external, false);
dfunc.noReturn = diea.getBool(DW_AT_noreturn, false);
// Retrieve the frame base if it exists
- DWARFLocation frameLoc = null;
- if (diea.hasAttribute(DW_AT_frame_base)) {
- List frameBase = diea.getAsLocation(DW_AT_frame_base, dfunc.getRange());
+ DWARFLocationList frameBaseLocs = diea.getLocationList(DW_AT_frame_base);
+ if (!frameBaseLocs.isEmpty()) {
+ DWARFLocation frameLoc = frameBaseLocs.getLocationContaining(dfunc.getEntryPc());
// get the framebase register, find where the frame is finally setup.
- frameLoc = DWARFLocation.getTopLocation(frameBase, dfunc.address.getOffset());
if (frameLoc != null) {
- dfunc.frameBase = (int) diea.evaluateLocation(frameLoc);
+ dfunc.frameBase = frameLoc.evaluate(diea.getCompilationUnit()).pop();
}
}
@@ -124,25 +117,47 @@ public class DWARFFunction {
return dfunc;
}
- private DWARFFunction(DIEAggregate diea, DWARFNameInfo dni, Address address) {
+ private DWARFFunction(DIEAggregate diea, DWARFName dni, DWARFRangeList dwarfBody) {
this.diea = diea;
this.name = dni;
- this.address = address;
+ this.dwarfBody = dwarfBody;
+ this.address = diea.getProgram().getCodeAddress(dwarfBody.getFirstAddress());
}
public DWARFProgram getProgram() {
return diea.getProgram();
}
- public DWARFRange getRange() {
- return new DWARFRange(address.getOffset(),
- highAddress != null ? highAddress.getOffset() : address.getOffset() + 1);
+ public String getDescriptiveName() {
+ return "%s@%s".formatted(name.getName(), address);
+ }
+
+ public DWARFRangeList getRangeList() {
+ return dwarfBody;
}
public String getCallingConventionName() {
return callingConventionName;
}
+ public AddressSetView getBody() {
+ DWARFProgram dprog = getProgram();
+ AddressSet result = new AddressSet();
+ for (DWARFRange drange : dwarfBody.ranges()) {
+ if (drange.isEmpty()) {
+ continue;
+ }
+ Address start = dprog.getCodeAddress(drange.getFrom());
+ Address end = dprog.getCodeAddress(drange.getTo() - 1);
+ result.add(new AddressRangeImpl(start, end));
+ }
+ return result;
+ }
+
+ public long getEntryPc() {
+ return dwarfBody.getFirstAddress();
+ }
+
/**
* Returns the DWARFVariable that starts at the specified stack offset.
*
@@ -264,18 +279,16 @@ public class DWARFFunction {
try {
varStorage = dvar.getVariableStorage();
if (hasConflictWithParamStorage(dvar)) {
- appendComment(function.getEntryPoint(), CodeUnit.PLATE_COMMENT,
+ getProgram().logWarningAt(function.getEntryPoint(), function.getName(),
"Local variable %s[%s] conflicts with parameter, skipped."
- .formatted(dvar.getDeclInfoString(), varStorage),
- "\n");
+ .formatted(dvar.getDeclInfoString(), varStorage));
return;
}
if (hasConflictWithExistingLocalVariableStorage(dvar)) {
- appendComment(function.getEntryPoint().add(dvar.lexicalOffset),
- CodeUnit.EOL_COMMENT, "Local omitted variable %s[%s] scope starts here"
- .formatted(dvar.getDeclInfoString(), varStorage),
- "; ");
+ getProgram().logWarningAt(function.getEntryPoint().add(dvar.lexicalOffset),
+ function.getName(), "Local omitted variable %s[%s] scope starts here"
+ .formatted(dvar.getDeclInfoString(), varStorage));
return;
}
@@ -301,55 +314,41 @@ public class DWARFFunction {
function.addLocalVariable(var, SourceType.IMPORTED);
}
catch (InvalidInputException | DuplicateNameException e) {
- appendComment(function.getEntryPoint().add(dvar.lexicalOffset), CodeUnit.EOL_COMMENT,
+ getProgram()
+ .logWarningAt(function.getEntryPoint().add(dvar.lexicalOffset),
+ function.getName(),
"Local omitted variable %s[%s] scope starts here".formatted(
dvar.getDeclInfoString(),
- varStorage != null ? varStorage.toString() : "UNKNOWN"),
- "; ");
-
+ varStorage != null ? varStorage.toString() : "UNKNOWN"));
}
}
- private static boolean isBadSubprogramDef(DIEAggregate diea) {
- if (diea.isDanglingDeclaration() || !diea.hasAttribute(DW_AT_low_pc)) {
- return true;
- }
-
- // fetch the low_pc attribute directly instead of calling diea.getLowPc() to avoid
- // any fixups applied by lower level code
- DWARFNumericAttribute attr = diea.getAttribute(DW_AT_low_pc, DWARFNumericAttribute.class);
- if (attr != null && attr.getUnsignedValue() == 0) {
- return true;
- }
-
- return false;
- }
-
- private void appendComment(Address address, int commentType, String comment, String sep) {
- DWARFUtil.appendComment(getProgram().getGhidraProgram(), address, commentType, "", comment,
- sep);
- }
-
//---------------------------------------------------------------------------------------------
- private static Address getFuncEntry(DIEAggregate diea) throws IOException {
- // TODO: dw_at_entry_pc is also sometimes available, typically in things like inlined_subroutines
+ public static AddressRange getFuncBody(DIEAggregate diea, boolean flattenDisjoint)
+ throws IOException {
+ // TODO: dw_at_entry_pc is also sometimes available, typically in things like inlined_subroutines
DWARFProgram dprog = diea.getProgram();
- DWARFNumericAttribute lowpcAttr =
- diea.getAttribute(DW_AT_low_pc, DWARFNumericAttribute.class);
- if (lowpcAttr != null && lowpcAttr.getUnsignedValue() != 0) {
- return dprog.getCodeAddress(
- lowpcAttr.getUnsignedValue() + dprog.getProgramBaseAddressFixup());
- }
- if (diea.hasAttribute(DW_AT_ranges)) {
- List bodyRanges = diea.readRange(DW_AT_ranges);
- if (!bodyRanges.isEmpty()) {
- return dprog.getCodeAddress(bodyRanges.get(0).getFrom());
- }
+ DWARFRangeList bodyRangeList = getFuncBodyRanges(diea);
+ if (bodyRangeList != null && !bodyRangeList.isEmpty()) {
+ DWARFRange bodyRange =
+ flattenDisjoint ? bodyRangeList.getFlattenedRange() : bodyRangeList.getFirst();
+ return dprog.getAddressRange(bodyRange, true);
}
return null;
}
+ public static DWARFRangeList getFuncBodyRanges(DIEAggregate diea) throws IOException {
+ DWARFRange body = diea.getPCRange();
+ if (body != null && !body.isEmpty()) {
+ return new DWARFRangeList(body);
+ }
+ if (diea.hasAttribute(DW_AT_ranges)) {
+ return diea.getRangeList(DW_AT_ranges);
+ }
+ return DWARFRangeList.EMTPY;
+ }
+
public boolean syncWithExistingGhidraFunction(boolean createIfMissing) {
try {
Program currentProgram = getProgram().getGhidraProgram();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java
similarity index 77%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java
index a4fbf5f113..88dcc044d7 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporter.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java
@@ -13,21 +13,14 @@
* 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 ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+package ghidra.app.util.bin.format.dwarf;
import java.io.IOException;
import java.util.*;
-import ghidra.app.cmd.label.SetLabelPrimaryCmd;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction.CommitMode;
-import ghidra.program.database.function.OverlappingFunctionException;
-import ghidra.program.model.address.Address;
-import ghidra.program.model.address.AddressSet;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
+import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.*;
@@ -126,6 +119,9 @@ public class DWARFFunctionImporter {
case DW_TAG_label:
processLabel(diea);
break;
+ default:
+ // do nothing
+ break;
}
}
catch (OutOfMemoryError oom) {
@@ -206,10 +202,8 @@ public class DWARFFunctionImporter {
dfunc.updateFunctionSignature();
}
else {
- Msg.warn(this,
- "Failed to get DWARF function signature information, leaving undefined: %s@%s"
- .formatted(dfunc.function.getName(), dfunc.function.getEntryPoint()));
- //Msg.debug(this, "DIE info: " + diea.toString());
+ prog.logWarningAt(dfunc.function.getEntryPoint(), dfunc.function.getName(),
+ "Failed to get DWARF function signature information, leaving undefined");
}
for (DWARFVariable localVar : dfunc.localVars) {
@@ -255,9 +249,8 @@ public class DWARFFunctionImporter {
FunctionDefinition origFuncDef) {
if (dfunc.sourceInfo != null) {
// Move the function into the program tree of the file
- moveIntoFragment(dfunc.function.getName(), dfunc.address,
- dfunc.highAddress != null ? dfunc.highAddress : dfunc.address.add(1),
- dfunc.sourceInfo.getFilename());
+ moveIntoFragment(dfunc.function.getName(), dfunc.getBody(),
+ dfunc.sourceInfo.filename());
if (importOptions.isOutputSourceLocationInfo()) {
appendPlateComment(dfunc.address, "", dfunc.sourceInfo.getDescriptionStr());
@@ -323,7 +316,9 @@ public class DWARFFunctionImporter {
DIEAggregate partDIEA = DIEAggregate.createSkipHead(diea);
processSubprogram(partDIEA);
break;
-
+ default:
+ // do nothing
+ break;
}
}
}
@@ -397,8 +392,9 @@ public class DWARFFunctionImporter {
Data varData = DataUtilities.createData(currentProgram, address, dataType, -1,
ClearDataMode.CLEAR_ALL_CONFLICT_DATA);
if (varData != null && globalVar.sourceInfo != null) {
- moveIntoFragment(name, varData.getMinAddress(), varData.getMaxAddress(),
- globalVar.sourceInfo.getFilename());
+ AddressSet dataRng =
+ new AddressSet(varData.getMinAddress(), varData.getMaxAddress());
+ moveIntoFragment(name, dataRng, globalVar.sourceInfo.filename());
}
variablesProcesesed.add(address);
importSummary.globalVarsAdded++;
@@ -426,33 +422,16 @@ public class DWARFFunctionImporter {
return;
}
- Number lowPC = null;
- boolean disjoint = false;
+ DWARFRangeList blockRanges =
+ Objects.requireNonNullElse(DWARFFunction.getFuncBodyRanges(diea), DWARFRangeList.EMTPY);
+ Address blockStart =
+ !blockRanges.isEmpty() ? prog.getCodeAddress(blockRanges.getFirst().getFrom()) : null;
- // TODO: Do we need to setup the correct frame base based on the
- // location of this lexical block?
-
- // Process low and high pc if it exists
- if (diea.hasAttribute(DW_AT_low_pc) && diea.hasAttribute(DW_AT_high_pc)) {
- lowPC = diea.getLowPC(0);
- }
- // Otherwise process a range list
- else if (diea.hasAttribute(DW_AT_ranges)) {
- List ranges = diea.parseDebugRange(DW_AT_ranges);
-
- // No range found
- if (ranges.isEmpty()) {
- return;
- }
-
- lowPC = ranges.get(0).getFrom();
- disjoint = ranges.size() > 1;
- }
- Address blockStart = lowPC != null ? prog.getCodeAddress(lowPC) : null;
if (blockStart != null && importOptions.isOutputLexicalBlockComments()) {
- DWARFNameInfo dni = prog.getName(diea);
+ boolean disjoint = blockRanges.getListCount() > 1;
+ DWARFName dni = prog.getName(diea);
appendComment(blockStart, CodeUnit.PRE_COMMENT,
- "Begin: " + dni.getName() + (disjoint ? " - Disjoint" : ""), "\n");
+ "Begin: %s%s".formatted(dni.getName(), disjoint ? " - Disjoint" : ""), "\n");
}
processFuncChildren(diea, dfunc,
@@ -465,54 +444,30 @@ public class DWARFFunctionImporter {
return;
}
- Number lowPC = null;
- Number highPC = null;
-
- // Process low and high pc if it exists
- if (diea.hasAttribute(DW_AT_low_pc) && diea.hasAttribute(DW_AT_high_pc)) {
- lowPC = diea.getLowPC(0);
- highPC = diea.getHighPC();
- }
- // Otherwise process a range list
- else if (diea.hasAttribute(DW_AT_ranges)) {
- List ranges = diea.parseDebugRange(DW_AT_ranges);
-
- // No range found
- if (ranges.isEmpty()) {
- return;
+ AddressRange body = DWARFFunction.getFuncBody(diea, true);
+ if (body != null) {
+ if (importOptions.isOutputInlineFuncComments()) {
+ addCommentsForInlineFunc(diea, body);
}
-
- lowPC = ranges.get(0).getFrom();
- highPC = ranges.get(ranges.size() - 1).getTo();
+ processFuncChildren(diea, dfunc, body.getMinAddress().subtract(dfunc.address));
}
- else {
- return;
- }
-
- Address startAddr = prog.getCodeAddress(lowPC);
- Address endAddr = prog.getCodeAddress(highPC);
- if (importOptions.isOutputInlineFuncComments()) {
- addCommentsForInlineFunc(diea, startAddr, endAddr);
- }
-
- processFuncChildren(diea, dfunc, startAddr.subtract(dfunc.address));
}
/*
* Constructs a function def signature for the function and adds it as a comment, either
* EOL or PRE depending on how small the inline func is.
*/
- private void addCommentsForInlineFunc(DIEAggregate diea, Address blockStart, Address blockEnd) {
+ private void addCommentsForInlineFunc(DIEAggregate diea, AddressRange range) {
FunctionDefinition funcDef = dwarfDTM.getFunctionSignature(diea);
if (funcDef != null) {
- long inlineFuncLen = blockEnd.subtract(blockStart);
+ long inlineFuncLen = range.getLength();
boolean isShort = inlineFuncLen < INLINE_FUNC_SHORT_LEN;
if (isShort) {
- appendComment(blockStart, CodeUnit.EOL_COMMENT,
+ appendComment(range.getMinAddress(), CodeUnit.EOL_COMMENT,
"inline " + funcDef.getPrototypeString(), "; ");
}
else {
- appendComment(blockStart, CodeUnit.PRE_COMMENT,
+ appendComment(range.getMinAddress(), CodeUnit.PRE_COMMENT,
"Begin: inline " + funcDef.getPrototypeString(), "\n");
}
}
@@ -550,7 +505,7 @@ public class DWARFFunctionImporter {
* @param end end address of the fragment
* @param fileID offset of the file name in the debug_line section
*/
- private void moveIntoFragment(String name, Address start, Address end, String fileName) {
+ private void moveIntoFragment(String name, AddressSetView range, String fileName) {
if (fileName != null) {
ProgramModule module = null;
int index = rootModule.getIndex(fileName);
@@ -559,8 +514,8 @@ public class DWARFFunctionImporter {
module = rootModule.createModule(fileName);
}
catch (DuplicateNameException e) {
- Msg.error(this,
- "Error while moving fragment " + name + " from " + start + " to " + end, e);
+ Msg.error(this, "Error while moving fragment %s (%s)".formatted(name, range),
+ e);
return;
}
}
@@ -579,10 +534,11 @@ public class DWARFFunctionImporter {
Group[] children = module.getChildren();//TODO add a getChildAt(index) method...
frag = (ProgramFragment) children[index];
}
- frag.move(start, end);
+ frag.move(range.getMinAddress(), range.getMaxAddress());
}
catch (NotFoundException e) {
- Msg.error(this, "Error moving fragment from " + start + " to " + end, e);
+ Msg.error(this, "Error while moving fragment %s (%s)".formatted(name, range),
+ e);
return;
}
catch (DuplicateNameException e) {
@@ -592,61 +548,15 @@ public class DWARFFunctionImporter {
}
}
- private Function createFunction(DWARFFunction dfunc, DIEAggregate diea) {
- try {
- // create a new symbol if one does not exist (symbol table will figure this out)
- SymbolTable symbolTable = currentProgram.getSymbolTable();
- symbolTable.createLabel(dfunc.address, dfunc.name.getName(), dfunc.namespace,
- SourceType.IMPORTED);
-
- // force new label to become primary (if already a function it will become function name)
- SetLabelPrimaryCmd cmd =
- new SetLabelPrimaryCmd(dfunc.address, dfunc.name.getName(), dfunc.namespace);
- cmd.applyTo(currentProgram);
-
- setExternalEntryPoint(dfunc.isExternal, dfunc.address);
-
- Function function = currentProgram.getListing().getFunctionAt(dfunc.address);
- if (function == null) {
-
- // TODO: If not contained within program memory should they be considered external?
-
- if (!currentProgram.getMemory()
- .getLoadedAndInitializedAddressSet()
- .contains(dfunc.address)) {
- Msg.warn(this,
- String.format(
- "DWARF: unable to create function not contained within loaded memory: %s@%s",
- dfunc.name, dfunc.address));
- return null;
- }
-
- // create 1-byte function if one does not exist - primary label will become function names
- function = currentProgram.getFunctionManager()
- .createFunction(null, dfunc.address, new AddressSet(dfunc.address),
- SourceType.IMPORTED);
- }
-
- return function;
- }
- catch (OverlappingFunctionException e) {
- throw new AssertException(e);
- }
- catch (InvalidInputException e) {
- Msg.error(this, "Failed to create function " + dfunc.namespace + "/" +
- dfunc.name.getName() + ": " + e.getMessage());
- }
- return null;
- }
-
private void processLabel(DIEAggregate diea) {
if (!shouldProcess(diea)) {
return;
}
String name = prog.getEntryName(diea);
- if (name != null && diea.hasAttribute(DW_AT_low_pc)) {
- Address address = prog.getCodeAddress(diea.getLowPC(0));
+ DWARFRange labelPc;
+ if (name != null && (labelPc = diea.getPCRange()) != null) {
+ Address address = prog.getCodeAddress(labelPc.getFrom());
if (address.getOffset() != 0) {
try {
SymbolTable symbolTable = currentProgram.getSymbolTable();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFIdentifierCase.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIdentifierCase.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFIdentifierCase.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIdentifierCase.java
index 7263d91fd1..0b95bca553 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFIdentifierCase.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIdentifierCase.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
+package ghidra.app.util.bin.format.dwarf;
import java.util.HashMap;
import java.util.Map;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportOptions.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportOptions.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportOptions.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportOptions.java
index 81b6f75a2d..68918bcbd2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportOptions.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportOptions.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import ghidra.app.plugin.core.analysis.AnalysisOptionsUpdater;
import ghidra.app.plugin.core.analysis.DWARFAnalyzer;
@@ -97,6 +97,7 @@ public class DWARFImportOptions {
private boolean tryPackStructs = true;
private boolean specialCaseSizedBaseTypes = true;
private boolean importLocalVariables = true;
+ private boolean useBookmarks = true;
/**
* Create new instance
@@ -355,6 +356,10 @@ public class DWARFImportOptions {
this.importLocalVariables = importLocalVariables;
}
+ public boolean isUseBookmarks() {
+ return useBookmarks;
+ }
+
/**
* See {@link Analyzer#registerOptions(Options, ghidra.program.model.listing.Program)}
*
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportSummary.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java
similarity index 65%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportSummary.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java
index b6fba8270e..f36816b2ae 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFImportSummary.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java
@@ -13,10 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.*;
import ghidra.util.Msg;
@@ -41,13 +40,23 @@ public class DWARFImportSummary {
int varDWARFExpressionValue;
int exprReadError;
Set typeRemappings = new HashSet<>();
+ int paramZeroLenDataType;
+ Set dwarfVers = new HashSet<>();
+ int compUnitCount;
+ int dieCount;
+ Set compDirs = new HashSet<>();
+ List compNames = new ArrayList<>();
+ Set producers = new HashSet<>();
+ Set sourceLangs = new HashSet<>();
/**
* Writes summary information to the {@link Msg} log.
*/
public void logSummaryResults() {
if (totalElapsedMS > 0) {
- Msg.info(this, String.format("DWARF import - total elapsed: %dms", totalElapsedMS));
+ Msg.info(this, "DWARF ver%s, %d compUnits, %d DIES, import - total elapsed: %dms"
+ .formatted(getSortedSet(dwarfVers).toString(), compUnitCount, dieCount,
+ totalElapsedMS));
}
if (dataTypeElapsedMS > 0) {
Msg.info(this,
@@ -67,6 +76,18 @@ public class DWARFImportSummary {
Msg.info(this,
String.format("DWARF function signatures added: %d", funcSignaturesAdded));
}
+ if (!compDirs.isEmpty()) {
+ Msg.info(this, "DWARF compile dirs: " + getSortedSet(compDirs).toString());
+ }
+ if (!producers.isEmpty()) {
+ Msg.info(this, "DWARF producers: " + getSortedSet(producers));
+ }
+ if (!sourceLangs.isEmpty()) {
+ Msg.info(this, "DWARF source languages: " + getSortedSet(sourceLangs));
+ }
+ for (String s : compNames) {
+ Msg.info(this, "DWARF compUnit: " + s);
+ }
if (!typeRemappings.isEmpty()) {
Msg.error(this,
@@ -108,8 +129,40 @@ public class DWARFImportSummary {
"DWARF variable definitions that failed because they are computed pseudo variables: " +
varDWARFExpressionValue);
}
+
+ if (paramZeroLenDataType > 0) {
+ Msg.error(this, "DWARF zero-length parameters: " + paramZeroLenDataType);
+ }
if (exprReadError > 0) {
Msg.error(this, "DWARF expression failed to read: " + exprReadError);
}
}
+
+ private > List getSortedSet(Set set) {
+ List result = new ArrayList<>(set);
+ Collections.sort(result);
+ return result;
+ }
+
+ void addCompunitInfo(List compUnits) {
+ for (DWARFCompilationUnit cu : compUnits) {
+ String compileDirectory = cu.getCompileDirectory();
+ if (compileDirectory != null && !compileDirectory.isBlank()) {
+ compDirs.add(compileDirectory);
+ }
+ String name = cu.getName();
+ if (name != null && !name.isBlank()) {
+ compNames.add(name);
+ }
+ String prod = cu.getProducer();
+ if (prod != null && !prod.isBlank()) {
+ producers.add(prod);
+ }
+ int lang = cu.getLanguage();
+ if (lang != -1) {
+ sourceLangs.add(DWARFUtil.toString(DWARFSourceLanguage.class, lang));
+ }
+ }
+
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java
similarity index 94%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java
index 14cf1d2972..236246f274 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFParser.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java
@@ -13,14 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import ghidra.app.plugin.core.datamgr.util.DataTypeUtils;
-import ghidra.app.util.bin.format.dwarf4.DWARFException;
import ghidra.program.model.data.*;
import ghidra.util.Msg;
import ghidra.util.Swing;
@@ -33,12 +32,12 @@ import utility.function.Dummy;
* Performs a DWARF datatype import and a DWARF function import, under the control of the
* {@link DWARFImportOptions}.
*/
-public class DWARFParser {
+public class DWARFImporter {
private DWARFProgram prog;
private DWARFDataTypeManager dwarfDTM;
private TaskMonitor monitor;
- public DWARFParser(DWARFProgram prog, TaskMonitor monitor) {
+ public DWARFImporter(DWARFProgram prog, TaskMonitor monitor) {
this.prog = prog;
this.monitor = monitor;
this.dwarfDTM = prog.getDwarfDTM();
@@ -87,9 +86,9 @@ public class DWARFParser {
prog.getGhidraProgram().getDataTypeManager().getDataType(dataTypePath);
if (dataType != null && !(dataType instanceof Pointer || dataType instanceof Array)) {
DWARFSourceInfo dsi = dwarfDTM.getSourceInfo(dataType);
- if (dsi != null && dsi.getFilename() != null) {
+ if (dsi != null && dsi.filename() != null) {
CategoryPath dataTypeOrigCP = dataType.getCategoryPath();
- CategoryPath newRoot = new CategoryPath(rootCP, dsi.getFilename());
+ CategoryPath newRoot = new CategoryPath(rootCP, dsi.filename());
CategoryPath newCP =
rehomeCategoryPathSubTree(unCatRootCp, newRoot, dataTypeOrigCP);
if (newCP != null) {
@@ -181,7 +180,7 @@ public class DWARFParser {
* @throws DWARFException
* @throws CancelledException
*/
- public DWARFImportSummary parse() throws IOException, DWARFException, CancelledException {
+ public DWARFImportSummary performImport() throws IOException, DWARFException, CancelledException {
monitor.setIndeterminate(false);
monitor.setShowProgressValue(true);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTable.java
new file mode 100644
index 0000000000..c462bd7e0f
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTable.java
@@ -0,0 +1,106 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * Handles a grouping of {@link DWARFIndirectTableHeader}s that specify how to look up a
+ * certain type of item (per CU).
+ */
+public class DWARFIndirectTable {
+ public interface CheckedIOFunction {
+ R apply(T value) throws IOException;
+ }
+
+ private final BinaryReader reader;
+ private final Map lookupMap = new HashMap<>();
+ private final Function baseOffsetFunc;
+
+ /**
+ * Creates a {@link DWARFIndirectTable}
+ *
+ * @param reader {@link BinaryReader} containing the {@link DWARFIndirectTableHeader}s
+ * @param baseOffsetFunc a function that will return the baseoffset value for a
+ * {@link DWARFCompilationUnit}.
+ */
+ public DWARFIndirectTable(BinaryReader reader,
+ Function baseOffsetFunc) {
+ this.reader = reader;
+ this.baseOffsetFunc = baseOffsetFunc;
+ }
+
+ /**
+ * Populates this instance will all {@link DWARFIndirectTableHeader} instances that can be
+ * read from the stream.
+ *
+ * @param msg String message to use for the taskmonitor
+ * @param headerReader a function that reads the specific table header type from the stream
+ * @param monitor {@link TaskMonitor}
+ * @throws CancelledException if cancelled
+ * @throws IOException if error reading a header
+ */
+ public void bootstrap(String msg,
+ CheckedIOFunction headerReader,
+ TaskMonitor monitor) throws CancelledException, IOException {
+ if (reader == null) {
+ return;
+ }
+ reader.setPointerIndex(0);
+ monitor.initialize(reader.length(), msg);
+ while (reader.hasNext()) {
+ monitor.checkCancelled();
+ monitor.setProgress(reader.getPointerIndex());
+ monitor.setMessage(msg + " #" + lookupMap.size());
+
+ DWARFIndirectTableHeader header = headerReader.apply(reader);
+ if (header != null) {
+ lookupMap.put(header.getFirstElementOffset(), header);
+ }
+ }
+ }
+
+ /**
+ * Returns the offset of an item, based on its index in a particular header (which is found
+ * by the controlling CU)
+ *
+ * @param index index of the item
+ * @param cu {@link DWARFCompilationUnit}
+ * @return long offset of the item. Caller responsible for reading the item themselves
+ * @throws IOException if error reading table data
+ */
+ public long getOffset(int index, DWARFCompilationUnit cu) throws IOException {
+ long base = baseOffsetFunc.apply(cu);
+ DWARFIndirectTableHeader header = lookupMap.get(base);
+ if (header == null) {
+ throw new IOException(
+ "Invalid base %d for compUnit %x".formatted(base, cu.getStartOffset()));
+ }
+ return header.getOffset(index, reader);
+ }
+
+ public void clear() {
+ lookupMap.clear();
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTableHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTableHeader.java
new file mode 100644
index 0000000000..8ffaadd42c
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFIndirectTableHeader.java
@@ -0,0 +1,52 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+
+/**
+ * Common base functionality of indirect table headers (DWARFAddressListHeader,
+ * DWARFLocationListHeader, etc)
+ */
+public abstract class DWARFIndirectTableHeader {
+
+ protected final long startOffset;
+ protected final long endOffset;
+ protected final long firstElementOffset;
+
+ public DWARFIndirectTableHeader(long startOffset, long endOffset, long firstElementOffset) {
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ this.firstElementOffset = firstElementOffset;
+ }
+
+ public long getStartOffset() {
+ return startOffset;
+ }
+
+ public long getFirstElementOffset() {
+ return firstElementOffset;
+ }
+
+ public long getEndOffset() {
+ return endOffset;
+ }
+
+ public abstract long getOffset(int index, BinaryReader reader) throws IOException;
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFInline.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFInline.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFInline.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFInline.java
index c6625d3176..a4c6f22ccf 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFInline.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFInline.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
+package ghidra.app.util.bin.format.dwarf;
import java.util.HashMap;
import java.util.Map;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLengthValue.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLengthValue.java
new file mode 100644
index 0000000000..acb4f95548
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLengthValue.java
@@ -0,0 +1,95 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+
+/**
+ * A tuple of length (of a thing in a dwarf stream) and size of integers used in the dwarf section.
+ *
+ * @param length the length of the following item
+ * @param intSize the size of integers used in the following item
+ */
+public record DWARFLengthValue(long length, int intSize) {
+ /**
+ * Read a variable-length length value from the stream.
+ *
+ * The length value will either occupy 4 (int32) or 12 bytes (int32 flag + int64 length) and
+ * as a side-effect signals the size integer values occupy.
+ *
+ * @param reader {@link BinaryReader} stream to read from
+ * @param defaultPointerSize size in bytes of pointers in the program
+ * @return new {@link DWARFLengthValue}, or null if the stream was just zero-padded data
+ * @throws IOException if io error
+ */
+ public static DWARFLengthValue read(BinaryReader reader, int defaultPointerSize)
+ throws IOException {
+ long startOffset = reader.getPointerIndex();
+ long length = reader.readNextUnsignedInt();
+ int intSize = 4;
+
+ if (length == 0xffff_ffffL /* max uint32 */) {
+ // Length of 0xffffffff implies 64-bit DWARF format
+ // Mostly untested as there is no easy way to force the compiler
+ // to generate this
+ length = reader.readNextLong();
+ intSize = 8;
+ }
+ else if (length >= 0xffff_fff0L) {
+ // Length of 0xfffffff0 or greater is reserved for DWARF
+ throw new IOException(
+ "Reserved DWARF length value: %x. Unknown extension.".formatted(length));
+ }
+ else if (length == 0) {
+ if (isAllZerosUntilEOF(reader)) {
+ // hack to handle trailing padding at end of section. (similar to the check for
+ // unexpectedTerminator in readDIEs(), when padding occurs inside the bounds
+ // of the compile unit's range after the end of the root DIE's children)
+ reader.setPointerIndex(reader.length());
+ return null;
+ }
+
+ // Test for special case of weird BE MIPS 64bit length value.
+ // Instead of following DWARF std (a few lines above with length == MAX_INT),
+ // it writes a raw 64bit long (BE). The upper 32 bits (already read as length) will
+ // always be 0 since super-large binaries from that system weren't really possible.
+ // The next 32 bits will be the remainder of the value.
+ if (reader.isBigEndian() && defaultPointerSize == 8) {
+ length = reader.readNextUnsignedInt();
+ intSize = 8;
+ }
+
+ if (length == 0) {
+ throw new IOException("Invalid DWARF length 0 at 0x%x".formatted(startOffset));
+ }
+ }
+
+ return new DWARFLengthValue(length, intSize);
+ }
+
+ private static boolean isAllZerosUntilEOF(BinaryReader reader) throws IOException {
+ reader = reader.clone();
+ while (reader.hasNext()) {
+ if (reader.readNextByte() != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLine.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLine.java
new file mode 100644
index 0000000000..7bcaf9c077
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLine.java
@@ -0,0 +1,424 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.FilenameUtils;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.DWARFLineContentType.Def;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.program.model.data.LEB128;
+
+/**
+ * Represents source file line number mapping info.
+ */
+public class DWARFLine {
+ private long unit_length;
+ private int version;
+ private long header_length;
+ private int minimum_instruction_length;
+ private int maximum_operations_per_instruction;
+ private int default_is_stmt;
+ private int line_base;
+ private int line_range;
+ private int opcode_base;
+ private int[] standard_opcode_length;
+ private List include_directories = new ArrayList<>();
+ private List file_names = new ArrayList<>();
+ private int address_size;
+ private int segment_selector_size;
+
+ public static DWARFLine empty() {
+ return new DWARFLine();
+ }
+
+ /**
+ * Read a v4 DWARFLine.
+ *
+ * @param dprog {@link DWARFProgram}
+ * @param reader {@link BinaryReader} stream
+ * @param lengthInfo {@link DWARFLengthValue}
+ * @param version DWARFLine version (from header)
+ * @return a new DWARFLine instance if DW_AT_stmt_list and stream are present, otherwise null
+ * @throws IOException if error reading data
+ * @throws DWARFException if bad DWARF values
+ */
+ public static DWARFLine readV4(DWARFProgram dprog, BinaryReader reader,
+ DWARFLengthValue lengthInfo, int version) throws IOException, DWARFException {
+
+ // length : dwarf_length
+ // version : 2 bytes
+ // header_len : dwarf_intsize
+ // min_instr_len : 1 byte
+ // ....
+ DWARFLine result = new DWARFLine();
+ result.unit_length = lengthInfo.length();
+
+ result.version = version;
+ result.header_length = reader.readNextUnsignedValue(lengthInfo.intSize());
+ result.minimum_instruction_length = reader.readNextUnsignedByte();
+
+ if (result.version >= 4) {
+ // Maximum operations per instruction only exists in DWARF version 4 or higher
+ result.maximum_operations_per_instruction = reader.readNextUnsignedByte();
+ }
+ else {
+ result.maximum_operations_per_instruction = 1;
+ }
+ result.default_is_stmt = reader.readNextUnsignedByte();
+ result.line_base = reader.readNextByte();
+ result.line_range = reader.readNextUnsignedByte();
+ result.opcode_base = reader.readNextUnsignedByte();
+ result.standard_opcode_length = new int[result.opcode_base];
+ result.standard_opcode_length[0] = 1; /* Should never be used */
+ for (int i = 1; i < result.opcode_base; i++) {
+ result.standard_opcode_length[i] = reader.readNextUnsignedByte();
+ }
+
+ // Read all include directories
+ String include = reader.readNextAsciiString();
+ while (include.length() != 0) {
+ result.include_directories.add(new DWARFFile(include));
+ include = reader.readNextAsciiString();
+ }
+
+ // Read all files, ending when null (hit empty filename)
+ DWARFFile file;
+ while ((file = DWARFFile.readV4(reader)) != null) {
+ result.file_names.add(file);
+ }
+
+ return result;
+ }
+
+ /**
+ * Read a v5 DWARFLine.
+ *
+ * @param dprog {@link DWARFProgram}
+ * @param reader {@link BinaryReader} stream
+ * @param lengthInfo {@link DWARFLengthValue}
+ * @param version DWARFLine version (from header)
+ * @param cu {@link DWARFCompilationUnit}
+ * @return a new DWARFLine instance if DW_AT_stmt_list and stream are present, otherwise null
+ * @throws IOException if error reading data
+ * @throws DWARFException if bad DWARF values
+ */
+ public static DWARFLine readV5(DWARFProgram dprog, BinaryReader reader,
+ DWARFLengthValue lengthInfo, int version, DWARFCompilationUnit cu)
+ throws IOException, DWARFException {
+
+ // length : dwarf_length
+ // version : 2 bytes
+ // address_size : 1 byte
+ // segment_selector_size : 1 byte
+ // header_len : dwarf_intsize
+ // min_instr_len : 1 byte
+ // ...
+ DWARFLine result = new DWARFLine();
+ result.unit_length = lengthInfo.length();
+ result.version = version;
+ result.address_size = reader.readNextUnsignedByte();
+ result.segment_selector_size = reader.readNextUnsignedByte();
+ result.header_length = reader.readNextUnsignedValue(lengthInfo.intSize());
+ result.minimum_instruction_length = reader.readNextUnsignedByte();
+ result.maximum_operations_per_instruction = reader.readNextUnsignedByte();
+ result.default_is_stmt = reader.readNextUnsignedByte();
+ result.line_base = reader.readNextByte();
+ result.line_range = reader.readNextUnsignedByte();
+ result.opcode_base = reader.readNextUnsignedByte();
+ result.standard_opcode_length = new int[result.opcode_base];
+ result.standard_opcode_length[0] = 1; /* Should never be used */
+ for (int i = 1; i < result.opcode_base; i++) {
+ result.standard_opcode_length[i] = reader.readNextUnsignedByte();
+ }
+ int directory_entry_format_count = reader.readNextUnsignedByte();
+ List dirFormatDefs = new ArrayList<>();
+ for (int i = 0; i < directory_entry_format_count; i++) {
+ Def lcntDef = DWARFLineContentType.Def.read(reader);
+ dirFormatDefs.add(lcntDef);
+ }
+
+ int directories_count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ for (int i = 0; i < directories_count; i++) {
+ DWARFFile dir = DWARFFile.readV5(reader, dirFormatDefs, cu);
+ result.include_directories.add(dir);
+ }
+
+ int filename_entry_format_count = reader.readNextUnsignedByte();
+ List fileFormatDefs = new ArrayList<>();
+ for (int i = 0; i < filename_entry_format_count; i++) {
+ Def lcntDef = DWARFLineContentType.Def.read(reader);
+ fileFormatDefs.add(lcntDef);
+ }
+
+ int file_names_count = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ for (int i = 0; i < file_names_count; i++) {
+ DWARFFile dir = DWARFFile.readV5(reader, fileFormatDefs, cu);
+ result.file_names.add(dir);
+ }
+
+ return result;
+ }
+
+ record DirectoryEntryFormat(int contentTypeCode, int formCode) {
+ static DirectoryEntryFormat read(BinaryReader reader) throws IOException, IOException {
+ int contentTypeCode = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int formCode = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+
+ return new DirectoryEntryFormat(contentTypeCode, formCode);
+ }
+ }
+
+ private DWARFLine() {
+ // empty, use #read()
+ }
+
+ /**
+ * Get a file name with the full path included.
+ * @param index index of the file
+ * @param compileDirectory current compile unit directory
+ * @return file name with full path
+ */
+ public String getFullFile(int index, String compileDirectory) {
+ if (index == 0) {
+ //TODO: Handle index = 0
+ throw new UnsupportedOperationException(
+ "Currently does not support retrieving the primary source file.");
+ }
+ else if (index > 0) {
+ // Retrieve the file by index (index starts at 1)
+ DWARFFile file = this.file_names.get(index - 1);
+
+ File fileObj = new File(file.getName());
+
+ // Check to see if the file is an absolute path and return if so
+ if (fileObj.isAbsolute()) {
+ return file.getName();
+ }
+
+ // Otherwise we need to retrieve the directory
+ int diridx = (int) file.getDirectoryIndex();
+ if (diridx == 0) {
+ // Use the compile directory if a directory index of 0 is given
+ if (compileDirectory != null) {
+ return compileDirectory + file.getName();
+ }
+ throw new IllegalArgumentException(
+ "No compile directory was given when one was expected.");
+ }
+ else if (diridx > 0) {
+ // Retrieve and append the directory
+ DWARFFile directory = this.include_directories.get(diridx - 1);
+ return directory.getName() + file.getName();
+ }
+ throw new IndexOutOfBoundsException(
+ "Negative directory index was found: " + Integer.toString(diridx));
+ }
+ throw new IllegalArgumentException(
+ "Negative file index was given: " + Integer.toString(index));
+ }
+
+ /**
+ * Get a file name given a file index.
+ * @param index index of the file
+ * @param compileDirectory current compile unit directory
+ * @return file name
+ */
+ public String getFile(int index, String compileDirectory) {
+ if (version < 5) {
+ if (index == 0) {
+ //TODO: Handle index = 0
+ throw new UnsupportedOperationException(
+ "Currently does not support retrieving the primary source file.");
+ }
+ else if (index > 0) {
+ // Retrieve the file by index (index starts at 1)
+ DWARFFile file = this.file_names.get(index - 1);
+ return FilenameUtils.getName(file.getName());
+ }
+ throw new IllegalArgumentException(
+ "Negative file index was given: " + Integer.toString(index));
+ }
+ else if (version >= 5) {
+ if (index < 0 || file_names.size() <= index) {
+ throw new IllegalArgumentException("Bad file index: " + index);
+ }
+ DWARFFile file = this.file_names.get(index);
+ return FilenameUtils.getName(file.getName());
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if file exists.
+ *
+ * @param index file number, excluding 0
+ * @return boolean true if file exists
+ */
+ public boolean isValidFileIndex(int index) {
+ index--;
+ return 0 <= index && index < file_names.size();
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("Line Entry");
+ buffer.append(" Include Directories: [");
+ for (DWARFFile dir : this.include_directories) {
+ buffer.append(dir);
+ buffer.append(", ");
+ }
+ buffer.append("] File Names: [");
+ for (DWARFFile file : this.file_names) {
+ buffer.append(file.toString());
+ buffer.append(", ");
+ }
+ buffer.append("]");
+ return buffer.toString();
+ }
+
+ /**
+ * DWARFFile is used to store file information for each entry in the line section header.
+ */
+ public static class DWARFFile {
+ /**
+ * Reads a DWARFFile entry.
+ *
+ * @param reader BinaryReader
+ * @return new DWARFFile, or null if end-of-list was found
+ * @throws IOException if error reading
+ */
+ public static DWARFFile readV4(BinaryReader reader) throws IOException {
+ String name = reader.readNextAsciiString();
+ if (name.length() == 0) {
+ // empty name == end-of-list of files
+ return null;
+ }
+
+ long directory_index = reader.readNext(LEB128::unsigned);
+ long modification_time = reader.readNext(LEB128::unsigned);
+ long length = reader.readNext(LEB128::unsigned);
+
+ return new DWARFFile(name, directory_index, modification_time, length, null);
+ }
+
+ /**
+ * Reads a DWARFFile entry.
+ *
+ * @param reader BinaryReader
+ * @param defs similar to a DIE's attributespec, a list of DWARFForms that define how values
+ * will be deserialized from the stream
+ * @param cu {@link DWARFCompilationUnit}
+ * @return new DWARFFile
+ * @throws IOException if error reading
+ */
+ public static DWARFFile readV5(BinaryReader reader, List defs,
+ DWARFCompilationUnit cu) throws IOException {
+
+ String name = null;
+ long directoryIndex = -1;
+ long modTime = 0;
+ long length = 0;
+ byte[] md5 = null;
+ for (DWARFLineContentType.Def def : defs) {
+ DWARFFormContext context = new DWARFFormContext(reader, cu, def);
+ DWARFAttributeValue val = def.getAttributeForm().readValue(context);
+
+ switch (def.getAttributeId()) {
+ case DW_LNCT_path:
+ name = val instanceof DWARFStringAttribute strval
+ ? strval.getValue(cu)
+ : null;
+ break;
+ case DW_LNCT_directory_index:
+ directoryIndex =
+ val instanceof DWARFNumericAttribute numval ? numval.getValue() : -1;
+ break;
+ case DW_LNCT_timestamp:
+ modTime =
+ val instanceof DWARFNumericAttribute numval ? numval.getValue() : 0;
+ break;
+ case DW_LNCT_size:
+ length = val instanceof DWARFNumericAttribute numval
+ ? numval.getUnsignedValue()
+ : 0;
+ break;
+ case DW_LNCT_MD5:
+ md5 = val instanceof DWARFBlobAttribute blobval ? blobval.getBytes() : null;
+ break;
+ default:
+ // skip any DW_LNCT_??? values that we don't care about
+ break;
+ }
+ }
+ if (name == null) {
+ throw new IOException("No name value for DWARFLine file");
+ }
+ return new DWARFFile(name, directoryIndex, modTime, length, md5);
+ }
+
+ private String name;
+ private long directory_index;
+ private long modification_time;
+ private long length;
+ private byte[] md5;
+
+ public DWARFFile(String name) {
+ this(name, -1, 0, 0, null);
+ }
+
+ /**
+ * Create a new DWARF file entry with the given parameters.
+ * @param name name of the file
+ * @param directory_index index of the directory for this file
+ * @param modification_time modification time of the file
+ * @param length length of the file
+ */
+ public DWARFFile(String name, long directory_index, long modification_time, long length,
+ byte[] md5) {
+ this.name = name;
+ this.directory_index = directory_index;
+ this.modification_time = modification_time;
+ this.length = length;
+ this.md5 = md5;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public long getDirectoryIndex() {
+ return this.directory_index;
+ }
+
+ public long getModificationTime() {
+ return this.modification_time;
+ }
+
+ @Override
+ public String toString() {
+ return "Filename: %s, Length: 0x%x, Time: 0x%x, DirIndex: %d".formatted(name, length,
+ modification_time, directory_index);
+ }
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLineContentType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLineContentType.java
new file mode 100644
index 0000000000..eb933c61d3
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLineContentType.java
@@ -0,0 +1,111 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+
+/**
+ * Represents an identifier of a value in a DWARFLine/DWARFFile object.
+ *
+ * Similar to the {@link DWARFAttribute} enum, both are identifiers of an attribute value
+ * that is serialized by a DWARFForm.
+ *
+ * Users of this enum should be tolerant of unknown values.
+ */
+public enum DWARFLineContentType {
+ DW_LNCT_path(0x1),
+ DW_LNCT_directory_index(0x2),
+ DW_LNCT_timestamp(0x3),
+ DW_LNCT_size(0x4),
+ DW_LNCT_MD5(0x5),
+ DW_LNCT_lo_user(0x2000),
+ DW_LNCT_hi_user(0x3fff),
+
+ DW_LNCT_UNKNOWN(-1); // fake ghidra value
+
+ DWARFLineContentType(int id) {
+ this.id = id;
+ }
+
+ private final int id;
+
+ public static DWARFLineContentType of(int id) {
+ return lookupMap.getOrDefault(id, DW_LNCT_UNKNOWN);
+ }
+
+ private static Map lookupMap = buildLookup();
+
+ private static Map buildLookup() {
+ Map result = new HashMap<>();
+ for (DWARFLineContentType e : values()) {
+ result.put(e.id, e);
+ }
+ return result;
+ }
+
+ /**
+ * Defines a {@link DWARFLineContentType} attribute value.
+ */
+ public static class Def extends DWARFAttributeDef {
+
+ /**
+ * Reads a {@link DWARFLineContentType.Def} instance from the {@link BinaryReader reader}.
+ *
+ * Returns a null if its a end-of-list marker.
+ *
+ * @param reader {@link BinaryReader} stream
+ * @return {@link DWARFLineContentType.Def}, or null if stream was at a end-of-list marker
+ * (which isn't really a thing for line content defs, but is a thing for attribute defs)
+ * @throws IOException if error reading
+ */
+ public static Def read(BinaryReader reader) throws IOException {
+ DWARFAttributeDef tmp =
+ DWARFAttributeDef.read(reader, DWARFLineContentType::of);
+ if (tmp == null) {
+ return null;
+ }
+
+ return new Def(tmp.getAttributeId(), tmp.getRawAttributeId(), tmp.getAttributeForm(),
+ tmp.getImplicitValue());
+ }
+
+ public Def(DWARFLineContentType attributeId, int rawAttributeId, DWARFForm attributeForm,
+ long implicitValue) {
+ super(attributeId, rawAttributeId, attributeForm, implicitValue);
+ }
+
+ public DWARFLineContentType getId() {
+ return super.getAttributeId();
+ }
+
+ @Override
+ protected String getRawAttributeIdDescription() {
+ return "DW_LNCT_???? %d (0x%x)".formatted(attributeId, attributeId);
+ }
+
+ @Override
+ public Def withForm(DWARFForm newForm) {
+ return new Def(attributeId, rawAttributeId, newForm, implicitValue);
+ }
+
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocation.java
new file mode 100644
index 0000000000..fddae01ef5
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocation.java
@@ -0,0 +1,77 @@
+/* ###
+ * 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.dwarf;
+
+import java.util.Arrays;
+
+import ghidra.app.util.bin.format.dwarf.expression.*;
+
+/**
+ * Represents the location of an item that is only valid for a certain range of program-counter
+ * locations.
+ *
+ * An instance that does not have a DWARFRange is considered valid for any pc.
+ */
+public class DWARFLocation {
+ private DWARFRange addressRange;
+ private byte[] expr;
+
+ /**
+ * Create a Location given an address range and location expression.
+ *
+ * @param start start address range
+ * @param end end of address range
+ * @param expr bytes of a DWARFExpression
+ */
+ public DWARFLocation(long start, long end, byte[] expr) {
+ this(new DWARFRange(start, end), expr);
+ }
+
+ public DWARFLocation(DWARFRange addressRange, byte[] expr) {
+ this.addressRange = addressRange;
+ this.expr = expr;
+ }
+
+ public DWARFRange getRange() {
+ return this.addressRange;
+ }
+
+ public byte[] getExpr() {
+ return this.expr;
+ }
+
+ public boolean isWildcard() {
+ return addressRange == null;
+ }
+
+ public long getOffset(long pc) {
+ return addressRange != null ? addressRange.getFrom() - pc : 0;
+ }
+
+ public boolean contains(long addr) {
+ return isWildcard() || addressRange.contains(addr);
+ }
+
+ public DWARFExpressionResult evaluate(DWARFCompilationUnit cu) throws DWARFExpressionException {
+ DWARFExpressionEvaluator evaluator = new DWARFExpressionEvaluator(cu);
+ return evaluator.evaluate(evaluator.readExpr(this.expr));
+ }
+
+ @Override
+ public String toString() {
+ return "DWARFLocation: range: %s, expr: %s".formatted(addressRange, Arrays.toString(expr));
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java
new file mode 100644
index 0000000000..c8055d9239
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java
@@ -0,0 +1,229 @@
+/* ###
+ * 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.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.DWARFLocationListEntry.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpression;
+import ghidra.program.model.data.LEB128;
+import ghidra.util.NumericUtilities;
+
+/**
+ * A collection of {@link DWARFLocation} elements, each which represents a location of an item
+ * that is only valid for a certain range of program-counter locations.
+ */
+public class DWARFLocationList {
+ public static final DWARFLocationList EMPTY = new DWARFLocationList(List.of());
+
+ /**
+ * Creates a simple location list containing a single wildcarded range and the specified
+ * expression bytes.
+ *
+ * @param expr {@link DWARFExpression} bytes
+ * @return new {@link DWARFLocationList} containing a single wildcarded range
+ */
+ public static DWARFLocationList withWildcardRange(byte[] expr) {
+ return new DWARFLocationList(List.of(new DWARFLocation(null, expr)));
+ }
+
+ /**
+ * Read a v4 {@link DWARFLocationList} from the debug_loc section.
+ *
+ * @param reader stream positioned at the start of a .debug_loc location list
+ * @param cu the compUnit that refers to the location list
+ * @return list of DWARF locations (address range and location expression)
+ * @throws IOException if an I/O error occurs
+ */
+ public static DWARFLocationList readV4(BinaryReader reader, DWARFCompilationUnit cu)
+ throws IOException {
+ List results = new ArrayList<>();
+
+ byte pointerSize = cu.getPointerSize();
+
+ DWARFRange cuRange = cu.getPCRange();
+ long baseAddrOffset = (cuRange != null) ? cuRange.getFrom() : 0;
+ long baseFixup = cu.getProgram().getProgramBaseAddressFixup();
+ long eolVal = pointerSize == 4 ? NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG : -1;
+
+ // Loop through the debug_loc entry
+ while (reader.hasNext()) {
+ long beginning = reader.readNextUnsignedValue(pointerSize);
+ long ending = reader.readNextUnsignedValue(pointerSize);
+
+ if (beginning == 0 && ending == 0) {
+ // List end
+ break;
+ }
+ else if (beginning == ending) {
+ // don't add empty range
+ continue;
+ }
+
+ // Check to see if this is a base address entry
+ if (beginning == eolVal) {
+ baseAddrOffset = ending + baseFixup;
+ }
+ else {
+ beginning += baseAddrOffset;
+ ending += baseAddrOffset;
+
+ // byte array size is 2 bytes
+ int size = reader.readNextUnsignedShort();
+
+ // Read the exprloc bytes
+ byte[] expr = reader.readNextByteArray(size);
+
+ // TODO: verify end addr calc with DWARFstd.pdf, inclusive vs exclusive
+ results.add(new DWARFLocation(new DWARFRange(beginning, ending), expr));
+ }
+ }
+ return new DWARFLocationList(results);
+ }
+
+ /**
+ * Reads a v5 {@link DWARFLocationList} from the debug_loclists stream.
+ *
+ * @param reader stream positioned at the start of a .debug_loclists location list
+ * @param cu the compUnit that refers to the location list
+ * @return list of DWARF locations (address range and location expression)
+ * @throws IOException if an I/O error occurs
+ */
+ public static DWARFLocationList readV5(BinaryReader reader, DWARFCompilationUnit cu)
+ throws IOException {
+ long baseAddrFixup = cu.getProgram().getProgramBaseAddressFixup();
+ long baseAddr = baseAddrFixup;
+ DWARFProgram dprog = cu.getProgram();
+
+ List list = new ArrayList<>();
+ while (reader.hasNext()) {
+ int lleId = reader.readNextUnsignedByte();
+ if (lleId == DW_LLE_end_of_list) {
+ break;
+ }
+ switch (lleId) {
+ case DW_LLE_base_addressx: {
+ int addrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ baseAddr = dprog.getAddress(DW_FORM_addrx, addrIndex, cu);
+ break;
+ }
+ case DW_LLE_startx_endx: {
+ int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int endAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray);
+ long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu);
+ long end = dprog.getAddress(DW_FORM_addrx, endAddrIndex, cu);
+ list.add(new DWARFLocation(start, end, expr));
+ break;
+ }
+ case DW_LLE_startx_length: {
+ int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray);
+ long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu);
+ list.add(new DWARFLocation(start, start + len, expr));
+ break;
+ }
+ case DW_LLE_offset_pair: {
+ int startOfs = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int endOfs = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray);
+ list.add(new DWARFLocation(baseAddr + startOfs, baseAddr + endOfs, expr));
+ break;
+ }
+ case DW_LLE_base_address: {
+ baseAddr = reader.readNextUnsignedValue(cu.getPointerSize()) + baseAddrFixup;
+ break;
+ }
+ case DW_LLE_start_end: {
+ long startAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ long endAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray);
+ list.add(new DWARFLocation(startAddr + baseAddrFixup, endAddr + baseAddrFixup,
+ expr));
+ break;
+ }
+ case DW_LLE_start_length: {
+ long startAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray);
+ list.add(new DWARFLocation(startAddr + baseAddrFixup,
+ startAddr + baseAddrFixup + len, expr));
+ break;
+ }
+ default:
+ throw new IOException(
+ "Unsupported DWARF Location List Entry type: %d".formatted(lleId));
+ }
+ }
+ return new DWARFLocationList(list);
+ }
+
+ private List list;
+
+ public DWARFLocationList(List list) {
+ this.list = list;
+ }
+
+ public boolean isEmpty() {
+ return list.isEmpty();
+ }
+
+ /**
+ * Get the location that corresponds to the specified PC location.
+ *
+ * @param pc programcounter address
+ * @return the byte array corresponding to the location expression
+ */
+ public DWARFLocation getLocationContaining(long pc) {
+ for (DWARFLocation loc : list) {
+ if (loc.contains(pc)) {
+ return loc;
+ }
+ }
+ return null;
+ }
+
+ public DWARFLocation getFirstLocation() {
+ return !list.isEmpty() ? list.get(0) : null;
+ }
+
+ @Override
+ public String toString() {
+ return "DWARFLocationList: " + list;
+ }
+
+ /**
+ * Reader func that reads a uleb128-length prefixed byte array.
+ *
+ * @param reader {@link BinaryReader} stream
+ * @return byte array, length specified by the leading leb128 value
+ * @throws IOException if error reading
+ */
+ private static byte[] uleb128SizedByteArray(BinaryReader reader) throws IOException {
+ int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ if (len > DWARFExpression.MAX_SANE_EXPR) {
+ throw new IOException("Invalid DWARF exprloc size: %d".formatted(len));
+ }
+ return reader.readNextByteArray(len);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListEntry.java
new file mode 100644
index 0000000000..9ca3585bfa
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListEntry.java
@@ -0,0 +1,34 @@
+/* ###
+ * 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.dwarf;
+
+public class DWARFLocationListEntry {
+
+ public static final int DW_LLE_end_of_list = 0x00;
+ public static final int DW_LLE_base_addressx = 0x01;
+ public static final int DW_LLE_startx_endx = 0x02;
+ public static final int DW_LLE_startx_length = 0x03;
+ public static final int DW_LLE_offset_pair = 0x04;
+ public static final int DW_LLE_default_location = 0x05;
+ public static final int DW_LLE_base_address = 0x06;
+ public static final int DW_LLE_start_end = 0x07;
+ public static final int DW_LLE_start_length = 0x08;
+
+ public static String toString(long value) {
+ return DWARFUtil.toString(DWARFLocationListEntry.class, value);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java
new file mode 100644
index 0000000000..b14969d9d5
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java
@@ -0,0 +1,88 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames;
+
+/**
+ * Header found at the start of a set of DWARFLocationList entries, which are stored sequentially
+ * in the {@link DWARFSectionNames#DEBUG_LOCLISTS .debug_loclists} section.
+ */
+public class DWARFLocationListHeader extends DWARFIndirectTableHeader {
+
+ public static DWARFLocationListHeader read(BinaryReader reader, int defaultIntSize)
+ throws IOException {
+ // length : dwarf_length
+ // version : 2 bytes
+ // address_size : 1 byte
+ // segment_selector_size : 1 byte
+ // offset entry count: 4 bytes
+ // offsets : array of elements are are dwarf_format_int sized
+
+ long startOffset = reader.getPointerIndex();
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, defaultIntSize);
+ if (lengthInfo == null) {
+ return null;
+ }
+
+ long endOffset = reader.getPointerIndex() + lengthInfo.length();
+ short version = reader.readNextShort();
+ if (version < 5) {
+ throw new DWARFException(
+ "DWARFLocationListHeader (0x%x): unsupported DWARF version [%d]"
+ .formatted(startOffset, version));
+ }
+ int addressSize = reader.readNextUnsignedByte();
+ int segmentSelectorSize = reader.readNextUnsignedByte();
+ int offsetEntryCount = reader.readNextUnsignedIntExact();
+ long offsetListPosition = reader.getPointerIndex();
+
+ reader.setPointerIndex(endOffset);
+ if (segmentSelectorSize != 0) {
+ throw new IOException("Unsupported segmentSelectorSize: " + segmentSelectorSize);
+ }
+
+ return new DWARFLocationListHeader(startOffset, endOffset, offsetListPosition,
+ lengthInfo.intSize(), offsetEntryCount, addressSize, segmentSelectorSize);
+ }
+
+ private final int offsetEntryCount;
+ private final int offsetIntSize;
+ private final int addressSize;
+ private final int segmentSelectorSize;
+
+ public DWARFLocationListHeader(long startOffset, long endOffset, long firstElementOffset,
+ int offsetIntSize, int offsetEntryCount, int addressSize, int segmentSelectorSize) {
+ super(startOffset, endOffset, firstElementOffset);
+ this.offsetIntSize = offsetIntSize;
+ this.offsetEntryCount = offsetEntryCount;
+ this.addressSize = addressSize;
+ this.segmentSelectorSize = segmentSelectorSize;
+ }
+
+ @Override
+ public long getOffset(int index, BinaryReader reader) throws IOException {
+ if (index < 0 || index >= offsetEntryCount) {
+ throw new IOException("Invalid location list index: " + index);
+ }
+ return firstElementOffset +
+ reader.readUnsignedValue(firstElementOffset + (index * offsetIntSize), offsetIntSize);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFName.java
similarity index 81%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfo.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFName.java
index c79e199844..92cd579305 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFName.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.util.List;
import java.util.Objects;
@@ -28,9 +28,9 @@ import ghidra.program.model.symbol.SymbolType;
* {@link Namespace namespaces} or {@link CategoryPath categorypaths}.
*
*/
-public class DWARFNameInfo {
+public class DWARFName {
- private final DWARFNameInfo parent;
+ private final DWARFName parent;
private final CategoryPath organizationalCategoryPath;
private final NamespacePath namespacePath;
private final String originalName;
@@ -40,42 +40,42 @@ public class DWARFNameInfo {
*
* @param rootCategory {@link CategoryPath} in the data type manager that will contain
* any sub-categories that represent namespaces
- * @return a new {@link DWARFNameInfo} instance
+ * @return a new {@link DWARFName} instance
*/
- public static DWARFNameInfo createRoot(CategoryPath rootCategory) {
- return new DWARFNameInfo(null, rootCategory, NamespacePath.ROOT, null);
+ public static DWARFName createRoot(CategoryPath rootCategory) {
+ return new DWARFName(null, rootCategory, NamespacePath.ROOT, null);
}
/**
- * Create a {@link DWARFNameInfo} instance using the specified {@link DataType}'s name.
+ * Create a {@link DWARFName} instance using the specified {@link DataType}'s name.
*
* @param dataType {@link DataType}
- * @return new {@link DWARFNameInfo} using the same name / CategoryPath as the data type
+ * @return new {@link DWARFName} using the same name / CategoryPath as the data type
*/
- public static DWARFNameInfo fromDataType(DataType dataType) {
- return new DWARFNameInfo(null, dataType.getCategoryPath(),
+ public static DWARFName fromDataType(DataType dataType) {
+ return new DWARFName(null, dataType.getCategoryPath(),
NamespacePath.create(null, dataType.getName(), null), dataType.getName());
}
/**
- * Create a child {@link DWARFNameInfo} instance of the specified parent.
+ * Create a child {@link DWARFName} instance of the specified parent.
*
* Example:
*
fromList(parent, List.of("name1", "name2")) → parent_name/name1/name2
*
- * @param parent {@link DWARFNameInfo} parent
+ * @param parent {@link DWARFName} parent
* @param names list of names
- * @return new {@link DWARFNameInfo} instance that is a child of the parent
+ * @return new {@link DWARFName} instance that is a child of the parent
*/
- public static DWARFNameInfo fromList(DWARFNameInfo parent, List names) {
+ public static DWARFName fromList(DWARFName parent, List names) {
for (String s : names) {
- DWARFNameInfo tmp = new DWARFNameInfo(parent, s, s, SymbolType.NAMESPACE);
+ DWARFName tmp = new DWARFName(parent, s, s, SymbolType.NAMESPACE);
parent = tmp;
}
return parent;
}
- private DWARFNameInfo(DWARFNameInfo parent, CategoryPath organizationalCategoryPath,
+ private DWARFName(DWARFName parent, CategoryPath organizationalCategoryPath,
NamespacePath namespacePath, String originalName) {
this.parent = parent;
this.organizationalCategoryPath =
@@ -84,7 +84,7 @@ public class DWARFNameInfo {
this.originalName = originalName;
}
- private DWARFNameInfo(DWARFNameInfo parent, String originalName, String name, SymbolType type) {
+ private DWARFName(DWARFName parent, String originalName, String name, SymbolType type) {
this.parent = parent;
this.organizationalCategoryPath = parent.getOrganizationalCategoryPath();
this.namespacePath = NamespacePath.create(parent.getNamespacePath(), name, type);
@@ -96,7 +96,7 @@ public class DWARFNameInfo {
*
* @return parent
*/
- public DWARFNameInfo getParent() {
+ public DWARFName getParent() {
return parent;
}
@@ -154,8 +154,8 @@ public class DWARFNameInfo {
* @param newOriginalName originalName for the new instance
* @return new instance with new name
*/
- public DWARFNameInfo replaceName(String newName, String newOriginalName) {
- return new DWARFNameInfo(getParent(), newOriginalName, newName, getType());
+ public DWARFName replaceName(String newName, String newOriginalName) {
+ return new DWARFName(getParent(), newOriginalName, newName, getType());
}
/**
@@ -165,8 +165,8 @@ public class DWARFNameInfo {
* @param newType new SymbolType value
* @return new instance with the specified SymbolType
*/
- public DWARFNameInfo replaceType(SymbolType newType) {
- return new DWARFNameInfo(parent, originalName, getName(), newType);
+ public DWARFName replaceType(SymbolType newType) {
+ return new DWARFName(parent, originalName, getName(), newType);
}
/**
@@ -255,7 +255,7 @@ public class DWARFNameInfo {
}
/**
- * Creates a {@link DWARFNameInfo} instance, which has a name that is contained with
+ * Creates a {@link DWARFName} instance, which has a name that is contained with
* this instance's namespace, using the specified name and symbol type.
*
* @param childOriginalName the unmodified name
@@ -263,9 +263,9 @@ public class DWARFNameInfo {
* @param childType the type of the object being named
* @return new DWARFNameInfo instance
*/
- public DWARFNameInfo createChild(String childOriginalName, String childName,
+ public DWARFName createChild(String childOriginalName, String childName,
SymbolType childType) {
- return new DWARFNameInfo(this, childOriginalName, childName, childType);
+ return new DWARFName(this, childOriginalName, childName, childType);
}
@Override
@@ -288,10 +288,10 @@ public class DWARFNameInfo {
if (obj == null) {
return false;
}
- if (!(obj instanceof DWARFNameInfo)) {
+ if (!(obj instanceof DWARFName)) {
return false;
}
- DWARFNameInfo other = (DWARFNameInfo) obj;
+ DWARFName other = (DWARFName) obj;
if (namespacePath == null) {
if (other.namespacePath != null) {
return false;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java
similarity index 63%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java
index b6e75efd58..1527933c22 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFProgram.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.*;
import java.util.*;
@@ -23,20 +26,17 @@ import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import ghidra.app.util.bin.*;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFAttributeFactory;
-import ghidra.app.util.bin.format.dwarf4.encoding.*;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
-import ghidra.app.util.bin.format.dwarf4.external.ExternalDebugInfo;
-import ghidra.app.util.bin.format.dwarf4.funcfixup.DWARFFunctionFixup;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.*;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
+import ghidra.app.util.bin.format.dwarf.external.ExternalDebugInfo;
+import ghidra.app.util.bin.format.dwarf.funcfixup.DWARFFunctionFixup;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.*;
import ghidra.app.util.bin.format.golang.rtti.GoSymbolName;
import ghidra.app.util.opinion.*;
import ghidra.formats.gfilesystem.FSUtilities;
-import ghidra.program.model.address.Address;
-import ghidra.program.model.address.AddressSpace;
+import ghidra.program.model.address.*;
import ghidra.program.model.data.CategoryPath;
-import ghidra.program.model.listing.Program;
+import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.util.Msg;
import ghidra.util.datastruct.*;
@@ -53,8 +53,11 @@ public class DWARFProgram implements Closeable {
public static final CategoryPath DWARF_ROOT_CATPATH = CategoryPath.ROOT.extend(DWARF_ROOT_NAME);
public static final CategoryPath UNCAT_CATPATH = DWARF_ROOT_CATPATH.extend("_UNCATEGORIZED_");
+ private static final String DWARF_BOOKMARK_CAT = "DWARF";
private static final int NAME_HASH_REPLACEMENT_SIZE = 8 + 2 + 2;
private static final String ELLIPSES_STR = "...";
+ protected static final EnumSet REF_ATTRS =
+ EnumSet.of(DW_AT_abstract_origin, DW_AT_specification);
/**
* Returns true if the {@link Program program} probably has DWARF information, without doing
@@ -118,38 +121,43 @@ public class DWARFProgram implements Closeable {
private final Program program;
private final DWARFDataTypeManager dwarfDTM;
- private DWARFNameInfo rootDNI = DWARFNameInfo.createRoot(DWARF_ROOT_CATPATH);
- private DWARFNameInfo unCatDataTypeRoot = DWARFNameInfo.createRoot(UNCAT_CATPATH);
+ private DWARFName rootDNI = DWARFName.createRoot(DWARF_ROOT_CATPATH);
+ private DWARFName unCatDataTypeRoot = DWARFName.createRoot(UNCAT_CATPATH);
private DWARFImportOptions importOptions;
- private DWARFImportSummary importSummary;
+ private DWARFImportSummary importSummary = new DWARFImportSummary();
private DWARFSectionProvider sectionProvider;
private StringTable debugStrings;
- private DWARFAttributeFactory attributeFactory;
+ private StringTable lineStrings;
private int totalAggregateCount;
private long programBaseAddressFixup;
private int maxDNICacheSize = 50;
- private FixedSizeHashMap dniCache =
+ private FixedSizeHashMap dniCache =
new FixedSizeHashMap<>(100, maxDNICacheSize);
- private Map attributeSpecIntern =
+ private Map attributeSpecIntern =
new HashMap<>();
private DWARFRegisterMappings dwarfRegisterMappings;
private final boolean stackGrowsNegative;
private List functionFixups;
+
+ // BinaryReaders for each of the various dwarf sections
private BinaryReader debugLocation;
+ private BinaryReader debugLocLists; // v5+
private BinaryReader debugRanges;
+ private BinaryReader debugRngLists; // v5+
private BinaryReader debugInfoBR;
private BinaryReader debugLineBR;
private BinaryReader debugAbbrBR;
-
+ private BinaryReader debugAddr; // v5+
+ private BinaryReader debugStrOffsets; // v5+
// dieOffsets, siblingIndexes, parentIndexes contain for each DIE the information needed
// to read each DIE and to navigate to parent / child / sibling elements.
- // Each DIE record in the binary will consume 8+4+4=16 bytes in ram in these indexes.
+ // Each DIE record in the binary will consume 8+4+4=16 bytes of ram in these indexes.
// DIE instances do not keep references to other DIEs.
protected long[] dieOffsets = new long[0]; // offset in the debuginfo stream of this DIE
protected int[] siblingIndexes = new int[0]; // index of each DIE's next sibling.
@@ -161,6 +169,14 @@ public class DWARFProgram implements Closeable {
protected TreeMap compUnitDieIndex = new TreeMap<>();
protected List compUnits = new ArrayList<>();
+ // Indirect tables, added with dwarf v5, provide an index -> offset lookup feature for
+ // index values such as DW_FORM_addrx or DW_FORM_strx and other similar 'x' attribute values.
+ // Each DWARFIndirectTable is made of per-CU lookup arrays held in a DWARFIndirectTableHeader.
+ private DWARFIndirectTable addressListTable; // DWARFAddressListHeaders, DW_AT_addr_base
+ private DWARFIndirectTable locationListTable; // DWARFLocationListHeaders, DW_AT_rgnlists_base
+ private DWARFIndirectTable rangeListTable; // DWARFRangeListHeaders, DW_AT_rgnlists_base
+ private DWARFIndirectTable stringsOffsetTable; // DWARFStringOffsetTableHeader, DW_AT_str_offsets_base
+
// boolean flag, per die record, indicating that the DIE is the target of another DIE via
// an aggregate reference, and therefore not the root DIE record of an aggregate.
protected BitSet indexHasRef = new BitSet();
@@ -173,7 +189,7 @@ public class DWARFProgram implements Closeable {
// Map of DIE offsets of {@link DIEAggregate}s that are being pointed to by
// other {@link DIEAggregate}s with a DW_AT_type property.
// In other words, a map of inbound links to a DIEA.
- private ListValuedMap typeReferers = new ArrayListValuedHashMap<>();
+ private ListValuedMap typeReferers = new ArrayListValuedHashMap<>();
/**
* Main constructor for DWARFProgram.
@@ -214,16 +230,35 @@ public class DWARFProgram implements Closeable {
this.program = program;
this.sectionProvider = sectionProvider;
this.importOptions = importOptions;
- this.importSummary = new DWARFImportSummary();
this.dwarfDTM = new DWARFDataTypeManager(this, program.getDataTypeManager());
this.stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative();
- this.attributeFactory = new DWARFAttributeFactory(this);
+
+ this.debugInfoBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_INFO, monitor);
+ this.debugAbbrBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_ABBREV, monitor);
this.debugLocation = getBinaryReaderFor(DWARFSectionNames.DEBUG_LOC, monitor);
- this.debugInfoBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_INFO, monitor);
- this.debugLineBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_LINE, monitor);
- this.debugAbbrBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_ABBREV, monitor);
+ this.debugLocLists = getBinaryReaderFor(DWARFSectionNames.DEBUG_LOCLISTS, monitor);
+
this.debugRanges = getBinaryReaderFor(DWARFSectionNames.DEBUG_RANGES, monitor);
+ this.debugRngLists = getBinaryReaderFor(DWARFSectionNames.DEBUG_RNGLISTS, monitor);
+
+ this.debugLineBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_LINE, monitor);
+ this.debugAddr = getBinaryReaderFor(DWARFSectionNames.DEBUG_ADDR, monitor);
+ this.debugStrOffsets = getBinaryReaderFor(DWARFSectionNames.DEBUG_STROFFSETS, monitor);
+
+ this.rangeListTable =
+ new DWARFIndirectTable(this.debugRngLists, DWARFCompilationUnit::getRangeListsBase);
+ this.addressListTable =
+ new DWARFIndirectTable(this.debugAddr, DWARFCompilationUnit::getAddrTableBase);
+ this.stringsOffsetTable =
+ new DWARFIndirectTable(this.debugStrOffsets, DWARFCompilationUnit::getStrOffsetsBase);
+ this.locationListTable =
+ new DWARFIndirectTable(this.debugLocLists, DWARFCompilationUnit::getLocListsBase);
+
+ this.debugStrings =
+ StringTable.of(getBinaryReaderFor(DWARFSectionNames.DEBUG_STR, monitor));
+ this.lineStrings =
+ StringTable.of(getBinaryReaderFor(DWARFSectionNames.DEBUG_LINE_STR, monitor));
// if there are relocations (already handled by the ghidra loader) anywhere in the
// debuginfo or debugrange sections, then we don't need to manually fix up addresses
@@ -251,12 +286,53 @@ public class DWARFProgram implements Closeable {
* @throws CancelledException if cancelled
*/
public void init(TaskMonitor monitor) throws IOException, DWARFException, CancelledException {
- monitor.setMessage("DWARF: Reading string table");
- this.debugStrings = StringTable.readStringTable(
- sectionProvider.getSectionAsByteProvider(DWARFSectionNames.DEBUG_STR, monitor));
-
bootstrapCompilationUnits(monitor);
+ int defaultIntSize = getDefaultIntSize();
+ rangeListTable.bootstrap("DWARF: Bootstrapping Range Lists",
+ reader -> DWARFRangeListHeader.read(reader, defaultIntSize), monitor);
+ locationListTable.bootstrap("DWARF: Bootstrapping Location Lists",
+ reader -> DWARFLocationListHeader.read(reader, defaultIntSize), monitor);
+ addressListTable.bootstrap("DWARF: Bootstrapping Address Lists",
+ reader -> DWARFAddressListHeader.read(reader, defaultIntSize), monitor);
+ stringsOffsetTable.bootstrap("DWARF: Bootstrapping String Offset Lists",
+ reader -> DWARFStringOffsetTableHeader.readV5(reader, defaultIntSize), monitor);
+
+ indexDIEs(monitor);
+ indexDIEATypeRefs(monitor);
+
+ importSummary.addCompunitInfo(compUnits);
+ }
+
+ private void bootstrapCompilationUnits(TaskMonitor monitor)
+ throws CancelledException, IOException, DWARFException {
+
+ debugInfoBR.setPointerIndex(0);
+ monitor.initialize(debugInfoBR.length(), "DWARF: Bootstrapping Compilation Units");
+ while (debugInfoBR.hasNext()) {
+ monitor.checkCancelled();
+ monitor.setProgress(debugInfoBR.getPointerIndex());
+ monitor.setMessage("DWARF: Bootstrapping Compilation Unit #" + compUnits.size());
+
+ DWARFUnitHeader unitHeader =
+ DWARFUnitHeader.read(this, debugInfoBR, debugAbbrBR, compUnits.size(), monitor);
+ if (unitHeader != null) {
+ debugInfoBR.setPointerIndex(unitHeader.getEndOffset());
+ }
+
+ if (unitHeader instanceof DWARFCompilationUnit cu) {
+ compUnits.add(cu);
+ importSummary.dwarfVers.add((int) cu.getDWARFVersion());
+ }
+ else {
+ Msg.info(this, "Unsupported unit header: " + unitHeader + " at " +
+ unitHeader.getStartOffset());
+ }
+ }
+ importSummary.compUnitCount = compUnits.size();
+ }
+
+ private void indexDIEs(TaskMonitor monitor) throws CancelledException, IOException {
LongArrayList dieOffsetList = new LongArrayList();
IntArrayList siblingIndexList = new IntArrayList();
IntArrayList parentIndexList = new IntArrayList();
@@ -266,8 +342,9 @@ public class DWARFProgram implements Closeable {
for (DWARFCompilationUnit cu : compUnits) {
debugInfoBR.setPointerIndex(cu.getFirstDIEOffset());
monitor.setMessage("DWARF: Indexing records - Compilation Unit #%d/%d"
- .formatted(cu.getCompUnitNumber() + 1, compUnits.size()));
- indexDIEsForCU(cu, dieOffsetList, parentIndexList, siblingIndexList, aggrTargets, monitor);
+ .formatted(cu.getUnitNumber() + 1, compUnits.size()));
+ indexDIEsForCU(cu, dieOffsetList, parentIndexList, siblingIndexList, aggrTargets,
+ monitor);
compUnitDieIndex.put(dieOffsetList.size() - 1, cu);
}
@@ -279,10 +356,7 @@ public class DWARFProgram implements Closeable {
int nonHeadCount = indexHasRef.cardinality();
totalAggregateCount = dieOffsetList.size() - nonHeadCount;
- indexDIEATypeRefs(monitor);
-
- Msg.info(this,
- "DWARF: %d compile units, %d DIEs".formatted(compUnits.size(), dieOffsets.length));
+ importSummary.dieCount = dieOffsets.length;
}
protected void indexDIEATypeRefs(TaskMonitor monitor) throws CancelledException {
@@ -291,7 +365,7 @@ public class DWARFProgram implements Closeable {
monitor.increment();
DIEAggregate typeRef = diea.getTypeRef();
if (typeRef != null) {
- typeReferers.put(typeRef.getOffset(), diea);
+ typeReferers.put(typeRef.getOffset(), diea.getOffset());
}
}
@@ -310,29 +384,9 @@ public class DWARFProgram implements Closeable {
}
}
- private void bootstrapCompilationUnits(TaskMonitor monitor)
- throws CancelledException, IOException, DWARFException {
-
- debugInfoBR.setPointerIndex(0);
- monitor.initialize(debugInfoBR.length(), "DWARF: Bootstrapping Compilation Units");
- while (debugInfoBR.hasNext()) {
- monitor.checkCancelled();
- monitor.setProgress(debugInfoBR.getPointerIndex());
- monitor.setMessage("DWARF: Bootstrapping Compilation Unit #" + compUnits.size());
-
- DWARFCompilationUnit cu = DWARFCompilationUnit.readCompilationUnit(this, debugInfoBR,
- debugAbbrBR, compUnits.size(), monitor);
-
- if (cu != null) {
- compUnits.add(cu);
- debugInfoBR.setPointerIndex(cu.getEndOffset());
- }
- }
- }
-
private void indexDIEsForCU(DWARFCompilationUnit cu, LongArrayList dieOffsetList,
- IntArrayList parentIndexList, IntArrayList siblingIndexList,
- LongArrayList aggrTargets, TaskMonitor monitor) throws CancelledException {
+ IntArrayList parentIndexList, IntArrayList siblingIndexList, LongArrayList aggrTargets,
+ TaskMonitor monitor) throws CancelledException {
long endOffset = cu.getEndOffset();
int perCuDieCount = 0;
@@ -347,8 +401,7 @@ public class DWARFProgram implements Closeable {
try {
int dieIndex = dieOffsetList.size();
- DebugInfoEntry die =
- DebugInfoEntry.read(debugInfoBR, cu, dieIndex, attributeFactory);
+ DebugInfoEntry die = DebugInfoEntry.read(debugInfoBR, cu, dieIndex);
if (die.isTerminator()) {
if (parentIndex == -1) {
@@ -379,8 +432,12 @@ public class DWARFProgram implements Closeable {
parentIndex = dieIndex;
}
+ if (die.getOffset() == cu.getFirstDIEOffset()) {
+ cu.init(die);
+ }
+
DIEAggregate diea = DIEAggregate.createSingle(die);
- for (int attr : DIEAggregate.REF_ATTRS) {
+ for (DWARFAttribute attr : REF_ATTRS) {
long refdOffset = diea.getUnsignedLong(attr, -1);
if (refdOffset != -1) {
aggrTargets.add(refdOffset);
@@ -392,7 +449,7 @@ public class DWARFProgram implements Closeable {
catch (IOException e) {
Msg.error(this,
"Failed to read DIE at offset 0x%x in compunit %d (at 0x%x), skipping remainder of compilation unit."
- .formatted(startOfDIE, cu.getCompUnitNumber(), cu.getStartOffset()),
+ .formatted(startOfDIE, cu.getUnitNumber(), cu.getStartOffset()),
e);
debugInfoBR.setPointerIndex(endOffset);
}
@@ -416,6 +473,11 @@ public class DWARFProgram implements Closeable {
}
if (debugStrings != null) {
debugStrings.clear();
+ debugStrings = null;
+ }
+ if (lineStrings != null) {
+ lineStrings.clear();
+ lineStrings = null;
}
compUnits.clear();
dniCache.clear();
@@ -424,7 +486,10 @@ public class DWARFProgram implements Closeable {
debugInfoBR = null;
debugLineBR = null;
debugLocation = null;
+ debugLocLists = null;
debugRanges = null;
+ debugRngLists = null;
+ debugAddr = null;
dieOffsets = new long[0];
parentIndexes = new int[0];
@@ -435,6 +500,11 @@ public class DWARFProgram implements Closeable {
typeReferers.clear();
compUnitDieIndex.clear();
+ locationListTable.clear();
+ rangeListTable.clear();
+ stringsOffsetTable.clear();
+ addressListTable.clear();
+
if (functionFixups != null) {
for (DWARFFunctionFixup funcFixup : functionFixups) {
if (funcFixup instanceof Closeable c) {
@@ -494,12 +564,12 @@ public class DWARFProgram implements Closeable {
}
public String getEntryName(DIEAggregate diea) {
- String name = diea.getString(DWARFAttribute.DW_AT_name, null);
+ String name = diea.getString(DW_AT_name, null);
if (name == null) {
- String linkageName = diea.getString(DWARFAttribute.DW_AT_linkage_name, null);
+ String linkageName = diea.getString(DW_AT_linkage_name, null);
if (linkageName == null) {
- linkageName = diea.getString(DWARFAttribute.DW_AT_MIPS_linkage_name, null);
+ linkageName = diea.getString(DW_AT_MIPS_linkage_name, null);
}
name = linkageName;
}
@@ -513,21 +583,22 @@ public class DWARFProgram implements Closeable {
* Always returns a name for the passed-in entry, but you should probably only use this
* for entries that are {@link DIEAggregate#isNamedType()}
*/
- private DWARFNameInfo getDWARFNameInfo(DIEAggregate diea, DWARFNameInfo localRootDNI) {
+ private DWARFName getDWARFName(DIEAggregate diea, DWARFName localRootDNI) {
- DWARFNameInfo parentDNI = localRootDNI;
+ DWARFName parentDNI = localRootDNI;
DIEAggregate declParent = diea.getDeclParent();
- if ((declParent != null) && declParent.getTag() != DWARFTag.DW_TAG_compile_unit) {
+ if ((declParent != null) && declParent.getTag() != DW_TAG_compile_unit) {
parentDNI = lookupDNIByOffset(declParent.getOffset());
if (parentDNI == null) {
- parentDNI = getDWARFNameInfo(declParent, localRootDNI);
+ parentDNI = getDWARFName(declParent, localRootDNI);
if (parentDNI != null) {
cacheDNIByOffset(declParent.getOffset(), parentDNI);
}
}
}
+ DWARFTag tag = diea.getTag();
String name = getEntryName(diea);
// Mangled names can occur in linkage attributes or in the regular name attribute.
@@ -537,7 +608,7 @@ public class DWARFProgram implements Closeable {
if (!nestings.isEmpty()) {
name = nestings.remove(nestings.size() - 1);
if (parentDNI == localRootDNI && !nestings.isEmpty()) {
- parentDNI = DWARFNameInfo.fromList(localRootDNI, nestings);
+ parentDNI = DWARFName.fromList(localRootDNI, nestings);
}
}
}
@@ -548,26 +619,25 @@ public class DWARFProgram implements Closeable {
List nestings = DWARFUtil.findLinkageNameInChildren(diea.getHeadFragment());
if (!nestings.isEmpty()) {
nestings.remove(nestings.size() - 1);
- parentDNI = DWARFNameInfo.fromList(localRootDNI, nestings);
+ parentDNI = DWARFName.fromList(localRootDNI, nestings);
}
}
if (name == null) {
- // check to see if there is a single inbound typedef that we can
- // steal its name.
- DIEAggregate referringTypedef = DWARFUtil.getReferringTypedef(diea);
- if (referringTypedef != null) {
- return getDWARFNameInfo(referringTypedef, localRootDNI);
+ // check to see if there is a single inbound typedef that we can steal its name.
+ List referers = getTypeReferers(diea, DW_TAG_typedef);
+ if (referers.size() == 1) {
+ return getDWARFName(referers.get(0), localRootDNI);
}
}
- if (name == null && diea.isStructureType()) {
+ if (name == null && tag.isStructureType()) {
String fingerprint = DWARFUtil.getStructLayoutFingerprint(diea);
// check to see if there are struct member defs that ref this anon type
// and build a name using the field names
List referringMembers =
- diea.getProgram().getTypeReferers(diea, DWARFTag.DW_TAG_member);
+ diea.getProgram().getTypeReferers(diea, DW_TAG_member);
String referringMemberNames = getReferringMemberFieldNames(referringMembers);
if (!referringMemberNames.isEmpty()) {
@@ -576,40 +646,38 @@ public class DWARFProgram implements Closeable {
parentDNI = getName(referringMembers.get(0).getParent());
referringMemberNames = "_for_" + referringMemberNames;
}
- name =
- "anon_" + DWARFUtil.getContainerTypeName(diea) + "_" + fingerprint +
- referringMemberNames;
- return parentDNI.createChild(null, name, DWARFUtil.getSymbolTypeFromDIE(diea));
+ name = "anon_" + tag.getContainerTypeName() + "_" + fingerprint + referringMemberNames;
+ return parentDNI.createChild(null, name, tag.getSymbolType());
}
boolean isAnon = false;
if (name == null) {
switch (diea.getTag()) {
- case DWARFTag.DW_TAG_base_type:
+ case DW_TAG_base_type:
name = getAnonBaseTypeName(diea);
isAnon = true;
break;
- case DWARFTag.DW_TAG_enumeration_type:
+ case DW_TAG_enumeration_type:
name = getAnonEnumName(diea);
isAnon = true;
break;
- case DWARFTag.DW_TAG_subroutine_type:
+ case DW_TAG_subroutine_type:
// unnamed subroutines (C func ptrs)
// See {@link #isAnonSubroutine(DataType)}
name = "anon_subr";
isAnon = true;
break;
- case DWARFTag.DW_TAG_lexical_block:
- name = DWARFUtil.getLexicalBlockName(diea);
+ case DW_TAG_lexical_block: // "lexical_block_1_2_3"
+ name = "lexical_block" + getLexicalBlockNameWorker(diea.getHeadFragment());
break;
- case DWARFTag.DW_TAG_formal_parameter:
+ case DW_TAG_formal_parameter:
name = "param_%d".formatted(diea.getHeadFragment().getPositionInParent());
isAnon = true;
break;
- case DWARFTag.DW_TAG_subprogram:
- case DWARFTag.DW_TAG_inlined_subroutine:
- if (declParent != null && declParent.isStructureType() &&
- diea.getBool(DWARFAttribute.DW_AT_artificial, false)) {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ if (declParent != null && declParent.getTag().isStructureType() &&
+ diea.getBool(DW_AT_artificial, false)) {
name = parentDNI.getName();
}
else {
@@ -618,7 +686,7 @@ public class DWARFProgram implements Closeable {
}
break;
default:
- if (declParent != null && declParent.isNameSpaceContainer()) {
+ if (declParent != null && declParent.getTag().isNameSpaceContainer()) {
name = DWARFUtil.getAnonNameForMeFromParentContext2(diea);
}
break;
@@ -627,7 +695,7 @@ public class DWARFProgram implements Closeable {
// Name was not found
if (isAnonDWARFName(name)) {
- name = createAnonName("anon_" + DWARFUtil.getContainerTypeName(diea), diea);
+ name = createAnonName("anon_" + tag.getContainerTypeName(), diea);
isAnon = true;
}
@@ -635,23 +703,38 @@ public class DWARFProgram implements Closeable {
String workingName = ensureSafeNameLength(name);
workingName = GoSymbolName.fixGolangSpecialSymbolnameChars(workingName);
- if (diea.getCompilationUnit()
- .getCompileUnit()
- .getLanguage() == DWARFSourceLanguage.DW_LANG_Rust &&
+ if (diea.getCompilationUnit().getLanguage() == DWARFSourceLanguage.DW_LANG_Rust &&
workingName.startsWith("{impl#") && parentDNI != null) {
// if matches a Rust {impl#NN} name, skip it and re-use the parent name
return parentDNI;
}
- DWARFNameInfo result =
- parentDNI.createChild(origName, workingName, DWARFUtil.getSymbolTypeFromDIE(diea));
+ DWARFName result = parentDNI.createChild(origName, workingName, tag.getSymbolType());
return result;
}
+ /**
+ * Returns the {@link DIEAggregate} of a typedef that points to the specified datatype.
+ *
+ * Returns null if there is no typedef pointing to the specified DIEA or if there are
+ * multiple.
+ *
+ * @param diea {@link DIEAggregate} of a data type that might be the target of typedefs.
+ * @return {@link DIEAggregate} of the singular typedef that points to the arg, otherwise
+ * null if none or multiple found.
+ */
+ public static DIEAggregate getReferringTypedef(DIEAggregate diea) {
+ if (diea == null) {
+ return null;
+ }
+ List referers = diea.getProgram().getTypeReferers(diea, DW_TAG_typedef);
+ return (referers.size() == 1) ? referers.get(0) : null;
+ }
+
private String getAnonBaseTypeName(DIEAggregate diea) {
try {
- int dwarfSize = diea.parseInt(DWARFAttribute.DW_AT_byte_size, 0);
- int dwarfEncoding = (int) diea.getUnsignedLong(DWARFAttribute.DW_AT_encoding, -1);
+ int dwarfSize = diea.parseInt(DW_AT_byte_size, 0);
+ int dwarfEncoding = (int) diea.getUnsignedLong(DW_AT_encoding, -1);
return "anon_basetype_%s_%d".formatted(DWARFEncoding.getTypeName(dwarfEncoding),
dwarfSize);
}
@@ -661,7 +744,7 @@ public class DWARFProgram implements Closeable {
}
private String getAnonEnumName(DIEAggregate diea) {
- int enumSize = Math.max(1, (int) diea.getUnsignedLong(DWARFAttribute.DW_AT_byte_size, 1));
+ int enumSize = Math.max(1, (int) diea.getUnsignedLong(DW_AT_byte_size, 1));
return "anon_enum_%d".formatted(enumSize * 8);
}
@@ -669,6 +752,14 @@ public class DWARFProgram implements Closeable {
return "%s.dwarf_%x".formatted(baseName, diea.getOffset());
}
+ private static String getLexicalBlockNameWorker(DebugInfoEntry die) {
+ if (die.getTag() == DW_TAG_lexical_block || die.getTag() == DW_TAG_inlined_subroutine) {
+ return "%s_%d".formatted(getLexicalBlockNameWorker(die.getParent()),
+ die.getPositionInParent());
+ }
+ return "";
+ }
+
private String getReferringMemberFieldNames(List referringMembers) {
if (referringMembers == null || referringMembers.isEmpty()) {
return "";
@@ -687,7 +778,7 @@ public class DWARFProgram implements Closeable {
if (positionInParent == -1) {
continue;
}
- DWARFNameInfo parentDNI = getName(commonParent);
+ DWARFName parentDNI = getName(commonParent);
memberName = "%s_%d".formatted(parentDNI.getName(), positionInParent);
}
if (result.length() > 0) {
@@ -696,7 +787,7 @@ public class DWARFProgram implements Closeable {
result.append(memberName);
}
return result.toString();
- }
+ }
/**
* Transform a string with a C++ template-like syntax into a hopefully shorter version that
@@ -741,21 +832,27 @@ public class DWARFProgram implements Closeable {
return strs;
}
- public DWARFNameInfo getName(DIEAggregate diea) {
- DWARFNameInfo dni = lookupDNIByOffset(diea.getOffset());
+ /**
+ * Returns a {@link DWARFName} for a {@link DIEAggregate}.
+ *
+ * @param diea {@link DIEAggregate}
+ * @return {@link DWARFName}, never null
+ */
+ public DWARFName getName(DIEAggregate diea) {
+ DWARFName dni = lookupDNIByOffset(diea.getOffset());
if (dni == null) {
- dni = getDWARFNameInfo(diea, unCatDataTypeRoot);
+ dni = getDWARFName(diea, unCatDataTypeRoot);
cacheDNIByOffset(diea.getOffset(), dni);
}
return dni;
}
- private DWARFNameInfo lookupDNIByOffset(long offset) {
- DWARFNameInfo tmp = dniCache.get(offset);
+ private DWARFName lookupDNIByOffset(long offset) {
+ DWARFName tmp = dniCache.get(offset);
return tmp;
}
- private void cacheDNIByOffset(long offset, DWARFNameInfo dni) {
+ private void cacheDNIByOffset(long offset, DWARFName dni) {
dniCache.put(offset, dni);
}
@@ -864,7 +961,7 @@ public class DWARFProgram implements Closeable {
if (dieOffset < cu.getFirstDIEOffset() || cu.getEndOffset() < dieOffset) {
throw new RuntimeException();
}
- die = DebugInfoEntry.read(debugInfoBR, cu, dieIndex, attributeFactory);
+ die = DebugInfoEntry.read(debugInfoBR, cu, dieIndex);
diesByOffset.put(dieOffset, die);
}
catch (IOException e) {
@@ -884,8 +981,7 @@ public class DWARFProgram implements Closeable {
}
private DebugInfoEntry getDIEByIndex(int dieIndex) {
- long dieOffset =
- 0 <= dieIndex && dieIndex < dieOffsets.length ? dieOffsets[dieIndex] : -1;
+ long dieOffset = 0 <= dieIndex && dieIndex < dieOffsets.length ? dieOffsets[dieIndex] : -1;
return getDIEByOffset(dieOffset, dieIndex);
}
@@ -896,7 +992,6 @@ public class DWARFProgram implements Closeable {
}
}
-
/**
* Returns the {@link DIEAggregate} that contains the specified {@link DebugInfoEntry}.
*
@@ -935,6 +1030,223 @@ public class DWARFProgram implements Closeable {
return getAggregate(die);
}
+ /**
+ * Returns a DWARF attribute string value, as specified by a form, offset/index, and the cu.
+ *
+ * @param form {@link DWARFForm}
+ * @param offset offset or index of the value
+ * @param cu {@link DWARFCompilationUnit}
+ * @return String value, never null
+ * @throws IOException if invalid form or bad offset/index
+ */
+ public String getString(DWARFForm form, long offset, DWARFCompilationUnit cu)
+ throws IOException {
+ switch (form) {
+ case DW_FORM_line_strp:
+ return lineStrings.getStringAtOffset(offset);
+ case DW_FORM_strp:
+ return debugStrings.getStringAtOffset(offset);
+ case DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, DW_FORM_strx4:
+ long strOffset = stringsOffsetTable.getOffset((int) offset, cu);
+ return debugStrings.getStringAtOffset(strOffset);
+ default:
+ throw new IOException("Unsupported string form: " + form);
+ }
+ }
+
+ /**
+ * Returns the {@link DWARFRangeList} pointed at by the specified attribute.
+ *
+ * @param diea {@link DIEAggregate}
+ * @param attribute attribute id to find in the DIEA
+ * @return {@link DWARFRangeList}, or null if attribute is not present
+ * @throws IOException if error reading range list
+ */
+ public DWARFRangeList getRangeList(DIEAggregate diea, DWARFAttribute attribute)
+ throws IOException {
+
+ DWARFNumericAttribute rngListAttr =
+ diea.getAttribute(attribute, DWARFNumericAttribute.class);
+ if (rngListAttr == null) {
+ return null;
+ }
+
+ DWARFCompilationUnit cu = diea.getCompilationUnit();
+
+ switch (rngListAttr.getAttributeForm()) {
+ case DW_FORM_rnglistx: { // assumes v5
+ int index = rngListAttr.getUnsignedIntExact();
+ long rnglistOffset = rangeListTable.getOffset(index, cu);
+ debugRngLists.setPointerIndex(rnglistOffset);
+ return DWARFRangeList.readV5(debugRngLists, cu);
+ }
+ case DW_FORM_sec_offset: {
+ long rnglistOffset = rngListAttr.getValue();
+ short dwarfVersion = cu.getDWARFVersion();
+ if (dwarfVersion < 5) {
+ debugRanges.setPointerIndex(rnglistOffset);
+ return DWARFRangeList.readV4(debugRanges, cu);
+ }
+ else if (dwarfVersion == 5) {
+ debugRngLists.setPointerIndex(rnglistOffset);
+ return DWARFRangeList.readV5(debugRngLists, cu);
+ }
+ break;
+ }
+ default:
+ break; // fall thru to throw
+ }
+ throw new IOException("Unsupported attribute form " + rngListAttr);
+ }
+
+ /**
+ * Returns the raw offset of an indexed item. For DW_FORM_addrx values, the returned value
+ * is not fixed up with Ghidra load offset.
+ *
+ * @param form {@link DWARFForm} of the index
+ * @param index int index into a lookup table (see {@link #addressListTable},
+ * {@link #locationListTable}, {@link #rangeListTable}, {@link #stringsOffsetTable})
+ * @param cu {@link DWARFCompilationUnit}
+ * @return raw offset of indexed item
+ * @throws IOException if error reading index table
+ */
+ public long getOffsetOfIndexedElement(DWARFForm form, int index, DWARFCompilationUnit cu)
+ throws IOException {
+ DWARFIndirectTable table = switch (form) {
+ case DW_FORM_addrx:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4:
+ yield addressListTable;
+ case DW_FORM_rnglistx:
+ yield rangeListTable;
+ case DW_FORM_loclistx:
+ yield locationListTable;
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ yield stringsOffsetTable;
+ default:
+ yield null;
+ };
+ return table != null ? table.getOffset(index, cu) : -1;
+ }
+
+ /**
+ * Returns an address value, corrected for any Ghidra load offset shenanigans.
+ *
+ * @param form the format of the numeric value
+ * @param value raw offset or indirect address index (depending on the DWARFForm)
+ * @param cu {@link DWARFCompilationUnit}
+ * @return address
+ * @throws IOException if error reading indirect lookup tables
+ */
+ public long getAddress(DWARFForm form, long value, DWARFCompilationUnit cu) throws IOException {
+ switch (form) {
+ case DW_FORM_addr:
+ case DW_FORM_udata:
+ return value + programBaseAddressFixup;
+ case DW_FORM_addrx:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4: {
+ long addr = addressListTable.getOffset((int) value, cu);
+ return addr + programBaseAddressFixup;
+ }
+ default:
+ throw new IOException("Unsupported form %s".formatted(form));
+ }
+ }
+
+ /**
+ * Returns the {@link DWARFLocationList} pointed to by the specified attribute value.
+ *
+ * @param diea {@link DIEAggregate}
+ * @param attribute attribute id that points to the location list
+ * @return {@link DWARFLocationList}, never null
+ * @throws IOException if specified attribute is not the correct type, or if other error reading
+ * data
+ */
+ public DWARFLocationList getLocationList(DIEAggregate diea, DWARFAttribute attribute)
+ throws IOException {
+ DWARFAttributeValue attrib = diea.getAttribute(attribute);
+ if (attrib == null) {
+ return DWARFLocationList.EMPTY;
+ }
+ if (attrib instanceof DWARFNumericAttribute dnum) {
+ return readLocationList(dnum, diea.getCompilationUnit());
+ }
+ else if (attrib instanceof DWARFBlobAttribute dblob) {
+ return DWARFLocationList.withWildcardRange(dblob.getBytes());
+ }
+ else {
+ throw new IOException("Unsupported form %s.".formatted(attrib));
+ }
+
+ }
+
+ private DWARFLocationList readLocationList(DWARFNumericAttribute loclistAttr,
+ DWARFCompilationUnit cu) throws IOException {
+ switch (loclistAttr.getAttributeForm()) {
+ case DW_FORM_sec_offset:
+ int dwarfVer = cu.getDWARFVersion();
+ if (dwarfVer < 5) {
+ debugLocation.setPointerIndex(loclistAttr.getUnsignedValue());
+ return DWARFLocationList.readV4(debugLocation, cu);
+ }
+ else if (dwarfVer == 5) {
+ debugLocLists.setPointerIndex(loclistAttr.getUnsignedValue());
+ return DWARFLocationList.readV5(debugLocLists, cu);
+ }
+ break;
+ case DW_FORM_loclistx:
+ int index = loclistAttr.getUnsignedIntExact();
+ long locOffset = locationListTable.getOffset(index, cu);
+ debugLocLists.setPointerIndex(locOffset);
+ return DWARFLocationList.readV5(debugLocLists, cu);
+ default:
+ break; // fallthru to throw
+ }
+ throw new IOException(
+ "Unsupported loclist form %s".formatted(loclistAttr.getAttributeForm()));
+ }
+
+ /**
+ * Returns the DWARFLine info pointed to by the specified attribute.
+ *
+ * @param diea {@link DIEAggregate}
+ * @param attribute attribute id that points to the line info
+ * @return {@link DWARFLine}, or null if attribute
+ * @throws IOException if error reading line data
+ */
+ public DWARFLine getLine(DIEAggregate diea, DWARFAttribute attribute) throws IOException {
+ DWARFNumericAttribute attrib = diea.getAttribute(attribute, DWARFNumericAttribute.class);
+ if (attrib == null || debugLineBR == null) {
+ return null;
+ }
+ long stmtListOffset = attrib.getUnsignedValue();
+ debugLineBR.setPointerIndex(stmtListOffset);
+
+ // probe for the DWARFLine version number
+ // length : dwarf_length
+ // version : 2 bytes
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(debugLineBR, getDefaultIntSize());
+ if (lengthInfo == null) {
+ throw new DWARFException("Invalid DWARFLine length at 0x%x".formatted(stmtListOffset));
+ }
+
+ int version = debugLineBR.readNextUnsignedShort();
+
+ return version < 5
+ ? DWARFLine.readV4(this, debugLineBR, lengthInfo, version)
+ : DWARFLine.readV5(this, debugLineBR, lengthInfo, version,
+ diea.getCompilationUnit());
+ }
+
/**
* Returns iterable that traverses all {@link DIEAggregate}s in the program.
*
@@ -953,52 +1265,28 @@ public class DWARFProgram implements Closeable {
return totalAggregateCount;
}
- public BinaryReader getDebugLocation() {
- return debugLocation;
- }
-
- public BinaryReader getDebugRanges() {
- return debugRanges;
- }
-
- public BinaryReader getDebugLine() {
- return debugLineBR;
+ public BinaryReader getReaderForCompUnit(DWARFCompilationUnit cu) {
+ return debugInfoBR;
}
public DWARFRegisterMappings getRegisterMappings() {
return dwarfRegisterMappings;
}
- public DWARFNameInfo getRootDNI() {
+ public DWARFName getRootDNI() {
return rootDNI;
}
- public DWARFNameInfo getUncategorizedRootDNI() {
+ public DWARFName getUncategorizedRootDNI() {
return unCatDataTypeRoot;
}
- public StringTable getDebugStrings() {
- return debugStrings;
- }
-
- public void setDebugStrings(StringTable debugStrings) {
- this.debugStrings = debugStrings;
- }
-
public AddressSpace getStackSpace() {
return program.getAddressFactory().getStackSpace();
}
- public DWARFAttributeFactory getAttributeFactory() {
- return attributeFactory;
- }
-
- public void setAttributeFactory(DWARFAttributeFactory attributeFactory) {
- this.attributeFactory = attributeFactory;
- }
-
- public DWARFAttributeSpecification internAttributeSpec(DWARFAttributeSpecification das) {
- DWARFAttributeSpecification inDAS = attributeSpecIntern.get(das);
+ public DWARFAttribute.AttrDef internAttributeSpec(DWARFAttribute.AttrDef das) {
+ DWARFAttribute.AttrDef inDAS = attributeSpecIntern.get(das);
if (inDAS == null) {
inDAS = das;
attributeSpecIntern.put(inDAS, inDAS);
@@ -1007,8 +1295,11 @@ public class DWARFProgram implements Closeable {
}
private List getTypeReferers(DIEAggregate targetDIEA) {
- List result = typeReferers.get(targetDIEA.getOffset());
- return (result != null) ? result : Collections.emptyList();
+ List dieaOffsets = typeReferers.get(targetDIEA.getOffset());
+ if (dieaOffsets == null) {
+ return List.of();
+ }
+ return dieaOffsets.stream().map(dieaOffset -> getAggregate(dieaOffset)).toList();
}
/**
@@ -1020,7 +1311,7 @@ public class DWARFProgram implements Closeable {
* to refer to the target DIEA.
* @return list of DIEAs that point to the target, empty list if nothing found.
*/
- public List getTypeReferers(DIEAggregate targetDIEA, int tag) {
+ public List getTypeReferers(DIEAggregate targetDIEA, DWARFTag tag) {
List result = new ArrayList<>();
for (DIEAggregate referer : getTypeReferers(targetDIEA)) {
@@ -1043,6 +1334,13 @@ public class DWARFProgram implements Closeable {
return programBaseAddressFixup;
}
+ public AddressRange getAddressRange(DWARFRange range, boolean isCode) {
+ AddressSpace defAS = program.getAddressFactory().getDefaultAddressSpace();
+ Address start = defAS.getAddress(range.getFrom(), true /* TODO check this */);
+ Address end = defAS.getAddress(range.getTo() - 1, true /* TODO check this */);
+ return new AddressRangeImpl(start, end);
+ }
+
public Address getCodeAddress(Number offset) {
return program.getAddressFactory()
.getDefaultAddressSpace()
@@ -1066,6 +1364,30 @@ public class DWARFProgram implements Closeable {
return functionFixups;
}
+ public int getDefaultIntSize() {
+ return program.getDefaultPointerSize();
+ }
+
+ public void logWarningAt(Address addr, String addrName, String msg) {
+ if (importOptions.isUseBookmarks()) {
+ BookmarkManager bmm = program.getBookmarkManager();
+ Bookmark existingBM = bmm.getBookmark(addr, BookmarkType.WARNING, DWARF_BOOKMARK_CAT);
+ String existingTxt = existingBM != null ? existingBM.getComment() : "";
+ if (existingTxt.contains(msg)) {
+ return;
+ }
+ msg = !existingTxt.isEmpty() ? existingTxt + "; " + msg : msg;
+ bmm.setBookmark(addr, BookmarkType.WARNING, DWARF_BOOKMARK_CAT, msg);
+ }
+ else {
+ Msg.warn(this, "%s: %s at %s@%s".formatted(DWARF_BOOKMARK_CAT, msg, addrName, addr));
+ }
+ }
+
+ /* for testing */ public void setStringTable(StringTable st) {
+ this.debugStrings = st;
+ }
+
//---------------------------------------------------------------------------------------------
private class DIEAggregateIterator implements Iterator, Iterable {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFRange.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRange.java
similarity index 56%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFRange.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRange.java
index d764c6a8fd..d9a7754f2f 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFRange.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRange.java
@@ -13,13 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
+
+import ghidra.program.model.address.AddressRange;
/**
- * Holds the start (inclusive) and end (exclusive) addresses of a range.
+ * Holds the start (inclusive) and end (exclusive, 1 past the last included address) addresses
+ * of a range.
+ *
+ * DWARF ranges are slightly different than Ghidra {@link AddressRange ranges} because the
+ * end address of a Ghidra AddressRange is inclusive, and the DWARF range is exclusive.
+ *
+ * DWARF ranges can represent an empty range, Ghidra AddressRanges can not.
+ * Ghidra AddressRanges can include the maximum 64bit address (0xffffffffffffffff), but DWARF ranges
+ * can not include that.
*/
public class DWARFRange implements Comparable {
- public static final DWARFRange EMPTY = new DWARFRange(0, 1);
+ public static final DWARFRange EMPTY = new DWARFRange(0, 0);
private final long start;
private final long end;
@@ -31,9 +41,9 @@ public class DWARFRange implements Comparable {
* @param end long ending address, exclusive
*/
public DWARFRange(long start, long end) {
- if (end < start) {
+ if (Long.compareUnsigned(end, start) < 0) {
throw new IllegalArgumentException(
- "Range max (" + end + ") cannot be less than min (" + start + ").");
+ "Range max (%d) cannot be less than min (%d).".formatted(end, start));
}
this.start = start;
this.end = end;
@@ -41,18 +51,26 @@ public class DWARFRange implements Comparable {
@Override
public String toString() {
- return "(" + this.start + "," + this.end + ")";
+ return "[%x,%x)".formatted(start, end);
}
@Override
public int compareTo(DWARFRange other) {
- int tmp = Long.compare(start, other.start);
+ int tmp = Long.compareUnsigned(start, other.start);
if (tmp == 0) {
- tmp = Long.compare(end, other.end);
+ tmp = Long.compareUnsigned(end, other.end);
}
return tmp;
}
+ public boolean isEmpty() {
+ return start == end;
+ }
+
+ public boolean contains(long addr) {
+ return Long.compareUnsigned(start, addr) <= 0 && Long.compareUnsigned(addr, end) < 0;
+ }
+
/**
* Returns starting address.
*
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java
new file mode 100644
index 0000000000..850d3f00f8
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java
@@ -0,0 +1,206 @@
+/* ###
+ * 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.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.DWARFRangeListEntry.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*;
+
+import java.io.IOException;
+import java.util.*;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.program.model.data.LEB128;
+import ghidra.util.NumericUtilities;
+
+/**
+ * Represents a list of {@link DWARFRange}s.
+ */
+public class DWARFRangeList {
+
+ public static final DWARFRangeList EMTPY = new DWARFRangeList(List.of());
+
+ /**
+ * Reads a v4 {@link DWARFRangeList} from the .debug_ranges stream.
+ *
+ * @param reader stream positioned to the start of a .debug_ranges range list
+ * @param cu the compUnit referring to this range
+ * @return new {@link DWARFRangeList}, never null
+ * @throws IOException if error reading
+ */
+ public static DWARFRangeList readV4(BinaryReader reader, DWARFCompilationUnit cu)
+ throws IOException {
+ byte pointerSize = cu.getPointerSize();
+ List ranges = new ArrayList<>();
+
+ DWARFRange cuRange = cu.getPCRange();
+ long baseAddress = cuRange != null ? cuRange.getFrom() : 0;
+
+ while (reader.hasNext()) {
+ // Read the beginning and ending addresses
+ long beginning = reader.readNextUnsignedValue(pointerSize);
+ long ending = reader.readNextUnsignedValue(pointerSize); // dwarf end addrs are exclusive
+
+ // End of the list
+ if (beginning == 0 && ending == 0) {
+ break;
+ }
+
+ // Check to see if this is a base address entry
+ if (beginning == -1 ||
+ (pointerSize == 4 && beginning == NumericUtilities.MAX_UNSIGNED_INT32_AS_LONG)) {
+ baseAddress = ending;
+ continue;
+ }
+
+ // Add the range to the list
+ ranges.add(new DWARFRange(baseAddress + beginning, baseAddress + ending));
+ }
+ return new DWARFRangeList(ranges);
+ }
+
+ /**
+ * Reads a v5 {@link DWARFRangeList} from the .debug_rnglists stream.
+ *
+ * @param reader stream positioned to the start of a .debug_rnglists range list
+ * @param cu the compUnit referring to this range
+ * @return new {@link DWARFRangeList}, never null
+ * @throws IOException if error reading
+ */
+ public static DWARFRangeList readV5(BinaryReader reader, DWARFCompilationUnit cu)
+ throws IOException {
+
+ List list = new ArrayList<>();
+
+ DWARFProgram dprog = cu.getProgram();
+ long baseAddrFixup = dprog.getProgramBaseAddressFixup();
+ long baseAddr = baseAddrFixup;
+
+ while (reader.hasNext()) {
+ int rleId = reader.readNextUnsignedByte();
+ if (rleId == DW_RLE_end_of_list) {
+ break;
+ }
+ switch (rleId) {
+ case DW_RLE_base_addressx: {
+ int addrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ baseAddr = dprog.getAddress(DW_FORM_addrx, addrIndex, cu);
+ break;
+ }
+ case DW_RLE_startx_endx: {
+ int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int endAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu);
+ long end = dprog.getAddress(DW_FORM_addrx, endAddrIndex, cu);
+ list.add(new DWARFRange(start, end));
+ break;
+ }
+ case DW_RLE_startx_length: {
+ int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu);
+ list.add(new DWARFRange(start, start + len));
+ break;
+ }
+ case DW_RLE_offset_pair: {
+ int startOfs = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int endOfs = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ list.add(new DWARFRange(baseAddr+startOfs, baseAddr+endOfs));
+ break;
+ }
+ case DW_RLE_base_address: {
+ baseAddr = reader.readNextUnsignedValue(cu.getPointerSize()) + baseAddrFixup;
+ break;
+ }
+ case DW_RLE_start_end: {
+ long startAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ long endAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ list.add(new DWARFRange(startAddr + baseAddrFixup, endAddr + baseAddrFixup));
+ break;
+ }
+ case DW_RLE_start_length: {
+ long startAddr = reader.readNextUnsignedValue(cu.getPointerSize());
+ int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ list.add(
+ new DWARFRange(startAddr + baseAddrFixup, startAddr + baseAddrFixup + len));
+ break;
+ }
+ default:
+ throw new IOException(
+ "Unsupported DWARF Range List Entry type: %d".formatted(rleId));
+ }
+ }
+ return new DWARFRangeList(list);
+ }
+
+ private List ranges;
+
+ public DWARFRangeList(DWARFRange singleRange) {
+ ranges = List.of(singleRange);
+ }
+
+ public DWARFRangeList(List ranges) {
+ this.ranges = ranges;
+ }
+
+ public boolean isEmpty() {
+ return ranges.isEmpty();
+ }
+
+ public long getFirstAddress() {
+ return getFirst().getFrom();
+ }
+
+ public DWARFRange getFirst() {
+ return ranges.get(0);
+ }
+
+ public DWARFRange get(int index) {
+ return ranges.get(index);
+ }
+
+ public List ranges() {
+ return ranges;
+ }
+
+ public int getListCount() {
+ return ranges.size();
+ }
+
+ public DWARFRange getLast() {
+ return ranges.get(ranges.size() - 1);
+ }
+
+ public DWARFRange getFlattenedRange() {
+ if (isEmpty()) {
+ return null;
+ }
+ if (ranges.size() == 1) {
+ return getFirst();
+ }
+
+ List copy = new ArrayList<>(ranges);
+ Collections.sort(copy);
+ DWARFRange first = copy.get(0);
+ DWARFRange last = copy.get(copy.size() - 1);
+ return new DWARFRange(first.getFrom(), last.getTo());
+ }
+
+ @Override
+ public String toString() {
+ return "DWARFRangeList: " + ranges;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListEntry.java
new file mode 100644
index 0000000000..2526f27805
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListEntry.java
@@ -0,0 +1,36 @@
+/* ###
+ * 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.dwarf;
+
+/**
+ * DWARF Range List Entry id
+ */
+public class DWARFRangeListEntry {
+
+ public static final int DW_RLE_end_of_list = 0x00;
+ public static final int DW_RLE_base_addressx = 0x01;
+ public static final int DW_RLE_startx_endx = 0x02;
+ public static final int DW_RLE_startx_length = 0x03;
+ public static final int DW_RLE_offset_pair = 0x04;
+ public static final int DW_RLE_base_address = 0x05;
+ public static final int DW_RLE_start_end = 0x06;
+ public static final int DW_RLE_start_length = 0x07;
+
+ public static String toString(long value) {
+ return DWARFUtil.toString(DWARFRangeListEntry.class, value);
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java
new file mode 100644
index 0000000000..e7a6b7c971
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java
@@ -0,0 +1,86 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames;
+
+/**
+ * Header found at the start of a set of DWARFRangeList entries, which are stored sequentially
+ * in the {@link DWARFSectionNames#DEBUG_RNGLISTS .debug_rnglists} section.
+ */
+public class DWARFRangeListHeader extends DWARFIndirectTableHeader {
+
+ public static DWARFRangeListHeader read(BinaryReader reader, int defaultIntSize)
+ throws IOException {
+ // length : dwarf_length
+ // version : 2 bytes
+ // address_size : 1 byte
+ // segment_selector_size : 1 byte
+ // offset entry count: 4 bytes
+ // offsets : array of elements are are dwarf_format_int sized
+
+ long startOffset = reader.getPointerIndex();
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, defaultIntSize);
+ if (lengthInfo == null) {
+ return null;
+ }
+
+ long endOffset = reader.getPointerIndex() + lengthInfo.length();
+ short version = reader.readNextShort();
+ if (version != 5) {
+ throw new DWARFException("DWARFRangeList (%x): unsupported DWARF version [%d]"
+ .formatted(startOffset, version));
+ }
+ int addressSize = reader.readNextUnsignedByte();
+ int segmentSelectorSize = reader.readNextUnsignedByte();
+ int offsetEntryCount = reader.readNextUnsignedIntExact();
+ long offsetListPosition = reader.getPointerIndex();
+
+ reader.setPointerIndex(endOffset);
+ if (segmentSelectorSize != 0) {
+ throw new IOException("Unsupported segmentSelectorSize: " + segmentSelectorSize);
+ }
+
+ return new DWARFRangeListHeader(startOffset, endOffset, offsetListPosition,
+ lengthInfo.intSize(), offsetEntryCount, addressSize, segmentSelectorSize);
+ }
+
+ private final int offsetEntryCount;
+ private final int offsetIntSize;
+ private final int addressSize;
+ private final int segmentSelectorSize;
+
+ public DWARFRangeListHeader(long startOffset, long endOffset, long firstElementOffset,
+ int offsetIntSize, int offsetEntryCount, int addressSize, int segmentSelectorSize) {
+ super(startOffset, endOffset, firstElementOffset);
+ this.offsetIntSize = offsetIntSize;
+ this.offsetEntryCount = offsetEntryCount;
+ this.addressSize = addressSize;
+ this.segmentSelectorSize = segmentSelectorSize;
+ }
+
+ @Override
+ public long getOffset(int index, BinaryReader reader) throws IOException {
+ if (index < 0 || offsetEntryCount <= index) {
+ throw new IOException("Invalid range list index: " + index);
+ }
+ return firstElementOffset +
+ reader.readUnsignedValue(firstElementOffset + (index * offsetIntSize), offsetIntSize);
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappings.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappings.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappings.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappings.java
index 880dccc36f..8c7cf96c41 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappings.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappings.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import ghidra.program.model.lang.Register;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappingsManager.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsManager.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappingsManager.java
index 385e2add5e..ae7ba3e677 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRegisterMappingsManager.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.util.*;
import java.util.regex.Matcher;
@@ -26,7 +26,6 @@ import org.jdom.*;
import org.jdom.input.SAXBuilder;
import generic.jar.ResourceFile;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
import ghidra.program.model.lang.*;
import ghidra.util.Msg;
import ghidra.util.xml.XmlUtilities;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFSourceInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceInfo.java
similarity index 62%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFSourceInfo.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceInfo.java
index 593fea9a90..d13619950b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFSourceInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceInfo.java
@@ -13,22 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.DW_AT_decl_line;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.DW_TAG_formal_parameter;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
-import ghidra.app.util.bin.format.dwarf4.DIEAggregate;
-import ghidra.app.util.bin.format.dwarf4.DebugInfoEntry;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFNumericAttribute;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFNumericAttribute;
/**
- * Small class to hold the filename and line number info values from
- * DWARF {@link DebugInfoEntry DIEs}.
- *
+ * Represents the filename and line number info values from DWARF {@link DebugInfoEntry DIEs}.
+ *
+ * @param filename String filename
+ * @param lineNum int line number
*/
-public class DWARFSourceInfo {
-
+public record DWARFSourceInfo(String filename, int lineNum) {
/**
* Creates a new {@link DWARFSourceInfo} instance from the supplied {@link DIEAggregate}
* if the info is present, otherwise returns null;
@@ -88,23 +86,6 @@ public class DWARFSourceInfo {
return sourceInfo != null ? sourceInfo.getDescriptionStr() : null;
}
- final private String filename;
- final private int lineNum;
-
- private DWARFSourceInfo(String filename, int lineNum) {
- this.filename = filename;
- this.lineNum = lineNum;
- }
-
- /**
- * Returns the filename
- *
- * @return string filename.
- */
- public String getFilename() {
- return filename;
- }
-
/**
* Returns the source location info as a string formatted as "filename:linenum"
*
@@ -114,50 +95,6 @@ public class DWARFSourceInfo {
return filename + ":" + lineNum;
}
- /**
- * Returns the source location info as a string formatted as "File: filename Line: linenum"
- *
- * @return "File: filename Line: linenum"
- */
- public String getDescriptionStr2() {
- return String.format("File: %s Line: %d", filename, lineNum);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((filename == null) ? 0 : filename.hashCode());
- result = prime * result + lineNum;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof DWARFSourceInfo)) {
- return false;
- }
- DWARFSourceInfo other = (DWARFSourceInfo) obj;
- if (filename == null) {
- if (other.filename != null) {
- return false;
- }
- }
- else if (!filename.equals(other.filename)) {
- return false;
- }
- if (lineNum != other.lineNum) {
- return false;
- }
- return true;
- }
-
@Override
public String toString() {
return "DWARFSourceInfo [filename=" + filename + ", lineNum=" + lineNum + "]";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFSourceLanguage.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceLanguage.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFSourceLanguage.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceLanguage.java
index 61b4237299..5426b6d067 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFSourceLanguage.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFSourceLanguage.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.encoding;
+package ghidra.app.util.bin.format.dwarf;
/**
* DWARF source lang consts from www.dwarfstd.org/doc/DWARF4.pdf.
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java
new file mode 100644
index 0000000000..ed7cf235ce
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java
@@ -0,0 +1,92 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFForm;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames;
+
+/**
+ * Table of offsets that point into the string table. These tables are stored sequentially in the
+ * {@link DWARFSectionNames#DEBUG_STROFFSETS .debug_str_offsets} section.
+ *
+ * Elements in the table are referred to by index via {@link DWARFForm#DW_FORM_strx} and friends.
+ *
+ * The table's {@link #getFirstElementOffset()} is referred to by a compUnit's
+ * {@link DWARFAttribute#DW_AT_str_offsets_base} value.
+ */
+public class DWARFStringOffsetTableHeader extends DWARFIndirectTableHeader {
+
+ /**
+ * Reads a string offset table header (found in the .debug_str_offsets section)
+ *
+ * @param dprog {@link DWARFProgram}
+ * @param reader {@link BinaryReader}
+ * @return new {@link DWARFStringOffsetTableHeader} instance
+ * @throws IOException if error reading
+ */
+ public static DWARFStringOffsetTableHeader readV5(BinaryReader reader, int defaultIntSize)
+ throws IOException {
+ // length : dwarf_length
+ // version : 2 bytes
+ // padding : 2 bytes
+ // offsets : array of elements are are dwarf_format_int sized
+
+ long startOffset = reader.getPointerIndex();
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, defaultIntSize);
+ if (lengthInfo == null) {
+ return null;
+ }
+
+ long endOffset = reader.getPointerIndex() + lengthInfo.length();
+
+ short version = reader.readNextShort();
+ if (version != 5) {
+ throw new DWARFException("Unsupported DWARF version [%d]".formatted(version));
+ }
+
+ /* int padding = */ reader.readNextShort();
+
+ long offsetArrayStart = reader.getPointerIndex();
+ reader.setPointerIndex(endOffset);
+
+ int count = (int) ((endOffset - offsetArrayStart) / lengthInfo.intSize());
+ return new DWARFStringOffsetTableHeader(startOffset, endOffset, offsetArrayStart,
+ lengthInfo.intSize(), count);
+ }
+
+ private final int count;
+ private final int intSize;
+
+ public DWARFStringOffsetTableHeader(long startOffset, long endOffset, long firstElementOffset,
+ int intSize, int count) {
+ super(startOffset, endOffset, firstElementOffset);
+ this.intSize = intSize;
+ this.count = count;
+ }
+
+ @Override
+ public long getOffset(int index, BinaryReader reader) throws IOException {
+ if (index < 0 || count <= index) {
+ throw new IOException(
+ "Invalid indirect string index: %d [0x%x]".formatted(index, index));
+ }
+ return reader.readUnsignedValue(firstElementOffset + (index * intSize), intSize);
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFTag.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFTag.java
new file mode 100644
index 0000000000..1b221c20d7
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFTag.java
@@ -0,0 +1,289 @@
+/* ###
+ * 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.dwarf;
+
+import java.util.*;
+
+import ghidra.program.model.symbol.SymbolType;
+
+/**
+ * Identifier/purpose of a DWARF DIE record.
+ *
+ * Users of this enum should be tolerant of unknown tag id values. See
+ * {@link DWARFAbbreviation}'s tagId.
+ */
+public enum DWARFTag {
+ DW_TAG_array_type(0x1),
+ DW_TAG_class_type(0x2),
+ DW_TAG_entry_point(0x3),
+ DW_TAG_enumeration_type(0x4),
+ DW_TAG_formal_parameter(0x5),
+ DW_TAG_imported_declaration(0x8),
+ DW_TAG_label(0xa),
+ DW_TAG_lexical_block(0xb),
+ DW_TAG_member(0xd),
+ DW_TAG_pointer_type(0xf),
+ DW_TAG_reference_type(0x10),
+ DW_TAG_compile_unit(0x11),
+ DW_TAG_string_type(0x12),
+ DW_TAG_structure_type(0x13),
+ DW_TAG_subroutine_type(0x15),
+ DW_TAG_typedef(0x16),
+ DW_TAG_union_type(0x17),
+ DW_TAG_unspecified_parameters(0x18),
+ DW_TAG_variant(0x19),
+ DW_TAG_common_block(0x1a),
+ DW_TAG_common_inclusion(0x1b),
+ DW_TAG_inheritance(0x1c),
+ DW_TAG_inlined_subroutine(0x1d),
+ DW_TAG_module(0x1e),
+ DW_TAG_ptr_to_member_type(0x1f),
+ DW_TAG_set_type(0x20),
+ DW_TAG_subrange_type(0x21),
+ DW_TAG_with_stmt(0x22),
+ DW_TAG_access_declaration(0x23),
+ DW_TAG_base_type(0x24),
+ DW_TAG_catch_block(0x25),
+ DW_TAG_const_type(0x26),
+ DW_TAG_constant(0x27),
+ DW_TAG_enumerator(0x28),
+ DW_TAG_file_type(0x29),
+ DW_TAG_friend(0x2a),
+ DW_TAG_namelist(0x2b),
+ DW_TAG_namelist_item(0x2c),
+ DW_TAG_packed_type(0x2d),
+ DW_TAG_subprogram(0x2e),
+ DW_TAG_template_type_param(0x2f),
+ DW_TAG_template_value_param(0x30),
+ DW_TAG_thrown_type(0x31),
+ DW_TAG_try_block(0x32),
+ DW_TAG_variant_part(0x33),
+ DW_TAG_variable(0x34),
+ DW_TAG_volatile_type(0x35),
+ DW_TAG_dwarf_procedure(0x36),
+ DW_TAG_restrict_type(0x37),
+ DW_TAG_interface_type(0x38),
+ DW_TAG_namespace(0x39),
+ DW_TAG_imported_module(0x3a),
+ DW_TAG_unspecified_type(0x3b),
+ DW_TAG_partial_unit(0x3c),
+ DW_TAG_imported_unit(0x3d),
+ DW_TAG_mutable_type(0x3e),
+ DW_TAG_condition(0x3f),
+ DW_TAG_shared_type(0x40),
+ DW_TAG_type_unit(0x41),
+ DW_TAG_rvalue_reference_type(0x42),
+ DW_TAG_template_alias(0x43),
+ DW_TAG_call_site(0x48),
+ DW_TAG_call_site_parameter(0x49),
+
+ DW_TAG_lo_user(0x4080),
+ DW_TAG_gnu_call_site(0x4109),
+ DW_TAG_gnu_call_site_parameter(0x410a),
+ DW_TAG_APPLE_ptrauth_type(0x4300), // Apple proprietary
+ DW_TAG_hi_user(0xffff),
+
+ DW_TAG_UNKNOWN(-1); // fake ghidra tag
+
+ private int id;
+
+ DWARFTag(int id) {
+ this.id = id;
+ }
+
+ /**
+ * Returns the name of this enum, falling back to the rawTagId value if this enum is the
+ * DW_TAG_UNKNOWN value.
+ *
+ * @param rawTagId tag id that corresponds to actual tag id found in the DWARF data
+ * @return string name of this enum
+ */
+ public String name(int rawTagId) {
+ return this != DW_TAG_UNKNOWN
+ ? name()
+ : "DW_TAG_??? %d (0x%x)".formatted(rawTagId, rawTagId);
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public boolean isType() {
+ return TYPE_TAGS.contains(this);
+ }
+
+ public boolean isNamedType() {
+ switch (this) {
+ case DW_TAG_base_type:
+ case DW_TAG_typedef:
+ case DW_TAG_namespace:
+ case DW_TAG_subprogram:
+ case DW_TAG_class_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_unspecified_type:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the children of this DIE are within a new namespace.
+ *
+ * Ie. Namespaces, subprogram, class, interface, struct, union, enum
+ *
+ * @return true if the children of this DIE are within a new namespace
+ */
+ public boolean isNameSpaceContainer() {
+ switch (this) {
+ case DW_TAG_namespace:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_class_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if this DIE defines a structure-like element (class, struct, interface, union).
+ *
+ * @return true if this DIE defines a structure-like element (class, struct, interface, union)
+ */
+ public boolean isStructureType() {
+ switch (this) {
+ case DW_TAG_class_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean isFuncDefType() {
+ switch (this) {
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Returns a string that describes what kind of object is specified by the {@link DIEAggregate}.
+ *
+ * Used to create a name for anonymous types.
+ *
+ * @return String describing the type of the DIEA.
+ */
+ public String getContainerTypeName() {
+ switch (this) {
+ case DW_TAG_structure_type:
+ return "struct";
+ case DW_TAG_class_type:
+ return "class";
+ case DW_TAG_enumeration_type:
+ return "enum";
+ case DW_TAG_union_type:
+ return "union";
+ case DW_TAG_lexical_block:
+ return "lexical_block";
+ case DW_TAG_subprogram:
+ return "subprogram";
+ case DW_TAG_subroutine_type:
+ return "subr";
+ case DW_TAG_variable:
+ return "var";
+ default:
+ return "unknown";
+ }
+ }
+
+ /**
+ * Returns the {@link SymbolType} that corresponds to a DWARF tag
+ *
+ * The mapping between tag type and SymbolType is not exact. There is no matching
+ * SymbolType for a DWARF static variable, so "LOCAL_VAR" is used currently.
+ *
+ * This mainly is used in constructing a NamespacePath, and the only critical usage
+ * there is Namespace vs. Class vs. everything else.
+ *
+ * @return {@link SymbolType}
+ */
+ public SymbolType getSymbolType() {
+ switch (this) {
+
+ case DW_TAG_subprogram:
+ return SymbolType.FUNCTION;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_interface_type:
+ case DW_TAG_class_type:
+ case DW_TAG_union_type:
+ case DW_TAG_enumeration_type:
+ return SymbolType.CLASS;
+
+ case DW_TAG_namespace:
+ return SymbolType.NAMESPACE;
+ case DW_TAG_formal_parameter:
+ return SymbolType.PARAMETER;
+
+ case DW_TAG_variable:
+ return SymbolType.LOCAL_VAR;
+
+ case DW_TAG_base_type:
+ case DW_TAG_typedef:
+ default:
+ return null;
+
+ }
+ }
+
+ //---------------------------------------------------------------------------------------------
+
+ public static DWARFTag of(int tagId) {
+ return lookupMap.getOrDefault(tagId, DW_TAG_UNKNOWN);
+ }
+
+ private static Map lookupMap = buildLookup();
+
+ private static Map buildLookup() {
+ Map result = new HashMap<>();
+ for (DWARFTag tag : values()) {
+ result.put(tag.id, tag);
+ }
+ return result;
+ }
+
+ private static final Set TYPE_TAGS = EnumSet.of(DW_TAG_base_type, DW_TAG_array_type,
+ DW_TAG_typedef, DW_TAG_class_type, DW_TAG_interface_type, DW_TAG_structure_type,
+ DW_TAG_union_type, DW_TAG_enumeration_type, DW_TAG_pointer_type, DW_TAG_reference_type,
+ DW_TAG_rvalue_reference_type, DW_TAG_const_type, DW_TAG_volatile_type,
+ DW_TAG_ptr_to_member_type, DW_TAG_unspecified_type, DW_TAG_subroutine_type);
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java
new file mode 100644
index 0000000000..f3e97ccc11
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java
@@ -0,0 +1,191 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.util.exception.CancelledException;
+import ghidra.util.task.TaskMonitor;
+
+/**
+ * The base class for a set of headers that share a common field layout.
+ */
+public class DWARFUnitHeader {
+ /**
+ * Reads the initial fields found in a unit header.
+ *
+ * @param dprog {@link DWARFProgram}
+ * @param reader {@link BinaryReader} .debug_info stream
+ * @param abbrReader {@link BinaryReader} .debug_abbr stream
+ * @param unitNumber ordinal of this item
+ * @param monitor {@link TaskMonitor}
+ * @return a unit header (only comp units for now), or null if at end-of-list
+ * @throws DWARFException if invalid dwarf data
+ * @throws IOException if error reading data
+ * @throws CancelledException if cancelled
+ */
+ public static DWARFUnitHeader read(DWARFProgram dprog, BinaryReader reader,
+ BinaryReader abbrReader, int unitNumber, TaskMonitor monitor)
+ throws DWARFException, IOException, CancelledException {
+ // unit_length : dwarf_length
+ // version : 2 bytes
+ // unit type : 1 byte [ version >= 5 ]
+
+ long startOffset = reader.getPointerIndex();
+ DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, dprog.getDefaultIntSize());
+ if (lengthInfo == null) {
+ return null;
+ }
+
+ long endOffset = reader.getPointerIndex() + lengthInfo.length();
+ short version = reader.readNextShort();
+ if (version < 2) {
+ throw new DWARFException("Unsupported DWARF version [%d]".formatted(version));
+ }
+
+ DWARFUnitHeader partial = new DWARFUnitHeader(dprog, startOffset, endOffset,
+ lengthInfo.length(), lengthInfo.intSize(), version, unitNumber);
+
+ if (2 <= version && version <= 4) {
+ return DWARFCompilationUnit.readV4(partial, reader, abbrReader, monitor);
+ }
+ int unitType = reader.readNextUnsignedByte();
+ switch (unitType) {
+ case DWARFUnitType.DW_UT_compile:
+ return DWARFCompilationUnit.readV5(partial, reader, abbrReader, monitor);
+ case DWARFUnitType.DW_UT_type:
+ case DWARFUnitType.DW_UT_partial:
+ case DWARFUnitType.DW_UT_skeleton:
+ case DWARFUnitType.DW_UT_split_compile:
+ case DWARFUnitType.DW_UT_split_type:
+ default:
+ throw new DWARFException("Unsupported unitType %d, %s".formatted(unitType,
+ DWARFUtil.toString(DWARFUnitType.class, unitType)));
+ }
+ }
+
+ /**
+ * Reference to the owning {@link DWARFProgram}.
+ */
+ protected final DWARFProgram dprog;
+
+ /**
+ * Offset in the debug_info section of this compUnit's header
+ */
+ protected final long startOffset;
+
+ /**
+ * Offset in the debug_info section of the end of this compUnit. (right after
+ * the last DIE record)
+ */
+ protected final long endOffset;
+
+ /**
+ * Length in bytes of this compUnit header and DIE records.
+ */
+ protected final long length;
+
+ /**
+ * size of integers, 4=int32 or 8=int64
+ */
+ protected final int intSize;
+
+ /**
+ * DWARF ver number, as read from the compunit structure, currently not used but being kept.
+ */
+ protected final short dwarfVersion;
+
+ /**
+ * Sequential number of this unit
+ */
+ protected final int unitNumber;
+
+ protected DWARFUnitHeader(DWARFUnitHeader other) {
+ this.dprog = other.dprog;
+ this.startOffset = other.startOffset;
+ this.endOffset = other.endOffset;
+ this.length = other.length;
+ this.intSize = other.intSize;
+ this.dwarfVersion = other.dwarfVersion;
+ this.unitNumber = other.unitNumber;
+ }
+
+ protected DWARFUnitHeader(DWARFProgram dprog, long startOffset, long endOffset, long length,
+ int intSize, short version, int unitNumber) {
+ this.dprog = dprog;
+ this.startOffset = startOffset;
+ this.endOffset = endOffset;
+ this.length = length;
+ this.intSize = intSize;
+ this.dwarfVersion = version;
+ this.unitNumber = unitNumber;
+ }
+
+ public DWARFProgram getProgram() {
+ return dprog;
+ }
+
+ public short getDWARFVersion() {
+ return dwarfVersion;
+ }
+
+ /**
+ * An unsigned long (4 bytes in 32-bit or 8 bytes in 64-bit format) representing
+ * the length of the .debug_info contribution for this unit, not including the length
+ * field itself.
+ *
+ * @return the length in bytes of this unit
+ */
+ public long getLength() {
+ return this.length;
+ }
+
+ /**
+ * Returns the byte offset to the start of this unit.
+ * @return the byte offset to the start of this unit
+ */
+ public long getStartOffset() {
+ return this.startOffset;
+ }
+
+ /**
+ * Returns the byte offset to the end of this unit.
+ * @return the byte offset to the end of this unit
+ */
+ public long getEndOffset() {
+ return this.endOffset;
+ }
+
+ /**
+ * Returns either 4 (for DWARF_32) or 8 (for DWARF_64) depending on the current unit format
+ *
+ * @return size of ints in this unit (4 or 8)
+ */
+ public int getIntSize() {
+ return this.intSize;
+ }
+
+ /**
+ * Return the ordinal number of this unit
+ *
+ * @return ordinal of this unit
+ */
+ public int getUnitNumber() {
+ return unitNumber;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitType.java
new file mode 100644
index 0000000000..291684f3a3
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitType.java
@@ -0,0 +1,29 @@
+/* ###
+ * 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.dwarf;
+
+public class DWARFUnitType {
+ public static final int DW_UT_compile = 0x01;
+ public static final int DW_UT_type = 0x02;
+ public static final int DW_UT_partial = 0x03;
+ public static final int DW_UT_skeleton = 0x04;
+ public static final int DW_UT_split_compile = 0x05;
+ public static final int DW_UT_split_type = 0x06;
+
+ public static final int DW_UT_lo_user = 0x80;
+ public static final int DW_UT_hi_user = 0xff;
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java
similarity index 62%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFUtil.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java
index 87caeee053..310a74e11d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFUtil.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java
@@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -24,13 +27,9 @@ import java.util.regex.Pattern;
import generic.jar.ResourceFile;
import ghidra.app.cmd.comments.AppendCommentCmd;
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFAttributeValue;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFNumericAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionException;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeValue;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFNumericAttribute;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException;
import ghidra.program.database.data.DataTypeUtilities;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
@@ -38,8 +37,6 @@ import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
-import ghidra.program.model.symbol.SymbolType;
-import ghidra.util.Conv;
public class DWARFUtil {
/**
@@ -53,7 +50,7 @@ public class DWARFUtil {
* @return the String name of the matching field.
*/
public static String toString(Class> clazz, int value) {
- return toString(clazz, Conv.intToLong(value));
+ return toString(clazz, Integer.toUnsignedLong(value));
}
/**
@@ -101,77 +98,9 @@ public class DWARFUtil {
//--------------------------------------
- /**
- * Returns a string that describes what kind of object is specified by the {@link DIEAggregate}.
- *
- * Used to create a name for anonymous types.
- *
- * @param diea {@link DIEAggregate}
- * @return String describing the type of the DIEA.
- */
- public static String getContainerTypeName(DIEAggregate diea) {
- switch (diea.getTag()) {
- case DWARFTag.DW_TAG_structure_type:
- return "struct";
- case DWARFTag.DW_TAG_class_type:
- return "class";
- case DWARFTag.DW_TAG_enumeration_type:
- return "enum";
- case DWARFTag.DW_TAG_union_type:
- return "union";
- case DWARFTag.DW_TAG_lexical_block:
- return "lexical_block";
- case DWARFTag.DW_TAG_subprogram:
- return "subprogram";
- case DWARFTag.DW_TAG_subroutine_type:
- return "subr";
- case DWARFTag.DW_TAG_variable:
- return "var";
- }
- return "unknown";
- }
- //-------------------------------------------
- /**
- * Returns the {@link SymbolType} that corresponds to the specified {@link DIEAggregate}.
- *
- * The mapping between DIE type and SymbolType is not exact. There is no matching
- * SymbolType for a DWARF static variable, so "LOCAL_VAR" is used currently.
- *
- * This mainly is used in constructing a NamespacePath, and the only critical usage
- * there is Namespace vs. Class vs. everything else.
- *
- * @param diea {@link DIEAggregate} to query
- * @return {@link SymbolType}
- */
- public static SymbolType getSymbolTypeFromDIE(DIEAggregate diea) {
- switch (diea.getTag()) {
- case DWARFTag.DW_TAG_subprogram:
- return SymbolType.FUNCTION;
-
- case DWARFTag.DW_TAG_structure_type:
- case DWARFTag.DW_TAG_interface_type:
- case DWARFTag.DW_TAG_class_type:
- case DWARFTag.DW_TAG_union_type:
- case DWARFTag.DW_TAG_enumeration_type:
- return SymbolType.CLASS;
-
- case DWARFTag.DW_TAG_namespace:
- return SymbolType.NAMESPACE;
- default:
- case DWARFTag.DW_TAG_base_type:
- case DWARFTag.DW_TAG_typedef:
- return null;
-
- case DWARFTag.DW_TAG_formal_parameter:
- return SymbolType.PARAMETER;
-
- case DWARFTag.DW_TAG_variable:
- return SymbolType.LOCAL_VAR;
- }
- }
private static Pattern MANGLED_NESTING_REGEX = Pattern.compile("(.*_Z)?N([0-9]+.*)");
@@ -223,9 +152,9 @@ public class DWARFUtil {
DWARFProgram prog = die.getProgram();
for (DebugInfoEntry childDIE : die.getChildren(DWARFTag.DW_TAG_subprogram)) {
DIEAggregate childDIEA = prog.getAggregate(childDIE);
- String linkage = childDIEA.getString(DWARFAttribute.DW_AT_linkage_name, null);
+ String linkage = childDIEA.getString(DW_AT_linkage_name, null);
if (linkage == null) {
- linkage = childDIEA.getString(DWARFAttribute.DW_AT_MIPS_linkage_name, null);
+ linkage = childDIEA.getString(DW_AT_MIPS_linkage_name, null);
}
if (linkage != null) {
@@ -236,7 +165,7 @@ public class DWARFUtil {
}
}
}
- return Collections.EMPTY_LIST;
+ return List.of();
}
/**
@@ -279,9 +208,10 @@ public class DWARFUtil {
for (DebugInfoEntry childDIE : parent.getChildren()) {
DIEAggregate childDIEA = prog.getAggregate(childDIE);
if (diea == childDIEA || diea.getOffset() == childDIEA.getOffset()) {
- return "anon_" + getContainerTypeName(childDIEA) + "_" + typeDefCount;
+ return "anon_%s_%d".formatted(childDIEA.getTag().getContainerTypeName(),
+ typeDefCount);
}
- if (childDIEA.isNamedType()) {
+ if (childDIEA.getTag().isNamedType()) {
typeDefCount++;
}
}
@@ -328,7 +258,7 @@ public class DWARFUtil {
sb.append(childName);
}
- return "anon_" + getContainerTypeName(diea) + "_for_" + sb.toString();
+ return "anon_" + diea.getTag().getContainerTypeName() + "_for_" + sb.toString();
}
/**
@@ -339,7 +269,7 @@ public class DWARFUtil {
* @return formatted string, example "80_5_73dc6de9" (80 bytes, 5 fields, hex hash of field names)
*/
public static String getStructLayoutFingerprint(DIEAggregate diea) {
- long structSize = diea.getUnsignedLong(DWARFAttribute.DW_AT_byte_size, 0);
+ long structSize = diea.getUnsignedLong(DW_AT_byte_size, 0);
int memberCount = 0;
List memberNames = new ArrayList<>();
for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren()) {
@@ -348,7 +278,7 @@ public class DWARFUtil {
continue;
}
DIEAggregate childDIEA = diea.getProgram().getAggregate(childEntry);
- if (childDIEA.hasAttribute(DWARFAttribute.DW_AT_external)) {
+ if (childDIEA.hasAttribute(DW_AT_external)) {
continue;
}
memberCount++;
@@ -357,7 +287,7 @@ public class DWARFUtil {
int memberOffset = 0;
try {
memberOffset =
- childDIEA.parseDataMemberOffset(DWARFAttribute.DW_AT_data_member_location, 0);
+ childDIEA.parseDataMemberOffset(DW_AT_data_member_location, 0);
}
catch (DWARFExpressionException | IOException e) {
// ignore, leave as default value 0
@@ -372,26 +302,6 @@ public class DWARFUtil {
return String.format("%d_%d_%08x", structSize, memberCount, memberNames.hashCode());
}
- /**
- * Create a name for a lexical block, with "_" separated numbers indicating nesting
- * information of the lexical block.
- *
- * @param diea {@link DIEAggregate} pointing to a lexical block entry.
- * @return string, ie. "lexical_block_1_2_3"
- */
- public static String getLexicalBlockName(DIEAggregate diea) {
- return "lexical_block" + getLexicalBlockNameWorker(diea.getHeadFragment());
- }
-
- private static String getLexicalBlockNameWorker(DebugInfoEntry die) {
- if (die.getTag() == DWARFTag.DW_TAG_lexical_block ||
- die.getTag() == DWARFTag.DW_TAG_inlined_subroutine) {
- return "%s_%d".formatted(getLexicalBlockNameWorker(die.getParent()),
- die.getPositionInParent());
- }
- return "";
- }
-
/**
* Append a string to a {@link DataType}'s description.
*
@@ -468,100 +378,6 @@ public class DWARFUtil {
return cu;
}
- /**
- * Read an offset value who's size depends on the DWARF format: 32 vs 64.
- *
- * @param reader BinaryReader pointing to the value to read
- * @param dwarfFormat - See {@link DWARFCompilationUnit#DWARF_32} and {@link DWARFCompilationUnit#DWARF_64}.
- * @return the offset value
- * @throws IOException if an I/O error occurs or bad dwarfFormat value
- */
- public static long readOffsetByDWARFformat(BinaryReader reader, int dwarfFormat)
- throws IOException {
- switch (dwarfFormat) {
- case DWARFCompilationUnit.DWARF_32:
- return reader.readNextUnsignedInt();
- case DWARFCompilationUnit.DWARF_64:
- return reader.readNextLong();
- }
- throw new IOException("Unknown DWARF Format Value: " + dwarfFormat);
- }
-
- /**
- * Read a variable-sized unsigned integer and return it as a java signed long.
- *
- * @param reader {@link BinaryReader} to read the data from
- * @param pointerSize number of bytes the value is stored in, must be 1, 2, 4, or 8.
- * @return unsigned long integer value.
- * @throws IOException if error
- */
- public static long readVarSizedULong(BinaryReader reader, int pointerSize) throws IOException {
- switch (pointerSize) {
- case 1:
- return reader.readNextUnsignedByte();
- case 2:
- return reader.readNextUnsignedShort();
- case 4:
- return reader.readNextUnsignedInt();
- case 8:
- return reader.readNextLong() /* no unsigned long mask possible */;
- }
- throw new IOException("Unsupported variable-sized int: " + pointerSize);
- }
-
- /**
- * Read a variable-sized unsigned integer and return it as a java signed int.
- *
- * Unsigned 32 bit int values larger than java's signed Integer.MAX_VALUE are not
- * supported and will throw an IOException.
- *
- * @param reader {@link BinaryReader} to read the data from
- * @param size number of bytes the integer value is stored in, must be 1, 2 or 4.
- * @return unsigned integer value.
- * @throws IOException if error
- */
- public static int readVarSizedUInt(BinaryReader reader, int size) throws IOException {
- switch (size) {
- case 1:
- return reader.readNextUnsignedByte();
- case 2:
- return reader.readNextUnsignedShort();
- case 4:
- long l = reader.readNextUnsignedInt();
- if (l < 0 || l > Integer.MAX_VALUE) {
- throw new IOException("Unsigned int value too large: " + l);
- }
- return (int) l;
- }
- throw new IOException("Unsupported variable-sized int: " + size);
- }
-
- /**
- * Reads a variable-sized unsigned 'address' value from a {@link BinaryReader} and
- * returns it as a 64 bit java long.
- *
- * The valid pointerSizes are 1, 2, 4, and 8.
- *
- * @param reader {@link BinaryReader} to read the data from
- * @param pointerSize number of bytes the value is stored in, must be 1, 2, 4, or 8.
- * @return unsigned long value.
- * @throws IOException if error
- */
- public static long readAddressAsLong(BinaryReader reader, byte pointerSize) throws IOException {
- switch (pointerSize) {
- case 1:
- return reader.readNextUnsignedByte();
- case 2:
- return reader.readNextUnsignedShort();
- case 4:
- return reader.readNextUnsignedInt();
- case 8:
- return reader.readNextLong();
- }
- throw new IllegalArgumentException(
- "Unknown pointer size: 0x" + Integer.toHexString(pointerSize));
- }
-
public static boolean isThisParam(DIEAggregate paramDIEA) {
// DWARF has multiple ways of indicating a DW_TAG_formal_parameter is
// the "this" parameter, and different versions of different toolchains
@@ -576,14 +392,14 @@ public class DWARFUtil {
// referencing the param that points to the object instance (ie. "this").
//
String paramName = paramDIEA.getName();
- if (paramDIEA.getBool(DWARFAttribute.DW_AT_artificial, false) ||
+ if (paramDIEA.getBool(DW_AT_artificial, false) ||
Function.THIS_PARAM_NAME.equals(paramName)) {
return true;
}
DIEAggregate funcDIEA = paramDIEA.getParent();
DWARFAttributeValue dwATObjectPointer =
- funcDIEA.getAttribute(DWARFAttribute.DW_AT_object_pointer);
+ funcDIEA.getAttribute(DW_AT_object_pointer);
if (dwATObjectPointer != null && dwATObjectPointer instanceof DWARFNumericAttribute dnum &&
paramDIEA.hasOffset(dnum.getUnsignedValue())) {
return true;
@@ -592,7 +408,7 @@ public class DWARFUtil {
// If the variable is not named, check to see if the parent of the function
// is a struct/class, and the parameter points to it
DIEAggregate classDIEA = funcDIEA.getParent();
- if (paramName == null && classDIEA != null && classDIEA.isStructureType()) {
+ if (paramName == null && classDIEA != null && classDIEA.getTag().isStructureType()) {
// Check to see if the parent data type equals the parameters' data type
return isPointerTo(classDIEA, paramDIEA.getTypeRef());
}
@@ -601,94 +417,15 @@ public class DWARFUtil {
}
public static boolean isPointerTo(DIEAggregate targetDIEA, DIEAggregate testDIEA) {
- return testDIEA != null && testDIEA.getTag() == DWARFTag.DW_TAG_pointer_type &&
+ return testDIEA != null && testDIEA.getTag() == DW_TAG_pointer_type &&
testDIEA.getTypeRef() == targetDIEA;
}
public static boolean isPointerDataType(DIEAggregate diea) {
- while (diea.getTag() == DWARFTag.DW_TAG_typedef) {
+ while (diea.getTag() == DW_TAG_typedef) {
diea = diea.getTypeRef();
}
- return diea.getTag() == DWARFTag.DW_TAG_pointer_type;
- }
-
- /**
- * Returns the {@link DIEAggregate} of a typedef that points to the specified datatype.
- *
- * Returns null if there is no typedef pointing to the specified DIEA or if there are
- * multiple.
- *
- * @param diea {@link DIEAggregate} of a data type that might be the target of typedefs.
- * @return {@link DIEAggregate} of the singular typedef that points to the arg, otherwise
- * null if none or multiple found.
- */
- public static DIEAggregate getReferringTypedef(DIEAggregate diea) {
- if (diea == null) {
- return null;
- }
- List referers =
- diea.getProgram().getTypeReferers(diea, DWARFTag.DW_TAG_typedef);
- return (referers.size() == 1) ? referers.get(0) : null;
- }
-
- public static class LengthResult {
- public final long length;
- public final int format; // either DWARF_32 or DWARF_64
-
- private LengthResult(long length, int format) {
- this.length = length;
- this.format = format;
- }
- }
-
- /**
- * Read a variable-length length value from the stream.
- *
- *
- * @param reader {@link BinaryReader} stream to read from
- * @param program Ghidra {@link Program}
- * @return new {@link LengthResult}, never null; length == 0 should be checked for and treated
- * specially
- * @throws IOException if io error
- * @throws DWARFException if invalid values
- */
- public static LengthResult readLength(BinaryReader reader, Program program)
- throws IOException, DWARFException {
- long length = reader.readNextUnsignedInt();
- int format;
-
- if (length == 0xffffffffL) {
- // Length of 0xffffffff implies 64-bit DWARF format
- // Mostly untested as there is no easy way to force the compiler
- // to generate this
- length = reader.readNextLong();
- format = DWARFCompilationUnit.DWARF_64;
- }
- else if (length >= 0xfffffff0L) {
- // Length of 0xfffffff0 or greater is reserved for DWARF
- throw new DWARFException("Reserved DWARF length value: " + Long.toHexString(length) +
- ". Unknown extension.");
- }
- else if (length == 0) {
- // Test for special case of weird BE MIPS 64bit length value.
- // Instead of following DWARF std (a few lines above with length == MAX_INT),
- // it writes a raw 64bit long (BE). The upper 32 bits (already read as length) will
- // always be 0 since super-large binaries from that system weren't really possible.
- // The next 32 bits will be the remainder of the value.
- if (reader.isBigEndian() && program.getDefaultPointerSize() == 8) {
- length = reader.readNextUnsignedInt();
- format = DWARFCompilationUnit.DWARF_64;
- }
- else {
- // length 0 signals an error to caller
- format = DWARFCompilationUnit.DWARF_32; // doesn't matter
- }
- }
- else {
- format = DWARFCompilationUnit.DWARF_32;
- }
-
- return new LengthResult(length, format);
+ return diea.getTag() == DW_TAG_pointer_type;
}
/**
@@ -700,7 +437,7 @@ public class DWARFUtil {
* @param lang {@link Language} to query
* @param name name of the option in the ldefs file
* @return file pointed to by the specified external_name tool entry
- * @throws IOException
+ * @throws IOException if not a sleigh lang
*/
public static ResourceFile getLanguageExternalFile(Language lang, String name)
throws IOException {
@@ -715,14 +452,13 @@ public class DWARFUtil {
*
* @param lang {@link Language} to get base definition directory
* @return base directory for language definition files
- * @throws IOException
+ * @throws IOException if not a sleigh lang
*/
public static ResourceFile getLanguageDefinitionDirectory(Language lang) throws IOException {
LanguageDescription langDesc = lang.getLanguageDescription();
- if (!(langDesc instanceof SleighLanguageDescription)) {
+ if (!(langDesc instanceof SleighLanguageDescription sld)) {
throw new IOException("Not a Sleigh Language: " + lang.getLanguageID());
}
- SleighLanguageDescription sld = (SleighLanguageDescription) langDesc;
ResourceFile defsFile = sld.getDefsFile();
ResourceFile parentFile = defsFile.getParentFile();
return parentFile;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFVariable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFVariable.java
similarity index 89%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFVariable.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFVariable.java
index e704feceda..b1c98bb8be 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DWARFVariable.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFVariable.java
@@ -13,16 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import java.io.IOException;
import java.util.*;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.expression.*;
+import ghidra.app.util.bin.format.dwarf.expression.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Register;
@@ -34,7 +33,7 @@ import ghidra.util.Msg;
import ghidra.util.exception.InvalidInputException;
/**
- * Represents a function parameter, local variable, or global variable.
+ * Represents a function's parameter or local variable; or a global variable.
*/
public class DWARFVariable {
/**
@@ -102,7 +101,7 @@ public class DWARFVariable {
private final DWARFProgram program;
private final DWARFFunction dfunc;
- public DWARFNameInfo name;
+ public DWARFName name;
public DataType type;
public long lexicalOffset; // offset inside function where variable storage becomes valid
public boolean isOutputParameter; // changes to parameter value escape back to the calling location
@@ -245,16 +244,17 @@ public class DWARFVariable {
private boolean readParamStorage(DIEAggregate diea) {
try {
if (DataTypeComponent.usesZeroLengthComponent(type)) {
- Msg.warn(this, "DWARF: zero-length function parameter %s:%s in %s@%s".formatted(
- name.getName(), type.getName(), dfunc.name.getName(), dfunc.address));
+ program.getImportSummary().paramZeroLenDataType++;
+ program.logWarningAt(dfunc.address, dfunc.name.getName(),
+ "Zero-length function parameter: %s : %s".formatted(name.getName(),
+ type.getName()));
return false;
}
- DWARFLocation topLocation = DWARFLocation.getTopLocation(
- diea.getAsLocation(DW_AT_location, dfunc.getRange()), dfunc.address.getOffset());
- if (topLocation == null) {
+ DWARFLocation paramLoc = diea.getLocation(DW_AT_location, dfunc.getEntryPc());
+ if (paramLoc == null) {
return false;
}
- return readStorage(diea, topLocation);
+ return readStorage(diea, paramLoc);
}
catch (IOException e) {
diea.getProgram().getImportSummary().exprReadError++;
@@ -264,8 +264,7 @@ public class DWARFVariable {
private boolean readLocalVariableStorage(DIEAggregate diea) {
try {
- DWARFLocation location = DWARFLocation
- .getFirstLocation(diea.getAsLocation(DW_AT_location, dfunc.getRange()));
+ DWARFLocation location = diea.getLocation(DW_AT_location, dfunc.getEntryPc());
if (location == null) {
return false;
}
@@ -274,7 +273,7 @@ public class DWARFVariable {
// with the address from the dwarf range. This gives slightly better results with
// test binaries in the decompiler, but might be wrong for other toolchains.
// If it causes problems, always use the address from the location's range.
- lexicalOffset = location.getRange().getFrom() - dfunc.address.getOffset();
+ lexicalOffset = location.getOffset(dfunc.getEntryPc());
}
return readStorage(diea, location);
@@ -289,16 +288,16 @@ public class DWARFVariable {
DWARFProgram prog = diea.getProgram();
try {
- DWARFLocation location = DWARFLocation
- .getFirstLocation(diea.getAsLocation(DW_AT_location, DWARFRange.EMPTY));
+ DWARFLocationList locList = diea.getLocationList(DW_AT_location);
+ DWARFLocation location = locList.getFirstLocation();
if (location == null) {
return false;
}
DWARFExpressionEvaluator exprEvaluator =
- DWARFExpressionEvaluator.create(diea.getHeadFragment());
+ new DWARFExpressionEvaluator(diea.getCompilationUnit());
- DWARFExpression expr = exprEvaluator.readExpr(location.getLocation());
+ DWARFExpression expr = exprEvaluator.readExpr(location.getExpr());
exprEvaluator.evaluate(expr);
if (exprEvaluator.getRawLastRegister() != -1) {
@@ -333,17 +332,17 @@ public class DWARFVariable {
return false;
}
- lexicalOffset = location.getRange().getFrom() - dfunc.address.getOffset();
+ lexicalOffset = location.getOffset(dfunc.address.getOffset());
DWARFProgram prog = diea.getProgram();
DWARFImportSummary importSummary = prog.getImportSummary();
try {
DWARFExpressionEvaluator exprEvaluator =
- DWARFExpressionEvaluator.create(diea.getHeadFragment());
+ new DWARFExpressionEvaluator(diea.getCompilationUnit());
exprEvaluator.setFrameBase(dfunc.frameBase);
- DWARFExpression expr = exprEvaluator.readExpr(location.getLocation());
+ DWARFExpression expr = exprEvaluator.readExpr(location.getExpr());
exprEvaluator.evaluate(expr);
long res = exprEvaluator.pop();
@@ -391,12 +390,10 @@ public class DWARFVariable {
}
if ((type.getLength() > reg.getMinimumByteSize())) {
importSummary.varFitError++;
-
- Msg.warn(this,
- "%s %s [%s, size=%d] for function %s@%s can not fit into specified register %s, size=%d, skipping. DWARF DIE: %s"
+ program.logWarningAt(dfunc.address, dfunc.name.getName(),
+ "%s %s [%s, size=%d] can not fit into specified register %s, size=%d"
.formatted(getVarTypeName(diea), name.getName(), type.getName(),
- type.getLength(), dfunc.name.getName(), dfunc.address,
- reg.getName(), reg.getMinimumByteSize(), diea.getHexOffset()));
+ type.getLength(), reg.getName(), reg.getMinimumByteSize()));
return false;
}
setRegisterStorage(List.of(reg));
@@ -410,7 +407,7 @@ public class DWARFVariable {
"%s location error for function %s@%s, %s: %s, DWARF DIE: %s, unsupported location information."
.formatted(getVarTypeName(diea), dfunc.name.getName(), dfunc.address,
name.getName(),
- DWARFExpression.exprToString(location.getLocation(), diea),
+ DWARFExpression.exprToString(location.getExpr(), diea),
diea.getHexOffset()));
return false;
}
@@ -425,7 +422,7 @@ public class DWARFVariable {
}
private String getVarTypeName(DIEAggregate diea) {
- return diea.getTag() == DWARFTag.DW_TAG_formal_parameter ? "Parameter" : "Variable";
+ return diea.getTag() == DW_TAG_formal_parameter ? "Parameter" : "Variable";
}
public int getStorageSize() {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DataTypeGraphComparator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DataTypeGraphComparator.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DataTypeGraphComparator.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DataTypeGraphComparator.java
index 6ce5580fc2..2da22b1022 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DataTypeGraphComparator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DataTypeGraphComparator.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.util.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DebugInfoEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java
similarity index 54%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DebugInfoEntry.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java
index 196697924d..3fcb4359d1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DebugInfoEntry.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java
@@ -13,16 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
import java.io.IOException;
import java.util.*;
import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.attribs.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.AttrDef;
import ghidra.program.model.data.LEB128;
import ghidra.util.datastruct.IntArrayList;
@@ -36,17 +34,10 @@ import ghidra.util.datastruct.IntArrayList;
*/
public class DebugInfoEntry {
- /**
- * List of common DWARF attributes that are not used currently in Ghidra. These attributes values will be
- * thrown away during reading to save some memory. There are lots of attributes that Ghidra doesn't
- * currently use, but they do not appear frequently enough to consume a significant amount of memory.
- */
- private static final Set ATTRIBUTES_TO_SKIP =
- Set.of(DWARFAttribute.DW_AT_sibling, DWARFAttribute.DW_AT_accessibility);
-
private final DWARFCompilationUnit compilationUnit;
private final DWARFAbbreviation abbreviation;
private final DWARFAttributeValue[] attributes;
+ private final int[] attrOffsets;
private final long offset;
private final int dieIndex;
@@ -54,71 +45,75 @@ public class DebugInfoEntry {
* Read a DIE record.
*
* @param reader {@link BinaryReader} positioned at the start of a DIE record
- * @param unit the compunit that contains the DIE
+ * @param cu the compunit that contains the DIE
* @param dieIndex the index of the DIE
- * @param attributeFactory the {@link DWARFAttributeFactory} to use to deserialize attribute
- * values
* @return new DIE instance
* @throws IOException if error reading data, or bad DWARF
*/
- public static DebugInfoEntry read(BinaryReader reader, DWARFCompilationUnit unit,
- int dieIndex, DWARFAttributeFactory attributeFactory) throws IOException {
+ public static DebugInfoEntry read(BinaryReader reader, DWARFCompilationUnit cu, int dieIndex)
+ throws IOException {
long offset = reader.getPointerIndex();
- int abbreviationCode = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int ac = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
// Check for terminator DIE
- if (abbreviationCode == 0) {
- return new DebugInfoEntry(unit, offset, -1, null);
+ if (ac == 0) {
+ return new DebugInfoEntry(cu, offset);
}
- DWARFAbbreviation abbreviation = unit.getCodeToAbbreviationMap().get(abbreviationCode);
+ DWARFAbbreviation abbreviation = cu.getAbbreviation(ac);
if (abbreviation == null) {
- throw new IOException("Abbreviation code " + abbreviationCode +
- " not found in the abbreviation map for compunit " + unit);
+ throw new IOException("Abbreviation code %d not found in compunit %d at 0x%x"
+ .formatted(ac, cu.getUnitNumber(), cu.getStartOffset()));
}
+ int[] attrOffsets = new int[abbreviation.getAttributeCount()];
- DebugInfoEntry result = new DebugInfoEntry(unit, offset, dieIndex, abbreviation);
// Read in all of the attribute values based on the attribute specification
- DWARFAttributeSpecification[] attributeSpecs = result.abbreviation.getAttributes();
+ AttrDef[] attributeSpecs = abbreviation.getAttributes();
+ int currentAttrOffset = (int) (reader.getPointerIndex() - offset);
for (int i = 0; i < attributeSpecs.length; i++) {
- DWARFAttributeSpecification attributeSpec = attributeSpecs[i];
- result.attributes[i] =
- attributeFactory.read(reader, unit, attributeSpec.getAttributeForm());
+ attrOffsets[i] = currentAttrOffset;
- if (ATTRIBUTES_TO_SKIP.contains(attributeSpec.getAttribute())) {
- // throw away the object holding the value and replace it with
- // the static boolean true value object to hold its place in
- // the list. This saves a little memory
- result.attributes[i] = DWARFBooleanAttribute.TRUE;
+ AttrDef attributeSpec = attributeSpecs[i];
+ DWARFFormContext context = new DWARFFormContext(reader, cu, attributeSpec);
+ long attrSize = attributeSpec.getAttributeForm().getSize(context);
+ if (attrSize < 0 || attrSize > Integer.MAX_VALUE) {
+ throw new IOException("Invalid attribute value size");
}
+
+ currentAttrOffset += attrSize;
+
+ // manually set stream position because some attributes don't read from the stream to determine size
+ reader.setPointerIndex(offset + currentAttrOffset);
}
- return result;
+ return new DebugInfoEntry(cu, offset, dieIndex, abbreviation, attrOffsets);
+ }
+
+ private DebugInfoEntry(DWARFCompilationUnit unit, long offset) {
+ this(unit, offset, -1, null, null);
}
/**
- * Creates a DIE. Used by
- * {@link #read(BinaryReader, DWARFCompilationUnit, DWARFAttributeFactory) static read()} and
- * junit tests.
+ * Creates a DIE.
*
- * @param unit compunit containing the DIE
+ * @param cu compunit containing the DIE
* @param offset offset of the DIE
* @param dieIndex index of the DIE
* @param abbreviation that defines the schema of this DIE record
+ * @param attrOffsets offset (from the die offset) of each attribute value
*/
- public DebugInfoEntry(DWARFCompilationUnit unit, long offset, int dieIndex,
- DWARFAbbreviation abbreviation) {
- this.compilationUnit = unit;
+ public DebugInfoEntry(DWARFCompilationUnit cu, long offset, int dieIndex,
+ DWARFAbbreviation abbreviation, int[] attrOffsets) {
+ this.compilationUnit = cu;
this.offset = offset;
this.dieIndex = dieIndex;
this.abbreviation = abbreviation;
- this.attributes = abbreviation != null
- ? new DWARFAttributeValue[abbreviation.getAttributeCount()]
- : null;
+ this.attrOffsets = attrOffsets;
+ this.attributes = attrOffsets != null ? new DWARFAttributeValue[attrOffsets.length] : null;
}
/**
- * Returns the index of this DIE (in the entire dwarf program)
+ * Returns the index of this DIE in the entire dwarf program.
*
* @return index of this DIE
*/
@@ -141,9 +136,10 @@ public class DebugInfoEntry {
* @param childTag DIE tag used to filter the child DIEs
* @return list of matching child DIE records
*/
- public List getChildren(int childTag) {
- List result = new ArrayList<>();
- for (DebugInfoEntry child : getChildren()) {
+ public List getChildren(DWARFTag childTag) {
+ List children = getChildren();
+ List result = new ArrayList<>(children.size());
+ for (DebugInfoEntry child : children) {
if (child.getTag() == childTag) {
result.add(child);
}
@@ -154,7 +150,7 @@ public class DebugInfoEntry {
/**
* Get the parent DIE of this DIE.
*
- * @return the parent DIE, or null if this DIE is the root of the compunit
+ * @return the parent DIE, or null if this DIE is the root of the compilation unit
*/
public DebugInfoEntry getParent() {
return getProgram().getParentOf(dieIndex);
@@ -172,30 +168,65 @@ public class DebugInfoEntry {
* Get the DWARFTag value of this DIE.
* @return the DWARFTag value of this DIE
*/
- public int getTag() {
- return (abbreviation != null) ? abbreviation.getTag() : 0;
- }
-
- public DWARFAttributeValue[] getAttributes() {
- return attributes;
+ public DWARFTag getTag() {
+ return (abbreviation != null) ? abbreviation.getTag() : null;
}
/**
- * Check to see if this DIE has the given attribute key.
- * @param attribute the attribute key
- * @return true if the DIE contains the attribute and false otherwise
+ * Returns the number of attributes in this DIE.
+ *
+ * @return number of attribute values in this DIE
*/
- public boolean hasAttribute(int attribute) {
- if (abbreviation == null) {
- return false;
- }
+ public int getAttributeCount() {
+ return attrOffsets.length;
+ }
- for (DWARFAttributeSpecification as : abbreviation.getAttributes()) {
- if (as.getAttribute() == attribute) {
- return true;
+ /**
+ * Returns the indexed attribute value.
+ *
+ * @param attribIndex index (0..count)
+ * @return {@link DWARFAttributeValue}
+ * @throws IOException if error reading the value
+ */
+ public DWARFAttributeValue getAttributeValue(int attribIndex) throws IOException {
+ if (attributes[attribIndex] == null) {
+ BinaryReader reader = getProgram().getReaderForCompUnit(compilationUnit)
+ .clone(offset + attrOffsets[attribIndex]);
+ DWARFFormContext context = new DWARFFormContext(reader, compilationUnit,
+ abbreviation.getAttributeAt(attribIndex));
+ attributes[attribIndex] = context.def().getAttributeForm().readValue(context);
+ }
+ return attributes[attribIndex];
+ }
+
+ /* for testing */ public void setAttributeValue(int index, DWARFAttributeValue attrVal) {
+ attributes[index] = attrVal;
+ }
+
+ private DWARFAttributeValue getAttributeValueUnchecked(int attribIndex) {
+ try {
+ return getAttributeValue(attribIndex);
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Searches the list of attributes for a specific attribute, by id.
+ *
+ * @param attributeId {@link DWARFAttribute}
+ * @return {@link DWARFAttributeValue}, or null if not found
+ */
+ public DWARFAttributeValue findAttribute(DWARFAttribute attributeId) {
+ AttrDef[] attrDefs = abbreviation.getAttributes();
+ for (int i = 0; i < attrDefs.length; i++) {
+ AttrDef attrDef = attrDefs[i];
+ if (attrDef.getAttributeId() == attributeId) {
+ return getAttributeValueUnchecked(i);
}
}
- return false;
+ return null;
}
/**
@@ -268,24 +299,23 @@ public class DebugInfoEntry {
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
- int tag = getTag();
+ DWARFTag tag = getTag();
+ int tagNum = tag != null ? tag.getId() : 0;
int abbrNum = abbreviation != null ? abbreviation.getAbbreviationCode() : 0;
int childCount = getProgram().getDIEChildIndexes(dieIndex).size();
buffer.append("<%d><%x>: %s [abbrev %d, tag %d, index %d, children %d]\n".formatted(
- getDepth(), offset, DWARFUtil.toString(DWARFTag.class, tag), abbrNum, tag, dieIndex,
- childCount));
+ getDepth(), offset, tag, abbrNum, tagNum, dieIndex, childCount));
if (isTerminator()) {
return buffer.toString();
}
- DWARFAttributeSpecification[] attributeSpecs = abbreviation.getAttributes();
- for (int i = 0; i < attributeSpecs.length; i++) {
- DWARFAttributeSpecification attributeSpec = attributeSpecs[i];
- buffer.append("\t\tAttribute: %s %s %s\n".formatted(
- DWARFUtil.toString(DWARFAttribute.class, attributeSpec.getAttribute()),
- attributes[i], attributeSpec.getAttributeForm().toString()));
+ for (int i = 0; i < attributes.length; i++) {
+ buffer.append("\t\t");
+ DWARFAttributeValue attribVal = getAttributeValueUnchecked(i);
+ buffer.append(attribVal != null ? attribVal.toString(compilationUnit) : "-missing-");
+ buffer.append("\n");
}
return buffer.toString();
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DwarfSectionNames.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DwarfSectionNames.java
index 0100bcae31..c06e300916 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DwarfSectionNames.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DwarfSectionNames.java
@@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
- * REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +15,15 @@
*/
package ghidra.app.util.bin.format.dwarf;
-import ghidra.app.util.opinion.*;
+import ghidra.app.plugin.core.analysis.DwarfLineNumberAnalyzer;
+import ghidra.app.util.opinion.ElfLoader;
+import ghidra.app.util.opinion.MachoLoader;
import ghidra.program.model.listing.Program;
+/**
+ * Section name logic for the obsolete {@link DwarfLineNumberAnalyzer}
+ */
+@Deprecated(forRemoval = true)
public final class DwarfSectionNames {
private final static String MACHO_PREFIX = "__";
private final static String ELF_PREFIX = ".";
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NameDeduper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NameDeduper.java
similarity index 90%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NameDeduper.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NameDeduper.java
index 11e8e022db..164adfa50d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NameDeduper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NameDeduper.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.util.*;
@@ -42,7 +42,7 @@ public class NameDeduper {
/**
* Add names to the the de-duper that have already been used.
*
- * @param alreadyUsedNames
+ * @param alreadyUsedNames names already used
*/
public void addUsedNames(Collection alreadyUsedNames) {
usedNames.addAll(alreadyUsedNames);
@@ -53,7 +53,7 @@ public class NameDeduper {
* calls to confirm that a name is unique, but instead prevent the name from being used
* when an auto-generated name is created.
*
- * @param additionalReservedNames
+ * @param additionalReservedNames names to reserve
*/
public void addReservedNames(Collection additionalReservedNames) {
reservedNames.addAll(additionalReservedNames);
@@ -62,8 +62,8 @@ public class NameDeduper {
/**
* Returns true if the specified name hasn't been allocated yet.
*
- * @param name
- * @return
+ * @param name string name to check
+ * @return boolean true if the specified name hasn't been allocated yet
*/
public boolean isUniqueName(String name) {
return name == null || !usedNames.contains(name);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NamespacePath.java
similarity index 99%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NamespacePath.java
index 1b4a6e9679..9bd927f533 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/NamespacePath.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/NamespacePath.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import java.util.*;
import java.util.function.Consumer;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/StringTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/StringTable.java
new file mode 100644
index 0000000000..1991ce42a1
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/StringTable.java
@@ -0,0 +1,92 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.util.datastruct.WeakValueHashMap;
+
+/**
+ * Represents a DWARF string table, backed by a memory section like .debug_str.
+ *
+ * Strings are read from the section the first time requested, and then cached in a weak lookup
+ * table.
+ */
+public class StringTable {
+ /**
+ * Creates a StringTable instance, if the supplied BinaryReader is non-null.
+ *
+ * @param reader BinaryReader
+ * @return new instance, or null if reader is null
+ */
+ public static StringTable of(BinaryReader reader) {
+ if (reader == null) {
+ return null;
+ }
+ return new StringTable(reader);
+ }
+
+ protected BinaryReader reader;
+ protected WeakValueHashMap cache = new WeakValueHashMap<>();
+
+ /**
+ * Creates a StringTable
+ *
+ * @param reader {@link BinaryReader} .debug_str or .debug_line_str
+ */
+ public StringTable(BinaryReader reader) {
+ this.reader = reader;
+ }
+
+ /**
+ * Returns true if the specified offset is a valid offset for this string table.
+ *
+ * @param offset location of possible string
+ * @return boolean true if location is valid
+ */
+ public boolean isValid(long offset) {
+ return reader.isValidIndex(offset);
+ }
+
+ public void clear() {
+ reader = null;
+ cache.clear();
+ }
+
+ /**
+ * Returns the string found at offset, or throws an {@link IOException}
+ * if the offset is out of bounds.
+ *
+ * @param offset location of string
+ * @return a string, never null
+ * @throws IOException if not valid location
+ */
+ public String getStringAtOffset(long offset) throws IOException {
+ if (!isValid(offset)) {
+ throw new IOException("Invalid offset requested " + offset);
+ }
+
+ String s = cache.get(offset);
+ if (s == null) {
+ s = reader.readUtf8String(offset);
+ cache.put(offset, s);
+ }
+
+ return s;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttribute.java
new file mode 100644
index 0000000000..c1c581e51c
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttribute.java
@@ -0,0 +1,265 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeClass.*;
+
+import java.io.IOException;
+import java.util.*;
+
+import ghidra.app.util.bin.BinaryReader;
+
+/**
+ * Defines the names and numeric ids of known DWARF attributes. Well-known attributes are also
+ * constrained to certain value types (see {@link DWARFAttributeClass}).
+ *
+ * Users of this enum should be tolerant of unknown attribute id values. See
+ * {@link AttrDef#getRawAttributeId()}.
+ */
+public enum DWARFAttribute {
+ DW_AT_sibling(0x1, reference),
+ DW_AT_location(0x2, exprloc, loclist),
+ DW_AT_name(0x3, string),
+ DW_AT_ordering(0x9, constant),
+ //DW_AT_subscr_data(0xa),
+ DW_AT_byte_size(0xb, constant, exprloc, reference),
+ DW_AT_bit_offset(0xc), // dwarf-3
+ DW_AT_bit_size(0xd, constant, exprloc, reference),
+ //DW_AT_element_list(0xf),
+ DW_AT_stmt_list(0x10, lineptr),
+ DW_AT_low_pc(0x11, address),
+ DW_AT_high_pc(0x12, address, constant),
+ DW_AT_language(0x13, constant),
+ //DW_AT_member(0x14),
+ DW_AT_discr(0x15, reference),
+ DW_AT_discr_value(0x16, constant),
+ DW_AT_visibility(0x17, constant),
+ DW_AT_import(0x18, reference),
+ DW_AT_string_length(0x19, exprloc, loclist, reference),
+ DW_AT_common_reference(0x1a, reference),
+ DW_AT_comp_dir(0x1b, string),
+ DW_AT_const_value(0x1c, block, constant, string),
+ DW_AT_containing_type(0x1d, reference),
+ DW_AT_default_value(0x1e, constant, reference, flag),
+ DW_AT_inline(0x20, constant),
+ DW_AT_is_optional(0x21, flag),
+ DW_AT_lower_bound(0x22, constant, exprloc, reference),
+ DW_AT_producer(0x25, string),
+ DW_AT_prototyped(0x27, flag),
+ DW_AT_return_addr(0x2a, exprloc, loclist),
+ DW_AT_start_scope(0x2c, constant, rnglist),
+ DW_AT_bit_stride(0x2e, constant, exprloc, reference),
+ DW_AT_upper_bound(0x2f, constant, exprloc, reference),
+ DW_AT_abstract_origin(0x31, reference),
+ DW_AT_accessibility(0x32, constant),
+ DW_AT_address_class(0x33, constant),
+ DW_AT_artificial(0x34, flag),
+ DW_AT_base_types(0x35, reference),
+ DW_AT_calling_convention(0x36, constant),
+ DW_AT_count(0x37, constant, exprloc, reference),
+ DW_AT_data_member_location(0x38, constant, exprloc, loclist),
+ DW_AT_decl_column(0x39, constant),
+ DW_AT_decl_file(0x3a, constant),
+ DW_AT_decl_line(0x3b, constant),
+ DW_AT_declaration(0x3c, flag),
+ DW_AT_discr_list(0x3d, block),
+ DW_AT_encoding(0x3e, constant),
+ DW_AT_external(0x3f, flag),
+ DW_AT_frame_base(0x40, exprloc, loclist),
+ DW_AT_friend(0x41, reference),
+ DW_AT_identifier_case(0x42, constant),
+ DW_AT_macro_info(0x43, macptr),
+ DW_AT_namelist_item(0x44, reference),
+ DW_AT_priority(0x45, reference),
+ DW_AT_segment(0x46, exprloc, loclist),
+ DW_AT_specification(0x47, reference),
+ DW_AT_static_link(0x48, exprloc, loclist),
+ DW_AT_type(0x49, reference),
+ DW_AT_use_location(0x4a, exprloc, loclist),
+ DW_AT_variable_parameter(0x4b, flag),
+ DW_AT_virtuality(0x4c, constant),
+ DW_AT_vtable_elem_location(0x4d, exprloc, loclist),
+ DW_AT_allocated(0x4e, constant, exprloc, reference),
+ DW_AT_associated(0x4f, constant, exprloc, reference),
+ DW_AT_data_location(0x50, exprloc),
+ DW_AT_byte_stride(0x51, constant, exprloc, reference),
+ DW_AT_entry_pc(0x52, address, constant),
+ DW_AT_use_UTF8(0x53, flag),
+ DW_AT_extension(0x54, reference),
+ DW_AT_ranges(0x55, rnglist),
+ DW_AT_trampoline(0x56, address, flag, reference, string),
+ DW_AT_call_column(0x57, constant),
+ DW_AT_call_file(0x58, constant),
+ DW_AT_call_line(0x59, constant),
+ DW_AT_description(0x5a, string),
+ DW_AT_binary_scale(0x5b, constant),
+ DW_AT_decimal_scale(0x5c, constant),
+ DW_AT_small(0x5d, reference),
+ DW_AT_decimal_sign(0x5e, constant),
+ DW_AT_digit_count(0x5f, constant),
+ DW_AT_picture_string(0x60, string),
+ DW_AT_mutable(0x61, flag),
+ DW_AT_threads_scaled(0x62, flag),
+ DW_AT_explicit(0x63, flag),
+ DW_AT_object_pointer(0x64, reference),
+ DW_AT_endianity(0x65, constant),
+ DW_AT_elemental(0x66, flag),
+ DW_AT_pure(0x67, flag),
+ DW_AT_recursive(0x68, flag),
+ DW_AT_signature(0x69, reference),
+ DW_AT_main_subprogram(0x6a, flag),
+ DW_AT_data_bit_offset(0x6b, constant),
+ DW_AT_const_expr(0x6c, flag),
+ DW_AT_enum_class(0x6d, flag),
+ DW_AT_linkage_name(0x6e, string),
+ DW_AT_string_length_bit_size(0x6f, constant),
+ DW_AT_string_length_byte_size(0x70, constant),
+ DW_AT_rank(0x71, constant, exprloc),
+ DW_AT_str_offsets_base(0x72, stroffsetsptr),
+ DW_AT_addr_base(0x73, addrptr),
+ DW_AT_rnglists_base(0x74, rnglistsptr),
+ // 0x75 reserved, unused
+ DW_AT_dwo_name(0x76, string),
+ DW_AT_reference(0x77, flag),
+ DW_AT_rvalue_reference(0x78, flag),
+ DW_AT_macros(0x79, macptr),
+ DW_AT_call_all_calls(0x7a, flag),
+ DW_AT_call_all_source_calls(0x7b, flag),
+ DW_AT_call_all_tail_calls(0x7c, flag),
+ DW_AT_call_return_pc(0x7d, address),
+ DW_AT_call_value(0x7e, exprloc),
+ DW_AT_call_origin(0x7f, exprloc),
+ DW_AT_call_parameter(0x80, reference),
+ DW_AT_call_pc(0x81, address),
+ DW_AT_call_tail_call(0x82, flag),
+ DW_AT_call_target(0x83, exprloc),
+ DW_AT_call_target_clobbered(0x84, exprloc),
+ DW_AT_call_data_location(0x85, exprloc),
+ DW_AT_call_data_value(0x86, exprloc),
+ DW_AT_noreturn(0x87, flag),
+ DW_AT_alignment(0x88, constant),
+ DW_AT_export_symbols(0x89, flag),
+ DW_AT_deleted(0x8a, flag),
+ DW_AT_defaulted(0x8b, constant),
+ DW_AT_loclists_base(0x8c, loclistsptr),
+
+ DW_AT_lo_user(0x2000),
+ DW_AT_hi_user(0x3fff),
+ DW_AT_MIPS_linkage_name(0x2007),
+
+ // GNU DebugFission stuff
+ DW_AT_GNU_dwo_name(0x2130),
+ DW_AT_GNU_dwo_id(0x2131),
+ DW_AT_GNU_ranges_base(0x2132),
+ DW_AT_GNU_addr_base(0x2133),
+ DW_AT_GNU_pubnames(0x2134),
+ DW_AT_GNU_pubtypes(0x2135),
+ // end GNU DebugFission
+
+ // Golang
+ DW_AT_go_kind(0x2900),
+ DW_AT_go_key(0x2901),
+ DW_AT_go_elem(0x2902),
+ DW_AT_go_embedded_field(0x2903),
+ DW_AT_go_runtime_type(0x2904),
+ DW_AT_go_package_name(0x2905),
+ DW_AT_go_dict_index(0x2906),
+ // end Golang
+
+ // Apple proprietary tags
+ DW_AT_APPLE_ptrauth_key(0x3e04),
+ DW_AT_APPLE_ptrauth_address_discriminated(0x3e05),
+ DW_AT_APPLE_ptrauth_extra_discriminator(0x3e06),
+ DW_AT_APPLE_omit_frame_ptr(0x3fe7),
+ DW_AT_APPLE_optimized(0x3fe1);
+ // end Apple proprietary tags
+
+ private int id;
+ private Set attributeClass;
+
+ DWARFAttribute(int id, DWARFAttributeClass... attributeClass) {
+ this.id = id;
+ this.attributeClass = EnumSet.noneOf(DWARFAttributeClass.class);
+ this.attributeClass.addAll(List.of(attributeClass));
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public Set getAttributeClass() {
+ return attributeClass;
+ }
+
+ public static final int EOL = 0; // value used as end of attributespec list
+
+ public static DWARFAttribute of(int attributeInt) {
+ return lookupMap.get(attributeInt);
+ }
+
+ private static Map lookupMap = buildLookup();
+
+ private static Map buildLookup() {
+ Map result = new HashMap<>();
+ for (DWARFAttribute attr : values()) {
+ result.put(attr.id, attr);
+ }
+ return result;
+ }
+
+ /**
+ * Represents how a specific DWARF attribute is stored in a DIE record.
+ */
+ public static class AttrDef extends DWARFAttributeDef {
+
+ /**
+ * Reads a {@link DWARFAttribute.AttrDef} instance from the {@link BinaryReader reader}.
+ *
+ * Returns a null if its a end-of-list marker.
+ *
+ * @param reader {@link BinaryReader} abbr stream
+ * @return new {@link AttrDef}, or null if end-of-list
+ * @throws IOException if error reading
+ */
+ public static AttrDef read(BinaryReader reader) throws IOException {
+ DWARFAttributeDef tmp =
+ DWARFAttributeDef.read(reader, DWARFAttribute::of);
+ if (tmp == null) {
+ return null;
+ }
+
+ return new AttrDef(tmp.getAttributeId(), tmp.getRawAttributeId(),
+ tmp.getAttributeForm(), tmp.getImplicitValue());
+ }
+
+ public AttrDef(DWARFAttribute attributeId, int rawAttributeId,
+ DWARFForm attributeForm, long implicitValue) {
+ super(attributeId, rawAttributeId, attributeForm, implicitValue);
+ }
+
+ @Override
+ protected String getRawAttributeIdDescription() {
+ return "DW_AT_???? %d (0x%x)".formatted(attributeId, attributeId);
+ }
+
+ @Override
+ public AttrDef withForm(DWARFForm newForm) {
+ return new AttrDef(attributeId, rawAttributeId, newForm, implicitValue);
+ }
+
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBlobAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeClass.java
similarity index 53%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBlobAttribute.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeClass.java
index 8b35a33a6a..9d37b81674 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBlobAttribute.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeClass.java
@@ -13,30 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
-
-import java.util.Arrays;
+package ghidra.app.util.bin.format.dwarf.attribs;
/**
- * DWARF attribute with binary bytes.
+ * Categories that a DWARF attribute value may belong to.
*/
-public class DWARFBlobAttribute implements DWARFAttributeValue {
- private final byte[] bytes;
+public enum DWARFAttributeClass {
- public DWARFBlobAttribute(byte[] bytes) {
- this.bytes = bytes;
- }
+ address,
+ addrptr,
+ block,
+ constant,
+ exprloc,
+ flag,
+ lineptr,
+ loclist,
+ loclistsptr,
+ macptr,
+ reference,
+ rnglist,
+ rnglistsptr,
+ string,
+ stroffsetsptr
- public byte[] getBytes() {
- return bytes;
- }
-
- public int getLength() {
- return bytes.length;
- }
-
- @Override
- public String toString() {
- return "DWARFBlobAttribute: len=" + bytes.length + ", contents=" + Arrays.toString(bytes);
- }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeDef.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeDef.java
new file mode 100644
index 0000000000..56fb596bd9
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeDef.java
@@ -0,0 +1,159 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Function;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.DWARFAbbreviation;
+import ghidra.program.model.data.LEB128;
+
+/**
+ * Information about a single DWARF attribute, as specified in a
+ * {@link DWARFAbbreviation abbreviation}.
+ *
+ * This class handles the case where a specified attribute id is unknown to us (therefore not
+ * listed in the attribute enum class), as well as the case where the form is customized with
+ * an implicitValue.
+ *
+ * Unknown forms are not supported and cause an exception.
+ *
+ * @param attribute id enum type
+ */
+public class DWARFAttributeDef> {
+
+ /**
+ * Reads a {@link DWARFAttributeDef} instance from the {@link BinaryReader reader}.
+ *
+ * Returns a null if its a end-of-list marker (which is only used by an attributespec list).
+ *
+ * @param attribute id enum type
+ * @param reader {@link BinaryReader}
+ * @param mapper func that converts an attribute id int into its enum
+ * @return DWARFAttributeDef instance, or null if EOL marker was read from the stream
+ * @throws IOException if error reading
+ */
+ public static > DWARFAttributeDef read(BinaryReader reader,
+ Function mapper) throws IOException {
+
+ int attributeId = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+ int formId = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
+
+ if (attributeId == DWARFAttribute.EOL && formId == DWARFForm.EOL) {
+ // end of attributespec list
+ return null;
+ }
+
+ DWARFForm form = DWARFForm.of(formId);
+ if ( form == null ) {
+ throw new IOException("Unknown DWARFForm %d (0x%x)".formatted(formId, formId));
+ }
+
+ E e = mapper.apply(attributeId);
+
+ // NOTE: implicit value is a space saving hack built into DWARF. It adds an extra
+ // field in the attributespec that needs to be read.
+ long implicitValue = form == DWARFForm.DW_FORM_indirect // read leb128 if present
+ ? reader.readNext(LEB128::signed)
+ : 0;
+
+ return new DWARFAttributeDef<>(e, attributeId, form, implicitValue);
+ }
+
+ protected final E attributeId;
+ protected final DWARFForm attributeForm;
+ protected final int rawAttributeId;
+ protected final long implicitValue;
+
+ public DWARFAttributeDef(E attributeId, int rawAttributeId, DWARFForm attributeForm,
+ long implicitValue) {
+ this.attributeId = attributeId;
+ this.rawAttributeId = rawAttributeId;
+ this.attributeForm = attributeForm;
+ this.implicitValue = implicitValue;
+ }
+
+ /**
+ * Get the attribute id of the attribute specification.
+ * @return the attribute value
+ */
+ public E getAttributeId() {
+ return attributeId;
+ }
+
+ public int getRawAttributeId() {
+ return rawAttributeId;
+ }
+
+ public String getAttributeName() {
+ return attributeId != null
+ ? attributeId.name()
+ : getRawAttributeIdDescription();
+ }
+
+ protected String getRawAttributeIdDescription() {
+ return "unknown attribute id %d (0x%x)".formatted(rawAttributeId, rawAttributeId);
+ }
+
+ /**
+ * Get the form of the attribute specification.
+ * @return the form value
+ */
+ public DWARFForm getAttributeForm() {
+ return this.attributeForm;
+ }
+
+ public boolean isImplicit() {
+ return attributeForm == DW_FORM_implicit_const;
+ }
+
+ public long getImplicitValue() {
+ return implicitValue;
+ }
+
+ public DWARFAttributeDef withForm(DWARFForm newForm) {
+ return new DWARFAttributeDef<>(attributeId, rawAttributeId, newForm, implicitValue);
+ }
+
+ @Override
+ public String toString() {
+ return getAttributeName() + "->" + getAttributeForm();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(attributeForm, attributeId, implicitValue, rawAttributeId);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof DWARFAttributeDef)) {
+ return false;
+ }
+ DWARFAttributeDef other = (DWARFAttributeDef) obj;
+ return attributeForm == other.attributeForm &&
+ Objects.equals(attributeId, other.attributeId) &&
+ implicitValue == other.implicitValue && rawAttributeId == other.rawAttributeId;
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeValue.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeValue.java
new file mode 100644
index 0000000000..fc491f5848
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeValue.java
@@ -0,0 +1,43 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
+
+/**
+ * Base class for all DWARF attribute value implementations.
+ */
+public abstract class DWARFAttributeValue {
+
+ protected final DWARFAttributeDef> def;
+
+ public DWARFAttributeValue(DWARFAttributeDef> def) {
+ this.def = def;
+ }
+
+ public DWARFForm getAttributeForm() {
+ return def.getAttributeForm();
+ }
+
+ public String getAttributeName() {
+ return def.getAttributeName();
+ }
+
+ public String toString(DWARFCompilationUnit compilationUnit) {
+ return toString();
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBlobAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBlobAttribute.java
new file mode 100644
index 0000000000..2680fd43a7
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBlobAttribute.java
@@ -0,0 +1,56 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
+import ghidra.app.util.bin.format.dwarf.expression.*;
+import ghidra.util.NumericUtilities;
+
+/**
+ * DWARF attribute with binary bytes.
+ */
+public class DWARFBlobAttribute extends DWARFAttributeValue {
+ private final byte[] bytes;
+
+ public DWARFBlobAttribute(byte[] bytes, DWARFAttributeDef> def) {
+ super(def);
+ this.bytes = bytes;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public int getLength() {
+ return bytes.length;
+ }
+
+ public DWARFExpressionEvaluator evaluateExpression(DWARFCompilationUnit cu)
+ throws DWARFExpressionException {
+
+ DWARFExpressionEvaluator exprEvaluator = new DWARFExpressionEvaluator(cu);
+ DWARFExpression expr = exprEvaluator.readExpr(bytes);
+ exprEvaluator.evaluate(expr);
+
+ return exprEvaluator;
+ }
+
+ @Override
+ public String toString() {
+ return "%s : %s = [%d]%s".formatted(getAttributeName(), getAttributeForm(), bytes.length,
+ NumericUtilities.convertBytesToString(bytes, " "));
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBooleanAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBooleanAttribute.java
similarity index 62%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBooleanAttribute.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBooleanAttribute.java
index 9a22dddd1b..15544e6634 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFBooleanAttribute.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFBooleanAttribute.java
@@ -13,22 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
+package ghidra.app.util.bin.format.dwarf.attribs;
/**
* DWARF boolean attribute.
*/
-public class DWARFBooleanAttribute implements DWARFAttributeValue {
- public static final DWARFBooleanAttribute TRUE = new DWARFBooleanAttribute(true);
- public static final DWARFBooleanAttribute FALSE = new DWARFBooleanAttribute(false);
-
- public static DWARFBooleanAttribute get(boolean b) {
- return b ? TRUE : FALSE;
- }
-
+public class DWARFBooleanAttribute extends DWARFAttributeValue {
private final boolean value;
- public DWARFBooleanAttribute(boolean value) {
+ public DWARFBooleanAttribute(boolean value, DWARFAttributeDef> def) {
+ super(def);
this.value = value;
}
@@ -38,6 +32,6 @@ public class DWARFBooleanAttribute implements DWARFAttributeValue {
@Override
public String toString() {
- return "DWARFBooleanAttribute: " + value;
+ return "%s : %s = %s".formatted(getAttributeName(), getAttributeForm(), getValue());
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFDeferredStringAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFDeferredStringAttribute.java
similarity index 57%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFDeferredStringAttribute.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFDeferredStringAttribute.java
index fdfe9b744d..000e17e924 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFDeferredStringAttribute.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFDeferredStringAttribute.java
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
-
-import ghidra.app.util.bin.format.dwarf4.next.StringTable;
+package ghidra.app.util.bin.format.dwarf.attribs;
import java.io.IOException;
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
+import ghidra.util.Msg;
+
/**
* DWARF string attribute, where getting the value from the string table is deferred
* until requested for the first time.
@@ -26,27 +27,39 @@ import java.io.IOException;
public class DWARFDeferredStringAttribute extends DWARFStringAttribute {
private long offset;
- public DWARFDeferredStringAttribute(long offset) {
- super(null);
+ public DWARFDeferredStringAttribute(long offset, DWARFAttributeDef> def) {
+ super(null, def);
this.offset = offset;
}
@Override
- public String getValue(StringTable stringTable) {
+ public String getValue(DWARFCompilationUnit cu) {
if (value == null) {
try {
- value = stringTable.getStringAtOffset(offset);
+ value = cu.getProgram().getString(getAttributeForm(), offset, cu);
}
catch (IOException e) {
+ Msg.error(this, "error getting string value", e);
return null;
}
}
return value;
}
- @Override
- public String toString() {
- return "DWARFDeferredStringAttribute [ offset=" + offset + ", value=" + value + "]";
+ public long getOffset() {
+ return offset;
}
+ @Override
+ public String toString(DWARFCompilationUnit cu) {
+ String str = value == null && cu != null ? getValue(cu) : value;
+ str = str != null ? "\"%s\"".formatted(value) : "-missing-";
+ return "%s : %s = %s (offset 0x%x)".formatted(getAttributeName(), getAttributeForm(), str,
+ offset);
+ }
+
+ @Override
+ public String toString() {
+ return toString(null);
+ }
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java
new file mode 100644
index 0000000000..5caee63b24
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java
@@ -0,0 +1,425 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeClass.*;
+
+import java.io.IOException;
+import java.util.*;
+
+import ghidra.app.util.bin.LEB128Info;
+import ghidra.program.model.data.LEB128;
+
+/**
+ * DWARF attribute encodings.
+ *
+ * Unknown encodings will prevent deserialization of DIE records.
+ */
+public enum DWARFForm {
+
+ DW_FORM_addr(0x1, DWARFForm.DYNAMIC_SIZE, address) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ return context.compUnit().getPointerSize();
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFNumericAttribute(
+ context.reader().readNextUnsignedValue(context.compUnit().getPointerSize()),
+ context.def());
+ }
+ },
+ DW_FORM_block2(0x3, DWARFForm.DYNAMIC_SIZE, block) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ int arraySize = context.reader().readNextUnsignedShort();
+ return 2 /*sizeof short */ + arraySize;
+ }
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedShort();
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(length),
+ context.def());
+ }
+ },
+ DW_FORM_block4(0x4, DWARFForm.DYNAMIC_SIZE, block) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ int arraySize = context.reader().readNextUnsignedIntExact();
+ return 4 /*sizeof int */ + arraySize;
+ }
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedIntExact();
+ if (length < 0 || length > MAX_BLOCK4_SIZE) {
+ throw new IOException("Invalid/bad dw_form_block4 size: " + length);
+ }
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(length),
+ context.def());
+ }
+ },
+ DW_FORM_data2(0x5, 2, constant),
+ DW_FORM_data4(0x6, 4, constant),
+ DW_FORM_data8(0x7, 8, constant) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFNumericAttribute(64, context.reader().readNextLong(), true, true,
+ context.def());
+ }
+ },
+ DW_FORM_string(0x8, DWARFForm.DYNAMIC_SIZE, string) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ long start = context.reader().getPointerIndex();
+ context.reader().readNextUtf8String();
+ return context.reader().getPointerIndex() - start;
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFStringAttribute(context.reader().readNextUtf8String(), context.def());
+ }
+ },
+ DW_FORM_block(0x9, DWARFForm.DYNAMIC_SIZE, block) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ LEB128Info uleb128 = context.reader().readNext(LEB128Info::unsigned);
+ return uleb128.getLength() + uleb128.asUInt32();
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ if (length < 0 || length > MAX_BLOCK4_SIZE) {
+ throw new IOException("Invalid/bad dw_form_block size: " + length);
+ }
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(length),
+ context.def());
+ }
+ },
+ DW_FORM_block1(0xa, DWARFForm.DYNAMIC_SIZE, block) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedByte();
+ return 1 /* sizeof byte */ + length;
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedByte();
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(length),
+ context.def());
+ }
+ },
+ DW_FORM_data1(0xb, 1, constant),
+ DW_FORM_flag(0xc, 1, flag) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFBooleanAttribute(context.reader().readNextByte() != 0, context.def());
+ }
+ },
+ DW_FORM_sdata(0xd, DWARFForm.LEB128_SIZE, constant) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFNumericAttribute(64, context.reader().readNext(LEB128::signed), true,
+ context.def());
+ }
+ },
+ DW_FORM_strp(0xe, DWARFForm.DWARF_INTSIZE, string) {
+ // offset in .debug_str
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ long stringOffset = context.reader().readNextUnsignedValue(context.dwarfIntSize());
+ return new DWARFDeferredStringAttribute(stringOffset, context.def());
+ }
+ },
+ DW_FORM_udata(0xf, DWARFForm.LEB128_SIZE, constant) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFNumericAttribute(64, context.reader().readNext(LEB128::unsigned), false,
+ context.def());
+ }
+ },
+ DW_FORM_ref_addr(0x10, DWARFForm.DWARF_INTSIZE, reference) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ long addr = context.reader().readNextUnsignedValue(context.dwarfIntSize());
+ return new DWARFNumericAttribute(addr, context.def());
+ }
+ },
+ DW_FORM_ref1(0x11, 1, reference),
+ DW_FORM_ref2(0x12, 2, reference),
+ DW_FORM_ref4(0x13, 4, reference),
+ DW_FORM_ref8(0x14, 8, reference),
+ DW_FORM_ref_udata(0x15, DWARFForm.LEB128_SIZE, constant) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ long uoffset = context.reader().readNext(LEB128::unsigned);
+ return new DWARFNumericAttribute(uoffset + context.compUnit().getStartOffset(),
+ context.def());
+ }
+ },
+ DW_FORM_indirect(0x16, DWARFForm.DYNAMIC_SIZE /* value class will depend on the indirect form*/ ) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ long start = context.reader().getPointerIndex();
+ int indirectFormInt = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ long firstSize = context.reader().getPointerIndex() - start;
+
+ DWARFForm indirectForm = DWARFForm.of(indirectFormInt);
+ DWARFAttributeDef> indirectAS = context.def().withForm(indirectForm);
+ DWARFFormContext indirectContext =
+ new DWARFFormContext(context.reader(), context.compUnit(), indirectAS);
+ long indirectSize = indirectForm.getSize(indirectContext);
+
+ return firstSize + indirectSize;
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int indirectFormInt = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ DWARFForm indirectForm = DWARFForm.of(indirectFormInt);
+ DWARFAttributeDef> indirectAS = context.def().withForm(indirectForm);
+ DWARFFormContext indirectContext =
+ new DWARFFormContext(context.reader(), context.compUnit(), indirectAS);
+ return indirectForm.readValue(indirectContext);
+ }
+ },
+ DW_FORM_sec_offset(0x17, DWARFForm.DWARF_INTSIZE, addrptr, lineptr, loclist, loclistsptr, macptr, rnglist, rnglistsptr, stroffsetsptr) {
+ // offset in a section other than .debug_info or .debug_str
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ long addr = context.reader().readNextUnsignedValue(context.dwarfIntSize());
+ return new DWARFNumericAttribute(addr, context.def());
+ }
+ },
+ DW_FORM_exprloc(0x18, DWARFForm.DYNAMIC_SIZE, exprloc) {
+ @Override
+ public long getSize(DWARFFormContext context) throws IOException {
+ LEB128Info uleb128 = context.reader().readNext(LEB128Info::unsigned);
+ return uleb128.getLength() + uleb128.asInt32();
+ }
+
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int length = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ if (length < 0 || length > MAX_BLOCK4_SIZE) {
+ throw new IOException("Invalid/bad dw_form_exprloc size: " + length);
+ }
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(length),
+ context.def());
+
+ }
+ },
+ DW_FORM_flag_present(0x19, 0, flag) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFBooleanAttribute(true, context.def());
+ }
+ },
+ DW_FORM_strx(0x1a, DWARFForm.LEB128_SIZE, string) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int index = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ return new DWARFDeferredStringAttribute(index, context.def());
+ }
+ },
+ DW_FORM_addrx(0x1b, DWARFForm.LEB128_SIZE, address) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ int index = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned);
+ return new DWARFIndirectAttribute(index, context.def());
+ }
+ },
+ DW_FORM_ref_sup4(0x1c, 4, reference), // unimpl
+ DW_FORM_strp_sup(0x1d, DWARFForm.DWARF_INTSIZE, string), // unimpl
+ DW_FORM_data16(0x1e, 16, constant) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFBlobAttribute(context.reader().readNextByteArray(16), context.def());
+ }
+ },
+ DW_FORM_line_strp(0x1f, DWARFForm.DWARF_INTSIZE, string) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFDeferredStringAttribute(
+ context.reader().readNextUnsignedValue(context.dwarfIntSize()), context.def());
+ }
+ },
+ DW_FORM_ref_sig8(0x20, 8, reference), // unimpl
+ DW_FORM_implicit_const(0x21, 0) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFNumericAttribute(64, context.def().getImplicitValue(), true,
+ context.def());
+ }
+ },
+ DW_FORM_loclistx(0x22, DWARFForm.LEB128_SIZE, loclist) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFIndirectAttribute(context.reader().readNext(LEB128::unsigned),
+ context.def());
+ }
+ },
+ DW_FORM_rnglistx(0x23, DWARFForm.LEB128_SIZE, rnglist) {
+ @Override
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ return new DWARFIndirectAttribute(context.reader().readNext(LEB128::unsigned),
+ context.def());
+ }
+ },
+ DW_FORM_ref_sup8(0x24, 8, reference), // unimpl
+ DW_FORM_strx1(0x25, 1, string),
+ DW_FORM_strx2(0x26, 2, string),
+ DW_FORM_strx3(0x27, 3, string),
+ DW_FORM_strx4(0x28, 4, string),
+ DW_FORM_addrx1(0x29, 1, address),
+ DW_FORM_addrx2(0x2a, 2, address),
+ DW_FORM_addrx3(0x2b, 3, address),
+ DW_FORM_addrx4(0x2c, 4, address);
+
+ private final int id;
+ /**
+ * The static size of values of this type, or one of the special values {@link #DYNAMIC_SIZE},
+ * {@link #DWARF_INTSIZE}, {@link #LEB128_SIZE}
+ */
+ private final int size;
+ private final Set attributeClasses;
+
+ private static final Map lookupMap = buildLookupmap();
+
+ DWARFForm(int id, int size, DWARFAttributeClass... attributeClasses) {
+ this.id = id;
+ this.size = size;
+ this.attributeClasses = EnumSet.noneOf(DWARFAttributeClass.class);
+ this.attributeClasses.addAll(List.of(attributeClasses));
+ }
+
+ /**
+ * Returns the id of this DWARFForm.
+ *
+ * @return DWARFForm numeric id
+ */
+ public int getId() {
+ return this.id;
+ }
+
+ public Set getFormClasses() {
+ return attributeClasses;
+ }
+
+ public boolean isClass(DWARFAttributeClass attrClass) {
+ return attributeClasses.size() == 1 && attributeClasses.contains(attrClass);
+ }
+
+ /**
+ * Returns the size the attribute value occupies in the stream.
+ *
+ * This default implementation handles static sizes, as well as LEB128 and DWARF_INT sizes.
+ * DWARFForms that are more complex and marked as {@link #DYNAMIC_SIZE} will need to override
+ * this method and provide custom logic to determine the size of a value.
+ *
+ * @param context {@link DWARFFormContext}
+ * @return size of the attribute value
+ * @throws IOException if error reading
+ */
+ public long getSize(DWARFFormContext context) throws IOException {
+ switch (size) {
+ case DWARF_INTSIZE:
+ return context.compUnit().getIntSize();
+ case LEB128_SIZE:
+ return context.reader().readNext(LEB128::getLength);
+ case DYNAMIC_SIZE:
+ throw new IOException("Unimplemented size for " + this);
+ default:
+ return size;
+ }
+ }
+
+ /**
+ * Reads a DIE attribute value from a stream.
+ *
+ * @param context {@link DWARFFormContext}
+ * @return {@link DWARFAttributeValue}
+ * @throws IOException if error reading
+ */
+ public DWARFAttributeValue readValue(DWARFFormContext context) throws IOException {
+ switch (this) {
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4: {
+ long index = context.reader().readNextUnsignedValue(size);
+ return new DWARFIndirectAttribute(index, context.def());
+ }
+
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8: {
+ long val = context.reader().readNextValue(size);
+ return new DWARFNumericAttribute(size * 8, val, true, true, context.def());
+ }
+
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8: {
+ long uoffset = context.reader().readNextUnsignedValue(size);
+ return new DWARFNumericAttribute(uoffset + context.compUnit().getStartOffset(),
+ context.def());
+ }
+
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4: {
+ long index = context.reader().readNextUnsignedValue(size);
+ return new DWARFDeferredStringAttribute(index, context.def());
+ }
+
+ default:
+ throw new IllegalArgumentException("Unsupported DWARF Form: " + this);
+ }
+ }
+
+ public static final int EOL = 0; // value used as end of attributespec list
+
+ /**
+ * Find the form value given raw int.
+ *
+ * @param key value to check
+ * @return DWARFForm enum, or null if it is an unknown form
+ */
+ public static DWARFForm of(int key) {
+ return lookupMap.get(key);
+ }
+
+ private static Map buildLookupmap() {
+ Map result = new HashMap<>();
+ for (DWARFForm form : DWARFForm.values()) {
+ result.put(form.getId(), form);
+ }
+ return result;
+
+ }
+
+ public static final int MAX_BLOCK4_SIZE = 1024 * 1024;
+ private static final int LEB128_SIZE = -3;
+ private static final int DWARF_INTSIZE = -2;
+ private static final int DYNAMIC_SIZE = -1;
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java
new file mode 100644
index 0000000000..bab61a90cb
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java
@@ -0,0 +1,39 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.format.dwarf.*;
+
+/**
+ * Context given to the {@link DWARFForm#readValue(DWARFFormContext)} method to enable it to
+ * create {@link DWARFAttributeValue}s.
+ *
+ * @param reader {@link BinaryReader}
+ * @param compUnit {@link DWARFCompilationUnit}
+ * @param def {@link DWARFAttributeDef}
+ */
+public record DWARFFormContext(BinaryReader reader, DWARFCompilationUnit compUnit,
+ DWARFAttributeDef> def) {
+
+ DWARFProgram dprog() {
+ return compUnit.getProgram();
+ }
+
+ int dwarfIntSize() {
+ return compUnit.getIntSize();
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java
new file mode 100644
index 0000000000..f08634c758
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java
@@ -0,0 +1,72 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
+import ghidra.app.util.bin.format.dwarf.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames;
+
+/**
+ * DWARF numeric attribute value that is an index into a lookup table
+ */
+public class DWARFIndirectAttribute extends DWARFNumericAttribute {
+
+ public DWARFIndirectAttribute(long index, DWARFAttributeDef> def) {
+ super(index, def);
+ }
+
+ public int getIndex() throws IOException {
+ return getUnsignedIntExact();
+ }
+
+ @Override
+ public String toString(DWARFCompilationUnit cu) {
+ try {
+ DWARFProgram prog = cu.getProgram();
+ int index = getIndex();
+ long offset = prog.getOffsetOfIndexedElement(getAttributeForm(), index, cu);
+ if (getAttributeForm().isClass(DWARFAttributeClass.address)) {
+ return "%s : %s, addr v%d 0x%x (idx %d)".formatted(getAttributeName(),
+ getAttributeForm(), cu.getDWARFVersion(), offset, index);
+ }
+ else if (getAttributeForm().isClass(DWARFAttributeClass.rnglist)) {
+ return toElementLocationString("rnglist", DWARFSectionNames.DEBUG_RNGLISTS, index,
+ offset, cu.getDWARFVersion());
+ }
+ else if (getAttributeForm().isClass(DWARFAttributeClass.loclist)) {
+ return toElementLocationString("loclist", DWARFSectionNames.DEBUG_LOCLISTS, index,
+ offset, cu.getDWARFVersion());
+ }
+ else if (getAttributeForm().isClass(DWARFAttributeClass.string)) {
+ return toElementLocationString("string", DWARFSectionNames.DEBUG_LOCLISTS, index,
+ offset, cu.getDWARFVersion());
+ }
+ }
+ catch (IOException e) {
+ // fall thru to default
+ }
+ return super.toString(cu);
+ }
+
+ @Override
+ public String toString() {
+ long index = getUnsignedValue();
+ return "%s : %s, index/offset %d [0x%x]".formatted(getAttributeName(), getAttributeForm(),
+ index, index);
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java
new file mode 100644
index 0000000000..9f86eb8872
--- /dev/null
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java
@@ -0,0 +1,148 @@
+/* ###
+ * 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.dwarf.attribs;
+
+import java.io.IOException;
+
+import ghidra.app.util.bin.InvalidDataException;
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames;
+import ghidra.program.model.scalar.Scalar;
+
+/**
+ * DWARF numeric attribute.
+ */
+public class DWARFNumericAttribute extends DWARFAttributeValue {
+
+ private final Scalar value;
+ private final boolean ambiguous;
+
+ /**
+ * Creates a new numeric value, using 64 bits and marked as signed
+ *
+ * @param value long 64 bit value
+ * @param def attribute id and form of this value
+ */
+ public DWARFNumericAttribute(long value, DWARFAttributeDef> def) {
+ this(64, value, true, false, def);
+ }
+
+ /**
+ * Creates a new numeric value, using the specific bitLength and value.
+ *
+ * @param bitLength number of bits, valid values are 1..64, or 0 if value is also 0
+ * @param value value of the scalar, any bits that are set above bitLength will be ignored
+ * @param signed true for a signed value, false for an unsigned value.
+ * @param def attribute id and form of this value
+ */
+ public DWARFNumericAttribute(int bitLength, long value, boolean signed,
+ DWARFAttributeDef> def) {
+ this(bitLength, value, signed, false, def);
+ }
+
+ /**
+ * Creates a new numeric value, using the specific bitLength and value.
+ *
+ * @param bitLength number of bits, valid values are 1..64, or 0 if value is also 0
+ * @param value value of the scalar, any bits that are set above bitLength will be ignored
+ * @param signed true for a signed value, false for an unsigned value.
+ * @param ambiguous true for value with ambiguous signedness ({@code signed} parameter should
+ * not be trusted), false for value where the {@code signed} parameter is known to be correct
+ * @param def attribute id and form of this value
+ */
+ public DWARFNumericAttribute(int bitLength, long value, boolean signed, boolean ambiguous,
+ DWARFAttributeDef> def) {
+ super(def);
+ this.value = new Scalar(bitLength, value, signed);
+ this.ambiguous = ambiguous;
+ }
+
+ /**
+ * {@return boolean flag, if true this value's signedness is up to the user of the value,
+ * if false the signedness was determined when the value was constructed}
+ */
+ public boolean isAmbiguousSignedness() {
+ return ambiguous;
+ }
+
+ /**
+ * {@return the value, forcing the signedness of ambiguous values using the specified hint}
+ * @param signednessHint true to default to a signed value, false to default to an
+ * unsigned value
+ */
+ public long getValueWithSignednessHint(boolean signednessHint) {
+ return value.getValue(ambiguous ? signednessHint : value.isSigned());
+ }
+
+ public boolean isHighbitSet() {
+ return value.bitLength() > 0 ? value.testBit(value.bitLength() - 1) : false;
+ }
+
+ public long getValue() {
+ return value.getValue();
+ }
+
+ public long getUnsignedValue() {
+ return value.getUnsignedValue();
+ }
+
+ public int getUnsignedIntExact() throws IOException {
+ long x = value.getUnsignedValue();
+ if (x < 0 || Integer.MAX_VALUE < x) {
+ throw new InvalidDataException(
+ "Value out of range for positive java 32 bit unsigned int: %d [0x%d]".formatted(x,
+ x));
+ }
+ return (int) x;
+ }
+
+ public String toElementLocationString(String elementType, String sectionName, int index,
+ long offset, int ver) {
+ String indexStr = index >= 0 ? " (idx %d)".formatted(index) : "";
+ return "%s : %s, %s v%d %s:%x%s".formatted(getAttributeName(), getAttributeForm(),
+ elementType, ver, sectionName, offset, indexStr);
+ }
+
+ @Override
+ public String toString(DWARFCompilationUnit cu) {
+ short ver = cu.getDWARFVersion();
+ if (getAttributeForm().isClass(DWARFAttributeClass.address)) {
+ return "%s : %s, addr v%d 0x%x".formatted(getAttributeName(), getAttributeForm(), ver,
+ getUnsignedValue());
+ }
+ else if (getAttributeForm().isClass(DWARFAttributeClass.rnglist)) {
+ String sectionName =
+ ver < 5 ? DWARFSectionNames.DEBUG_RANGES : DWARFSectionNames.DEBUG_RNGLISTS;
+ return toElementLocationString("rnglist", sectionName, -1, getUnsignedValue(),
+ cu.getDWARFVersion()) + " offset: " + getUnsignedValue();
+ }
+ else if (getAttributeForm().isClass(DWARFAttributeClass.loclist)) {
+ String sectionName =
+ ver < 5 ? DWARFSectionNames.DEBUG_LOC : DWARFSectionNames.DEBUG_LOCLISTS;
+ return toElementLocationString("loclist", sectionName, -1, getUnsignedValue(),
+ cu.getDWARFVersion());
+ }
+ return toString();
+ }
+
+ @Override
+ public String toString() {
+ String orStr =
+ ambiguous && isHighbitSet() ? " or " + value.getValue(!value.isSigned()) : "";
+ return "%s : %s = %d%s [%s]".formatted(getAttributeName(), getAttributeForm(), getValue(),
+ orStr, value.toString(16, true, false, "", ""));
+ }
+}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFStringAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFStringAttribute.java
similarity index 64%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFStringAttribute.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFStringAttribute.java
index 27d112cad7..14a742e592 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFStringAttribute.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFStringAttribute.java
@@ -13,26 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
+package ghidra.app.util.bin.format.dwarf.attribs;
-import ghidra.app.util.bin.format.dwarf4.next.StringTable;
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
/**
* DWARF string attribute.
*/
-public class DWARFStringAttribute implements DWARFAttributeValue {
+public class DWARFStringAttribute extends DWARFAttributeValue {
protected String value;
- public DWARFStringAttribute(String value) {
+ public DWARFStringAttribute(String value, DWARFAttributeDef> def) {
+ super(def);
this.value = value;
}
- public String getValue(StringTable stringTable) {
+ public String getValue(DWARFCompilationUnit cu) {
return value;
}
@Override
public String toString() {
- return "DWARFStringAttribute: [" + value + "]";
+ return "%s : %s = \"%s\"".formatted(getAttributeName(), getAttributeForm(), value);
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpression.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpression.java
similarity index 92%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpression.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpression.java
index 9a6ece3d8a..c48eb7e948 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpression.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpression.java
@@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-import java.io.IOException;
-
import ghidra.app.util.bin.*;
-import ghidra.app.util.bin.format.dwarf4.*;
+import ghidra.app.util.bin.format.dwarf.DIEAggregate;
import ghidra.program.model.data.LEB128;
import ghidra.util.NumericUtilities;
@@ -33,6 +32,7 @@ import ghidra.util.NumericUtilities;
*/
public class DWARFExpression {
static long EMPTY_OPERANDS_VALUE[] = {};
+ public static final int MAX_SANE_EXPR = 256;
private final List operations;
@@ -41,7 +41,7 @@ public class DWARFExpression {
public static String exprToString(byte[] exprBytes, DIEAggregate diea) {
try {
DWARFExpression expr =
- DWARFExpressionEvaluator.create(diea.getHeadFragment()).readExpr(exprBytes);
+ new DWARFExpressionEvaluator(diea.getCompilationUnit()).readExpr(exprBytes);
return expr.toString();
}
catch (DWARFExpressionException e) {
@@ -51,14 +51,14 @@ public class DWARFExpression {
}
public static DWARFExpression read(byte[] exprBytes, byte addrSize, boolean isLittleEndian,
- int dwarf_format) throws DWARFExpressionException {
+ int intSize) throws DWARFExpressionException {
ByteProvider provider = new ByteArrayProvider(exprBytes);
BinaryReader reader = new BinaryReader(provider, isLittleEndian);
- return read(reader, addrSize, dwarf_format);
+ return read(reader, addrSize, intSize);
}
- public static DWARFExpression read(BinaryReader reader, byte addrSize, int dwarf_format)
+ public static DWARFExpression read(BinaryReader reader, byte addrSize, int intSize)
throws DWARFExpressionException {
List operations = new ArrayList<>();
@@ -91,8 +91,7 @@ public class DWARFExpression {
blob = readSizedBlobOperand(reader, operandValues[i - 1]);
}
else {
- operandValues[i] =
- readOperandValue(optype, reader, addrSize, dwarf_format);
+ operandValues[i] = readOperandValue(optype, reader, addrSize, intSize);
}
}
@@ -117,11 +116,11 @@ public class DWARFExpression {
}
private static long readOperandValue(DWARFExpressionOperandType operandType,
- BinaryReader reader, byte addrSize, int dwarf_format) throws IOException {
+ BinaryReader reader, byte addrSize, int intSize) throws IOException {
try {
switch (operandType) {
case ADDR:
- return DWARFUtil.readAddressAsLong(reader, addrSize);
+ return reader.readNextUnsignedValue(addrSize);
case S_BYTE:
return reader.readNextByte();
case S_SHORT:
@@ -145,9 +144,7 @@ public class DWARFExpression {
case SIZED_BLOB:
throw new IOException("Can't read SIZED_BLOB as a Long value");
case DWARF_INT:
- return (dwarf_format == DWARFCompilationUnit.DWARF_32)
- ? reader.readNextUnsignedInt()
- : reader.readNextLong();
+ return reader.readNextUnsignedValue(intSize);
}
}
catch (ArrayIndexOutOfBoundsException aioob) {
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java
similarity index 94%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluator.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java
index 61c8feeb22..046e406582 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java
@@ -13,17 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
-import static ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes.*;
+import static ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionOpCodes.*;
import java.util.ArrayDeque;
import java.util.Objects;
-import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
-import ghidra.app.util.bin.format.dwarf4.DebugInfoEntry;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFRegisterMappings;
+import ghidra.app.util.bin.format.dwarf.*;
import ghidra.program.model.lang.Register;
/**
@@ -44,7 +41,7 @@ public class DWARFExpressionEvaluator {
*/
private static final int DEFAULT_MAX_STEP_COUNT = 1000;
- private final int dwarfFormat;
+ private final int intSize;
private int maxStepCount = DEFAULT_MAX_STEP_COUNT;
@@ -89,20 +86,16 @@ public class DWARFExpressionEvaluator {
private DWARFExpressionOperation currentOp;
private int currentOpIndex = -1;
- public static DWARFExpressionEvaluator create(DebugInfoEntry die) {
- DWARFCompilationUnit compUnit = die.getCompilationUnit();
- DWARFProgram prog = die.getProgram();
- DWARFExpressionEvaluator evaluator = new DWARFExpressionEvaluator(compUnit.getPointerSize(),
- !prog.isBigEndian(), compUnit.getFormat(), prog.getRegisterMappings());
-
- return evaluator;
+ public DWARFExpressionEvaluator(DWARFCompilationUnit cu) {
+ this(cu.getPointerSize(), cu.getProgram().isLittleEndian(), cu.getIntSize(),
+ cu.getProgram().getRegisterMappings());
}
- public DWARFExpressionEvaluator(byte pointerSize, boolean isLittleEndian, int dwarfFormat,
+ public DWARFExpressionEvaluator(byte pointerSize, boolean isLittleEndian, int intSize,
DWARFRegisterMappings registerMappings) {
this.pointerSize = pointerSize;
this.isLittleEndian = isLittleEndian;
- this.dwarfFormat = dwarfFormat;
+ this.intSize = intSize;
this.registerMappings =
Objects.requireNonNullElse(registerMappings, DWARFRegisterMappings.DUMMY);
}
@@ -151,7 +144,7 @@ public class DWARFExpressionEvaluator {
public DWARFExpression readExpr(byte[] exprBytes) throws DWARFExpressionException {
DWARFExpression tmp =
- DWARFExpression.read(exprBytes, pointerSize, isLittleEndian, dwarfFormat);
+ DWARFExpression.read(exprBytes, pointerSize, isLittleEndian, intSize);
return tmp;
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeValue.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorContext.java
similarity index 75%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeValue.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorContext.java
index 2b522dcd5f..2d2738bce3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeValue.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorContext.java
@@ -13,11 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
+package ghidra.app.util.bin.format.dwarf.expression;
-/**
- * Base interface for all DWARF attribute value implementations. Not much here.
- */
-public interface DWARFAttributeValue {
+import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit;
-}
+public record DWARFExpressionEvaluatorContext(DWARFCompilationUnit cu) {}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionException.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionException.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionException.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionException.java
index 63d7227e76..ada4392161 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionException.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionException.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
/**
* A exception that is thrown when dealing with {@link DWARFExpression DWARF expressions}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOpCodes.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOpCodes.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOpCodes.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOpCodes.java
index f3f5780659..6afbd81374 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOpCodes.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOpCodes.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
-import static ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOperandType.*;
+import static ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionOperandType.*;
import java.lang.reflect.Field;
import java.util.*;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
/**
* DWARF expression opcode consts from www.dwarfstd.org/doc/DWARF4.pdf
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperandType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperandType.java
similarity index 96%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperandType.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperandType.java
index 7e6dcb7b36..9712e4789a 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperandType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperandType.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
/**
* Enumeration that represents the different type of operands that a
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperation.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperation.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperation.java
index bdcbdd5066..6eee3a9f75 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionOperation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionOperation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
import java.util.Arrays;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionResult.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionResult.java
similarity index 95%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionResult.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionResult.java
index 3cf3235bed..2e40c7156b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionResult.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionResult.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
import java.util.ArrayDeque;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/BuildIdSearchLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/BuildIdSearchLocation.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/BuildIdSearchLocation.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/BuildIdSearchLocation.java
index 6fbc28fd32..c3e4adc0a6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/BuildIdSearchLocation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/BuildIdSearchLocation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.File;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/DWARFExternalDebugFilesPlugin.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/DWARFExternalDebugFilesPlugin.java
index f5e4e86620..d2f3289a62 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/DWARFExternalDebugFilesPlugin.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/DWARFExternalDebugFilesPlugin.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.File;
import java.util.ArrayList;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugFilesService.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugFilesService.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugFilesService.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugFilesService.java
index 642ed54f0a..656ca428c5 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugFilesService.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugFilesService.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.IOException;
import java.util.List;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugInfo.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugInfo.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugInfo.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugInfo.java
index 0e6df08413..5afa7e1ca2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/ExternalDebugInfo.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/ExternalDebugInfo.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import ghidra.app.util.bin.format.elf.info.GnuDebugLink;
import ghidra.app.util.bin.format.elf.info.NoteGnuBuildId;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/LocalDirectorySearchLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/LocalDirectorySearchLocation.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/LocalDirectorySearchLocation.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/LocalDirectorySearchLocation.java
index f87c5f56e0..cbae723c95 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/LocalDirectorySearchLocation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/LocalDirectorySearchLocation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.*;
import java.util.zip.CRC32;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SameDirSearchLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SameDirSearchLocation.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SameDirSearchLocation.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SameDirSearchLocation.java
index 1e7be9de7c..3ab0172962 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SameDirSearchLocation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SameDirSearchLocation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.File;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocation.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocation.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocation.java
index 9742073f99..f4b6cf3da6 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocation.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationCreatorContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationCreatorContext.java
similarity index 96%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationCreatorContext.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationCreatorContext.java
index 7b25cbb456..3ad2c3588d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationCreatorContext.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationCreatorContext.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import ghidra.program.model.listing.Program;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationRegistry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationRegistry.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationRegistry.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationRegistry.java
index 352371f23c..1bd4695c4d 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/external/SearchLocationRegistry.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/external/SearchLocationRegistry.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.external;
+package ghidra.app.util.bin.format.dwarf.external;
import java.util.ArrayList;
import java.util.List;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/DWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/DWARFFunctionFixup.java
similarity index 93%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/DWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/DWARFFunctionFixup.java
index 6977fb40a4..87f7ce688b 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/DWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/DWARFFunctionFixup.java
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
import java.io.Closeable;
import java.util.List;
-import ghidra.app.util.bin.format.dwarf4.DWARFException;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
+import ghidra.app.util.bin.format.dwarf.DWARFException;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.classfinder.ExtensionPoint;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/OutputParamCheckDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/OutputParamCheckDWARFFunctionFixup.java
similarity index 78%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/OutputParamCheckDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/OutputParamCheckDWARFFunctionFixup.java
index 9123ce17e0..70f9d6e680 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/OutputParamCheckDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/OutputParamCheckDWARFFunctionFixup.java
@@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFVariable;
-import ghidra.util.Msg;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
+import ghidra.app.util.bin.format.dwarf.DWARFVariable;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
@@ -33,8 +32,10 @@ public class OutputParamCheckDWARFFunctionFixup implements DWARFFunctionFixup {
// some other fixup, as we don't know what to do with them.
for (DWARFVariable dvar : dfunc.params) {
if (dvar.isOutputParameter && dvar.isMissingStorage()) {
- Msg.warn(this, "Unsupported output parameter for %s@%s"
- .formatted(dfunc.name.getName(), dfunc.address));
+ String paramName = dvar.name.getName();
+ dfunc.getProgram()
+ .logWarningAt(dfunc.address, dfunc.name.getName(),
+ "Unsupported output parameter %s".formatted(paramName));
}
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamNameDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamNameDWARFFunctionFixup.java
similarity index 94%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamNameDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamNameDWARFFunctionFixup.java
index 69607d4cd9..7c1f0598d8 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamNameDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamNameDWARFFunctionFixup.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.next.*;
+import ghidra.app.util.bin.format.dwarf.*;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamSpillDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamSpillDWARFFunctionFixup.java
similarity index 90%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamSpillDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamSpillDWARFFunctionFixup.java
index 3d5309bce3..ad9b746c27 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ParamSpillDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ParamSpillDWARFFunctionFixup.java
@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFVariable;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
+import ghidra.app.util.bin.format.dwarf.DWARFVariable;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/RustDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/RustDWARFFunctionFixup.java
similarity index 82%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/RustDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/RustDWARFFunctionFixup.java
index 98e0f3e8db..b6ed905bb0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/RustDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/RustDWARFFunctionFixup.java
@@ -13,15 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
import java.io.IOException;
-import ghidra.app.util.bin.format.dwarf4.DIEAggregate;
-import ghidra.app.util.bin.format.dwarf4.DWARFException;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction.CommitMode;
+import ghidra.app.util.bin.format.dwarf.*;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode;
import ghidra.program.database.data.ProgramBasedDataTypeManagerDB;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Program;
@@ -39,7 +36,7 @@ public class RustDWARFFunctionFixup implements DWARFFunctionFixup {
@Override
public void fixupDWARFFunction(DWARFFunction dfunc) throws DWARFException {
DIEAggregate diea = dfunc.diea;
- int cuLang = diea.getCompilationUnit().getCompileUnit().getLanguage();
+ int cuLang = diea.getCompilationUnit().getLanguage();
if (cuLang == DWARFSourceLanguage.DW_LANG_Rust) {
dfunc.callingConventionName = getRustCC(dfunc.getProgram().getGhidraProgram());
dfunc.signatureCommitMode = CommitMode.FORMAL;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/SanityCheckDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/SanityCheckDWARFFunctionFixup.java
similarity index 74%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/SanityCheckDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/SanityCheckDWARFFunctionFixup.java
index 41a2fbc5f9..7087308a74 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/SanityCheckDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/SanityCheckDWARFFunctionFixup.java
@@ -13,19 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.DWARFException;
-import ghidra.app.util.bin.format.dwarf4.attribs.DWARFAttributeValue;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.util.Msg;
+import ghidra.app.util.bin.format.dwarf.DWARFException;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
* Check for errors and prevent probable bad function info from being locked in
*/
@ExtensionPointProperties(priority = DWARFFunctionFixup.PRIORITY_NORMAL_LATE)
-public class SanityCheckDWARFFunctionFixup implements DWARFFunctionFixup, DWARFAttributeValue {
+public class SanityCheckDWARFFunctionFixup implements DWARFFunctionFixup {
@Override
public void fixupDWARFFunction(DWARFFunction dfunc) throws DWARFException {
@@ -33,8 +31,9 @@ public class SanityCheckDWARFFunctionFixup implements DWARFFunctionFixup, DWARFA
// don't force the method to have an empty param signature because there are other
// issues afoot.
if (dfunc.params.isEmpty() && dfunc.localVarErrors) {
- Msg.error(this, "Inconsistent function signature information, leaving undefined: %s@%s"
- .formatted(dfunc.name.getName(), dfunc.address));
+ dfunc.getProgram()
+ .logWarningAt(dfunc.address, dfunc.name.getName(),
+ "Inconsistent function signature information, leaving undefined");
throw new DWARFException("Failed sanity check");
}
}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/StorageVerificationDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/StorageVerificationDWARFFunctionFixup.java
similarity index 86%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/StorageVerificationDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/StorageVerificationDWARFFunctionFixup.java
index 0d167b5571..c364be9782 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/StorageVerificationDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/StorageVerificationDWARFFunctionFixup.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction.CommitMode;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFVariable;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
+import ghidra.app.util.bin.format.dwarf.DWARFVariable;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ThisCallingConventionDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ThisCallingConventionDWARFFunctionFixup.java
similarity index 81%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ThisCallingConventionDWARFFunctionFixup.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ThisCallingConventionDWARFFunctionFixup.java
index 62e17682e3..682274c796 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/funcfixup/ThisCallingConventionDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/funcfixup/ThisCallingConventionDWARFFunctionFixup.java
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.funcfixup;
+package ghidra.app.util.bin.format.dwarf.funcfixup;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFVariable;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction;
+import ghidra.app.util.bin.format.dwarf.DWARFVariable;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.listing.Function;
-import ghidra.util.Msg;
import ghidra.util.classfinder.ExtensionPointProperties;
/**
@@ -39,9 +38,10 @@ public class ThisCallingConventionDWARFFunctionFixup implements DWARFFunctionFix
if (firstParam.isThis) {
if (!firstParam.name.isAnon() &&
!Function.THIS_PARAM_NAME.equals(firstParam.name.getOriginalName())) {
- Msg.warn(this, "Renaming %s to %s in function %s@%s".formatted(
- firstParam.name.getName(), Function.THIS_PARAM_NAME, dfunc.name.getName(),
- dfunc.address));
+ dfunc.getProgram()
+ .logWarningAt(dfunc.address, dfunc.name.getName(),
+ "Renamed parameter \"%s\" to %s".formatted(firstParam.name.getName(),
+ Function.THIS_PARAM_NAME));
}
firstParam.name =
firstParam.name.replaceName(Function.THIS_PARAM_NAME, Function.THIS_PARAM_NAME);
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/BaseSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/BaseSectionProvider.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/BaseSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/BaseSectionProvider.java
index 6fafd698c5..d3802481a1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/BaseSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/BaseSectionProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.util.List;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/CompressedSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/CompressedSectionProvider.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/CompressedSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/CompressedSectionProvider.java
index 9049d4a18a..dd00181eb2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/CompressedSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/CompressedSectionProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.util.HashMap;
import java.util.Map;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DSymSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DSymSectionProvider.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DSymSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DSymSectionProvider.java
index ff22331653..647b6e3776 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DSymSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DSymSectionProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.util.HashMap;
import java.util.Map;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionNames.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java
similarity index 78%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionNames.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java
index f52f59fa72..2b3ff4afce 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionNames.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
public final class DWARFSectionNames {
public static final String DEBUG_INFO = "debug_info";
@@ -21,13 +21,18 @@ public final class DWARFSectionNames {
public static final String DEBUG_ABBREV = "debug_abbrev";
public static final String DEBUG_ARRANGES = "debug_arranges";
public static final String DEBUG_LINE = "debug_line";
+ public static final String DEBUG_LINE_STR = "debug_line_str"; // v5+
public static final String DEBUG_FRAME = "debug_frame";
public static final String DEBUG_LOC = "debug_loc";
+ public static final String DEBUG_LOCLISTS = "debug_loclists"; // v5+
public static final String DEBUG_STR = "debug_str";
+ public static final String DEBUG_STROFFSETS = "debug_str_offsets"; // v5+
public static final String DEBUG_RANGES = "debug_ranges";
+ public static final String DEBUG_RNGLISTS = "debug_rnglists"; // v5+
public static final String DEBUG_PUBNAMES = "debug_pubnames";
public static final String DEBUG_PUBTYPES = "debug_pubtypes";
public static final String DEBUG_MACINFO = "debug_macinfo";
+ public static final String DEBUG_ADDR = "debug_addr";
public static final String[] MINIMAL_DWARF_SECTIONS = { DEBUG_INFO, DEBUG_ABBREV };
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProvider.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProvider.java
index 734ec8e75d..b3dec2635e 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.io.Closeable;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProviderFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java
similarity index 98%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProviderFactory.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java
index 4aeb051cdf..cdca67c653 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/DWARFSectionProviderFactory.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.io.Closeable;
import java.util.List;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/ExternalDebugFileSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/ExternalDebugFileSectionProvider.java
similarity index 97%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/ExternalDebugFileSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/ExternalDebugFileSectionProvider.java
index 914e95b09a..6412034576 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/ExternalDebugFileSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/ExternalDebugFileSectionProvider.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.List;
import ghidra.app.util.bin.ByteProvider;
-import ghidra.app.util.bin.format.dwarf4.external.*;
+import ghidra.app.util.bin.format.dwarf.external.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.ElfLoader;
import ghidra.formats.gfilesystem.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/NullSectionProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/NullSectionProvider.java
similarity index 94%
rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/NullSectionProvider.java
rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/NullSectionProvider.java
index fe9df0206c..7adaef0174 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/sectionprovider/NullSectionProvider.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/NullSectionProvider.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next.sectionprovider;
+package ghidra.app.util.bin.format.dwarf.sectionprovider;
import java.io.IOException;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAbbreviation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAbbreviation.java
deleted file mode 100644
index d01f7c7fd4..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAbbreviation.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/* ###
- * 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;
-
-import java.util.*;
-
-import java.io.IOException;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFChildren;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.program.model.data.LEB128;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.task.TaskMonitor;
-
-/**
- * This class represents the 'schema' for a DWARF DIE record.
- *
- * A raw DWARF DIE record specifies its abbreviation code (pointing to an instance of
- * this class) and the corresponding DWARFAbbreviation instance has the information
- * about how the raw DIE is laid out.
- */
-public class DWARFAbbreviation
-{
- private final int abbreviationCode;
- private final int tag;
- private final boolean hasChildren;
- private final DWARFAttributeSpecification[] attributes;
-
- public static DWARFAbbreviation read(BinaryReader reader, DWARFProgram prog,
- TaskMonitor monitor)
- throws IOException, CancelledException {
-
- int ac = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
- if (ac == 0) {
- return null;
- }
- int tag = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
- DWARFChildren hasChildren = DWARFChildren.find((int) reader.readNextByte());
-
- // Read each attribute specification until attribute and its value is 0
- List tmpAttrSpecs = new ArrayList<>();
- DWARFAttributeSpecification attr;
- while ((attr = DWARFAttributeSpecification.read(reader)) != null) {
- monitor.checkCancelled();
- tmpAttrSpecs.add(prog.internAttributeSpec(attr));
- }
- DWARFAttributeSpecification[] attrSpecArray =
- tmpAttrSpecs.toArray(new DWARFAttributeSpecification[tmpAttrSpecs.size()]);
-
- DWARFAbbreviation result = new DWARFAbbreviation(ac, tag,
- hasChildren == DWARFChildren.DW_CHILDREN_yes, attrSpecArray);
-
- return result;
- }
-
- public static Map readAbbreviations(BinaryReader reader,
- DWARFProgram prog, TaskMonitor monitor) throws IOException, CancelledException {
- Map result = new HashMap<>();
-
- // Read all abbreviations for this compilation unit and add to a map
- DWARFAbbreviation abbrev = null;
- while ((abbrev = DWARFAbbreviation.read(reader, prog, monitor)) != null) {
- monitor.checkCancelled();
- result.put(abbrev.getAbbreviationCode(), abbrev);
- }
-
- return result;
- }
-
- public DWARFAbbreviation(int abbreviationCode, int tag, boolean hasChildren,
- DWARFAttributeSpecification[] attributes) {
- this.abbreviationCode = abbreviationCode;
- this.tag = tag;
- this.hasChildren = hasChildren;
- this.attributes = attributes;
- }
-
- @Override
- public String toString()
- {
- return Integer.toHexString(getAbbreviationCode()) + ":" +
- DWARFUtil.toString(DWARFTag.class, getTag());
- }
-
- /**
- * Get the abbreviation code.
- * @return the abbreviation code
- */
- public int getAbbreviationCode()
- {
- return this.abbreviationCode;
- }
-
- /**
- * Get the tag value.
- * @return the tag value
- */
- public int getTag() {
- return this.tag;
- }
-
- /**
- * Checks to see if this abbreviation has any DIE children.
- * @return true if this abbreviation has DIE children
- */
- public boolean hasChildren() {
- return this.hasChildren;
- }
-
- /**
- * Return a live list of the attributes.
- * @return list of attributes
- */
- public DWARFAttributeSpecification[] getAttributes() {
- return attributes;
- }
-
- public int getAttributeCount() {
- return attributes.length;
- }
-
- /**
- * Get the attribute at the given index.
- * @param index index of the attribute
- * @return attribute specification
- */
- public DWARFAttributeSpecification getAttributeAt(int index) {
- return this.attributes[index];
- }
-
- /**
- * Get the attribute with the given attribute key.
- * @param attribute attribute key
- * @return attribute specification
- */
- public DWARFAttributeSpecification findAttribute(int attribute) {
- for(DWARFAttributeSpecification spec : this.attributes) {
- if(spec.getAttribute() == attribute) {
- return spec;
- }
- }
- return null;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAttributeSpecification.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAttributeSpecification.java
deleted file mode 100644
index d22339954a..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFAttributeSpecification.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/* ###
- * 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;
-
-import java.io.IOException;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-import ghidra.program.model.data.LEB128;
-
-/**
- * Information about a single DWARF attribute.
- */
-public class DWARFAttributeSpecification {
- private final int attribute;
- private final DWARFForm attributeForm;
-
- /**
- * Reads a {@link DWARFAttributeSpecification} instance from the {@link BinaryReader reader}.
- *
- * Returns a null if its a end-of-list marker.
- *
- * @param reader
- * @return
- * @throws IOException
- */
- public static DWARFAttributeSpecification read(BinaryReader reader) throws IOException {
- int attribute = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
- DWARFForm attributeForm =
- DWARFForm.find(reader.readNextUnsignedVarIntExact(LEB128::unsigned));
-
- return attribute != 0 && attributeForm != DWARFForm.NULL
- ? new DWARFAttributeSpecification(attribute, attributeForm) : null;
- }
-
- public DWARFAttributeSpecification(int attribute, DWARFForm attributeForm) {
- this.attribute = attribute;
- this.attributeForm = attributeForm;
- }
-
- /**
- * Get the attribute of the attribute specification.
- * @return the attribute value
- */
- public int getAttribute() {
- return this.attribute;
- }
-
- /**
- * Get the form of the attribute specification.
- * @return the form value
- */
- public DWARFForm getAttributeForm() {
- return this.attributeForm;
- }
-
- @Override
- public String toString() {
- return DWARFUtil.toString(DWARFAttribute.class, getAttribute()) + "->" + getAttributeForm();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + attribute;
- result = prime * result + ((attributeForm == null) ? 0 : attributeForm.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (!(obj instanceof DWARFAttributeSpecification))
- return false;
- DWARFAttributeSpecification other = (DWARFAttributeSpecification) obj;
- if (attribute != other.attribute)
- return false;
- if (attributeForm != other.attributeForm)
- return false;
- return true;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompilationUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompilationUnit.java
deleted file mode 100644
index 457b3b3433..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompilationUnit.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/* ###
- * 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;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil.LengthResult;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.util.Msg;
-import ghidra.util.exception.CancelledException;
-import ghidra.util.task.TaskMonitor;
-
-/**
- * A DWARF "CompilationUnit" is a contiguous block of {@link DebugInfoEntry DIE} records found
- * in a ".debug_info" section of an ELF program. The compilation unit block starts with a
- * header that has a few important values and flags, and is followed by the DIE records.
- *
- * The first DIE record must be a DW_TAG_compile_unit (see {@link DWARFCompileUnit},
- * and {@link #getCompileUnit()}).
- *
- * DIE records are identified by their byte offset in the ".debug_info" section.
- *
- */
-public class DWARFCompilationUnit {
-
- public static final int DWARF_32 = 32;
- public static final int DWARF_64 = 64;
-
- /**
- * Reference to the owning {@link DWARFProgram}.
- */
- private final DWARFProgram dwarfProgram;
-
- /**
- * Offset in the debug_info section of this compUnit's header
- */
- private final long startOffset;
-
- /**
- * Offset in the debug_info section of the end of this compUnit. (right after
- * the last DIE record)
- */
- private final long endOffset;
-
- /**
- * Length in bytes of this compUnit header and DIE records.
- */
- private final long length;
-
- /**
- * {@link #DWARF_32} or {@link #DWARF_64}
- */
- private final int format;
-
- /**
- * DWARF ver number, as read from the compunit structure, currently not used but being kept.
- */
- @SuppressWarnings("unused")
- private final short version;
-
- /**
- * Sequential number of this compUnit
- */
- private final int compUnitNumber;
-
- /**
- * Size of pointers that are held in DIEs in this compUnit.
- */
- private final byte pointerSize;
-
- /**
- * Offset in the abbr section of this compUnit's abbreviations.
- */
- private final long abbreviationOffset;
-
- /**
- * Offset in the debug_info section of the first DIE of this compUnit.
- */
- private final long firstDIEOffset;
-
- /**
- * Map of abbrevCode to {@link DWARFAbbreviation} instances.
- */
- private final Map codeToAbbreviationMap;
-
- /**
- * The contents of the first DIE (that must be a compile unit) in this compUnit.
- */
- protected DWARFCompileUnit compUnit;
-
- /**
- * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data
- * from the debug_info section and the debug_abbr section and its compileUnit DIE (ie.
- * the first DIE right after the header).
- *
- * Returns {@code NULL} if there was an ignorable error while reading the compilation unit (and
- * leaves the input stream at the next compilation unit to read), otherwise throws
- * an IOException if there was an unrecoverable error.
- *
- * Also returns {@code NULL} (and leaves the stream at EOF) if the remainder of the stream
- * is filled with null bytes.
- *
- * @param dwarfProgram the dwarf program.
- * @param debugInfoBR the debug info binary reader.
- * @param debugAbbrBR the debug abbreviation binary reader
- * @param cuNumber the compilation unit number
- * @param monitor the current task monitor
- * @return the read compilation unit, or null if the compilation unit was bad/empty and should
- * be ignored
- * @throws DWARFException if an invalid or unsupported DWARF version is read.
- * @throws IOException if the length of the compilation unit is invalid.
- * @throws CancelledException if the task has been canceled.
- */
- public static DWARFCompilationUnit readCompilationUnit(DWARFProgram dwarfProgram,
- BinaryReader debugInfoBR, BinaryReader debugAbbrBR, int cuNumber, TaskMonitor monitor)
- throws DWARFException, IOException, CancelledException {
-
- long startOffset = debugInfoBR.getPointerIndex();
- LengthResult lengthInfo =
- DWARFUtil.readLength(debugInfoBR, dwarfProgram.getGhidraProgram());
- if (lengthInfo.length == 0) {
- if (isAllZerosUntilEOF(debugInfoBR)) {
- // hack to handle trailing padding at end of section. (similar to the check for
- // unexpectedTerminator in readDIEs(), when padding occurs inside the bounds
- // of the compile unit's range after the end of the root DIE's children)
- debugInfoBR.setPointerIndex(debugInfoBR.length());
- return null;
- }
- throw new DWARFException(
- "Invalid DWARF length 0 at 0x" + Long.toHexString(startOffset));
- }
-
- long endOffset = debugInfoBR.getPointerIndex() + lengthInfo.length;
- short version = debugInfoBR.readNextShort();
- long abbreviationOffset = DWARFUtil.readOffsetByDWARFformat(debugInfoBR, lengthInfo.format);
- byte pointerSize = debugInfoBR.readNextByte();
- long firstDIEOffset = debugInfoBR.getPointerIndex();
-
- if (version < 2 || version > 4) {
- throw new DWARFException(
- "Only DWARF version 2, 3, or 4 information is currently supported (detected " +
- version + ").");
- }
- if (firstDIEOffset > endOffset) {
- throw new IOException("Invalid length " + (endOffset - startOffset) +
- " for DWARF Compilation Unit at 0x" + Long.toHexString(startOffset));
- }
- else if (firstDIEOffset == endOffset) {
- // silently skip this empty compunit
- return null;
- }
-
- debugAbbrBR.setPointerIndex(abbreviationOffset);
- Map abbrMap =
- DWARFAbbreviation.readAbbreviations(debugAbbrBR, dwarfProgram, monitor);
-
- DWARFCompilationUnit cu = new DWARFCompilationUnit(dwarfProgram, startOffset, endOffset,
- lengthInfo.length, lengthInfo.format, version, abbreviationOffset, pointerSize,
- cuNumber, firstDIEOffset, abbrMap);
-
- try {
- DebugInfoEntry compileUnitDIE =
- DebugInfoEntry.read(debugInfoBR, cu, -1, dwarfProgram.getAttributeFactory());
-
- DWARFCompileUnit compUnit =
- DWARFCompileUnit.read(DIEAggregate.createSingle(compileUnitDIE));
- cu.compUnit = compUnit;
- return cu;
- }
- catch (IOException ioe) {
- Msg.error(DWARFCompilationUnit.class,
- "Failed to parse the DW_TAG_compile_unit DIE at the start of compilation unit %d at offset %d (0x%x), skipping entire compilation unit"
- .formatted(cuNumber, startOffset, startOffset),
- ioe);
- debugInfoBR.setPointerIndex(cu.getEndOffset());
- return null;
- }
- }
-
- private static boolean isAllZerosUntilEOF(BinaryReader reader) throws IOException {
- reader = reader.clone();
- while (reader.hasNext()) {
- if (reader.readNextByte() != 0) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * This ctor is public only for junit tests. Do not use directly.
- *
- * @param dwarfProgram {@link DWARFProgram}
- * @param startOffset offset in provider where it starts
- * @param endOffset offset in provider where it ends
- * @param length how many bytes following the header the DIEs of this unit take
- * @param format DWARF_32 or DWARF_64
- * @param version 2, 3, 4
- * @param abbreviationOffset offset into abbrev section
- * @param pointerSize default size of pointers
- * @param compUnitNumber this compunits ordinal in the file
- * @param firstDIEOffset start of DIEs in the provider
- * @param codeToAbbreviationMap map of abbreviation numbers to {@link DWARFAbbreviation} instances
- */
- public DWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset,
- long length, int format, short version, long abbreviationOffset, byte pointerSize,
- int compUnitNumber, long firstDIEOffset,
- Map codeToAbbreviationMap) {
- this.dwarfProgram = dwarfProgram;
- this.startOffset = startOffset;
- this.endOffset = endOffset;
- this.length = length;
- this.format = format;
- this.version = version;
- this.abbreviationOffset = abbreviationOffset;
- this.pointerSize = pointerSize;
- this.compUnitNumber = compUnitNumber;
- this.firstDIEOffset = firstDIEOffset;
- this.codeToAbbreviationMap =
- (codeToAbbreviationMap != null) ? codeToAbbreviationMap : new HashMap<>();
- }
-
- public DWARFCompileUnit getCompileUnit() {
- return compUnit;
- }
-
- public DWARFProgram getProgram() {
- return dwarfProgram;
- }
-
- /**
- * An unsigned long (4 bytes in 32-bit or 8 bytes in 64-bit format) representing
- * the length of the .debug_info contribution for that compilation unit,
- * not including the length field itself.
- * @return the length in bytes of the this compilation unit
- */
- public long getLength() {
- return this.length;
- }
-
- /**
- * A 1-byte unsigned integer representing the size
- * in bytes of an address on the target
- * architecture. If the system uses segmented addressing, this
- * value represents the size of the offset portion of an address.
- * @return the size in bytes of pointers
- */
- public byte getPointerSize() {
- return this.pointerSize;
- }
-
- /**
- * Returns the byte offset to the start of this compilation unit.
- * @return the byte offset to the start of this compilation unit
- */
- public long getStartOffset() {
- return this.startOffset;
- }
-
- /**
- * Returns the byte offset to the end of this compilation unit.
- * @return the byte offset to the end of this compilation unit
- */
- public long getEndOffset() {
- return this.endOffset;
- }
-
- /**
- * Returns either DWARF_32 or DWARF_64 depending on the current compilation unit format
- * @return DWARF_32 or DWARF_64 constant depending on the current compilation unit format
- */
- public int getFormat() {
- return this.format;
- }
-
- /**
- * Returns true if the {@code offset} value is within
- * this compUnit's start and end position in the debug_info section.
- * @param offset DIE offset
- * @return true if within range of this compunit
- */
- public boolean containsOffset(long offset) {
- return firstDIEOffset <= offset && offset < endOffset;
- }
-
- @Override
- public String toString() {
- StringBuilder buffer = new StringBuilder();
- buffer.append("Compilation Unit");
- buffer.append(" [Start:0x" + Long.toHexString(this.startOffset) + "]");
- buffer.append(" [Length:0x" + Long.toHexString(this.length) + "]");
- buffer.append(" [AbbreviationOffset:0x" + Long.toHexString(this.abbreviationOffset) + "]");
- buffer.append(
- " [CompileUnit: " + (compUnit != null ? compUnit.toString() : "not present") + "]");
- return buffer.toString();
- }
-
- public Map getCodeToAbbreviationMap() {
- return codeToAbbreviationMap;
- }
-
- public long getFirstDIEOffset() {
- return firstDIEOffset;
- }
-
- public int getCompUnitNumber() {
- return compUnitNumber;
- }
-
-}
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
deleted file mode 100644
index 8ecec8c08c..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/* ###
- * 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;
-
-import java.io.File;
-import java.io.IOException;
-
-import ghidra.app.util.bin.format.dwarf4.encoding.*;
-
-/**
- * DWARFCompileUnit hold some values retrieved from a DWARF DW_TAG_compile_unit DIE.
- *
- */
-public class DWARFCompileUnit {
- private final String name;
- private final String producer;
- private final String comp_dir;
- private final Number high_pc;
- private final Number low_pc;
- private final Number language;
- private final boolean hasDWO;
-
- private DWARFLine line = null;
-
- public static DWARFCompileUnit read(DIEAggregate diea)
- throws IOException, DWARFException {
- if (diea.getTag() != DWARFTag.DW_TAG_compile_unit) {
- throw new IOException("Expecting a DW_TAG_compile_unit DIE, found " + diea.getTag());
- }
-
- String name = diea.getString(DWARFAttribute.DW_AT_name, null);
- String producer = diea.getString(DWARFAttribute.DW_AT_producer, null);
- String comp_dir = diea.getString(DWARFAttribute.DW_AT_comp_dir, null);
-
- Number high_pc = null, low_pc = null, language = null;
-
- if (diea.hasAttribute(DWARFAttribute.DW_AT_low_pc)) {
- low_pc = diea.getLowPC(0);
- }
-
- // 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();
- }
-
- if (diea.hasAttribute(DWARFAttribute.DW_AT_language)) {
- language = diea.getUnsignedLong(DWARFAttribute.DW_AT_language, -1);
- }
-
- boolean hasDWO = diea.hasAttribute(DWARFAttribute.DW_AT_GNU_dwo_id) &&
- diea.hasAttribute(DWARFAttribute.DW_AT_GNU_dwo_name);
-
- DWARFLine line = DWARFLine.read(diea);
-
- return new DWARFCompileUnit(name, producer, comp_dir, low_pc, high_pc, language, hasDWO,
- line);
- }
-
- /*
- * Construct a DWARF compile unit with the given values.
- */
- public DWARFCompileUnit(String name, String producer, String comp_dir, Number low_pc,
- Number high_pc, Number language, boolean hasDWO, DWARFLine line) {
- this.name = name;
- this.producer = producer;
- this.comp_dir = comp_dir;
- this.low_pc = low_pc;
- this.high_pc = high_pc;
- this.language = language;
- this.hasDWO = hasDWO;
- this.line = line;
- }
-
- /**
- * Get the name of the compile unit
- * @return the name of the compile unit
- */
- public String getName() {
- return this.name;
- }
-
- /**
- * Get the filename of the compile unit
- * @return the filename of the compile unit
- */
- public String getFileName() {
- return getName() == null ? null : new File(getName()).getName();
- }
-
- /**
- * Get a file name with the full path included based on a file index.
- * @param index index of the file
- * @return file name with full path or null if line information does not exist
- * @throws IllegalArgumentException if a negative or invalid file index is given
- */
- public String getFullFileByIndex(int index) {
- if (index < 0) {
- throw new IllegalArgumentException("Negative file index was given.");
- }
- if (this.line == null) {
- return null;
- }
-
- return this.line.getFullFile(index, this.comp_dir);
- }
-
- /**
- * Get a file name based on a file index.
- * @param index index of the file
- * @return file name or null if line information does not exist
- * @throws IllegalArgumentException if a negative or invalid file index is given
- */
- public String getFileByIndex(int index) {
- if (index < 0) {
- throw new IllegalArgumentException("Negative file index was given.");
- }
- if (this.line == null) {
- return null;
- }
-
- return this.line.getFile(index, this.comp_dir);
- }
-
- /**
- * Checks validity of a file index number.
- *
- * @param index file number, 1..N
- * @return boolean true if index is a valid file number, false otherwise
- */
- public boolean isValidFileIndex(int index) {
- return line.isValidFileIndex(index);
- }
-
- /**
- * Get the producer of the compile unit
- * @return the producer of the compile unit
- */
- public String getProducer() {
- return this.producer;
- }
-
- /**
- * Get the compile directory of the compile unit
- * @return the compile directory of the compile unit
- */
- public String getCompileDirectory() {
- return this.comp_dir;
- }
-
- /**
- * Get the high PC value of the compile unit
- * @return the high PC value of the compile unit
- */
- public Number getHighPC() {
- return this.high_pc;
- }
-
- /**
- * Get the low PC value of the compile unit
- * @return the low PC value of the compile unit
- */
- public Number getLowPC() {
- return this.low_pc;
- }
-
- /**
- * Get the source language of the compile unit.
- *
- * See {@link DWARFSourceLanguage} for values.
- *
- * @return the source language of the compile unit
- */
- public int getLanguage() {
- return this.language == null ? -1 : this.language.intValue();
- }
-
- public boolean hasDWO() {
- return hasDWO;
- }
-
- @Override
- public String toString() {
- return String.format(
- "DWARFCompileUnit [name=%s, producer=%s, comp_dir=%s, high_pc=%s, low_pc=%s, language=%s, hasDWO=%s, line=%s]",
- name, producer, comp_dir, high_pc, low_pc, language, hasDWO, line);
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLine.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLine.java
deleted file mode 100644
index d59f400acf..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLine.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/* ###
- * 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;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.commons.io.FilenameUtils;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil.LengthResult;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.program.model.data.LEB128;
-
-public class DWARFLine {
- private long unit_length;
- private int format;
- private int version;
- private long header_length;
- private int minimum_instruction_length;
- private int maximum_operations_per_instruction;
- private int default_is_stmt;
- private int line_base;
- private int line_range;
- private int opcode_base;
- private int[] standard_opcode_length;
- private List include_directories;
- private List file_names;
-
- /**
- * Read a DWARFLine from the compile unit's DW_AT_stmt_list location in the
- * DebugLine stream (if present).
- *
- * @param diea {@link DIEAggregate} compile unit DIE(a)
- * @return a new DWARFLine instance if DW_AT_stmt_list and stream are present, otherwise null
- * @throws IOException if error reading data
- * @throws DWARFException if bad DWARF values
- */
- public static DWARFLine read(DIEAggregate diea) throws IOException, DWARFException {
- DWARFProgram dProg = diea.getProgram();
- BinaryReader reader = dProg.getDebugLine();
-
- // DW_AT_stmt_list can be const or ptr form types.
- long stmtListOffset = diea.getUnsignedLong(DWARFAttribute.DW_AT_stmt_list, -1);
-
- if (reader == null || stmtListOffset < 0) {
- return null;
- }
-
- reader.setPointerIndex(stmtListOffset);
-
- DWARFLine result = new DWARFLine();
-
- LengthResult lengthInfo = DWARFUtil.readLength(reader, dProg.getGhidraProgram());
- result.unit_length = lengthInfo.length;
- result.format = lengthInfo.format;
- if (result.unit_length == 0) {
- throw new DWARFException(
- "Invalid DWARFLine length 0 at 0x" + Long.toHexString(stmtListOffset));
- }
-
- // A version number for this line number information section
- result.version = reader.readNextUnsignedShort();
-
- // Get the header length based on the current format
- result.header_length = DWARFUtil.readOffsetByDWARFformat(reader, result.format);
-
- result.minimum_instruction_length = reader.readNextUnsignedByte();
-
- // Maximum operations per instruction only exists in DWARF version 4 or higher
- if (result.version >= 4) {
- result.maximum_operations_per_instruction = reader.readNextUnsignedByte();
- }
- else {
- result.maximum_operations_per_instruction = 1;
- }
- result.default_is_stmt = reader.readNextUnsignedByte();
- result.line_base = reader.readNextByte();
- result.line_range = reader.readNextUnsignedByte();
- result.opcode_base = reader.readNextUnsignedByte();
- result.standard_opcode_length = new int[result.opcode_base];
- result.standard_opcode_length[0] = 1; /* Should never be used */
- for (int i = 1; i < result.opcode_base; i++) {
- result.standard_opcode_length[i] = reader.readNextUnsignedByte();
- }
-
- // Read all include directories
- result.include_directories = new ArrayList<>();
- String include = reader.readNextAsciiString();
- while (include.length() != 0) {
- result.include_directories.add(include);
- include = reader.readNextAsciiString();
- }
-
- // Read all files
- result.file_names = new ArrayList<>();
- DWARFFile file = new DWARFFile(reader);
- while (file.getName().length() != 0) {
- result.file_names.add(file);
- file = new DWARFFile(reader);
- }
-
- return result;
- }
-
- private DWARFLine() {
- // empty, use #read()
- }
-
- /**
- * Get a file name with the full path included.
- * @param index index of the file
- * @param compileDirectory current compile unit directory
- * @return file name with full path
- */
- public String getFullFile(int index, String compileDirectory) {
- if (index == 0) {
- //TODO: Handle index = 0
- throw new UnsupportedOperationException(
- "Currently does not support retrieving the primary source file.");
- }
- else if (index > 0) {
- // Retrieve the file by index (index starts at 1)
- DWARFFile file = this.file_names.get(index - 1);
-
- File fileObj = new File(file.getName());
-
- // Check to see if the file is an absolute path and return if so
- if (fileObj.isAbsolute()) {
- return file.getName();
- }
-
- // Otherwise we need to retrieve the directory
- int diridx = (int) file.getDirectoryIndex();
- if (diridx == 0) {
- // Use the compile directory if a directory index of 0 is given
- if (compileDirectory != null) {
- return compileDirectory + file.getName();
- }
- throw new IllegalArgumentException(
- "No compile directory was given when one was expected.");
- }
- else if (diridx > 0) {
- // Retrieve and append the directory
- String directory = this.include_directories.get(diridx - 1);
- return directory + file.getName();
- }
- throw new IndexOutOfBoundsException(
- "Negative directory index was found: " + Integer.toString(diridx));
- }
- throw new IllegalArgumentException(
- "Negative file index was given: " + Integer.toString(index));
- }
-
- /**
- * Get a file name given a file index.
- * @param index index of the file
- * @param compileDirectory current compile unit directory
- * @return file name
- */
- public String getFile(int index, String compileDirectory) {
- if (index == 0) {
- //TODO: Handle index = 0
- throw new UnsupportedOperationException(
- "Currently does not support retrieving the primary source file.");
- }
- else if (index > 0) {
- // Retrieve the file by index (index starts at 1)
- DWARFFile file = this.file_names.get(index - 1);
- return FilenameUtils.getName(file.getName());
- }
- throw new IllegalArgumentException(
- "Negative file index was given: " + Integer.toString(index));
- }
-
- /**
- * Returns true if file exists.
- *
- * @param index file number, excluding 0
- * @return boolean true if file exists
- */
- public boolean isValidFileIndex(int index) {
- index--;
- return 0 <= index && index < file_names.size();
- }
-
- @Override
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("Line Entry");
- buffer.append(" Include Directories: [");
- for (String dir : this.include_directories) {
- buffer.append(dir);
- buffer.append(", ");
- }
- buffer.append("] File Names: [");
- for (DWARFFile file : this.file_names) {
- buffer.append(file.toString());
- buffer.append(", ");
- }
- buffer.append("]");
- return buffer.toString();
- }
-
- /**
- * DWARFFile is used to store file information for each entry in the line section header.
- */
- public static class DWARFFile {
- private String name;
- private long directory_index;
- private long modification_time;
- private long length;
-
- /**
- * Read in a new file entry and store into this object.
- * @param reader binary reader to read the file entry
- * @throws IOException if an I/O error occurs
- */
- public DWARFFile(BinaryReader reader) throws IOException {
- this.name = reader.readNextAsciiString();
-
- // This entry exists only if the length of the string is more than 0
- if (this.name.length() > 0) {
- this.directory_index = reader.readNext(LEB128::unsigned);
- this.modification_time = reader.readNext(LEB128::unsigned);
- this.length = reader.readNext(LEB128::unsigned);
- }
- }
-
- /**
- * Create a new DWARF file entry with the given parameters.
- * @param name name of the file
- * @param directory_index index of the directory for this file
- * @param modification_time modification time of the file
- * @param length length of the file
- */
- public DWARFFile(String name, long directory_index, long modification_time, long length) {
- this.name = name;
- this.directory_index = directory_index;
- this.modification_time = modification_time;
- this.length = length;
- }
-
- public String getName() {
- return this.name;
- }
-
- public long getDirectoryIndex() {
- return this.directory_index;
- }
-
- public long getModificationTime() {
- return this.modification_time;
- }
-
- @Override
- public String toString() {
- StringBuffer buffer = new StringBuffer();
- buffer.append("Filename: ");
- buffer.append(this.name);
- buffer.append(" Length: ");
- buffer.append(Long.toHexString(this.length));
- return buffer.toString();
- }
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLocation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLocation.java
deleted file mode 100644
index f37b4e14ee..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFLocation.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* ###
- * 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;
-
-import java.util.List;
-
-public class DWARFLocation {
- private DWARFRange addressRange;
- private byte[] location;
-
- /**
- * Create a Location given an address range and location expression.
- * @param addressRange memory range of this location
- * @param location byte array holding location expression
- */
- public DWARFLocation(DWARFRange addressRange, byte[] location) {
- this.addressRange = addressRange;
- this.location = location;
- }
-
- public DWARFRange getRange() {
- return this.addressRange;
- }
-
- public byte[] getLocation() {
- return this.location;
- }
-
- /**
- * Get the location that corresponds to the entry point of the function If
- * there is only a single location, assume it applies to whole function
- *
- * @param locList
- * @param funcAddr
- * @return the byte array corresponding to the location expression
- */
- public static DWARFLocation getTopLocation(List locList, long funcAddr) {
- if (locList.size() == 1) {
- return locList.get(0);
- }
- for (DWARFLocation loc : locList) {
- if (loc.getRange().getFrom() == funcAddr) {
- return loc;
- }
- }
- return null;
- }
-
- public static DWARFLocation getEntryLocation(List locList, long funcAddr) {
- for (DWARFLocation loc : locList) {
- if (loc.getRange().getFrom() == funcAddr) {
- return loc;
- }
- }
- return null;
- }
-
- public static DWARFLocation getFirstLocation(List locList) {
- return !locList.isEmpty() ? locList.get(0) : null;
- }
-
- /*
- * I know we frown on keeping large chunks of code around that have been commented
- * out, but...
- * 1) this is how a core DWARF data structure is read from disk, and contains some gotchas
- * and hard-won knowledge
- * 2) isn't being used right now due to changes in the analyzer and how it uses addr data.
- * 3) might be needed in the future if the analyzer changes its ways
- */
-// /**
-// * Return a list of DWARF locations read from the debug_loc section.
-// * @param offset offset into the debug_loc section
-// * @param die the DIE that pointed to this debug_loc location list
-// * @return list of DWARF locations (address range and location expression)
-// * @throws IOException if an I/O error occurs
-// */
-// public static List parseLocationList(long offset, DebugInfoEntry die)
-// throws IOException {
-// DWARFProgram prog = die.getCompilationUnit().getProgram();
-// BinaryReader debug_loc = prog.getDebugLocation();
-//
-// List ranges = new ArrayList<>();
-// if (debug_loc == null) {
-// return ranges;
-// }
-//
-// debug_loc.setPointerIndex(offset);
-// byte pointerSize = die.getCompilationUnit().getPointerSize();
-//
-// Number baseAddress = die.getCompilationUnit().getCompileUnit().getLowPC();
-// long baseAddressOffset = (baseAddress != null) ? baseAddress.longValue() : 0;
-//
-// Number cuLowPC = die.getCompilationUnit().getCompileUnit().getLowPC();
-// long cuBase = (cuLowPC != null) ? cuLowPC.longValue() : Long.MAX_VALUE;
-//
-// // Loop through the debug_loc entry
-// while (debug_loc.getPointerIndex() < debug_loc.length()) {
-// Number beginning = DWARFUtil.readAddress(debug_loc, pointerSize);
-// Number ending = DWARFUtil.readAddress(debug_loc, pointerSize); // dwarf end addrs are exclusive
-//
-// // List end
-// if (beginning.longValue() == 0 && ending.longValue() == 0) {
-// break;
-// }
-//
-// // Check to see if this is a base address entry
-// if (NumberUtil.equalsMaxUnsignedValue(beginning)) {
-// baseAddressOffset = ending.longValue();
-// continue;
-// }
-//
-// // Size is 2 bytes
-// int size = debug_loc.readNextUnsignedShort();
-//
-// // Read the location description
-// byte[] location = debug_loc.readNextByteArray(size);
-//
-// // Test to see if the 'offset' read from the debug_loc data is already
-// // greater-than the compunit's lowpc. This indicates the 'offset' isn't
-// // an offset, but already an absolute value. This occurs in some
-// // gcc dwarf compilation flag combinations.
-// boolean isBadOffset = (beginning.longValue() > cuBase);
-//
-// long absStart = beginning.longValue();
-// long absEnd = ending.longValue();
-// if (!isBadOffset) {
-// absStart += baseAddressOffset;
-// absEnd += baseAddressOffset;
-// }
-//
-// ranges.add(new DWARFLocation(new DWARFRange(absStart, absEnd), location));
-// }
-// return ranges;
-// }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactory.java
deleted file mode 100644
index c4ba40ce40..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactory.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/* ###
- * 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.attribs;
-
-import java.io.IOException;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.app.util.bin.format.dwarf4.next.StringTable;
-import ghidra.program.model.data.LEB128;
-
-/**
- * A factory for deserializing {@link DWARFAttributeValue dwarf attribute} from
- * a stream.
- */
-public class DWARFAttributeFactory {
-
- /**
- * Max number of bytes that dw_form_block4 is allowed to specify, 1Mb.
- */
- public static final int MAX_BLOCK4_SIZE = 1024 * 1024;
-
- private DWARFProgram prog;
-
- public DWARFAttributeFactory(DWARFProgram prog) {
- this.prog = prog;
- }
-
- /**
- * Read from the given BinaryReader based on the type of DWARFForm that is given.
- * @param reader BinaryReader pointing to the value to read
- * @param unit the current compilation unit
- * @param form DWARFForm type defining the type of value to read
- * @return Object representing the value that was read
- * @throws IOException if an I/O error occurs
- */
- public DWARFAttributeValue read(BinaryReader reader, DWARFCompilationUnit unit, DWARFForm form)
- throws IOException {
- StringTable debugStrings = prog.getDebugStrings();
- switch (form) {
- case DW_FORM_addr:
- return new DWARFNumericAttribute(
- reader.readNextUnsignedValue(unit.getPointerSize()));
- case DW_FORM_ref1: {
- long uoffset = reader.readNextUnsignedValue(1);
- return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
- }
- case DW_FORM_ref2: {
- long uoffset = reader.readNextUnsignedValue(2);
- return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
- }
- case DW_FORM_ref4: {
- long uoffset = reader.readNextUnsignedValue(4);
- return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
- }
- case DW_FORM_ref8: {
- long uoffset = reader.readNextUnsignedValue(8);
- return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
- }
- case DW_FORM_ref_udata: {
- long uoffset = reader.readNext(LEB128::unsigned);
- return new DWARFNumericAttribute(uoffset + unit.getStartOffset());
- }
-
- // DW_FORM_ref_addr and DW_FORM_sec_offset have identical raw forms,
- // but point to different items (ref_addr points to elements in .debug_info,
- // sec_offset points to elements in other sections)
- case DW_FORM_ref_addr:
- return new DWARFNumericAttribute(
- DWARFUtil.readOffsetByDWARFformat(reader, unit.getFormat()));
- case DW_FORM_sec_offset:
- return new DWARFNumericAttribute(
- DWARFUtil.readOffsetByDWARFformat(reader, unit.getFormat()));
-
- case DW_FORM_block1: {
- int length = DWARFUtil.readVarSizedUInt(reader, 1);
- return new DWARFBlobAttribute(reader.readNextByteArray(length));
- }
- case DW_FORM_block2: {
- int length = DWARFUtil.readVarSizedUInt(reader, 2);
- return new DWARFBlobAttribute(reader.readNextByteArray(length));
- }
- case DW_FORM_block4: {
- int length = DWARFUtil.readVarSizedUInt(reader, 4);
- if (length < 0 || length > MAX_BLOCK4_SIZE) {
- throw new IOException("Invalid/bad dw_form_block4 size: " + length);
- }
- return new DWARFBlobAttribute(reader.readNextByteArray(length));
- }
- case DW_FORM_block: {
- int length = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
- if (length < 0 || length > MAX_BLOCK4_SIZE) {
- throw new IOException("Invalid/bad dw_form_block size: " + length);
- }
- return new DWARFBlobAttribute(reader.readNextByteArray(length));
- }
- case DW_FORM_data1:
- return new DWARFNumericAttribute(8, reader.readNextByte(), true, true);
- case DW_FORM_data2:
- return new DWARFNumericAttribute(16, reader.readNextShort(), true, true);
- case DW_FORM_data4:
- return new DWARFNumericAttribute(32, reader.readNextInt(), true, true);
- case DW_FORM_data8:
- return new DWARFNumericAttribute(64, reader.readNextLong(), true, true);
- case DW_FORM_sdata:
- return new DWARFNumericAttribute(64, reader.readNext(LEB128::signed), true);
- case DW_FORM_udata:
- return new DWARFNumericAttribute(64, reader.readNext(LEB128::unsigned), false);
-
- case DW_FORM_exprloc: {
- int length = reader.readNextUnsignedVarIntExact(LEB128::unsigned);
- if (length < 0 || length > MAX_BLOCK4_SIZE) {
- throw new IOException("Invalid/bad dw_form_exprloc size: " + length);
- }
- return new DWARFBlobAttribute(reader.readNextByteArray(length));
- }
-
- case DW_FORM_flag:
- return DWARFBooleanAttribute.get(reader.readNextByte() != 0);
- case DW_FORM_flag_present:
- return DWARFBooleanAttribute.TRUE;
-
- case DW_FORM_string:
- return new DWARFStringAttribute(reader.readNextUtf8String());
- case DW_FORM_strp:
- // Note: we can either read the string from the string section (via. the
- // string table) here and put it in a DWARFStringAttribute and hope
- // it is used and not wasted memory, or use a DWARFDeferredStringAttribute
- // to hold the offset until the string is actually requested in DIEAggregate.getString()
- long stringOffset = DWARFUtil.readOffsetByDWARFformat(reader, unit.getFormat());
- if (!debugStrings.isValid(stringOffset))
- throw new IOException("Bad string offset " + Long.toHexString(stringOffset));
- return new DWARFDeferredStringAttribute(stringOffset);
- //return new DWARFStringAttribute(debugStrings.getStringAtOffset(stringOffset));
-
- case DW_FORM_ref_sig8:
- throw new UnsupportedOperationException(
- "DW_FORM_ref_sig8 is currently not implemented");
-
- // Indirect Form
- case DW_FORM_indirect:
- DWARFForm formValue =
- DWARFForm.find(reader.readNextUnsignedVarIntExact(LEB128::unsigned));
- DWARFAttributeValue value = read(reader, unit, formValue);
-
- return new DWARFIndirectAttribute(value, formValue);
- default:
- }
- throw new IllegalArgumentException("Unknown DWARF Form: " + form.toString());
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFIndirectAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFIndirectAttribute.java
deleted file mode 100644
index ed0ae0765b..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFIndirectAttribute.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/* ###
- * 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.attribs;
-
-import ghidra.app.util.bin.format.dwarf4.DWARFAbbreviation;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-
-/**
- * DWARF indirect attribute.
- *
- * Holds a reference to an actual {@link DWARFAttributeValue} instance and its {@link DWARFForm type}.
- *
- * Used with DW_FORM_indirect attributes that encode the {@link DWARFForm form type} of the attribute
- * value inline instead of in the DIE's {@link DWARFAbbreviation abbreviation}.
- *
- */
-public class DWARFIndirectAttribute implements DWARFAttributeValue {
- private DWARFAttributeValue value;
- private DWARFForm form;
-
- public DWARFIndirectAttribute(DWARFAttributeValue value, DWARFForm form) {
- this.value = value;
- this.form = form;
- }
-
- public DWARFAttributeValue getValue() {
- return value;
- }
-
- public DWARFForm getForm() {
- return form;
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFNumericAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFNumericAttribute.java
deleted file mode 100644
index 31a5273901..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFNumericAttribute.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/* ###
- * 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.attribs;
-
-import ghidra.program.model.scalar.Scalar;
-
-/**
- * DWARF numeric attribute.
- */
-public class DWARFNumericAttribute extends Scalar implements DWARFAttributeValue {
-
- private final boolean ambiguous;
-
- /**
- * Creates a new numeric value, using 64 bits and marked as signed
- *
- * @param value long 64 bit value
- */
- public DWARFNumericAttribute(long value) {
- this(64, value, true, false);
- }
-
- /**
- * Creates a new numeric value, using the specific bitLength and value.
- *
- * @param bitLength number of bits, valid values are 1..64, or 0 if value is also 0
- * @param value value of the scalar, any bits that are set above bitLength will be ignored
- * @param signed true for a signed value, false for an unsigned value.
- */
- public DWARFNumericAttribute(int bitLength, long value, boolean signed) {
- this(bitLength, value, signed, false);
- }
-
- /**
- * Creates a new numeric value, using the specific bitLength and value.
- *
- * @param bitLength number of bits, valid values are 1..64, or 0 if value is also 0
- * @param value value of the scalar, any bits that are set above bitLength will be ignored
- * @param signed true for a signed value, false for an unsigned value.
- * @param ambiguous true for value with ambiguous signedness ({@code signed} parameter should
- * not be trusted), false for value where the {@code signed} parameter is known to be correct
- */
- public DWARFNumericAttribute(int bitLength, long value, boolean signed, boolean ambiguous) {
- super(bitLength, value, signed);
- this.ambiguous = ambiguous;
- }
-
- /**
- * {@return boolean flag, if true this value's signedness is up to the user of the value,
- * if false the signedness was determined when the value was constructed}
- */
- public boolean isAmbiguousSignedness() {
- return ambiguous;
- }
-
- /**
- * {@return the value, forcing the signedness of ambiguous values using the specified hint}
- * @param signednessHint true to default to a signed value, false to default to an
- * unsigned value
- */
- public long getValueWithSignednessHint(boolean signednessHint) {
- return getValue(ambiguous ? signednessHint : isSigned());
- }
-
- @Override
- public String toString() {
- return String.format("DWARFNumericAttribute: %d [%08x]", getValue(), getValue());
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAttribute.java
deleted file mode 100644
index 9048590952..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFAttribute.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/* ###
- * 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.encoding;
-
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
-
-public final class DWARFAttribute {
- public static final int DW_AT_sibling = 0x1;
- public static final int DW_AT_location = 0x2;
- public static final int DW_AT_name = 0x3;
- public static final int DW_AT_ordering = 0x9;
- //public static final int DW_AT_subscr_data = 0xa;
- public static final int DW_AT_byte_size = 0xb;
- public static final int DW_AT_bit_offset = 0xc;
- public static final int DW_AT_bit_size = 0xd;
- //public static final int DW_AT_element_list = 0xf;
- public static final int DW_AT_stmt_list = 0x10;
- public static final int DW_AT_low_pc = 0x11;
- public static final int DW_AT_high_pc = 0x12;
- public static final int DW_AT_language = 0x13;
- //public static final int DW_AT_member = 0x14;
- public static final int DW_AT_discr = 0x15;
- public static final int DW_AT_discr_value = 0x16;
- public static final int DW_AT_visibility = 0x17;
- public static final int DW_AT_import = 0x18;
- public static final int DW_AT_string_length = 0x19;
- public static final int DW_AT_common_reference = 0x1a;
- public static final int DW_AT_comp_dir = 0x1b;
- public static final int DW_AT_const_value = 0x1c;
- public static final int DW_AT_containing_type = 0x1d;
- public static final int DW_AT_default_value = 0x1e;
- public static final int DW_AT_inline = 0x20;
- public static final int DW_AT_is_optional = 0x21;
- public static final int DW_AT_lower_bound = 0x22;
- public static final int DW_AT_producer = 0x25;
- public static final int DW_AT_prototyped = 0x27;
- public static final int DW_AT_return_addr = 0x2a;
- public static final int DW_AT_start_scope = 0x2c;
- public static final int DW_AT_bit_stride = 0x2e;
- public static final int DW_AT_upper_bound = 0x2f;
- public static final int DW_AT_abstract_origin = 0x31;
- public static final int DW_AT_accessibility = 0x32;
- public static final int DW_AT_address_class = 0x33;
- public static final int DW_AT_artificial = 0x34;
- public static final int DW_AT_base_types = 0x35;
- public static final int DW_AT_calling_convention = 0x36;
- public static final int DW_AT_count = 0x37;
- public static final int DW_AT_data_member_location = 0x38;
- public static final int DW_AT_decl_column = 0x39;
- public static final int DW_AT_decl_file = 0x3a;
- public static final int DW_AT_decl_line = 0x3b;
- public static final int DW_AT_declaration = 0x3c;
- public static final int DW_AT_discr_list = 0x3d;
- public static final int DW_AT_encoding = 0x3e;
- public static final int DW_AT_external = 0x3f;
- public static final int DW_AT_frame_base = 0x40;
- public static final int DW_AT_friend = 0x41;
- public static final int DW_AT_identifier_case = 0x42;
- public static final int DW_AT_macro_info = 0x43;
- public static final int DW_AT_namelist_item = 0x44;
- public static final int DW_AT_priority = 0x45;
- public static final int DW_AT_segment = 0x46;
- public static final int DW_AT_specification = 0x47;
- public static final int DW_AT_static_link = 0x48;
- public static final int DW_AT_type = 0x49;
- public static final int DW_AT_use_location = 0x4a;
- public static final int DW_AT_variable_parameter = 0x4b;
- public static final int DW_AT_virtuality = 0x4c;
- public static final int DW_AT_vtable_elem_location = 0x4d;
- public static final int DW_AT_allocated = 0x4e;
- public static final int DW_AT_associated = 0x4f;
- public static final int DW_AT_data_location = 0x50;
- public static final int DW_AT_byte_stride = 0x51;
- public static final int DW_AT_entry_pc = 0x52;
- public static final int DW_AT_use_UTF8 = 0x53;
- public static final int DW_AT_extension = 0x54;
- public static final int DW_AT_ranges = 0x55;
- public static final int DW_AT_trampoline = 0x56;
- public static final int DW_AT_call_column = 0x57;
- public static final int DW_AT_call_file = 0x58;
- public static final int DW_AT_call_line = 0x59;
- public static final int DW_AT_description = 0x5a;
- public static final int DW_AT_binary_scale = 0x5b;
- public static final int DW_AT_decimal_scale = 0x5c;
- public static final int DW_AT_small = 0x5d;
- public static final int DW_AT_decimal_sign = 0x5e;
- public static final int DW_AT_digit_count = 0x5f;
- public static final int DW_AT_picture_string = 0x60;
- public static final int DW_AT_mutable = 0x61;
- public static final int DW_AT_threads_scaled = 0x62;
- public static final int DW_AT_explicit = 0x63;
- public static final int DW_AT_object_pointer = 0x64;
- public static final int DW_AT_endianity = 0x65;
- public static final int DW_AT_elemental = 0x66;
- public static final int DW_AT_pure = 0x67;
- public static final int DW_AT_recursive = 0x68;
- public static final int DW_AT_signature = 0x69;
- public static final int DW_AT_main_subprogram = 0x6a;
- public static final int DW_AT_data_bit_offset = 0x6b;
- public static final int DW_AT_const_expr = 0x6c;
- public static final int DW_AT_enum_class = 0x6d;
- public static final int DW_AT_linkage_name = 0x6e;
- public static final int DW_AT_string_length_bit_size = 0x6f;
- public static final int DW_AT_string_length_byte_size = 0x70;
- public static final int DW_AT_rank = 0x71;
- public static final int DW_AT_str_offsets_base = 0x72;
- public static final int DW_AT_addr_base = 0x73;
- public static final int DW_AT_rnglists_base = 0x74;
- // 0x75 reserved, unused
- public static final int DW_AT_dwo_name = 0x76;
- public static final int DW_AT_reference = 0x77;
- public static final int DW_AT_rvalue_reference = 0x78;
- public static final int DW_AT_macros = 0x79;
- public static final int DW_AT_call_all_calls = 0x7a;
- public static final int DW_AT_call_all_source_calls = 0x7b;
- public static final int DW_AT_call_all_tail_calls = 0x7c;
- public static final int DW_AT_call_return_pc = 0x7d;
- public static final int DW_AT_call_value = 0x7e;
- public static final int DW_AT_call_origin = 0x7f;
- public static final int DW_AT_call_parameter = 0x80;
- public static final int DW_AT_call_pc = 0x81;
- public static final int DW_AT_call_tail_call = 0x82;
- public static final int DW_AT_call_target = 0x83;
- public static final int DW_AT_call_target_clobbered = 0x84;
- public static final int DW_AT_call_data_location = 0x85;
- public static final int DW_AT_call_data_value = 0x86;
- public static final int DW_AT_noreturn = 0x87;
- public static final int DW_AT_alignment = 0x88;
- public static final int DW_AT_export_symbols = 0x89;
- public static final int DW_AT_deleted = 0x8a;
- public static final int DW_AT_defaulted = 0x8b;
- public static final int DW_AT_loclists_base = 0x8c;
-
- public static final int DW_AT_lo_user = 0x2000;
- public static final int DW_AT_hi_user = 0x3fff;
- public static final int DW_AT_MIPS_linkage_name = 0x2007;
-
- // GNU DebugFission stuff
- public static final int DW_AT_GNU_dwo_name = 0x2130;
- public static final int DW_AT_GNU_dwo_id = 0x2131;
- public static final int DW_AT_GNU_ranges_base = 0x2132;
- public static final int DW_AT_GNU_addr_base = 0x2133;
- public static final int DW_AT_GNU_pubnames = 0x2134;
- public static final int DW_AT_GNU_pubtypes = 0x2135;
- // end GNU DebugFission
-
- // Golang
- public static final int DW_AT_go_kind = 0x2900;
- public static final int DW_AT_go_key = 0x2901;
- public static final int DW_AT_go_elem = 0x2902;
- public static final int DW_AT_go_embedded_field = 0x2903;
- public static final int DW_AT_go_runtime_type = 0x2904;
- public static final int DW_AT_go_package_name = 0x2905;
- public static final int DW_AT_go_dict_index = 0x2906;
- // end Golang
-
- // Apple proprietary tags
- public static final int DW_AT_APPLE_ptrauth_key = 0x3e04;
- public static final int DW_AT_APPLE_ptrauth_address_discriminated = 0x3e05;
- public static final int DW_AT_APPLE_ptrauth_extra_discriminator = 0x3e06;
- public static final int DW_AT_APPLE_omit_frame_ptr = 0x3fe7;
- public static final int DW_AT_APPLE_optimized = 0x3fe1;
- // end Apple proprietary tags
-
- public static String toString(long value) {
- return DWARFUtil.toString(DWARFAttribute.class, value);
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFChildren.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFChildren.java
deleted file mode 100644
index b20c6e0aa0..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFChildren.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ###
- * 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.encoding;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * DWARF child determination consts from www.dwarfstd.org/doc/DWARF4.pdf.
- *
- * Yes, its a direct equiv to a boolean, but its in the spec.
- */
-public enum DWARFChildren
-{
- DW_CHILDREN_no(0),
- DW_CHILDREN_yes(1);
-
- private final int value;
-
- private static final Map valueMap;
-
- static {
- valueMap = new HashMap();
- for(DWARFChildren access : DWARFChildren.values()) {
- valueMap.put(access.getValue(), access);
- }
- }
-
- private DWARFChildren(int value) {
- this.value = value;
- }
-
- /**
- * Get the integer value of this enum.
- * @return the integer value of the enum
- */
- public int getValue() {
- return this.value;
- }
-
- /**
- * Find the children value given a Number value.
- * @param key Number value to check
- * @return DWARFChildren enum if it exists
- * @throws IllegalArgumentException if the key is not found
- */
- public static DWARFChildren find(Number key) {
- DWARFChildren access = valueMap.get(key.intValue());
- if(access != null)
- return access;
- throw new IllegalArgumentException("Invalid Integer value: " + key.toString());
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFForm.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFForm.java
deleted file mode 100644
index 8f718aa429..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFForm.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/* ###
- * 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.encoding;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * DWARF attribute encoding consts from www.dwarfstd.org/doc/DWARF4.pdf
- */
-public enum DWARFForm {
- NULL(0x0),
- DW_FORM_addr(0x1),
- DW_FORM_block2(0x3),
- DW_FORM_block4(0x4),
- DW_FORM_data2(0x5),
- DW_FORM_data4(0x6),
- DW_FORM_data8(0x7),
- DW_FORM_string(0x8),
- DW_FORM_block(0x9),
- DW_FORM_block1(0xa),
- DW_FORM_data1(0xb),
- DW_FORM_flag(0xc),
- DW_FORM_sdata(0xd),
- DW_FORM_strp(0xe),
- DW_FORM_udata(0xf),
- DW_FORM_ref_addr(0x10),
- DW_FORM_ref1(0x11),
- DW_FORM_ref2(0x12),
- DW_FORM_ref4(0x13),
- DW_FORM_ref8(0x14),
- DW_FORM_ref_udata(0x15),
- DW_FORM_indirect(0x16),
- DW_FORM_sec_offset(0x17),
- DW_FORM_exprloc(0x18),
- DW_FORM_flag_present(0x19),
- DW_FORM_ref_sig8(0x20);
-
- private final int value;
-
- private static final Map valueMap;
-
- static {
- valueMap = new HashMap<>();
- for (DWARFForm access : DWARFForm.values()) {
- valueMap.put(access.getValue(), access);
- }
- }
-
- private DWARFForm(int value) {
- this.value = value;
- }
-
- /**
- * Get the integer value of this enum.
- * @return the integer value of the enum
- */
- public int getValue() {
- return this.value;
- }
-
- /**
- * Find the form value given a Number value.
- * @param key Number value to check
- * @return DWARFForm enum if it exists
- * @throws IllegalArgumentException if the key is not found
- */
- public static DWARFForm find(int key) {
- DWARFForm access = valueMap.get(key);
- if (access != null) {
- return access;
- }
- throw new IllegalArgumentException("Invalid Integer value: " + key);
- }
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFTag.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFTag.java
deleted file mode 100644
index b7016c7ad4..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/encoding/DWARFTag.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/* ###
- * 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.encoding;
-
-/**
- * DWARF uses a series of debugging information entries to define a
- * low-level representation of a source program. Each debugging
- * information entry is described by an identifying tag and
- * contains a series of attributes. The tag specifies the class
- * to which an entry belongs, and the attributes define the
- * specific characteristics of the entry.
- *
- * The debugging information entries in DWARF Version 2, 3, and 4 are
- * intended to exist in the .debug_info section of an object file.
- *
- * The set of required tag names is listed below.
- */
-public final class DWARFTag
-{
- public static final int DW_TAG_array_type = 0x1;
- public static final int DW_TAG_class_type = 0x2;
- public static final int DW_TAG_entry_point = 0x3;
- public static final int DW_TAG_enumeration_type = 0x4;
- public static final int DW_TAG_formal_parameter = 0x5;
- public static final int DW_TAG_imported_declaration = 0x8;
- public static final int DW_TAG_label = 0xa;
- public static final int DW_TAG_lexical_block = 0xb;
- public static final int DW_TAG_member = 0xd;
- public static final int DW_TAG_pointer_type = 0xf;
- public static final int DW_TAG_reference_type = 0x10;
- public static final int DW_TAG_compile_unit = 0x11;
- public static final int DW_TAG_string_type = 0x12;
- public static final int DW_TAG_structure_type = 0x13;
- public static final int DW_TAG_subroutine_type = 0x15;
- public static final int DW_TAG_typedef = 0x16;
- public static final int DW_TAG_union_type = 0x17;
- public static final int DW_TAG_unspecified_parameters = 0x18;
- public static final int DW_TAG_variant = 0x19;
- public static final int DW_TAG_common_block = 0x1a;
- public static final int DW_TAG_common_inclusion = 0x1b;
- public static final int DW_TAG_inheritance = 0x1c;
- public static final int DW_TAG_inlined_subroutine = 0x1d;
- public static final int DW_TAG_module = 0x1e;
- public static final int DW_TAG_ptr_to_member_type = 0x1f;
- public static final int DW_TAG_set_type = 0x20;
- public static final int DW_TAG_subrange_type = 0x21;
- public static final int DW_TAG_with_stmt = 0x22;
- public static final int DW_TAG_access_declaration = 0x23;
- public static final int DW_TAG_base_type = 0x24;
- public static final int DW_TAG_catch_block = 0x25;
- public static final int DW_TAG_const_type = 0x26;
- public static final int DW_TAG_constant = 0x27;
- public static final int DW_TAG_enumerator = 0x28;
- public static final int DW_TAG_file_type = 0x29;
- public static final int DW_TAG_friend = 0x2a;
- public static final int DW_TAG_namelist = 0x2b;
- public static final int DW_TAG_namelist_item = 0x2c;
- public static final int DW_TAG_packed_type = 0x2d;
- public static final int DW_TAG_subprogram = 0x2e;
- public static final int DW_TAG_template_type_param = 0x2f;
- public static final int DW_TAG_template_value_param = 0x30;
- public static final int DW_TAG_thrown_type = 0x31;
- public static final int DW_TAG_try_block = 0x32;
- public static final int DW_TAG_variant_part = 0x33;
- public static final int DW_TAG_variable = 0x34;
- public static final int DW_TAG_volatile_type = 0x35;
- public static final int DW_TAG_dwarf_procedure = 0x36;
- public static final int DW_TAG_restrict_type = 0x37;
- public static final int DW_TAG_interface_type = 0x38;
- public static final int DW_TAG_namespace = 0x39;
- public static final int DW_TAG_imported_module = 0x3a;
- public static final int DW_TAG_unspecified_type = 0x3b;
- public static final int DW_TAG_partial_unit = 0x3c;
- public static final int DW_TAG_imported_unit = 0x3d;
- public static final int DW_TAG_mutable_type = 0x3e;
- public static final int DW_TAG_condition = 0x3f;
- public static final int DW_TAG_shared_type = 0x40;
- public static final int DW_TAG_type_unit = 0x41;
- public static final int DW_TAG_rvalue_reference_type = 0x42;
- public static final int DW_TAG_template_alias = 0x43;
- public static final int DW_TAG_call_site = 0x48;
- public static final int DW_TAG_call_site_parameter = 0x49;
- public static final int DW_TAG_lo_user = 0x4080;
- public static final int DW_TAG_gnu_call_site = 0x4109;
- public static final int DW_TAG_gnu_call_site_parameter = 0x410a;
- public static final int DW_TAG_hi_user = 0xffff;
-
- public static final int DW_TAG_APPLE_ptrauth_type = 0x4300; // Apple proprietary
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/StringTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/StringTable.java
deleted file mode 100644
index 1a3cf7da1a..0000000000
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/StringTable.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/* ###
- * 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 java.io.IOException;
-import java.nio.charset.StandardCharsets;
-
-import ghidra.app.util.bin.ByteProvider;
-
-/**
- * A offset-to-String string table backed by a simple byte array (encoded as UTF-8).
- *
- * Requested strings are instantiated when requested.
- */
-public class StringTable {
- private byte[] bytes;
-
- /**
- * Create a {@link StringTable} by reading the entire contents of a {@link ByteProvider}
- * into memory.
- *
- * If the specified {@link ByteProvider} is null, an empty string table will be constructed.
- *
- * @param bp
- * @return
- * @throws IOException
- */
- public static StringTable readStringTable(ByteProvider bp) throws IOException {
- byte[] bytes = (bp != null) ? bp.readBytes(0, bp.length()) : new byte[0];
- return new StringTable(bytes);
- }
-
- /**
- * Creates a StringTable using the bytes contained in the supplied array.
- */
- public StringTable(byte[] bytes) {
- this.bytes = bytes;
- }
-
- /**
- * Returns true if the specified offset is a valid offset for this string table.
- *
- * @param offset
- * @return
- */
- public boolean isValid(long offset) {
- return (offset >= 0) && (offset < bytes.length);
- }
-
- public void clear() {
- bytes = null;
- }
-
- /**
- * Returns the string found at offset, or throws an {@link IOException}
- * if the offset is out of bounds.
- *
- * @param offset
- * @return a string, never null.
- * @throws IOException if not found
- */
- public String getStringAtOffset(long offset) throws IOException {
- if (!isValid(offset)) {
- throw new IOException("Invalid offset requested " + offset);
- }
-
- String tmp = new String(bytes, (int) offset, getNullTermStringLen(bytes, (int) offset),
- StandardCharsets.UTF_8);
-
- return tmp;
- }
-
- private static final int getNullTermStringLen(byte[] bytes, int startOffset) {
- int cp = startOffset;
- while (cp < bytes.length && bytes[cp] != 0) {
- cp++;
- }
- return cp - startOffset;
- }
-
- public int getByteCount() {
- return bytes.length;
- }
-
- /**
- * Modifies the string table to add a string at a specified offset, growing the
- * internal byte[] storage as necessary to accommodate the string at the offset.
- *
- * Used for unit tests to construct a custom string table for test cases.
- *
- * @param offset where to place the string in the table
- * @param s string to insert into table
- */
- public void add(int offset, String s) {
- byte[] sBytes = s.getBytes();
- int newLen = Math.max(bytes.length, offset + sBytes.length + 1);
- byte[] newBytes = new byte[newLen];
- System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
- System.arraycopy(sBytes, 0, newBytes, offset, sBytes.length);
-
- this.bytes = newBytes;
- }
-
-}
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java
index 00a8f4a212..1d9cd12682 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionFixup.java
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.golang;
import java.util.ArrayList;
import java.util.List;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java
index 62cbf71ddd..92c11096b1 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoFunctionMultiReturn.java
@@ -19,7 +19,7 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import ghidra.app.util.bin.format.dwarf4.next.*;
+import ghidra.app.util.bin.format.dwarf.*;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult;
import ghidra.program.model.lang.Register;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java
index 74c1169b27..8fdb451fc0 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoParamStorageAllocator.java
@@ -17,7 +17,7 @@ package ghidra.app.util.bin.format.golang;
import java.util.*;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
index ab2fd04905..c01d261806 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GoRegisterInfoManager.java
@@ -23,7 +23,7 @@ import org.jdom.*;
import org.jdom.input.SAXBuilder;
import generic.jar.ResourceFile;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
import ghidra.program.model.lang.*;
import ghidra.util.Msg;
import ghidra.util.xml.XmlUtilities;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java
index 1ffc556ea3..d50f254488 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/GolangDWARFFunctionFixup.java
@@ -19,11 +19,9 @@ import java.util.*;
import ghidra.app.plugin.core.analysis.TransientProgramProperties;
import ghidra.app.plugin.core.analysis.TransientProgramProperties.SCOPE;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
-import ghidra.app.util.bin.format.dwarf4.funcfixup.DWARFFunctionFixup;
-import ghidra.app.util.bin.format.dwarf4.next.*;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunction.CommitMode;
+import ghidra.app.util.bin.format.dwarf.*;
+import ghidra.app.util.bin.format.dwarf.DWARFFunction.CommitMode;
+import ghidra.app.util.bin.format.dwarf.funcfixup.DWARFFunctionFixup;
import ghidra.app.util.bin.format.golang.rtti.GoFuncData;
import ghidra.app.util.bin.format.golang.rtti.GoRttiMapper;
import ghidra.program.model.address.Address;
@@ -32,7 +30,6 @@ import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SymbolType;
-import ghidra.util.Msg;
import ghidra.util.classfinder.ExtensionPointProperties;
import ghidra.util.task.TaskMonitor;
@@ -66,7 +63,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
*/
public static boolean isGolangFunction(DWARFFunction dfunc) {
DIEAggregate diea = dfunc.diea;
- int cuLang = diea.getCompilationUnit().getCompileUnit().getLanguage();
+ int cuLang = diea.getCompilationUnit().getLanguage();
if (cuLang != DWARFSourceLanguage.DW_LANG_Go) {
return false;
}
@@ -175,12 +172,11 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
spillVars.add(dvar);
if (dvar.type instanceof Structure &&
dvar.getStorageSize() != dvar.type.getLength()) {
- Msg.warn(GoFunctionFixup.class,
- "Known storage allocation problem: func %s@%s param %s register allocation for structs missing inter-field padding."
- .formatted(dfunc.name.getName(), dfunc.address,
- dvar.name.getName()));
+ dfunc.getProgram()
+ .logWarningAt(dfunc.address, dfunc.name.getName(),
+ "Golang known storage allocation problem: param \"%s\" register allocation for structs missing inter-field padding."
+ .formatted(dvar.name.getName()));
}
-
}
else {
if (!dvar.isZeroByte()) {
@@ -210,7 +206,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
// because we will do it manually
for (DataTypeComponent dtc : multiReturn.getNormalStorageComponents()) {
allocateReturnStorage(dfunc, dfunc.retval,
- dtc.getFieldName() + "-return-result-alias", dtc.getDataType(),
+ dtc.getFieldName() + "_return_result_alias", dtc.getDataType(),
storageAllocator, false);
}
@@ -218,7 +214,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
// the decompiler's expectations for storage layout)
for (DataTypeComponent dtc : multiReturn.getStackStorageComponents()) {
allocateReturnStorage(dfunc, dfunc.retval,
- dtc.getFieldName() + "-return-result-alias", dtc.getDataType(),
+ dtc.getFieldName() + "_return_result_alias", dtc.getDataType(),
storageAllocator, false);
}
@@ -231,7 +227,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
}
}
else {
- allocateReturnStorage(dfunc, dfunc.retval, "return-value-alias-variable",
+ allocateReturnStorage(dfunc, dfunc.retval, "return_value_alias_variable",
dfunc.retval.type, storageAllocator, true);
}
}
@@ -251,7 +247,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
// by variables that we create artificially.
for (DWARFVariable dvar : spillVars) {
DWARFVariable spill = DWARFVariable.fromDataType(dfunc, dvar.type);
- String paramName = dvar.name.getName() + "-spill";
+ String paramName = dvar.name.getName() + "_spill";
spill.name = dvar.name.replaceName(paramName, paramName);
spill.setStackStorage(storageAllocator.getStackAllocation(spill.type));
dfunc.localVars.add(spill);
@@ -282,8 +278,7 @@ public class GolangDWARFFunctionFixup implements DWARFFunctionFixup {
private DWARFVariable createReturnResultAliasVar(DWARFFunction dfunc, DataType dataType,
String name, long stackOffset) {
- DWARFVariable returnResultVar =
- DWARFVariable.fromDataType(dfunc, dataType);
+ DWARFVariable returnResultVar = DWARFVariable.fromDataType(dfunc, dataType);
returnResultVar.name = dfunc.name.createChild(name, name, SymbolType.LOCAL_VAR);
returnResultVar.setStackStorage(stackOffset);
return returnResultVar;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
index f5e194dc4b..4a8e8853e3 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoRttiMapper.java
@@ -29,8 +29,8 @@ import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.plugin.core.analysis.TransientProgramProperties;
import ghidra.app.plugin.core.datamgr.util.DataTypeArchiveUtility;
import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeConflictHandler;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.DWARFDataTypeConflictHandler;
+import ghidra.app.util.bin.format.dwarf.DWARFProgram;
import ghidra.app.util.bin.format.golang.*;
import ghidra.app.util.bin.format.golang.rtti.types.*;
import ghidra.app.util.bin.format.golang.structmapping.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoString.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoString.java
index 162144b3d7..a142e77831 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoString.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/GoString.java
@@ -19,7 +19,7 @@ import java.io.IOException;
import java.util.function.Predicate;
import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFDataInstanceHelper;
+import ghidra.app.util.bin.format.dwarf.DWARFDataInstanceHelper;
import ghidra.app.util.bin.format.golang.structmapping.*;
import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
index 85f7de8b62..db5ba15483 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/rtti/types/GoStructType.java
@@ -18,7 +18,7 @@ package ghidra.app.util.bin.format.golang.rtti.types;
import java.io.IOException;
import java.util.*;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
import ghidra.app.util.bin.format.golang.rtti.GoName;
import ghidra.app.util.bin.format.golang.rtti.GoSlice;
import ghidra.app.util.bin.format.golang.structmapping.*;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/DataTypeMapper.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/DataTypeMapper.java
index 246e3da45d..690b4aa795 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/DataTypeMapper.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/DataTypeMapper.java
@@ -21,7 +21,7 @@ import java.util.*;
import generic.jar.ResourceFile;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.MemoryByteProvider;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFDataTypeConflictHandler;
+import ghidra.app.util.bin.format.dwarf.DWARFDataTypeConflictHandler;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java
index e716c8432b..93682197b2 100644
--- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java
+++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/golang/structmapping/MarkupSession.java
@@ -19,8 +19,8 @@ import java.io.IOException;
import java.lang.reflect.Array;
import java.util.*;
-import ghidra.app.util.bin.format.dwarf4.DWARFUtil;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFDataInstanceHelper;
+import ghidra.app.util.bin.format.dwarf.DWARFDataInstanceHelper;
+import ghidra.app.util.bin.format.dwarf.DWARFUtil;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFConflictHandlerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFConflictHandlerTest.java
similarity index 99%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFConflictHandlerTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFConflictHandlerTest.java
index 75298dc17e..e6502c3afb 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFConflictHandlerTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFConflictHandlerTest.java
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import static org.junit.Assert.*;
import org.junit.*;
+import ghidra.app.util.bin.format.dwarf.DWARFDataTypeConflictHandler;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java
similarity index 98%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java
index c33f431603..5c5c21c7b4 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFDataTypeImporterTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
@@ -23,9 +23,6 @@ import java.util.*;
import org.junit.Test;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
import ghidra.program.model.data.*;
import ghidra.program.model.data.Enum;
import ghidra.program.model.symbol.SymbolUtilities;
@@ -1318,12 +1315,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase {
buildMockDIEIndexes();
- DWARFNameInfo sDNI = dwarfProg.getName(getAggregate(structDIE));
- DWARFNameInfo exactDNI = dwarfProg.getName(getAggregate(exactDIE));
- DWARFNameInfo exactTemplateDNI = dwarfProg.getName(getAggregate(exactTemplateDIE));
- DWARFNameInfo exactTemplateDNI2 = dwarfProg.getName(getAggregate(exactTemplateDIE2));
- DWARFNameInfo templateDNI = dwarfProg.getName(getAggregate(templateDIE));
- DWARFNameInfo s3DNI = dwarfProg.getName(getAggregate(struct3DIE));
+ DWARFName sDNI = dwarfProg.getName(getAggregate(structDIE));
+ DWARFName exactDNI = dwarfProg.getName(getAggregate(exactDIE));
+ DWARFName exactTemplateDNI = dwarfProg.getName(getAggregate(exactTemplateDIE));
+ DWARFName exactTemplateDNI2 = dwarfProg.getName(getAggregate(exactTemplateDIE2));
+ DWARFName templateDNI = dwarfProg.getName(getAggregate(templateDIE));
+ DWARFName s3DNI = dwarfProg.getName(getAggregate(struct3DIE));
assertEquals(structLongName, sDNI.getOriginalName());
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java
similarity index 97%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java
index 3b936c8075..af00c4c1d1 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFFunctionImporterTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import static org.junit.Assert.*;
@@ -23,10 +23,8 @@ import java.util.List;
import org.junit.Test;
import ghidra.app.util.NamespaceUtils;
-import ghidra.app.util.bin.format.dwarf4.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
-import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute;
+import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionOpCodes;
import ghidra.program.database.function.OverlappingFunctionException;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.*;
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFNameInfoTest.java
similarity index 88%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFNameInfoTest.java
index 901f93eab5..f4f04010fa 100644
--- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFNameInfoTest.java
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFNameInfoTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
import static org.junit.Assert.*;
@@ -21,7 +21,6 @@ import java.io.IOException;
import org.junit.Test;
-import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.symbol.Namespace;
@@ -30,12 +29,12 @@ import ghidra.util.exception.CancelledException;
public class DWARFNameInfoTest extends DWARFTestBase {
- private DWARFNameInfo root =
- DWARFNameInfo.createRoot(new CategoryPath(CategoryPath.ROOT, "TEST_DNI"));
+ private DWARFName root =
+ DWARFName.createRoot(new CategoryPath(CategoryPath.ROOT, "TEST_DNI"));
@Test
public void testSimple() {
- DWARFNameInfo dni = root.createChild("simplename", "simplename", SymbolType.CLASS);
+ DWARFName dni = root.createChild("simplename", "simplename", SymbolType.CLASS);
assertEquals(new CategoryPath("/TEST_DNI/simplename"), dni.asCategoryPath());
assertEquals(
NamespacePath.create(NamespacePath.ROOT, "simplename", SymbolType.CLASS),
@@ -44,7 +43,7 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testSlash() {
- DWARFNameInfo dni = root.createChild("blah/", "blah/", SymbolType.CLASS);
+ DWARFName dni = root.createChild("blah/", "blah/", SymbolType.CLASS);
assertEquals(new CategoryPath(CategoryPath.ROOT, "TEST_DNI", "blah/"),
dni.asCategoryPath());
@@ -57,8 +56,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testColon() {
- DWARFNameInfo dni = root.createChild("blah::blah", "blah::blah", SymbolType.CLASS);
- DWARFNameInfo dni2 = dni.createChild("sub::sub", "sub::sub", SymbolType.CLASS);
+ DWARFName dni = root.createChild("blah::blah", "blah::blah", SymbolType.CLASS);
+ DWARFName dni2 = dni.createChild("sub::sub", "sub::sub", SymbolType.CLASS);
assertEquals(new CategoryPath("/TEST_DNI/blah::blah/sub::sub"),
dni2.asCategoryPath());
@@ -71,8 +70,8 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testNamespaceTypes() {
- DWARFNameInfo dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
- DWARFNameInfo dni_ns1class1 = dni_ns1.createChild("class1", "class1", SymbolType.CLASS);
+ DWARFName dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
+ DWARFName dni_ns1class1 = dni_ns1.createChild("class1", "class1", SymbolType.CLASS);
assertEquals(new CategoryPath("/TEST_DNI/ns1/class1"), dni_ns1class1.asCategoryPath());
Namespace class1_ns = dni_ns1class1.asNamespace(program);
@@ -84,12 +83,12 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testNamespaceConvertToClass() {
// tests that a plain namespace can be 'upgraded' to a class namespace
- DWARFNameInfo dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
+ DWARFName dni_ns1 = root.createChild("ns1", "ns1", SymbolType.NAMESPACE);
Namespace ns1 = dni_ns1.asNamespace(program);
assertFalse(ns1 instanceof GhidraClass);
- DWARFNameInfo dni_ns1a = root.createChild("ns1", "ns1", SymbolType.CLASS);
+ DWARFName dni_ns1a = root.createChild("ns1", "ns1", SymbolType.CLASS);
Namespace ns1a = dni_ns1a.asNamespace(program);
assertTrue(ns1a instanceof GhidraClass);
}
@@ -97,12 +96,12 @@ public class DWARFNameInfoTest extends DWARFTestBase {
@Test
public void testClassConvertToNamespace() {
// tests that a class namespace isn't 'downgraded' to a plain namespace
- DWARFNameInfo dni_class1 = root.createChild("class1", "class1", SymbolType.CLASS);
+ DWARFName dni_class1 = root.createChild("class1", "class1", SymbolType.CLASS);
Namespace class1 = dni_class1.asNamespace(program);
assertTrue(class1 instanceof GhidraClass);
- DWARFNameInfo dni_class1a = root.createChild("class1", "class1", SymbolType.NAMESPACE);
+ DWARFName dni_class1a = root.createChild("class1", "class1", SymbolType.NAMESPACE);
Namespace class1a = dni_class1a.asNamespace(program);
// symbol should NOT have been converted to a plain namespace.
assertTrue(class1a instanceof GhidraClass);
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/dwarf/DWARFStaticVarImporterTest.java
similarity index 94%
rename from Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java
rename to Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFStaticVarImporterTest.java
index d900764cec..85864100ae 100644
--- 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/dwarf/DWARFStaticVarImporterTest.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.next;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
@@ -24,9 +24,7 @@ import java.util.Set;
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.app.util.bin.format.dwarf.expression.DWARFExpressionOpCodes;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java
new file mode 100644
index 0000000000..51fe051395
--- /dev/null
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java
@@ -0,0 +1,136 @@
+/* ###
+ * 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.dwarf;
+
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*;
+
+import java.util.*;
+
+import ghidra.app.util.bin.format.dwarf.attribs.*;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.AttrDef;
+
+/**
+ * Helper class to create mock DebugInfoEntry instances for use during junit tests.
+ */
+public class DIECreator {
+ record AttrInfo(DWARFAttribute attribute, AttrDef spec, DWARFAttributeValue value) {}
+
+ private MockDWARFProgram dwarfProg;
+ private DWARFTag tag;
+ private Map attributes = new HashMap<>();
+ private DebugInfoEntry parent;
+
+ public DIECreator(MockDWARFProgram dwarfProg, DWARFTag tag) {
+ this.dwarfProg = dwarfProg;
+ this.tag = tag;
+ }
+
+ private void add(AttrDef attrSpec, DWARFAttributeValue attrVal) {
+ attributes.put(attrSpec.getAttributeId(),
+ new AttrInfo(attrSpec.getAttributeId(), attrSpec, attrVal));
+ }
+
+ public DIECreator addString(DWARFAttribute attribute, String value) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_string, 0);
+ add(attrSpec, new DWARFStringAttribute(value, attrSpec));
+ return this;
+ }
+
+ public DIECreator addUInt(DWARFAttribute attribute, long value) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_udata, 0);
+ add(attrSpec, new DWARFNumericAttribute(value, attrSpec));
+ return this;
+ }
+
+ public DIECreator addInt(DWARFAttribute attribute, long value) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_sdata, 0);
+ add(attrSpec, new DWARFNumericAttribute(value, attrSpec));
+ return this;
+ }
+
+ public DIECreator addRef(DWARFAttribute attribute, DebugInfoEntry die) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_ref8, 0);
+ add(attrSpec, new DWARFNumericAttribute(die.getOffset(), attrSpec));
+ return this;
+ }
+
+ public DIECreator addRef(DWARFAttribute attribute, long offset) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_ref8, 0);
+ add(attrSpec, new DWARFNumericAttribute(offset, attrSpec));
+ return this;
+ }
+
+ public DIECreator addBoolean(DWARFAttribute attribute, boolean value) {
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_flag, 0);
+ add(attrSpec, new DWARFBooleanAttribute(value, attrSpec));
+ return this;
+ }
+
+ public DIECreator addBlock(DWARFAttribute attribute, int... intBytes) {
+ byte[] bytes = new byte[intBytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) intBytes[i];
+ }
+ AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_block1, 0);
+ add(attrSpec, new DWARFBlobAttribute(bytes, attrSpec));
+ return this;
+ }
+
+ AttrDef[] makeAttrSpecArray() {
+ AttrDef[] attrSpecs = new AttrDef[attributes.size()];
+ List attrInfoList = new ArrayList<>(attributes.values());
+ for (int i = 0; i < attrInfoList.size(); i++) {
+ AttrInfo attrInfo = attrInfoList.get(i);
+ attrSpecs[i] = attrInfo.spec;
+ }
+ return attrSpecs;
+ }
+
+ public DIECreator setParent(DebugInfoEntry parent) {
+ this.parent = parent;
+ return this;
+ }
+
+ public DebugInfoEntry createRootDIE() {
+ MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit();
+ DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag);
+ DebugInfoEntry die = dwarfProg.addDIE(abbr, null);
+
+ int attrNum = 0;
+ for (AttrInfo attrInfo : attributes.values()) {
+ die.setAttributeValue(attrNum++, attrInfo.value);
+ }
+
+ return die;
+ }
+
+ public DebugInfoEntry create() {
+ MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit();
+ if (cu == null) {
+ cu = dwarfProg.addCompUnit();
+ }
+ DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag);
+ DebugInfoEntry die =
+ dwarfProg.addDIE(abbr, parent != null ? parent : cu.getCompileUnitDIE());
+
+ int attrNum = 0;
+ for (AttrInfo attrInfo : attributes.values()) {
+ die.setAttributeValue(attrNum++, attrInfo.value);
+ }
+
+ return die;
+ }
+}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreatorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java
similarity index 96%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreatorTest.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java
index 8a472bf6ef..f68db68b94 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreatorTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java
@@ -13,16 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
+import ghidra.app.util.bin.format.dwarf.*;
import ghidra.util.exception.CancelledException;
/**
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/dwarf/DWARFTestBase.java
similarity index 89%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DWARFTestBase.java
index f8c68df4f0..5ef82fce88 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/dwarf/DWARFTestBase.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding.*;
-import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFEncoding.*;
+import static ghidra.app.util.bin.format.dwarf.DWARFTag.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
@@ -27,9 +27,9 @@ import org.junit.Before;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.services.DataTypeManagerService;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.next.*;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.NullSectionProvider;
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.ByteArrayProvider;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.NullSectionProvider;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.DataTypeManagerDB;
@@ -57,14 +57,16 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
protected DWARFImportOptions importOptions;
protected MockDWARFProgram dwarfProg;
- protected MockDWARFCompilationUnit currentCU;
+ protected MockDWARFCompilationUnit cu;
protected DWARFDataTypeManager dwarfDTM;
+ protected MockStringTable stringTable;
protected CategoryPath uncatCP;
protected CategoryPath dwarfRootCP;
+
@Before
public void setUp() throws Exception {
- program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._X64, this);
+ program = createProgram();
space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataTypeManager();
@@ -81,11 +83,18 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
importOptions = new DWARFImportOptions();
dwarfProg = new MockDWARFProgram(program, importOptions, TaskMonitor.DUMMY,
new NullSectionProvider());
+ stringTable = new MockStringTable(br());
+ dwarfProg.setStringTable(stringTable);
+
dwarfDTM = dwarfProg.getDwarfDTM();
dwarfRootCP = dwarfProg.getRootDNI().asCategoryPath();
uncatCP = dwarfProg.getUncategorizedRootDNI().asCategoryPath();
}
+ public ProgramDB createProgram() throws Exception {
+ return createDefaultProgram(testName.getMethodName(), ProgramBuilder._X64, this);
+ }
+
@After
public void tearDown() throws Exception {
endTransaction();
@@ -101,8 +110,13 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
program.endTransaction(transactionID, true);
}
+ protected BinaryReader br(byte... bytes) {
+ return new BinaryReader(new ByteArrayProvider(bytes), dwarfProg.isLittleEndian());
+ }
+
protected void buildMockDIEIndexes() throws CancelledException, DWARFException {
dwarfProg.buildMockDIEIndexes();
+ dwarfProg.dumpDIEs(System.out);
}
protected void importAllDataTypes() throws CancelledException, IOException, DWARFException {
@@ -123,17 +137,27 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
}
protected void ensureCompUnit() {
- if (dwarfProg.getCurrentCompUnit() == null) {
- dwarfProg.addCompUnit();
+ if (cu == null) {
+ addCompUnit();
}
}
protected MockDWARFCompilationUnit addCompUnit() {
- return dwarfProg.addCompUnit();
+ return addCompUnit(DWARFSourceLanguage.DW_LANG_C);
+ }
+
+ protected MockDWARFCompilationUnit addCompUnit64() {
+ setCompUnit(dwarfProg.addCompUnit(DWARFSourceLanguage.DW_LANG_C, 8 /* dwarf64 */));
+ return cu;
}
protected MockDWARFCompilationUnit addCompUnit(int cuLang) {
- return dwarfProg.addCompUnit(cuLang);
+ setCompUnit(dwarfProg.addCompUnit(cuLang));
+ return cu;
+ }
+
+ protected void setCompUnit(MockDWARFCompilationUnit cu) {
+ this.cu = cu;
}
protected DebugInfoEntry addBaseType(String name, int size, int encoding) {
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/dwarf/MockDWARFCompilationUnit.java
similarity index 50%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFCompilationUnit.java
index 7e8559df59..18bf93b58f 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/dwarf/MockDWARFCompilationUnit.java
@@ -13,31 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
+
+import java.util.Map;
+
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.AttrDef;
public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
- private DebugInfoEntry compUnitDIE;
- private MockDWARFProgram dwarfProgram;
private int dieCount;
public MockDWARFCompilationUnit(MockDWARFProgram dwarfProgram, long startOffset, long endOffset,
- long length, int format, short version, long abbreviationOffset, byte pointerSize,
- int compUnitNumber, int language) {
- super(dwarfProgram, startOffset, endOffset, length, format, version, abbreviationOffset,
- pointerSize, compUnitNumber, startOffset, null);
- this.dwarfProgram = dwarfProgram;
-
- this.compUnit = new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer",
- "Mock Comp Unit Dir", 0, 0, language, false, null);
- }
-
- public void setCompUnitDIE(DebugInfoEntry compUnitDIE) {
- this.compUnitDIE = compUnitDIE;
+ long length, int intSize, short version, byte pointerSize, int compUnitNumber) {
+ super(dwarfProgram, startOffset, endOffset, length, intSize, version, pointerSize,
+ compUnitNumber, startOffset, null);
}
public DebugInfoEntry getCompileUnitDIE() {
- return compUnitDIE;
+ return diea.getHeadFragment();
}
public int incDIECount() {
@@ -46,13 +39,14 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
@Override
public MockDWARFProgram getProgram() {
- return dwarfProgram;
+ return (MockDWARFProgram) dprog;
}
- public DWARFAbbreviation createAbbreviation(DWARFAttributeSpecification[] attrSpecs, int tag) {
+ public DWARFAbbreviation createAbbreviation(AttrDef[] attrSpecs, DWARFTag tag) {
+ Map map = getCodeToAbbreviationMap();
DWARFAbbreviation abbr =
- new DWARFAbbreviation(getCodeToAbbreviationMap().size(), tag, true /*??*/, attrSpecs);
- getCodeToAbbreviationMap().put(abbr.getAbbreviationCode(), abbr);
+ new DWARFAbbreviation(map.size(), tag.getId(), true /*??*/, attrSpecs);
+ map.put(abbr.getAbbreviationCode(), abbr);
return abbr;
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFProgram.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java
similarity index 84%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFProgram.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java
index de2ed3d2e0..112e8b187e 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFProgram.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
+
+import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
@@ -21,11 +23,8 @@ import java.util.List;
import org.junit.Assert;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFSourceLanguage;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFImportOptions;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider;
import ghidra.program.model.listing.Program;
import ghidra.util.datastruct.IntArrayList;
import ghidra.util.datastruct.LongArrayList;
@@ -57,6 +56,10 @@ public class MockDWARFProgram extends DWARFProgram {
}
public MockDWARFCompilationUnit addCompUnit(int cuLang) {
+ return addCompUnit(cuLang, 4 /* dwarf32 */);
+ }
+
+ public MockDWARFCompilationUnit addCompUnit(int cuLang, int dwarfIntSize) {
if (currentCompUnit == null && !compUnitDieIndex.isEmpty()) {
Assert.fail();
}
@@ -66,14 +69,19 @@ public class MockDWARFProgram extends DWARFProgram {
}
long start = compUnits.size() * 0x1000;
currentCompUnit = new MockDWARFCompilationUnit(this, start, start + 0x1000, 0,
- DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 0, cuLang);
-
+ dwarfIntSize, (short) 4, (byte) 8, 0);
compUnits.add(currentCompUnit);
compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit);
- DebugInfoEntry compUnitRootDIE =
- new DIECreator(this, DWARFTag.DW_TAG_compile_unit).createRootDIE();
- currentCompUnit.setCompUnitDIE(compUnitRootDIE);
+ DebugInfoEntry compUnitRootDIE = new DIECreator(this, DWARFTag.DW_TAG_compile_unit)
+ .addInt(DWARFAttribute.DW_AT_language, cuLang)
+ .createRootDIE();
+ try {
+ currentCompUnit.init(compUnitRootDIE);
+ }
+ catch (IOException e) {
+ fail();
+ }
return currentCompUnit;
}
@@ -92,7 +100,7 @@ public class MockDWARFProgram extends DWARFProgram {
int cuDIECount = currentCompUnit.incDIECount();
DebugInfoEntry die =
new DebugInfoEntry(currentCompUnit, currentCompUnit.getStartOffset() + cuDIECount,
- dieIndex, abbr);
+ dieIndex, abbr, new int[abbr.getAttributeCount()]);
diesByOffset.put(die.getOffset(), die);
dieOffsetList.add(die.getOffset());
@@ -121,7 +129,7 @@ public class MockDWARFProgram extends DWARFProgram {
LongArrayList aggrTargets = new LongArrayList();
for (DebugInfoEntry die : dies) {
DIEAggregate diea = DIEAggregate.createSingle(die);
- for (int attr : DIEAggregate.REF_ATTRS) {
+ for (DWARFAttribute attr : REF_ATTRS) {
long refdOffset = diea.getUnsignedLong(attr, -1);
if (refdOffset != -1) {
aggrTargets.add(refdOffset);
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java
new file mode 100644
index 0000000000..e1f14e141f
--- /dev/null
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java
@@ -0,0 +1,44 @@
+/* ###
+ * 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.dwarf;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import ghidra.app.util.bin.*;
+
+public class MockStringTable extends StringTable {
+
+ public MockStringTable(BinaryReader reader) {
+ super(new BinaryReader(new ByteArrayProvider(new byte[4 * 1024]), true /* LE */));
+ }
+
+ public void add(int index, String s) throws IOException {
+ s = s + "\0";
+ byte[] stringBytes = s.getBytes(StandardCharsets.UTF_8);
+ ByteProvider bp = reader.getByteProvider();
+ byte[] allBytes = bp.readBytes(0, bp.length());
+ if ((index + stringBytes.length) >= allBytes.length) {
+ byte[] newBytes = new byte[index + stringBytes.length];
+ System.arraycopy(allBytes, 0, newBytes, 0, allBytes.length);
+ allBytes = newBytes;
+ }
+ System.arraycopy(stringBytes, 0, allBytes, index, stringBytes.length);
+ reader = new BinaryReader(new ByteArrayProvider(allBytes), true /* LE */);
+ cache.clear();
+ }
+
+}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/NamespacePathTest.java
similarity index 94%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/NamespacePathTest.java
index 1df32ffe4e..1235e2cac3 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/NamespacePathTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/NamespacePathTest.java
@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
import static org.junit.Assert.*;
import org.junit.Test;
-import ghidra.app.util.bin.format.dwarf4.next.NamespacePath;
+import ghidra.app.util.bin.format.dwarf.NamespacePath;
import ghidra.program.model.symbol.SymbolType;
public class NamespacePathTest {
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/StringTableTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/StringTableTest.java
similarity index 79%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/StringTableTest.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/StringTableTest.java
index bcd1a6ee39..33002c10b7 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/StringTableTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/StringTableTest.java
@@ -13,20 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4;
+package ghidra.app.util.bin.format.dwarf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.ByteArrayProvider;
-import ghidra.app.util.bin.format.dwarf4.next.StringTable;
+import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import generic.test.AbstractGenericTest;
+import ghidra.app.util.bin.BinaryReader;
+import ghidra.app.util.bin.ByteArrayProvider;
+import ghidra.app.util.bin.format.dwarf.StringTable;
/**
* Test reading DWARF string table
@@ -47,7 +45,7 @@ public class StringTableTest extends AbstractGenericTest {
/* str3 */ (byte) 'x', (byte) 'y', (byte) '\n', (byte) 0
);
// @formatter:on
- StringTable st = StringTable.readStringTable(br.getByteProvider());
+ StringTable st = new StringTable(br);
assertEquals("ab", st.getStringAtOffset(0));
assertEquals("c", st.getStringAtOffset(3));
@@ -65,7 +63,7 @@ public class StringTableTest extends AbstractGenericTest {
/* str3 */ (byte) 'x', (byte) 'y', (byte) '\n', (byte) 0
);
// @formatter:on
- StringTable st = StringTable.readStringTable(br.getByteProvider());
+ StringTable st = new StringTable(br);
assertEquals("ab", st.getStringAtOffset(0));
assertEquals("b", st.getStringAtOffset(1));
@@ -74,7 +72,7 @@ public class StringTableTest extends AbstractGenericTest {
}
@Test
- public void testTrailingOffcutStr() throws IOException {
+ public void testTrailingOffcutStr() {
// @formatter:off
BinaryReader br = br(
/* str1 */ (byte) 'a', (byte) 'b', (byte) 0,
@@ -82,7 +80,7 @@ public class StringTableTest extends AbstractGenericTest {
/* str3 */ (byte) 'x', (byte) 'y', (byte) '\n', (byte) 0
);
// @formatter:on
- StringTable st = StringTable.readStringTable(br.getByteProvider());
+ StringTable st = new StringTable(br);
try {
st.getStringAtOffset(9);
@@ -94,7 +92,7 @@ public class StringTableTest extends AbstractGenericTest {
}
@Test
- public void testNegOffset() throws IOException {
+ public void testNegOffset() {
// @formatter:off
BinaryReader br = br(
/* str1 */ (byte) 'a', (byte) 'b', (byte) 0,
@@ -102,7 +100,7 @@ public class StringTableTest extends AbstractGenericTest {
/* str3 */ (byte) 'x', (byte) 'y', (byte) '\n', (byte) 0
);
// @formatter:on
- StringTable st = StringTable.readStringTable(br.getByteProvider());
+ StringTable st = new StringTable(br);
try {
st.getStringAtOffset(-2);
@@ -114,9 +112,9 @@ public class StringTableTest extends AbstractGenericTest {
}
@Test
- public void testEmptyStrTable() throws IOException {
+ public void testEmptyStrTable() {
BinaryReader br = br();
- StringTable st = StringTable.readStringTable(br.getByteProvider());
+ StringTable st = new StringTable(br);
try {
st.getStringAtOffset(0);
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java
similarity index 70%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryTest.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java
index 178dd23475..a8451ffe93 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java
@@ -13,60 +13,40 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.attribs;
+package ghidra.app.util.bin.format.dwarf.attribs;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.*;
+import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*;
import static org.junit.Assert.*;
import java.io.IOException;
-import org.junit.Before;
import org.junit.Test;
-import generic.test.AbstractGenericTest;
import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.ByteArrayProvider;
-import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-import ghidra.app.util.bin.format.dwarf4.next.*;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.NullSectionProvider;
-import ghidra.program.model.listing.Program;
-import ghidra.test.ToyProgramBuilder;
-import ghidra.util.task.TaskMonitor;
+import ghidra.app.util.bin.format.dwarf.DWARFSourceLanguage;
+import ghidra.app.util.bin.format.dwarf.DWARFTestBase;
+import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttribute.AttrDef;
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.database.ProgramDB;
/**
* Test reading binary representations of DWARF attributes from raw bytes.
*/
-public class DWARFAttributeFactoryTest extends AbstractGenericTest {
+public class DWARFAttributeFactoryTest extends DWARFTestBase {
- private DWARFProgram prog;
- private StringTable stringTable;
- private DWARFAttributeFactory attribFactory;
- private DWARFCompilationUnit cu;
- private DWARFCompilationUnit cu64;
-
- @Before
- public void setUp() throws Exception {
-
- ToyProgramBuilder builder = new ToyProgramBuilder("Test", true);
- Program ghidraProgram = builder.getProgram();
-
- ghidraProgram.startTransaction("Test");
- prog = new DWARFProgram(ghidraProgram, new DWARFImportOptions(), TaskMonitor.DUMMY,
- new NullSectionProvider());
- prog.setDebugStrings(new StringTable(new byte[1000]));
- stringTable = prog.getDebugStrings();
- attribFactory = prog.getAttributeFactory();
-
- cu = new DWARFCompilationUnit(prog, 0x1000, 0x2000, 0, DWARFCompilationUnit.DWARF_32,
- (short) 4, 0, (byte) 8, 0, 0, null);
- cu64 = new DWARFCompilationUnit(prog, 0x2000, 0x4000, 0, DWARFCompilationUnit.DWARF_64,
- (short) 4, 0, (byte) 8, 0, 0, null);
-
- assertTrue("These tests were written for big endian", prog.isBigEndian());
+ @Override
+ public ProgramDB createProgram() throws Exception {
+ return createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY64_BE, this);
}
- private BinaryReader br(byte... bytes) {
- return new BinaryReader(new ByteArrayProvider(bytes), prog.isLittleEndian());
+ private DWARFAttributeValue read(BinaryReader br, DWARFAttribute attr, DWARFForm form)
+ throws IOException {
+ ensureCompUnit();
+ AttrDef spec = new AttrDef(attr, attr.getId(), form, 0);
+ DWARFFormContext context = new DWARFFormContext(br, cu, spec);
+ DWARFAttributeValue val = form.readValue(context);
+ return val;
}
@Test
@@ -78,15 +58,15 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
/* str3 */ (byte) 'x', (byte) 'y', (byte) '\n', (byte) 0,
/* guard byte for test */ (byte) 0xff);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_string);
+ DWARFAttributeValue result = read(br, DW_AT_name, DW_FORM_string);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
assertEquals("ab", ((DWARFStringAttribute) result).getValue(null));
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_string);
+ result = read(br, DW_AT_name, DW_FORM_string);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
assertEquals("c", ((DWARFStringAttribute) result).getValue(null));
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_string);
+ result = read(br, DW_AT_name, DW_FORM_string);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
assertEquals("Test reading nullterm string with non-printable chars", "xy\n",
((DWARFStringAttribute) result).getValue(null));
@@ -96,8 +76,8 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
@Test
public void testStrp_32() throws IOException {
- prog.getDebugStrings().add(1, "string1 at 1");
- prog.getDebugStrings().add(100, "string2 at 100");
+ stringTable.add(1, "string1 at 1");
+ stringTable.add(100, "string2 at 100");
// @formatter:off
BinaryReader br = br(
@@ -107,26 +87,26 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
/* guard byte for test */ (byte) 0xff);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_strp);
+ DWARFAttributeValue result = read(br, DW_AT_name, DW_FORM_strp);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
- assertEquals("string2 at 100", ((DWARFStringAttribute) result).getValue(stringTable));
+ assertEquals("string2 at 100", ((DWARFStringAttribute) result).getValue(cu));
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_strp);
+ result = read(br, DW_AT_name, DW_FORM_strp);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
- assertEquals("string1 at 1", ((DWARFStringAttribute) result).getValue(stringTable));
+ assertEquals("string1 at 1", ((DWARFStringAttribute) result).getValue(cu));
// test string ref to substring of string2
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_strp);
+ result = read(br, DW_AT_name, DW_FORM_strp);
assertTrue("Should be string", result instanceof DWARFStringAttribute);
- assertEquals("tring2 at 100", ((DWARFStringAttribute) result).getValue(stringTable));
+ assertEquals("tring2 at 100", ((DWARFStringAttribute) result).getValue(cu));
assertEquals("guard byte", (byte) 0xff, br.readNextByte());
}
@Test
public void testStrp_64() throws IOException {
- prog.getDebugStrings().add(1, "string1 at 1");
- prog.getDebugStrings().add(100, "string2 at 100");
+ stringTable.add(1, "string1 at 1");
+ stringTable.add(100, "string2 at 100");
// @formatter:off
BinaryReader br = br(
@@ -135,13 +115,15 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
/* guard byte for test */ (byte) 0xff);
// @formatter:on
- DWARFAttributeValue result1 = attribFactory.read(br, cu64, DWARFForm.DW_FORM_strp);
- assertTrue("Should be string", result1 instanceof DWARFStringAttribute);
- assertEquals("string2 at 100", ((DWARFStringAttribute) result1).getValue(stringTable));
+ setCompUnit(dwarfProg.addCompUnit(DWARFSourceLanguage.DW_LANG_C, 8 /* dwarf64 */));
- DWARFAttributeValue result2 = attribFactory.read(br, cu64, DWARFForm.DW_FORM_strp);
+ DWARFAttributeValue result1 = read(br, DW_AT_name, DW_FORM_strp);
+ assertTrue("Should be string", result1 instanceof DWARFStringAttribute);
+ assertEquals("string2 at 100", ((DWARFStringAttribute) result1).getValue(cu));
+
+ DWARFAttributeValue result2 = read(br, DW_AT_name, DW_FORM_strp);
assertTrue("Should be string", result2 instanceof DWARFStringAttribute);
- assertEquals("string1 at 1", ((DWARFStringAttribute) result2).getValue(stringTable));
+ assertEquals("string1 at 1", ((DWARFStringAttribute) result2).getValue(cu));
assertEquals("guard byte", (byte) 0xff, br.readNextByte());
}
@@ -150,11 +132,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testData1() throws IOException {
BinaryReader br = br((byte) 55, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data1);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_data1);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data1);
+ result = read(br, DW_AT_byte_size, DW_FORM_data1);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be -2", -2, ((DWARFNumericAttribute) result).getValue());
assertEquals("should be fe", 0xfe, ((DWARFNumericAttribute) result).getUnsignedValue());
@@ -164,11 +146,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testData2() throws IOException {
BinaryReader br = br((byte) 0, (byte) 55, (byte) 0xff, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data2);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_data2);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data2);
+ result = read(br, DW_AT_byte_size, DW_FORM_data2);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be -2", -2, ((DWARFNumericAttribute) result).getValue());
assertEquals("should be fffe", 0xfffe, ((DWARFNumericAttribute) result).getUnsignedValue());
@@ -179,11 +161,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
BinaryReader br = br((byte) 0, (byte) 0, (byte) 0, (byte) 55, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data4);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_data4);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data4);
+ result = read(br, DW_AT_byte_size, DW_FORM_data4);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be -2", -2, ((DWARFNumericAttribute) result).getValue());
assertEquals("should be 0xfffffffe", 0xffff_fffeL,
@@ -198,11 +180,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfe);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data8);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_data8);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_data8);
+ result = read(br, DW_AT_byte_size, DW_FORM_data8);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
// these next two asserts are probably the same test as there isn't a way to
// simulate unsigned long values
@@ -215,15 +197,15 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testSData() throws IOException {
BinaryReader br = br((byte) 0, (byte) 55, (byte) 0xff, (byte) 0x7e);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_sdata);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_sdata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 0", 0, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_sdata);
+ result = read(br, DW_AT_byte_size, DW_FORM_sdata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_sdata);
+ result = read(br, DW_AT_byte_size, DW_FORM_sdata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be -129", -129, ((DWARFNumericAttribute) result).getValue());
}
@@ -232,15 +214,15 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testUData() throws IOException {
BinaryReader br = br((byte) 0, (byte) 55, (byte) 0xff, (byte) 0x7e);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_udata);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_udata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 0", 0, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_udata);
+ result = read(br, DW_AT_byte_size, DW_FORM_udata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_udata);
+ result = read(br, DW_AT_byte_size, DW_FORM_udata);
assertTrue("Should be const", result instanceof DWARFNumericAttribute);
assertEquals("should be 16255", 16255, ((DWARFNumericAttribute) result).getValue());
}
@@ -253,11 +235,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfe);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_addr);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_addr);
assertTrue("Should be addr", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getUnsignedValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_addr);
+ result = read(br, DW_AT_byte_size, DW_FORM_addr);
assertTrue("Should be addr", result instanceof DWARFNumericAttribute);
assertEquals("should be feffffffffffffff", 0xfffffffffffffffeL,
((DWARFNumericAttribute) result).getUnsignedValue());
@@ -267,18 +249,18 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testBlock1() throws IOException {
BinaryReader br = br((byte) 1, (byte) 0x55, (byte) 0);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block1);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_block1);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 1", 1, ((DWARFBlobAttribute) result).getLength());
assertEquals("should be 0x55", 0x55, ((DWARFBlobAttribute) result).getBytes()[0]);
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block1);
+ result = read(br, DW_AT_byte_size, DW_FORM_block1);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 0", 0, ((DWARFBlobAttribute) result).getLength());
byte[] bytes = new byte[1 + 255 /* max_ubyte */];
bytes[0] = (byte) 0xff;
- result = attribFactory.read(br(bytes), cu, DWARFForm.DW_FORM_block1);
+ result = read(br(bytes), DW_AT_byte_size, DW_FORM_block1);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 255", 255, ((DWARFBlobAttribute) result).getLength());
}
@@ -287,19 +269,19 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testBlock2() throws IOException {
BinaryReader br = br((byte) 0, (byte) 1, (byte) 0x55, (byte) 0, (byte) 0);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block2);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_block2);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 1", 1, ((DWARFBlobAttribute) result).getLength());
assertEquals("should be 0x55", 0x55, ((DWARFBlobAttribute) result).getBytes()[0]);
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block1);
+ result = read(br, DW_AT_byte_size, DW_FORM_block1);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 0", 0, ((DWARFBlobAttribute) result).getLength());
byte[] bytes = new byte[2 + 0xffff /* max_ushort */];
bytes[0] = (byte) 0xff;
bytes[1] = (byte) 0xff;
- result = attribFactory.read(br(bytes), cu, DWARFForm.DW_FORM_block2);
+ result = read(br(bytes), DW_AT_byte_size, DW_FORM_block2);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 64k", 0xffff, ((DWARFBlobAttribute) result).getLength());
}
@@ -309,36 +291,36 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
BinaryReader br = br((byte) 0, (byte) 0, (byte) 0, (byte) 1, (byte) 0x55, (byte) 0,
(byte) 0, (byte) 0, (byte) 0);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block4);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_block4);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 1", 1, ((DWARFBlobAttribute) result).getLength());
assertEquals("should be 0x55", 0x55, ((DWARFBlobAttribute) result).getBytes()[0]);
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block4);
+ result = read(br, DW_AT_byte_size, DW_FORM_block4);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 0", 0, ((DWARFBlobAttribute) result).getLength());
// Test max block4 sized chunk
- byte[] bytes = new byte[4 + DWARFAttributeFactory.MAX_BLOCK4_SIZE];
+ byte[] bytes = new byte[4 + DWARFForm.MAX_BLOCK4_SIZE];
//DWARFAttributeFactory.MAX_BLOCK4_SIZE == 0x00_10_00_00
bytes[0] = (byte) 0x00;
bytes[1] = (byte) 0x10;
bytes[2] = (byte) 0x00;
bytes[3] = (byte) 0x00;
- result = attribFactory.read(br(bytes), cu, DWARFForm.DW_FORM_block4);
+ result = read(br(bytes), DW_AT_byte_size, DW_FORM_block4);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
- assertEquals("should be MAX_BLOCK4_SIZE", DWARFAttributeFactory.MAX_BLOCK4_SIZE,
+ assertEquals("should be MAX_BLOCK4_SIZE", DWARFForm.MAX_BLOCK4_SIZE,
((DWARFBlobAttribute) result).getLength());
// Test block4 size that is larger than max
- bytes = new byte[4 + DWARFAttributeFactory.MAX_BLOCK4_SIZE + 1];
+ bytes = new byte[4 + DWARFForm.MAX_BLOCK4_SIZE + 1];
//DWARFAttributeFactory.MAX_BLOCK4_SIZE == 0x00_10_00_00 + 1 == 0x00_10_00_01
bytes[0] = (byte) 0x00;
bytes[1] = (byte) 0x10;
bytes[2] = (byte) 0x00;
bytes[3] = (byte) 0x01;
try {
- result = attribFactory.read(br(bytes), cu, DWARFForm.DW_FORM_block4);
+ result = read(br(bytes), DW_AT_byte_size, DW_FORM_block4);
fail(
"Should not get here, dw_form_block4 size should have been larger than max sanity check");
}
@@ -351,12 +333,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testBlock() throws IOException {
BinaryReader br = br((byte) 1, (byte) 0x55, (byte) 0);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_block);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 1", 1, ((DWARFBlobAttribute) result).getLength());
assertEquals("should be 0x55", 0x55, ((DWARFBlobAttribute) result).getBytes()[0]);
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_block);
+ result = read(br, DW_AT_byte_size, DW_FORM_block);
assertTrue("Should be block", result instanceof DWARFBlobAttribute);
assertEquals("should be 0", 0, ((DWARFBlobAttribute) result).getLength());
}
@@ -365,12 +347,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testExprLoc() throws IOException {
BinaryReader br = br((byte) 1, (byte) 0x55, (byte) 0);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_exprloc);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_exprloc);
assertTrue("Should be exprloc", result instanceof DWARFBlobAttribute);
assertEquals("should be 1", 1, ((DWARFBlobAttribute) result).getLength());
assertEquals("should be 0x55", 0x55, ((DWARFBlobAttribute) result).getBytes()[0]);
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_exprloc);
+ result = read(br, DW_AT_byte_size, DW_FORM_exprloc);
assertTrue("Should be exprloc", result instanceof DWARFBlobAttribute);
assertEquals("should be 0", 0, ((DWARFBlobAttribute) result).getLength());
}
@@ -379,11 +361,11 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testFlag() throws IOException {
BinaryReader br = br((byte) 55, (byte) 0x00);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_flag);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_flag);
assertTrue("Should be flag", result instanceof DWARFBooleanAttribute);
assertEquals("should be true", true, ((DWARFBooleanAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_flag);
+ result = read(br, DW_AT_byte_size, DW_FORM_flag);
assertTrue("Should be flag", result instanceof DWARFBooleanAttribute);
assertEquals("should be false", false, ((DWARFBooleanAttribute) result).getValue());
}
@@ -392,7 +374,7 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testFlagPresent() throws IOException {
BinaryReader br = br(new byte[] {} /* no bytes needed for flag_present */);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_flag_present);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_flag_present);
assertTrue("Should be flag", result instanceof DWARFBooleanAttribute);
assertEquals("should be true", true, ((DWARFBooleanAttribute) result).getValue());
}
@@ -401,12 +383,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testRef1() throws IOException {
BinaryReader br = br((byte) 55, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref1);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref1);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55 + cuOffset", 55 + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref1);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref1);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be fe + cuOffset", 0xfe + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
@@ -416,12 +398,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testRef2() throws IOException {
BinaryReader br = br((byte) 0, (byte) 55, (byte) 0xff, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref2);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref2);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55 + cuOffset", 55 + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref2);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref2);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be fffe + cuOffset", 0xfffe + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
@@ -432,12 +414,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
BinaryReader br = br((byte) 0, (byte) 0, (byte) 0, (byte) 55, (byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xfe);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref4);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref4);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55 + cuOffset", 55 + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref4);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref4);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be fffffffe + cuOffset", 0xff_ff_ff_feL + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
@@ -452,11 +434,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_sec_offset);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_sec_offset);
assertTrue("Should be ptr", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu64, DWARFForm.DW_FORM_sec_offset);
+ addCompUnit64();
+ result = read(br, DW_AT_byte_size, DW_FORM_sec_offset);
assertTrue("Should be ptr", result instanceof DWARFNumericAttribute);
assertEquals("should be 56", 56, ((DWARFNumericAttribute) result).getValue());
}
@@ -469,12 +452,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xfe);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref8);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref8);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55 + cuOffset", 55 + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref8);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref8);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be fffffffffffffffe + cuOffset",
0xff_ff_ff_ff_ff_ff_ff_feL + cu.getStartOffset(),
@@ -485,12 +468,12 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testRefUData() throws IOException {
BinaryReader br = br((byte) 55, (byte) 0xff, (byte) 0x7e);
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref_udata);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref_udata);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55 + cuOffset", 55 + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref_udata);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref_udata);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 0x3f7f + cuOffset", 0x3f7f + cu.getStartOffset(),
((DWARFNumericAttribute) result).getValue());
@@ -507,20 +490,23 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref_addr);
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_ref_addr);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_ref_addr);
+ result = read(br, DW_AT_byte_size, DW_FORM_ref_addr);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be ffffffff", 0xff_ff_ff_ffL,
((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu64, DWARFForm.DW_FORM_ref_addr);
+ addCompUnit64();
+
+ result = read(br, DW_AT_byte_size, DW_FORM_ref_addr);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu64, DWARFForm.DW_FORM_ref_addr);
+ addCompUnit64();
+ result = read(br, DW_AT_byte_size, DW_FORM_ref_addr);
assertTrue("Should be ref", result instanceof DWARFNumericAttribute);
assertEquals("should be fffffffffffffffe", 0xff_ff_ff_ff_ff_ff_ff_feL,
((DWARFNumericAttribute) result).getValue());
@@ -530,22 +516,19 @@ public class DWARFAttributeFactoryTest extends AbstractGenericTest {
public void testIndirect() throws IOException {
// @formatter:off
BinaryReader br = br(
- (byte)DWARFForm.DW_FORM_data1.getValue(),
+ (byte)DW_FORM_data1.getId(),
(byte) 55,
- (byte)DWARFForm.DW_FORM_ref4.getValue(),
+ (byte)DW_FORM_ref4.getId(),
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xaa
);
// @formatter:on
- DWARFAttributeValue result = attribFactory.read(br, cu, DWARFForm.DW_FORM_indirect);
- DWARFIndirectAttribute dia = (DWARFIndirectAttribute) result;
- DWARFNumericAttribute nestedAttr = (DWARFNumericAttribute) dia.getValue();
- assertEquals("should be 55", 55, nestedAttr.getValue());
+ DWARFAttributeValue result = read(br, DW_AT_byte_size, DW_FORM_indirect);
+ assertEquals("should be 55", 55, ((DWARFNumericAttribute) result).getValue());
- result = attribFactory.read(br, cu, DWARFForm.DW_FORM_indirect);
- dia = (DWARFIndirectAttribute) result;
- nestedAttr = (DWARFNumericAttribute) dia.getValue();
- assertEquals("should be aa + cuOffset", 0xaa + cu.getStartOffset(), nestedAttr.getValue());
+ result = read(br, DW_AT_byte_size, DW_FORM_indirect);
+ assertEquals("should be aa + cuOffset", 0xaa + cu.getStartOffset(),
+ ((DWARFNumericAttribute) result).getValue());
}
}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluatorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorTest.java
similarity index 97%
rename from Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluatorTest.java
rename to Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorTest.java
index 98eee4f70a..a27d3f3fc6 100644
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/expression/DWARFExpressionEvaluatorTest.java
+++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluatorTest.java
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package ghidra.app.util.bin.format.dwarf4.expression;
+package ghidra.app.util.bin.format.dwarf.expression;
-import static ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes.*;
+import static ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionOpCodes.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.*;
-import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFRegisterMappings;
+import ghidra.app.util.bin.format.dwarf.DWARFRegisterMappings;
+import ghidra.app.util.bin.format.dwarf.expression.*;
public class DWARFExpressionEvaluatorTest {
@@ -31,7 +31,7 @@ public class DWARFExpressionEvaluatorTest {
@Before
public void setup() {
- evaluator = new DWARFExpressionEvaluator((byte) 8, true, DWARFCompilationUnit.DWARF_32,
+ evaluator = new DWARFExpressionEvaluator((byte) 8, true, 4 /* dwarf32 */,
DWARFRegisterMappings.DUMMY);
}
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
deleted file mode 100644
index de57d1f997..0000000000
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/* ###
- * 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;
-
-import java.util.*;
-
-import ghidra.app.util.bin.format.dwarf4.attribs.*;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-
-/**
- * Helper class to create mock DebugInfoEntry instances for use during junit tests.
- */
-public class DIECreator {
- private static class AttrInfo {
- int attribute;
- DWARFForm form;
- DWARFAttributeValue value;
-
- public AttrInfo(int attribute, DWARFForm form, DWARFAttributeValue value) {
- this.attribute = attribute;
- this.form = form;
- this.value = value;
- }
- }
-
- private MockDWARFProgram dwarfProg;
- private int tag;
- private Map attributes = new HashMap<>();
- private DebugInfoEntry parent;
-
- public DIECreator(MockDWARFProgram dwarfProg, int tag) {
- this.dwarfProg = dwarfProg;
- this.tag = tag;
- }
-
- public DIECreator addString(int attribute, String value) {
- attributes.put(attribute,
- new AttrInfo(attribute, DWARFForm.DW_FORM_string, new DWARFStringAttribute(value)));
- return this;
- }
-
- public DIECreator addUInt(int attribute, long value) {
- attributes.put(attribute,
- new AttrInfo(attribute, DWARFForm.DW_FORM_udata, new DWARFNumericAttribute(value)));
- return this;
- }
-
- public DIECreator addInt(int attribute, long value) {
- attributes.put(attribute,
- new AttrInfo(attribute, DWARFForm.DW_FORM_sdata, new DWARFNumericAttribute(value)));
-
- return this;
- }
-
- public DIECreator addRef(int attribute, DebugInfoEntry die) {
- attributes.put(attribute, new AttrInfo(attribute, DWARFForm.DW_FORM_ref8,
- new DWARFNumericAttribute(die.getOffset())));
-
- return this;
- }
-
- public DIECreator addRef(int attribute, long offset) {
- attributes.put(attribute,
- new AttrInfo(attribute, DWARFForm.DW_FORM_ref8, new DWARFNumericAttribute(offset)));
-
- return this;
- }
-
- public DIECreator addBoolean(int attribute, boolean value) {
- attributes.put(attribute,
- new AttrInfo(attribute, DWARFForm.DW_FORM_flag, new DWARFBooleanAttribute(value)));
-
- 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;
- }
-
- DWARFAttributeSpecification[] makeAttrSpecArray() {
- DWARFAttributeSpecification[] attrSpecs =
- new DWARFAttributeSpecification[attributes.size()];
- List attrInfoList = new ArrayList<>(attributes.values());
- for (int i = 0; i < attrInfoList.size(); i++) {
- AttrInfo attrInfo = attrInfoList.get(i);
- attrSpecs[i] = new DWARFAttributeSpecification(attrInfo.attribute, attrInfo.form);
- }
- return attrSpecs;
- }
-
- public DIECreator setParent(DebugInfoEntry parent) {
- this.parent = parent;
- return this;
- }
-
- public DebugInfoEntry createRootDIE() {
- MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit();
- DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag);
- DebugInfoEntry die = dwarfProg.addDIE(abbr, null);
-
- int attrNum = 0;
- for (AttrInfo attrInfo : attributes.values()) {
- die.getAttributes()[attrNum++] = attrInfo.value;
- }
-
- return die;
- }
-
- public DebugInfoEntry create() {
- MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit();
- if (cu == null) {
- cu = dwarfProg.addCompUnit();
- }
- DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag);
- DebugInfoEntry die =
- dwarfProg.addDIE(abbr, parent != null ? parent : cu.getCompileUnitDIE());
-
- int attrNum = 0;
- for (AttrInfo attrInfo : attributes.values()) {
- die.getAttributes()[attrNum++] = attrInfo.value;
- }
-
- return die;
- }
-}
diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryFlaky.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryFlaky.java
deleted file mode 100644
index a0545b936e..0000000000
--- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/attribs/DWARFAttributeFactoryFlaky.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/* ###
- * 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.attribs;
-
-import ghidra.app.util.bin.BinaryReader;
-import ghidra.app.util.bin.format.dwarf4.DWARFCompilationUnit;
-import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Test helper that injects errors when reading DWARF attributes from a stream.
- *
- * Used with real DWARF binaries to inject changes / errors at specific locations
- * in the file that the tester determined was an important point.
- */
-public class DWARFAttributeFactoryFlaky extends DWARFAttributeFactory {
-
- private int counter;
- private Set offsets = new HashSet<>();
-
- public DWARFAttributeFactoryFlaky(DWARFProgram prog) {
- super(prog);
- }
-
- public DWARFAttributeFactoryFlaky addOffset(long offset) {
- offsets.add(offset);
- return this;
- }
-
- public DWARFAttributeValue read(BinaryReader reader, DWARFCompilationUnit unit, DWARFForm form)
- throws IOException {
- counter++;
-
- long offset = reader.getPointerIndex();
- DWARFAttributeValue result = super.read(reader, unit, form);
-
- if (shouldError(offset, result, form)) {
- result = injectError(offset, result, form);
- }
-
- return result;
- }
-
- private boolean shouldError(long offset, DWARFAttributeValue attribute, DWARFForm form) {
- return offsets.contains(offset);
- }
-
- private DWARFAttributeValue injectError(long offset, DWARFAttributeValue attribute,
- DWARFForm form) {
- switch (form) {
- case DW_FORM_addr:
- return new DWARFNumericAttribute(0);
-
- // Block Form
- case DW_FORM_block4:
- case DW_FORM_block2:
- case DW_FORM_block1:
- case DW_FORM_block:
- return new DWARFBlobAttribute(new byte[] {});
-
- // Constant Form
- case DW_FORM_data8:
- case DW_FORM_data4:
- case DW_FORM_data2:
- case DW_FORM_data1:
- case DW_FORM_udata:
- case DW_FORM_sdata:
- return new DWARFNumericAttribute(0);
-
- // Exprloc Form
- case DW_FORM_exprloc:
- return new DWARFBlobAttribute(new byte[] {});
-
- case DW_FORM_flag_present:
- case DW_FORM_flag:
- return DWARFBooleanAttribute.TRUE;
-
- // Pointer Types Form (lineptr, loclistptr, macptr, rangelistptr)
- case DW_FORM_sec_offset:
- return new DWARFNumericAttribute(0);
-
- // Reference Form
- case DW_FORM_ref8:
- case DW_FORM_ref4:
- case DW_FORM_ref2:
- case DW_FORM_ref1:
- case DW_FORM_ref_udata:
- case DW_FORM_ref_addr:
- return new DWARFNumericAttribute(0);
-
- // String Form
- case DW_FORM_strp:
- case DW_FORM_string:
- return new DWARFStringAttribute("");
-
- case DW_FORM_indirect:
- case NULL:
- default:
- throw new IllegalArgumentException("Invalid DWARF Form: " + form);
- }
- }
-}
diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java
index 488f4abecd..40166304b8 100644
--- a/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java
+++ b/Ghidra/Features/Decompiler/ghidra_scripts/RecoverClassesFromRTTIScript.java
@@ -66,10 +66,10 @@ import ghidra.app.script.GhidraScript;
import ghidra.app.services.Analyzer;
import ghidra.app.services.GraphDisplayBroker;
import ghidra.app.util.NamespaceUtils;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFFunctionImporter;
-import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProvider;
-import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.DWARFSectionProviderFactory;
+import ghidra.app.util.bin.format.dwarf.DWARFFunctionImporter;
+import ghidra.app.util.bin.format.dwarf.DWARFProgram;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider;
+import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProviderFactory;
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.PeLoader;
diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsTest.java
index 0e7d411053..e30cafb70a 100644
--- a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsTest.java
+++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFRegisterMappingsTest.java
@@ -29,6 +29,8 @@ import org.junit.experimental.categories.Category;
import generic.test.category.NightlyCategory;
import ghidra.GhidraTestApplicationLayout;
+import ghidra.app.util.bin.format.dwarf.DWARFRegisterMappings;
+import ghidra.app.util.bin.format.dwarf.DWARFRegisterMappingsManager;
import ghidra.program.model.lang.*;
import ghidra.program.util.DefaultLanguageService;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;