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 419c125d0e..9f5025d5a9 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 @@ -743,10 +743,14 @@ public class DIEAggregate { DWARFAttribute lowPc = findAttribute(DW_AT_low_pc); if (lowPc != null && lowPc.getValue() instanceof DWARFNumericAttribute lowPcAttrVal) { try { - // TODO: previous code excluded lowPc values that were == 0 as invalid. long rawLowPc = lowPcAttrVal.getUnsignedValue(); long lowPcOffset = getDIEContainer().getAddress(lowPc.getAttributeForm(), rawLowPc, getCompilationUnit()); + + if (lowPcOffset == 0 && getProgram().isAddr0Tombstone()) { + return DWARFRange.EMPTY; + } + long highPcOffset = lowPcOffset; DWARFAttribute highPc = findAttribute(DW_AT_high_pc); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java index 2cb7e4da9c..abb54d8396 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/DWARFImportSummary.java @@ -41,6 +41,7 @@ public class DWARFImportSummary { int paramZeroLenDataType; public int badSourceFileCount; public int numEnumsCreated; + public int tombstonedSourceLineEntrySkippedCount; Set dwarfVers = new HashSet<>(); int compUnitCount; 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 9537127ed7..75c810e8be 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 @@ -121,6 +121,7 @@ public class DWARFProgram implements Closeable { private DWARFImportSummary importSummary = new DWARFImportSummary(); private DWARFSectionProvider sectionProvider; protected long programBaseAddressFixup; + protected boolean addr0IsTombstone; private Charset charset; private int maxDNICacheSize = 50; @@ -594,6 +595,9 @@ public class DWARFProgram implements Closeable { public void setProgramBaseAddressFixup(long programBaseAddressFixup) { this.programBaseAddressFixup = programBaseAddressFixup; + this.addr0IsTombstone = !program.getMemory() + .getExecuteSet() + .contains(getCodeAddress(0 + programBaseAddressFixup)); } public AddressRange getAddressRange(DWARFRange range, boolean isCode) { @@ -622,6 +626,10 @@ public class DWARFProgram implements Closeable { return realZero.equals(addr); } + public boolean isAddr0Tombstone() { + return addr0IsTombstone; + } + public boolean stackGrowsNegative() { return stackGrowsNegative; } 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 ac21637783..7bf38d380f 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 @@ -268,7 +268,7 @@ public class DWARFLine { 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); + default_is_stmt, cu.getProgram().isAddr0Tombstone()); return lpe; } @@ -286,6 +286,12 @@ public class DWARFLine { try (DWARFLineProgramExecutor lpe = getLineProgramExecutor(cu)) { List results = new ArrayList<>(); for (DWARFLineProgramState row : lpe.allRows()) { + if (row.tombstone) { + // skips elements that were based on tombstoned/dead code that wasn't included + // in final binary + cu.getProgram().getImportSummary().tombstonedSourceLineEntrySkippedCount++; + continue; + } try { DWARFFile file = getFile(row.file); results.add(new SourceFileAddr(row.address, file.getPathName(this), diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramExecutor.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramExecutor.java index 696063dc06..2530c48071 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramExecutor.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramExecutor.java @@ -40,10 +40,11 @@ public final class DWARFLineProgramExecutor implements Closeable { private final int lineBase; private final int minInstrLen; private final boolean defaultIsStatement; + private final boolean addr0IsTombstone; public DWARFLineProgramExecutor(BinaryReader reader, long streamEnd, int pointerSize, int opcodeBase, int lineBase, int lineRange, int minInstrLen, - boolean defaultIsStatement) { + boolean defaultIsStatement, boolean addr0IsTombstone) { this.reader = reader; this.streamEnd = streamEnd; this.pointerSize = pointerSize; @@ -52,6 +53,7 @@ public final class DWARFLineProgramExecutor implements Closeable { this.lineRange = lineRange; this.minInstrLen = minInstrLen; this.defaultIsStatement = defaultIsStatement; + this.addr0IsTombstone = addr0IsTombstone; } @Override @@ -161,6 +163,13 @@ public final class DWARFLineProgramExecutor implements Closeable { break; case DW_LNE_set_address: state.address = reader.readNextUnsignedValue(pointerSize); + + // set tombstone flag when an absolute 0 is set for the address. (will not catch + // relative offsets that evaluate to 0, but that is not a pattern that has been seen) + // Following instructions that have relative offset changes to the address value + // will inherit this value in each row object that is cloned + state.tombstone = addr0IsTombstone && (state.address == 0); + operands = List.of(state.address); break; case DW_LNE_define_file: { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramState.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramState.java index 687fc01162..b0868a56e5 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramState.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/dwarf/line/DWARFLineProgramState.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. @@ -63,6 +63,12 @@ public class DWARFLineProgramState { public long discriminator; + /** + * A boolean indicating that the row is based on instructions that are likely attached to a + * dead / tombstoned location. + */ + public boolean tombstone; + public DWARFLineProgramState(boolean defaultIsStatement) { this.isStatement = defaultIsStatement; } @@ -79,6 +85,7 @@ public class DWARFLineProgramState { this.epilogueBegin = other.epilogueBegin; this.isa = other.isa; this.discriminator = other.discriminator; + this.tombstone = other.tombstone; } public boolean isSameFileLine(DWARFLineProgramState other) { @@ -88,9 +95,9 @@ public class DWARFLineProgramState { @Override public String toString() { return String.format( - "DWARFLineProgramState [address=%s, file=%s, line=%s, column=%s, isStatement=%s, isBasicBlock=%s, isEndSequence=%s, prologueEnd=%s, epilogueBegin=%s, isa=%s, discriminator=%s]", + "DWARFLineProgramState [address=%s, file=%s, line=%s, column=%s, isStatement=%s, isBasicBlock=%s, isEndSequence=%s, prologueEnd=%s, epilogueBegin=%s, isa=%s, discriminator=%s, tombstone=%s]", address, file, line, column, isStatement, isBasicBlock, isEndSequence, prologueEnd, - epilogueBegin, isa, discriminator); + epilogueBegin, isa, discriminator, tombstone); } }