diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARF_ExtractorScript.java b/Ghidra/Features/Base/ghidra_scripts/DWARF_ExtractorScript.java deleted file mode 100644 index 1a2c9f56e7..0000000000 --- a/Ghidra/Features/Base/ghidra_scripts/DWARF_ExtractorScript.java +++ /dev/null @@ -1,77 +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. - */ -//This script extracts DWARF 2, 3, or 4 debug information -//and applies it to the program. -// -// This script reads DWARF information from the debug sections of a binary and -// imports the information into Ghidra. -// This information includes: data type definitions, namespace and class information, -// function signatures, and function source file locations. -// Currently, the script is based off of DWARF2, DWARF3, and DWARF4 specification. However, -// not all features or possibilities have been implemented. -// The default max of 512MB RAM allocated for Ghidra is not enough for running the -// script on larger binaries. Setting -Xmx2g should be sufficient. -// -// Features that still require implementing: -// - All TAG data types have not yet been implemented. This script will not complete if -// it encounters an unknown data type and that data type is used. -// - Location description processing is currently hardcoded for the most common expressions. -// This should be updated to support any valid location description. -// - Expression description processing is incomplete. All description opcodes should be supported. -// - Location description and Expression description should probably be set up similiar -// to frysk (see frysk-core/frysk/debuginfo/LocationExpression.java) -// - Handle all errors correctly, setup warning/error system to print out or log -// warnings/errors while processing -// - Program tree currently does not allow any duplicate names -// - Match all datatypes found by the demangler with datatypes processed in DWARF -// - Various testing and fixes on a variety of different compiled binaries -// -// -// Possible Future Improvements: -// - Create a custom data type manager to handle adding datatypes temporarily -// - Only add datatypes to Ghidra's data type manager after all data types have been processed -// - Increase speed of the script as most of the waiting involves waiting on adding -// data types to Ghidra's data type manager -// - Remove any hacks that are currently necessary for the script to add and use data types correctly -// - Possibility to add data types to a subfolder based on namespace or class during data -// type processing -// - Check source language type and look for certain language constructs while processing -// -// -//@author User Submitted - based on DWARF_script.java -//@category Binary -// - -import ghidra.app.script.GhidraScript; -import ghidra.app.util.bin.format.dwarf4.next.*; - -public class DWARF_ExtractorScript extends GhidraScript { - - @Override - public void run() throws Exception { - if (!DWARFProgram.isDWARF(currentProgram)) { - popup("Unable to find DWARF information, aborting"); - return; - } - DWARFImportOptions importOptions = new DWARFImportOptions(); - importOptions.setImportLimitDIECount(Integer.MAX_VALUE); - try (DWARFProgram dwarfProg = new DWARFProgram(currentProgram, importOptions, monitor)) { - DWARFParser dp = new DWARFParser(dwarfProg, monitor); - DWARFImportSummary importSummary = dp.parse(); - importSummary.logSummaryResults(); - } - } -} 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 770d4f07b1..6ae117201b 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 @@ -17,14 +17,10 @@ package ghidra.app.plugin.core.analysis; import java.io.IOException; -import ghidra.app.plugin.core.analysis.rust.RustUtilities; import ghidra.app.services.*; -import ghidra.app.util.bin.format.dwarf4.DWARFException; -import ghidra.app.util.bin.format.dwarf4.DWARFPreconditionException; 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.golang.rtti.GoRttiMapper; import ghidra.app.util.importer.MessageLog; import ghidra.framework.options.Options; import ghidra.program.model.address.AddressSetView; @@ -95,24 +91,14 @@ public class DWARFAnalyzer extends AbstractAnalyzer { return false; } - if (GoRttiMapper.isGolangProgram(program)) { - Msg.info(this, "DWARF: Enabling DIE preload for golang binary"); - importOptions.setPreloadAllDIEs(true); - } - - if (RustUtilities.isRustProgram(program)) { - Msg.info(this, "DWARF: Enabling DIE preload for Rust binary"); - importOptions.setPreloadAllDIEs(true); - } - 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 [" + - program.getLanguageID().getIdAsString() + - "], function information may be incorrect / incomplete."); + "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(); @@ -126,13 +112,7 @@ public class DWARFAnalyzer extends AbstractAnalyzer { catch (CancelledException ce) { throw ce; } - catch (DWARFPreconditionException e) { - log.appendMsg("Skipping DWARF import because a precondition was not met:"); - log.appendMsg(e.getMessage()); - log.appendMsg( - "Manually re-run the DWARF analyzer after adjusting the options or start it via Dwarf_ExtractorScript"); - } - catch (DWARFException | IOException e) { + catch (IOException e) { log.appendMsg("Error during DWARFAnalyzer import: " + e); Msg.error(this, "Error during DWARFAnalyzer import: ", e); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java index 17f9afc763..3db7f23d73 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DIEAggregate.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.bin.format.dwarf4; +import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*; import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*; import java.io.IOException; @@ -51,6 +52,8 @@ 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 @@ -94,13 +97,13 @@ public class DIEAggregate { // keep querying for abstract_origin DIEs as long as we haven't seen them yet, // and add them to the fragment list. DebugInfoEntry tmp; - while ((tmp = result.getRefDIE(DWARFAttribute.DW_AT_abstract_origin)) != null && + while ((tmp = result.getRefDIE(DW_AT_abstract_origin)) != null && !result.hasOffset(tmp.getOffset()) && result.getFragmentCount() < MAX_FRAGMENT_COUNT) { result.addFragment(tmp); } // look for 1 spec DIE and add it. - tmp = result.getRefDIE(DWARFAttribute.DW_AT_specification); + tmp = result.getRefDIE(DW_AT_specification); if (tmp != null) { result.addFragment(tmp); } @@ -227,7 +230,7 @@ public class DIEAggregate { } public DWARFProgram getProgram() { - return getHeadFragment().getCompilationUnit().getProgram(); + return getHeadFragment().getProgram(); } /** @@ -250,13 +253,13 @@ public class DIEAggregate { public DIEAggregate getDeclParent() { DebugInfoEntry declDIE = getLastFragment(); DebugInfoEntry declParent = declDIE.getParent(); - return getCompilationUnit().getProgram().getAggregate(declParent); + return getProgram().getAggregate(declParent); } public DIEAggregate getParent() { DebugInfoEntry die = getHeadFragment(); DebugInfoEntry parent = die.getParent(); - return getCompilationUnit().getProgram().getAggregate(parent); + return getProgram().getAggregate(parent); } /** @@ -272,13 +275,7 @@ public class DIEAggregate { * @return */ public int getDepth() { - DebugInfoEntry die = getHeadFragment(); - int result = 0; - while (die != null) { - result++; - die = die.getParent(); - } - return result - 1; + return getProgram().getParentDepth(getHeadFragment().getIndex()); } private AttrInfo findAttribute(int attribute) { @@ -431,9 +428,9 @@ public class DIEAggregate { DWARFNumericAttribute val = attrInfo.getValue(DWARFNumericAttribute.class); long offset = (val != null) ? val.getUnsignedValue() : -1; - DebugInfoEntry result = getProgram().getEntryAtByteOffsetUnchecked(offset); + DebugInfoEntry result = getProgram().getDIEByOffset(offset); if (result == null) { - Msg.warn(this, "Invalid reference value [" + Long.toHexString(offset) + "]"); + Msg.warn(this, "Invalid reference value [%x]".formatted(offset)); Msg.warn(this, this.toString()); } return result; @@ -441,7 +438,7 @@ public class DIEAggregate { public DIEAggregate getRef(int attribute) { DebugInfoEntry die = getRefDIE(attribute); - return getCompilationUnit().getProgram().getAggregate(die); + return getProgram().getAggregate(die); } /** @@ -500,7 +497,7 @@ public class DIEAggregate { * abstract portion */ public DIEAggregate getAbstractInstance() { - AttrInfo aoAttr = findAttribute(DWARFAttribute.DW_AT_abstract_origin); + AttrInfo aoAttr = findAttribute(DW_AT_abstract_origin); if (aoAttr == null) { return null; } @@ -585,16 +582,16 @@ public class DIEAggregate { } } - private int assertValidInt(long l) throws IOException { + private int assertValidInt(long l) throws DWARFException { if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { - throw new IOException("Value out of allowed range: " + l); + throw new DWARFException("Value out of allowed range: " + l); } return (int) l; } - private int assertValidUInt(long l) throws IOException { + private int assertValidUInt(long l) throws DWARFException { if (l < 0 || l > Integer.MAX_VALUE) { - throw new IOException("Value out of allowed range: " + l); + throw new DWARFException("Value out of allowed range: " + l); } return (int) l; } @@ -606,11 +603,11 @@ public class DIEAggregate { * @param attribute * @param defaultValue * @return - * @throws IOException + * @throws DWARFException * @throws DWARFExpressionException */ public int parseDataMemberOffset(int attribute, int defaultValue) - throws IOException, DWARFExpressionException { + throws DWARFException, DWARFExpressionException { AttrInfo attrInfo = findAttribute(attribute); if (attrInfo == null) { @@ -633,7 +630,7 @@ public class DIEAggregate { return assertValidUInt(evaluator.pop()); } else { - throw new IOException( + throw new DWARFException( "DWARF attribute form not valid for data member offset: " + attrInfo.form); } } @@ -698,7 +695,7 @@ public class DIEAggregate { * @throws IOException if an I/O error occurs */ private List readDebugLocList(long offset) throws IOException { - BinaryReader debug_loc = getCompilationUnit().getProgram().getDebugLocation(); + BinaryReader debug_loc = getProgram().getDebugLocation(); List results = new ArrayList<>(); if (debug_loc == null) { @@ -890,7 +887,7 @@ public class DIEAggregate { */ public List readRange(int attribute) throws IOException { byte pointerSize = getCompilationUnit().getPointerSize(); - BinaryReader reader = getCompilationUnit().getProgram().getDebugRanges(); + BinaryReader reader = getProgram().getDebugRanges(); long offset = getUnsignedLong(attribute, -1); if (offset == -1) { 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 index 8fc7382117..457b3b3433 100644 --- 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 @@ -16,7 +16,8 @@ package ghidra.app.util.bin.format.dwarf4; import java.io.IOException; -import java.util.*; +import java.util.HashMap; +import java.util.Map; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf4.DWARFUtil.LengthResult; @@ -101,7 +102,7 @@ public class DWARFCompilationUnit { /** * The contents of the first DIE (that must be a compile unit) in this compUnit. */ - private DWARFCompileUnit compUnit; + protected DWARFCompileUnit compUnit; /** * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data @@ -175,18 +176,17 @@ public class DWARFCompilationUnit { try { DebugInfoEntry compileUnitDIE = - DebugInfoEntry.read(debugInfoBR, cu, dwarfProgram.getAttributeFactory()); + DebugInfoEntry.read(debugInfoBR, cu, -1, dwarfProgram.getAttributeFactory()); DWARFCompileUnit compUnit = DWARFCompileUnit.read(DIEAggregate.createSingle(compileUnitDIE)); - cu.setCompileUnit(compUnit); + cu.compUnit = compUnit; return cu; } catch (IOException ioe) { - Msg.error(null, - "Failed to parse the DW_TAG_compile_unit DIE at the start of compilation unit " + - cuNumber + " at offset " + startOffset + " (0x" + - Long.toHexString(startOffset) + "), skipping entire compilation unit", + 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; @@ -240,10 +240,6 @@ public class DWARFCompilationUnit { return compUnit; } - protected void setCompileUnit(DWARFCompileUnit compUnit) { - this.compUnit = compUnit; - } - public DWARFProgram getProgram() { return dwarfProgram; } @@ -327,77 +323,4 @@ public class DWARFCompilationUnit { return compUnitNumber; } - /** - * Reads the {@link DebugInfoEntry} records for this compilation unit from the .debug_info - * section. - *

