GP-5977 refactor DWARF DIE serialization into its own class

This will allow reading DIEs from multiple files.
This commit is contained in:
dev747368
2026-02-09 18:50:32 +00:00
parent f51dfa9299
commit 7dff240fe6
44 changed files with 1550 additions and 1337 deletions
@@ -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<DWARFCompilationUnit> 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<SourceFileAddr> allSFA = cu.getLine().getAllSourceFileAddrInfo(cu, reader);
List<SourceFileAddr> allSFA = cu.getLine().getAllSourceFileAddrInfo(cu);
for (SourceFileAddr sfa : allSFA) {
Address addr = dprog.getCodeAddress(sfa.address());
DWARFUtil.appendComment(currentProgram, addr, CommentType.EOL, "",
@@ -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);
@@ -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);
@@ -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."
@@ -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();
}
@@ -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<DIEAggregate> 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()) {
@@ -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<AttrDef> 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<Integer, DWARFAbbreviation> readAbbreviations(BinaryReader reader,
DWARFProgram prog, TaskMonitor monitor) throws IOException, CancelledException {
DIEContainer dieContainer) throws IOException {
Map<Integer, DWARFAbbreviation> 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);
}
@@ -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.
* <p>
* 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<Integer, DWARFAbbreviation> abbrMap =
DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor);
Map<Integer, DWARFAbbreviation> 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.
* <p>
* 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<Integer, DWARFAbbreviation> abbrMap =
DWARFAbbreviation.readAbbreviations(abbrReader, partial.dprog, monitor);
Map<Integer, DWARFAbbreviation> 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<Integer, DWARFAbbreviation> 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;
}
@@ -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<Integer> dimensions = new ArrayList<>();
List<DebugInfoEntry> 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)) {
@@ -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: {
@@ -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<SourceFileAddr> 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");
@@ -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<DWARFLocation> 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;
}
@@ -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 {
File diff suppressed because it is too large Load Diff
@@ -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<DWARFRange> 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;
}
@@ -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 {
@@ -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.
* <p>
* Elements in the table are referred to by index via {@link DWARFForm#DW_FORM_strx} and friends.
* <p>
@@ -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;
}
@@ -145,9 +145,8 @@ public class DWARFUtil {
* name.
*/
public static List<String> 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<String> 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;
}
@@ -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<DebugInfoEntry> 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<DWARFTag> 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));
@@ -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);
}
@@ -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();
}
}
@@ -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)) {
@@ -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);
}
@@ -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;
}
@@ -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<SourceFileAddr> getAllSourceFileAddrInfo(DWARFCompilationUnit cu,
BinaryReader reader) throws IOException {
try (DWARFLineProgramExecutor lpe = getLineProgramexecutor(cu, reader)) {
public List<SourceFileAddr> getAllSourceFileAddrInfo(DWARFCompilationUnit cu)
throws IOException {
if (cu.getDIEContainer().getDebugLineReader() == null) {
return List.of();
}
try (DWARFLineProgramExecutor lpe = getLineProgramExecutor(cu)) {
List<SourceFileAddr> results = new ArrayList<>();
for (DWARFLineProgramState row : lpe.allRows()) {
try {
@@ -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<Integer, List<DWARFForm>> opcodeMap = DWARFMacroOpcode.defaultOpcodeOperandMap;
if ((flags & OPCODE_OPERANDS_TABLE_FLAG_MASK) != 0) {
@@ -135,7 +135,7 @@ public class DWARFMacroHeader {
}
public List<DWARFMacroInfoEntry> getEntries() throws IOException {
return cu.getProgram().getMacroEntries(this);
return cu.getDIEContainer().getMacroEntries(this);
}
public DWARFCompilationUnit getCompilationUnit() {
@@ -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);
}
}
@@ -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;
}
}
@@ -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 };
}
@@ -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.
* <p>
* 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;
}
}
@@ -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;
}
}
@@ -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
@@ -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();
@@ -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)
@@ -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<DWARFAttributeId, AttrInfo> 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()) {
@@ -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.
* <pre>
@@ -83,9 +83,6 @@ public class DIECreatorTest extends DWARFTestBase {
* \
* mystruct ao2
* </pre>
* @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);
@@ -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();
@@ -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<DebugInfoEntry> 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);
}
}
@@ -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);
}
@@ -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<DebugInfoEntry> 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();
}
}
@@ -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 {
@@ -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);