diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java index 8debd154be..5342882fff 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/DebugData.java @@ -80,14 +80,11 @@ public class DebugData { /** * Returns the Frame Pointer Omission data - * @return the framePointerOmissionData or null if does not exist - * @throws PdbException PdbException upon error in processing components + * @return the framePointerOmissionData or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ public List getFramePointerOmissionData() - throws CancelledException, PdbException, IOException { + throws CancelledException { int streamNum = debugStreams.get(DebugType.FRAME_POINTER_OMISSION.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -105,14 +102,10 @@ public class DebugData { /** * Returns the OMAP_FROM_SOURCE mapping of RVA to RVA - * @return the omapFromSource or null if does not exist. - * @throws PdbException PdbException upon error in processing components + * @return the omapFromSource or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ - public SortedMap getOmapFromSource() - throws CancelledException, PdbException, IOException { + public SortedMap getOmapFromSource() throws CancelledException { int streamNum = debugStreams.get(DebugType.OMAP_FROM_SOURCE.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -122,14 +115,10 @@ public class DebugData { /** * Returns the {@link List}<{@link ImageSectionHeader}> - * @return the imageSectionHeaders or null if does not exist - * @throws PdbException PdbException upon error in processing components + * @return the imageSectionHeaders or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ - public List getImageSectionHeaders() - throws CancelledException, PdbException, IOException { + public List getImageSectionHeaders() throws CancelledException { int streamNum = debugStreams.get(DebugType.SECTION_HEADER.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -141,15 +130,11 @@ public class DebugData { * Returns XData * When this returns a non-null list the OMAP_FROM_SRC should be * used for remapping global symbols - * @return the imageSectionHeadersOrig or null if does not exist - * @throws PdbException PdbException upon error in processing components + * @return the imageSectionHeadersOrig or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ // TODO: just put a return of null Integer for now until figured out. - public Integer getXData() - throws CancelledException, PdbException, IOException { + public Integer getXData() throws CancelledException { int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -161,14 +146,10 @@ public class DebugData { * Returns PData * When this returns a non-null list the OMAP_FROM_SRC should be * used for remapping global symbols - * @return the imageSectionHeadersOrig or null if does not exist - * @throws PdbException PdbException upon error in processing components + * @return the imageSectionHeadersOrig or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ - public List getPData() - throws CancelledException, PdbException, IOException { + public List getPData() throws CancelledException { int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -180,14 +161,10 @@ public class DebugData { * Returns the {@link List}<{@link ImageSectionHeader}>. * When this returns a non-null list the OMAP_FROM_SRC should be * used for remapping global symbols - * @return the imageSectionHeadersOrig or null if does not exist - * @throws PdbException PdbException upon error in processing components + * @return the imageSectionHeadersOrig or null if does not exist or problem parsing * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ - public List getImageSectionHeadersOrig() - throws CancelledException, PdbException, IOException { + public List getImageSectionHeadersOrig() throws CancelledException { int streamNum = debugStreams.get(DebugType.SECTION_HEADER_ORIG.getValue()); if (streamNum == MsfStream.NIL_STREAM_NUMBER) { return null; @@ -208,8 +185,7 @@ public class DebugData { * @throws PdbException upon error in processing components * @throws CancelledException upon user cancellation */ - public void deserializeHeader(PdbByteReader reader) - throws PdbException, CancelledException { + public void deserializeHeader(PdbByteReader reader) throws PdbException, CancelledException { while (reader.hasMore()) { pdb.checkCancelled(); int debugStreamNumber = reader.parseUnsignedShortVal(); @@ -230,8 +206,7 @@ public class DebugData { * inability to read required bytes */ @Deprecated - public void deserialize() - throws PdbException, CancelledException, IOException { + public void deserialize() throws PdbException, CancelledException, IOException { if (debugStreams.isEmpty()) { throw new PdbException( "DebugData Header had not been deserialized at the appropriate time"); @@ -281,44 +256,67 @@ public class DebugData { } private List deserializeFramePointerOmissionData(int streamNum) - throws PdbException, CancelledException, IOException { + throws CancelledException { // TODO: check implementation for completeness. - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - List fpOmissionData = new ArrayList<>(); - while (reader.hasMore()) { - pdb.checkCancelled(); - FramePointerOmissionRecord framePointerOmissionRecord = - new FramePointerOmissionRecord(); - framePointerOmissionRecord.parse(reader); - fpOmissionData.add(framePointerOmissionRecord); + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + List fpOmissionData = new ArrayList<>(); + while (reader.hasMore()) { + pdb.checkCancelled(); + FramePointerOmissionRecord framePointerOmissionRecord = + new FramePointerOmissionRecord(); + framePointerOmissionRecord.parse(reader); + fpOmissionData.add(framePointerOmissionRecord); + } + return fpOmissionData; } - return fpOmissionData; + catch (PdbException | IOException e) { + PdbLog.message("Returning null Debug Frame Pointer Omission Data due to" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; + } + } private SortedMap deserializeOMap(int streamNum) - throws PdbException, CancelledException, IOException { - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - SortedMap omap = new TreeMap<>(); - while (reader.hasMore()) { - pdb.checkCancelled(); - long v1 = reader.parseUnsignedIntVal(); - long v2 = reader.parseUnsignedIntVal(); - omap.put(v1, v2); + throws CancelledException { + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + SortedMap omap = new TreeMap<>(); + while (reader.hasMore()) { + pdb.checkCancelled(); + long v1 = reader.parseUnsignedIntVal(); + long v2 = reader.parseUnsignedIntVal(); + omap.put(v1, v2); + } + return omap; } - return omap; + catch (PdbException | IOException e) { + PdbLog.message("Returning null Debug OMap due to" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; + } + } private List deserializeSectionHeaders(int streamNum) - throws PdbException, CancelledException, IOException { - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - List sectionHeaders = new ArrayList<>(); - while (reader.hasMore()) { - pdb.checkCancelled(); - ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb); - imageSectionHeader.parse(reader); - sectionHeaders.add(imageSectionHeader); + throws CancelledException { + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + List sectionHeaders = new ArrayList<>(); + while (reader.hasMore()) { + pdb.checkCancelled(); + ImageSectionHeader imageSectionHeader = new ImageSectionHeader(pdb); + imageSectionHeader.parse(reader); + sectionHeaders.add(imageSectionHeader); + } + return sectionHeaders; + } + catch (PdbException | IOException e) { + PdbLog.message("Returning null Debug Image Section Headers due to" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; } - return sectionHeaders; } // TODO: This is incomplete. @@ -328,55 +326,63 @@ public class DebugData { */ // TODO: just put a return of null Integer for now until figured out. private Integer deserializeXData(int streamNum) - throws PdbException, CancelledException, IOException { - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - int streamLength = reader.getLimit(); - //System.out.println(reader.dump(0x20)); - RvaVaDebugHeader header = new RvaVaDebugHeader(); + throws CancelledException { + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + int streamLength = reader.getLimit(); + //System.out.println(reader.dump(0x20)); + RvaVaDebugHeader header = new RvaVaDebugHeader(); - header.deserialize(reader); - //System.out.println(header.dump()); - if (header.getHeaderVersion() != 1) { - return null; // Silent... TODO: add logging event. + header.deserialize(reader); + //System.out.println(header.dump()); + if (header.getHeaderVersion() != 1) { + return null; // Silent... TODO: add logging event. + } + long headerLength = header.getHeaderLength(); + long dataLength = header.getDataLength(); + if (headerLength + dataLength > streamLength) { + throw new PdbException("Problem parsing Debug XData"); + } + reader.setIndex((int) headerLength); + //System.out.println(reader.dump()); + PdbByteReader xDataReader = reader.getSubPdbByteReader(reader.numRemaining()); + // TODO: This is a partial implementation. We need to figure out more to know + // how to deal with it. The only API information regarding the XData is with + // regard to processing PData when the "machine" is IA64 or AMD64. The interpretation + // for these machines is not real clear (or a bit of work), and there is no other + // interpretation available when the machine is different. } - long headerLength = header.getHeaderLength(); - long dataLength = header.getDataLength(); - if (headerLength + dataLength > streamLength) { - throw new PdbException("Problem parsing Debug XData"); + catch (PdbException | IOException e) { + PdbLog.message("Returning null Debug XData" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; } - reader.setIndex((int) headerLength); - //System.out.println(reader.dump()); - PdbByteReader xDataReader = reader.getSubPdbByteReader(reader.numRemaining()); - // TODO: This is a partial implementation. We need to figure out more to know - // how to deal with it. The only API information regarding the XData is with - // regard to processing PData when the "machine" is IA64 or AMD64. The interpretation - // for these machines is not real clear (or a bit of work), and there is no other - // interpretation available when the machine is different. return null; } // TODO: This is incomplete. private List deserializePData(int streamNum) - throws PdbException, CancelledException, IOException { - PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); - List myPData = new ArrayList<>(); - int streamLength = reader.getLimit(); - RvaVaDebugHeader header = new RvaVaDebugHeader(); - header.deserialize(reader); - //System.out.println(header.dump()); - if (header.getHeaderVersion() != 1) { - return myPData; // Silent... TODO: add logging event. - } - long headerLength = header.getHeaderLength(); - long dataLength = header.getDataLength(); - if (headerLength + dataLength > streamLength) { - throw new PdbException("Problem parsing Debug PData"); - } - reader.setIndex((int) headerLength); - //System.out.println(reader.dump()); - // TODO: current partial implementation does not work (throws exception) - // for ucrtbase.dll arm64. Need to look at this closer. + throws CancelledException { + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + List myPData = new ArrayList<>(); + int streamLength = reader.getLimit(); + RvaVaDebugHeader header = new RvaVaDebugHeader(); + header.deserialize(reader); + //System.out.println(header.dump()); + if (header.getHeaderVersion() != 1) { + return myPData; // Silent... TODO: add logging event. + } + long headerLength = header.getHeaderLength(); + long dataLength = header.getDataLength(); + if (headerLength + dataLength > streamLength) { + throw new PdbException("Problem parsing Debug PData"); + } + reader.setIndex((int) headerLength); + //System.out.println(reader.dump()); + // TODO: current partial implementation does not work (throws exception) + // for ucrtbase.dll arm64. Need to look at this closer. // while (reader.hasMore()) { // pdb.checkCancelled(); // ImageFunctionEntry entry = new ImageFunctionEntry(); @@ -389,23 +395,30 @@ public class DebugData { // xDataReader.setIndex((int) index); // //System.out.println(xDataReader.dumpBytes(0x20)); // } - // TODO: More work possible. See XData processing and notes there. This is very - // incomplete. - PdbDebugInfo debugInfo = pdb.getDebugInfo(); - if (debugInfo instanceof PdbNewDebugInfo) { - //Processor target = pdb.getTargetProcessor(); - PdbNewDebugInfo dbi = (PdbNewDebugInfo) debugInfo; - ImageFileMachine machine = dbi.getMachineType(); - switch (machine) { - case IA64: - break; - case AMD64: - break; - default: - break; + // TODO: More work possible. See XData processing and notes there. This is very + // incomplete. + PdbDebugInfo debugInfo = pdb.getDebugInfo(); + if (debugInfo instanceof PdbNewDebugInfo) { + //Processor target = pdb.getTargetProcessor(); + PdbNewDebugInfo dbi = (PdbNewDebugInfo) debugInfo; + ImageFileMachine machine = dbi.getMachineType(); + switch (machine) { + case IA64: + break; + case AMD64: + break; + default: + break; + } } + return myPData; } - return myPData; + catch (PdbException | IOException e) { + PdbLog.message("Returning null Debug PData due to" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; + } + } /** diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java index 40ca480083..17464d1612 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/AbstractFunctionTypeApplier.java @@ -237,8 +237,8 @@ public abstract class AbstractFunctionTypeApplier extends MsDataTypeApplier { } /** - * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types - * to ensure that the types get scheduled... and detects whether any types were not yet + * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(RecordNumber)}) on all underlying + * types to ensure that the types get scheduled... and detects whether any types were not yet * available so that this composite type is denoted as not done. * @param type the MS type of the function * @return {@code true} if all underlying types are already available diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassFieldAttributes.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassFieldAttributes.java new file mode 100644 index 0000000000..7daf68c059 --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/ClassFieldAttributes.java @@ -0,0 +1,238 @@ +/* ### + * 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.pdb.pdbapplicator; + +import java.util.*; + +import ghidra.app.util.bin.format.pdb2.pdbreader.type.ClassFieldMsAttributes; + +/** + * + */ +public class ClassFieldAttributes { + + private static final Map map = new HashMap<>(); + + // These initializations use the map above, so it must be initialized first + public static final ClassFieldAttributes UNKNOWN = get(Access.UNKNOWN, Property.UNKNOWN); + public static final ClassFieldAttributes BLANK = get(Access.BLANK, Property.BLANK); + + private final Access access; + private final Property property; + + public static ClassFieldAttributes get(Access access, Property property) { + ClassFieldAttributes key = new ClassFieldAttributes(access, property); + ClassFieldAttributes cfa = map.putIfAbsent(key, key); + return (cfa != null) ? cfa : key; + } + + static ClassFieldAttributes convert(ClassFieldMsAttributes msAtts, Access defaultAccess) { + Access myAccess = switch (msAtts.getAccess()) { + case PUBLIC -> Access.PUBLIC; + case PROTECTED -> Access.PROTECTED; + case PRIVATE -> Access.PRIVATE; + case BLANK -> defaultAccess; + default -> Access.UNKNOWN; + }; + Property myProperty = switch (msAtts.getProperty()) { + case VIRTUAL -> Property.VIRTUAL; + case STATIC -> Property.STATIC; + case FRIEND -> Property.FRIEND; + case BLANK -> Property.BLANK; + default -> Property.UNKNOWN; + }; + return get(myAccess, myProperty); + } + + private ClassFieldAttributes(Access access, Property property) { + this.access = access; + this.property = property; + } + + Access getAccess() { + return access; + } + + Property getProperty() { + return property; + } + + void emit(StringBuilder builder) { + StringBuilder myBuilder = new StringBuilder(); + if (access.getValue() > Access.BLANK.getValue()) { + myBuilder.append(access); + myBuilder.append(' '); + } + if (property.getValue() > Property.BLANK.getValue()) { + myBuilder.append(property); + myBuilder.append(' '); + } + builder.append(myBuilder); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + emit(builder); + return builder.toString(); + } + + @Override + public int hashCode() { + return Objects.hash(access, property); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ClassFieldAttributes other = (ClassFieldAttributes) obj; + return access == other.access && property == other.property; + } + + //---------------------------------------------------------------------------------------------- + // TODO: Consider expanding these beyond C++. + // See https://en.wikipedia.org/wiki/Access_modifiers + // These could then be: +// UNKNOWN("UNKNOWN_ACCESS ", -1), +// OPEN("open", 0), +// PUBLIC("internal", 1), +// INTERNAL("internal", 2), +// PACKAGE("package", 3), +// PROTECTED("protected", 4), +// PROTECTED_INTERNAL("protected internal", 5), +// PRIVATE_PROTECTED("private protected", 6), +// FILE("file", 7), +// FILE_PRIVATE("fileprivate", 8), +// PRIVATE("private", 9); + static enum Access { + UNKNOWN("UNKNOWN_ACCESS", -1), + BLANK("", 0), // eliminated 20230524... using defaultAccess on some methods. Could renumber + PUBLIC("public", 1), + PROTECTED("protected", 2), + PRIVATE("private", 3); + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (Access val : values()) { + BY_VALUE.put(val.value, val); + } + } + private final String label; + private final int value; + + public String getString() { + return label; + } + + @Override + public String toString() { + return label; + } + + public int getValue() { + return value; + } + + public static Access fromValue(int val) { + return BY_VALUE.getOrDefault(val, UNKNOWN); + } + + private Access(String label, int value) { + this.label = label; + this.value = value; + } + + /** + * Merge two Access values, leaning toward more restrictive. UNKNOWN is only returned + * if both are UNKNOWN. + * @param other value to merge + * @return the merged value + */ + public Access mergeRestrictive(Access other) { + // No need to test for UNKNOWN as its value is on the permissive end. + if (this.value > other.value) { + return this; + } + return other; + } + + /** + * Merge two Access values, leaning toward more permissive. UNKNOWN is only returned + * if both are UNKNOWN. + * @param other value to merge + * @return the merged value + */ + public Access mergePermissive(Access other) { + if (this.value < other.value) { + // Only need special test for UNKNOWN here, as its value is on the permissive end. + if (this == UNKNOWN) { + return other; + } + return this; + } + return other; + } + } + + //---------------------------------------------------------------------------------------------- + static enum Property { + UNKNOWN("INVALID_PROPERTY", -1), + BLANK("", 0), // means non-virtual, non-static, non-friend + VIRTUAL("virtual", 1), + STATIC("static", 2), + FRIEND("friend", 3); + // Also consider , , . See MSFT. + + private static final Map BY_VALUE = new HashMap<>(); + static { + for (Property val : values()) { + BY_VALUE.put(val.value, val); + } + } + private final String label; + private final int value; + + public String getString() { + return label; + } + + @Override + public String toString() { + return label; + } + + public int getValue() { + return value; + } + + public static Property fromValue(int val) { + return BY_VALUE.getOrDefault(val, UNKNOWN); + } + + private Property(String label, int value) { + this.label = label; + this.value = value; + } + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java index d2dca25ef3..7ca899e2f3 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CompositeTypeApplier.java @@ -23,6 +23,7 @@ import ghidra.app.util.SymbolPath; import ghidra.app.util.bin.format.pdb.DefaultCompositeMember; import ghidra.app.util.bin.format.pdb2.pdbreader.*; import ghidra.app.util.bin.format.pdb2.pdbreader.type.*; +import ghidra.app.util.pdb.pdbapplicator.ClassFieldAttributes.Access; import ghidra.program.model.data.*; import ghidra.util.Msg; import ghidra.util.exception.AssertException; @@ -211,6 +212,9 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { throws PdbException, CancelledException { AbstractCompositeMsType cType = (AbstractCompositeMsType) type; + ClassFieldAttributes.Access defaultAccess = + (type instanceof AbstractClassMsType) ? ClassFieldAttributes.Access.PRIVATE + : ClassFieldAttributes.Access.PUBLIC; for (AbstractMsType baseType : msBases) { applicator.checkCancelled(); @@ -222,13 +226,14 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } if (baseType instanceof AbstractBaseClassMsType baseClassType) { - applyDirectBaseClass(baseClassType, myClassType); + applyDirectBaseClass(baseClassType, myClassType, defaultAccess); } else if (baseType instanceof AbstractVirtualBaseClassMsType virtualBaseClassType) { - applyDirectVirtualBaseClass(virtualBaseClassType, myClassType); + applyDirectVirtualBaseClass(virtualBaseClassType, myClassType, defaultAccess); } else if (baseType instanceof AbstractIndirectVirtualBaseClassMsType indirectVirtualBaseClassType) { - applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType); + applyIndirectVirtualBaseClass(indirectVirtualBaseClassType, myClassType, + defaultAccess); } else { throw new AssertException( @@ -237,7 +242,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } } - private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType) + private void applyDirectBaseClass(AbstractBaseClassMsType base, CppCompositeType myClassType, + Access defaultAccess) throws PdbException { CppCompositeType underlyingClassType = getUnderlyingClassType(base.getBaseClassRecordNumber()); @@ -246,11 +252,12 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } ClassFieldMsAttributes atts = base.getAttributes(); int offset = applicator.bigIntegerToInt(base.getOffset()); - myClassType.addDirectBaseClass(underlyingClassType, convertAttributes(atts), offset); + myClassType.addDirectBaseClass(underlyingClassType, + ClassFieldAttributes.convert(atts, defaultAccess), offset); } private void applyDirectVirtualBaseClass(AbstractVirtualBaseClassMsType base, - CppCompositeType myClassType) throws PdbException { + CppCompositeType myClassType, Access defaultAccess) throws PdbException { CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); if (underlyingCt == null) { @@ -261,12 +268,13 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); - myClassType.addDirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + myClassType.addDirectVirtualBaseClass(underlyingCt, + ClassFieldAttributes.convert(atts, defaultAccess), basePointerOffset, vbtptr, offsetFromVbt); } private void applyIndirectVirtualBaseClass(AbstractIndirectVirtualBaseClassMsType base, - CppCompositeType myClassType) throws PdbException { + CppCompositeType myClassType, Access defaultAccess) throws PdbException { CppCompositeType underlyingCt = getUnderlyingClassType(base.getBaseClassRecordNumber()); if (underlyingCt == null) { @@ -277,7 +285,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { ClassFieldMsAttributes atts = base.getAttributes(); int basePointerOffset = applicator.bigIntegerToInt(base.getBasePointerOffset()); int offsetFromVbt = applicator.bigIntegerToInt(base.getBaseOffsetFromVbt()); - myClassType.addIndirectVirtualBaseClass(underlyingCt, convertAttributes(atts), + myClassType.addIndirectVirtualBaseClass(underlyingCt, + ClassFieldAttributes.convert(atts, defaultAccess), basePointerOffset, vbtptr, offsetFromVbt); } @@ -313,49 +322,18 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { return dataType; } - private static CppCompositeType.ClassFieldAttributes convertAttributes( - ClassFieldMsAttributes atts) { - CppCompositeType.Access myAccess; - switch (atts.getAccess()) { - case PUBLIC: - myAccess = CppCompositeType.Access.PUBLIC; - break; - case PROTECTED: - myAccess = CppCompositeType.Access.PROTECTED; - break; - case PRIVATE: - myAccess = CppCompositeType.Access.PRIVATE; - break; - default: - myAccess = CppCompositeType.Access.BLANK; - break; - } - CppCompositeType.Property myProperty; - switch (atts.getProperty()) { - case VIRTUAL: - myProperty = CppCompositeType.Property.VIRTUAL; - break; - case STATIC: - myProperty = CppCompositeType.Property.STATIC; - break; - case FRIEND: - myProperty = CppCompositeType.Property.FRIEND; - break; - default: - myProperty = CppCompositeType.Property.BLANK; - break; - } - return new CppCompositeType.ClassFieldAttributes(myAccess, myProperty); - } - private void addMembers(Composite composite, CppCompositeType myClassType, List msMembers, AbstractCompositeMsType type, List myMembers) throws CancelledException, PdbException { + ClassFieldAttributes.Access defaultAccess = + (type instanceof AbstractClassMsType) ? ClassFieldAttributes.Access.PRIVATE + : ClassFieldAttributes.Access.PUBLIC; for (int index = 0; index < msMembers.size(); index++) { applicator.checkCancelled(); AbstractMemberMsType memberType = msMembers.get(index); - DefaultPdbUniversalMember member = getNonStaticMember(composite, memberType, index); + DefaultPdbUniversalMember member = + getNonStaticMember(composite, defaultAccess, memberType, index); DataType dt = member.getDataType().getDataType(); myMembers.add(member); myClassType.addMember(member.getName(), dt, member.isZeroLengthArray(), @@ -386,8 +364,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } /** - * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(Integer)}) on all underlying types - * to ensure that the types get scheduled... and detects whether any types were not yet + * Uses {@link DefaultPdbApplicator#getDataTypeOrSchedule(RecordNumber)}) on all underlying + * types to ensure that the types get scheduled... and detects whether any types were not yet * available so that this composite type is denoted as not done. * @param lists the lists of all underlying types * @return {@code true} if all underlying types are already available @@ -461,14 +439,15 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { throw new PdbException("Unhandled type: " + method.getClass().getSimpleName()); } } - for (AbstractNestedTypeMsType nested : lists.nestedTypes()) { - applicator.checkCancelled(); - RecordNumber recordNumber = nested.getNestedTypeDefinitionRecordNumber(); - DataType dt = applicator.getDataTypeOrSchedule(recordNumber); - if (dt == null) { - done = false; - } - } + // Might cause problems, so remove until understood and possibly needed +// for (AbstractNestedTypeMsType nested : lists.nestedTypes()) { +// applicator.checkCancelled(); +// RecordNumber recordNumber = nested.getNestedTypeDefinitionRecordNumber(); +// DataType dt = applicator.getDataTypeOrSchedule(recordNumber); +// if (dt == null) { +// done = false; +// } +// } for (AbstractMemberMsType nonstaticMember : lists.nonstaticMembers()) { applicator.checkCancelled(); RecordNumber recordNumber = nonstaticMember.getFieldTypeRecordNumber(); @@ -509,7 +488,7 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { } private DefaultPdbUniversalMember getNonStaticMember(Composite container, - AbstractMemberMsType memberMsType, int ordinal) + Access defaultAccess, AbstractMemberMsType memberMsType, int ordinal) throws CancelledException, PdbException { MsTypeApplier applier = applicator.getTypeApplier(memberMsType); @@ -546,7 +525,8 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier { arrayApplier.isFlexibleArray(fieldType)); DefaultPdbUniversalMember member = new DefaultPdbUniversalMember(memberName, fieldDataType, - isZeroLengthArray, offset, convertAttributes(memberAttributes), memberComment); + isZeroLengthArray, offset, + ClassFieldAttributes.convert(memberAttributes, defaultAccess), memberComment); return member; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java index 2c00a035e7..a34685d2c9 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/CppCompositeType.java @@ -252,8 +252,7 @@ public class CppCompositeType { } public void addVirtualFunctionTablePointer(String name, DataType dataType, int offset) { - Member newMember = new Member(name, dataType, false, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset); + Member newMember = new Member(name, dataType, false, ClassFieldAttributes.UNKNOWN, offset); layoutVftPtrMembers.add(newMember); } @@ -275,14 +274,14 @@ public class CppCompositeType { public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset, String comment) { - addMember(memberName, dataType, isFlexibleArray, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment); + addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + comment); } public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset) { - addMember(memberName, dataType, isFlexibleArray, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null); + addMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + null); } public void addMember(String memberName, DataType dataType, boolean isFlexibleArray, @@ -314,14 +313,14 @@ public class CppCompositeType { */ public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset, String comment) { - insertMember(memberName, dataType, isFlexibleArray, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, comment); + insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + comment); } public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, int offset) { - insertMember(memberName, dataType, isFlexibleArray, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset, null); + insertMember(memberName, dataType, isFlexibleArray, ClassFieldAttributes.UNKNOWN, offset, + null); } public void insertMember(String memberName, DataType dataType, boolean isFlexibleArray, @@ -351,8 +350,7 @@ public class CppCompositeType { } public void addStaticMember(String memberName, DataType dataType) { - addStaticMember(memberName, dataType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + addStaticMember(memberName, dataType, ClassFieldAttributes.UNKNOWN); } public void addStaticMember(String memberName, DataType dataType, @@ -379,8 +377,7 @@ public class CppCompositeType { } public void addSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + addSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); } public void addSyntacticBaseClass(CppCompositeType baseClassType, @@ -390,8 +387,7 @@ public class CppCompositeType { } public void addDirectSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addDirectSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + addDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); } public void addDirectSyntacticBaseClass(CppCompositeType baseClassType, @@ -401,8 +397,7 @@ public class CppCompositeType { } public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType) throws PdbException { - addVirtualSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN)); + addVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN); } public void addVirtualSyntacticBaseClass(CppCompositeType baseClassType, @@ -413,8 +408,7 @@ public class CppCompositeType { public void insertSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) throws PdbException { - insertSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + insertSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); } public void insertSyntacticBaseClass(CppCompositeType baseClassType, @@ -429,8 +423,7 @@ public class CppCompositeType { public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) throws PdbException { - insertDirectSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + insertDirectSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); } public void insertDirectSyntacticBaseClass(CppCompositeType baseClassType, @@ -445,8 +438,7 @@ public class CppCompositeType { public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, int ordinal) throws PdbException { - insertVirtualSyntacticBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), ordinal); + insertVirtualSyntacticBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, ordinal); } public void insertVirtualSyntacticBaseClass(CppCompositeType baseClassType, @@ -461,8 +453,7 @@ public class CppCompositeType { //============================================================================================== public void addDirectBaseClass(CppCompositeType baseClassType, int offset) throws PdbException { - addDirectBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), offset); + addDirectBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, offset); } public void addDirectBaseClass(CppCompositeType baseClassType, ClassFieldAttributes attributes, @@ -491,9 +482,8 @@ public class CppCompositeType { // public void addDirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, DataType vbptr, int offsetFromVbt) throws PdbException { - addDirectVirtualBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr, - offsetFromVbt); + addDirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset, + vbptr, offsetFromVbt); } public void addDirectVirtualBaseClass(CppCompositeType baseClassType, @@ -524,9 +514,8 @@ public class CppCompositeType { // public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, int basePointerOffset, DataType vbptr, int offsetFromVbt) throws PdbException { - addIndirectVirtualBaseClass(baseClassType, - new ClassFieldAttributes(Access.UNKNOWN, Property.UNKNOWN), basePointerOffset, vbptr, - offsetFromVbt); + addIndirectVirtualBaseClass(baseClassType, ClassFieldAttributes.UNKNOWN, basePointerOffset, + vbptr, offsetFromVbt); } public void addIndirectVirtualBaseClass(CppCompositeType baseClassType, @@ -947,7 +936,8 @@ public class CppCompositeType { } boolean allVbtFound = true; - for (Entry tableEntry : placeholderVirtualBaseTables.entrySet()) { + for (Entry tableEntry : placeholderVirtualBaseTables + .entrySet()) { int vbtptrOffset = tableEntry.getKey(); PlaceholderVirtualBaseTable table = tableEntry.getValue(); if (!table.validateOffset()) { @@ -1736,7 +1726,8 @@ public class CppCompositeType { } PlaceholderVirtualBaseTableEntry getEntryByName(String nameParam) { - for (Entry entry : entriesByIndex.entrySet()) { + for (Entry entry : entriesByIndex + .entrySet()) { if (nameParam.equals( entry.getValue().getVirtualBaseClass().getBaseClassType().getName())) { return entry.getValue(); @@ -1749,36 +1740,6 @@ public class CppCompositeType { //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------- - static class ClassFieldAttributes { - Access access; - Property property; - - ClassFieldAttributes(Access access, Property property) { - this.access = access; - this.property = property; - } - - private Access getAccess() { - return access; - } - - private Property getProperty() { - return property; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (access.getValue() > Access.BLANK.getValue()) { - builder.append(access); - } - if (property.equals(Property.VIRTUAL)) { - builder.append(property); - } - return builder.toString(); - } - } - //---------------------------------------------------------------------------------------------- static enum Type { UNKNOWN("UNKNOWN_TYPE", -1), @@ -1822,91 +1783,4 @@ public class CppCompositeType { } } - //---------------------------------------------------------------------------------------------- - static enum Access { - UNKNOWN("UNKNOWN_ACCESS ", -1), - BLANK("", 0), - PUBLIC("public", 1), - PROTECTED("protected", 2), - PRIVATE("private", 3); - - private static final Map BY_VALUE = new HashMap<>(); - static { - for (Access val : values()) { - BY_VALUE.put(val.value, val); - } - } - private final String label; - private final int value; - - public String getString() { - return label; - } - - @Override - public String toString() { - if (label.length() != 0) { - return label + " "; - } - return label; - } - - public int getValue() { - return value; - } - - public static Access fromValue(int val) { - return BY_VALUE.getOrDefault(val, UNKNOWN); - } - - private Access(String label, int value) { - this.label = label; - this.value = value; - } - } - - //---------------------------------------------------------------------------------------------- - static enum Property { - UNKNOWN("INVALID_PROPERTY", -1), - BLANK("", 0), - VIRTUAL("virtual ", 1), - STATIC("static ", 2), - FRIEND("friend ", 3); - // Also consider , , . See MSFT. - - private static final Map BY_VALUE = new HashMap<>(); - static { - for (Property val : values()) { - BY_VALUE.put(val.value, val); - } - } - private final String label; - private final int value; - - public String getString() { - return label; - } - - @Override - public String toString() { - if (label.length() != 0) { - return label + " "; - } - return label; - } - - public int getValue() { - return value; - } - - public static Property fromValue(int val) { - return BY_VALUE.getOrDefault(val, UNKNOWN); - } - - private Property(String label, int value) { - this.label = label; - this.value = value; - } - } - } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java index 3f7452fa9e..42bbb96a18 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbApplicator.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. @@ -15,7 +15,6 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.io.IOException; import java.math.BigInteger; import java.util.*; @@ -197,12 +196,10 @@ public class DefaultPdbApplicator implements PdbApplicator { * @param logParam the MessageLog to which to output messages * @throws PdbException if there was a problem processing the data * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ public void applyTo(Program programParam, DataTypeManager dataTypeManagerParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, - MessageLog logParam) throws PdbException, CancelledException, IOException { + MessageLog logParam) throws PdbException, CancelledException { // FIXME: should not support use of DataTypeManager-only since it will not have the correct // data organization if it corresponds to a data type archive. Need to evaluate archive @@ -420,12 +417,10 @@ public class DefaultPdbApplicator implements PdbApplicator { * Initializes helper classes and data items used for applying the PDB * @throws CancelledException upon user cancellation * @throws PdbException upon error in processing components - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ private void initializeApplyTo(Program programParam, DataTypeManager dataTypeManagerParam, Address imageBaseParam, PdbApplicatorOptions applicatorOptionsParam, - MessageLog logParam) throws PdbException, CancelledException, IOException { + MessageLog logParam) throws PdbException, CancelledException { validateAndSetParameters(programParam, dataTypeManagerParam, imageBaseParam, applicatorOptionsParam, logParam); @@ -846,7 +841,7 @@ public class DefaultPdbApplicator implements PdbApplicator { if (dt != null) { return dt; } - multiphaseResolver.scheduleTodo(recordNumber); + multiphaseResolver.scheduleTodo(mappedNumber); return null; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java index 980d6d30dc..55ba1cf70c 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/DefaultPdbUniversalMember.java @@ -16,7 +16,6 @@ package ghidra.app.util.pdb.pdbapplicator; import ghidra.app.util.bin.format.pdb.*; -import ghidra.app.util.pdb.pdbapplicator.CppCompositeType.*; import ghidra.program.model.data.DataType; import ghidra.util.exception.CancelledException; @@ -30,9 +29,6 @@ public class DefaultPdbUniversalMember extends PdbMember { private ClassFieldAttributes attributes; private boolean isZeroLengthArray; - private static final ClassFieldAttributes blankAtttributes = - new ClassFieldAttributes(Access.BLANK, Property.BLANK); - /** * Default PDB member construction * @param name member field name. For bitfields this also conveys the bit-size @@ -43,7 +39,7 @@ public class DefaultPdbUniversalMember extends PdbMember { DefaultPdbUniversalMember(String name, DataType dataType, int offset) { super(name, dataType.getName(), offset, null); this.dataType = dataType; - this.attributes = blankAtttributes; + this.attributes = ClassFieldAttributes.BLANK; this.isZeroLengthArray = false; } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java index 14d9b668ba..ef30881d2f 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MsTypeApplier.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. @@ -16,20 +16,9 @@ package ghidra.app.util.pdb.pdbapplicator; import ghidra.app.util.bin.format.pdb2.pdbreader.PdbLog; -import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType; -import ghidra.program.model.data.DataType; /** - * Abstract class representing the applier for a specific PDB_ID type. The - * {@link #apply(AbstractMsType type, FixupContext fixupContext, boolean breakCycle)} method - * creates an associated {@link DataType}, if applicable, The latter of these forces the - * creation of the defined type when and forward reference type is not appropriate for the - * consumer. Note that this should only be used when sanctioned and not on a whim. Currently, - * such situations include when ghidra needs a defined type for the underlying type of an array, - * when used as a base class of a class or when needed as a member of another class/composite. - * Methods associated with the {@link MsTypeApplier} or derived class will - * make fields available to the user, first by trying to get them from the {@link DataType}, - * otherwise getting them from the {@link AbstractMsType} argument. + * Abstract class representing the applier for a specific PDB_ID type. */ public abstract class MsTypeApplier { diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java index 0d25925244..567454fff7 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/MultiphaseDataTypeResolver.java @@ -59,6 +59,8 @@ public class MultiphaseDataTypeResolver { if (applicator.getDataType(recordNumber) != null) { return; } + // Location where one might do conditional: todoStack.setDebug(true) + // If not in the map, it will also not be in the todo or resolve stacks, as both // should be empty at this point. scheduleTodo(recordNumber); @@ -81,6 +83,7 @@ public class MultiphaseDataTypeResolver { resolveStack.push(recordToProcess); } } + // If set true above, location where one might do conditional: todoStack.setDebug(false) // Pop top of stack and work on it. while ((recordToProcess = resolveStack.pop()) != null) { @@ -134,13 +137,21 @@ public class MultiphaseDataTypeResolver { private RecordNode(RecordNumber recordNumber) { this.recordNumber = recordNumber; } + + @Override + public String toString() { + return recordNumber.toString(); + } } + static final int TO_STRING_LIMIT = 500; static final RecordNumber HEAD = RecordNumber.typeRecordNumber(-1); static final RecordNumber TAIL = RecordNumber.typeRecordNumber(-2); Map map; RecordNode head; RecordNode tail; + boolean debug; + StringBuilder debugBuilder; /** * Constructor for new record stack @@ -156,6 +167,14 @@ public class MultiphaseDataTypeResolver { tail.prev = null; } + /** + * Set or clear developer debug + * @param debug {@code true} to turn on; {@code false} to turn off + */ + void setDebug(boolean debug) { + this.debug = debug; + } + /** * Indicates if number number exists on stack * @param recordNumber the record number to check @@ -177,6 +196,14 @@ public class MultiphaseDataTypeResolver { } if (node == null) { node = new RecordNode(recordNumber); + if (debug) { + if (map.isEmpty()) { + debugBuilder = new StringBuilder(); + } + debugBuilder.append("push:"); + debugBuilder.append(recordNumber); + debugBuilder.append("\n"); + } map.put(recordNumber, node); } else { // already exists in non-top-of-stack position @@ -208,6 +235,14 @@ public class MultiphaseDataTypeResolver { } removeNodeLinkage(node); map.remove(node.recordNumber); + if (debug) { + debugBuilder.append(" pop:"); + debugBuilder.append(node.recordNumber); + debugBuilder.append("\n"); + if (map.isEmpty()) { + System.out.println(debugBuilder.toString()); + } + } return node.recordNumber; } @@ -249,6 +284,27 @@ public class MultiphaseDataTypeResolver { node.next = null; } + @Override + public String toString() { + int count = 0; + RecordNode node = head.prev; + StringBuilder builder = new StringBuilder(); + builder.append('['); + while (node != tail && count < TO_STRING_LIMIT) { + if (count != 0) { + builder.append(","); + } + builder.append(node); + node = node.prev; + count++; + } + if (node != tail) { + builder.append("..."); + } + builder.append(']'); + return builder.toString(); + } + } } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java index fba43adeb1..8e41472a79 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressCalculator.java @@ -15,7 +15,6 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.io.IOException; import java.util.*; import org.apache.commons.collections4.CollectionUtils; @@ -36,7 +35,7 @@ abstract class PdbAddressCalculator { private int maxSegment; static PdbAddressCalculator chooseAddressCalculator(PdbApplicator applicator, Address imageBase) - throws CancelledException, PdbException, IOException { + throws CancelledException, PdbException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo dbi = pdb.getDebugInfo(); diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java index 97e1efadf3..415960712b 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbAddressManager.java @@ -15,7 +15,6 @@ */ package ghidra.app.util.pdb.pdbapplicator; -import java.io.IOException; import java.util.*; import ghidra.app.util.bin.format.pdb2.pdbreader.*; @@ -80,11 +79,9 @@ public class PdbAddressManager { * @param imageBase Address from which all other addresses are based. * @throws PdbException If Program is null; * @throws CancelledException upon user cancellation - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ PdbAddressManager(DefaultPdbApplicator applicator, Address imageBase) - throws PdbException, CancelledException, IOException { + throws PdbException, CancelledException { Objects.requireNonNull(applicator, "applicator may not be null"); Objects.requireNonNull(imageBase, "imageBase may not be null"); this.applicator = applicator; @@ -342,11 +339,8 @@ public class PdbAddressManager { /** * Determines memory blocks * @throws CancelledException upon user cancellation - * @throws PdbException upon error in processing components - * @throws IOException on file seek or read, invalid parameters, bad file configuration, or - * inability to read required bytes */ - private void determineMemoryBlocks() throws CancelledException, PdbException, IOException { + private void determineMemoryBlocks() throws CancelledException { AbstractPdb pdb = applicator.getPdb(); PdbDebugInfo debugInfo = pdb.getDebugInfo(); segmentMapList = debugInfo.getSegmentMapList(); diff --git a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandler2Test.java similarity index 97% rename from Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java rename to Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandler2Test.java index 6dd99d64e6..7ef045bd68 100644 --- a/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandlerTest2.java +++ b/Ghidra/Features/PDB/src/test/java/ghidra/app/util/pdb/pdbapplicator/ConflictHandler2Test.java @@ -36,12 +36,12 @@ import ghidra.util.task.TaskMonitor; * * */ -public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest { +public class ConflictHandler2Test extends AbstractGhidraHeadedIntegrationTest { private ProgramDB program; private DataTypeManagerDB dtm; private int transactionID; - public ConflictHandlerTest2() { + public ConflictHandler2Test() { super(); } @@ -137,7 +137,7 @@ public class ConflictHandlerTest2 extends AbstractGhidraHeadedIntegrationTest { } try { if (!DefaultCompositeMember.applyDataTypeMembers(composite, false, size, members, - msg -> Msg.warn(ConflictHandlerTest2.class, msg), monitor)) { + msg -> Msg.warn(ConflictHandler2Test.class, msg), monitor)) { ((Structure) composite).deleteAll(); } }