diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java index 433649621e..9eafd5ab5f 100644 --- a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoCommentScript.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.util.List; import ghidra.app.script.GhidraScript; -import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.*; import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileAddr; import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider; @@ -42,25 +41,23 @@ public class DWARFLineInfoCommentScript extends GhidraScript { } DWARFImportOptions importOptions = new DWARFImportOptions(); - try (DWARFProgram dprog = new DWARFProgram(currentProgram, importOptions, monitor, dsp)) { + try (DWARFProgram dprog = new DWARFProgram(currentProgram, importOptions, dsp)) { dprog.init(monitor); addSourceLineInfo(dprog); } } private void addSourceLineInfo(DWARFProgram dprog) throws CancelledException, IOException { - BinaryReader reader = dprog.getDebugLineBR(); - if (reader == null) { + if (!dprog.getDIEContainer().hasLineInfo()) { return; } int count = 0; - monitor.initialize(reader.length(), "DWARF Source Line Info"); - List compUnits = dprog.getCompilationUnits(); - for (DWARFCompilationUnit cu : compUnits) { + monitor.initialize(dprog.getDIEContainer().getLineDataSize(), "DWARF Source Line Info"); + for (DWARFCompilationUnit cu : dprog.getDIEContainer().getCompilationUnits()) { try { monitor.checkCancelled(); monitor.setProgress(cu.getLine().getStartOffset()); - List allSFA = cu.getLine().getAllSourceFileAddrInfo(cu, reader); + List allSFA = cu.getLine().getAllSourceFileAddrInfo(cu); for (SourceFileAddr sfa : allSFA) { Address addr = dprog.getCodeAddress(sfa.address()); DWARFUtil.appendComment(currentProgram, addr, CommentType.EOL, "", diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoSourceMapScript.java b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoSourceMapScript.java index 588d505d5b..dd4304a5a4 100644 --- a/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoSourceMapScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/DWARFLineInfoSourceMapScript.java @@ -24,7 +24,6 @@ import java.io.IOException; import java.util.*; import ghidra.app.script.GhidraScript; -import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.*; import ghidra.app.util.bin.format.dwarf.external.*; import ghidra.app.util.bin.format.dwarf.line.DWARFLine; @@ -65,7 +64,7 @@ public class DWARFLineInfoSourceMapScript extends GhidraScript { } DWARFImportOptions importOptions = new DWARFImportOptions(); - try (DWARFProgram dprog = new DWARFProgram(currentProgram, importOptions, monitor, dsp)) { + try (DWARFProgram dprog = new DWARFProgram(currentProgram, importOptions, dsp)) { dprog.init(monitor); addSourceLineInfo(dprog); } @@ -73,8 +72,7 @@ public class DWARFLineInfoSourceMapScript extends GhidraScript { private void addSourceLineInfo(DWARFProgram dprog) throws CancelledException, IOException, LockException, AddressOverflowException { - BinaryReader reader = dprog.getDebugLineBR(); - if (reader == null) { + if (!dprog.getDIEContainer().hasLineInfo()) { popup("Unable to get reader for debug line info"); return; } @@ -127,7 +125,7 @@ public class DWARFLineInfoSourceMapScript extends GhidraScript { continue; } } - sourceInfo.addAll(cu.getLine().getAllSourceFileAddrInfo(cu, reader)); + sourceInfo.addAll(cu.getLine().getAllSourceFileAddrInfo(cu)); } monitor.setIndeterminate(true); diff --git a/Ghidra/Features/Base/ghidra_scripts/DWARFMacroScript.java b/Ghidra/Features/Base/ghidra_scripts/DWARFMacroScript.java index eaba9c16d1..0f680f08d3 100644 --- a/Ghidra/Features/Base/ghidra_scripts/DWARFMacroScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/DWARFMacroScript.java @@ -37,8 +37,7 @@ public class DWARFMacroScript extends GhidraScript { return; } - try (DWARFProgram dprog = - new DWARFProgram(currentProgram, new DWARFImportOptions(), monitor, dsp)) { + try (DWARFProgram dprog = new DWARFProgram(currentProgram, new DWARFImportOptions(), dsp)) { dprog.init(monitor); for (DWARFCompilationUnit cu : dprog.getCompilationUnits()) { dumpMacros(cu.getMacros(), 0); 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 2aea5dc07f..b555036ceb 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 @@ -101,7 +101,7 @@ public class DWARFAnalyzer extends AbstractAnalyzer { extDFSI.importSymbols(log); } - try (DWARFProgram prog = new DWARFProgram(program, importOptions, monitor, dsp)) { + try (DWARFProgram prog = new DWARFProgram(program, importOptions, dsp)) { if (prog.getRegisterMappings() == null && importOptions.isImportFuncs()) { log.appendMsg("No DWARF to Ghidra register mappings found for this program's " + "language [%s], function information may be incorrect / incomplete." diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java index bbfc533b2b..2306a6d6b2 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/BinaryReader.java @@ -201,9 +201,8 @@ public class BinaryReader { * Returns the length of the underlying file. * * @return returns the length of the underlying file - * @exception IOException if an I/O error occurs */ - public long length() throws IOException { + public long length() { return provider.length(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEAggregate.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEAggregate.java index 113a36c322..5021c57dd0 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEAggregate.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEAggregate.java @@ -231,6 +231,13 @@ public class DIEAggregate { return getHeadFragment().getProgram(); } + /** + * {@return the program's single {@link DIEContainer}} + */ + public DIEContainer getDIEContainer() { + return getProgram().getDIEContainer(); + } + /** * Returns the last {@link DebugInfoEntry DIE} fragment, ie. the decl DIE. * @return last DIE of this aggregate @@ -251,13 +258,13 @@ public class DIEAggregate { public DIEAggregate getDeclParent() { DebugInfoEntry declDIE = getLastFragment(); DebugInfoEntry declParent = declDIE.getParent(); - return getProgram().getAggregate(declParent); + return getDIEContainer().getAggregate(declParent); } public DIEAggregate getParent() { DebugInfoEntry die = getHeadFragment(); DebugInfoEntry parent = die.getParent(); - return getProgram().getAggregate(parent); + return getDIEContainer().getAggregate(parent); } /** @@ -274,7 +281,7 @@ public class DIEAggregate { * that this instance was already the root of the compUnit */ public int getDepth() { - return getProgram().getParentDepth(getHeadFragment().getIndex()); + return getHeadFragment().getDepth(); } /** @@ -294,7 +301,7 @@ public class DIEAggregate { return attributeValue; } for (DebugInfoEntry childDIE : getChildren(childTag)) { - DIEAggregate childDIEA = getProgram().getAggregate(childDIE); + DIEAggregate childDIEA = getDIEContainer().getAggregate(childDIE); attributeValue = childDIEA.findValue(attrId, clazz); if (attributeValue != null) { return attributeValue; @@ -428,7 +435,7 @@ public class DIEAggregate { } try { - return getProgram().getDIE(foundAttr.getAttributeForm(), val.getUnsignedValue(), + return getDIEContainer().getDIE(foundAttr.getAttributeForm(), val.getUnsignedValue(), foundAttr.getDIE().getCompilationUnit()); } catch (IOException e) { @@ -449,7 +456,7 @@ public class DIEAggregate { */ public DIEAggregate getRef(DWARFAttributeId attrId) { DebugInfoEntry die = getRefDIE(attrId); - return getProgram().getAggregate(die); + return getDIEContainer().getAggregate(die); } /** @@ -650,7 +657,7 @@ public class DIEAggregate { * @throws IOException if error reading data */ public DWARFLocationList getLocationList(DWARFAttributeId attrId) throws IOException { - return getProgram().getLocationList(this, attrId); + return getDIEContainer().getLocationList(this, attrId); } /** @@ -708,7 +715,7 @@ public class DIEAggregate { * @throws IOException if an I/O error occurs */ public DWARFRangeList getRangeList(DWARFAttributeId attrId) throws IOException { - return getProgram().getRangeList(this, attrId); + return getDIEContainer().getRangeList(this, attrId); } /** @@ -723,7 +730,7 @@ public class DIEAggregate { try { // TODO: previous code excluded lowPc values that were == 0 as invalid. long rawLowPc = lowPcAttrVal.getUnsignedValue(); - long lowPcOffset = getProgram().getAddress(lowPc.getAttributeForm(), rawLowPc, + long lowPcOffset = getDIEContainer().getAddress(lowPc.getAttributeForm(), rawLowPc, getCompilationUnit()); long highPcOffset = lowPcOffset; @@ -758,7 +765,7 @@ public class DIEAggregate { // build list of params, as seen by the function's DIEA List params = new ArrayList<>(); for (DebugInfoEntry paramDIE : getChildren(DW_TAG_formal_parameter)) { - DIEAggregate paramDIEA = getProgram().getAggregate(paramDIE); + DIEAggregate paramDIEA = getDIEContainer().getAggregate(paramDIE); params.add(paramDIEA); } @@ -777,7 +784,7 @@ public class DIEAggregate { } else { // add generic (abstract) definition of the param to the list - newParams.add(getProgram().getAggregate(paramDIE)); + newParams.add(getDIEContainer().getAggregate(paramDIE)); } } if (!params.isEmpty()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEContainer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEContainer.java new file mode 100644 index 0000000000..7149331f65 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DIEContainer.java @@ -0,0 +1,1097 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.dwarf; + +import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId.*; +import static ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId.*; + +import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.Charset; +import java.util.*; +import java.util.Map.Entry; +import java.util.function.Predicate; + +import org.apache.commons.collections4.ListValuedMap; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; + +import ghidra.app.util.bin.*; +import ghidra.app.util.bin.format.dwarf.attribs.*; +import ghidra.app.util.bin.format.dwarf.line.DWARFLine; +import ghidra.app.util.bin.format.dwarf.macro.DWARFMacroHeader; +import ghidra.app.util.bin.format.dwarf.macro.entry.DWARFMacroInfoEntry; +import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId; +import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider; +import ghidra.app.util.opinion.ElfLoader; +import ghidra.program.model.listing.Program; +import ghidra.util.Msg; +import ghidra.util.datastruct.*; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Provides access to a set of DIE records (and associated bits and bobs) + */ +public class DIEContainer implements Iterable { + protected static final EnumSet REF_ATTRS = + EnumSet.of(DW_AT_abstract_origin, DW_AT_specification); + + protected DWARFProgram dprog; + protected DWARFSectionProvider sectionProvider; + + protected Map> abbrCache = new HashMap<>(); + + // 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 of ram in these indexes. + // DIE instances do not keep references to other DIEs. + protected long[] dieOffsets = new long[0]; // offset in the debuginfo stream of this DIE + protected int[] siblingIndexes = new int[0]; // index of each DIE's next sibling. + protected int[] parentIndexes = new int[0]; // index of each DIE's parent record, or -1 for root + + // 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<>(); + + // Indirect tables, added with dwarf v5, provide an index -> offset lookup feature for + // index values such as DW_FORM_addrx or DW_FORM_strx and other similar 'x' attribute values. + // Each DWARFIndirectTable is made of per-CU lookup arrays held in a DWARFIndirectTableHeader. + protected DWARFIndirectTable addressListTable; // DWARFAddressListHeaders, DW_AT_addr_base + protected DWARFIndirectTable locationListTable; // DWARFLocationListHeaders, DW_AT_rgnlists_base + protected DWARFIndirectTable rangeListTable; // DWARFRangeListHeaders, DW_AT_rgnlists_base + protected DWARFIndirectTable stringsOffsetTable; // DWARFStringOffsetTableHeader, DW_AT_str_offsets_base + + // boolean flag, per die record, indicating that the DIE is the target of another DIE via + // an aggregate reference, and therefore not the root DIE record of an aggregate. + protected BitSet indexHasRef = new BitSet(); + + // 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<>(); + protected WeakValueHashMap aggsByOffset = new WeakValueHashMap<>(); + + // Map of DIE offsets of DIEAggregates that are being pointed to by + // other DIEAggregates with a DW_AT_type property. + // In other words, a map of inbound links to a DIEA. + protected ListValuedMap typeReferers = new ArrayListValuedHashMap<>(); + + protected int totalAggregateCount; + + protected StringTable debugStrings; + protected StringTable lineStrings; + + protected Map cachedDWARFLines = new HashMap<>(); + + // BinaryReaders for each of the various dwarf sections + protected BinaryReader debugLocation; + protected BinaryReader debugLocLists; // v5+ + protected BinaryReader debugRanges; + protected BinaryReader debugRngLists; // v5+ + protected BinaryReader debugInfoBR; + protected BinaryReader debugLineBR; + protected BinaryReader debugAbbrBR; + protected BinaryReader debugAddr; // v5+ + protected BinaryReader debugStrOffsets; // v5+ + protected BinaryReader debugMacros; // v5+ + + protected DWARFImportSummary importSummary; + + public DIEContainer(DWARFProgram dprog) { + this.dprog = dprog; + this.sectionProvider = dprog.getSectionProvider(); + this.importSummary = dprog.getImportSummary(); + } + + /** + * Fetches required sections and sets up variables. + * + * @param monitor {@link TaskMonitor} + * @throws IOException if error + */ + public void init(TaskMonitor monitor) throws IOException { + this.debugInfoBR = getReader(DEBUG_INFO, monitor); + this.debugAbbrBR = getReader(DEBUG_ABBREV, monitor); + + this.debugLocation = getReader(DEBUG_LOC, monitor); + this.debugLocLists = getReader(DEBUG_LOCLISTS, monitor); + + this.debugRanges = getReader(DEBUG_RANGES, monitor); + this.debugRngLists = getReader(DEBUG_RNGLISTS, monitor); + + this.debugLineBR = getReader(DEBUG_LINE, monitor); + this.debugAddr = getReader(DEBUG_ADDR, monitor); + this.debugStrOffsets = getReader(DEBUG_STROFFSETS, monitor); + + this.debugMacros = getReader(DEBUG_MACRO, monitor); + + this.rangeListTable = + new DWARFIndirectTable(this.debugRngLists, DWARFCompilationUnit::getRangeListsBase); + this.addressListTable = + new DWARFIndirectTable(this.debugAddr, DWARFCompilationUnit::getAddrTableBase); + this.stringsOffsetTable = + new DWARFIndirectTable(this.debugStrOffsets, DWARFCompilationUnit::getStrOffsetsBase); + this.locationListTable = + new DWARFIndirectTable(this.debugLocLists, DWARFCompilationUnit::getLocListsBase); + + Charset charset = dprog.getCharset(); + this.debugStrings = StringTable.of(getReader(DEBUG_STR, monitor), charset); + this.lineStrings = StringTable.of(getReader(DEBUG_LINE_STR, monitor), charset); + + // 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. + // TODO: probably only needed for local section provider + boolean hasRelocations = hasRelocations(debugInfoBR) || hasRelocations(debugRanges); + if (!hasRelocations) { + Program prog = dprog.getGhidraProgram(); + Long oib = ElfLoader.getElfOriginalImageBase(prog); + if (oib != null && oib.longValue() != prog.getImageBase().getOffset()) { + dprog.setProgramBaseAddressFixup(prog.getImageBase().getOffset() - oib.longValue()); + } + } + } + + /** + * Reads and indexes the DIE records found in the section. + * + * @param monitor {@link TaskMonitor} + * @throws CancelledException if cancelled + * @throws DWARFException if error + * @throws IOException if error + */ + public void indexData(TaskMonitor monitor) + throws CancelledException, DWARFException, IOException { + bootstrapCompilationUnits(monitor); + + int defaultIntSize = dprog.getDefaultIntSize(); + rangeListTable.bootstrap("DWARF: Bootstrapping Range Lists", + reader -> DWARFRangeListHeader.read(reader, defaultIntSize), monitor); + locationListTable.bootstrap("DWARF: Bootstrapping Location Lists", + reader -> DWARFLocationListHeader.read(reader, defaultIntSize), monitor); + addressListTable.bootstrap("DWARF: Bootstrapping Address Lists", + reader -> DWARFAddressListHeader.read(reader, defaultIntSize), monitor); + stringsOffsetTable.bootstrap("DWARF: Bootstrapping String Offset Lists", + reader -> DWARFStringOffsetTableHeader.readV5(reader, defaultIntSize), monitor); + + indexDIEs(monitor); + indexDIEATypeRefs(monitor); + + importSummary.addCompunitInfo(compUnits); + } + + public void close() { + if (debugStrings != null) { + debugStrings.clear(); + debugStrings = null; + } + if (lineStrings != null) { + lineStrings.clear(); + lineStrings = null; + } + compUnits.clear(); + + debugAbbrBR = null; + debugInfoBR = null; + debugLineBR = null; + debugLocation = null; + debugLocLists = null; + debugRanges = null; + debugRngLists = null; + debugAddr = null; + + dieOffsets = new long[0]; + parentIndexes = new int[0]; + siblingIndexes = new int[0]; + indexHasRef.clear(); + aggsByOffset.clear(); + diesByOffset.clear(); + typeReferers.clear(); + compUnitDieIndex.clear(); + + locationListTable.clear(); + rangeListTable.clear(); + stringsOffsetTable.clear(); + addressListTable.clear(); + } + + private BinaryReader getReader(DWARFSectionId section, TaskMonitor monitor) throws IOException { + ByteProvider bp = + sectionProvider.getSectionAsByteProvider(section.getSectionName(), monitor); + return (bp != null) ? new BinaryReader(bp, dprog.isLittleEndian()) : null; + } + + private boolean hasRelocations(BinaryReader br) { + if (br == null) { + return false; + } + ByteProvider bp = br.getByteProvider(); + if (bp instanceof MemoryByteProvider mbp && !mbp.isEmpty()) { + Program providerProgram = mbp.getMemory().getProgram(); + if (providerProgram.getRelocationTable() + .getRelocations(mbp.getAddressSet()) + .hasNext()) { + return true; + } + } + return false; + } + + private void bootstrapCompilationUnits(TaskMonitor monitor) + throws CancelledException, IOException, DWARFException { + + debugInfoBR.setPointerIndex(0); + monitor.initialize(debugInfoBR.length(), "DWARF: Bootstrapping Compilation Units"); + while (debugInfoBR.hasNext()) { + monitor.checkCancelled(); + monitor.setProgress(debugInfoBR.getPointerIndex()); + monitor.setMessage("DWARF: Bootstrapping Compilation Unit #" + compUnits.size()); + + DWARFUnitHeader unitHeader = DWARFUnitHeader.read(this, debugInfoBR, compUnits.size()); + if (unitHeader == null) { + break; + } + + debugInfoBR.setPointerIndex(unitHeader.getEndOffset()); + if (unitHeader instanceof DWARFCompilationUnit cu) { + compUnits.add(cu); + importSummary.dwarfVers.add((int) cu.getDWARFVersion()); + } + else { + Msg.info(this, "Unsupported unit header: " + unitHeader + " at " + + unitHeader.getStartOffset()); + } + } + importSummary.compUnitCount = compUnits.size(); + } + + private void indexDIEs(TaskMonitor monitor) throws CancelledException, IOException { + LongArrayList dieOffsetList = new LongArrayList(); + IntArrayList siblingIndexList = new IntArrayList(); + IntArrayList parentIndexList = new IntArrayList(); + 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.getUnitNumber() + 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; + + importSummary.dieCount = 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.getOffset()); + } + } + monitor.initialize(0, ""); + } + + 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 indexDIEsForCU(DWARFCompilationUnit cu, LongArrayList dieOffsetList, + IntArrayList parentIndexList, IntArrayList siblingIndexList, LongArrayList aggrTargets, + TaskMonitor monitor) throws CancelledException, DWARFException { + 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); + + 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; + } + + if (die.getOffset() == cu.getFirstDIEOffset()) { + cu.init(die); + } + + DIEAggregate diea = DIEAggregate.createSingle(die); + for (DWARFAttributeId attrId : REF_ATTRS) { + DWARFAttribute refAttr = diea.findAttribute(attrId); + if (refAttr != null && + refAttr.getValue() instanceof DWARFNumericAttribute refVal) { + long refdOffset = getLocalDIEOffset(refAttr.getAttributeForm(), + refVal.getUnsignedValue(), cu); + aggrTargets.add(refdOffset); + } + } + + diesByOffset.put(startOfDIE, die); + } + catch (DWARFException e) { + throw e; + } + 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: %s" + .formatted(startOfDIE, cu.getUnitNumber(), cu.getStartOffset(), + Objects.requireNonNullElse(e.getMessage(), "unspecified"))); + Msg.debug(this, "Error location", e); + debugInfoBR.setPointerIndex(endOffset); + } + } + + } + + private long getLocalDIEOffset(DWARFForm form, long rawOffset, DWARFCompilationUnit cu) + throws DWARFException { + switch (form) { + case DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata: + return rawOffset + cu.getStartOffset(); + case DW_FORM_ref_addr: + return rawOffset; + case DW_FORM_gnu_ref_alt: + throw new DWARFException("Unsupported DIE reference form: " + form); + default: + Msg.warn(this, "Nontypical form %s used for reference".formatted(form)); + return rawOffset; + } + } + + protected void updateSiblingIndexes(IntArrayList siblingIndexList, IntArrayList parentIndexList, + int index) { + int x = siblingIndexList.size(); + while (index != -1) { + siblingIndexList.set(index, x); + index = parentIndexList.get(index); + } + } + + private DWARFCompilationUnit getCompilationUnitForDIE(int dieIndex) { + Entry entry = compUnitDieIndex.ceilingEntry(dieIndex); + return entry != null ? entry.getValue() : null; + } + + /** + * Return the DIE referenced by an attribute value (a DW_FORM and offset) + * + * @param form {@link DWARFForm} + * @param rawOffset index / offset from the numeric attribute + * @param cu compilation unit containing the value + * @return {@link DebugInfoEntry}, or null if doesn't exist + * @throws IOException if unsupported format for reference + */ + public DebugInfoEntry getDIE(DWARFForm form, long rawOffset, DWARFCompilationUnit cu) + throws IOException { + return getDIEByOffset(getLocalDIEOffset(form, rawOffset, cu)); + } + + /** + * 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); + 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}. + * + * @param die {@link DebugInfoEntry} or null + * @return {@link DIEAggregate} that contains the specified DIE, or null if DIE null or + * the aggregate was not found. + */ + public DIEAggregate getAggregate(DebugInfoEntry die) { + DIEAggregate diea = (die != null) ? aggsByOffset.get(die.getOffset()) : null; + if (diea == null && die != null) { + diea = DIEAggregate.createFromHead(die); + aggsByOffset.put(die.getOffset(), diea); + } + 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 dieOffset offset of a DIE record + * @return {@link DIEAggregate} that contains the DIE record specified, or null if bad + * offset. + */ + public DIEAggregate getAggregate(long dieOffset) { + DIEAggregate diea = aggsByOffset.get(dieOffset); + if (diea != null) { + return diea; + } + DebugInfoEntry die = getDIEByOffset(dieOffset); + return getAggregate(die); + } + + /** + * Returns iterable that traverses all {@link DIEAggregate}s in the program. + * + * @return sequence of {@link DIEAggregate}es + */ + public Iterable allAggregates() { + return new DIEAggregateIterator(); + } + + /** + * Returns the total number of {@link DIEAggregate} objects in the entire program. + * + * @return the total number of {@link DIEAggregate} objects in the entire program. + */ + public int getTotalAggregateCount() { + return totalAggregateCount; + } + + public BinaryReader getReaderForCompUnit(DWARFCompilationUnit cu) { + return debugInfoBR; + } + + public Map getAbbrevs(long abbrevOffset) throws IOException { + Map result = abbrCache.get(abbrevOffset); + if (result == null) { + debugAbbrBR.setPointerIndex(abbrevOffset); + result = DWARFAbbreviation.readAbbreviations(debugAbbrBR, this); + abbrCache.put(abbrevOffset, result); + } + return result; + } + + public DWARFProgram getProgram() { + return dprog; + } + + public List getCompilationUnits() { + return compUnits; + } + + /** + * 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; + } + + /** + * 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 int getParentIndex(int dieIndex) { + return parentIndexes[dieIndex]; + } + + /** + * 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; + } + + /** + * 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; + } + + /** + * 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 + */ + private 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; + } + + public int getChildCount(int dieIndex) { + int result = 0; + if (dieIndex >= 0) { + int parentSiblingIndex = siblingIndexes[dieIndex]; + for (int index = dieIndex + 1; index < parentSiblingIndex; index = + siblingIndexes[index]) { + result++; + } + } + return result; + } + + /** + * Returns the raw offset of an indexed item. For DW_FORM_addrx values, the returned value + * is not fixed up with Ghidra load offset. + * + * @param form {@link DWARFForm} of the index + * @param index int index into a lookup table (see {@link #addressListTable}, + * {@link #locationListTable}, {@link #rangeListTable}, {@link #stringsOffsetTable}) + * @param cu {@link DWARFCompilationUnit} + * @return raw offset of indexed item + * @throws IOException if error reading index table + */ + public long getOffsetOfIndexedElement(DWARFForm form, int index, DWARFCompilationUnit cu) + throws IOException { + DWARFIndirectTable table = switch (form) { + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + yield addressListTable; + case DW_FORM_rnglistx: + yield rangeListTable; + case DW_FORM_loclistx: + yield locationListTable; + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: + yield stringsOffsetTable; + default: + yield null; + }; + return table != null ? table.getOffset(index, cu) : -1; + } + + /** + * Returns an address value. + * + * @param form the format of the numeric value + * @param value raw offset or indirect address index (depending on the DWARFForm) + * @param cu {@link DWARFCompilationUnit} + * @return address + * @throws IOException if error reading indirect lookup tables + */ + public long getAddress(DWARFForm form, long value, DWARFCompilationUnit cu) throws IOException { + switch (form) { + case DW_FORM_addr: + case DW_FORM_udata: + return value; + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: { + long addr = addressListTable.getOffset((int) value, cu); + return addr; + } + case DW_FORM_gnu_addr_index: + default: + throw new IOException("Unsupported form %s".formatted(form)); + } + } + + /** + * Returns the {@link DWARFLocationList} pointed to by the specified attribute value. + * + * @param diea {@link DIEAggregate} + * @param attrId attribute id that points to the location list + * @return {@link DWARFLocationList}, never null + * @throws IOException if specified attribute is not the correct type, or if other error reading + * data + */ + public DWARFLocationList getLocationList(DIEAggregate diea, DWARFAttributeId attrId) + throws IOException { + DWARFAttribute attrib = diea.findAttribute(attrId); + if (attrib == null) { + return DWARFLocationList.EMPTY; + } + return switch (attrib.getValue()) { + case DWARFNumericAttribute dnum -> readLocationList(attrib, dnum); + case DWARFBlobAttribute dblob -> DWARFLocationList.withWildcardRange(dblob.getBytes()); + default -> throw new IOException("Unsupported form %s.".formatted(attrib)); + }; + } + + + private DWARFLocationList readLocationList(DWARFAttribute attr, DWARFNumericAttribute val) + throws IOException { + try { + DWARFCompilationUnit cu = attr.getCU(); + switch (attr.getAttributeForm()) { + case DW_FORM_sec_offset: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: + int dwarfVer = cu.getDWARFVersion(); + if (dwarfVer < 5) { + debugLocation.setPointerIndex(val.getUnsignedValue()); + return DWARFLocationList.readV4(debugLocation, cu); + } + else if (dwarfVer == 5) { + debugLocLists.setPointerIndex(val.getUnsignedValue()); + return DWARFLocationList.readV5(debugLocLists, cu); + } + break; + case DW_FORM_loclistx: + int index = val.getUnsignedIntExact(); + long locOffset = locationListTable.getOffset(index, cu); + debugLocLists.setPointerIndex(locOffset); + return DWARFLocationList.readV5(debugLocLists, cu); + default: + break; // fallthru to throw + } + } + catch (IOException | IllegalArgumentException e) { + throw new IOException( + "Failed to read location list specified by %s".formatted(attr.toString()), e); + } + throw new IOException("Unsupported loclist form %s".formatted(attr.getAttributeForm())); + } + + /** + * Returns a DWARF attribute string value, as specified by a form, offset/index, and the cu. + * + * @param form {@link DWARFForm} + * @param offset offset or index of the value + * @param cu {@link DWARFCompilationUnit} + * @return String value, never null + * @throws IOException if invalid form or bad offset/index + */ + public String getString(DWARFForm form, long offset, DWARFCompilationUnit cu) + throws IOException { + switch (form) { + case DW_FORM_line_strp: + return lineStrings.getStringAtOffset(offset); + case DW_FORM_strp: + return debugStrings.getStringAtOffset(offset); + case DW_FORM_gnu_strp_alt: + case DW_FORM_gnu_str_index: + throw new IOException("Unsupported DWARF string attribute form " + form); + case DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, DW_FORM_strx4: + long strOffset = stringsOffsetTable.getOffset((int) offset, cu); + return debugStrings.getStringAtOffset(strOffset); + + default: + throw new IOException("Unsupported string form: " + form); + } + } + + public StringTable getStringTable() { + return debugStrings; + } + + /** + * Returns the {@link DWARFRangeList} pointed at by the specified attribute. + * + * @param diea {@link DIEAggregate} + * @param attribute attribute id to find in the DIEA + * @return {@link DWARFRangeList}, or null if attribute is not present + * @throws IOException if error reading range list + */ + public DWARFRangeList getRangeList(DIEAggregate diea, DWARFAttributeId attribute) + throws IOException { + + DWARFAttribute rngListAttr = diea.findAttribute(attribute); + if (rngListAttr == null || + !(rngListAttr.getValue() instanceof DWARFNumericAttribute rngListVal)) { + return null; + } + + DWARFCompilationUnit cu = diea.getCompilationUnit(); + + switch (rngListAttr.getAttributeForm()) { + case DW_FORM_rnglistx: { // assumes v5 + int index = rngListVal.getUnsignedIntExact(); + long rnglistOffset = rangeListTable.getOffset(index, cu); + debugRngLists.setPointerIndex(rnglistOffset); + return DWARFRangeList.readV5(debugRngLists, cu); + } + case DW_FORM_sec_offset: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_data8: { + long rnglistOffset = rngListVal.getValue(); + short dwarfVersion = cu.getDWARFVersion(); + if (dwarfVersion < 5) { + debugRanges.setPointerIndex(rnglistOffset); + return DWARFRangeList.readV4(debugRanges, cu); + } + else if (dwarfVersion == 5) { + debugRngLists.setPointerIndex(rnglistOffset); + return DWARFRangeList.readV5(debugRngLists, cu); + } + break; + } + default: + break; // fall thru to throw + } + throw new IOException("Unsupported attribute form " + rngListAttr); + } + + /** + * Returns the DWARFLine info pointed to by the specified attribute. + * + * @param diea {@link DIEAggregate} + * @param attribute attribute id that points to the line info + * @return {@link DWARFLine}, never null, see {@link DWARFLine#empty()} + * @throws IOException if error reading line data + */ + public DWARFLine getLine(DIEAggregate diea, DWARFAttributeId attribute) throws IOException { + DWARFNumericAttribute attrib = diea.findValue(attribute, DWARFNumericAttribute.class); + if (attrib == null || debugLineBR == null) { + return DWARFLine.empty(); + } + long stmtListOffset = attrib.getUnsignedValue(); + return getLine(stmtListOffset, diea.getCompilationUnit(), true); + } + + public DWARFLine getLine(long offset, DWARFCompilationUnit cu, boolean readIfMissing) + throws IOException { + DWARFLine result = cachedDWARFLines.get(offset); + if (result == null && readIfMissing) { + result = DWARFLine.read(debugLineBR.clone(offset), dprog.getDefaultIntSize(), cu); + cachedDWARFLines.put(offset, result); + } + return result; + } + + public long getLineDataSize() { + return debugLineBR != null ? debugLineBR.length() : 0; + } + + public BinaryReader getDebugLineReader() { + return debugLineBR; + } + + public boolean hasLineInfo() { + return debugLineBR != null; + } + + public DWARFMacroHeader getMacroHeader(long offset, DWARFCompilationUnit cu) { + if (debugMacros != null) { + try { + return DWARFMacroHeader.readV5(debugMacros.clone(offset), cu); + } + catch (IOException e) { + // ignore, fall thru return emtpy + } + } + return DWARFMacroHeader.EMTPY; + } + + public List getMacroEntries(DWARFMacroHeader macroHeader) + throws IOException { + if (debugMacros == null) { + return List.of(); + } + + return DWARFMacroHeader.readMacroEntries( + debugMacros.clone(macroHeader.getEntriesStartOffset()), macroHeader); + } + + public int getPositionInParent(DebugInfoEntry die, Predicate dwTagFilter) { + int dieIndex = die.getIndex(); + int parentIndex = getParentIndex(dieIndex); + if (parentIndex < 0) { + return -1; + } + IntArrayList childIndexes = getDIEChildIndexes(parentIndex); + for (int i = 0, positionNum = 0; i < childIndexes.size(); i++) { + int childDIEIndex = childIndexes.get(i); + if (childDIEIndex == dieIndex) { + return positionNum; + } + DebugInfoEntry childDIE = getDIEByIndex(childDIEIndex); + if (childDIE != null && dwTagFilter.test(childDIE.getTag())) { + positionNum++; + } + } + // only way to get here is if our in-memory indexes are corrupt / incorrect + throw new RuntimeException("DWARF DIE index failure."); + } + + @Override + public DIEIterator iterator() { + return new DIEIterator(); + } + + public DIEIterator unreferencedDIEs() { + return new DIEHeadIterator(); + } + + private List getTypeReferers(DIEAggregate targetDIEA) { + List dieaOffsets = typeReferers.get(targetDIEA.getOffset()); + if (dieaOffsets == null) { + return List.of(); + } + return dieaOffsets.stream().map(dieaOffset -> getAggregate(dieaOffset)).toList(); + } + + /** + * Returns a list of {@link DIEAggregate}s that refer to the targetDIEA via an + * attribute of the specified tag type. + * + * @param targetDIEA {@link DIEAggregate} that might be pointed to by other DIEAs. + * @param tag the {@link DWARFTag} attribute type that is pointing DIEAs are using + * to refer to the target DIEA. + * @return list of DIEAs that point to the target, empty list if nothing found. + */ + public List getTypeReferers(DIEAggregate targetDIEA, DWARFTag tag) { + List result = new ArrayList<>(); + + for (DIEAggregate referer : getTypeReferers(targetDIEA)) { + if (referer.getTag() == tag) { + result.add(referer); + } + } + return result; + } + + private class DIEHeadIterator extends DIEIterator { + @Override + protected boolean includeDIE(int dieIndex) { + return !indexHasRef.get(dieIndex); + } + + @Override + public Iterator iterator() { + return this; + } + } + + private class DIEIterator 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 (includeDIE(i)) { + return i; + } + } + } + return i; + } + + protected boolean includeDIE(int dieIndex) { + return true; + } + + @Override + public Iterator iterator() { + return this; + } + + @Override + public boolean hasNext() { + if (index == -1) { + index = findNext(); + } + return 0 <= index && index < dieOffsets.length; + } + + @Override + public DebugInfoEntry next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + int resultIndex = index; + index = findNext(); + return getDIEByIndex(resultIndex); + } + + } + + 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/dwarf/DWARFAbbreviation.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java index db894edafd..f706e5aca7 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFAbbreviation.java @@ -23,8 +23,6 @@ import ghidra.app.util.bin.format.dwarf.attribs.*; import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId.AttrDef; import ghidra.program.model.data.LEB128; import ghidra.util.Msg; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; /** * This class represents the 'schema' for a DWARF DIE record. @@ -45,14 +43,12 @@ public class DWARFAbbreviation { * Reads a {@link DWARFAbbreviation} from the stream. * * @param reader {@link BinaryReader} stream - * @param prog {@link DWARFProgram} - * @param monitor {@link TaskMonitor} + * @param dieContainer {@link DIEContainer} * @return {@link DWARFAbbreviation}, or null if the stream was at a end-of-list marker * @throws IOException if error reading - * @throws CancelledException if canceled */ - public static DWARFAbbreviation read(BinaryReader reader, DWARFProgram prog, - TaskMonitor monitor) throws IOException, CancelledException { + public static DWARFAbbreviation read(BinaryReader reader, DIEContainer dieContainer) + throws IOException { int ac = reader.readNextUnsignedVarIntExact(LEB128::unsigned); if (ac == EOL) { @@ -65,8 +61,6 @@ public class DWARFAbbreviation { List tmpAttrSpecs = new ArrayList<>(); AttrDef attrSpec; while ((attrSpec = AttrDef.read(reader)) != null) { - monitor.checkCancelled(); - attrSpec = prog.internAttributeSpec(attrSpec); tmpAttrSpecs.add(attrSpec); warnIfMismatchedForms(attrSpec); } @@ -99,20 +93,17 @@ public class DWARFAbbreviation { * encountered. * * @param reader {@link BinaryReader} .debug_abbr stream - * @param prog {@link DWARFProgram} - * @param monitor {@link TaskMonitor} + * @param dieContainer {@link DIEContainer} * @return map of abbrCode -> abbr instance * @throws IOException if error reading - * @throws CancelledException if cancelled */ public static Map readAbbreviations(BinaryReader reader, - DWARFProgram prog, TaskMonitor monitor) throws IOException, CancelledException { + DIEContainer dieContainer) throws IOException { Map result = new HashMap<>(); // Read a list of abbreviations, terminated by a marker value that returns null from read() DWARFAbbreviation abbrev = null; - while ((abbrev = DWARFAbbreviation.read(reader, prog, monitor)) != null) { - monitor.checkCancelled(); + while ((abbrev = DWARFAbbreviation.read(reader, dieContainer)) != null) { result.put(abbrev.getAbbreviationCode(), abbrev); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java index 512232fd2a..6286bba425 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFCompilationUnit.java @@ -24,8 +24,6 @@ import java.util.Map; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.line.DWARFLine; import ghidra.app.util.bin.format.dwarf.macro.DWARFMacroHeader; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; /** * A DWARF CompilationUnit is a contiguous block of {@link DebugInfoEntry DIE} records found @@ -39,8 +37,7 @@ import ghidra.util.task.TaskMonitor; public class DWARFCompilationUnit extends DWARFUnitHeader { /** * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data - * from the debug_info section and the debug_abbr section and its compileUnit DIE (ie. - * the first DIE right after the header). + * from the debug_info section. *

* Returns {@code NULL} if there was an ignorable error while reading the compilation unit (and * leaves the input stream at the next compilation unit to read), otherwise throws @@ -51,17 +48,13 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { * * @param partial already read partial unit header * @param reader .debug_info BinaryReader - * @param abbrReader .debug_abbr BinaryReader - * @param monitor the current task monitor * @return the read compilation unit, or null if the compilation unit was bad/empty and should * be ignored * @throws DWARFException if an invalid or unsupported DWARF version is read. * @throws IOException if the length of the compilation unit is invalid. - * @throws CancelledException if the task has been canceled. */ - public static DWARFCompilationUnit readV4(DWARFUnitHeader partial, BinaryReader reader, - BinaryReader abbrReader, TaskMonitor monitor) - throws DWARFException, IOException, CancelledException { + public static DWARFCompilationUnit readV4(DWARFUnitHeader partial, BinaryReader reader) + throws DWARFException, IOException { long abbreviationOffset = reader.readNextUnsignedValue(partial.getIntSize()); byte pointerSize = reader.readNextByte(); @@ -76,19 +69,17 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { return null; } - abbrReader.setPointerIndex(abbreviationOffset); - Map abbrMap = - DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor); + Map abbrevs = + partial.getDIEContainer().getAbbrevs(abbreviationOffset); DWARFCompilationUnit cu = - new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrMap); + new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrevs); return cu; } /** * Creates a new {@link DWARFCompilationUnit} by reading a compilationUnit's header data - * from the debug_info section and the debug_abbr section and its compileUnit DIE (ie. - * the first DIE right after the header). + * from the debug_info section. *

* Returns {@code NULL} if there was an ignorable error while reading the compilation unit (and * leaves the input stream at the next compilation unit to read), otherwise throws @@ -99,17 +90,13 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { * * @param partial already read partial unit header * @param reader .debug_info BinaryReader - * @param abbrReader .debug_abbr BinaryReader - * @param monitor the current task monitor * @return the read compilation unit, or null if the compilation unit was bad/empty and should * be ignored * @throws DWARFException if an invalid or unsupported DWARF version is read. * @throws IOException if the length of the compilation unit is invalid. - * @throws CancelledException if the task has been canceled. */ - public static DWARFCompilationUnit readV5(DWARFUnitHeader partial, BinaryReader reader, - BinaryReader abbrReader, TaskMonitor monitor) - throws DWARFException, IOException, CancelledException { + public static DWARFCompilationUnit readV5(DWARFUnitHeader partial, BinaryReader reader) + throws DWARFException, IOException { byte pointerSize = reader.readNextByte(); long abbreviationOffset = reader.readNextUnsignedValue(partial.getIntSize()); @@ -125,12 +112,10 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { return null; } - abbrReader.setPointerIndex(abbreviationOffset); - Map abbrMap = - DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor); - + Map abbrevs = + partial.getDIEContainer().getAbbrevs(abbreviationOffset); DWARFCompilationUnit cu = - new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrMap); + new DWARFCompilationUnit(partial, pointerSize, firstDIEOffset, abbrevs); return cu; } @@ -168,20 +153,20 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { /** * This ctor is public only for junit tests. Do not use directly. * - * @param dwarfProgram {@link DWARFProgram} + * @param dieContainer holds all DIE records and related serialization info * @param startOffset offset in provider where it starts * @param endOffset offset in provider where it ends * @param intSize 4 (DWARF_32) or 8 (DWARF_64) * @param dwarfVersion 2-5 * @param pointerSize default size of pointers - * @param unitNumber this compunits ordinal in the file + * @param unitNumber this compunit's ordinal in the file * @param firstDIEOffset start of DIEs in the provider * @param codeToAbbreviationMap map of abbreviation numbers to {@link DWARFAbbreviation} instances */ - public DWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset, + public DWARFCompilationUnit(DIEContainer dieContainer, long startOffset, long endOffset, int intSize, short dwarfVersion, byte pointerSize, int unitNumber, long firstDIEOffset, Map codeToAbbreviationMap) { - super(dwarfProgram, startOffset, endOffset, intSize, dwarfVersion, unitNumber); + super(dieContainer, startOffset, endOffset, intSize, dwarfVersion, unitNumber); this.pointerSize = pointerSize; this.firstDIEOffset = firstDIEOffset; this.codeToAbbreviationMap = @@ -197,7 +182,7 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { */ public void init(DebugInfoEntry rootDIE) throws IOException { diea = DIEAggregate.createSingle(rootDIE); - line = getProgram().getLine(diea, DW_AT_stmt_list); + line = getDIEContainer().getLine(diea, DW_AT_stmt_list); } /** @@ -237,7 +222,7 @@ public class DWARFCompilationUnit extends DWARFUnitHeader { public DWARFMacroHeader getMacros() { long macrosOffset = diea.getUnsignedLong(DW_AT_macros, -1); return macrosOffset != -1 - ? diea.getProgram().getMacroHeader(macrosOffset, this) + ? getDIEContainer().getMacroHeader(macrosOffset, this) : DWARFMacroHeader.EMTPY; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java index 7b7c8fbb17..6bf4530140 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporter.java @@ -467,7 +467,7 @@ public class DWARFDataTypeImporter { // NOTE: gcc tends to emit values without an explicit signedness. The caller // can specify a default signedness, but this should probably always be unsigned. for (DebugInfoEntry childEntry : diea.getChildren(DW_TAG_enumerator)) { - DIEAggregate childDIEA = prog.getAggregate(childEntry); + DIEAggregate childDIEA = prog.getDIEContainer().getAggregate(childEntry); String valueName = childDIEA.getName(); DWARFNumericAttribute enumValAttr = childDIEA @@ -642,7 +642,7 @@ public class DWARFDataTypeImporter { UnionDataType union = (UnionDataType) ddt.dataType; for (DebugInfoEntry childEntry : diea.getChildren(DW_TAG_member)) { - DIEAggregate childDIEA = prog.getAggregate(childEntry); + DIEAggregate childDIEA = prog.getDIEContainer().getAggregate(childEntry); // skip static member vars as they do not have storage in the structure // C does not allow static member vars in unions @@ -836,7 +836,7 @@ public class DWARFDataTypeImporter { for (DebugInfoEntry childEntry : diea.getChildren(childTagType)) { - DIEAggregate childDIEA = prog.getAggregate(childEntry); + DIEAggregate childDIEA = prog.getDIEContainer().getAggregate(childEntry); // skip static member vars as they do not have storage in the structure if (childDIEA.hasAttribute(DW_AT_external)) { continue; @@ -1099,7 +1099,8 @@ public class DWARFDataTypeImporter { List dimensions = new ArrayList<>(); List subrangeDIEs = diea.getChildren(DW_TAG_subrange_type); for (int subRangeDIEIndex = 0; subRangeDIEIndex < subrangeDIEs.size(); subRangeDIEIndex++) { - DIEAggregate subrangeAggr = prog.getAggregate(subrangeDIEs.get(subRangeDIEIndex)); + DIEAggregate subrangeAggr = + prog.getDIEContainer().getAggregate(subrangeDIEs.get(subRangeDIEIndex)); long numElements = -1; try { if (subrangeAggr.hasAttribute(DW_AT_count)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java index 4a72f328f8..8e38092891 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporter.java @@ -331,7 +331,7 @@ public class DWARFFunctionImporter { // offsetFromFuncStart will be -1 if the containing block didn't have location info for (DebugInfoEntry childEntry : diea.getHeadFragment().getChildren()) { - DIEAggregate childDIEA = prog.getAggregate(childEntry); + DIEAggregate childDIEA = prog.getDIEContainer().getAggregate(childEntry); switch (childDIEA.getTag()) { case DW_TAG_variable: { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java index 444b101762..459c9d4e3d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImporter.java @@ -21,7 +21,6 @@ import java.util.*; import org.apache.commons.io.FilenameUtils; import ghidra.app.plugin.core.datamgr.util.DataTypeUtils; -import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.DWARFImportOptions.MacroEnumSetting; import ghidra.app.util.bin.format.dwarf.line.DWARFLine; import ghidra.app.util.bin.format.dwarf.line.DWARFLine.SourceFileAddr; @@ -39,7 +38,6 @@ import ghidra.program.model.sourcemap.SourceFileManager; import ghidra.util.*; import ghidra.util.exception.*; import ghidra.util.task.TaskMonitor; -import utility.function.Dummy; /** * Performs a DWARF datatype import and a DWARF function import, under the control of the @@ -102,7 +100,7 @@ public class DWARFImporter { if ((monitor.getProgress() % 5) == 0) { /* balance between getting work done and pampering the swing thread */ - Swing.runNow(Dummy.runnable()); + Swing.allowSwingToProcessEvents(); } DataType dataType = @@ -199,17 +197,11 @@ public class DWARFImporter { * "." and "/../" entries stripped and then be placed under artificial directories based on * {@code DEFAULT_COMPILATION_DIR}. * - * @param reader reader * @throws CancelledException if cancelled by user * @throws IOException if error during reading * @throws LockException if invoked without exclusive access */ - private void addSourceLineInfo(BinaryReader reader) - throws CancelledException, IOException, LockException { - if (reader == null) { - Msg.warn(this, "Can't add source line info - reader is null"); - return; - } + private void addSourceLineInfo() throws CancelledException, IOException, LockException { int entryCount = 0; Program ghidraProgram = prog.getGhidraProgram(); long maxLength = prog.getImportOptions().getMaxSourceMapEntryLength(); @@ -223,7 +215,7 @@ public class DWARFImporter { List sourceInfo = new ArrayList<>(); for (DWARFCompilationUnit cu : compUnits) { DWARFLine dLine = cu.getLine(); - monitor.increment(1); + monitor.increment(); for (SourceFileInfo sfi : dLine.getAllSourceFileInfos()) { if (sourceFileInfoToSourceFile.containsKey(sfi)) { continue; @@ -249,7 +241,7 @@ public class DWARFImporter { continue; } } - sourceInfo.addAll(cu.getLine().getAllSourceFileAddrInfo(cu, reader)); + sourceInfo.addAll(cu.getLine().getAllSourceFileAddrInfo(cu)); } int sourceInfoSize = sourceInfo.size(); @@ -263,7 +255,7 @@ public class DWARFImporter { AddressSet warnedAddresses = new AddressSet(); for (int i = 0; i < sourceInfo.size(); i++) { - monitor.increment(1); + monitor.increment(); SourceFileAddr sfa = sourceInfo.get(i); if (SOURCEFILENAMES_IGNORE.contains(sfa.fileName()) || SOURCEFILENAMES_IGNORE.contains(FilenameUtils.getName(sfa.fileName())) || @@ -424,7 +416,7 @@ public class DWARFImporter { } else { try { - addSourceLineInfo(prog.getDebugLineBR()); + addSourceLineInfo(); } catch (LockException e) { throw new AssertException("LockException after exclusive access verified"); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java index 13fcfb1c53..7230f6ab86 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationList.java @@ -102,7 +102,7 @@ public class DWARFLocationList { public static DWARFLocationList readV5(BinaryReader reader, DWARFCompilationUnit cu) throws IOException { long baseAddr = cu.getPCRange().getFrom(); - DWARFProgram dprog = cu.getProgram(); + DIEContainer dieContainer = cu.getDIEContainer(); List list = new ArrayList<>(); while (reader.hasNext()) { @@ -113,15 +113,15 @@ public class DWARFLocationList { switch (lleId) { case DW_LLE_base_addressx: { int addrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); - baseAddr = dprog.getAddress(DW_FORM_addrx, addrIndex, cu); + baseAddr = dieContainer.getAddress(DW_FORM_addrx, addrIndex, cu); break; } case DW_LLE_startx_endx: { int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); int endAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray); - long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu); - long end = dprog.getAddress(DW_FORM_addrx, endAddrIndex, cu); + long start = dieContainer.getAddress(DW_FORM_addrx, startAddrIndex, cu); + long end = dieContainer.getAddress(DW_FORM_addrx, endAddrIndex, cu); list.add(new DWARFLocation(start, end, expr)); break; } @@ -129,7 +129,7 @@ public class DWARFLocationList { int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned); byte[] expr = reader.readNext(DWARFLocationList::uleb128SizedByteArray); - long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu); + long start = dieContainer.getAddress(DW_FORM_addrx, startAddrIndex, cu); list.add(new DWARFLocation(start, start + len, expr)); break; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java index 92e4b80542..6243777768 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFLocationListHeader.java @@ -18,11 +18,11 @@ package ghidra.app.util.bin.format.dwarf; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames; +import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId; /** * Header found at the start of a set of DWARFLocationList entries, which are stored sequentially - * in the {@link DWARFSectionNames#DEBUG_LOCLISTS .debug_loclists} section. + * in the {@link DWARFSectionId#DEBUG_LOCLISTS .debug_loclists} section. */ public class DWARFLocationListHeader extends DWARFIndirectTableHeader { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java index bee47c24cb..b1275206c4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFProgram.java @@ -18,24 +18,16 @@ package ghidra.app.util.bin.format.dwarf; import static ghidra.app.util.bin.format.dwarf.DWARFTag.*; import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId.*; -import java.io.*; +import java.io.Closeable; +import java.io.IOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.Map.Entry; -import java.util.function.Predicate; -import org.apache.commons.collections4.ListValuedMap; -import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; - -import ghidra.app.util.bin.*; -import ghidra.app.util.bin.format.dwarf.attribs.*; +import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId; import ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionException; import ghidra.app.util.bin.format.dwarf.external.ExternalDebugInfo; import ghidra.app.util.bin.format.dwarf.funcfixup.DWARFFunctionFixup; -import ghidra.app.util.bin.format.dwarf.line.DWARFLine; -import ghidra.app.util.bin.format.dwarf.macro.DWARFMacroHeader; -import ghidra.app.util.bin.format.dwarf.macro.entry.DWARFMacroInfoEntry; import ghidra.app.util.bin.format.dwarf.sectionprovider.*; import ghidra.app.util.bin.format.golang.rtti.GoSymbolName; import ghidra.app.util.opinion.*; @@ -45,7 +37,7 @@ import ghidra.program.model.data.CategoryPath; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.SymbolUtilities; import ghidra.util.Msg; -import ghidra.util.datastruct.*; +import ghidra.util.datastruct.FixedSizeHashMap; import ghidra.util.exception.CancelledException; import ghidra.util.task.TaskMonitor; @@ -97,7 +89,7 @@ public class DWARFProgram implements Closeable { // as compressed sections try (DWARFSectionProvider tmp = new CompressedSectionProvider(new BaseSectionProvider(program))) { - return tmp.hasSection(DWARFSectionNames.MINIMAL_DWARF_SECTIONS); + return tmp.hasSection(DWARFSectionId.MINIMAL_DWARF_SECTIONS); } } @@ -127,75 +119,20 @@ public class DWARFProgram implements Closeable { private DWARFName unCatDataTypeRoot = DWARFName.createRoot(UNCAT_CATPATH); private DWARFImportOptions importOptions; private DWARFImportSummary importSummary = new DWARFImportSummary(); - private DWARFSectionProvider sectionProvider; - private StringTable debugStrings; - private StringTable lineStrings; + protected long programBaseAddressFixup; private Charset charset; - private int totalAggregateCount; - private long programBaseAddressFixup; private int maxDNICacheSize = 50; private FixedSizeHashMap dniCache = new FixedSizeHashMap<>(100, maxDNICacheSize); - private Map attributeSpecIntern = - new HashMap<>(); - private DWARFRegisterMappings dwarfRegisterMappings; private final boolean stackGrowsNegative; private List functionFixups; - // BinaryReaders for each of the various dwarf sections - private BinaryReader debugLocation; - private BinaryReader debugLocLists; // v5+ - private BinaryReader debugRanges; - private BinaryReader debugRngLists; // v5+ - private BinaryReader debugInfoBR; - private BinaryReader debugLineBR; - private BinaryReader debugAbbrBR; - private BinaryReader debugAddr; // v5+ - private BinaryReader debugStrOffsets; // v5+ - private BinaryReader debugMacros; // v5+ - - // dieOffsets, siblingIndexes, parentIndexes contain for each DIE the information needed - // to read each DIE and to navigate to parent / child / sibling elements. - // Each DIE record in the binary will consume 8+4+4=16 bytes of ram in these indexes. - // DIE instances do not keep references to other DIEs. - protected long[] dieOffsets = new long[0]; // offset in the debuginfo stream of this DIE - protected int[] siblingIndexes = new int[0]; // index of each DIE's next sibling. - protected int[] parentIndexes = new int[0]; // index of each DIE's parent record, or -1 for root - - // 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<>(); - - // Indirect tables, added with dwarf v5, provide an index -> offset lookup feature for - // index values such as DW_FORM_addrx or DW_FORM_strx and other similar 'x' attribute values. - // Each DWARFIndirectTable is made of per-CU lookup arrays held in a DWARFIndirectTableHeader. - private DWARFIndirectTable addressListTable; // DWARFAddressListHeaders, DW_AT_addr_base - private DWARFIndirectTable locationListTable; // DWARFLocationListHeaders, DW_AT_rgnlists_base - private DWARFIndirectTable rangeListTable; // DWARFRangeListHeaders, DW_AT_rgnlists_base - private DWARFIndirectTable stringsOffsetTable; // DWARFStringOffsetTableHeader, DW_AT_str_offsets_base - - // boolean flag, per die record, indicating that the DIE is the target of another DIE via - // an aggregate reference, and therefore not the root DIE record of an aggregate. - protected BitSet indexHasRef = new BitSet(); - - // 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 DIEAggregates that are being pointed to by - // other DIEAggregates with a DW_AT_type property. - // In other words, a map of inbound links to a DIEA. - private ListValuedMap typeReferers = new ArrayListValuedHashMap<>(); - - private Map cachedDWARFLines = new HashMap<>(); + protected DIEContainer dieContainer; /** * Main constructor for DWARFProgram. @@ -211,7 +148,7 @@ public class DWARFProgram implements Closeable { */ public DWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor) throws CancelledException, IOException, DWARFException { - this(program, importOptions, monitor, + this(program, importOptions, DWARFSectionProviderFactory.createSectionProviderFor(program, monitor)); } @@ -220,15 +157,12 @@ public class DWARFProgram implements Closeable { * * @param program Ghidra {@link Program}. * @param importOptions {@link DWARFImportOptions} to controls options during reading / parsing /importing. - * @param monitor {@link TaskMonitor} to control canceling and progress. * @param sectionProvider {@link DWARFSectionProvider} factory that finds DWARF .debug_* sections * wherever they live. - * @throws CancelledException if user cancels * @throws IOException if error reading data - * @throws DWARFException if bad stuff happens. */ - public DWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor, - DWARFSectionProvider sectionProvider) throws CancelledException, IOException { + public DWARFProgram(Program program, DWARFImportOptions importOptions, + DWARFSectionProvider sectionProvider) throws IOException { if (sectionProvider == null) { throw new IllegalArgumentException("Null DWARFSectionProvider"); } @@ -239,51 +173,18 @@ public class DWARFProgram implements Closeable { this.dwarfDTM = new DWARFDataTypeManager(this, program.getDataTypeManager()); this.stackGrowsNegative = program.getCompilerSpec().stackGrowsNegative(); - this.debugInfoBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_INFO, monitor); - this.debugAbbrBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_ABBREV, monitor); - - this.debugLocation = getBinaryReaderFor(DWARFSectionNames.DEBUG_LOC, monitor); - this.debugLocLists = getBinaryReaderFor(DWARFSectionNames.DEBUG_LOCLISTS, monitor); - - this.debugRanges = getBinaryReaderFor(DWARFSectionNames.DEBUG_RANGES, monitor); - this.debugRngLists = getBinaryReaderFor(DWARFSectionNames.DEBUG_RNGLISTS, monitor); - - this.debugLineBR = getBinaryReaderFor(DWARFSectionNames.DEBUG_LINE, monitor); - this.debugAddr = getBinaryReaderFor(DWARFSectionNames.DEBUG_ADDR, monitor); - this.debugStrOffsets = getBinaryReaderFor(DWARFSectionNames.DEBUG_STROFFSETS, monitor); - - this.debugMacros = getBinaryReaderFor(DWARFSectionNames.DEBUG_MACRO, monitor); - - this.rangeListTable = - new DWARFIndirectTable(this.debugRngLists, DWARFCompilationUnit::getRangeListsBase); - this.addressListTable = - new DWARFIndirectTable(this.debugAddr, DWARFCompilationUnit::getAddrTableBase); - this.stringsOffsetTable = - new DWARFIndirectTable(this.debugStrOffsets, DWARFCompilationUnit::getStrOffsetsBase); - this.locationListTable = - new DWARFIndirectTable(this.debugLocLists, DWARFCompilationUnit::getLocListsBase); - this.charset = importOptions.getCharset(StandardCharsets.UTF_8); - this.debugStrings = - StringTable.of(getBinaryReaderFor(DWARFSectionNames.DEBUG_STR, monitor), charset); - this.lineStrings = - StringTable.of(getBinaryReaderFor(DWARFSectionNames.DEBUG_LINE_STR, monitor), charset); - - // 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); - if (oib != null && oib.longValue() != program.getImageBase().getOffset()) { - this.programBaseAddressFixup = program.getImageBase().getOffset() - oib.longValue(); - } - } dwarfRegisterMappings = DWARFRegisterMappingsManager.hasDWARFRegisterMapping(program.getLanguage()) ? DWARFRegisterMappingsManager.getMappingForLang(program.getLanguage()) : null; + + dieContainer = new DIEContainer(this); + } + + public DIEContainer getDIEContainer() { + return dieContainer; } /** @@ -295,192 +196,8 @@ public class DWARFProgram implements Closeable { * @throws CancelledException if cancelled */ public void init(TaskMonitor monitor) throws IOException, DWARFException, CancelledException { - bootstrapCompilationUnits(monitor); - - int defaultIntSize = getDefaultIntSize(); - rangeListTable.bootstrap("DWARF: Bootstrapping Range Lists", - reader -> DWARFRangeListHeader.read(reader, defaultIntSize), monitor); - locationListTable.bootstrap("DWARF: Bootstrapping Location Lists", - reader -> DWARFLocationListHeader.read(reader, defaultIntSize), monitor); - addressListTable.bootstrap("DWARF: Bootstrapping Address Lists", - reader -> DWARFAddressListHeader.read(reader, defaultIntSize), monitor); - stringsOffsetTable.bootstrap("DWARF: Bootstrapping String Offset Lists", - reader -> DWARFStringOffsetTableHeader.readV5(reader, defaultIntSize), monitor); - - indexDIEs(monitor); - indexDIEATypeRefs(monitor); - - importSummary.addCompunitInfo(compUnits); - } - - private void bootstrapCompilationUnits(TaskMonitor monitor) - throws CancelledException, IOException, DWARFException { - - debugInfoBR.setPointerIndex(0); - monitor.initialize(debugInfoBR.length(), "DWARF: Bootstrapping Compilation Units"); - while (debugInfoBR.hasNext()) { - monitor.checkCancelled(); - monitor.setProgress(debugInfoBR.getPointerIndex()); - monitor.setMessage("DWARF: Bootstrapping Compilation Unit #" + compUnits.size()); - - DWARFUnitHeader unitHeader = - DWARFUnitHeader.read(this, debugInfoBR, debugAbbrBR, compUnits.size(), monitor); - if (unitHeader == null) { - break; - } - - debugInfoBR.setPointerIndex(unitHeader.getEndOffset()); - if (unitHeader instanceof DWARFCompilationUnit cu) { - compUnits.add(cu); - importSummary.dwarfVers.add((int) cu.getDWARFVersion()); - } - else { - Msg.info(this, "Unsupported unit header: " + unitHeader + " at " + - unitHeader.getStartOffset()); - } - } - importSummary.compUnitCount = compUnits.size(); - } - - private void indexDIEs(TaskMonitor monitor) throws CancelledException, IOException { - LongArrayList dieOffsetList = new LongArrayList(); - IntArrayList siblingIndexList = new IntArrayList(); - IntArrayList parentIndexList = new IntArrayList(); - 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.getUnitNumber() + 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; - - importSummary.dieCount = 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.getOffset()); - } - } - monitor.initialize(0, ""); - } - - 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 indexDIEsForCU(DWARFCompilationUnit cu, LongArrayList dieOffsetList, - IntArrayList parentIndexList, IntArrayList siblingIndexList, LongArrayList aggrTargets, - TaskMonitor monitor) throws CancelledException, DWARFException { - 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); - - 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; - } - - if (die.getOffset() == cu.getFirstDIEOffset()) { - cu.init(die); - } - - DIEAggregate diea = DIEAggregate.createSingle(die); - for (DWARFAttributeId attrId : REF_ATTRS) { - DWARFAttribute refAttr = diea.findAttribute(attrId); - if (refAttr != null && - refAttr.getValue() instanceof DWARFNumericAttribute refVal) { - long refdOffset = getLocalDIEOffset(refAttr.getAttributeForm(), - refVal.getUnsignedValue(), cu); - aggrTargets.add(refdOffset); - } - } - - diesByOffset.put(startOfDIE, die); - } - catch (DWARFException e) { - throw e; - } - 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: %s" - .formatted(startOfDIE, cu.getUnitNumber(), cu.getStartOffset(), - Objects.requireNonNullElse(e.getMessage(), "unspecified"))); - Msg.debug(this, "Error location", 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); - } + dieContainer.init(monitor); + dieContainer.indexData(monitor); } @Override @@ -488,40 +205,11 @@ public class DWARFProgram implements Closeable { if (sectionProvider != null) { sectionProvider.close(); } - if (debugStrings != null) { - debugStrings.clear(); - debugStrings = null; + if (dieContainer != null) { + dieContainer.close(); } - if (lineStrings != null) { - lineStrings.clear(); - lineStrings = null; - } - compUnits.clear(); dniCache.clear(); - debugAbbrBR = null; - debugInfoBR = null; - debugLineBR = null; - debugLocation = null; - debugLocLists = null; - debugRanges = null; - debugRngLists = null; - debugAddr = null; - - dieOffsets = new long[0]; - parentIndexes = new int[0]; - siblingIndexes = new int[0]; - indexHasRef.clear(); - aggsByOffset.clear(); - diesByOffset.clear(); - typeReferers.clear(); - compUnitDieIndex.clear(); - - locationListTable.clear(); - rangeListTable.clear(); - stringsOffsetTable.clear(); - addressListTable.clear(); - if (functionFixups != null) { for (DWARFFunctionFixup funcFixup : functionFixups) { if (funcFixup instanceof Closeable c) { @@ -550,7 +238,7 @@ public class DWARFProgram implements Closeable { } public List getCompilationUnits() { - return compUnits; + return dieContainer.getCompilationUnits(); } public boolean isBigEndian() { @@ -561,30 +249,8 @@ public class DWARFProgram implements Closeable { return !program.getLanguage().isBigEndian(); } - public BinaryReader getDebugLineBR() { - return debugLineBR; - } - - private BinaryReader getBinaryReaderFor(String sectionName, TaskMonitor monitor) - throws IOException { - ByteProvider bp = sectionProvider.getSectionAsByteProvider(sectionName, monitor); - return (bp != null) ? new BinaryReader(bp, isLittleEndian()) : null; - } - - private boolean hasRelocations(BinaryReader br) { - if (br == null) { - return false; - } - ByteProvider bp = br.getByteProvider(); - if (bp instanceof MemoryByteProvider mbp && !mbp.isEmpty()) { - Program providerProgram = mbp.getMemory().getProgram(); - if (providerProgram.getRelocationTable() - .getRelocations(mbp.getAddressSet()) - .hasNext()) { - return true; - } - } - return false; + public DWARFSectionProvider getSectionProvider() { + return sectionProvider; } private static boolean isAnonDWARFName(String name) { @@ -653,7 +319,7 @@ public class DWARFProgram implements Closeable { if (name == null) { // check to see if there is a single inbound typedef that we can steal its name. - List referers = getTypeReferers(diea, DW_TAG_typedef); + List referers = dieContainer.getTypeReferers(diea, DW_TAG_typedef); if (referers.size() == 1) { return getDWARFName(referers.get(0), localRootDNI); } @@ -664,8 +330,7 @@ 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.getProgram().getTypeReferers(diea, DW_TAG_member); + List referringMembers = dieContainer.getTypeReferers(diea, DW_TAG_member); String referringMemberNames = getReferringMemberFieldNames(referringMembers); if (!referringMemberNames.isEmpty()) { @@ -699,8 +364,8 @@ public class DWARFProgram implements Closeable { name = "lexical_block" + getLexicalBlockNameWorker(diea.getHeadFragment()); break; case DW_TAG_formal_parameter: - name = "param_%d".formatted(getPositionInParent(diea.getHeadFragment(), - dietag -> dietag == DW_TAG_formal_parameter)); + name = "param_%d".formatted(dieContainer.getPositionInParent( + diea.getHeadFragment(), dietag -> dietag == DW_TAG_formal_parameter)); isAnon = true; break; case DW_TAG_subprogram: @@ -742,24 +407,6 @@ public class DWARFProgram implements Closeable { return result; } - /** - * Returns the {@link DIEAggregate} of a typedef that points to the specified datatype. - *

- * Returns null if there is no typedef pointing to the specified DIEA or if there are - * multiple. - * - * @param diea {@link DIEAggregate} of a data type that might be the target of typedefs. - * @return {@link DIEAggregate} of the singular typedef that points to the arg, otherwise - * null if none or multiple found. - */ - public static DIEAggregate getReferringTypedef(DIEAggregate diea) { - if (diea == null) { - return null; - } - List referers = diea.getProgram().getTypeReferers(diea, DW_TAG_typedef); - return (referers.size() == 1) ? referers.get(0) : null; - } - private String getAnonBaseTypeName(DIEAggregate diea) { try { int dwarfSize = diea.parseInt(DW_AT_byte_size, 0); @@ -784,7 +431,7 @@ public class DWARFProgram implements Closeable { private String getLexicalBlockNameWorker(DebugInfoEntry die) { if (isLexicalBlockTag(die.getTag())) { return "%s_%d".formatted(getLexicalBlockNameWorker(die.getParent()), - getPositionInParent(die, this::isLexicalBlockTag)); + dieContainer.getPositionInParent(die, this::isLexicalBlockTag)); } return ""; } @@ -808,7 +455,7 @@ public class DWARFProgram implements Closeable { String memberName = referringMember.getName(); if (memberName == null) { int positionInParent = - getPositionInParent(referringMember.getHeadFragment(), x -> true); + dieContainer.getPositionInParent(referringMember.getHeadFragment(), x -> true); if (positionInParent == -1) { continue; } @@ -890,192 +537,6 @@ public class DWARFProgram implements Closeable { 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; - } - - /** - * 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 int getParentIndex(int dieIndex) { - return parentIndexes[dieIndex]; - } - - /** - * 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; - } - - /** - * 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; - } - - /** - * 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 - */ - private 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; - } - - public int getChildCount(int dieIndex) { - int result = 0; - if (dieIndex >= 0) { - int parentSiblingIndex = siblingIndexes[dieIndex]; - for (int index = dieIndex + 1; index < parentSiblingIndex; index = - siblingIndexes[index]) { - result++; - } - } - 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); - 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}. - * - * @param die {@link DebugInfoEntry} or null - * @return {@link DIEAggregate} that contains the specified DIE, or null if DIE null or - * the aggregate was not found. - */ - public DIEAggregate getAggregate(DebugInfoEntry die) { - DIEAggregate diea = (die != null) ? aggsByOffset.get(die.getOffset()) : null; - if (diea == null && die != null) { - diea = DIEAggregate.createFromHead(die); - aggsByOffset.put(die.getOffset(), diea); - } - 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 dieOffset offset of a DIE record - * @return {@link DIEAggregate} that contains the DIE record specified, or null if bad - * offset. - */ - public DIEAggregate getAggregate(long dieOffset) { - DIEAggregate diea = aggsByOffset.get(dieOffset); - if (diea != null) { - return diea; - } - DebugInfoEntry die = getDIEByOffset(dieOffset); - return getAggregate(die); - } - /** * {@return charset to use when decoding debug strings} */ @@ -1083,280 +544,7 @@ public class DWARFProgram implements Closeable { return charset; } - /** - * Returns a DWARF attribute string value, as specified by a form, offset/index, and the cu. - * - * @param form {@link DWARFForm} - * @param offset offset or index of the value - * @param cu {@link DWARFCompilationUnit} - * @return String value, never null - * @throws IOException if invalid form or bad offset/index - */ - public String getString(DWARFForm form, long offset, DWARFCompilationUnit cu) - throws IOException { - switch (form) { - case DW_FORM_line_strp: - return lineStrings.getStringAtOffset(offset); - case DW_FORM_strp: - return debugStrings.getStringAtOffset(offset); - case DW_FORM_gnu_strp_alt: - case DW_FORM_gnu_str_index: - throw new IOException("Unsupported DWARF string attribute form " + form); - case DW_FORM_strx, DW_FORM_strx1, DW_FORM_strx2, DW_FORM_strx3, DW_FORM_strx4: - long strOffset = stringsOffsetTable.getOffset((int) offset, cu); - return debugStrings.getStringAtOffset(strOffset); - default: - throw new IOException("Unsupported string form: " + form); - } - } - - private long getLocalDIEOffset(DWARFForm form, long rawOffset, DWARFCompilationUnit cu) - throws DWARFException { - switch (form) { - case DW_FORM_ref1, DW_FORM_ref2, DW_FORM_ref4, DW_FORM_ref8, DW_FORM_ref_udata: - return rawOffset + cu.getStartOffset(); - case DW_FORM_ref_addr: - return rawOffset; - case DW_FORM_gnu_ref_alt: - throw new DWARFException("Unsupported DIE reference form: " + form); - default: - Msg.warn(this, "Nontypical form %s used for reference".formatted(form)); - return rawOffset; - } - } - - /** - * Return the DIE referenced by an attribute value (a DW_FORM and offset) - * - * @param form {@link DWARFForm} - * @param rawOffset index / offset from the numeric attribute - * @param cu compilation unit containing the value - * @return {@link DebugInfoEntry}, or null if doesn't exist - * @throws IOException if unsupported format for reference - */ - public DebugInfoEntry getDIE(DWARFForm form, long rawOffset, DWARFCompilationUnit cu) - throws IOException { - return getDIEByOffset(getLocalDIEOffset(form, rawOffset, cu)); - } - - /** - * Returns the {@link DWARFRangeList} pointed at by the specified attribute. - * - * @param diea {@link DIEAggregate} - * @param attribute attribute id to find in the DIEA - * @return {@link DWARFRangeList}, or null if attribute is not present - * @throws IOException if error reading range list - */ - public DWARFRangeList getRangeList(DIEAggregate diea, DWARFAttributeId attribute) - throws IOException { - - DWARFAttribute rngListAttr = diea.findAttribute(attribute); - if (rngListAttr == null || - !(rngListAttr.getValue() instanceof DWARFNumericAttribute rngListVal)) { - return null; - } - - DWARFCompilationUnit cu = diea.getCompilationUnit(); - - switch (rngListAttr.getAttributeForm()) { - case DW_FORM_rnglistx: { // assumes v5 - int index = rngListVal.getUnsignedIntExact(); - long rnglistOffset = rangeListTable.getOffset(index, cu); - debugRngLists.setPointerIndex(rnglistOffset); - return DWARFRangeList.readV5(debugRngLists, cu); - } - case DW_FORM_sec_offset: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: { - long rnglistOffset = rngListVal.getValue(); - short dwarfVersion = cu.getDWARFVersion(); - if (dwarfVersion < 5) { - debugRanges.setPointerIndex(rnglistOffset); - return DWARFRangeList.readV4(debugRanges, cu); - } - else if (dwarfVersion == 5) { - debugRngLists.setPointerIndex(rnglistOffset); - return DWARFRangeList.readV5(debugRngLists, cu); - } - break; - } - default: - break; // fall thru to throw - } - throw new IOException("Unsupported attribute form " + rngListAttr); - } - - /** - * Returns the raw offset of an indexed item. For DW_FORM_addrx values, the returned value - * is not fixed up with Ghidra load offset. - * - * @param form {@link DWARFForm} of the index - * @param index int index into a lookup table (see {@link #addressListTable}, - * {@link #locationListTable}, {@link #rangeListTable}, {@link #stringsOffsetTable}) - * @param cu {@link DWARFCompilationUnit} - * @return raw offset of indexed item - * @throws IOException if error reading index table - */ - public long getOffsetOfIndexedElement(DWARFForm form, int index, DWARFCompilationUnit cu) - throws IOException { - DWARFIndirectTable table = switch (form) { - case DW_FORM_addrx: - case DW_FORM_addrx1: - case DW_FORM_addrx2: - case DW_FORM_addrx3: - case DW_FORM_addrx4: - yield addressListTable; - case DW_FORM_rnglistx: - yield rangeListTable; - case DW_FORM_loclistx: - yield locationListTable; - case DW_FORM_strx: - case DW_FORM_strx1: - case DW_FORM_strx2: - case DW_FORM_strx3: - case DW_FORM_strx4: - yield stringsOffsetTable; - default: - yield null; - }; - return table != null ? table.getOffset(index, cu) : -1; - } - - /** - * Returns an address value. - * - * @param form the format of the numeric value - * @param value raw offset or indirect address index (depending on the DWARFForm) - * @param cu {@link DWARFCompilationUnit} - * @return address - * @throws IOException if error reading indirect lookup tables - */ - public long getAddress(DWARFForm form, long value, DWARFCompilationUnit cu) throws IOException { - switch (form) { - case DW_FORM_addr: - case DW_FORM_udata: - return value; - case DW_FORM_addrx: - case DW_FORM_addrx1: - case DW_FORM_addrx2: - case DW_FORM_addrx3: - case DW_FORM_addrx4: { - long addr = addressListTable.getOffset((int) value, cu); - return addr; - } - case DW_FORM_gnu_addr_index: - default: - throw new IOException("Unsupported form %s".formatted(form)); - } - } - - /** - * Returns the {@link DWARFLocationList} pointed to by the specified attribute value. - * - * @param diea {@link DIEAggregate} - * @param attrId attribute id that points to the location list - * @return {@link DWARFLocationList}, never null - * @throws IOException if specified attribute is not the correct type, or if other error reading - * data - */ - public DWARFLocationList getLocationList(DIEAggregate diea, DWARFAttributeId attrId) - throws IOException { - DWARFAttribute attrib = diea.findAttribute(attrId); - if (attrib == null) { - return DWARFLocationList.EMPTY; - } - return switch (attrib.getValue()) { - case DWARFNumericAttribute dnum -> readLocationList(attrib, dnum); - case DWARFBlobAttribute dblob -> DWARFLocationList.withWildcardRange(dblob.getBytes()); - default -> throw new IOException("Unsupported form %s.".formatted(attrib)); - }; - } - - private DWARFLocationList readLocationList(DWARFAttribute attr, DWARFNumericAttribute val) - throws IOException { - try { - DWARFCompilationUnit cu = attr.getCU(); - switch (attr.getAttributeForm()) { - case DW_FORM_sec_offset: - case DW_FORM_data2: - case DW_FORM_data4: - case DW_FORM_data8: - int dwarfVer = cu.getDWARFVersion(); - if (dwarfVer < 5) { - debugLocation.setPointerIndex(val.getUnsignedValue()); - return DWARFLocationList.readV4(debugLocation, cu); - } - else if (dwarfVer == 5) { - debugLocLists.setPointerIndex(val.getUnsignedValue()); - return DWARFLocationList.readV5(debugLocLists, cu); - } - break; - case DW_FORM_loclistx: - int index = val.getUnsignedIntExact(); - long locOffset = locationListTable.getOffset(index, cu); - debugLocLists.setPointerIndex(locOffset); - return DWARFLocationList.readV5(debugLocLists, cu); - default: - break; // fallthru to throw - } - } - catch (IOException | IllegalArgumentException e) { - throw new IOException( - "Failed to read location list specified by %s".formatted(attr.toString()), e); - } - throw new IOException("Unsupported loclist form %s".formatted(attr.getAttributeForm())); - } - - /** - * Returns the DWARFLine info pointed to by the specified attribute. - * - * @param diea {@link DIEAggregate} - * @param attribute attribute id that points to the line info - * @return {@link DWARFLine}, never null, see {@link DWARFLine#empty()} - * @throws IOException if error reading line data - */ - public DWARFLine getLine(DIEAggregate diea, DWARFAttributeId attribute) throws IOException { - DWARFNumericAttribute attrib = diea.findValue(attribute, DWARFNumericAttribute.class); - if (attrib == null || debugLineBR == null) { - return DWARFLine.empty(); - } - long stmtListOffset = attrib.getUnsignedValue(); - return getLine(stmtListOffset, diea.getCompilationUnit(), true); - } - - public DWARFLine getLine(long offset, DWARFCompilationUnit cu, boolean readIfMissing) - throws IOException { - DWARFLine result = cachedDWARFLines.get(offset); - if (result == null && readIfMissing) { - result = DWARFLine.read(debugLineBR.clone(offset), getDefaultIntSize(), cu); - cachedDWARFLines.put(offset, result); - } - return result; - } - - public DWARFMacroHeader getMacroHeader(long offset, DWARFCompilationUnit cu) { - if (debugMacros != null) { - try { - return DWARFMacroHeader.readV5(debugMacros.clone(offset), cu); - } - catch (IOException e) { - // ignore, fall thru return emtpy - } - } - return DWARFMacroHeader.EMTPY; - } - - public List getMacroEntries(DWARFMacroHeader macroHeader) - throws IOException { - if (debugMacros == null) { - return List.of(); - } - - return DWARFMacroHeader.readMacroEntries( - debugMacros.clone(macroHeader.getEntriesStartOffset()), macroHeader); - } /** * Returns iterable that traverses all {@link DIEAggregate}s in the program. @@ -1364,7 +552,7 @@ public class DWARFProgram implements Closeable { * @return sequence of {@link DIEAggregate}es */ public Iterable allAggregates() { - return new DIEAggregateIterator(); + return dieContainer.allAggregates(); } /** @@ -1373,11 +561,7 @@ public class DWARFProgram implements Closeable { * @return the total number of {@link DIEAggregate} objects in the entire program. */ public int getTotalAggregateCount() { - return totalAggregateCount; - } - - public BinaryReader getReaderForCompUnit(DWARFCompilationUnit cu) { - return debugInfoBR; + return dieContainer.getTotalAggregateCount(); } public DWARFRegisterMappings getRegisterMappings() { @@ -1396,43 +580,6 @@ public class DWARFProgram implements Closeable { return program.getAddressFactory().getStackSpace(); } - public DWARFAttributeId.AttrDef internAttributeSpec(DWARFAttributeId.AttrDef das) { - DWARFAttributeId.AttrDef inDAS = attributeSpecIntern.get(das); - if (inDAS == null) { - inDAS = das; - attributeSpecIntern.put(inDAS, inDAS); - } - return inDAS; - } - - private List getTypeReferers(DIEAggregate targetDIEA) { - List dieaOffsets = typeReferers.get(targetDIEA.getOffset()); - if (dieaOffsets == null) { - return List.of(); - } - return dieaOffsets.stream().map(dieaOffset -> getAggregate(dieaOffset)).toList(); - } - - /** - * Returns a list of {@link DIEAggregate}s that refer to the targetDIEA via an - * attribute of the specified tag type. - * - * @param targetDIEA {@link DIEAggregate} that might be pointed to by other DIEAs. - * @param tag the {@link DWARFTag} attribute type that is pointing DIEAs are using - * to refer to the target DIEA. - * @return list of DIEAs that point to the target, empty list if nothing found. - */ - public List getTypeReferers(DIEAggregate targetDIEA, DWARFTag tag) { - List result = new ArrayList<>(); - - for (DIEAggregate referer : getTypeReferers(targetDIEA)) { - if (referer.getTag() == tag) { - result.add(referer); - } - } - return result; - } - /** * A fixup value that needs to be applied to static addresses of the program. *

@@ -1445,6 +592,10 @@ public class DWARFProgram implements Closeable { return programBaseAddressFixup; } + public void setProgramBaseAddressFixup(long programBaseAddressFixup) { + this.programBaseAddressFixup = programBaseAddressFixup; + } + public AddressRange getAddressRange(DWARFRange range, boolean isCode) { AddressSpace defAS = program.getAddressFactory().getDefaultAddressSpace(); Address start = @@ -1497,71 +648,4 @@ public class DWARFProgram implements Closeable { } } - /* for testing */ public void setStringTable(StringTable st) { - this.debugStrings = st; - } - - private int getPositionInParent(DebugInfoEntry die, Predicate dwTagFilter) { - int dieIndex = die.getIndex(); - int parentIndex = getParentIndex(dieIndex); - if (parentIndex < 0) { - return -1; - } - IntArrayList childIndexes = getDIEChildIndexes(parentIndex); - for (int i = 0, positionNum = 0; i < childIndexes.size(); i++) { - int childDIEIndex = childIndexes.get(i); - if (childDIEIndex == dieIndex) { - return positionNum; - } - DebugInfoEntry childDIE = getDIEByIndex(childDIEIndex); - if (childDIE != null && dwTagFilter.test(childDIE.getTag())) { - positionNum++; - } - } - // only way to get here is if our in-memory indexes are corrupt / incorrect - throw new RuntimeException("DWARF DIE index failure."); - } - - //--------------------------------------------------------------------------------------------- - - 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/dwarf/DWARFRangeList.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java index 2348b99d5d..b0702071c6 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeList.java @@ -4,9 +4,9 @@ * 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. @@ -83,7 +83,7 @@ public class DWARFRangeList { List list = new ArrayList<>(); - DWARFProgram dprog = cu.getProgram(); + DIEContainer dieContainer = cu.getDIEContainer(); long baseAddr = cu.getPCRange().getFrom(); while (reader.hasNext()) { @@ -94,21 +94,21 @@ public class DWARFRangeList { switch (rleId) { case DW_RLE_base_addressx: { int addrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); - baseAddr = dprog.getAddress(DW_FORM_addrx, addrIndex, cu); + baseAddr = dieContainer.getAddress(DW_FORM_addrx, addrIndex, cu); break; } case DW_RLE_startx_endx: { int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); int endAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); - long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu); - long end = dprog.getAddress(DW_FORM_addrx, endAddrIndex, cu); + long start = dieContainer.getAddress(DW_FORM_addrx, startAddrIndex, cu); + long end = dieContainer.getAddress(DW_FORM_addrx, endAddrIndex, cu); list.add(new DWARFRange(start, end)); break; } case DW_RLE_startx_length: { int startAddrIndex = reader.readNextUnsignedVarIntExact(LEB128::unsigned); int len = reader.readNextUnsignedVarIntExact(LEB128::unsigned); - long start = dprog.getAddress(DW_FORM_addrx, startAddrIndex, cu); + long start = dieContainer.getAddress(DW_FORM_addrx, startAddrIndex, cu); list.add(new DWARFRange(start, start + len)); break; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java index 74969570a2..872efaec7c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFRangeListHeader.java @@ -18,11 +18,11 @@ package ghidra.app.util.bin.format.dwarf; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames; +import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId; /** * Header found at the start of a set of DWARFRangeList entries, which are stored sequentially - * in the {@link DWARFSectionNames#DEBUG_RNGLISTS .debug_rnglists} section. + * in the {@link DWARFSectionId#DEBUG_RNGLISTS .debug_rnglists} section. */ public class DWARFRangeListHeader extends DWARFIndirectTableHeader { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java index e1245da606..7c53c831d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFStringOffsetTableHeader.java @@ -20,11 +20,11 @@ import java.io.IOException; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId; import ghidra.app.util.bin.format.dwarf.attribs.DWARFForm; -import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames; +import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId; /** * Table of offsets that point into the string table. These tables are stored sequentially in the - * {@link DWARFSectionNames#DEBUG_STROFFSETS .debug_str_offsets} section. + * {@link DWARFSectionId#DEBUG_STROFFSETS .debug_str_offsets} section. *

* Elements in the table are referred to by index via {@link DWARFForm#DW_FORM_strx} and friends. *

diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java index 649d7a97d7..5953749fe4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUnitHeader.java @@ -4,9 +4,9 @@ * 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. @@ -18,8 +18,6 @@ package ghidra.app.util.bin.format.dwarf; import java.io.IOException; import ghidra.app.util.bin.BinaryReader; -import ghidra.util.exception.CancelledException; -import ghidra.util.task.TaskMonitor; /** * The base class for a set of headers that share a common field layout. @@ -28,23 +26,20 @@ public class DWARFUnitHeader { /** * Reads the initial fields found in a unit header. * - * @param dprog {@link DWARFProgram} + * @param dieContainer {@link DIEContainer} * @param reader {@link BinaryReader} stream - * @param abbrReader {@link BinaryReader} .debug_abbr stream * @param unitNumber ordinal of this item - * @param monitor {@link TaskMonitor} * @return a unit header (only comp units for now), or null if at end-of-list * @throws DWARFException if invalid dwarf data * @throws IOException if error reading data - * @throws CancelledException if cancelled */ - public static DWARFUnitHeader read(DWARFProgram dprog, BinaryReader reader, - BinaryReader abbrReader, int unitNumber, TaskMonitor monitor) - throws DWARFException, IOException, CancelledException { + public static DWARFUnitHeader read(DIEContainer dieContainer, BinaryReader reader, + int unitNumber) throws DWARFException, IOException { // unit_length : dwarf_length // version : 2 bytes // unit type : 1 byte [ version >= 5 ] + DWARFProgram dprog = dieContainer.getProgram(); long startOffset = reader.getPointerIndex(); DWARFLengthValue lengthInfo = DWARFLengthValue.read(reader, dprog.getDefaultIntSize()); if (lengthInfo == null) { @@ -57,16 +52,16 @@ public class DWARFUnitHeader { throw new DWARFException("Unsupported DWARF version [%d]".formatted(version)); } - DWARFUnitHeader partial = new DWARFUnitHeader(dprog, startOffset, endOffset, + DWARFUnitHeader partial = new DWARFUnitHeader(dieContainer, startOffset, endOffset, lengthInfo.intSize(), version, unitNumber); if (2 <= version && version <= 4) { - return DWARFCompilationUnit.readV4(partial, reader, abbrReader, monitor); + return DWARFCompilationUnit.readV4(partial, reader); } int unitType = reader.readNextUnsignedByte(); switch (unitType) { case DWARFUnitType.DW_UT_compile: - return DWARFCompilationUnit.readV5(partial, reader, abbrReader, monitor); + return DWARFCompilationUnit.readV5(partial, reader); case DWARFUnitType.DW_UT_type: case DWARFUnitType.DW_UT_partial: case DWARFUnitType.DW_UT_skeleton: @@ -83,6 +78,8 @@ public class DWARFUnitHeader { */ protected final DWARFProgram dprog; + protected final DIEContainer dieContainer; + /** * Offset in the section of this header */ @@ -111,6 +108,7 @@ public class DWARFUnitHeader { protected DWARFUnitHeader(DWARFUnitHeader other) { this.dprog = other.dprog; + this.dieContainer = other.dieContainer; this.startOffset = other.startOffset; this.endOffset = other.endOffset; this.intSize = other.intSize; @@ -118,9 +116,10 @@ public class DWARFUnitHeader { this.unitNumber = other.unitNumber; } - protected DWARFUnitHeader(DWARFProgram dprog, long startOffset, long endOffset, int intSize, - short version, int unitNumber) { - this.dprog = dprog; + protected DWARFUnitHeader(DIEContainer dieContainer, long startOffset, long endOffset, + int intSize, short version, int unitNumber) { + this.dieContainer = dieContainer; + this.dprog = dieContainer.getProgram(); this.startOffset = startOffset; this.endOffset = endOffset; this.intSize = intSize; @@ -132,6 +131,10 @@ public class DWARFUnitHeader { return dprog; } + public DIEContainer getDIEContainer() { + return dieContainer; + } + public short getDWARFVersion() { return dwarfVersion; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java index bf2e2c22f1..78c4f6277e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFUtil.java @@ -145,9 +145,8 @@ public class DWARFUtil { * name. */ public static List findLinkageNameInChildren(DebugInfoEntry die) { - DWARFProgram prog = die.getProgram(); for (DebugInfoEntry childDIE : die.getChildren(DWARFTag.DW_TAG_subprogram)) { - DIEAggregate childDIEA = prog.getAggregate(childDIE); + DIEAggregate childDIEA = die.getContainer().getAggregate(childDIE); String linkage = childDIEA.getString(DW_AT_linkage_name, null); if (linkage == null) { linkage = childDIEA.getString(DW_AT_MIPS_linkage_name, null); @@ -202,7 +201,7 @@ public class DWARFUtil { DWARFProgram prog = diea.getProgram(); int typeDefCount = 0; for (DebugInfoEntry childDIE : parent.getChildren()) { - DIEAggregate childDIEA = prog.getAggregate(childDIE); + DIEAggregate childDIEA = diea.getDIEContainer().getAggregate(childDIE); if (diea == childDIEA || diea.getOffset() == childDIEA.getOffset()) { return "anon_%s_%d".formatted(childDIEA.getTag().getContainerTypeName(), typeDefCount); @@ -230,10 +229,9 @@ public class DWARFUtil { return null; } - DWARFProgram prog = diea.getProgram(); List users = new ArrayList<>(); for (DebugInfoEntry childDIE : parent.getChildren()) { - DIEAggregate childDIEA = prog.getAggregate(childDIE); + DIEAggregate childDIEA = diea.getDIEContainer().getAggregate(childDIE); String childName = childDIEA.getName(); DIEAggregate type = childDIEA.getTypeRef(); @@ -273,7 +271,7 @@ public class DWARFUtil { childEntry.getTag() == DWARFTag.DW_TAG_inheritance)) { continue; } - DIEAggregate childDIEA = diea.getProgram().getAggregate(childEntry); + DIEAggregate childDIEA = diea.getDIEContainer().getAggregate(childEntry); if (childDIEA.hasAttribute(DW_AT_external)) { continue; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java index fc002de78f..c463b77e3b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DebugInfoEntry.java @@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.dwarf; import java.io.IOException; import java.util.*; +import java.util.function.Predicate; import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.format.dwarf.attribs.*; @@ -126,7 +127,7 @@ public class DebugInfoEntry { * @return list of child DIE's */ public List getChildren() { - return getProgram().getChildrenOf(dieIndex); + return getContainer().getChildrenOf(dieIndex); } /** @@ -152,7 +153,7 @@ public class DebugInfoEntry { * @return the parent DIE, or null if this DIE is the root of the compilation unit */ public DebugInfoEntry getParent() { - return getProgram().getParentOf(dieIndex); + return getContainer().getParentOf(dieIndex); } /** @@ -188,7 +189,7 @@ public class DebugInfoEntry { */ public DWARFAttributeValue getAttributeValue(int attribIndex) { if (attributes[attribIndex] == null) { - BinaryReader reader = getProgram().getReaderForCompUnit(compilationUnit) + BinaryReader reader = getContainer().getReaderForCompUnit(compilationUnit) .clone(offset + attrOffsets[attribIndex]); DWARFFormContext context = new DWARFFormContext(reader, compilationUnit, abbreviation.getAttributeAt(attribIndex)); @@ -259,12 +260,20 @@ public class DebugInfoEntry { return compilationUnit; } + public DIEContainer getContainer() { + return compilationUnit.getDIEContainer(); + } + public DWARFProgram getProgram() { return getCompilationUnit().getProgram(); } public int getDepth() { - return getProgram().getParentDepth(dieIndex); + return getContainer().getParentDepth(dieIndex); + } + + public int getPositionInParent(Predicate dwTagFilter) { + return getContainer().getPositionInParent(this, dwTagFilter); } @Override @@ -291,7 +300,7 @@ public class DebugInfoEntry { DWARFTag tag = getTag(); int tagNum = tag != null ? tag.getId() : 0; int abbrNum = abbreviation != null ? abbreviation.getAbbreviationCode() : 0; - int childCount = getProgram().getChildCount(dieIndex); + int childCount = getContainer().getChildCount(dieIndex); buffer.append("<%d><%x>: %s [abbrev %d, tag %d, index %d, children %d]\n".formatted( getDepth(), offset, tag, abbrNum, tagNum, dieIndex, childCount)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java index 8f09a93d3f..89bd3c3f31 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFForm.java @@ -356,23 +356,20 @@ public enum DWARFForm { case DW_FORM_strx3: case DW_FORM_strx4: { long index = context.reader().readNextUnsignedValue(size); - String s = - context.compUnit().getProgram().getString(this, index, context.compUnit()); + String s = context.dieContainer().getString(this, index, context.compUnit()); return new DWARFStringAttribute(s); } case DW_FORM_strp: case DW_FORM_line_strp: case DW_FORM_gnu_strp_alt: { long offset = context.reader().readNextUnsignedValue(context.dwarfIntSize()); - String s = - context.compUnit().getProgram().getString(this, offset, context.compUnit()); + String s = context.dieContainer().getString(this, offset, context.compUnit()); return new DWARFStringAttribute(s); } case DW_FORM_strx: case DW_FORM_gnu_str_index: { int index = context.reader().readNextUnsignedVarIntExact(LEB128::unsigned); - String s = - context.compUnit().getProgram().getString(this, index, context.compUnit()); + String s = context.dieContainer().getString(this, index, context.compUnit()); return new DWARFStringAttribute(s); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java index 33d09047e6..f096399ca4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFFormContext.java @@ -16,8 +16,7 @@ package ghidra.app.util.bin.format.dwarf.attribs; import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit; -import ghidra.app.util.bin.format.dwarf.DWARFProgram; +import ghidra.app.util.bin.format.dwarf.*; /** * Context given to the {@link DWARFForm#readValue(DWARFFormContext)} method to enable it to @@ -49,4 +48,8 @@ public record DWARFFormContext(BinaryReader reader, DWARFCompilationUnit compUni DWARFProgram dprog() { return compUnit.getProgram(); } + + DIEContainer dieContainer() { + return compUnit.getDIEContainer(); + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java index 682f8af39b..e27a299f60 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFIndirectAttribute.java @@ -15,11 +15,11 @@ */ package ghidra.app.util.bin.format.dwarf.attribs; +import static ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId.*; + import java.io.IOException; import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit; -import ghidra.app.util.bin.format.dwarf.DWARFProgram; -import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames; /** * DWARF numeric attribute value that is an index into a lookup table @@ -36,20 +36,19 @@ public class DWARFIndirectAttribute extends DWARFNumericAttribute { @Override public String getValueString(DWARFCompilationUnit cu, DWARFAttributeDef def) { - DWARFProgram dprog = cu.getProgram(); DWARFForm form = def.getAttributeForm(); try { int index = getIndex(); - long offset = dprog.getOffsetOfIndexedElement(form, index, cu); + long offset = cu.getDIEContainer().getOffsetOfIndexedElement(form, index, cu); if (form.isClass(DWARFAttributeClass.address)) { return "addr v%d 0x%x (idx %d)".formatted(cu.getDWARFVersion(), offset, index); } else if (form.isClass(DWARFAttributeClass.rnglist)) { - return toElementLocationString("rnglist", DWARFSectionNames.DEBUG_RNGLISTS, index, + return toElementLocationString("rnglist", DEBUG_RNGLISTS.getSectionName(), index, offset, cu.getDWARFVersion()); } else if (form.isClass(DWARFAttributeClass.loclist)) { - return toElementLocationString("loclist", DWARFSectionNames.DEBUG_LOCLISTS, index, + return toElementLocationString("loclist", DEBUG_LOCLISTS.getSectionName(), index, offset, cu.getDWARFVersion()); } else if (form.isClass(DWARFAttributeClass.string)) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java index 42e3ec905f..6d408fa13f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFNumericAttribute.java @@ -15,11 +15,12 @@ */ package ghidra.app.util.bin.format.dwarf.attribs; +import static ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId.*; + import java.io.IOException; import ghidra.app.util.bin.InvalidDataException; import ghidra.app.util.bin.format.dwarf.DWARFCompilationUnit; -import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionNames; import ghidra.program.model.scalar.Scalar; /** @@ -118,14 +119,12 @@ public class DWARFNumericAttribute implements DWARFAttributeValue { return "addr v%d 0x%x".formatted(ver, getUnsignedValue()); } else if (form.isClass(DWARFAttributeClass.rnglist)) { - String sectionName = - ver < 5 ? DWARFSectionNames.DEBUG_RANGES : DWARFSectionNames.DEBUG_RNGLISTS; + String sectionName = (ver < 5 ? DEBUG_RANGES : DEBUG_RNGLISTS).getSectionName(); return toElementLocationString("rnglist", sectionName, -1, getUnsignedValue(), ver) + " offset: " + getUnsignedValue(); } else if (form.isClass(DWARFAttributeClass.loclist)) { - String sectionName = - ver < 5 ? DWARFSectionNames.DEBUG_LOC : DWARFSectionNames.DEBUG_LOCLISTS; + String sectionName = (ver < 5 ? DEBUG_LOC : DEBUG_LOCLISTS).getSectionName(); return toElementLocationString("loclist", sectionName, -1, getUnsignedValue(), ver); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java index f7c21389a3..6a572bc92b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/expression/DWARFExpressionEvaluator.java @@ -15,13 +15,13 @@ */ package ghidra.app.util.bin.format.dwarf.expression; +import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*; import static ghidra.app.util.bin.format.dwarf.expression.DWARFExpressionOpCode.*; import java.io.IOException; import java.util.*; import ghidra.app.util.bin.format.dwarf.*; -import ghidra.app.util.bin.format.dwarf.attribs.DWARFForm; import ghidra.program.model.address.Address; import ghidra.program.model.lang.Language; import ghidra.program.model.lang.Register; @@ -658,8 +658,8 @@ public class DWARFExpressionEvaluator { throw new DWARFExpressionUnsupportedOpException(instr); case DW_OP_addrx: try { - long addr = dprog.getAddress(DWARFForm.DW_FORM_addrx, - instr.getOperandValue(0), cu); + long addr = cu.getDIEContainer() + .getAddress(DW_FORM_addrx, instr.getOperandValue(0), cu); push(addr); break; } @@ -669,8 +669,8 @@ public class DWARFExpressionEvaluator { } case DW_OP_constx: // same as addrx, but different relocation-able specifications try { - long addr = dprog.getAddress(DWARFForm.DW_FORM_addrx, - instr.getOperandValue(0), cu); + long addr = cu.getDIEContainer() + .getAddress(DW_FORM_addrx, instr.getOperandValue(0), cu); push(addr); break; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLine.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLine.java index 98d1d7bd1c..ac21637783 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLine.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLine.java @@ -264,11 +264,11 @@ public class DWARFLine { return endOffset; } - public DWARFLineProgramExecutor getLineProgramexecutor(DWARFCompilationUnit cu, - BinaryReader reader) { - DWARFLineProgramExecutor lpe = new DWARFLineProgramExecutor(reader.clone(opcodes_start), - endOffset, cu.getPointerSize(), opcode_base, line_base, line_range, - minimum_instruction_length, default_is_stmt); + public DWARFLineProgramExecutor getLineProgramExecutor(DWARFCompilationUnit cu) { + DWARFLineProgramExecutor lpe = new DWARFLineProgramExecutor( + cu.getDIEContainer().getDebugLineReader().clone(opcodes_start), endOffset, + cu.getPointerSize(), opcode_base, line_base, line_range, minimum_instruction_length, + default_is_stmt); return lpe; } @@ -278,9 +278,12 @@ public class DWARFLine { public record SourceFileAddr(long address, String fileName, byte[] md5, int lineNum, boolean isEndSequence) {} - public List getAllSourceFileAddrInfo(DWARFCompilationUnit cu, - BinaryReader reader) throws IOException { - try (DWARFLineProgramExecutor lpe = getLineProgramexecutor(cu, reader)) { + public List getAllSourceFileAddrInfo(DWARFCompilationUnit cu) + throws IOException { + if (cu.getDIEContainer().getDebugLineReader() == null) { + return List.of(); + } + try (DWARFLineProgramExecutor lpe = getLineProgramExecutor(cu)) { List results = new ArrayList<>(); for (DWARFLineProgramState row : lpe.allRows()) { try { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/DWARFMacroHeader.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/DWARFMacroHeader.java index 329faa1a7b..ffbe81c60a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/DWARFMacroHeader.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/DWARFMacroHeader.java @@ -57,7 +57,7 @@ public class DWARFMacroHeader { long debug_line_offset = -1; if ((flags & DEBUG_LINE_OFFSET_FLAG_MASK) != 0) { debug_line_offset = reader.readNextUnsignedValue(intSize); - line = cu.getProgram().getLine(debug_line_offset, cu, false); + line = cu.getDIEContainer().getLine(debug_line_offset, cu, false); } Map> opcodeMap = DWARFMacroOpcode.defaultOpcodeOperandMap; if ((flags & OPCODE_OPERANDS_TABLE_FLAG_MASK) != 0) { @@ -135,7 +135,7 @@ public class DWARFMacroHeader { } public List getEntries() throws IOException { - return cu.getProgram().getMacroEntries(this); + return cu.getDIEContainer().getMacroEntries(this); } public DWARFCompilationUnit getCompilationUnit() { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/entry/DWARFMacroImport.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/entry/DWARFMacroImport.java index 70f357787d..ab5e7f8e70 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/entry/DWARFMacroImport.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/macro/entry/DWARFMacroImport.java @@ -37,7 +37,7 @@ public class DWARFMacroImport extends DWARFMacroInfoEntry { public DWARFMacroHeader getImportedMacroHeader() throws IOException { long offset = getOffset(); DWARFCompilationUnit cu = macroHeader.getCompilationUnit(); - return cu.getProgram().getMacroHeader(offset, cu); + return cu.getDIEContainer().getMacroHeader(offset, cu); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionId.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionId.java new file mode 100644 index 0000000000..98828392d6 --- /dev/null +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionId.java @@ -0,0 +1,53 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.dwarf.sectionprovider; + +/** + * Enum specifying common DWARF sections + */ +public enum DWARFSectionId { + DEBUG_INFO("debug_info"), + DEBUG_TYPES("debug_types"), + DEBUG_ABBREV("debug_abbrev"), + DEBUG_ARRANGES("debug_arranges"), + DEBUG_LINE("debug_line"), + DEBUG_LINE_STR("debug_line_str"), // v5+ + DEBUG_FRAME("debug_frame"), + DEBUG_LOC("debug_loc"), + DEBUG_LOCLISTS("debug_loclists"), // v5+ + DEBUG_STR("debug_str"), + DEBUG_STROFFSETS("debug_str_offsets"), // v5+ + DEBUG_RANGES("debug_ranges"), + DEBUG_RNGLISTS("debug_rnglists"), // v5+ + DEBUG_PUBNAMES("debug_pubnames"), + DEBUG_PUBTYPES("debug_pubtypes"), + DEBUG_MACINFO("debug_macinfo"), + DEBUG_MACRO("debug_macro"), // v5+ + DEBUG_ADDR("debug_addr"); + + public static final String[] MINIMAL_DWARF_SECTIONS = + new String[] { DEBUG_INFO.getSectionName(), DEBUG_ABBREV.getSectionName() }; + + private final String name; + + private DWARFSectionId(String name) { + this.name = name; + } + + public String getSectionName() { + return name; + } +} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java deleted file mode 100644 index 61253a2deb..0000000000 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionNames.java +++ /dev/null @@ -1,40 +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.dwarf.sectionprovider; - -public final class DWARFSectionNames { - public static final String DEBUG_INFO = "debug_info"; - public static final String DEBUG_TYPES = "debug_types"; - public static final String DEBUG_ABBREV = "debug_abbrev"; - public static final String DEBUG_ARRANGES = "debug_arranges"; - public static final String DEBUG_LINE = "debug_line"; - public static final String DEBUG_LINE_STR = "debug_line_str"; // v5+ - public static final String DEBUG_FRAME = "debug_frame"; - public static final String DEBUG_LOC = "debug_loc"; - public static final String DEBUG_LOCLISTS = "debug_loclists"; // v5+ - public static final String DEBUG_STR = "debug_str"; - public static final String DEBUG_STROFFSETS = "debug_str_offsets"; // v5+ - public static final String DEBUG_RANGES = "debug_ranges"; - public static final String DEBUG_RNGLISTS = "debug_rnglists"; // v5+ - public static final String DEBUG_PUBNAMES = "debug_pubnames"; - public static final String DEBUG_PUBTYPES = "debug_pubtypes"; - public static final String DEBUG_MACINFO = "debug_macinfo"; - public static final String DEBUG_MACRO = "debug_macro"; // v5+ - public static final String DEBUG_ADDR = "debug_addr"; - - public static final String[] MINIMAL_DWARF_SECTIONS = { DEBUG_INFO, DEBUG_ABBREV }; - -} diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java index 001558f4d8..199872916f 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/sectionprovider/DWARFSectionProviderFactory.java @@ -15,6 +15,8 @@ */ package ghidra.app.util.bin.format.dwarf.sectionprovider; +import static ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionId.*; + import java.io.Closeable; import java.util.List; import java.util.function.BiFunction; @@ -48,7 +50,7 @@ public class DWARFSectionProviderFactory { /** * Iterates through the statically registered {@link #sectionProviderFactoryFuncs factory funcs}, * trying each factory method until one returns a {@link DWARFSectionProvider} - * that can successfully retrieve the {@link DWARFSectionNames#MINIMAL_DWARF_SECTIONS minimal} + * that can successfully retrieve the {@link DWARFSectionId#MINIMAL_DWARF_SECTIONS minimal} * sections we need to do a DWARF import. *

* The resulting {@link DWARFSectionProvider} is {@link Closeable} and it is the caller's @@ -65,14 +67,14 @@ public class DWARFSectionProviderFactory { DWARFSectionProvider sp = factoryFunc.apply(program, monitor); if (sp != null) { try { - if (sp.hasSection(DWARFSectionNames.MINIMAL_DWARF_SECTIONS)) { + if (sp.hasSection(MINIMAL_DWARF_SECTIONS)) { return sp; } // if normal sections were not found, look for compressed sections in the // same provider sp = new CompressedSectionProvider(sp); - if (sp.hasSection(DWARFSectionNames.MINIMAL_DWARF_SECTIONS)) { + if (sp.hasSection(MINIMAL_DWARF_SECTIONS)) { return sp; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java index 65892fc7a6..6cc66a8f13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/PortableExecutable.java @@ -172,14 +172,6 @@ public class PortableExecutable { } public long getFileLength() { - if (reader != null) { - try { - return reader.length(); - } catch (IOException e) { - // IGNORE - return 0; - } - } - return 0; + return reader != null ? reader.length() : 0; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugDirectoryParser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugDirectoryParser.java index fe91275765..c934ade2e5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugDirectoryParser.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/debug/DebugDirectoryParser.java @@ -4,9 +4,9 @@ * 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. @@ -195,12 +195,7 @@ public class DebugDirectoryParser implements OffsetValidator { @Override public boolean checkPointer(long ptr) { - try { - return ptr > 0 && ptr < reader.length(); - } - catch (IOException e) { - return false; - } + return ptr > 0 && ptr < reader.length(); } @Override diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java index 1ed4688d30..b6f06b03f3 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFDataTypeImporterTest.java @@ -278,7 +278,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // test that cached types are handled correctly. DebugInfoEntry int2DIE = addInt(); DebugInfoEntry structB_cu2 = newStruct("structB", 20).create(); - long structA_cu2_offset = dwarfProg.getRelativeDIEOffset(2); + long structA_cu2_offset = dieContainer.getRelativeDIEOffset(2); newMember(structB_cu2, "structAfield", structA_cu2_offset, 0).create(); newMember(structB_cu2, "guardfield", int2DIE, 16).create(); @@ -1289,7 +1289,7 @@ public class DWARFDataTypeImporterTest extends DWARFTestBase { // 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. - long fwdDIE = dwarfProg.getRelativeDIEOffset(1); + long fwdDIE = dieContainer.getRelativeDIEOffset(1); DebugInfoEntry constDIE = new DIECreator(dwarfProg, DWARFTag.DW_TAG_const_type).addRef(DW_AT_type, fwdDIE) .create(); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java index 54ad233636..6b2ca8d2bd 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/bin/format/dwarf/DWARFFunctionImporterTest.java @@ -265,7 +265,7 @@ public class DWARFFunctionImporterTest extends DWARFTestBase { DebugInfoEntry floatDIE = addFloat(); DebugInfoEntry struct1PtrDIE = addFwdPtr(1); DebugInfoEntry struct1DIE = newStruct("mystruct", 100).create(); - long formalParamDIEOffset = dwarfProg.getRelativeDIEOffset(2); + long formalParamDIEOffset = dieContainer.getRelativeDIEOffset(2); DebugInfoEntry fooDIE = newSubprogram("foo", intDIE, 0x410, 10) .addRef(DW_AT_object_pointer, formalParamDIEOffset) .setParent(struct1DIE) diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java index b92f0c93fd..a5ab39fc4d 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreator.java @@ -29,12 +29,14 @@ public class DIECreator { record AttrInfo(DWARFAttributeId attribute, AttrDef spec, DWARFAttributeValue value) {} private MockDWARFProgram dwarfProg; + private MockDIEContainer dieContainer; private DWARFTag tag; private Map attributes = new HashMap<>(); private DebugInfoEntry parent; - public DIECreator(MockDWARFProgram dwarfProg, DWARFTag tag) { - this.dwarfProg = dwarfProg; + public DIECreator(MockDWARFProgram dprog, DWARFTag tag) { + this.dieContainer = dprog.getDIEContainer(); + this.dwarfProg = dprog; this.tag = tag; } @@ -64,14 +66,14 @@ public class DIECreator { public DIECreator addRef(DWARFAttributeId attribute, DebugInfoEntry die) { AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_ref8, 0); add(attrSpec, new DWARFNumericAttribute( - die.getOffset() - dwarfProg.getCurrentCompUnit().getStartOffset())); + die.getOffset() - dieContainer.getCurrentCompUnit().getStartOffset())); return this; } public DIECreator addRef(DWARFAttributeId attribute, long offset) { AttrDef attrSpec = new AttrDef(attribute, attribute.getId(), DW_FORM_ref8, 0); add(attrSpec, new DWARFNumericAttribute( - offset - dwarfProg.getCurrentCompUnit().getStartOffset())); + offset - dieContainer.getCurrentCompUnit().getStartOffset())); return this; } @@ -112,9 +114,9 @@ public class DIECreator { } public DebugInfoEntry createRootDIE() { - MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit(); + MockDWARFCompilationUnit cu = dieContainer.getCurrentCompUnit(); DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag); - DebugInfoEntry die = dwarfProg.addDIE(abbr, null); + DebugInfoEntry die = dieContainer.addDIE(abbr, null); int attrNum = 0; for (AttrInfo attrInfo : attributes.values()) { @@ -125,13 +127,13 @@ public class DIECreator { } public DebugInfoEntry create() { - MockDWARFCompilationUnit cu = dwarfProg.getCurrentCompUnit(); + MockDWARFCompilationUnit cu = dieContainer.getCurrentCompUnit(); if (cu == null) { - cu = dwarfProg.addCompUnit(); + cu = dieContainer.addCompUnit(); } DWARFAbbreviation abbr = cu.createAbbreviation(makeAttrSpecArray(), tag); DebugInfoEntry die = - dwarfProg.addDIE(abbr, parent != null ? parent : cu.getCompileUnitDIE()); + dieContainer.addDIE(abbr, parent != null ? parent : cu.getCompileUnitDIE()); int attrNum = 0; for (AttrInfo attrInfo : attributes.values()) { diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java index 9d0470b8f5..e338c75848 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DIECreatorTest.java @@ -63,7 +63,7 @@ public class DIECreatorTest extends DWARFTestBase { buildMockDIEIndexes(); - DIEAggregate struct_via_ao = dwarfProg.getAggregate(aoStruct); + DIEAggregate struct_via_ao = dwarfProg.getDIEContainer().getAggregate(aoStruct); assertEquals("MyStruct aggregate should have 3 fragments", 3, struct_via_ao.getOffsets().length); @@ -73,7 +73,7 @@ public class DIECreatorTest extends DWARFTestBase { 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. *

@@ -83,9 +83,6 @@ public class DIECreatorTest extends DWARFTestBase {
 	 *                                                 \
 	 *                                                   mystruct ao2
 	 * 
- * @throws DWARFException - * @throws IOException - * @throws CancelledException */ @Test public void testDIEAggregateMulti() throws DWARFException, CancelledException, IOException { @@ -126,8 +123,8 @@ public class DIECreatorTest extends DWARFTestBase { buildMockDIEIndexes(); - DIEAggregate ao1 = dwarfProg.getAggregate(ao1Struct); - DIEAggregate ao2 = dwarfProg.getAggregate(ao2Struct); + DIEAggregate ao1 = dwarfProg.getDIEContainer().getAggregate(ao1Struct); + DIEAggregate ao2 = dwarfProg.getDIEContainer().getAggregate(ao2Struct); assertEquals("Should have 3 fragments", 3, ao1.getOffsets().length); assertEquals("Should have 3 fragments", 3, ao2.getOffsets().length); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DWARFTestBase.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DWARFTestBase.java index 8166864821..ca91398cfa 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DWARFTestBase.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/DWARFTestBase.java @@ -56,8 +56,8 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { protected int transactionID; protected TaskMonitor monitor = TaskMonitor.DUMMY; - protected DWARFImportOptions importOptions; protected MockDWARFProgram dwarfProg; + protected MockDIEContainer dieContainer; protected MockDWARFCompilationUnit cu; protected DWARFDataTypeManager dwarfDTM; protected MockStringTable stringTable; @@ -80,11 +80,11 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { DataTypeManagerService dtms = mgr.getDataTypeManagerService(); builtInDTM = dtms.getBuiltInDataTypesManager(); - importOptions = new DWARFImportOptions(); - dwarfProg = new MockDWARFProgram(program, importOptions, TaskMonitor.DUMMY, - new NullSectionProvider()); - stringTable = new MockStringTable(br()); - dwarfProg.setStringTable(stringTable); + dwarfProg = + new MockDWARFProgram(program, new DWARFImportOptions(), new NullSectionProvider()); + dwarfProg.init(monitor); + dieContainer = dwarfProg.getDIEContainer(); + stringTable = dieContainer.getStringTable(); dwarfDTM = dwarfProg.getDwarfDTM(); dwarfRootCP = dwarfProg.getRootDNI().asCategoryPath(); @@ -115,8 +115,8 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { } protected void buildMockDIEIndexes() throws CancelledException, DWARFException { - dwarfProg.buildMockDIEIndexes(); - //dwarfProg.dumpDIEs(System.out); + dieContainer.buildMockDIEIndexes(); + //dieContainer.dumpDIEs(System.out); } protected void importAllDataTypes() throws CancelledException, IOException, DWARFException { @@ -133,7 +133,7 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { } protected DIEAggregate getAggregate(DebugInfoEntry die) { - return dwarfProg.getAggregate(die); + return dieContainer.getAggregate(die); } protected void ensureCompUnit() { @@ -147,12 +147,12 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { } protected MockDWARFCompilationUnit addCompUnit64() { - setCompUnit(dwarfProg.addCompUnit(DWARFSourceLanguage.DW_LANG_C, 8 /* dwarf64 */)); + setCompUnit(dieContainer.addCompUnit(DWARFSourceLanguage.DW_LANG_C, 8 /* dwarf64 */)); return cu; } protected MockDWARFCompilationUnit addCompUnit(int cuLang) { - setCompUnit(dwarfProg.addCompUnit(cuLang)); + setCompUnit(dieContainer.addCompUnit(cuLang)); return cu; } @@ -280,7 +280,7 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { protected DebugInfoEntry addFwdPtr(int fwdRecordOffset) { ensureCompUnit(); - long absOffset = dwarfProg + long absOffset = dieContainer .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(); diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDIEContainer.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDIEContainer.java new file mode 100644 index 0000000000..3f87995d2a --- /dev/null +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDIEContainer.java @@ -0,0 +1,153 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.app.util.bin.format.dwarf; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; + +import ghidra.app.util.bin.BinaryReader; +import ghidra.app.util.bin.ByteArrayProvider; +import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId; +import ghidra.util.datastruct.IntArrayList; +import ghidra.util.datastruct.LongArrayList; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +public class MockDIEContainer extends DIEContainer { + private MockDWARFCompilationUnit currentCompUnit; + private List dies = new ArrayList<>(); + + public MockDIEContainer(MockDWARFProgram dprog) { + super(dprog); + } + + @Override + public void init(TaskMonitor monitor) throws IOException, DWARFException { + super.init(monitor); + debugStrings = new MockStringTable( + new BinaryReader(new ByteArrayProvider(new byte[0]), dprog.isLittleEndian())); + } + + @Override + public MockDWARFProgram getProgram() { + return (MockDWARFProgram) super.getProgram(); + } + + public MockDWARFCompilationUnit getCurrentCompUnit() { + return currentCompUnit; + } + + @Override + public MockStringTable getStringTable() { + return (MockStringTable) super.getStringTable(); + } + + public MockDWARFCompilationUnit addCompUnit() { + return addCompUnit(DWARFSourceLanguage.DW_LANG_C); + } + + public MockDWARFCompilationUnit addCompUnit(int cuLang) { + return addCompUnit(cuLang, 4 /* dwarf32 */); + } + + public MockDWARFCompilationUnit addCompUnit(int cuLang, int dwarfIntSize) { + 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, dwarfIntSize, + (short) 4, (byte) 8, 0); + compUnits.add(currentCompUnit); + compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit); + + DebugInfoEntry compUnitRootDIE = new DIECreator(getProgram(), DWARFTag.DW_TAG_compile_unit) + .addInt(DWARFAttributeId.DW_AT_language, cuLang) + .createRootDIE(); + try { + currentCompUnit.init(compUnitRootDIE); + } + catch (IOException e) { + fail(); + } + + 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, new int[abbr.getAttributeCount()]); + + 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 (DWARFAttributeId attr : 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/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFCompilationUnit.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFCompilationUnit.java index 39256969fd..f6afc3222d 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFCompilationUnit.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFCompilationUnit.java @@ -23,9 +23,9 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit { private int dieCount; - public MockDWARFCompilationUnit(MockDWARFProgram dwarfProgram, long startOffset, long endOffset, + public MockDWARFCompilationUnit(MockDIEContainer dieContainer, long startOffset, long endOffset, int intSize, short version, byte pointerSize, int compUnitNumber) { - super(dwarfProgram, startOffset, endOffset, intSize, version, pointerSize, + super(dieContainer, startOffset, endOffset, intSize, version, pointerSize, compUnitNumber, startOffset, null); } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java index 1c1ce4befd..e6dcf12565 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockDWARFProgram.java @@ -15,130 +15,29 @@ */ package ghidra.app.util.bin.format.dwarf; -import static org.junit.Assert.*; - import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import org.junit.Assert; - -import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId; import ghidra.app.util.bin.format.dwarf.sectionprovider.DWARFSectionProvider; import ghidra.program.model.listing.Program; -import ghidra.util.datastruct.IntArrayList; -import ghidra.util.datastruct.LongArrayList; -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, + DWARFSectionProvider sectionProvider) throws IOException { + super(program, importOptions, sectionProvider); + this.dieContainer = new MockDIEContainer(this); } - public MockDWARFProgram(Program program, DWARFImportOptions importOptions, TaskMonitor monitor, - DWARFSectionProvider sectionProvider) - throws CancelledException, IOException, DWARFException { - super(program, importOptions, monitor, sectionProvider); + @Override + public void init(TaskMonitor monitor) throws IOException { + dieContainer.init(monitor); + // dieContainer.indexData() is not called, data is added by caller manually } - public MockDWARFCompilationUnit getCurrentCompUnit() { - return currentCompUnit; - } - - public MockDWARFCompilationUnit addCompUnit() { - return addCompUnit(DWARFSourceLanguage.DW_LANG_C); - } - - public MockDWARFCompilationUnit addCompUnit(int cuLang) { - return addCompUnit(cuLang, 4 /* dwarf32 */); - } - - public MockDWARFCompilationUnit addCompUnit(int cuLang, int dwarfIntSize) { - 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, dwarfIntSize, - (short) 4, (byte) 8, 0); - compUnits.add(currentCompUnit); - compUnitDieIndex.put(dieOffsets.length - 1, currentCompUnit); - - DebugInfoEntry compUnitRootDIE = new DIECreator(this, DWARFTag.DW_TAG_compile_unit) - .addInt(DWARFAttributeId.DW_AT_language, cuLang) - .createRootDIE(); - try { - currentCompUnit.init(compUnitRootDIE); - } - catch (IOException e) { - fail(); - } - - 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, new int[abbr.getAttributeCount()]); - - 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 (DWARFAttributeId attr : 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); - + @Override + public MockDIEContainer getDIEContainer() { + return (MockDIEContainer) super.getDIEContainer(); } } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java index 7098831bf3..5b217a61ba 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/MockStringTable.java @@ -23,8 +23,7 @@ import ghidra.app.util.bin.*; public class MockStringTable extends StringTable { public MockStringTable(BinaryReader reader) { - super(new BinaryReader(new ByteArrayProvider(new byte[4 * 1024]), true /* LE */), - StandardCharsets.UTF_8); + super(reader, StandardCharsets.UTF_8); } public void add(int index, String s) throws IOException { diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java index 6a2de3091b..a1c6b4518c 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/bin/format/dwarf/attribs/DWARFAttributeFactoryTest.java @@ -15,6 +15,7 @@ */ package ghidra.app.util.bin.format.dwarf.attribs; +import static ghidra.app.util.bin.format.dwarf.DWARFSourceLanguage.*; import static ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId.*; import static ghidra.app.util.bin.format.dwarf.attribs.DWARFForm.*; import static org.junit.Assert.*; @@ -24,7 +25,6 @@ import java.io.IOException; import org.junit.Test; import ghidra.app.util.bin.BinaryReader; -import ghidra.app.util.bin.format.dwarf.DWARFSourceLanguage; import ghidra.app.util.bin.format.dwarf.DWARFTestBase; import ghidra.app.util.bin.format.dwarf.attribs.DWARFAttributeId.AttrDef; import ghidra.program.database.ProgramBuilder; @@ -115,7 +115,7 @@ public class DWARFAttributeFactoryTest extends DWARFTestBase { /* guard byte for test */ 0xff); // @formatter:on - setCompUnit(dwarfProg.addCompUnit(DWARFSourceLanguage.DW_LANG_C, 8 /* dwarf64 */)); + setCompUnit(dieContainer.addCompUnit(DW_LANG_C, 8 /* dwarf64 */)); DWARFAttributeValue result1 = read(br, DW_AT_name, DW_FORM_strp); assertTrue("Should be string", result1 instanceof DWARFStringAttribute);