- * @param entries List of DIE records that is written to by this method. This list should - * be empty if the caller only wants this CU's records (ie. normal mode), or the list - * can be used to accumulate all DIE records (preload all DIE mode). - * @param monitor {@link TaskMonitor} to watch for cancelation - * @throws IOException if error reading data - * @throws DWARFException if error in DWARF structure - * @throws CancelledException if user cancels. - */ - public void readDIEs(List entries, TaskMonitor monitor) - throws IOException, DWARFException, CancelledException { - - BinaryReader br = dwarfProgram.getDebugInfo(); - br.setPointerIndex(firstDIEOffset); - - Deque parentStack = new ArrayDeque<>(); - - DebugInfoEntry parent = null; - DebugInfoEntry die; - DebugInfoEntry unexpectedTerminator = null; - while (br.getPointerIndex() < endOffset) { - long startOfDIE = br.getPointerIndex(); - try { - die = DebugInfoEntry.read(br, this, dwarfProgram.getAttributeFactory()); - } - 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, compUnitNumber, startOffset), - e); - br.setPointerIndex(endOffset); - continue; - } - - monitor.checkCancelled(); - - if (die.isTerminator()) { - if (parent == null && parentStack.isEmpty()) { - unexpectedTerminator = die; - continue; - } - parent = !parentStack.isEmpty() ? parentStack.pop() : null; - continue; - } - - if (unexpectedTerminator != null) { - throw new DWARFException("Unexpected terminator entry at 0x%x" - .formatted(unexpectedTerminator.getOffset())); - } - entries.add(die); - - if (parent != null) { - parent.addChild(die); - die.setParent(parent); - } - else { - if (die.getOffset() != firstDIEOffset) { - throw new DWARFException( - "Unexpected root level DIE at 0x%x".formatted(die.getOffset())); - } - } - - if (die.getAbbreviation().hasChildren()) { - if (parent != null) { - parentStack.push(parent); - } - parent = die; - } - } - } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java index 513553932f..8ecec8c08c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFCompileUnit.java @@ -31,7 +31,6 @@ public class DWARFCompileUnit { private final Number high_pc; private final Number low_pc; private final Number language; - private final DWARFIdentifierCase identifier_case; private final boolean hasDWO; private DWARFLine line = null; @@ -62,34 +61,26 @@ public class DWARFCompileUnit { language = diea.getUnsignedLong(DWARFAttribute.DW_AT_language, -1); } - DWARFIdentifierCase identifier_case = null; - if (diea.hasAttribute(DWARFAttribute.DW_AT_identifier_case)) { - identifier_case = DWARFIdentifierCase.find( - diea.getUnsignedLong(DWARFAttribute.DW_AT_identifier_case, -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, - identifier_case, hasDWO, line); + 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, DWARFIdentifierCase identifier_case, boolean hasDWO, - DWARFLine line) { + 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.identifier_case = identifier_case; this.hasDWO = hasDWO; this.line = line; } @@ -197,22 +188,15 @@ public class DWARFCompileUnit { return this.language == null ? -1 : this.language.intValue(); } - /** - * Get the identifier case of the compile unit - * @return the identifier case of the compile unit - */ - public DWARFIdentifierCase getIdentifierCase() { - return this.identifier_case; - } - public boolean hasDWO() { return hasDWO; } @Override public String toString() { - return "DWARFCompileUnit [name=" + name + ", producer=" + producer + ", comp_dir=" + - comp_dir + ", high_pc=" + high_pc + ", low_pc=" + low_pc + ", language=" + language + - ", identifier_case=" + identifier_case + ", hasDWO=" + hasDWO + ", line=" + line + "]"; + 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/DWARFException.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFException.java index 9ee7a55ae8..c31d399ff4 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/dwarf4/DWARFException.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,14 +15,24 @@ */ package ghidra.app.util.bin.format.dwarf4; -public class DWARFException extends Exception -{ +import java.io.IOException; + +public class DWARFException extends IOException { + + public DWARFException() { + // empty + } + /** * Constructs a DWARFException with the specified message. * @param message the detail message */ - public DWARFException(String message) - { + public DWARFException(String message) { super(message); } + + public DWARFException(String message, Throwable cause) { + super(message, cause); + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFPreconditionException.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFPreconditionException.java deleted file mode 100644 index 40a6736c71..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/DWARFPreconditionException.java +++ /dev/null @@ -1,28 +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; - -/** - * Thrown when a precondition to successfully processing DWARF information is not - * met. - */ -public class DWARFPreconditionException extends DWARFException { - - public DWARFPreconditionException(String message) { - super(message); - } - -} 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/dwarf4/DWARFUtil.java index 8462f7936e..87caeee053 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/dwarf4/DWARFUtil.java @@ -15,13 +15,12 @@ */ package ghidra.app.util.bin.format.dwarf4; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import generic.jar.ResourceFile; import ghidra.app.cmd.comments.AppendCommentCmd; @@ -221,7 +220,7 @@ public class DWARFUtil { * name. */ public static List findLinkageNameInChildren(DebugInfoEntry die) { - DWARFProgram prog = die.getCompilationUnit().getProgram(); + 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); @@ -279,7 +278,7 @@ public class DWARFUtil { int typeDefCount = 0; for (DebugInfoEntry childDIE : parent.getChildren()) { DIEAggregate childDIEA = prog.getAggregate(childDIE); - if (diea == childDIEA) { + if (diea == childDIEA || diea.getOffset() == childDIEA.getOffset()) { return "anon_" + getContainerTypeName(childDIEA) + "_" + typeDefCount; } if (childDIEA.isNamedType()) { @@ -387,32 +386,12 @@ public class DWARFUtil { private static String getLexicalBlockNameWorker(DebugInfoEntry die) { if (die.getTag() == DWARFTag.DW_TAG_lexical_block || die.getTag() == DWARFTag.DW_TAG_inlined_subroutine) { - return getLexicalBlockNameWorker(die.getParent()) + "_" + - Integer.toString(getMyPositionInParent(die)); + return "%s_%d".formatted(getLexicalBlockNameWorker(die.getParent()), + die.getPositionInParent()); } return ""; } - /** - * Returns the ordinal position of this {@link DebugInfoEntry} in it's parent. - * - * @param die {@link DebugInfoEntry} - * @return int index of ourself in our parent, or -1 if not found in parent. - */ - public static int getMyPositionInParent(DebugInfoEntry die) { - DebugInfoEntry parent = die.getParent(); - if (parent != null) { - int position = 0; - for (DebugInfoEntry childDIE : parent.getChildren(die.getTag())) { - if (childDIE == die) { - return position; - } - position++; - } - } - return -1; - } - /** * Append a string to a {@link DataType}'s description. * 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/dwarf4/DebugInfoEntry.java index 2e21681214..196697924d 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/dwarf4/DebugInfoEntry.java @@ -15,15 +15,16 @@ */ package ghidra.app.util.bin.format.dwarf4; -import java.util.*; - 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.program.model.data.LEB128; +import ghidra.util.datastruct.IntArrayList; /** * A DWARF Debug Info Entry is a collection of {@link DWARFAttributeValue attributes} @@ -44,29 +45,30 @@ public class DebugInfoEntry { Set.of(DWARFAttribute.DW_AT_sibling, DWARFAttribute.DW_AT_accessibility); private final DWARFCompilationUnit compilationUnit; - private final long offset; private final DWARFAbbreviation abbreviation; private final DWARFAttributeValue[] attributes; - private long parentOffset = -1; - private List children; + private final long offset; + private final int dieIndex; /** * Read a DIE record. * - * @param reader - * @param unit - * @param attributeFactory - * @return - * @throws IOException + * @param reader {@link BinaryReader} positioned at the start of a DIE record + * @param unit 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, - DWARFAttributeFactory attributeFactory) throws IOException { + int dieIndex, DWARFAttributeFactory attributeFactory) throws IOException { long offset = reader.getPointerIndex(); int abbreviationCode = reader.readNextUnsignedVarIntExact(LEB128::unsigned); // Check for terminator DIE if (abbreviationCode == 0) { - return new DebugInfoEntry(unit, offset, null); + return new DebugInfoEntry(unit, offset, -1, null); } DWARFAbbreviation abbreviation = unit.getCodeToAbbreviationMap().get(abbreviationCode); @@ -75,7 +77,7 @@ public class DebugInfoEntry { " not found in the abbreviation map for compunit " + unit); } - DebugInfoEntry result = new DebugInfoEntry(unit, offset, abbreviation); + 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(); for (int i = 0; i < attributeSpecs.length; i++) { @@ -95,46 +97,49 @@ public class DebugInfoEntry { } /** - * Creates an empty DIE. Used by {@link #read(BinaryReader, DWARFCompilationUnit, DWARFAttributeFactory) static read()} - * and junit tests. - *

- * @param unit - * @param offset - * @param abbreviation + * Creates a DIE. Used by + * {@link #read(BinaryReader, DWARFCompilationUnit, DWARFAttributeFactory) static read()} and + * junit tests. + * + * @param unit 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 */ - public DebugInfoEntry(DWARFCompilationUnit unit, long offset, DWARFAbbreviation abbreviation) { + public DebugInfoEntry(DWARFCompilationUnit unit, long offset, int dieIndex, + DWARFAbbreviation abbreviation) { this.compilationUnit = unit; this.offset = offset; + this.dieIndex = dieIndex; this.abbreviation = abbreviation; - this.attributes = - (abbreviation != null) ? new DWARFAttributeValue[abbreviation.getAttributeCount()] - : null; + this.attributes = abbreviation != null + ? new DWARFAttributeValue[abbreviation.getAttributeCount()] + : null; } /** - * Add a child DIE to this DIE. - * @param child DIE of the child + * Returns the index of this DIE (in the entire dwarf program) + * + * @return index of this DIE */ - public void addChild(DebugInfoEntry child) { - if (children == null) { - children = new ArrayList<>(5); - } - this.children.add(child); + public int getIndex() { + return dieIndex; } /** - * Return a live list of the child DIE's. + * Return a list of the child DIE's. + * * @return list of child DIE's */ public List getChildren() { - return children != null ? children : Collections.EMPTY_LIST; + return getProgram().getChildrenOf(dieIndex); } /** * Return a list of children that are of a specific DWARF type. *

- * @param childTag - * @return + * @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<>(); @@ -146,30 +151,13 @@ public class DebugInfoEntry { return result; } - /** - * Check to see if this DIE has any child DIE's. - * @return true if there are child DIE's and false otherwise - */ - public boolean hasChildren() { - return !this.children.isEmpty(); - } - - /** - * Set the parent DIE of this DIE. - * @param parent the parent DIE - */ - public void setParent(DebugInfoEntry parent) { - parentOffset = (parent != null) ? parent.getOffset() : -1; - } - /** * Get the parent DIE of this DIE. - * @return the parent DIE + * + * @return the parent DIE, or null if this DIE is the root of the compunit */ public DebugInfoEntry getParent() { - return (parentOffset != -1) - ? compilationUnit.getProgram().getEntryAtByteOffsetUnchecked(parentOffset) - : null; + return getProgram().getParentOf(dieIndex); } /** @@ -226,48 +214,42 @@ public class DebugInfoEntry { return abbreviation == null; } - @Override - public String toString() { - StringBuilder buffer = new StringBuilder(getClass().getSimpleName()); - buffer.append(" - Offset: 0x").append(Long.toHexString(this.offset)).append("\n"); - buffer.append("AbbreviationCode: 0x").append( - Long.toHexString(abbreviation != null ? abbreviation.getAbbreviationCode() : 0)); - - if (isTerminator()) { - return buffer.toString(); + /** + * Returns the ordinal position of this DIE record in its parent's list of children. + * + * @return index of ourself in our parent, or -1 if root DIE + */ + public int getPositionInParent() { + DWARFProgram dprog = getProgram(); + int parentIndex = dprog.getParentIndex(dieIndex); + if (parentIndex < 0) { + return -1; } - - buffer.append(" ").append( - DWARFUtil.toString(DWARFTag.class, this.abbreviation.getTag())).append("\n"); - - DWARFAttributeSpecification[] attributeSpecs = abbreviation.getAttributes(); - for (int i = 0; i < attributeSpecs.length; i++) { - DWARFAttributeSpecification attributeSpec = attributeSpecs[i]; - buffer.append("\tAttribute: "); - buffer.append(DWARFUtil.toString(DWARFAttribute.class, attributeSpec.getAttribute())); - buffer.append(" "); - buffer.append(attributes[i]); - buffer.append(" "); - buffer.append(attributeSpec.getAttributeForm().toString()); - buffer.append("\n"); + IntArrayList childIndexes = dprog.getDIEChildIndexes(parentIndex); + for (int i = 0; i < childIndexes.size(); i++) { + if (childIndexes.get(i) == dieIndex) { + return i; + } } - if (children != null && !children.isEmpty()) { - buffer.append("\tChild count: ").append(children.size()).append("\n"); - } - - return buffer.toString(); + // only way to get here is if our in-memory indexes are corrupt / incorrect + throw new RuntimeException("DWARF DIE index failure."); } public DWARFCompilationUnit getCompilationUnit() { return compilationUnit; } + public DWARFProgram getProgram() { + return getCompilationUnit().getProgram(); + } + + public int getDepth() { + return getProgram().getParentDepth(dieIndex); + } + @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + (int) (offset ^ (offset >>> 32)); - return result; + return Objects.hash(compilationUnit, dieIndex, offset); } @Override @@ -275,17 +257,38 @@ public class DebugInfoEntry { if (this == obj) { return true; } - if (obj == null) { - return false; - } if (!(obj instanceof DebugInfoEntry)) { return false; } DebugInfoEntry other = (DebugInfoEntry) obj; - if (offset != other.offset) { - return false; + return Objects.equals(compilationUnit, other.compilationUnit) && + dieIndex == other.dieIndex && offset == other.offset; + } + + @Override + public String toString() { + StringBuilder buffer = new StringBuilder(); + int tag = getTag(); + 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)); + + if (isTerminator()) { + return buffer.toString(); } - return true; + + 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())); + } + + return buffer.toString(); } } 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/dwarf4/expression/DWARFExpressionEvaluator.java index 580d02d5f8..61c8feeb22 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/dwarf4/expression/DWARFExpressionEvaluator.java @@ -91,7 +91,7 @@ public class DWARFExpressionEvaluator { public static DWARFExpressionEvaluator create(DebugInfoEntry die) { DWARFCompilationUnit compUnit = die.getCompilationUnit(); - DWARFProgram prog = die.getCompilationUnit().getProgram(); + DWARFProgram prog = die.getProgram(); DWARFExpressionEvaluator evaluator = new DWARFExpressionEvaluator(compUnit.getPointerSize(), !prog.isBigEndian(), compUnit.getFormat(), prog.getRegisterMappings()); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DIEAMonitoredIterator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DIEAMonitoredIterator.java deleted file mode 100644 index 3dc46db7d6..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf4/next/DIEAMonitoredIterator.java +++ /dev/null @@ -1,193 +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.util.Iterator; -import java.util.NoSuchElementException; - -import ghidra.app.util.bin.format.dwarf4.*; -import ghidra.util.Msg; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; - -/** - * Handles the details of iterating all the {@link DIEAggregate DIEAs} of a DWARF program. - *

- * DWARF programs are made of multiple compilation units (CUs), and each CU has - * {@link DebugInfoEntry DIE}s that are grouped together into aggregates (DIEAs). - *

- * In normal operation, to iterate the DIEAs, each CU's DIEs are loaded into memory, - * iterated, and then thrown away before going to the next CU. - *

- * There are typically no DIE references between CUs, but if there are, - * {@link DWARFImportOptions#isPreloadAllDIEs()} needs to be turned on by the user before - * analysis begins. - */ -public class DIEAMonitoredIterator { - - /** - * Create an iterable to allow for-each usage of this iterator. - * - * @param prog {@link DWARFProgram} that holds the DIEs. - * @param monitorMessage String to display in the TaskMonitor. - * @param monitor {@link TaskMonitor} - * @return Iterable that can be used in a for-each loop. - */ - public static Iterable iterable(DWARFProgram prog, String monitorMessage, - TaskMonitor monitor) { - return new Iterable() { - @Override - public Iterator iterator() { - return prog.getImportOptions().isPreloadAllDIEs() - ? new SimpleDIEAMonitoredIterator(prog, monitorMessage, monitor) - : new PagedDIEAMonitoredIterator(prog, monitorMessage, monitor); - } - }; - } - - /** - * {@link DIEAggregate} iterator for the "preload all dies" mode. - */ - static class SimpleDIEAMonitoredIterator implements Iterator { - private Iterator aggregateIterator; - private int aggregateTotalCount; - private TaskMonitor monitor; - private String monitorMessage; - - public SimpleDIEAMonitoredIterator(DWARFProgram prog, String monitorMessage, - TaskMonitor monitor) { - this.monitor = monitor; - this.monitorMessage = monitorMessage; - this.aggregateTotalCount = prog.getTotalAggregateCount(); - this.aggregateIterator = prog.getAggregates().iterator(); - - monitor.setIndeterminate(false); - monitor.setShowProgressValue(true); - monitor.initialize(aggregateTotalCount); - monitor.setMessage(monitorMessage); - } - - @Override - public boolean hasNext() { - return aggregateIterator.hasNext(); - } - - @Override - public DIEAggregate next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - DIEAggregate diea = aggregateIterator.next(); - - monitor.setMaximum(aggregateTotalCount); - monitor.setMessage(monitorMessage); - monitor.incrementProgress(1); - return diea; - } - - } - - /** - * {@link DIEAggregate} iterator for normal, CU-by-CU iteration of DIE records. - */ - static class PagedDIEAMonitoredIterator implements Iterator { - private TaskMonitor monitor; - private DWARFProgram prog; - private String monitorMessage; - private Iterator cuIterator; - private DWARFCompilationUnit cu; - private Iterator aggregateIterator; - private int cuCount; - private int aggregateTotalCount; - - public PagedDIEAMonitoredIterator(DWARFProgram prog, String monitorMessage, - TaskMonitor monitor) { - this.prog = prog; - this.monitor = monitor; - this.monitorMessage = monitorMessage; - this.cuCount = prog.getCompilationUnits().size(); - this.aggregateTotalCount = prog.getTotalAggregateCount(); - this.cuIterator = prog.getCompilationUnits().iterator(); - - monitor.setIndeterminate(false); - monitor.setShowProgressValue(true); - monitor.initialize(aggregateTotalCount); - monitor.setMessage(monitorMessage); - } - - private void updateMonitorMessage() { - // monitor's max gets tweaked by other users during analysis, so - // we reset it here every now and then - monitor.setMaximum(aggregateTotalCount); - monitor.setMessage( - monitorMessage + " - Compilation Unit #" + cu.getCompUnitNumber() + "/" + cuCount); - } - - private void finalizeMonitorMessage() { - monitor.setMessage(monitorMessage + " - Done"); - } - - @Override - public boolean hasNext() { - while (true) { - if (aggregateIterator == null) { - if (cuIterator.hasNext()) { - cu = cuIterator.next(); - - try { - prog.setCurrentCompilationUnit(cu, monitor); - } - catch (IOException | DWARFException e) { - Msg.warn(this, - "Error when reading DIE entries for CU #" + cu.getCompUnitNumber(), - e); - return false; - } - catch (CancelledException e) { - // no need to emit warning - return false; - } - aggregateIterator = prog.getAggregates().iterator(); - updateMonitorMessage(); - } - else { - finalizeMonitorMessage(); - return false; - } - } - if (aggregateIterator.hasNext()) { - return true; - } - - // The DIEA iterator for this CU is done. - // Throw it away (which signals that this CU is done.) The next - // loop in this while() will advance to the next CU and its entries. - aggregateIterator = null; - } - } - - @Override - public DIEAggregate next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - DIEAggregate diea = aggregateIterator.next(); - monitor.incrementProgress(1); - return diea; - } - } -} 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/dwarf4/next/DWARFDataTypeImporter.java index 94f76c2fc7..a3a5a096fc 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/dwarf4/next/DWARFDataTypeImporter.java @@ -56,7 +56,7 @@ public class DWARFDataTypeImporter { /** * Tracks which {@link DIEAggregate DIEAs} have been visited by {@link #getDataTypeWorker(DIEAggregate, DataType)} - * during the current {@link #getDataType(DIEAggregate, DataType)} session. + * during the current {@link #getDataType(DIEAggregate, DWARFDataType)} session. *

* Some recursive calls are permitted to handle loops in the data types, but are limited * to 2 recursions. @@ -625,12 +625,8 @@ public class DWARFDataTypeImporter { return (structSize < 0 || structSize > Integer.MAX_VALUE); } - /** + /* * Populates stub structs or unions with there fields. - * @param diea - * @param dataType - * @throws IOException - * @throws DWARFExpressionException */ private void finishStruct(DIEAggregate diea, DWARFDataType ddt) throws IOException, DWARFExpressionException { @@ -646,13 +642,8 @@ public class DWARFDataTypeImporter { } } - /** + /* * Populates an empty {@link UnionDataType} with its fields. - * @param union - * @param diea - * @param rec - * @throws IOException - * @throws DWARFExpressionException */ private void populateStubUnion(DWARFDataType ddt, DIEAggregate diea) throws IOException, DWARFExpressionException { @@ -775,12 +766,8 @@ public class DWARFDataTypeImporter { } } - /** + /* * Populates an empty {@link StructureDataType} with its fields. - * @param structure - * @param diea - * @throws IOException - * @throws DWARFExpressionException */ private void populateStubStruct(DWARFDataType ddt, DIEAggregate diea) throws IOException, DWARFExpressionException { @@ -804,12 +791,11 @@ public class DWARFDataTypeImporter { } } - /** + /* * Restore structure fields to their regular size (if there is room) to ensure * future DataType equiv and comparisons are successful. *

* (ie. undoes {@link #getUnpaddedDataTypeLength(DataType)} if there is room) - * @param structure */ private void removeUneededStructMemberShrinkage(StructureDataType structure) { DataTypeComponent[] definedComponents = structure.getDefinedComponents(); @@ -836,10 +822,8 @@ public class DWARFDataTypeImporter { } - /** + /* * Detect the real length of a DataType (ie. drop any trailing padding). - * @param dt - * @return */ private int getUnpaddedDataTypeLength(DataType dt) { if (dt instanceof TypeDef) { @@ -1088,14 +1072,10 @@ public class DWARFDataTypeImporter { return result; } - /** + /* * Creates a Ghidra {@link ArrayDataType}. *

* Multi-dim DWARF arrays will result in nested Ghidra array types. - *

- * @param diea - * @throws IOException - * @throws DWARFExpressionException */ private DWARFDataType makeDataTypeForArray(DIEAggregate diea) throws IOException, DWARFExpressionException { @@ -1179,7 +1159,7 @@ public class DWARFDataTypeImporter { return result; } - /** + /* * Creates a {@link Pointer} datatype. *

* If there is no pointer size specified in the DWARF DIE, use the default pointer size @@ -1197,9 +1177,6 @@ public class DWARFDataTypeImporter { * The struct creation code will stop the recursive loop after the second time * makeDataTypeForPointer() is hit because there will be an empty struct in the cache. * - * @param diea - * @throws IOException - * @throws DWARFExpressionException */ private DWARFDataType makeDataTypeForPointer(DIEAggregate diea) throws IOException, DWARFExpressionException { @@ -1251,7 +1228,7 @@ public class DWARFDataTypeImporter { return new DWARFDataType(dt, dni, diea.getOffset()); } - /** + /* * Creates a {@link TypeDef} datatype. *

* If the typedef has the same name as the destination type, create an equiv mapping @@ -1265,10 +1242,6 @@ public class DWARFDataTypeImporter { * create the typedef as it can do it better if there are size specifiers in the typedef name * (eg. int64_t). * - * @param diea - * @param rec - * @throws IOException - * @throws DWARFExpressionException */ private DWARFDataType makeDataTypeForTypedef(DIEAggregate diea) throws IOException, DWARFExpressionException { @@ -1325,13 +1298,11 @@ public class DWARFDataTypeImporter { return new DWARFDataType(typedefDT, typedefDNI, diea.getOffset()); } - /** + /* * Creates a datatype representing the string in the unspecifiedtype dwarf definition. *

* Most likely will be a void type. * - * @param diea - * @return */ private DWARFDataType makeDataTypeForUnspecifiedType(DIEAggregate diea) { DWARFNameInfo dni = prog.getName(diea); 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/dwarf4/next/DWARFDataTypeManager.java index f5c1df950d..65fc1c63af 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/dwarf4/next/DWARFDataTypeManager.java @@ -15,6 +15,8 @@ */ package ghidra.app.util.bin.format.dwarf4.next; +import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*; + import java.io.IOException; import java.util.*; import java.util.regex.Matcher; @@ -39,6 +41,12 @@ 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; @@ -329,15 +337,6 @@ public class DWARFDataTypeManager { return baseDataTypeVoid; } - /** - * Returns datatype to hold a 1 byte undefined value. - * - * @return undefined 1 byte {@link DataType}. - */ - public DataType getUndefined1Type() { - return baseDataTypeUndefined1; - } - /** * Returns a DWARF base data type based on its name, or null if it does not exist. * @@ -458,14 +457,10 @@ public class DWARFDataTypeManager { return usedFixedSizeType ? null : dataTypeManager; } - /** + /* * Create a string with the data type's size and type info so that * the data type can be stored in the same map as the regular named base types without * conflicting. - *

- * @param dwarfLength - * @param dwarfEncoding - * @return */ private String mangleDataTypeInfo(int dwarfLength, int dwarfEncoding) { return String.format("%s_%d_%d", BASETYPE_MANGLE_PREFIX, dwarfLength, dwarfEncoding); @@ -558,29 +553,29 @@ public class DWARFDataTypeManager { throws IOException, DWARFException, CancelledException { int dtCountBefore = dataTypeManager.getDataTypeCount(true); - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(prog, "DWARF Import Types", - monitor)) { - monitor.checkCancelled(); + monitor.initialize(prog.getTotalAggregateCount(), "DWARF Import Types"); + for (DIEAggregate diea : prog.allAggregates()) { + monitor.increment(); try { - if (isDataType(diea)) { + if (TYPE_TAGS.contains(diea.getTag())) { doGetDataType(diea); } } catch (IllegalArgumentException iae) { // squelch full stack trace for data type errors where structure is defined to // have itself inside itself. - Msg.error(this, - "Failed to process DWARF DIE " + diea.getHexOffset() + ": " + iae.getMessage()); + Msg.error(this, "Failed to process DWARF DIE %x: %s".formatted(diea.getOffset(), + iae.getMessage())); } catch (OutOfMemoryError oom) { throw oom; } catch (Throwable th) { - // Aggressively catch pretty much everything to allow the import to - // try to continue with the next compunit. - Msg.error(this, - "Error when processing DWARF information for DIE " + diea.getHexOffset(), th); + // Aggressively catch pretty much everything to allow the import to continue + Msg.error(this, "Error when processing DWARF information for DIE %x" + .formatted(diea.getOffset()), + th); Msg.info(this, "DIE info:\n" + diea.toString()); } } @@ -628,31 +623,6 @@ public class DWARFDataTypeManager { return null; } - private boolean isDataType(DIEAggregate diea) { - switch (diea.getTag()) { - case DWARFTag.DW_TAG_base_type: - case DWARFTag.DW_TAG_array_type: - case DWARFTag.DW_TAG_typedef: - 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_pointer_type: - case DWARFTag.DW_TAG_reference_type: - case DWARFTag.DW_TAG_rvalue_reference_type: - case DWARFTag.DW_TAG_const_type: - case DWARFTag.DW_TAG_volatile_type: - case DWARFTag.DW_TAG_ptr_to_member_type: - case DWARFTag.DW_TAG_unspecified_type: - case DWARFTag.DW_TAG_subroutine_type: - return true; - - default: - return false; - } - } - /** * Creates a new {@link FunctionDefinitionDataType} from the specified {@link DIEAggregate} * using already known datatypes. 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/dwarf4/next/DWARFFunctionImporter.java index 5b021371b0..a4fbf5f113 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/dwarf4/next/DWARFFunctionImporter.java @@ -20,7 +20,6 @@ import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*; import java.io.IOException; import java.util.*; -import java.util.stream.Collectors; import ghidra.app.cmd.label.SetLabelPrimaryCmd; import ghidra.app.util.bin.format.dwarf4.*; @@ -98,9 +97,9 @@ public class DWARFFunctionImporter { } } - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(prog, - "DWARF - Create Funcs & Symbols", monitor)) { - monitor.checkCancelled(); + monitor.initialize(prog.getTotalAggregateCount(), "DWARF - Create Funcs & Symbols"); + for (DIEAggregate diea : prog.allAggregates()) { + monitor.increment(); try { switch (diea.getTag()) { @@ -133,8 +132,9 @@ public class DWARFFunctionImporter { throw oom; } catch (Throwable th) { - Msg.error(this, - "Error when processing DWARF information for DIE " + diea.getHexOffset(), th); + Msg.error(this, "Error when processing DWARF information for DIE %x" + .formatted(diea.getOffset()), + th); Msg.info(this, "DIE info:\n" + diea.toString()); } } @@ -145,17 +145,12 @@ public class DWARFFunctionImporter { private void logImportErrorSummary() { if (!importSummary.unknownRegistersEncountered.isEmpty()) { - Msg.error(this, "Found " + importSummary.unknownRegistersEncountered.size() + - " unknown registers referenced in DWARF expression operands:"); + Msg.error(this, "Found %d unknown registers referenced in DWARF expression operands:" + .formatted(importSummary.unknownRegistersEncountered.size())); List sortedUnknownRegs = new ArrayList<>(importSummary.unknownRegistersEncountered); Collections.sort(sortedUnknownRegs); - Msg.error(this, - " unknown registers: " + - sortedUnknownRegs.stream() - .map(i -> Integer.toString(i)) - .collect( - Collectors.joining(", "))); + Msg.error(this, " unknown registers: %s".formatted(sortedUnknownRegs)); } } 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/dwarf4/next/DWARFImportOptions.java index 2c2b86fa17..81b6f75a2d 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/dwarf4/next/DWARFImportOptions.java @@ -28,21 +28,11 @@ public class DWARFImportOptions { private static final String OPTION_IMPORT_DATATYPES_DESC = "Import data types defined in the DWARF debug info."; - private static final String OPTION_PRELOAD_ALL_DIES = "Preload All DIEs"; - private static final String OPTION_PRELOAD_ALL_DIES_DESC = - "Preload all DIE records. Requires more memory, but necessary for some non-standard " + - "layouts."; - private static final String OPTION_IMPORT_FUNCS = "Import Functions"; private static final String OPTION_IMPORT_FUNCS_DESC = "Import function information defined in the DWARF debug info\n" + "(implies 'Import Data Types' is selected)."; - private static final String OPTION_IMPORT_LIMIT_DIE_COUNT = "Debug Item Limit"; - private static final String OPTION_IMPORT_LIMIT_DIE_COUNT_DESC = - "If the number of DWARF debug items are greater than this setting, DWARF analysis will " + - "be skipped."; - private static final String OPTION_OUTPUT_SOURCE_INFO = "Output Source Info"; private static final String OPTION_OUTPUT_SOURCE_INFO_DESC = "Include source code location info (filename:linenumber) in comments attached to the " + @@ -53,10 +43,6 @@ public class DWARFImportOptions { "Include DWARF DIE offset info in comments attached to the Ghidra datatype or function " + "or variable created."; - private static final String OPTION_NAME_LENGTH_CUTOFF = "Maximum Name Length"; - private static final String OPTION_NAME_LENGTH_CUTOFF_DESC = - "Truncate symbol and type names longer than this limit. Range 20..2000"; - private static final String OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS = "Add Lexical Block Comments"; private static final String OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS_DESC = "Add comments to the start of lexical blocks"; @@ -84,12 +70,9 @@ public class DWARFImportOptions { //================================================================================================== private static final String OPTION_IMPORT_DATATYPES_OLD = "Import data types"; - private static final String OPTION_PRELOAD_ALL_DIES_OLD = "Preload all DIEs"; private static final String OPTION_IMPORT_FUNCS_OLD = "Import functions"; - private static final String OPTION_IMPORT_LIMIT_DIE_COUNT_OLD = "Debug item count limit"; private static final String OPTION_OUTPUT_SOURCE_INFO_OLD = "Output Source info"; private static final String OPTION_OUTPUT_DWARF_DIE_INFO_OLD = "Output DWARF DIE info"; - private static final String OPTION_NAME_LENGTH_CUTOFF_OLD = "Name length cutoff"; private static final String OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS_OLD = "Lexical block comments"; private static final String OPTION_OUTPUT_INLINE_FUNC_COMMENTS_OLD = "Inlined functions comments"; @@ -99,8 +82,6 @@ public class DWARFImportOptions { // End Old Option Names //================================================================================================== - private static final int DEFAULT_IMPORT_LIMIT_DIE_COUNT = 2_000_000; - private AnalysisOptionsUpdater optionsUpdater = new AnalysisOptionsUpdater(); private boolean outputDWARFLocationInfo = false; @@ -108,9 +89,6 @@ public class DWARFImportOptions { private boolean elideTypedefsWithSameName = true; private boolean importDataTypes = true; private boolean importFuncs = true; - private int importLimitDIECount = DEFAULT_IMPORT_LIMIT_DIE_COUNT; - private int nameLengthCutoff = DWARFProgram.DEFAULT_NAME_LENGTH_CUTOFF; - private boolean preloadAllDIEs = false; private boolean outputInlineFuncComments = false; private boolean outputLexicalBlockComments = false; private boolean copyRenameAnonTypes = true; @@ -125,16 +103,11 @@ public class DWARFImportOptions { */ public DWARFImportOptions() { optionsUpdater.registerReplacement(OPTION_IMPORT_DATATYPES, OPTION_IMPORT_DATATYPES_OLD); - optionsUpdater.registerReplacement(OPTION_PRELOAD_ALL_DIES, OPTION_PRELOAD_ALL_DIES_OLD); optionsUpdater.registerReplacement(OPTION_IMPORT_FUNCS, OPTION_IMPORT_FUNCS_OLD); - optionsUpdater.registerReplacement(OPTION_IMPORT_LIMIT_DIE_COUNT, - OPTION_IMPORT_LIMIT_DIE_COUNT_OLD); optionsUpdater.registerReplacement(OPTION_OUTPUT_SOURCE_INFO, OPTION_OUTPUT_SOURCE_INFO_OLD); optionsUpdater.registerReplacement(OPTION_OUTPUT_DWARF_DIE_INFO, OPTION_OUTPUT_DWARF_DIE_INFO_OLD); - optionsUpdater.registerReplacement(OPTION_NAME_LENGTH_CUTOFF, - OPTION_NAME_LENGTH_CUTOFF_OLD); optionsUpdater.registerReplacement(OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS, OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS_OLD); optionsUpdater.registerReplacement(OPTION_OUTPUT_INLINE_FUNC_COMMENTS, @@ -243,64 +216,6 @@ public class DWARFImportOptions { this.importFuncs = output_Funcs; } - /** - * Option to skip DWARF import if the DWARF record count is too large. - * - * @return integer count of the max number of DWARF records that will be attempted to import. - */ - public int getImportLimitDIECount() { - return importLimitDIECount; - } - - /** - * Option to skip DWARF import if the DWARF record count is too large. - * - * @param import_limit_die_count integer record count - */ - public void setImportLimitDIECount(int import_limit_die_count) { - this.importLimitDIECount = import_limit_die_count; - } - - /** - * Option to control how long DWARF symbol names are allowed to be before being truncated. - * - * @return integer max length of symbol names from DWARF. - */ - public int getNameLengthCutoff() { - return nameLengthCutoff; - } - - /** - * Option to control how long DWARF symbol names are allowed to be before being truncated. - * - * @param name_length_cutoff integer max length. - */ - public void setNameLengthCutoff(int name_length_cutoff) { - this.nameLengthCutoff = name_length_cutoff; - } - - /** - * Option to cause the DWARF parser to load all DWARF records into memory, instead of - * processing one compile unit at a time. Needed to handle binaries created by some - * toolchains. The import pre-check will warn the user if this needs to be turned on. - * - * @return boolean flag - */ - public boolean isPreloadAllDIEs() { - return preloadAllDIEs; - } - - /** - * Option to cause the DWARF parser to load all DWARF records into memory, instead of - * processing one compile unit at a time. Needed to handle binaries created by some - * toolchains. The import pre-check will warn the user if this needs to be turned on. - * - * @param b boolean flag to set - */ - public void setPreloadAllDIEs(boolean b) { - this.preloadAllDIEs = b; - } - /** * Option to control tagging inlined-functions with comments. * @@ -449,9 +364,6 @@ public class DWARFImportOptions { options.registerOption(OPTION_IMPORT_DATATYPES, isImportDataTypes(), null, OPTION_IMPORT_DATATYPES_DESC); - options.registerOption(OPTION_PRELOAD_ALL_DIES, isPreloadAllDIEs(), null, - OPTION_PRELOAD_ALL_DIES_DESC); - options.registerOption(OPTION_IMPORT_FUNCS, isImportFuncs(), null, OPTION_IMPORT_FUNCS_DESC); @@ -467,12 +379,6 @@ public class DWARFImportOptions { options.registerOption(OPTION_OUTPUT_SOURCE_INFO, isOutputSourceLocationInfo(), null, OPTION_OUTPUT_SOURCE_INFO_DESC); - options.registerOption(OPTION_IMPORT_LIMIT_DIE_COUNT, getImportLimitDIECount(), null, - OPTION_IMPORT_LIMIT_DIE_COUNT_DESC); - - options.registerOption(OPTION_NAME_LENGTH_CUTOFF, getNameLengthCutoff(), null, - OPTION_NAME_LENGTH_CUTOFF_DESC); - options.registerOption(OPTION_OUTPUT_FUNC_SIGS, isCreateFuncSignatures(), null, OPTION_OUTPUT_FUNC_SIGS_DESC); @@ -490,7 +396,6 @@ public class DWARFImportOptions { */ public void optionsChanged(Options options) { setOutputDIEInfo(options.getBoolean(OPTION_OUTPUT_DWARF_DIE_INFO, isOutputDIEInfo())); - setPreloadAllDIEs(options.getBoolean(OPTION_PRELOAD_ALL_DIES, isPreloadAllDIEs())); setOutputSourceLocationInfo( options.getBoolean(OPTION_OUTPUT_SOURCE_INFO, isOutputSourceLocationInfo())); setOutputLexicalBlockComments(options.getBoolean(OPTION_OUTPUT_LEXICAL_BLOCK_COMMENTS, @@ -499,14 +404,10 @@ public class DWARFImportOptions { options.getBoolean(OPTION_OUTPUT_INLINE_FUNC_COMMENTS, isOutputInlineFuncComments())); setImportDataTypes(options.getBoolean(OPTION_IMPORT_DATATYPES, isImportDataTypes())); setImportFuncs(options.getBoolean(OPTION_IMPORT_FUNCS, isImportFuncs())); - setImportLimitDIECount( - options.getInt(OPTION_IMPORT_LIMIT_DIE_COUNT, getImportLimitDIECount())); - setNameLengthCutoff(options.getInt(OPTION_NAME_LENGTH_CUTOFF, getNameLengthCutoff())); setCreateFuncSignatures( options.getBoolean(OPTION_OUTPUT_FUNC_SIGS, isCreateFuncSignatures())); setTryPackDataTypes(options.getBoolean(OPTION_TRY_PACK_STRUCTS, isTryPackStructs())); setImportLocalVariables( options.getBoolean(OPTION_IMPORT_LOCAL_VARS, isImportLocalVariables())); - } } 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/dwarf4/next/DWARFProgram.java index 332911d4c7..5b5cc549c2 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/dwarf4/next/DWARFProgram.java @@ -15,9 +15,9 @@ */ package ghidra.app.util.bin.format.dwarf4.next; -import java.io.Closeable; -import java.io.IOException; +import java.io.*; import java.util.*; +import java.util.Map.Entry; import org.apache.commons.collections4.ListValuedMap; import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; @@ -40,7 +40,7 @@ import ghidra.program.model.data.DataType; import ghidra.program.model.listing.Program; import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.Msg; -import ghidra.util.datastruct.FixedSizeHashMap; +import ghidra.util.datastruct.*; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -54,10 +54,6 @@ 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_"); - public static final int DEFAULT_NAME_LENGTH_CUTOFF = SymbolUtilities.MAX_SYMBOL_NAME_LENGTH; - public static final int MAX_NAME_LENGTH_CUTOFF = SymbolUtilities.MAX_SYMBOL_NAME_LENGTH; - public static final int MIN_NAME_LENGTH_CUTOFF = 20; - private static final int NAME_HASH_REPLACEMENT_SIZE = 8 + 2 + 2; private static final String ELLIPSES_STR = "..."; @@ -122,71 +118,64 @@ public class DWARFProgram implements Closeable { } private final Program program; - private DWARFImportOptions importOptions; - private DWARFImportSummary importSummary; + private final DWARFDataTypeManager dwarfDTM; private DWARFNameInfo rootDNI = DWARFNameInfo.createRoot(DWARF_ROOT_CATPATH); private DWARFNameInfo unCatDataTypeRoot = DWARFNameInfo.createRoot(UNCAT_CATPATH); + private DWARFImportOptions importOptions; + private DWARFImportSummary importSummary; private DWARFSectionProvider sectionProvider; private StringTable debugStrings; - private List compUnits = new ArrayList<>(); - private DWARFCompilationUnit currentCompUnit; private DWARFAttributeFactory attributeFactory; - private int totalDIECount = -1; private int totalAggregateCount; - private boolean foundCrossCURefs = false; private long programBaseAddressFixup; private int maxDNICacheSize = 50; private FixedSizeHashMap dniCache = new FixedSizeHashMap<>(100, maxDNICacheSize); - private int nameLengthCutoffSize = DEFAULT_NAME_LENGTH_CUTOFF; private Map attributeSpecIntern = new HashMap<>(); + private DWARFRegisterMappings dwarfRegisterMappings; + private final boolean stackGrowsNegative; + + private List functionFixups; private BinaryReader debugLocation; private BinaryReader debugRanges; private BinaryReader debugInfoBR; private BinaryReader debugLineBR; private BinaryReader debugAbbrBR; - private DWARFRegisterMappings dwarfRegisterMappings; - /** - * List of all the currently loaded DIE records. - */ - private List currentDIEs = new ArrayList<>(); + // 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. + // 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. + protected int[] parentIndexes = new int[0]; // index of each DIE's parent record, or -1 for root - /** - * Map of DIE offsets to DIE instances of the elements in {@link #currentDIEs}. - */ - private Map offsetMap = new HashMap<>(); + // DIE index -> compunit lookup. Each key in the map is the index of the last DIE of a + // compunit. Querying the map for the ceilingEntry() of a DIE's index will return + // the compunit for that DIE. + protected TreeMap compUnitDieIndex = new TreeMap<>(); + protected List compUnits = new ArrayList<>(); - /** - * Map of DIE offsets to {@link DIEAggregate} instances. - */ - private Map aggregatesByOffset = new HashMap<>(); + // 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(); - /** - * List of current {@link DIEAggregate} instances. - */ - private List aggregates = new ArrayList<>(); + // Cache of DIE and DIEAggregate instances. If needed instance is not found (because of + // gc), it will be re-read / re-created and placed back into the map. + protected WeakValueHashMap diesByOffset = new WeakValueHashMap<>(); + private WeakValueHashMap aggsByOffset = new WeakValueHashMap<>(); - /** - * 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. - */ + // 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 final DWARFDataTypeManager dwarfDTM; - - private final boolean stackGrowsNegative; - - private List functionFixups; - /** * Main constructor for DWARFProgram. *

@@ -218,8 +207,7 @@ public class DWARFProgram implements Closeable { * @throws DWARFException if bad stuff happens. */ public DWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor, - DWARFSectionProvider sectionProvider) - throws CancelledException, IOException, DWARFException { + DWARFSectionProvider sectionProvider) throws CancelledException, IOException { if (sectionProvider == null) { throw new IllegalArgumentException("Null DWARFSectionProvider"); } @@ -228,15 +216,8 @@ public class DWARFProgram implements Closeable { this.sectionProvider = sectionProvider; this.importOptions = importOptions; this.importSummary = new DWARFImportSummary(); - this.nameLengthCutoffSize = Math.max(MIN_NAME_LENGTH_CUTOFF, - Math.min(importOptions.getNameLengthCutoff(), MAX_NAME_LENGTH_CUTOFF)); this.dwarfDTM = new DWARFDataTypeManager(this, program.getDataTypeManager()); this.stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative(); - - monitor.setMessage("Reading DWARF debug string table"); - this.debugStrings = StringTable.readStringTable( - sectionProvider.getSectionAsByteProvider(DWARFSectionNames.DEBUG_STR, monitor)); - this.attributeFactory = new DWARFAttributeFactory(this); this.debugLocation = getBinaryReaderFor(DWARFSectionNames.DEBUG_LOC, monitor); @@ -245,8 +226,9 @@ public class DWARFProgram implements Closeable { this.debugAbbrBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_ABBREV, monitor); this.debugRanges = getBinaryReaderFor(DWARFSectionNames.DEBUG_RANGES, 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 extracted from DWARF data. + // 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 + // extracted from DWARF data. boolean hasRelocations = hasRelocations(debugInfoBR) || hasRelocations(debugRanges); if (!hasRelocations) { Long oib = ElfLoader.getElfOriginalImageBase(program); @@ -259,22 +241,200 @@ public class DWARFProgram implements Closeable { DWARFRegisterMappingsManager.hasDWARFRegisterMapping(program.getLanguage()) ? DWARFRegisterMappingsManager.getMappingForLang(program.getLanguage()) : null; + } + + /** + * Reads and indexes available DWARF information. + * + * @param monitor {@link TaskMonitor} + * @throws IOException if error reading data + * @throws DWARFException if bad or invalid DWARF information + * @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); - checkPreconditions(monitor); + + LongArrayList dieOffsetList = new LongArrayList(); + IntArrayList siblingIndexList = new IntArrayList(); + IntArrayList parentIndexList = new IntArrayList(); + LongArrayList aggrTargets = new LongArrayList(); + + monitor.initialize(debugInfoBR.length(), "DWARF: Indexing records"); + 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); + compUnitDieIndex.put(dieOffsetList.size() - 1, cu); + } + + dieOffsets = dieOffsetList.toLongArray(); + siblingIndexes = siblingIndexList.toArray(); + parentIndexes = parentIndexList.toArray(); + + indexDIEAggregates(aggrTargets, monitor); // after this point, DIEAggregates are functional + int nonHeadCount = indexHasRef.cardinality(); + totalAggregateCount = dieOffsetList.size() - nonHeadCount; + + indexDIEATypeRefs(monitor); + + Msg.info(this, + "DWARF: %d compile units, %d DIEs".formatted(compUnits.size(), dieOffsets.length)); + } + + protected void indexDIEATypeRefs(TaskMonitor monitor) throws CancelledException { + monitor.initialize(totalAggregateCount, "DWARF: Indexing Type References"); + for (DIEAggregate diea : allAggregates()) { + monitor.increment(); + DIEAggregate typeRef = diea.getTypeRef(); + if (typeRef != null) { + typeReferers.put(typeRef.getOffset(), diea); + } + } + + } + + protected void indexDIEAggregates(LongArrayList aggrTargets, TaskMonitor monitor) + throws CancelledException, DWARFException { + monitor.initialize(aggrTargets.size(), "DWARF: Indexing DIE Aggregates"); + for (long aggrTargetOffset : aggrTargets) { + monitor.increment(); + int dieIndex = getDIEIndex(aggrTargetOffset); + if (dieIndex < 0) { + throw new DWARFException(); + } + indexHasRef.set(dieIndex); + } + } + + 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 { + long endOffset = cu.getEndOffset(); + + int perCuDieCount = 0; + int parentIndex = -1; + long unexpectedTerminator = -1; + while (debugInfoBR.getPointerIndex() < endOffset) { + + long startOfDIE = debugInfoBR.getPointerIndex(); + monitor.setProgress(startOfDIE); + monitor.setMessage("DWARF: Indexing Compilation Unit #" + compUnits.size()); + monitor.checkCancelled(); + + try { + int dieIndex = dieOffsetList.size(); + DebugInfoEntry die = + DebugInfoEntry.read(debugInfoBR, cu, dieIndex, attributeFactory); + + if (die.isTerminator()) { + if (parentIndex == -1) { + unexpectedTerminator = startOfDIE; + continue; + } + parentIndex = parentIndexList.get(parentIndex); + continue; + } + if (unexpectedTerminator != -1) { + // if we run into a non-terminator die after hitting a terminator, throw error + throw new DWARFException( + "Unexpected terminator entry at 0x%x".formatted(unexpectedTerminator)); + } + if (parentIndex == -1 && perCuDieCount != 0 /* first die of CU */) { + throw new DWARFException( + "Unexpected root level DIE at 0x%x".formatted(startOfDIE)); + } + + dieOffsetList.add(startOfDIE); + parentIndexList.add(parentIndex); + siblingIndexList.add(dieIndex + 1); + perCuDieCount++; + + updateSiblingIndexes(siblingIndexList, parentIndexList, dieIndex); + + if (die.getAbbreviation().hasChildren()) { + parentIndex = dieIndex; + } + + DIEAggregate diea = DIEAggregate.createSingle(die); + for (int attr : DIEAggregate.REF_ATTRS) { + long refdOffset = diea.getUnsignedLong(attr, -1); + if (refdOffset != -1) { + aggrTargets.add(refdOffset); + } + } + + diesByOffset.put(startOfDIE, die); + } + 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()), + e); + debugInfoBR.setPointerIndex(endOffset); + } + } + + } + + protected void updateSiblingIndexes(IntArrayList siblingIndexList, IntArrayList parentIndexList, + int index) { + int x = siblingIndexList.size(); + while (index != -1) { + siblingIndexList.set(index, x); + index = parentIndexList.get(index); + } } @Override public void close() throws IOException { - sectionProvider.close(); + if (sectionProvider != null) { + sectionProvider.close(); + } + if (debugStrings != null) { + debugStrings.clear(); + } compUnits.clear(); + dniCache.clear(); + debugAbbrBR = null; debugInfoBR = null; debugLineBR = null; debugLocation = null; debugRanges = null; - debugStrings.clear(); - dniCache.clear(); - clearDIEIndexes(); + + dieOffsets = new long[0]; + parentIndexes = new int[0]; + siblingIndexes = new int[0]; + indexHasRef.clear(); + aggsByOffset.clear(); + diesByOffset.clear(); + typeReferers.clear(); + compUnitDieIndex.clear(); if (functionFixups != null) { for (DWARFFunctionFixup funcFixup : functionFixups) { @@ -314,10 +474,10 @@ public class DWARFProgram implements Closeable { private BinaryReader getBinaryReaderFor(String sectionName, TaskMonitor monitor) throws IOException { ByteProvider bp = sectionProvider.getSectionAsByteProvider(sectionName, monitor); - return (bp != null) ? new BinaryReader(bp, !isBigEndian()) : null; + return (bp != null) ? new BinaryReader(bp, isLittleEndian()) : null; } - private boolean hasRelocations(BinaryReader br) throws IOException { + private boolean hasRelocations(BinaryReader br) { if (br == null) { return false; } @@ -330,7 +490,6 @@ public class DWARFProgram implements Closeable { return false; } - //------------------------------------------------------------------------- private static boolean isAnonDWARFName(String name) { return (name == null) || name.startsWith("._") || name.startsWith(" * Always returns a name for the passed-in entry, but you should probably only use this * for entries that are {@link DIEAggregate#isNamedType()} - *

- * @param diea - * @return never null */ private DWARFNameInfo getDWARFNameInfo(DIEAggregate diea, DWARFNameInfo localRootDNI) { @@ -411,12 +567,13 @@ public class DWARFProgram implements Closeable { // 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 != null) - ? diea.getProgram().getTypeReferers(diea, DWARFTag.DW_TAG_member) - : null; + List referringMembers = + diea.getProgram().getTypeReferers(diea, DWARFTag.DW_TAG_member); String referringMemberNames = getReferringMemberFieldNames(referringMembers); if (!referringMemberNames.isEmpty()) { + // this re-homes this anon struct def from the root of the compunit to the + // structure that is using this anon struct def. parentDNI = getName(referringMembers.get(0).getParent()); referringMemberNames = "_for_" + referringMemberNames; } @@ -447,7 +604,7 @@ public class DWARFProgram implements Closeable { name = DWARFUtil.getLexicalBlockName(diea); break; case DWARFTag.DW_TAG_formal_parameter: - name = "param_" + DWARFUtil.getMyPositionInParent(diea.getHeadFragment()); + name = "param_%d".formatted(diea.getHeadFragment().getPositionInParent()); isAnon = true; break; case DWARFTag.DW_TAG_subprogram: @@ -531,13 +688,12 @@ public class DWARFProgram implements Closeable { } String memberName = referringMember.getName(); if (memberName == null) { - int positionInParent = - DWARFUtil.getMyPositionInParent(referringMember.getHeadFragment()); + int positionInParent = referringMember.getHeadFragment().getPositionInParent(); if (positionInParent == -1) { continue; } DWARFNameInfo parentDNI = getName(commonParent); - memberName = parentDNI.getName() + "_" + Integer.toString(positionInParent); + memberName = "%s_%d".formatted(parentDNI.getName(), positionInParent); } if (result.length() > 0) { result.append("_"); @@ -546,7 +702,7 @@ public class DWARFProgram implements Closeable { } return result.toString(); } - + /** * Transform a string with a C++ template-like syntax into a hopefully shorter version that * uses a fixed-length hash of the original string. @@ -556,32 +712,31 @@ public class DWARFProgram implements Closeable { * becomes *

* blah<$12345678$> - * @param s - * @return + * @param s data type name + * @return transformed data type name */ private static String abbrevTemplateName(String s) { int startBracket = s.indexOf('<'); int endBracket = s.lastIndexOf('>'); if (startBracket + NAME_HASH_REPLACEMENT_SIZE < endBracket) { String templateParams = s.substring(startBracket, endBracket); - return s.substring(0, startBracket + 1) + "$" + - Integer.toHexString(templateParams.hashCode()) + "$" + s.substring(endBracket); + return "%s$%x$%s".formatted(s.substring(0, startBracket + 1), templateParams.hashCode(), + s.substring(endBracket)); } return s; } private String ensureSafeNameLength(String s) { - if (s.length() <= nameLengthCutoffSize) { + if (s.length() <= SymbolUtilities.MAX_SYMBOL_NAME_LENGTH) { return s; } s = abbrevTemplateName(s); - if (s.length() <= nameLengthCutoffSize) { + if (s.length() <= SymbolUtilities.MAX_SYMBOL_NAME_LENGTH) { return s; } - int prefixKeepLength = - nameLengthCutoffSize - ELLIPSES_STR.length() - NAME_HASH_REPLACEMENT_SIZE; - return s.substring(0, prefixKeepLength) + ELLIPSES_STR + "$" + - Integer.toHexString(s.hashCode()) + "$"; + int prefixKeepLength = SymbolUtilities.MAX_SYMBOL_NAME_LENGTH - ELLIPSES_STR.length() - + NAME_HASH_REPLACEMENT_SIZE; + return "%s%s$%x$".formatted(s.substring(0, prefixKeepLength), ELLIPSES_STR, s.hashCode()); } private List ensureSafeNameLengths(List strs) { @@ -600,42 +755,153 @@ public class DWARFProgram implements Closeable { return dni; } - public DWARFNameInfo lookupDNIByOffset(long offset) { + private DWARFNameInfo lookupDNIByOffset(long offset) { DWARFNameInfo tmp = dniCache.get(offset); return tmp; } - public void cacheDNIByOffset(long offset, DWARFNameInfo dni) { + private void cacheDNIByOffset(long offset, DWARFNameInfo dni) { dniCache.put(offset, dni); } - //------------------------------------------------------------------------------ + /** + * Returns the parent DIE of the specified (by index) DIE + * + * @param dieIndex index of a DIE record + * @return parent DIE, or null if no parent (eg. root DIE) + */ + public DebugInfoEntry getParentOf(int dieIndex) { + int parentIndex = parentIndexes[dieIndex]; + return parentIndex >= 0 ? getDIEByIndex(parentIndex) : null; + } /** - * Bootstrap all compilation unit headers and abbreviation definitions. - * @throws DWARFException - * @throws IOException - * @throws CancelledException + * Returns the index of the parent of the specified DIE. + * + * @param dieIndex index of a DIE record + * @return index of the parent of specified DIE, or -1 if no parent (eg. root DIE) */ - private void bootstrapCompilationUnits(TaskMonitor monitor) - throws CancelledException, IOException, DWARFException { + public int getParentIndex(int dieIndex) { + return parentIndexes[dieIndex]; + } - BinaryReader br = debugInfoBR; - br.setPointerIndex(0); - while (br.hasNext()) { - monitor.checkCancelled(); - monitor.setMessage("Bootstrapping DWARF Compilation Unit #" + compUnits.size()); + /** + * Returns the depth of the specified DIE. + * + * @param dieIndex index of a DIE record + * @return parent/child depth of specified record, where 0 is the root DIE + */ + public int getParentDepth(int dieIndex) { + int depth = 0; + while (dieIndex != -1) { + dieIndex = parentIndexes[dieIndex]; + depth++; + } + return depth - 1; + } - DWARFCompilationUnit cu = DWARFCompilationUnit.readCompilationUnit(this, br, - debugAbbrBR, compUnits.size(), monitor); + /** + * Returns the children of the specified DIE + * + * @param dieIndex index of a DIE record + * @return list of DIE instances that are children of the specified DIE + */ + public List getChildrenOf(int dieIndex) { + IntArrayList childIndexes = getDIEChildIndexes(dieIndex); + if (childIndexes.isEmpty()) { + return List.of(); + } + List result = new ArrayList<>(childIndexes.size()); + for (int i = 0; i < childIndexes.size(); i++) { + result.add(getDIEByIndex(childIndexes.get(i))); + } + return result; + } - if (cu != null) { - compUnits.add(cu); - br.setPointerIndex(cu.getEndOffset()); + /** + * Returns list of indexes of the children of the specified DIE + * + * @param dieIndex index of a DIE record + * @return list of DIE indexes that are children of the specified DIE + */ + public IntArrayList getDIEChildIndexes(int dieIndex) { + IntArrayList result = new IntArrayList(true); + if (dieIndex >= 0) { + int parentSiblingIndex = siblingIndexes[dieIndex]; + for (int index = dieIndex + 1; index < parentSiblingIndex; index = + siblingIndexes[index]) { + result.add(index); } } + return result; } + private DWARFCompilationUnit getCompilationUnitForDIE(int dieIndex) { + Entry entry = compUnitDieIndex.ceilingEntry(dieIndex); + return entry != null ? entry.getValue() : null; + } + + /** + * Returns the specified DIE record. + * + * @param dieOffset offset of a DIE record + * @return {@link DebugInfoEntry} instance, or null if invalid offset + */ + public DebugInfoEntry getDIEByOffset(long dieOffset) { + DebugInfoEntry die = diesByOffset.get(dieOffset); + if (die != null) { + return die; + } + int dieIndex = getDIEIndex(dieOffset); + return getDIEByOffset(dieOffset, dieIndex); + } + + private DebugInfoEntry getDIEByOffset(long dieOffset, int dieIndex) { + if (dieOffset == -1 || dieIndex == -1) { + return null; + } + + DebugInfoEntry die = diesByOffset.get(dieOffset); + if (die == null) { + try { + debugInfoBR.setPointerIndex(dieOffset); + DWARFCompilationUnit cu = getCompilationUnitForDIE(dieIndex); + if (dieOffset < cu.getFirstDIEOffset() || cu.getEndOffset() < dieOffset) { + throw new RuntimeException(); + } + die = DebugInfoEntry.read(debugInfoBR, cu, dieIndex, attributeFactory); + diesByOffset.put(dieOffset, die); + } + catch (IOException e) { + // shouldn't happen, will fall thru and return null + } + } + return die; + } + + private int getDIEIndex(long dieOffset) { + DebugInfoEntry die = diesByOffset.get(dieOffset); + if (die != null) { + return die.getIndex(); + } + int index = Arrays.binarySearch(dieOffsets, dieOffset); + return index >= 0 ? index : -1; + } + + private DebugInfoEntry getDIEByIndex(int dieIndex) { + long dieOffset = + 0 <= dieIndex && dieIndex < dieOffsets.length ? dieOffsets[dieIndex] : -1; + return getDIEByOffset(dieOffset, dieIndex); + } + + public void dumpDIEs(PrintStream ps) { + for (int dieIndex = 0; dieIndex < dieOffsets.length; dieIndex++) { + DebugInfoEntry die = getDIEByIndex(dieIndex); + ps.append(die.toString()); + } + } + + /** * Returns the {@link DIEAggregate} that contains the specified {@link DebugInfoEntry}. * @@ -644,43 +910,43 @@ public class DWARFProgram implements Closeable { * the aggregate was not found. */ public DIEAggregate getAggregate(DebugInfoEntry die) { - if (die != null && !importOptions.isPreloadAllDIEs() && - die.getCompilationUnit() != currentCompUnit) { - throw new RuntimeException( - "Bad request for getAggregate() when compUnit is not updated"); + DIEAggregate diea = (die != null) ? aggsByOffset.get(die.getOffset()) : null; + if (diea == null && die != null) { + diea = DIEAggregate.createFromHead(die); + aggsByOffset.put(die.getOffset(), diea); } - return (die != null) ? aggregatesByOffset.get(die.getOffset()) : null; + return diea; + } + + private DIEAggregate getAggregateByIndex(int dieIndex) { + DebugInfoEntry die = getDIEByIndex(dieIndex); + return getAggregate(die); } /** * Returns the {@link DIEAggregate} that contains the {@link DebugInfoEntry} specified * by the offset. * - * @param offset offset of a DIE record + * @param dieOffset offset of a DIE record * @return {@link DIEAggregate} that contains the DIE record specified, or null if bad * offset. */ - public DIEAggregate getAggregate(long offset) { - return aggregatesByOffset.get(offset); + public DIEAggregate getAggregate(long dieOffset) { + DIEAggregate diea = aggsByOffset.get(dieOffset); + if (diea != null) { + return diea; + } + DebugInfoEntry die = getDIEByOffset(dieOffset); + return getAggregate(die); } /** - * Returns the list of all currently loaded {@link DIEAggregate}s, which will be either - * just the DIEA of the current CU, or all DIEA if {@link DWARFImportOptions#isPreloadAllDIEs()}. + * Returns iterable that traverses all {@link DIEAggregate}s in the program. * - * @return List of {@link DIEAggregate}. + * @return sequence of {@link DIEAggregate}es */ - public List getAggregates() { - return aggregates; - } - - /** - * Returns the total number of DIE records in the entire program. - * - * @return the total number of DIE records in the entire program. - */ - public int getTotalDIECount() { - return totalDIECount; + public Iterable allAggregates() { + return new DIEAggregateIterator(); } /** @@ -692,42 +958,6 @@ public class DWARFProgram implements Closeable { return totalAggregateCount; } - /** - * Sets the currently active compilation unit. Used when 'paging' through the DIE records - * in a compilation-unit-at-a-time manner, vs the {@link DWARFImportOptions#isPreloadAllDIEs()} - * where all DIE/DIEA records are loaded at once. - * - * @param cu {@link DWARFCompilationUnit} to set as the active element and load it's DIE records. - * @param monitor {@link TaskMonitor} to update with status and check for cancelation. - * @throws CancelledException if user cancels - * @throws IOException if error reading data - * @throws DWARFException if error in DWARF record structure - */ - public void setCurrentCompilationUnit(DWARFCompilationUnit cu, TaskMonitor monitor) - throws CancelledException, IOException, DWARFException { - if (cu != currentCompUnit) { - currentCompUnit = cu; - if (cu != null && !importOptions.isPreloadAllDIEs()) { - clearDIEIndexes(); - cu.readDIEs(currentDIEs, monitor); - rebuildDIEIndexes(); - } - } - } - - public List getCompilationUnits() { - return compUnits; - } - - public DWARFCompilationUnit getCompilationUnitFor(long offset) { - for (DWARFCompilationUnit cu : getCompilationUnits()) { - if (cu.containsOffset(offset)) { - return cu; - } - } - return null; - } - public BinaryReader getDebugLocation() { return debugLocation; } @@ -736,10 +966,6 @@ public class DWARFProgram implements Closeable { return debugRanges; } - public BinaryReader getDebugInfo() { - return debugInfoBR; - } - public BinaryReader getDebugLine() { return debugLineBR; } @@ -772,14 +998,6 @@ public class DWARFProgram implements Closeable { this.attributeFactory = attributeFactory; } - public boolean getFoundCrossCURefs() { - return foundCrossCURefs; - } - - public void setFoundCrossCURefs(boolean b) { - this.foundCrossCURefs = b; - } - public DWARFAttributeSpecification internAttributeSpec(DWARFAttributeSpecification das) { DWARFAttributeSpecification inDAS = attributeSpecIntern.get(das); if (inDAS == null) { @@ -789,53 +1007,6 @@ public class DWARFProgram implements Closeable { return inDAS; } - /** - * @return the entries list - */ - public List getEntries() { - return currentDIEs; - } - - /** - * Returns the count of the DIE records in this compilation unit. - *

- * Only valid if called after {@link #checkPreconditions(TaskMonitor)} - * and before {@link #clearDIEIndexes()}. - * @return number of DIE records in the compunit. - * @throws IOException - * @throws CancelledException - */ - public int getDIECount() throws IOException, CancelledException { - return currentDIEs.size(); - } - - /** - * Releases the memory used by the DIE entries read when invoking - * {@link #checkPreconditions(TaskMonitor)}. - */ - public void clearDIEIndexes() { - offsetMap.clear(); - currentDIEs.clear(); - aggregatesByOffset.clear(); - aggregates.clear(); - typeReferers.clear(); - } - - /** - * Returns the entry with the given byte offset. - *

- * The byte offset corresponds to the byte index - * in the original file where the entry was defined. - *

- * Returns null if the requested entry does not exist. - * - * @param byteOffset the byte offset - * @return the entry with the given byte offset - */ - public DebugInfoEntry getEntryAtByteOffsetUnchecked(long byteOffset) { - return offsetMap.get(Long.valueOf(byteOffset)); - } - private List getTypeReferers(DIEAggregate targetDIEA) { List result = typeReferers.get(targetDIEA.getOffset()); return (result != null) ? result : Collections.emptyList(); @@ -861,192 +1032,6 @@ public class DWARFProgram implements Closeable { return result; } - private void rebuildDIEIndexes() { - buildDIEIndex(); - buildAggregateIndex(); - buildTypeRefIndex(); - } - - private void buildDIEIndex() { - for (DebugInfoEntry die : currentDIEs) { - offsetMap.put(Long.valueOf(die.getOffset()), die); - } - } - - private boolean checkForCrossCURefs(List dies) { - // 'static' set of attribute types that refer from one DIE to another DIE - int[] refAttrs = { DWARFAttribute.DW_AT_type, DWARFAttribute.DW_AT_abstract_origin, - DWARFAttribute.DW_AT_specification }; - for (DebugInfoEntry die : dies) { - DIEAggregate diea = DIEAggregate.createSingle(die); - for (int attr : refAttrs) { - long refdOffset = diea.getUnsignedLong(attr, -1); - if (refdOffset == -1) { - continue; - } - if (!die.getCompilationUnit().containsOffset(refdOffset)) { - return true; - } - } - } - return false; - } - - private void buildAggregateIndex() { - Map offsetMap2Head = buildHeadIndex(); - for (DebugInfoEntry die : currentDIEs) { - if (aggregatesByOffset.containsKey(die.getOffset())) { - continue; - } - DebugInfoEntry head = getHead(die, offsetMap2Head); - DIEAggregate diea = DIEAggregate.createFromHead(head); - aggregates.add(diea); - for (long fragOffset : diea.getOffsets()) { - aggregatesByOffset.put(fragOffset, diea); - } - } - } - - private int countAggregates() { - Map offsetMap2Head = buildHeadIndex(); - Set uniqueHeads = new HashSet<>(); - for (DebugInfoEntry die : currentDIEs) { - DebugInfoEntry head = getHead(die, offsetMap2Head); - uniqueHeads.add(head.getOffset()); - } - return uniqueHeads.size(); - } - - private void buildTypeRefIndex() { - for (DIEAggregate diea : aggregates) { - DIEAggregate typeRef = diea.getTypeRef(); - if (typeRef != null) { - typeReferers.put(typeRef.getOffset(), diea); - } - } - } - - private Map buildHeadIndex() { - Map offsetMap2Head = new HashMap<>(); - for (DebugInfoEntry die : currentDIEs) { - offsetMap2Head.put(Long.valueOf(die.getOffset()), die); - - // If this entry has refs back to a previous DIE, overwrite their - // offset2head mapping so that their offset points to this entry. - // This codeblock is similar to the logic in DIEAggregrate#createFromHead() - DIEAggregate diea = DIEAggregate.createSingle(die); - int[] refAttrs = - { DWARFAttribute.DW_AT_abstract_origin, DWARFAttribute.DW_AT_specification }; - for (int attr : refAttrs) { - long refdOffset = diea.getUnsignedLong(attr, -1); - if (refdOffset == -1) { - continue; - } - - offsetMap2Head.put(refdOffset, die); - } - } - return offsetMap2Head; - } - - /** - * Returns the 'head'-most {@link DebugInfoEntry DIE} instance of the DIEs that - * make up the fragment chain that include the {@code die} parameter. - *

- * Since there can be many-to-one DIE relationships (for instance, many 'spec' DIEs pointing - * to the same decl DIE), the results can be asymmetric, and will return the last - * 'head' that references the non-head DIE. - * - * @param die {@link DebugInfoEntry} record - * @return never null - */ - private DebugInfoEntry getHead(DebugInfoEntry die, Map offsetMap2Head) { - // Loop until the we don't find any more redirections in the offset2HeadMap. - // This loop isn't endless because the lastmost DIE read will always - // point to itself, ending the loop. - while (true) { - DebugInfoEntry tmp = offsetMap2Head.get(die.getOffset()); - if (tmp == die) { - return die; - } - die = tmp; - } - } - - /** - * Iterates over all the DWARF DIE records in the program and checks for some - * pre-known issues, throwing an exception if there is a problem that would - * prevent a successful run. - * - * @param monitor {@link TaskMonitor} to check for cancel and upate with status. - * @throws DWARFException if DWARF structure error. - * @throws CancelledException if user cancels. - * @throws IOException if error reading data. - */ - public void checkPreconditions(TaskMonitor monitor) - throws DWARFPreconditionException, DWARFException, CancelledException, IOException { - monitor.setIndeterminate(false); - monitor.setShowProgressValue(true); - - monitor.setMaximum(getCompilationUnits().size()); - - if (getCompilationUnits().size() > 0 && - getCompilationUnits().get(0).getCompileUnit().hasDWO()) { - // probably won't get anything from the file because its all in an external DWO - Msg.warn(this, - "Unsupported DWARF DWO (external debug file) detected -- unlikely any debug information will be found"); - } - - // This loop: - // 1) preloads the DIEs if that option is set - // 2) checks for cross-cu refs - // 3) sums up the total number of DIE records found and updates prog with total. - boolean preLoad = importOptions.isPreloadAllDIEs(); - totalDIECount = 0; - totalAggregateCount = 0; - clearDIEIndexes(); - for (DWARFCompilationUnit cu : getCompilationUnits()) { - monitor.setMessage("DWARF Checking Preconditions - Compilation Unit #" + - cu.getCompUnitNumber() + "/" + getCompilationUnits().size()); - monitor.setProgress(cu.getCompUnitNumber()); - - cu.readDIEs(currentDIEs, monitor); - - if (totalDIECount > importOptions.getImportLimitDIECount() && !preLoad) { - throw new DWARFPreconditionException( - String.format(program.getName() + " has more DIE records (%d) than limit of %d", - totalDIECount, importOptions.getImportLimitDIECount())); - } - - if (!preLoad) { - foundCrossCURefs |= checkForCrossCURefs(currentDIEs); - totalDIECount += currentDIEs.size(); - totalAggregateCount += countAggregates(); - currentDIEs.clear(); - if (foundCrossCURefs) { - throw new DWARFPreconditionException( - "Found cross-compilation unit references between DIE records, but 'preload' is not turned on"); - } - } - - } - if (preLoad) { - // build DIE indexes once - rebuildDIEIndexes(); - this.totalAggregateCount = aggregates.size(); - this.totalDIECount = currentDIEs.size(); - } - } - - /** - * Sets the maximum length of symbols and datatypes created during import. - * - * @param nameLenCutoff int, should not be more than {@link SymbolUtilities#MAX_SYMBOL_NAME_LENGTH}. - */ - public void setNameLengthCutoff(int nameLenCutoff) { - this.nameLengthCutoffSize = nameLenCutoff; - } - /** * A fixup value that needs to be applied to static addresses of the program. *

@@ -1081,4 +1066,48 @@ public class DWARFProgram implements Closeable { } return functionFixups; } + + //--------------------------------------------------------------------------------------------- + + private class DIEAggregateIterator implements Iterator, Iterable { + + private int index = -1; + + private int findNext() { + int i = index; + if (i < dieOffsets.length) { + for (i = i + 1; i < dieOffsets.length; i++) { + if (!indexHasRef.get(i)) { + return i; + } + } + } + return i; + } + + @Override + public Iterator iterator() { + return this; + } + + @Override + public boolean hasNext() { + if (index == -1) { + index = findNext(); + } + return 0 <= index && index < dieOffsets.length; + } + + @Override + public DIEAggregate next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + int resultIndex = index; + index = findNext(); + return getAggregateByIndex(resultIndex); + } + + } + } 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/dwarf4/next/sectionprovider/ExternalDebugFileSectionProvider.java index 0814c3023d..914e95b09a 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/dwarf4/next/sectionprovider/ExternalDebugFileSectionProvider.java @@ -15,10 +15,9 @@ */ package ghidra.app.util.bin.format.dwarf4.next.sectionprovider; -import java.util.List; - 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.*; @@ -52,7 +51,7 @@ public class ExternalDebugFileSectionProvider extends BaseSectionProvider { if (extDebugInfo == null) { return null; } - Msg.info(ExternalDebugFilesService.class, + Msg.info(ExternalDebugFileSectionProvider.class, "DWARF external debug information found: " + extDebugInfo); ExternalDebugFilesService edfs = DWARFExternalDebugFilesPlugin.getExternalDebugFilesService( @@ -61,7 +60,7 @@ public class ExternalDebugFileSectionProvider extends BaseSectionProvider { if (extDebugFile == null) { return null; } - Msg.info(ExternalDebugFilesService.class, + Msg.info(ExternalDebugFileSectionProvider.class, "DWARF External Debug File: found: " + extDebugFile); FileSystemService fsService = FileSystemService.getInstance(); try ( 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/dwarf4/next/DWARFDataTypeImporterTest.java index c5dcb13598..c33f431603 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/dwarf4/next/DWARFDataTypeImporterTest.java @@ -18,9 +18,8 @@ package ghidra.app.util.bin.format.dwarf4.next; import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*; import static org.junit.Assert.*; -import java.util.*; - import java.io.IOException; +import java.util.*; import org.junit.Test; @@ -29,6 +28,7 @@ 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; import ghidra.util.exception.CancelledException; /** @@ -48,7 +48,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { */ @Test public void testAnonBaseType() throws CancelledException, IOException, DWARFException { - DebugInfoEntry baseDIE = addBaseType(null, 4, DWARFEncoding.DW_ATE_signed, cu); + DebugInfoEntry baseDIE = addBaseType(null, 4, DWARFEncoding.DW_ATE_signed); importAllDataTypes(); @@ -60,8 +60,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testAnonBaseTypeWithTypedef() throws CancelledException, IOException, DWARFException { - DebugInfoEntry baseDIE = addBaseType(null, 4, DWARFEncoding.DW_ATE_signed, cu); - DebugInfoEntry typedefDIE = addTypedef("mytypedef", baseDIE, cu); + DebugInfoEntry baseDIE = addBaseType(null, 4, DWARFEncoding.DW_ATE_signed); + DebugInfoEntry typedefDIE = addTypedef("mytypedef", baseDIE); importAllDataTypes(); @@ -83,7 +83,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testNonStandardBaseTypeName() throws CancelledException, IOException, DWARFException { - DebugInfoEntry baseDIE = addBaseType("blah", 4, DWARFEncoding.DW_ATE_signed, cu); + DebugInfoEntry baseDIE = addBaseType("blah", 4, DWARFEncoding.DW_ATE_signed); importAllDataTypes(); @@ -97,7 +97,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testBaseTypeInt() throws CancelledException, IOException, DWARFException { - addTypedef("mytypedef", addInt(cu), cu); + addTypedef("mytypedef", addInt()); importAllDataTypes(); @@ -113,8 +113,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testBaseTypeUInt() throws CancelledException, IOException, DWARFException { - addTypedef("mytypedef", addBaseType("unsigned int", 4, DWARFEncoding.DW_ATE_unsigned, cu), - cu); + addTypedef("mytypedef", addBaseType("unsigned int", 4, DWARFEncoding.DW_ATE_unsigned)); importAllDataTypes(); @@ -132,8 +131,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { throws CancelledException, IOException, DWARFException { // test when int data type name has a bitsize string (8|16|32|64,etc) - addBaseType("uint32_t", 4, DWARFEncoding.DW_ATE_unsigned, cu); - addBaseType("blah32blah", 4, DWARFEncoding.DW_ATE_signed, cu); + addBaseType("uint32_t", 4, DWARFEncoding.DW_ATE_unsigned); + addBaseType("blah32blah", 4, DWARFEncoding.DW_ATE_signed); importAllDataTypes(); @@ -155,7 +154,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { throws CancelledException, IOException, DWARFException { // test when int data type name has a bitsize string that doesn't make sense - addBaseType("uint32_t", 2 /* not 4 */, DWARFEncoding.DW_ATE_unsigned, cu); + addBaseType("uint32_t", 2 /* not 4 */, DWARFEncoding.DW_ATE_unsigned); importAllDataTypes(); @@ -169,12 +168,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @SuppressWarnings("unused") public void testStructType() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - DebugInfoEntry structF1DIE = newMember(structDIE, "f1", intDIE, 0).create(cu); - DebugInfoEntry structF2DIE = newMember(structDIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + DebugInfoEntry structF1DIE = newMember(structDIE, "f1", intDIE, 0).create(); + DebugInfoEntry structF2DIE = newMember(structDIE, "f2", floatDIE, 10).create(); importAllDataTypes(); @@ -184,13 +183,13 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructDecl() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry declDIE = newDeclStruct("mystruct").create(cu); - DebugInfoEntry structDIE = newSpecStruct(declDIE, 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry declDIE = newDeclStruct("mystruct").create(); + DebugInfoEntry structDIE = newSpecStruct(declDIE, 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", floatDIE, 10).create(); importAllDataTypes(); @@ -210,15 +209,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructDanglingDecl() throws CancelledException, IOException, DWARFException { // CU1 - newDeclStruct("mystruct").create(cu); + newDeclStruct("mystruct").create(); + + addCompUnit(); // CU2 - DebugInfoEntry intDIE = addInt(cu2); - DebugInfoEntry floatDIE = addFloat(cu2); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu2); - newMember(structDIE, "f1", intDIE, 0).create(cu2); - newMember(structDIE, "f2", floatDIE, 10).create(cu2); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", floatDIE, 10).create(); importAllDataTypes(); @@ -243,20 +244,22 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructDeclThenGrow() throws CancelledException, IOException, DWARFException { // CU1 - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry struct1Decl = newDeclStruct("struct1").create(cu); - DebugInfoEntry struct2 = newStruct("struct2", 20).create(cu); - newMember(struct2, "struct1field", struct1Decl, 0).create(cu); - newMember(struct2, "guardfield", intDIE, 16).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry struct1Decl = newDeclStruct("struct1").create(); + DebugInfoEntry struct2 = newStruct("struct2", 20).create(); + newMember(struct2, "struct1field", struct1Decl, 0).create(); + newMember(struct2, "guardfield", intDIE, 16).create(); + + addCompUnit(); // CU2 - DebugInfoEntry int2DIE = addInt(cu2); + DebugInfoEntry int2DIE = addInt(); - DebugInfoEntry struct1Impl = newStruct("struct1", 16).create(cu2); - newMember(struct1Impl, "f1", int2DIE, 0).create(cu2); - newMember(struct1Impl, "f2", int2DIE, 4).create(cu2); - newMember(struct1Impl, "f3", int2DIE, 8).create(cu2); - newMember(struct1Impl, "f4", int2DIE, 12).create(cu2); + DebugInfoEntry struct1Impl = newStruct("struct1", 16).create(); + newMember(struct1Impl, "f1", int2DIE, 0).create(); + newMember(struct1Impl, "f2", int2DIE, 4).create(); + newMember(struct1Impl, "f3", int2DIE, 8).create(); + newMember(struct1Impl, "f4", int2DIE, 12).create(); importAllDataTypes(); @@ -273,11 +276,13 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // CU1 // struct structA; // fwd decl // struct structB { structA struct1field; int guardfield; } - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry structADecl = newDeclStruct("structA").create(cu); - DebugInfoEntry structB = newStruct("structB", 20).create(cu); - newMember(structB, "structAfield", structADecl, 0).create(cu); - newMember(structB, "guardfield", intDIE, 16).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry structADecl = newDeclStruct("structA").create(); + DebugInfoEntry structB = newStruct("structB", 20).create(); + newMember(structB, "structAfield", structADecl, 0).create(); + newMember(structB, "guardfield", intDIE, 16).create(); + + addCompUnit(); // CU2 // struct structB { structA struct1field; int guardfield; } @@ -287,16 +292,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // The order of the DIE records is important. The structure (structB) // containing the problematic structA needs to be hit first so we can // test that cached types are handled correctly. - DebugInfoEntry int2DIE = addInt(cu2); - DebugInfoEntry structB_cu2 = newStruct("structB", 20).create(cu2); - newMember(structB_cu2, "structAfield", getForwardOffset(cu2, 2), 0).create(cu2); - newMember(structB_cu2, "guardfield", int2DIE, 16).create(cu2); + DebugInfoEntry int2DIE = addInt(); + DebugInfoEntry structB_cu2 = newStruct("structB", 20).create(); + long structA_cu2_offset = dwarfProg.getRelativeDIEOffset(2); + newMember(structB_cu2, "structAfield", structA_cu2_offset, 0).create(); + newMember(structB_cu2, "guardfield", int2DIE, 16).create(); - DebugInfoEntry structA_cu2 = newStruct("structA", 16).create(cu2); - newMember(structA_cu2, "f1", int2DIE, 0).create(cu2); - newMember(structA_cu2, "f2", int2DIE, 4).create(cu2); - newMember(structA_cu2, "f3", int2DIE, 8).create(cu2); - newMember(structA_cu2, "f4", int2DIE, 12).create(cu2); + DebugInfoEntry structA_cu2 = newStruct("structA", 16).create(); + newMember(structA_cu2, "f1", int2DIE, 0).create(); + newMember(structA_cu2, "f2", int2DIE, 4).create(); + newMember(structA_cu2, "f3", int2DIE, 8).create(); + newMember(structA_cu2, "f4", int2DIE, 12).create(); importAllDataTypes(); @@ -313,20 +319,22 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructDup() throws CancelledException, IOException, DWARFException { // CU1 - DebugInfoEntry intDIE1 = addInt(cu); - DebugInfoEntry floatDIE1 = addFloat(cu); + DebugInfoEntry intDIE1 = addInt(); + DebugInfoEntry floatDIE1 = addFloat(); - DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(cu); - newMember(structDIE1, "f1", intDIE1, 0).create(cu); - newMember(structDIE1, "f2", floatDIE1, 10).create(cu); + DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(); + newMember(structDIE1, "f1", intDIE1, 0).create(); + newMember(structDIE1, "f2", floatDIE1, 10).create(); + + addCompUnit(); // CU2 - DebugInfoEntry intDIE2 = addInt(cu2); - DebugInfoEntry floatDIE2 = addFloat(cu2); + DebugInfoEntry intDIE2 = addInt(); + DebugInfoEntry floatDIE2 = addFloat(); - DebugInfoEntry structDIE2 = newStruct("mystruct", 100).create(cu2); - newMember(structDIE2, "f1", intDIE2, 0).create(cu2); - newMember(structDIE2, "f2", floatDIE2, 10).create(cu2); + DebugInfoEntry structDIE2 = newStruct("mystruct", 100).create(); + newMember(structDIE2, "f1", intDIE2, 0).create(); + newMember(structDIE2, "f2", floatDIE2, 10).create(); importAllDataTypes(); @@ -347,21 +355,23 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructConflictDup() throws CancelledException, IOException, DWARFException { // CU1 - DebugInfoEntry intDIE1 = addInt(cu); - DebugInfoEntry floatDIE1 = addFloat(cu); + DebugInfoEntry intDIE1 = addInt(); + DebugInfoEntry floatDIE1 = addFloat(); - DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(cu); - newMember(structDIE1, "f1", intDIE1, 0).create(cu); - newMember(structDIE1, "f2", floatDIE1, 10).create(cu); + DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(); + newMember(structDIE1, "f1", intDIE1, 0).create(); + newMember(structDIE1, "f2", floatDIE1, 10).create(); + + addCompUnit(); // CU2 - DebugInfoEntry intDIE2 = addInt(cu2); - DebugInfoEntry floatDIE2 = addFloat(cu2); + DebugInfoEntry intDIE2 = addInt(); + DebugInfoEntry floatDIE2 = addFloat(); // incompatible field datatypes when compared to previous def (int f1, float f2 vs float f1, int f2) - DebugInfoEntry structDIE2 = newStruct("mystruct", 50).create(cu2); - newMember(structDIE2, "f1", floatDIE2, 0).create(cu2); - newMember(structDIE2, "f2", intDIE2, 10).create(cu2); + DebugInfoEntry structDIE2 = newStruct("mystruct", 50).create(); + newMember(structDIE2, "f1", floatDIE2, 0).create(); + newMember(structDIE2, "f2", intDIE2, 10).create(); importAllDataTypes(); @@ -375,20 +385,22 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructDupPartial() throws CancelledException, IOException, DWARFException { - DebugInfoEntry floatDIE1 = addFloat(cu); + DebugInfoEntry floatDIE1 = addFloat(); // this struct has only 1 field defined - DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(cu); - // missing field def: newMember(structDIE1, "f1", intDIE1, 0).create(cu); - newMember(structDIE1, "f2", floatDIE1, 10).create(cu); + DebugInfoEntry structDIE1 = newStruct("mystruct", 100).create(); + // missing field def: newMember(structDIE1, "f1", intDIE1, 0).create(); + newMember(structDIE1, "f2", floatDIE1, 10).create(); - DebugInfoEntry intDIE2 = addInt(cu2); - DebugInfoEntry floatDIE2 = addFloat(cu2); + addCompUnit(); + + DebugInfoEntry intDIE2 = addInt(); + DebugInfoEntry floatDIE2 = addFloat(); // this struct has both fields defined - DebugInfoEntry structDIE2 = newStruct("mystruct", 100).create(cu2); - newMember(structDIE2, "f1", intDIE2, 0).create(cu2); - newMember(structDIE2, "f2", floatDIE2, 10).create(cu2); + DebugInfoEntry structDIE2 = newStruct("mystruct", 100).create(); + newMember(structDIE2, "f1", intDIE2, 0).create(); + newMember(structDIE2, "f2", floatDIE2, 10).create(); importAllDataTypes(); @@ -404,15 +416,15 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructWithPtr() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); - DebugInfoEntry struct2DIE = newStruct("mystruct2", 10).create(cu); - newMember(struct2DIE, "ptr_to_struct1", addPtr(struct1DIE, cu), 0).create(cu); + DebugInfoEntry struct2DIE = newStruct("mystruct2", 10).create(); + newMember(struct2DIE, "ptr_to_struct1", addPtr(struct1DIE), 0).create(); importAllDataTypes(); @@ -428,25 +440,25 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructWithLoop() throws CancelledException, IOException, DWARFException { // base types - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- // decl mystruct - DebugInfoEntry struct1DeclDIE = newDeclStruct("mystruct").create(cu); - DebugInfoEntry struct1PtrDIE = addPtr(struct1DeclDIE, cu); + DebugInfoEntry struct1DeclDIE = newDeclStruct("mystruct").create(); + DebugInfoEntry struct1PtrDIE = addPtr(struct1DeclDIE); //----------------------- // mystruct2 { ptr_to_struct1 : struct1PtrDIE } - DebugInfoEntry struct2DIE = newStruct("mystruct2", 10).create(cu); + DebugInfoEntry struct2DIE = newStruct("mystruct2", 10).create(); DebugInfoEntry struct2F1DIE = - newMember(struct2DIE, "ptr_to_struct1", struct1PtrDIE, 0).create(cu); - DebugInfoEntry struct2PtrDIE = addPtr(struct2DIE, cu); + newMember(struct2DIE, "ptr_to_struct1", struct1PtrDIE, 0).create(); + DebugInfoEntry struct2PtrDIE = addPtr(struct2DIE); //-------------------- // spec mystruct { f1: intDIE; f2_ptr_to_struct2: struct2PtrDIE } DebugInfoEntry struct1DIE = - newSpecStruct(struct1DeclDIE, 100).addString(DW_AT_name, "mystruct").create(cu); - DebugInfoEntry structF1DIE = newMember(struct1DIE, "f1", intDIE, 0).create(cu); + newSpecStruct(struct1DeclDIE, 100).addString(DW_AT_name, "mystruct").create(); + DebugInfoEntry structF1DIE = newMember(struct1DIE, "f1", intDIE, 0).create(); DebugInfoEntry structF2DIE = - newMember(struct1DIE, "f2_ptr_to_struct2", struct2PtrDIE, 10).create(cu); + newMember(struct1DIE, "f2_ptr_to_struct2", struct2PtrDIE, 10).create(); //---------------------- importAllDataTypes(); @@ -465,15 +477,16 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @SuppressWarnings("unused") public void testStructWithBadSelfLoop() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry struct1DeclDIE = newDeclStruct("mystruct").create(cu); + DebugInfoEntry struct1DeclDIE = newDeclStruct("mystruct").create(); //----------------------- DebugInfoEntry struct1DIE = - newSpecStruct(struct1DeclDIE, 100).addString(DW_AT_name, "mystruct").create(cu); - DebugInfoEntry structF1DIE = newMember(struct1DIE, "f1", intDIE, 0).create(cu); - DebugInfoEntry structF2DIE = newMember(struct1DIE, "f2_struct1", struct1DIE, 10).create(cu); + newSpecStruct(struct1DeclDIE, 100).addString(DW_AT_name, "mystruct").create(); + DebugInfoEntry structF1DIE = newMember(struct1DIE, "f1", intDIE, 0).create(); + DebugInfoEntry structF2DIE = + newMember(struct1DIE, "f2_struct1", struct1DIE, 10).create(); //---------------------- importAllDataTypes(); @@ -486,24 +499,32 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @SuppressWarnings("unused") public void testStructConflictingMemberOffsets() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry declDIE = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DW_AT_name, - "mystruct").addBoolean(DW_AT_declaration, true).create(cu); + DebugInfoEntry declDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_structure_type) // + .addString(DW_AT_name, "mystruct") + .addBoolean(DW_AT_declaration, true) + .create(); - DebugInfoEntry structDIE = - new DIECreator(DWARFTag.DW_TAG_structure_type).addRef(DW_AT_specification, - declDIE).addInt(DW_AT_byte_size, 100).create(cu); + DebugInfoEntry structDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_structure_type) // + .addRef(DW_AT_specification, declDIE) + .addInt(DW_AT_byte_size, 100) + .create(); - DebugInfoEntry structF1DIE = - new DIECreator(DWARFTag.DW_TAG_member).addString(DW_AT_name, "f1").addRef(DW_AT_type, - intDIE).addInt(DW_AT_data_member_location, 10).setParent(structDIE).create(cu); + DebugInfoEntry structF1DIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_member) // + .addString(DW_AT_name, "f1") + .addRef(DW_AT_type, intDIE) + .addInt(DW_AT_data_member_location, 10) + .setParent(structDIE) + .create(); - DebugInfoEntry structF2DIE = - new DIECreator(DWARFTag.DW_TAG_member).addString(DW_AT_name, "f2").addRef(DW_AT_type, - floatDIE).addInt(DW_AT_data_member_location, 10).setParent(structDIE).create(cu); + DebugInfoEntry structF2DIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_member) // + .addString(DW_AT_name, "f2") + .addRef(DW_AT_type, floatDIE) + .addInt(DW_AT_data_member_location, 10) + .setParent(structDIE) + .create(); importAllDataTypes(); @@ -516,24 +537,32 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @SuppressWarnings("unused") public void testStructConflictingMemberNames() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry declDIE = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DW_AT_name, - "mystruct").addBoolean(DW_AT_declaration, true).create(cu); + DebugInfoEntry declDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_structure_type) // + .addString(DW_AT_name, "mystruct") + .addBoolean(DW_AT_declaration, true) + .create(); - DebugInfoEntry structDIE = - new DIECreator(DWARFTag.DW_TAG_structure_type).addRef(DW_AT_specification, - declDIE).addInt(DW_AT_byte_size, 100).create(cu); + DebugInfoEntry structDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_structure_type) // + .addRef(DW_AT_specification, declDIE) + .addInt(DW_AT_byte_size, 100) + .create(); - DebugInfoEntry structF1DIE = - new DIECreator(DWARFTag.DW_TAG_member).addString(DW_AT_name, "f1").addRef(DW_AT_type, - intDIE).addInt(DW_AT_data_member_location, 0).setParent(structDIE).create(cu); + DebugInfoEntry structF1DIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_member) // + .addString(DW_AT_name, "f1") + .addRef(DW_AT_type, intDIE) + .addInt(DW_AT_data_member_location, 0) + .setParent(structDIE) + .create(); - DebugInfoEntry structF2DIE = - new DIECreator(DWARFTag.DW_TAG_member).addString(DW_AT_name, "f1").addRef(DW_AT_type, - floatDIE).addInt(DW_AT_data_member_location, 10).setParent(structDIE).create(cu); + DebugInfoEntry structF2DIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_member) // + .addString(DW_AT_name, "f1") + .addRef(DW_AT_type, floatDIE) + .addInt(DW_AT_data_member_location, 10) + .setParent(structDIE) + .create(); importAllDataTypes(); @@ -561,12 +590,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructMemberWithSameNameAsStruct() throws CancelledException, IOException, DWARFException { - addInt(cu); - addFloat(cu); + addInt(); + addFloat(); - DebugInfoEntry struct1aDIE = newStruct("mystruct", 1).create(cu); - DebugInfoEntry struct1bDIE = newStruct("mystruct", 4).create(cu); - newMember(struct1bDIE, "f1", struct1aDIE, 0).create(cu); + DebugInfoEntry struct1aDIE = newStruct("mystruct", 1).create(); + DebugInfoEntry struct1bDIE = newStruct("mystruct", 4).create(); + newMember(struct1bDIE, "f1", struct1aDIE, 0).create(); importAllDataTypes(); @@ -593,12 +622,13 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructMemberWithSameNameAsStruct2() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - DebugInfoEntry struct1aDIE = newStruct("mystruct", 4).create(cu); - DebugInfoEntry struct1bDIE = newStruct("mystruct", 4).create(cu); - DebugInfoEntry struct1bF1DIE = newMember(struct1bDIE, "f1", struct1aDIE, 0).create(cu); + DebugInfoEntry struct1aDIE = newStruct("mystruct", 4).create(); + DebugInfoEntry struct1bDIE = newStruct("mystruct", 4).create(); + DebugInfoEntry struct1bF1DIE = + newMember(struct1bDIE, "f1", struct1aDIE, 0).create(); importAllDataTypes(); @@ -640,14 +670,14 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructInherit() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); //----------------------- - DebugInfoEntry baseDIE = newStruct("base", 10).create(cu); - newMember(baseDIE, "basef1", intDIE, 0).create(cu); + DebugInfoEntry baseDIE = newStruct("base", 10).create(); + newMember(baseDIE, "basef1", intDIE, 0).create(); //-------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newInherit(struct1DIE, baseDIE, 0).create(cu); - newMember(struct1DIE, "f1", intDIE, 50).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newInherit(struct1DIE, baseDIE, 0).create(); + newMember(struct1DIE, "f1", intDIE, 50).create(); //-------------------- importAllDataTypes(); @@ -666,14 +696,14 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // and the outer struct has fields that are defined to be within the footprint // of the embedded struct's trailing padding. - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); //----------------------- - DebugInfoEntry baseDIE = newStruct("base", 20).create(cu); - newMember(baseDIE, "basef1", intDIE, 0).create(cu); + DebugInfoEntry baseDIE = newStruct("base", 20).create(); + newMember(baseDIE, "basef1", intDIE, 0).create(); //-------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newInherit(struct1DIE, baseDIE, 0).create(cu); - newMember(struct1DIE, "f1", intDIE, 4).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newInherit(struct1DIE, baseDIE, 0).create(); + newMember(struct1DIE, "f1", intDIE, 4).create(); //-------------------- importAllDataTypes(); @@ -700,16 +730,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructNested() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); //-------------------- - DebugInfoEntry struct2DIE = newStruct("mystruct2", 10).setParent(struct1DIE).create(cu); - newMember(struct2DIE, "blah1", intDIE, 0).create(cu); + DebugInfoEntry struct2DIE = + newStruct("mystruct2", 10).setParent(struct1DIE).create(); + newMember(struct2DIE, "blah1", intDIE, 0).create(); //---------------------- importAllDataTypes(); @@ -725,17 +756,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructAnonNestedStructFurball() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - DebugInfoEntry anonStructDIE = newStruct(null, 10).setParent(struct1DIE).create(cu); - newMember(anonStructDIE, "blah1", intDIE, 0).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); - newMember(struct1DIE, "f3", anonStructDIE, 14).create(cu); - newMember(struct1DIE, "f4", anonStructDIE, 54).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + DebugInfoEntry anonStructDIE = newStruct(null, 10).setParent(struct1DIE).create(); + newMember(anonStructDIE, "blah1", intDIE, 0).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + newMember(struct1DIE, "f3", anonStructDIE, 14).create(); + newMember(struct1DIE, "f4", anonStructDIE, 54).create(); //---------------------- importAllDataTypes(); @@ -753,18 +784,18 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // tests that the dwarf context / location where an anon struct is defined // does not affect where the Ghidra data type is created (in the parent struct's // category path) - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry anonStructDIE = newStruct(null, 10).create(cu); - newMember(anonStructDIE, "blah1", intDIE, 0).create(cu); + DebugInfoEntry anonStructDIE = newStruct(null, 10).create(); + newMember(anonStructDIE, "blah1", intDIE, 0).create(); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); - newMember(struct1DIE, "f3", anonStructDIE, 14).create(cu); - newMember(struct1DIE, "f4", anonStructDIE, 54).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + newMember(struct1DIE, "f3", anonStructDIE, 14).create(); + newMember(struct1DIE, "f4", anonStructDIE, 54).create(); //---------------------- importAllDataTypes(); @@ -783,11 +814,11 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // tests that an anon struct with a typedef to it gets the name of the typedef // and that the typedef itself isn't created - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry anonStructDIE = newStruct(null, 10).create(cu); - newMember(anonStructDIE, "f1", intDIE, 0).create(cu); - newMember(anonStructDIE, "f2", intDIE, 0).create(cu); - addTypedef("mystruct", anonStructDIE, cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry anonStructDIE = newStruct(null, 10).create(); + newMember(anonStructDIE, "f1", intDIE, 0).create(); + newMember(anonStructDIE, "f2", intDIE, 0).create(); + addTypedef("mystruct", anonStructDIE); //---------------------- @@ -801,12 +832,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructFlexarray() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArray(cu, intDIE, false, -1); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArray(intDIE, false, -1); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "flexarray", arrayDIE, 100).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "flexarray", arrayDIE, 100).create(); importAllDataTypes(); @@ -828,12 +859,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructFlexarray_noValue() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArray(cu, intDIE, true, -1); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArray(intDIE, true, -1); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "flexarray", arrayDIE, 100).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "flexarray", arrayDIE, 100).create(); importAllDataTypes(); @@ -850,12 +881,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructFlexarray_0count() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArrayUsingCount(cu, intDIE, 0); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArrayUsingCount(intDIE, 0); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "flexarray", arrayDIE, 100).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "flexarray", arrayDIE, 100).create(); importAllDataTypes(); @@ -867,12 +898,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructInteriorFlexarray() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArray(cu, intDIE, false, -1); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArray(intDIE, false, -1); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "flexarray", arrayDIE, 100).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "flexarray", arrayDIE, 100).create(); importAllDataTypes(); @@ -892,12 +923,12 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructZeroLenField() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - DebugInfoEntry structDIE = newStruct("mystruct", 10).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "f2", emptyStructDIE, 4).create(cu); + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + DebugInfoEntry structDIE = newStruct("mystruct", 10).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", emptyStructDIE, 4).create(); importAllDataTypes(); @@ -917,14 +948,14 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStruct2ZeroLenField() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - DebugInfoEntry structDIE = newStruct("mystruct", 10).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "f2", emptyStructDIE, 4).create(cu); - newMember(structDIE, "f3", emptyStructDIE, 4).create(cu); - newMember(structDIE, "f4", intDIE, 4).create(cu); + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + DebugInfoEntry structDIE = newStruct("mystruct", 10).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", emptyStructDIE, 4).create(); + newMember(structDIE, "f3", emptyStructDIE, 4).create(); + newMember(structDIE, "f4", intDIE, 4).create(); importAllDataTypes(); @@ -949,22 +980,22 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructBitfields() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu); - newMember(structDIE, "f1", intDIE, 0).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); newMember(structDIE, "bitfield1_3", intDIE, 4) // .addInt(DW_AT_bit_size, 3) // .addInt(DW_AT_bit_offset, 29) // - .create(cu); + .create(); newMember(structDIE, "bitfield2_2", intDIE, 4) // .addInt(DW_AT_bit_size, 2) // .addInt(DW_AT_bit_offset, 27) // - .create(cu); + .create(); newMember(structDIE, "bitfield3_9", intDIE, 4) // .addInt(DW_AT_bit_size, 9) // .addInt(DW_AT_bit_offset, 18) // - .create(cu); + .create(); importAllDataTypes(); @@ -991,17 +1022,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructNamespaceReservedChar_Colon() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct::with::colons", 100).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct::with::colons", 100).create(); DebugInfoEntry nestedStructDIE = - newStruct("nested_struct", 10).setParent(struct1DIE).create(cu); - newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); - newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu); + newStruct("nested_struct", 10).setParent(struct1DIE).create(); + newMember(nestedStructDIE, "blah1", intDIE, 0).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + newMember(struct1DIE, "f3", nestedStructDIE, 20).create(); //---------------------- importAllDataTypes(); @@ -1015,17 +1046,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructNamespaceReservedChar_FwdSlash() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(); DebugInfoEntry nestedStructDIE = - newStruct("nested_struct", 10).setParent(struct1DIE).create(cu); - newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); - newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu); + newStruct("nested_struct", 10).setParent(struct1DIE).create(); + newMember(nestedStructDIE, "blah1", intDIE, 0).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + newMember(struct1DIE, "f3", nestedStructDIE, 20).create(); //---------------------- importAllDataTypes(); @@ -1039,13 +1070,13 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testStructNamespaceReservedChar_Spaces() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); //----------------------- - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); //---------------------- importAllDataTypes(); @@ -1058,23 +1089,25 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testUnion() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry doubleDIE = addDouble(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry doubleDIE = addDouble(); - DebugInfoEntry unionDeclDIE = - new DIECreator(DWARFTag.DW_TAG_union_type).addString(DW_AT_name, "myunion").addBoolean( - DW_AT_declaration, true).create(cu); + DebugInfoEntry unionDeclDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_union_type) // + .addString(DW_AT_name, "myunion") + .addBoolean(DW_AT_declaration, true) + .create(); //----------------------- int UNION_STATIC_SIZE = 10; - DebugInfoEntry unionDIE = - new DIECreator(DWARFTag.DW_TAG_union_type).addRef(DW_AT_specification, - unionDeclDIE).addInt(DW_AT_byte_size, UNION_STATIC_SIZE).create(cu); + DebugInfoEntry unionDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_union_type) // + .addRef(DW_AT_specification, unionDeclDIE) + .addInt(DW_AT_byte_size, UNION_STATIC_SIZE) + .create(); - newMember(unionDIE, "f1", intDIE, -1).create(cu); - newMember(unionDIE, "f2_self", unionDIE, -1).create(cu); - newMember(unionDIE, "f3", doubleDIE, -1).create(cu); + newMember(unionDIE, "f1", intDIE, -1).create(); + newMember(unionDIE, "f2_self", unionDIE, -1).create(); + newMember(unionDIE, "f3", doubleDIE, -1).create(); //---------------------- @@ -1090,17 +1123,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testUnionFlexArray() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArray(cu, intDIE, false, -1); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArray(intDIE, false, -1); int UNION_STATIC_SIZE = 10; - DebugInfoEntry unionDIE = new DIECreator(DWARFTag.DW_TAG_union_type) // - .addString(DW_AT_name, "myunion") // - .addInt(DW_AT_byte_size, UNION_STATIC_SIZE) // - .create(cu); + DebugInfoEntry unionDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_union_type) // + .addString(DW_AT_name, "myunion") + .addInt(DW_AT_byte_size, UNION_STATIC_SIZE) + .create(); - newMember(unionDIE, "f1", intDIE, -1).create(cu); - newMember(unionDIE, "flexarray", arrayDIE, -1).create(cu); + newMember(unionDIE, "f1", intDIE, -1).create(); + newMember(unionDIE, "flexarray", arrayDIE, -1).create(); //---------------------- @@ -1123,25 +1156,29 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { */ @Test public void testConstElide() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); DebugInfoEntry constDIE = - new DIECreator(DWARFTag.DW_TAG_const_type).addRef(DW_AT_type, intDIE).create(cu); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_const_type).addRef(DW_AT_type, intDIE) + .create(); DebugInfoEntry volatileDIE = - new DIECreator(DWARFTag.DW_TAG_volatile_type).addRef(DW_AT_type, intDIE).create(cu); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_volatile_type).addRef(DW_AT_type, intDIE) + .create(); DebugInfoEntry volatileconstDIE = - new DIECreator(DWARFTag.DW_TAG_volatile_type).addRef(DW_AT_type, constDIE).create(cu); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_volatile_type).addRef(DW_AT_type, constDIE) + .create(); - DebugInfoEntry structDIE = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DW_AT_name, "mystruct").addInt( - DW_AT_byte_size, 100).create(cu); + DebugInfoEntry structDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_structure_type) // + .addString(DW_AT_name, "mystruct") + .addInt(DW_AT_byte_size, 100) + .create(); - newMember(structDIE, "f1", intDIE, 0).create(cu); - newMember(structDIE, "f2", constDIE, 10).create(cu); - newMember(structDIE, "f3", volatileDIE, 20).create(cu); - newMember(structDIE, "f4", volatileconstDIE, 40).create(cu); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", constDIE, 10).create(); + newMember(structDIE, "f3", volatileDIE, 20).create(); + newMember(structDIE, "f4", volatileconstDIE, 40).create(); importAllDataTypes(); @@ -1171,8 +1208,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { */ @Test public void testArray() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArray(cu, intDIE, false, 10); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArray(intDIE, false, 10); importAllDataTypes(); @@ -1186,8 +1223,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { */ @Test public void testArrayWithCountAttr() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArrayUsingCount(cu, intDIE, 10); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArrayUsingCount(intDIE, 10); importAllDataTypes(); @@ -1201,8 +1238,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { throws CancelledException, IOException, DWARFException { // Tests that an array with non-zero elements, but with zero-len data type // becomes a zero-element array. (yuck) - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - DebugInfoEntry arrayDIE = newArrayUsingCount(cu, emptyStructDIE, 10); + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + DebugInfoEntry arrayDIE = newArrayUsingCount(emptyStructDIE, 10); importAllDataTypes(); @@ -1216,8 +1253,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testArrayWithZeroElements() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry arrayDIE = newArrayUsingCount(cu, intDIE, 0); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry arrayDIE = newArrayUsingCount(intDIE, 0); importAllDataTypes(); @@ -1260,9 +1297,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testExtremeNames() throws CancelledException, DWARFException, IOException { - int nameLenCutoff = 50; - dwarfProg.getImportOptions().setNameLengthCutoff(nameLenCutoff); - dwarfProg.setNameLengthCutoff(nameLenCutoff); + int nameLenCutoff = SymbolUtilities.MAX_SYMBOL_NAME_LENGTH; String structLongName = longName("mystruct_", "", 1000); String templateLongName = longName("mystruct_", "", 1000); @@ -1273,15 +1308,15 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { String exactTemplateName2 = longName("", "template", nameLenCutoff - "template".length() + 1); - DebugInfoEntry structDIE = newStruct(structLongName, 0).create(cu); - DebugInfoEntry exactDIE = newStruct(exactName, 0).create(cu); - DebugInfoEntry exactTemplateDIE = newStruct(exactTemplateName, 0).create(cu); - DebugInfoEntry exactTemplateDIE2 = newStruct(exactTemplateName2, 0).create(cu); - DebugInfoEntry templateDIE = newStruct(templateLongName, 0).create(cu); + DebugInfoEntry structDIE = newStruct(structLongName, 0).create(); + DebugInfoEntry exactDIE = newStruct(exactName, 0).create(); + DebugInfoEntry exactTemplateDIE = newStruct(exactTemplateName, 0).create(); + DebugInfoEntry exactTemplateDIE2 = newStruct(exactTemplateName2, 0).create(); + DebugInfoEntry templateDIE = newStruct(templateLongName, 0).create(); DebugInfoEntry struct3DIE = - newStruct(substructLongName, 0).setParent(templateDIE).create(cu); + newStruct(substructLongName, 0).setParent(templateDIE).create(); - checkPreconditions(); + buildMockDIEIndexes(); DWARFNameInfo sDNI = dwarfProg.getName(getAggregate(structDIE)); DWARFNameInfo exactDNI = dwarfProg.getName(getAggregate(exactDIE)); @@ -1325,12 +1360,15 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testHostilePtrLoop() throws CancelledException, IOException, DWARFException { + addCompUnit(); + // hack to make a forward reference to a DIE that hasn't been created yet. // This creates a hostile loop in the data type references. - DebugInfoEntry constDIE = new DIECreator(DWARFTag.DW_TAG_const_type).addRef(DW_AT_type, - getForwardOffset(cu, 1)).create(cu); - DebugInfoEntry ptrDIE = - new DIECreator(DWARFTag.DW_TAG_pointer_type).addRef(DW_AT_type, constDIE).create(cu); + long fwdDIE = dwarfProg.getRelativeDIEOffset(1); + DebugInfoEntry constDIE = + new DIECreator(dwarfProg, DWARFTag.DW_TAG_const_type).addRef(DW_AT_type, fwdDIE) + .create(); + DebugInfoEntry ptrDIE = addPtr(constDIE); importAllDataTypes(); @@ -1367,17 +1405,19 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { public void testStructDeclViaPtr() throws CancelledException, IOException, DWARFException { // CU1 - addFwdPtr(cu, 1); // points to the DIE created in the next line even though it doesn't exist yet - newDeclStruct("mystruct").create(cu); + addFwdPtr(1); // points to the DIE created in the next line even though it doesn't exist yet + newDeclStruct("mystruct").create(); + + addCompUnit(); // CU2 - DebugInfoEntry intDIE = addInt(cu2); - DebugInfoEntry floatDIE = addFloat(cu2); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); - addFwdPtr(cu2, 1); // fwd points to structDIE even though it doesn't exist yet - DebugInfoEntry structDIE = newStruct("mystruct", 100).create(cu2); - newMember(structDIE, "f1", intDIE, 0).create(cu2); - newMember(structDIE, "f2", floatDIE, 10).create(cu2); + addFwdPtr(1); // fwd points to structDIE even though it doesn't exist yet + DebugInfoEntry structDIE = newStruct("mystruct", 100).create(); + newMember(structDIE, "f1", intDIE, 0).create(); + newMember(structDIE, "f2", floatDIE, 10).create(); importAllDataTypes(); @@ -1397,13 +1437,17 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { throws CancelledException, IOException, DWARFException { // CU1 // this struct has a field with a typedef to a basetype int - DebugInfoEntry structDIE = newStruct("mystruct", 10).create(cu); - newMember(structDIE, "f1", addTypedef("intX_t", addInt(cu), cu), 0).create(cu); + DebugInfoEntry typedefDIE = addTypedef("intX_t", addInt()); + DebugInfoEntry structDIE = newStruct("mystruct", 10).create(); + newMember(structDIE, "f1", typedefDIE, 0).create(); + + addCompUnit(); // CU2 // this struct has a field with a basetype int - DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(cu2); - newMember(structDIE_CU2, "f1", addInt(cu2), 0).create(cu2); + DebugInfoEntry cu2IntDIE = addInt(); + DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(); + newMember(structDIE_CU2, "f1", cu2IntDIE, 0).create(); importAllDataTypes(); @@ -1416,15 +1460,23 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testAsymetricEquivTypedefedBaseTypes_rev() throws CancelledException, IOException, DWARFException { + // CU1 + DebugInfoEntry cu1IntDIE = addInt(); + // this struct has a field with a basetype int - DebugInfoEntry structDIE = newStruct("mystruct", 10).create(cu); - newMember(structDIE, "f1", addInt(cu), 0).create(cu); + DebugInfoEntry structDIE = newStruct("mystruct", 10).create(); + newMember(structDIE, "f1", cu1IntDIE, 0).create(); + + addCompUnit(); // CU2 + DebugInfoEntry cu2IntDIE = addInt(); + DebugInfoEntry cu2TypedefDIE = addTypedef("intX_t", cu2IntDIE); + // this struct has a field with a typedef of a basetype int - DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(cu2); - newMember(structDIE_CU2, "f1", addTypedef("intX_t", addInt(cu2), cu2), 0).create(cu2); + DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(); + newMember(structDIE_CU2, "f1", cu2TypedefDIE, 0).create(); importAllDataTypes(); @@ -1437,15 +1489,18 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testAsymetricEquivTypedefedBaseTypes_not_false_positive() throws CancelledException, IOException, DWARFException { + // CU1 // this struct has a field with a typedef to a basetype int - DebugInfoEntry structDIE = newStruct("mystruct", 10).create(cu); - newMember(structDIE, "f1", addTypedef("intX_t", addInt(cu), cu), 0).create(cu); + DebugInfoEntry cu2TypedefDIE = addTypedef("intX_t", addInt()); + DebugInfoEntry structDIE = newStruct("mystruct", 10).create(); + newMember(structDIE, "f1", cu2TypedefDIE, 0).create(); // CU2 + DebugInfoEntry cu2FloatDIE = addFloat(); // this struct has a field with a basetype float, which is incompatible with int - DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(cu2); - newMember(structDIE_CU2, "f1", addFloat(cu2), 0).create(cu2); + DebugInfoEntry structDIE_CU2 = newStruct("mystruct", 10).create(); + newMember(structDIE_CU2, "f1", cu2FloatDIE, 0).create(); importAllDataTypes(); @@ -1462,8 +1517,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { //================================================================================= @Test public void testEnum() throws CancelledException, IOException, DWARFException { - DebugInfoEntry enumDIE = createEnum("enum1", 4, cu); - addEnumValue(enumDIE, "val1", 1, cu); + DebugInfoEntry enumDIE = createEnum("enum1", 4); + addEnumValue(enumDIE, "val1", 1); importAllDataTypes(); @@ -1475,8 +1530,8 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testAnonEnum() throws CancelledException, IOException, DWARFException { - DebugInfoEntry enumDIE = createEnum(null, 4, cu); - addEnumValue(enumDIE, "val1", 1, cu); + DebugInfoEntry enumDIE = createEnum(null, 4); + addEnumValue(enumDIE, "val1", 1); importAllDataTypes(); @@ -1487,9 +1542,9 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testAnonEnumWithTypedef() throws CancelledException, IOException, DWARFException { - DebugInfoEntry enumDIE = createEnum(null, 4, cu); - addEnumValue(enumDIE, "val1", 1, cu); - DebugInfoEntry typedefDIE = addTypedef("typedefed_enum", enumDIE, cu); + DebugInfoEntry enumDIE = createEnum(null, 4); + addEnumValue(enumDIE, "val1", 1); + DebugInfoEntry typedefDIE = addTypedef("typedefed_enum", enumDIE); importAllDataTypes(); @@ -1503,13 +1558,13 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testMultiAnonEnumWithTypedef() throws CancelledException, IOException, DWARFException { - DebugInfoEntry enum1DIE = createEnum(null, 4, cu); - addEnumValue(enum1DIE, "val1", 1, cu); - DebugInfoEntry typedef1DIE = addTypedef("typedefed_enum1", enum1DIE, cu); + DebugInfoEntry enum1DIE = createEnum(null, 4); + addEnumValue(enum1DIE, "val1", 1); + DebugInfoEntry typedef1DIE = addTypedef("typedefed_enum1", enum1DIE); - DebugInfoEntry enum2DIE = createEnum(null, 4, cu); - addEnumValue(enum2DIE, "abc1", 1, cu); - DebugInfoEntry typedef2DIE = addTypedef("typedefed_enum2", enum2DIE, cu); + DebugInfoEntry enum2DIE = createEnum(null, 4); + addEnumValue(enum2DIE, "abc1", 1); + DebugInfoEntry typedef2DIE = addTypedef("typedefed_enum2", enum2DIE); importAllDataTypes(); @@ -1541,23 +1596,23 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { @Test public void testMultiAnonEnumWithTypedef2() throws CancelledException, IOException, DWARFException { - DebugInfoEntry enum1DIE = createEnum(null, 4, cu); - addEnumValue(enum1DIE, "val1", 1, cu); - DebugInfoEntry typedef1aDIE = addTypedef("typedefed_enum1a", enum1DIE, cu); + DebugInfoEntry enum1DIE = createEnum(null, 4); + addEnumValue(enum1DIE, "val1", 1); + DebugInfoEntry typedef1aDIE = addTypedef("typedefed_enum1a", enum1DIE); - DebugInfoEntry enum2DIE = createEnum(null, 4, cu); - addEnumValue(enum2DIE, "abc1", 1, cu); - DebugInfoEntry typedef2aDIE = addTypedef("typedefed_enum2a", enum2DIE, cu); + DebugInfoEntry enum2DIE = createEnum(null, 4); + addEnumValue(enum2DIE, "abc1", 1); + DebugInfoEntry typedef2aDIE = addTypedef("typedefed_enum2a", enum2DIE); - DebugInfoEntry enum3DIE = createEnum(null, 4, cu); - addEnumValue(enum3DIE, "three1", 1, cu); - DebugInfoEntry typedef3DIE = addTypedef("typedefed_enum3", enum3DIE, cu); + DebugInfoEntry enum3DIE = createEnum(null, 4); + addEnumValue(enum3DIE, "three1", 1); + DebugInfoEntry typedef3DIE = addTypedef("typedefed_enum3", enum3DIE); - DebugInfoEntry enum4DIE = createEnum(null, 4, cu); - addEnumValue(enum4DIE, "four1", 1, cu); + DebugInfoEntry enum4DIE = createEnum(null, 4); + addEnumValue(enum4DIE, "four1", 1); - DebugInfoEntry typedef1bDIE = addTypedef("typedefed_enum1b", enum1DIE, cu); - DebugInfoEntry typedef2bDIE = addTypedef("typedefed_enum2b", enum2DIE, cu); + DebugInfoEntry typedef1bDIE = addTypedef("typedefed_enum1b", enum1DIE); + DebugInfoEntry typedef2bDIE = addTypedef("typedefed_enum2b", enum2DIE); importAllDataTypes(); 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/dwarf4/next/DWARFFunctionImporterTest.java index a173311067..3b936c8075 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/dwarf4/next/DWARFFunctionImporterTest.java @@ -44,16 +44,12 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { // test that Ghidra functions in a Rust compilation unit do have their info set // if they look like they have normal param info - cu = new MockDWARFCompilationUnit(dwarfProg, 0x1000, 0x2000, 0, - DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 0, - DWARFSourceLanguage.DW_LANG_Rust); - cu2 = null; - setMockCompilationUnits(cu); + addCompUnit(DWARFSourceLanguage.DW_LANG_Rust); - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(); newFormalParam(fooDIE, "param1", intDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) - .create(cu); + .create(); importFunctions(); @@ -74,14 +70,10 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { @Test public void testRustMethod_SetsRustCC() throws CancelledException, IOException, DWARFException { - cu = new MockDWARFCompilationUnit(dwarfProg, 0x1000, 0x2000, 0, - DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 0, - DWARFSourceLanguage.DW_LANG_Rust); - cu2 = null; - setMockCompilationUnits(cu); + addCompUnit(DWARFSourceLanguage.DW_LANG_Rust); - DebugInfoEntry intDIE = addInt(cu); - newSubprogram("foo", intDIE, 0x410, 10).create(cu); + DebugInfoEntry intDIE = addInt(); + newSubprogram("foo", intDIE, 0x410, 10).create(); importFunctions(); @@ -99,21 +91,21 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { // that contains a namespace template argument (templateclass) // is encountered and a Ghidra namespace is created - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); - DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(cu); - DebugInfoEntry nestedStructPtrDIE = addFwdPtr(cu, 1); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1DIE = newStruct("mystruct::operator/()", 100).create(); + DebugInfoEntry nestedStructPtrDIE = addFwdPtr(1); DebugInfoEntry nestedStructDIE = - newStruct("nested_struct", 10).setParent(struct1DIE).create(cu); - newMember(nestedStructDIE, "blah1", intDIE, 0).create(cu); + newStruct("nested_struct", 10).setParent(struct1DIE).create(); + newMember(nestedStructDIE, "blah1", intDIE, 0).create(); DebugInfoEntry fooDIE = - newSubprogram("foo", intDIE, 0x410, 10).setParent(nestedStructDIE).create(cu); + newSubprogram("foo", intDIE, 0x410, 10).setParent(nestedStructDIE).create(); newFormalParam(fooDIE, "this", nestedStructPtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) - .create(cu); + .create(); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); - newMember(struct1DIE, "f3", nestedStructDIE, 20).create(cu); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + newMember(struct1DIE, "f3", nestedStructDIE, 20).create(); importFunctions(); @@ -123,7 +115,7 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { assertEquals("foo", fooFunc.getName()); assertEquals("nested_struct", ((Pointer) fooFunc.getParameter(0).getDataType()).getDataType().getName()); - assertEquals("__thiscall", fooFunc.getCallingConventionName()); + assertEquals(CompilerSpec.CALLING_CONVENTION_thiscall, fooFunc.getCallingConventionName()); assertEquals("nested_struct", nsParts.get(nsParts.size() - 1).getName()); assertEquals("mystruct::operator/()", nsParts.get(nsParts.size() - 2).getName()); @@ -136,10 +128,10 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { @Test public void testNoReturnFlag_True() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); DIECreator func = newSubprogram("foo", intDIE, 0x410, 10); func.addBoolean(DWARFAttribute.DW_AT_noreturn, true); - func.create(cu); + func.create(); importFunctions(); @@ -150,9 +142,9 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { @Test public void testNoReturnFlag_False() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); + DebugInfoEntry intDIE = addInt(); DIECreator func = newSubprogram("foo", intDIE, 0x410, 10); - func.create(cu); + func.create(); importFunctions(); @@ -168,10 +160,10 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { // In this case, it refers to a location in the function's local variable area, so // it should have been converted to a spill local variable. - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(); newFormalParam(fooDIE, "param1", intDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) // fbreg -14, func local variable area - .create(cu); + .create(); importFunctions(); @@ -199,10 +191,10 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { // TODO: need to also test location info from a debug_loc sequence that specifies a lexical offset - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(); newFormalParam(fooDIE, "param1", intDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x8) // fbreg +8, caller stack area - .create(cu); + .create(); importFunctions(); @@ -226,99 +218,133 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { @Test public void testThisParamDetect_NamedThis() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); - DebugInfoEntry struct1PtrDIE = addFwdPtr(cu, 1); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1PtrDIE = addFwdPtr(1); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); DebugInfoEntry fooDIE = - newSubprogram("foo", intDIE, 0x410, 10).setParent(struct1DIE).create(cu); + newSubprogram("foo", intDIE, 0x410, 10).setParent(struct1DIE).create(); newFormalParam(fooDIE, "this", struct1PtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) - .create(cu); + .create(); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); importFunctions(); Function fooFunc = program.getListing().getFunctionAt(addr(0x410)); assertEquals("foo", fooFunc.getName()); - assertEquals("__thiscall", fooFunc.getCallingConventionName()); + assertEquals(CompilerSpec.CALLING_CONVENTION_thiscall, fooFunc.getCallingConventionName()); } @Test public void testThisParamDetect_ArtificalUnNamed() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); - DebugInfoEntry struct1PtrDIE = addFwdPtr(cu, 1); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1PtrDIE = addFwdPtr(1); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); DebugInfoEntry fooDIE = - newSubprogram("foo", intDIE, 0x410, 10).setParent(struct1DIE).create(cu); + newSubprogram("foo", intDIE, 0x410, 10).setParent(struct1DIE).create(); newFormalParam(fooDIE, null, struct1PtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) .addBoolean(DWARFAttribute.DW_AT_artificial, true) - .create(cu); + .create(); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); importFunctions(); Function fooFunc = program.getListing().getFunctionAt(addr(0x410)); assertEquals("foo", fooFunc.getName()); - assertEquals("__thiscall", fooFunc.getCallingConventionName()); + assertEquals(CompilerSpec.CALLING_CONVENTION_thiscall, fooFunc.getCallingConventionName()); } @Test public void testThisParamDetect_ObjectPointer() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); - DebugInfoEntry struct1PtrDIE = addFwdPtr(cu, 1); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1PtrDIE = addFwdPtr(1); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + long formalParamDIEOffset = dwarfProg.getRelativeDIEOffset(2); DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10) - .addRef(DWARFAttribute.DW_AT_object_pointer, getForwardOffset(cu, 1)) + .addRef(DWARFAttribute.DW_AT_object_pointer, formalParamDIEOffset) .setParent(struct1DIE) - .create(cu); - newFormalParam(fooDIE, null, struct1PtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) - .create(cu); + .create(); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + // give the param a non-this name to defeat the logic in DWARFUtil.isThisParam() + newFormalParam(fooDIE, "not_the_normal_this_name", struct1PtrDIE, + DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c).create(); + + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); importFunctions(); Function fooFunc = program.getListing().getFunctionAt(addr(0x410)); assertEquals("foo", fooFunc.getName()); - assertEquals("__thiscall", fooFunc.getCallingConventionName()); + assertEquals(CompilerSpec.CALLING_CONVENTION_thiscall, fooFunc.getCallingConventionName()); + } + + @Test + public void testThisParamDetect_ObjectPointer_inverse() + throws CancelledException, IOException, DWARFException { + // Test that Ghidra doesn't mark foo()'s param as 'this' when we don't have a DW_AT_obj_ptr + // This is to ensure that testThisParamDetect_ObjectPointer() is a strong test + // The data in this test needs to mirror the data in testThisParamDetect_ObjectPointer(), + // minus the DW_AT_object_pointer attribute. + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1PtrDIE = addFwdPtr(1); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10) + //.addRef(DWARFAttribute.DW_AT_object_pointer, ??) don't add this attribute + .setParent(struct1DIE) + .create(); + + // give the param a non-this name to defeat the logic in DWARFUtil.isThisParam() + newFormalParam(fooDIE, "not_the_normal_this_name", struct1PtrDIE, + DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c).create(); + + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); + + importFunctions(); + + Function fooFunc = program.getListing().getFunctionAt(addr(0x410)); + + assertEquals("foo", fooFunc.getName()); + assertNotEquals(CompilerSpec.CALLING_CONVENTION_thiscall, + fooFunc.getCallingConventionName()); } @Test public void testThisParamDetect_Unnamed() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry floatDIE = addFloat(cu); - DebugInfoEntry struct1PtrDIE = addFwdPtr(cu, 1); - DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(cu); - DebugInfoEntry fooDIE = - newSubprogram("foo", intDIE, 0x410, 10) - .setParent(struct1DIE) - .create(cu); - newFormalParam(fooDIE, null, struct1PtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) - .create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry floatDIE = addFloat(); + DebugInfoEntry struct1PtrDIE = addFwdPtr(1); + DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); - newMember(struct1DIE, "f1", intDIE, 0).create(cu); - newMember(struct1DIE, "f2", floatDIE, 10).create(cu); + DebugInfoEntry fooDIE = + newSubprogram("foo", intDIE, 0x410, 10).setParent(struct1DIE).create(); + newFormalParam(fooDIE, null, struct1PtrDIE, DWARFExpressionOpCodes.DW_OP_fbreg, 0x6c) + .create(); + + newMember(struct1DIE, "f1", intDIE, 0).create(); + newMember(struct1DIE, "f2", floatDIE, 10).create(); importFunctions(); Function fooFunc = program.getListing().getFunctionAt(addr(0x410)); assertEquals("foo", fooFunc.getName()); - assertEquals("__thiscall", fooFunc.getCallingConventionName()); + assertEquals(CompilerSpec.CALLING_CONVENTION_thiscall, fooFunc.getCallingConventionName()); } @Test @@ -333,11 +359,11 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { initialFoo.addLocalVariable(new LocalVariableImpl("testxyz", intDT, -16, program), SourceType.USER_DEFINED); - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(cu); - newFormalParam(fooDIE, "param1", intDIE).create(cu); - newFormalParam(fooDIE, "param2", intDIE).create(cu); - newFormalParam(fooDIE, "testxyz" /* should collide with local var */, intDIE).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(); + newFormalParam(fooDIE, "param1", intDIE).create(); + newFormalParam(fooDIE, "param2", intDIE).create(); + newFormalParam(fooDIE, "testxyz" /* should collide with local var */, intDIE).create(); importFunctions(); @@ -351,13 +377,12 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { @Test public void testParamNameBadChars() - throws CancelledException, IOException, DWARFException, InvalidInputException, - OverlappingFunctionException, DuplicateNameException { + throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(cu); - newFormalParam(fooDIE, "param 1", intDIE).create(cu); - newFormalParam(fooDIE, "param\t2", intDIE).create(cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10).create(); + newFormalParam(fooDIE, "param 1", intDIE).create(); + newFormalParam(fooDIE, "param\t2", intDIE).create(); importFunctions(); 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/dwarf4/next/DWARFNameInfoTest.java index f82fba894d..901f93eab5 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/dwarf4/next/DWARFNameInfoTest.java @@ -110,8 +110,8 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNestedStructNames() throws CancelledException, IOException, DWARFException { - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - DebugInfoEntry substructDIE = newStruct("substruct", 200).setParent(structDIE).create(cu); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + DebugInfoEntry substructDIE = newStruct("substruct", 200).setParent(structDIE).create(); importAllDataTypes(); @@ -125,8 +125,8 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNestedAnonStructNames_NotUsedInParent() throws CancelledException, IOException, DWARFException { - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - DebugInfoEntry substructDIE = newStruct(null, 200).setParent(structDIE).create(cu); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + DebugInfoEntry substructDIE = newStruct(null, 200).setParent(structDIE).create(); importAllDataTypes(); @@ -141,9 +141,9 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNestedAnonStructNames_UsedInParent_Once() throws CancelledException, IOException, DWARFException { - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - DebugInfoEntry substructDIE = newStruct(null, 10).setParent(structDIE).create(cu); - newMember(structDIE, "f1", substructDIE, 0).create(cu); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + DebugInfoEntry substructDIE = newStruct(null, 10).setParent(structDIE).create(); + newMember(structDIE, "f1", substructDIE, 0).create(); importAllDataTypes(); @@ -158,10 +158,10 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNestedAnonStructNames_UsedInParent_Multi() throws CancelledException, IOException, DWARFException { - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - DebugInfoEntry substructDIE = newStruct(null, 10).setParent(structDIE).create(cu); - newMember(structDIE, "f1", substructDIE, 0).create(cu); - newMember(structDIE, "f2", substructDIE, 20).create(cu); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + DebugInfoEntry substructDIE = newStruct(null, 10).setParent(structDIE).create(); + newMember(structDIE, "f1", substructDIE, 0).create(); + newMember(structDIE, "f2", substructDIE, 20).create(); importAllDataTypes(); @@ -176,10 +176,10 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNonNestedAnonStructNames_UsedInParent_Once() throws CancelledException, IOException, DWARFException { - DebugInfoEntry anonstructDIE = newStruct(null, 10).create(cu); - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - newMember(structDIE, "f1", anonstructDIE, 0).create(cu); - newMember(structDIE, "f2", anonstructDIE, 20).create(cu); + DebugInfoEntry anonstructDIE = newStruct(null, 10).create(); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + newMember(structDIE, "f1", anonstructDIE, 0).create(); + newMember(structDIE, "f2", anonstructDIE, 20).create(); importAllDataTypes(); @@ -190,10 +190,10 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testNonNestedStructNames() throws CancelledException, IOException, DWARFException { - DebugInfoEntry struct4FieldDIE = newStruct("struct_10", 10).create(cu); - DebugInfoEntry structDIE = newStruct("struct", 100).create(cu); - newMember(structDIE, "f1", struct4FieldDIE, 0).create(cu); - newMember(structDIE, "f2", struct4FieldDIE, 20).create(cu); + DebugInfoEntry struct4FieldDIE = newStruct("struct_10", 10).create(); + DebugInfoEntry structDIE = newStruct("struct", 100).create(); + newMember(structDIE, "f1", struct4FieldDIE, 0).create(); + newMember(structDIE, "f2", struct4FieldDIE, 20).create(); importAllDataTypes(); @@ -204,8 +204,8 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testFuncDef() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry funcDIE = addSubroutineType("operator <", intDIE, cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry funcDIE = addSubroutineType("operator <", intDIE); importAllDataTypes(); @@ -217,9 +217,9 @@ public class DWARFNameInfoTest extends DWARFTestBase { @Test public void testAnonFuncDef() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - DebugInfoEntry funcDIE = addSubroutineType(null, intDIE, cu); - DebugInfoEntry func2DIE = addSubroutineType(null, null, cu); + DebugInfoEntry intDIE = addInt(); + DebugInfoEntry funcDIE = addSubroutineType(null, intDIE); + DebugInfoEntry func2DIE = addSubroutineType(null, null); importAllDataTypes(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf4/next/DWARFStaticVarImporterTest.java index e7e4c34e2c..d900764cec 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/dwarf4/next/DWARFStaticVarImporterTest.java @@ -18,11 +18,10 @@ package ghidra.app.util.bin.format.dwarf4.next; import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*; import static org.junit.Assert.*; +import java.io.IOException; import java.util.HashSet; import java.util.Set; -import java.io.IOException; - import org.junit.Test; import ghidra.app.util.bin.format.dwarf4.*; @@ -39,13 +38,13 @@ public class DWARFStaticVarImporterTest extends DWARFTestBase { @Test public void testIntStaticVar() throws CancelledException, IOException, DWARFException { - DebugInfoEntry intDIE = addInt(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + DebugInfoEntry intDIE = addInt(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var1") .addRef(DW_AT_type, intDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); + .create(); importFunctions(); @@ -58,13 +57,13 @@ public class DWARFStaticVarImporterTest extends DWARFTestBase { @Test public void testZeroLenGlobalVar() throws CancelledException, IOException, DWARFException { - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var1") .addRef(DW_AT_type, emptyStructDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); + .create(); importFunctions(); @@ -78,19 +77,19 @@ public class DWARFStaticVarImporterTest extends DWARFTestBase { @Test public void test2ZeroLenGlobalVar() throws CancelledException, IOException, DWARFException { - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var1") .addRef(DW_AT_type, emptyStructDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + .create(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var2") .addRef(DW_AT_type, emptyStructDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); + .create(); importFunctions(); @@ -102,20 +101,20 @@ public class DWARFStaticVarImporterTest extends DWARFTestBase { @Test public void testZeroLenGlobalVarOnTopOfNormalVar() throws CancelledException, IOException, DWARFException { - DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(cu); - DebugInfoEntry intDIE = addInt(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + DebugInfoEntry emptyStructDIE = newStruct("emptystruct", 0).create(); + DebugInfoEntry intDIE = addInt(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var1") .addRef(DW_AT_type, intDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); - new DIECreator(DWARFTag.DW_TAG_variable) + .create(); + new DIECreator(dwarfProg, DWARFTag.DW_TAG_variable) .addString(DW_AT_name, "static_var2") .addRef(DW_AT_type, emptyStructDIE) .addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0, 0, 0) - .create(cu); + .create(); importFunctions(); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIEAMonitoredIteratorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIEAMonitoredIteratorTest.java deleted file mode 100644 index e9dbaa5d93..0000000000 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIEAMonitoredIteratorTest.java +++ /dev/null @@ -1,105 +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 static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.DW_AT_name; -import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.DW_AT_type; - -import java.io.IOException; - -import org.junit.Assert; -import org.junit.Test; - -import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag; -import ghidra.app.util.bin.format.dwarf4.next.DIEAMonitoredIterator; -import ghidra.util.exception.CancelledException; - -public class DIEAMonitoredIteratorTest extends DWARFTestBase { - - @Test - public void testForwardCrossCURef() throws CancelledException, DWARFException, IOException { - DebugInfoEntry cu2Int = addInt(cu2); - new DIECreator(DWARFTag.DW_TAG_typedef).addString(DW_AT_name, "forward").addRef(DW_AT_type, - cu2Int.getOffset()).create(cu); - - dwarfProg.getImportOptions().setPreloadAllDIEs(true); - checkPreconditions(); - - int count = 0; - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(dwarfProg, "Testing", monitor)) { - count++; - } - Assert.assertEquals(4, count); - } - - @Test - public void testNormalIteration() throws CancelledException, DWARFException, IOException { - addFloat(cu); - addInt(cu2); - - checkPreconditions(); - - int count = 0; - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(dwarfProg, "Testing", monitor)) { - count++; - } - Assert.assertEquals(4, count); - } - - @Test - public void testCrossCUAggregate() throws CancelledException, DWARFException, IOException { - DebugInfoEntry cu1Struct = newDeclStruct("mystruct").create(cu); - DebugInfoEntry cu2Struct = newSpecStruct(cu1Struct, 10).create(cu2); - - dwarfProg.getImportOptions().setPreloadAllDIEs(true); - - checkPreconditions(); - - int count = 0; - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(dwarfProg, "Testing", monitor)) { - count++; - } - - DIEAggregate diea = getAggregate(cu2Struct); - Assert.assertEquals(2, diea.getFragmentCount()); - Assert.assertEquals(3, dwarfProg.getTotalAggregateCount()); - Assert.assertEquals(3, count); - } - - @Test - public void testCrossCUAggregate2() throws CancelledException, DWARFException, IOException { - DebugInfoEntry cu1Struct = newDeclStruct("mystruct").create(cu); - addFloat(cu); - addDouble(cu); - DebugInfoEntry cu2Struct = newSpecStruct(cu1Struct, 10).create(cu2); - addFloat(cu2); - addDouble(cu2); - - dwarfProg.getImportOptions().setPreloadAllDIEs(true); - - checkPreconditions(); - - int count = 0; - for (DIEAggregate diea : DIEAMonitoredIterator.iterable(dwarfProg, "Testing", monitor)) { - count++; - } - - DIEAggregate diea = getAggregate(cu2Struct); - Assert.assertEquals(2, diea.getFragmentCount()); - Assert.assertEquals(7, dwarfProg.getTotalAggregateCount()); - Assert.assertEquals(7, count); - } -} diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java index 506f22a8ad..de57d1f997 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreator.java @@ -17,8 +17,6 @@ package ghidra.app.util.bin.format.dwarf4; import java.util.*; -import org.junit.Assert; - import ghidra.app.util.bin.format.dwarf4.attribs.*; import ghidra.app.util.bin.format.dwarf4.encoding.DWARFForm; @@ -38,12 +36,13 @@ public class DIECreator { } } + private MockDWARFProgram dwarfProg; private int tag; private Map attributes = new HashMap<>(); - private List children = new ArrayList<>(); private DebugInfoEntry parent; - public DIECreator(int tag) { + public DIECreator(MockDWARFProgram dwarfProg, int tag) { + this.dwarfProg = dwarfProg; this.tag = tag; } @@ -97,17 +96,15 @@ public class DIECreator { return this; } - DWARFAbbreviation createAbbreviation(MockDWARFCompilationUnit cu) { + DWARFAttributeSpecification[] makeAttrSpecArray() { DWARFAttributeSpecification[] attrSpecs = new DWARFAttributeSpecification[attributes.size()]; - ArrayList attrInfoList = new ArrayList<>(attributes.values()); + 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); } - DWARFAbbreviation abbr = new DWARFAbbreviation(cu.getCodeToAbbreviationMap().size(), tag, - !children.isEmpty(), attrSpecs); - return abbr; + return attrSpecs; } public DIECreator setParent(DebugInfoEntry parent) { @@ -115,31 +112,32 @@ public class DIECreator { return this; } - public DebugInfoEntry create(MockDWARFCompilationUnit cu) { - DWARFAbbreviation abbr = createAbbreviation(cu); - cu.getCodeToAbbreviationMap().put(abbr.getAbbreviationCode(), abbr); - DebugInfoEntry die = - new DebugInfoEntry(cu, cu.getStartOffset() + cu.getMockEntryCount(), abbr); + 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; } - for (DebugInfoEntry childDIE : children) { - Assert.assertTrue(childDIE.getCompilationUnit() == cu); - die.addChild(childDIE); - } + return die; + } - if (parent == null) { - parent = cu.getCompileUnitDIE(); + public DebugInfoEntry create() { + MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit(); + if (cu == null) { + cu = dwarfProg.addCompUnit(); } - if (parent != null) { - die.setParent(parent); - Assert.assertTrue(parent.getCompilationUnit() == cu); - parent.addChild(die); + 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; } - cu.addMockEntry(die); 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/dwarf4/DIECreatorTest.java new file mode 100644 index 0000000000..8a472bf6ef --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIECreatorTest.java @@ -0,0 +1,145 @@ +/* ### + * 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 static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*; +import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*; +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import ghidra.util.exception.CancelledException; + +/** + * Testing the DIECreator, which is used in other tests. + */ +public class DIECreatorTest extends DWARFTestBase { + + @Test + public void testDIEAggregate() throws CancelledException, DWARFException, IOException { +// DebugInfoEntry baseType = +// new DIECreator(DWARFTag.DW_TAG_base_type).addString(DWARFAttribute.DW_AT_name, +// "base_type_name").addInt(DWARFAttribute.DW_AT_byte_size, 4).addInt( +// DWARFAttribute.DW_AT_encoding, DWARFEncoding.DW_ATE_unsigned).create(cu); +// +// DebugInfoEntry td = +// new DIECreator(DWARFTag.DW_TAG_typedef).addString(DWARFAttribute.DW_AT_name, +// "mytypedef").addRef(DWARFAttribute.DW_AT_type, baseType).create(cu); + + DebugInfoEntry declStruct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addBoolean(DW_AT_declaration, true) + .addString(DW_AT_const_value, "declConst") + .addString(DW_AT_description, "declDesc") + .create(); + + DebugInfoEntry implStruct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addRef(DW_AT_specification, declStruct) + .addString(DW_AT_const_value, "specConst") + .addString(DW_AT_description, "declDesc") + .create(); + + DebugInfoEntry aoStruct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addRef(DW_AT_abstract_origin, implStruct) + .addString(DW_AT_description, "aoDesc") + .create(); + + buildMockDIEIndexes(); + + DIEAggregate struct_via_ao = dwarfProg.getAggregate(aoStruct); + + assertEquals("MyStruct aggregate should have 3 fragments", 3, + struct_via_ao.getOffsets().length); + assertEquals("Attr dw_at_const should be from spec", "specConst", + struct_via_ao.getString(DW_AT_const_value, null)); + assertEquals("Attr dw_at_description should be from ao", "aoDesc", + struct_via_ao.getString(DW_AT_description, null)); + } + + /** + * Tests the creation of DIEAggregates when there is a many-to-one layout of + * abstractorigin -> spec -> decl links. + *

+ *

+	 *                                                   mystruct ao1
+	 *                                                 /
+	 *   mystruct decl <------  mystruct spec  <------+
+	 *                                                 \
+	 *                                                   mystruct ao2
+	 * 
+ * @throws DWARFException + * @throws IOException + * @throws CancelledException + */ + @Test + public void testDIEAggregateMulti() throws DWARFException, CancelledException, IOException { +// DebugInfoEntry baseType = +// new DIECreator(DWARFTag.DW_TAG_base_type).addString(DWARFAttribute.DW_AT_name, +// "base_type_name").addInt(DWARFAttribute.DW_AT_byte_size, 4).addInt( +// DWARFAttribute.DW_AT_encoding, DWARFEncoding.DW_ATE_unsigned).create(cu); +// +// DebugInfoEntry td = +// new DIECreator(DWARFTag.DW_TAG_typedef).addString(DWARFAttribute.DW_AT_name, +// "mytypedef").addRef(DWARFAttribute.DW_AT_type, baseType).create(cu); + + DebugInfoEntry declStruct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addBoolean(DW_AT_declaration, true) + .addString(DW_AT_const_value, "declConst") + .addString(DW_AT_description, "declDesc") + .create(); + + DebugInfoEntry implStruct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addRef(DW_AT_specification, declStruct) + .addString(DW_AT_const_value, "specConst") + .addString(DW_AT_description, "declDesc") + .create(); + + DebugInfoEntry ao1Struct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addRef(DW_AT_abstract_origin, implStruct) + .addString(DW_AT_description, "ao1Desc") + .create(); + + DebugInfoEntry ao2Struct = + new DIECreator(dwarfProg, DW_TAG_structure_type).addString(DW_AT_name, "mystruct") + .addRef(DW_AT_abstract_origin, implStruct) + .addString(DW_AT_description, "ao2Desc") + .create(); + + buildMockDIEIndexes(); + + DIEAggregate ao1 = dwarfProg.getAggregate(ao1Struct); + DIEAggregate ao2 = dwarfProg.getAggregate(ao2Struct); + + assertEquals("Should have 3 fragments", 3, ao1.getOffsets().length); + assertEquals("Should have 3 fragments", 3, ao2.getOffsets().length); + assertEquals("Attr dw_at_const should be from spec", "specConst", + ao1.getString(DW_AT_const_value, null)); + assertEquals("Attr dw_at_const should be from spec", "specConst", + ao2.getString(DW_AT_const_value, null)); + assertEquals("Attr dw_at_description should be from ao1", "ao1Desc", + ao1.getString(DW_AT_description, null)); + assertEquals("Attr dw_at_description should be from ao2", "ao2Desc", + ao2.getString(DW_AT_description, null)); + } + +} diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIETest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIETest.java deleted file mode 100644 index fcc4e36491..0000000000 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DIETest.java +++ /dev/null @@ -1,204 +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 static org.junit.Assert.assertEquals; - -import java.io.IOException; - -import org.junit.*; - -import generic.test.AbstractGenericTest; -import ghidra.app.util.bin.format.dwarf4.attribs.DWARFAttributeFactory; -import ghidra.app.util.bin.format.dwarf4.encoding.*; -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.NullSectionProvider; -import ghidra.program.model.listing.Program; -import ghidra.test.ToyProgramBuilder; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; - -/** - * Testing the DIECreator, which is used in other tests. - */ -public class DIETest extends AbstractGenericTest { - DWARFProgram prog; - DWARFAttributeFactory attribFactory; - MockDWARFCompilationUnit cu; - int transactionID; - Program ghidraProgram; - - @Before - public void setUp() throws Exception { - - ToyProgramBuilder builder = new ToyProgramBuilder("Test", true); - ghidraProgram = builder.getProgram(); - - startTransaction(); - prog = new DWARFProgram(ghidraProgram, new DWARFImportOptions(), TaskMonitor.DUMMY, - new NullSectionProvider()); - attribFactory = prog.getAttributeFactory(); - - cu = new MockDWARFCompilationUnit(prog, 0x1000, 0x2000, 0, DWARFCompilationUnit.DWARF_32, - (short) 4, 0, (byte) 8, 0, DWARFSourceLanguage.DW_LANG_C); - - } - - @After - public void tearDown() throws Exception { - endTransaction(); - } - - @Test - public void testDIEAggregate() - throws DWARFPreconditionException, CancelledException, DWARFException, IOException { -// DebugInfoEntry baseType = -// new DIECreator(DWARFTag.DW_TAG_base_type).addString(DWARFAttribute.DW_AT_name, -// "base_type_name").addInt(DWARFAttribute.DW_AT_byte_size, 4).addInt( -// DWARFAttribute.DW_AT_encoding, DWARFEncoding.DW_ATE_unsigned).create(cu); -// -// DebugInfoEntry td = -// new DIECreator(DWARFTag.DW_TAG_typedef).addString(DWARFAttribute.DW_AT_name, -// "mytypedef").addRef(DWARFAttribute.DW_AT_type, baseType).create(cu); - - DebugInfoEntry declStruct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addBoolean(DWARFAttribute.DW_AT_declaration, true).addString( - DWARFAttribute.DW_AT_const_value, "declConst").addString( - DWARFAttribute.DW_AT_description, "declDesc").create(cu); - - DebugInfoEntry implStruct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addRef(DWARFAttribute.DW_AT_specification, declStruct).addString( - DWARFAttribute.DW_AT_const_value, "specConst").addString( - DWARFAttribute.DW_AT_description, "declDesc").create(cu); - - DebugInfoEntry aoStruct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addRef(DWARFAttribute.DW_AT_abstract_origin, implStruct).addString( - DWARFAttribute.DW_AT_description, "aoDesc").create(cu); - - prog.checkPreconditions(TaskMonitor.DUMMY); - prog.setCurrentCompilationUnit(cu, TaskMonitor.DUMMY); - - DIEAggregate struct_via_ao = prog.getAggregate(aoStruct); - - assertEquals("MyStruct aggregate should have 3 fragments", 3, - struct_via_ao.getOffsets().length); - assertEquals("Attr dw_at_const should be from spec", "specConst", - struct_via_ao.getString(DWARFAttribute.DW_AT_const_value, null)); - assertEquals("Attr dw_at_description should be from ao", "aoDesc", - struct_via_ao.getString(DWARFAttribute.DW_AT_description, null)); - } - - /** - * Tests the creation of DIEAggregates when there is a many-to-one layout of - * abstractorigin -> spec -> decl links. - *

- *

-	 *                                                   mystruct ao1
-	 *                                                 /
-	 *   mystruct decl <------  mystruct spec  <------+
-	 *                                                 \
-	 *                                                   mystruct ao2
-	 * 
- * @throws DWARFException - * @throws IOException - * @throws CancelledException - */ - @Test - public void testDIEAggregateMulti() throws DWARFException, CancelledException, IOException { -// DebugInfoEntry baseType = -// new DIECreator(DWARFTag.DW_TAG_base_type).addString(DWARFAttribute.DW_AT_name, -// "base_type_name").addInt(DWARFAttribute.DW_AT_byte_size, 4).addInt( -// DWARFAttribute.DW_AT_encoding, DWARFEncoding.DW_ATE_unsigned).create(cu); -// -// DebugInfoEntry td = -// new DIECreator(DWARFTag.DW_TAG_typedef).addString(DWARFAttribute.DW_AT_name, -// "mytypedef").addRef(DWARFAttribute.DW_AT_type, baseType).create(cu); - - DebugInfoEntry declStruct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addBoolean(DWARFAttribute.DW_AT_declaration, true).addString( - DWARFAttribute.DW_AT_const_value, "declConst").addString( - DWARFAttribute.DW_AT_description, "declDesc").create(cu); - - DebugInfoEntry implStruct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addRef(DWARFAttribute.DW_AT_specification, declStruct).addString( - DWARFAttribute.DW_AT_const_value, "specConst").addString( - DWARFAttribute.DW_AT_description, "declDesc").create(cu); - - DebugInfoEntry ao1Struct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addRef(DWARFAttribute.DW_AT_abstract_origin, implStruct).addString( - DWARFAttribute.DW_AT_description, "ao1Desc").create(cu); - - DebugInfoEntry ao2Struct = - new DIECreator(DWARFTag.DW_TAG_structure_type).addString(DWARFAttribute.DW_AT_name, - "mystruct").addRef(DWARFAttribute.DW_AT_abstract_origin, implStruct).addString( - DWARFAttribute.DW_AT_description, "ao2Desc").create(cu); - - prog.checkPreconditions(TaskMonitor.DUMMY); - prog.setCurrentCompilationUnit(cu, TaskMonitor.DUMMY); - - DIEAggregate ao1 = prog.getAggregate(ao1Struct); - DIEAggregate ao2 = prog.getAggregate(ao2Struct); - - assertEquals("Should have 3 fragments", 3, ao1.getOffsets().length); - assertEquals("Should have 3 fragments", 3, ao2.getOffsets().length); - assertEquals("Attr dw_at_const should be from spec", "specConst", - ao1.getString(DWARFAttribute.DW_AT_const_value, null)); - assertEquals("Attr dw_at_const should be from spec", "specConst", - ao2.getString(DWARFAttribute.DW_AT_const_value, null)); - assertEquals("Attr dw_at_description should be from ao1", "ao1Desc", - ao1.getString(DWARFAttribute.DW_AT_description, null)); - assertEquals("Attr dw_at_description should be from ao2", "ao2Desc", - ao2.getString(DWARFAttribute.DW_AT_description, null)); - } - - @Test - public void testPagedEntryChecking() throws DWARFException, CancelledException, IOException { - DebugInfoEntry die1 = new DIECreator(DWARFTag.DW_TAG_base_type).create(cu); - - prog.checkPreconditions(TaskMonitor.DUMMY); - - try { - DIEAggregate diea1 = prog.getAggregate(die1); - Assert.assertNotNull(diea1); - } - catch (RuntimeException rte) { - // good, getAggregate() should fail if we haven't called setCurrentCompileUnit() - } - - prog.setCurrentCompilationUnit(cu, TaskMonitor.DUMMY); - DIEAggregate diea1 = prog.getAggregate(die1); - Assert.assertNotNull(diea1); - - } - - //--------------------------------------------------------------------------------------------- - - protected void startTransaction() { - transactionID = ghidraProgram.startTransaction("Test"); - } - - protected void endTransaction() { - ghidraProgram.endTransaction(transactionID, true); - } - -} diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java index 6f8ec90133..f8c68df4f0 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/DWARFTestBase.java @@ -16,8 +16,7 @@ package ghidra.app.util.bin.format.dwarf4; import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*; -import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding.DW_ATE_float; -import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding.DW_ATE_signed; +import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFEncoding.*; import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag.*; import static org.junit.Assert.*; @@ -28,7 +27,6 @@ import org.junit.Before; import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.services.DataTypeManagerService; -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.*; import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.NullSectionProvider; @@ -58,9 +56,8 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { protected TaskMonitor monitor = TaskMonitor.DUMMY; protected DWARFImportOptions importOptions; - protected DWARFProgram dwarfProg; - protected MockDWARFCompilationUnit cu; - protected MockDWARFCompilationUnit cu2; + protected MockDWARFProgram dwarfProg; + protected MockDWARFCompilationUnit currentCU; protected DWARFDataTypeManager dwarfDTM; protected CategoryPath uncatCP; protected CategoryPath dwarfRootCP; @@ -82,20 +79,11 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { builtInDTM = dtms.getBuiltInDataTypesManager(); importOptions = new DWARFImportOptions(); - dwarfProg = - new DWARFProgram(program, importOptions, TaskMonitor.DUMMY, new NullSectionProvider()); + dwarfProg = new MockDWARFProgram(program, importOptions, TaskMonitor.DUMMY, + new NullSectionProvider()); dwarfDTM = dwarfProg.getDwarfDTM(); dwarfRootCP = dwarfProg.getRootDNI().asCategoryPath(); uncatCP = dwarfProg.getUncategorizedRootDNI().asCategoryPath(); - - cu = new MockDWARFCompilationUnit(dwarfProg, 0x1000, 0x2000, 0, - DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 0, - DWARFSourceLanguage.DW_LANG_C); - cu2 = new MockDWARFCompilationUnit(dwarfProg, 0x3000, 0x4000, 0, - DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 1, - DWARFSourceLanguage.DW_LANG_C); - - setMockCompilationUnits(cu, cu2); } @After @@ -105,13 +93,6 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { program.release(this); } - protected void setMockCompilationUnits(DWARFCompilationUnit... compilationUnits) { - dwarfProg.getCompilationUnits().clear(); - for (DWARFCompilationUnit compilationUnit : compilationUnits) { - dwarfProg.getCompilationUnits().add(compilationUnit); - } - } - protected void startTransaction() { transactionID = program.startTransaction("Test"); } @@ -120,113 +101,125 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { program.endTransaction(transactionID, true); } - protected void checkPreconditions() throws CancelledException, DWARFException, IOException { - dwarfProg.checkPreconditions(monitor); + protected void buildMockDIEIndexes() throws CancelledException, DWARFException { + dwarfProg.buildMockDIEIndexes(); } protected void importAllDataTypes() throws CancelledException, IOException, DWARFException { - dwarfProg.checkPreconditions(monitor); + buildMockDIEIndexes(); dwarfDTM.importAllDataTypes(monitor); } protected void importFunctions() throws CancelledException, IOException, DWARFException { - dwarfProg.checkPreconditions(monitor); + buildMockDIEIndexes(); dwarfDTM.importAllDataTypes(monitor); DWARFFunctionImporter dfi = new DWARFFunctionImporter(dwarfProg, monitor); dfi.importFunctions(); } - protected DIEAggregate getAggregate(DebugInfoEntry die) - throws CancelledException, IOException, DWARFException { - dwarfProg.setCurrentCompilationUnit(die.getCompilationUnit(), monitor); + protected DIEAggregate getAggregate(DebugInfoEntry die) { return dwarfProg.getAggregate(die); } - protected DebugInfoEntry addBaseType(String name, int size, int encoding, - MockDWARFCompilationUnit dcu) { - DIECreator tmp = new DIECreator(DW_TAG_base_type) + protected void ensureCompUnit() { + if (dwarfProg.getCurrentCompUnit() == null) { + dwarfProg.addCompUnit(); + } + } + + protected MockDWARFCompilationUnit addCompUnit() { + return dwarfProg.addCompUnit(); + } + + protected MockDWARFCompilationUnit addCompUnit(int cuLang) { + return dwarfProg.addCompUnit(cuLang); + } + + protected DebugInfoEntry addBaseType(String name, int size, int encoding) { + ensureCompUnit(); + DIECreator tmp = new DIECreator(dwarfProg, DW_TAG_base_type) // .addInt(DW_AT_byte_size, size) .addInt(DW_AT_encoding, encoding); if (name != null) { tmp.addString(DW_AT_name, name); } - return tmp.create(dcu); + return tmp.create(); } - protected DebugInfoEntry addInt(MockDWARFCompilationUnit dcu) { - return addBaseType("int", 4, DW_ATE_signed, dcu); + protected DebugInfoEntry addInt() { + ensureCompUnit(); + return addBaseType("int", 4, DW_ATE_signed); } - protected DebugInfoEntry addFloat(MockDWARFCompilationUnit dcu) { - return addBaseType("float", 4, DW_ATE_float, dcu); + protected DebugInfoEntry addFloat() { + ensureCompUnit(); + return addBaseType("float", 4, DW_ATE_float); } - protected DebugInfoEntry addDouble(MockDWARFCompilationUnit dcu) { - return addBaseType("double", 8, DW_ATE_float, dcu); + protected DebugInfoEntry addDouble() { + ensureCompUnit(); + return addBaseType("double", 8, DW_ATE_float); } - protected DebugInfoEntry addTypedef(String name, DebugInfoEntry die, - MockDWARFCompilationUnit dcu) { - assertTrue(die.getCompilationUnit() == dcu); - return new DIECreator(DW_TAG_typedef) - .addString(DW_AT_name, name) + protected DebugInfoEntry addTypedef(String name, DebugInfoEntry die) { + ensureCompUnit(); + return new DIECreator(dwarfProg, DW_TAG_typedef).addString(DW_AT_name, name) .addRef(DW_AT_type, die) - .create(dcu); + .create(); } - protected DebugInfoEntry addSubprogram(String name, DebugInfoEntry returnTypeDIE, - MockDWARFCompilationUnit dcu) { - assertTrue(returnTypeDIE == null || returnTypeDIE.getCompilationUnit() == dcu); - DIECreator tmp = new DIECreator(DW_TAG_subprogram); + protected DebugInfoEntry addSubprogram(String name, DebugInfoEntry returnTypeDIE) { + ensureCompUnit(); + DIECreator tmp = new DIECreator(dwarfProg, DW_TAG_subprogram); if (name != null) { tmp.addString(DW_AT_name, name); } if (returnTypeDIE != null) { tmp.addRef(DW_AT_type, returnTypeDIE); } - return tmp.create(dcu); + return tmp.create(); } - protected DebugInfoEntry addSubroutineType(String name, DebugInfoEntry returnTypeDIE, - MockDWARFCompilationUnit dcu) { - assertTrue(returnTypeDIE == null || returnTypeDIE.getCompilationUnit() == dcu); - DIECreator tmp = new DIECreator(DW_TAG_subroutine_type); + protected DebugInfoEntry addSubroutineType(String name, DebugInfoEntry returnTypeDIE) { + ensureCompUnit(); + DIECreator tmp = new DIECreator(dwarfProg, DW_TAG_subroutine_type); if (name != null) { tmp.addString(DW_AT_name, name); } if (returnTypeDIE != null) { tmp.addRef(DW_AT_type, returnTypeDIE); } - return tmp.create(dcu); + return tmp.create(); } - protected DebugInfoEntry addParam(DebugInfoEntry parent, String name, DebugInfoEntry typeDIE, - MockDWARFCompilationUnit dcu) { - assertTrue(typeDIE == null || typeDIE.getCompilationUnit() == dcu); - assertTrue(parent.getCompilationUnit() == dcu); - return new DIECreator(DW_TAG_formal_parameter) + protected DebugInfoEntry addParam(DebugInfoEntry parent, String name, DebugInfoEntry typeDIE) { + ensureCompUnit(); + return new DIECreator(dwarfProg, DW_TAG_formal_parameter) // .addRef(DW_AT_type, typeDIE) .setParent(parent) - .create(dcu); + .create(); } protected DIECreator newSpecStruct(DebugInfoEntry declDIE, int size) { - DIECreator struct = new DIECreator(DW_TAG_structure_type) + ensureCompUnit(); + DIECreator struct = new DIECreator(dwarfProg, DW_TAG_structure_type) // .addRef(DW_AT_specification, declDIE) .addInt(DW_AT_byte_size, size); return struct; } protected DIECreator newDeclStruct(String name) { - DIECreator struct = new DIECreator(DW_TAG_structure_type) + ensureCompUnit(); + DIECreator struct = new DIECreator(dwarfProg, DW_TAG_structure_type) // .addBoolean(DW_AT_declaration, true) .addString(DW_AT_name, name); return struct; } protected DIECreator newStruct(String name, int size) { - DIECreator struct = new DIECreator(DW_TAG_structure_type); + ensureCompUnit(); + DIECreator struct = new DIECreator(dwarfProg, DW_TAG_structure_type); if (name != null) { struct.addString(DW_AT_name, name); } @@ -234,52 +227,56 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { return struct; } - protected DebugInfoEntry createEnum(String name, int size, MockDWARFCompilationUnit dcu) { - DIECreator resultEnum = new DIECreator(DW_TAG_enumeration_type); + protected DebugInfoEntry createEnum(String name, int size) { + ensureCompUnit(); + DIECreator resultEnum = new DIECreator(dwarfProg, DW_TAG_enumeration_type); if (name != null) { resultEnum.addString(DW_AT_name, name); } resultEnum.addInt(DW_AT_byte_size, size); - return resultEnum.create(dcu); + return resultEnum.create(); } protected DebugInfoEntry addEnumValue(DebugInfoEntry parentEnum, String valueName, - long valueValue, MockDWARFCompilationUnit dcu) { - assertTrue(parentEnum.getCompilationUnit() == dcu); - DIECreator enumValue = new DIECreator(DW_TAG_enumerator) + long valueValue) { + ensureCompUnit(); + DIECreator enumValue = new DIECreator(dwarfProg, DW_TAG_enumerator) // .addString(DW_AT_name, valueName) .addInt(DW_AT_const_value, valueValue) .setParent(parentEnum); - return enumValue.create(dcu); + return enumValue.create(); } - protected DebugInfoEntry addPtr(DebugInfoEntry targetDIE, MockDWARFCompilationUnit dcu) { - assertTrue(targetDIE.getCompilationUnit() == dcu); - return new DIECreator(DW_TAG_pointer_type).addRef(DW_AT_type, targetDIE).create(dcu); + protected DebugInfoEntry addPtr(DebugInfoEntry targetDIE) { + ensureCompUnit(); + return new DIECreator(dwarfProg, DW_TAG_pointer_type) // + .addRef(DW_AT_type, targetDIE) + .create(); } - protected DebugInfoEntry addFwdPtr(MockDWARFCompilationUnit dcu, int fwdRecordOffset) { - return new DIECreator(DW_TAG_pointer_type) - .addRef(DW_AT_type, getForwardOffset(dcu, fwdRecordOffset)) - .create(dcu); - } - - protected long getForwardOffset(MockDWARFCompilationUnit dcu, int count) { - return dcu.getStartOffset() + dcu.getMockEntryCount() + count; + protected DebugInfoEntry addFwdPtr(int fwdRecordOffset) { + ensureCompUnit(); + long absOffset = + dwarfProg.getRelativeDIEOffset(fwdRecordOffset + /* the ptr die we are about to add */ 1); + return new DIECreator(dwarfProg, DW_TAG_pointer_type) + .addRef(DW_AT_type, absOffset) + .create(); } protected DIECreator newMember(DebugInfoEntry parentStruct, String fieldName, DebugInfoEntry dataType, int offset) { assertTrue( dataType == null || dataType.getCompilationUnit() == parentStruct.getCompilationUnit()); + ensureCompUnit(); return newMember(parentStruct, fieldName, dataType.getOffset(), offset); } protected DIECreator newMember(DebugInfoEntry parentStruct, String fieldName, - long memberDIEOffset, int offset) { - DIECreator field = new DIECreator(DWARFTag.DW_TAG_member) + long typeDIEOffset, int offset) { + ensureCompUnit(); + DIECreator field = new DIECreator(dwarfProg, DWARFTag.DW_TAG_member) // .addString(DW_AT_name, fieldName) - .addRef(DW_AT_type, memberDIEOffset) + .addRef(DW_AT_type, typeDIEOffset) .setParent(parentStruct); if (offset != -1) { field.addInt(DW_AT_data_member_location, offset); @@ -291,44 +288,48 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { int offset) { assertTrue( dataType == null || dataType.getCompilationUnit() == parentStruct.getCompilationUnit()); - DIECreator field = new DIECreator(DW_TAG_inheritance) + ensureCompUnit(); + DIECreator field = new DIECreator(dwarfProg, DW_TAG_inheritance) // .addRef(DW_AT_type, dataType) .addInt(DW_AT_data_member_location, offset) .setParent(parentStruct); return field; } - protected DebugInfoEntry newArray(MockDWARFCompilationUnit dcu, DebugInfoEntry baseTypeDIE, - boolean elideEmptyDimRangeValue, int... dimensions) { - DebugInfoEntry arrayType = new DIECreator(DW_TAG_array_type) + protected DebugInfoEntry newArray(DebugInfoEntry baseTypeDIE, boolean elideEmptyDimRangeValue, + int... dimensions) { + ensureCompUnit(); + DebugInfoEntry arrayType = new DIECreator(dwarfProg, DW_TAG_array_type) // .addRef(DW_AT_type, baseTypeDIE) - .create(dcu); + .create(); for (int dimIndex = 0; dimIndex < dimensions.length; dimIndex++) { int dim = dimensions[dimIndex]; - DIECreator dimDIE = new DIECreator(DW_TAG_subrange_type).setParent(arrayType); + DIECreator dimDIE = new DIECreator(dwarfProg, DW_TAG_subrange_type) // + .setParent(arrayType); if (dim != -1 || !elideEmptyDimRangeValue) { dimDIE.addInt(DW_AT_upper_bound, dimensions[dimIndex]); } - dimDIE.create(dcu); + dimDIE.create(); } return arrayType; } - protected DebugInfoEntry newArrayUsingCount(MockDWARFCompilationUnit dcu, - DebugInfoEntry baseTypeDIE, int count) { - DebugInfoEntry arrayType = new DIECreator(DW_TAG_array_type) + protected DebugInfoEntry newArrayUsingCount(DebugInfoEntry baseTypeDIE, int count) { + ensureCompUnit(); + DebugInfoEntry arrayType = new DIECreator(dwarfProg, DW_TAG_array_type) // .addRef(DW_AT_type, baseTypeDIE) - .create(dcu); - DIECreator dimDIE = new DIECreator(DW_TAG_subrange_type) - .setParent(arrayType); - dimDIE.addInt(DW_AT_count, count); - dimDIE.create(dcu); + .create(); + new DIECreator(dwarfProg, DW_TAG_subrange_type) // + .setParent(arrayType) + .addInt(DW_AT_count, count) + .create(); return arrayType; } protected DIECreator newSubprogram(String name, DebugInfoEntry returnType, long startAddress, long length) { - return new DIECreator(DW_TAG_subprogram) + ensureCompUnit(); + return new DIECreator(dwarfProg, DW_TAG_subprogram) // .addString(DW_AT_name, name) .addRef(DW_AT_type, returnType) .addUInt(DW_AT_low_pc, startAddress) @@ -337,7 +338,8 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { protected DIECreator newFormalParam(DebugInfoEntry subprogram, String paramName, DebugInfoEntry paramDataType, int... locationExpr) { - DIECreator param = new DIECreator(DW_TAG_formal_parameter) + ensureCompUnit(); + DIECreator param = new DIECreator(dwarfProg, DW_TAG_formal_parameter) // .addRef(DW_AT_type, paramDataType) .setParent(subprogram); if (locationExpr.length > 0) { diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java index 3e0434783b..7e8559df59 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFCompilationUnit.java @@ -15,47 +15,46 @@ */ package ghidra.app.util.bin.format.dwarf4; -import java.util.ArrayList; -import java.util.List; - -import ghidra.app.util.bin.format.dwarf4.encoding.*; -import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram; -import ghidra.util.task.TaskMonitor; - public class MockDWARFCompilationUnit extends DWARFCompilationUnit { - private List mockEntries = new ArrayList<>(); private DebugInfoEntry compUnitDIE; + private MockDWARFProgram dwarfProgram; + private int dieCount; - public MockDWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset, + 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; - setCompileUnit( - new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer", "Mock Comp Unit Dir", - 0, 0, language, DWARFIdentifierCase.DW_ID_case_insensitive, false, null)); - compUnitDIE = new DIECreator(DWARFTag.DW_TAG_compile_unit) - .addString(DWARFAttribute.DW_AT_name, "MockCompUnit" + compUnitNumber) - .create(this); + this.compUnit = new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer", + "Mock Comp Unit Dir", 0, 0, language, false, null); } - @Override - public void readDIEs(List dies, TaskMonitor unused_monitor) { - dies.addAll(mockEntries); + public void setCompUnitDIE(DebugInfoEntry compUnitDIE) { + this.compUnitDIE = compUnitDIE; } public DebugInfoEntry getCompileUnitDIE() { return compUnitDIE; } - public void addMockEntry(DebugInfoEntry die) { - mockEntries.add(die); + public int incDIECount() { + return dieCount++; } - public int getMockEntryCount() { - return mockEntries.size(); + @Override + public MockDWARFProgram getProgram() { + return dwarfProgram; + } + + public DWARFAbbreviation createAbbreviation(DWARFAttributeSpecification[] attrSpecs, int tag) { + DWARFAbbreviation abbr = + new DWARFAbbreviation(getCodeToAbbreviationMap().size(), tag, true /*??*/, attrSpecs); + getCodeToAbbreviationMap().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/dwarf4/MockDWARFProgram.java new file mode 100644 index 0000000000..de2ed3d2e0 --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf4/MockDWARFProgram.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.dwarf4; + +import java.io.IOException; +import java.util.ArrayList; +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.program.model.listing.Program; +import ghidra.util.datastruct.IntArrayList; +import ghidra.util.datastruct.LongArrayList; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class MockDWARFProgram extends DWARFProgram { + + private MockDWARFCompilationUnit currentCompUnit; + private List dies = new ArrayList<>(); + + public MockDWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor) + throws CancelledException, IOException, DWARFException { + super(program, importOptions, monitor); + } + + public MockDWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor, + DWARFSectionProvider sectionProvider) + throws CancelledException, IOException, DWARFException { + super(program, importOptions, monitor, sectionProvider); + } + + public MockDWARFCompilationUnit getCurrentCompUnit() { + return currentCompUnit; + } + + public MockDWARFCompilationUnit addCompUnit() { + return addCompUnit(DWARFSourceLanguage.DW_LANG_C); + } + + public MockDWARFCompilationUnit addCompUnit(int cuLang) { + if (currentCompUnit == null && !compUnitDieIndex.isEmpty()) { + Assert.fail(); + } + + if (currentCompUnit != null) { + compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit); + } + long start = compUnits.size() * 0x1000; + currentCompUnit = new MockDWARFCompilationUnit(this, start, start + 0x1000, 0, + DWARFCompilationUnit.DWARF_32, (short) 4, 0, (byte) 8, 0, cuLang); + + compUnits.add(currentCompUnit); + compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit); + + DebugInfoEntry compUnitRootDIE = + new DIECreator(this, DWARFTag.DW_TAG_compile_unit).createRootDIE(); + currentCompUnit.setCompUnitDIE(compUnitRootDIE); + + return currentCompUnit; + } + + public long getRelativeDIEOffset(int count) { + int cuDIECount = currentCompUnit.incDIECount(); + return currentCompUnit.getStartOffset() + cuDIECount + count; + } + + public DebugInfoEntry addDIE(DWARFAbbreviation abbr, DebugInfoEntry parent) { + LongArrayList dieOffsetList = new LongArrayList(dieOffsets); + IntArrayList siblingIndexList = new IntArrayList(siblingIndexes); + IntArrayList parentIndexList = new IntArrayList(parentIndexes); + + int dieIndex = dieOffsetList.size(); + int cuDIECount = currentCompUnit.incDIECount(); + DebugInfoEntry die = + new DebugInfoEntry(currentCompUnit, currentCompUnit.getStartOffset() + cuDIECount, + dieIndex, abbr); + + diesByOffset.put(die.getOffset(), die); + dieOffsetList.add(die.getOffset()); + parentIndexList.add(parent != null ? parent.getIndex() : -1); + siblingIndexList.add(dieIndex + 1); + + updateSiblingIndexes(siblingIndexList, parentIndexList, dieIndex); + + dieOffsets = dieOffsetList.toLongArray(); + siblingIndexes = siblingIndexList.toArray(); + parentIndexes = parentIndexList.toArray(); + + dies.add(die); + + return die; + } + + public void buildMockDIEIndexes() throws CancelledException, DWARFException { + if (currentCompUnit == null) { + return; + } + + compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit); + currentCompUnit = null; + + LongArrayList aggrTargets = new LongArrayList(); + for (DebugInfoEntry die : dies) { + DIEAggregate diea = DIEAggregate.createSingle(die); + for (int attr : DIEAggregate.REF_ATTRS) { + long refdOffset = diea.getUnsignedLong(attr, -1); + if (refdOffset != -1) { + aggrTargets.add(refdOffset); + } + } + } + indexDIEAggregates(aggrTargets, TaskMonitor.DUMMY); // after this point, DIEAggregates are functional + indexDIEATypeRefs(TaskMonitor.DUMMY); + + } + +} diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/IntArrayList.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/IntArrayList.java index 92f7de828c..1afb1db6f5 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/IntArrayList.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/IntArrayList.java @@ -26,6 +26,7 @@ import ghidra.util.Saveable; */ public class IntArrayList implements Serializable, Saveable { private final static long serialVersionUID = 1; + private final static int[] EMPTY_INT_ARRAY = new int[0]; public static final int MIN_SIZE = 4; int [] ints; @@ -38,6 +39,10 @@ public class IntArrayList implements Serializable, Saveable { ints = new int[MIN_SIZE]; } + public IntArrayList(boolean useZeroSize) { + ints = useZeroSize ? EMPTY_INT_ARRAY : new int[MIN_SIZE]; + } + /** * Creates a new intArrayList using the values in the given array * @param arr array of ints to initialize to. @@ -149,6 +154,10 @@ public class IntArrayList implements Serializable, Saveable { return size; } + public boolean isEmpty() { + return size == 0; + } + /** * Converts to a primitive array. * @return int[] int array for results. @@ -163,11 +172,11 @@ public class IntArrayList implements Serializable, Saveable { * Doubles the size of the array. * @param size The new capacity of the array. */ - private void growArray() { - int [] newints = new int[ints.length*2]; - System.arraycopy(ints,0,newints,0,ints.length); - ints = newints; - } + private void growArray() { + int[] newints = new int[Math.max(ints.length * 2, MIN_SIZE)]; + System.arraycopy(ints, 0, newints, 0, ints.length); + ints = newints; + } private void shrinkArray() { int newsize = ints.length/2; @@ -230,4 +239,5 @@ public class IntArrayList implements Serializable, Saveable { public boolean isPrivate() { return false; } + } diff --git a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/LongArrayList.java b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/LongArrayList.java index 2c350743e8..00fb4fc2d3 100644 --- a/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/LongArrayList.java +++ b/Ghidra/Framework/Generic/src/main/java/ghidra/util/datastruct/LongArrayList.java @@ -15,15 +15,15 @@ */ package ghidra.util.datastruct; -import ghidra.util.Msg; - import java.util.*; +import ghidra.util.Msg; + /** * An ArrayList for longs. */ -public class LongArrayList implements List { +public class LongArrayList implements List, RandomAccess { public static final int MIN_SIZE = 4; private long [] longs; @@ -61,6 +61,7 @@ public class LongArrayList implements List { /** * @see java.util.List#add(java.lang.Object) */ + @Override public boolean add(Long value) { add(size, value); return true; @@ -70,13 +71,15 @@ public class LongArrayList implements List { /** * @see java.util.List#add(int, java.lang.Object) */ + @Override public void add(int index, Long value) { add(index, value.longValue()); } public void add(int index, long value) { if (index < 0 || index > size) { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException( + "Invalid index %d for list of size %d".formatted(index, size)); } if (size == longs.length) { growArray(); @@ -91,9 +94,11 @@ public class LongArrayList implements List { size++; } - public Long remove(int index) { + @Override + public Long remove(int index) { if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException( + "Invalid index %d for list of size %d".formatted(index, size)); } Long returnValue = longs[index]; System.arraycopy(longs, index+1, longs, index, size-index-1); @@ -104,24 +109,24 @@ public class LongArrayList implements List { return returnValue; } - /** - * @see java.util.List#get(int) - */ - public Long get(int index) { + @Override + public Long get(int index) { if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException( + "Invalid index %d for list of size %d".formatted(index, size)); } return longs[index]; } + public long getLongValue(int index) { if (index < 0 || index >= size) { - throw new IndexOutOfBoundsException(); + throw new IndexOutOfBoundsException( + "Invalid index %d for list of size %d".formatted(index, size)); } return longs[index]; } - /** - * @see LongArraySubList#set(int, long) - */ + + @Override public Long set(int index, Long value) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); @@ -134,6 +139,7 @@ public class LongArrayList implements List { /** * @see LongArraySubList#clear() */ + @Override public void clear() { size = 0; longs = new long[MIN_SIZE]; @@ -142,6 +148,7 @@ public class LongArrayList implements List { /** * @see LongArraySubList#size() */ + @Override public int size() { return size; } @@ -149,6 +156,7 @@ public class LongArrayList implements List { /** * @see LongArraySubList#toArray() */ + @Override public Long [] toArray() { Long[] values = new Long[size]; for(int i=0;i { } + @Override public boolean remove(Object value) { if (!(value instanceof Long)) { return false; @@ -215,6 +224,7 @@ public class LongArrayList implements List { return false; } + @Override public int indexOf(Object value) { if (!(value instanceof Long)) { return -1; @@ -227,14 +237,17 @@ public class LongArrayList implements List { } return -1; } + @Override public List subList(int startIndex, int endIndex) { return new LongArraySubList(this, startIndex, endIndex); } + @Override public boolean addAll(Collection c) { return addAll(size(), c); } + @Override public boolean addAll(int index, Collection c) { int newSize = size + c.size(); long[] newValues = new long[newSize]; @@ -250,10 +263,12 @@ public class LongArrayList implements List { return true; } + @Override public boolean contains(Object value) { return indexOf(value) >= 0; } + @Override public boolean containsAll(Collection c) { Iterator it = c.iterator(); while(it.hasNext()) { @@ -264,14 +279,17 @@ public class LongArrayList implements List { return true; } + @Override public boolean isEmpty() { return size() == 0; } + @Override public Iterator iterator() { return new LongArrayListIterator(this, 0); } + @Override public int lastIndexOf(Object value) { if (!(value instanceof Long)) { return -1; @@ -285,14 +303,17 @@ public class LongArrayList implements List { return -1; } + @Override public ListIterator listIterator() { return new LongArrayListIterator(this, 0); } + @Override public ListIterator listIterator(int index) { return new LongArrayListIterator(this, index); } + @Override public boolean removeAll(Collection c) { boolean changed = false; Iterator it = c.iterator(); @@ -305,6 +326,7 @@ public class LongArrayList implements List { } + @Override public boolean retainAll(Collection c) { long[] newValues = new long[longs.length]; int newIndex = 0; @@ -330,6 +352,7 @@ public class LongArrayList implements List { this.endIndex = endIndex; } + @Override public boolean add(Long value) { backingList.add(endIndex++, value); return true; @@ -338,6 +361,7 @@ public class LongArrayList implements List { backingList.add(endIndex++, value); } + @Override public void add(int index, Long value) { if (index < 0 || index > (endIndex-startIndex)) { throw new IndexOutOfBoundsException(); @@ -353,6 +377,7 @@ public class LongArrayList implements List { endIndex++; } + @Override public Long remove(int index) { if (index < 0 || index >= (endIndex-startIndex)) { throw new IndexOutOfBoundsException(); @@ -361,6 +386,7 @@ public class LongArrayList implements List { return backingList.remove(startIndex+index); } + @Override public Long get(int index) { if (index < 0 || index >= (endIndex-startIndex)) { throw new IndexOutOfBoundsException(); @@ -375,6 +401,7 @@ public class LongArrayList implements List { backingList.set(startIndex+index, value); } + @Override public void clear() { for(int i=startIndex;i { endIndex = startIndex; } + @Override public int size() { return endIndex-startIndex; } + @Override public Long[] toArray() { int size = size(); Long[] values = new Long[size]; @@ -395,6 +424,7 @@ public class LongArrayList implements List { return values; } + @Override public boolean remove(Object value) { if (!(value instanceof Long)) { return false; @@ -419,22 +449,26 @@ public class LongArrayList implements List { return -1; } + @Override public boolean addAll(Collection c) { backingList.addAll(endIndex, c); endIndex += c.size(); return true; } + @Override public boolean addAll(int index, Collection c) { backingList.addAll(startIndex+index, c); endIndex += c.size(); return true; } + @Override public boolean contains(Object o) { return indexOf(o) >= 0; } + @Override public boolean containsAll(Collection c) { Iterator it = c.iterator(); while(it.hasNext()) { @@ -445,6 +479,7 @@ public class LongArrayList implements List { return true; } + @Override public int indexOf(Object value) { if (!(value instanceof Long)) { return -1; @@ -458,14 +493,17 @@ public class LongArrayList implements List { return -1; } + @Override public boolean isEmpty() { return size() == 0; } + @Override public Iterator iterator() { return new LongArrayListIterator(this, 0); } + @Override public int lastIndexOf(Object value) { if (!(value instanceof Long)) { return -1; @@ -479,14 +517,17 @@ public class LongArrayList implements List { return -1; } + @Override public ListIterator listIterator() { return new LongArrayListIterator(this, 0); } + @Override public ListIterator listIterator(int index) { return new LongArrayListIterator(this, index); } + @Override public boolean removeAll(Collection c) { boolean changed = false; Iterator it = c.iterator(); @@ -498,6 +539,7 @@ public class LongArrayList implements List { return changed; } + @Override public boolean retainAll(Collection c) { boolean changed = false; Iterator it = iterator(); @@ -511,6 +553,7 @@ public class LongArrayList implements List { return changed; } + @Override public Long set(int index, Long element) { if (index < 0 || index >= size()) { throw new IllegalArgumentException(); @@ -520,10 +563,12 @@ public class LongArrayList implements List { return oldValue; } + @Override public List subList(int fromIndex, int toIndex) { return new LongArraySubList(backingList,startIndex+fromIndex, startIndex+toIndex); } + @Override @SuppressWarnings("unchecked") // unchecked casts public T[] toArray(T[] a) { if (a.length < size()) { @@ -540,6 +585,7 @@ public class LongArrayList implements List { } + @Override @SuppressWarnings("unchecked") // unchecked cast public T[] toArray(T[] a) { if (a.length < size) { @@ -573,18 +619,22 @@ class LongArrayListIterator implements ListIterator { this.nextIndex = startIndex; } + @Override public void add(Long o) { list.add(nextIndex, o); } + @Override public boolean hasNext() { return nextIndex < list.size(); } + @Override public boolean hasPrevious() { return nextIndex > 0; } + @Override public Long next() { if (!hasNext()) { throw new NoSuchElementException(); @@ -593,10 +643,12 @@ class LongArrayListIterator implements ListIterator { return list.get(nextIndex++); } + @Override public int nextIndex() { return nextIndex; } + @Override public Long previous() { if (!hasPrevious()) { throw new NoSuchElementException(); @@ -605,10 +657,12 @@ class LongArrayListIterator implements ListIterator { return list.get(--nextIndex); } + @Override public int previousIndex() { return nextIndex-1; } + @Override public void remove() { if (lastReturnedIndex == -1) { throw new IllegalStateException(); @@ -620,6 +674,7 @@ class LongArrayListIterator implements ListIterator { lastReturnedIndex = -1; } + @Override public void set(Long o) { if (lastReturnedIndex == -1) { throw new IllegalStateException();