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 05d0cce0a7..c3e75c6de5 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 @@ -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. @@ -47,7 +47,8 @@ public class DebugData { X_DATA(7), P_DATA(8), NEW_FRAME_POINTER_OMISSION(9), - SECTION_HEADER_ORIG(10); + SECTION_HEADER_ORIG(10), + UNKNOWN_DEBUG_11(11); // should be renamed when identified private final int value; @@ -180,6 +181,20 @@ public class DebugData { return deserializeSectionHeaders(streamNum); } + /** + * Returns the New Frame Pointer Omission data (FrameDataRecord) + * @return the frame data or null if does not exist or problem parsing + * @throws CancelledException upon user cancellation + */ + public List getNewFramePointerOmissionData() + throws CancelledException { + int streamNum = getDebugStream(DebugType.NEW_FRAME_POINTER_OMISSION); + if (streamNum == MsfStream.NIL_STREAM_NUMBER) { + return null; + } + return deserializeNewFramePointerOmissionData(streamNum); + } + /** * Deserialize {@link DebugData} header from the {@link PdbByteReader} input. This parses * stream numbers for varying Debug Types--the order/location of the stream number is for @@ -259,6 +274,9 @@ public class DebugData { case SECTION_HEADER_ORIG: // imageSectionHeadersOrig = deserializeSectionHeaders(streamNum); break; + case UNKNOWN_DEBUG_11: + // unknown + break; } } } @@ -426,6 +444,28 @@ public class DebugData { } + private List deserializeNewFramePointerOmissionData(int streamNum) + throws CancelledException { + // TODO: check implementation for completeness. + try { + PdbByteReader reader = pdb.getReaderForStreamNumber(streamNum); + List frameData = new ArrayList<>(); + while (reader.hasMore()) { + pdb.checkCancelled(); + FrameDataRecord frameDataRecord = new FrameDataRecord(); + frameDataRecord.parse(reader); + frameData.add(frameDataRecord); + } + return frameData; + } + catch (PdbException | IOException e) { + //catch (IOException e) { + PdbLog.message("Returning null Debug New Frame Pointer Omission Data due to" + + " problem during deserialization from stream" + streamNum + ": " + e.getMessage()); + return null; + } + } + /** * Dumps the {@link DebugData}. This package-protected method is for debugging only * @param writer {@link Writer} to which to write the debug dump @@ -504,6 +544,16 @@ public class DebugData { } writer.write("End PData---------------------------------------------------\n"); + writer.write("NewFramePointerOmissionData---------------------------------\n"); + List frameData = getNewFramePointerOmissionData(); + if (frameData != null) { + for (FrameDataRecord frameDataRecord : frameData) { + pdb.checkCancelled(); + frameDataRecord.dump(writer); + } + } + writer.write("End NewFramePointerOmissionData-----------------------------\n"); + writer.write("End DebugData-----------------------------------------------\n"); } diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FrameDataRecord.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FrameDataRecord.java new file mode 100644 index 0000000000..e4967bec0a --- /dev/null +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FrameDataRecord.java @@ -0,0 +1,183 @@ +/* ### + * 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.pdb2.pdbreader; + +import java.io.IOException; +import java.io.Writer; + +/** + * FRAMEDATA from cvinfo.h + * Most members are coded as unsigned long or unsigned long bit-fields; two are coded as + * unsigned short: prolog and saved regs. + */ +public class FrameDataRecord { + + private long rvaStart; // unsigned long + private long numBlockBytes; // unsigned long + private long numLocalBytes; // unsigned long + private long numParamBytes; // unsigned long + private long maxStackBytes; // unsigned long + private long frameFunc; // ? // unsigned long + private int numPrologBytes; // unsigned short + private int numSavedRegBytes; // unsigned short + private boolean hasSEH; // unsigned long bit-field + private boolean hasEH; // unsigned long bit-field + private boolean isFunctionStart; // unsigned long bit-field + private long reserved; // contains shifted/masked remainder of unsigned long + + /** + * Returns the RVA start + * @return the RVA start + */ + public long getRvaStart() { + return rvaStart; + } + + /** + * Returns the number of bytes in the block (function) + * @return the number of bytes in the block + */ + public long getNumberBlockBytes() { + return numBlockBytes; + } + + /** + * Returns the number of bytes used by local variables + * @return the number of bytes used by locals + */ + public long getNumberLocalBytes() { + return numLocalBytes; + } + + /** + * Returns the number of bytes used by the parameters + * @return the number of bytes used by parameters + */ + public long getNumberParameterBytes() { + return numParamBytes; + } + + /** + * Returns max number of stack bytes + * @return max stack bytes + */ + public long getMaxStackBytes() { + return maxStackBytes; + } + + // TODO: change javadoc and method name and underlying variable once we've determined what + // this is + /** + * Returns the frame func... not yet sure what this is + * @return the frame func + */ + public long getFrameFunc() { + return frameFunc; + } + + /** + * Returns the number of bytes in the function prolog + * @return the number of bytes in the prolog + */ + public int getNumberFunctionPrologBytes() { + return numPrologBytes; + } + + /** + * Returns the number of bytes for saved registers + * @return the number of bytes used by saved registers + */ + public int getNumberSavedRegisterBytes() { + return numSavedRegBytes; + } + + /** + * Returns whether has SEH + * @return {@code true} if has SEH + */ + public boolean hasSEH() { + return hasSEH; + } + + /** + * Returns whether has EH + * @return {@code true} if has EH + */ + public boolean hasEH() { + return hasEH; + } + + /** + * Returns whether is function start + * @return {@code true} if us function start + */ + public boolean isFunctionStart() { + return isFunctionStart; + } + + /** + * Returns the value of the reserved, remaining 29 bit-field bits + * @return the value of the reserved field + */ + public long reserved() { + return reserved; + } + + public void parse(PdbByteReader reader) throws PdbException { + if (reader.numRemaining() < 32) { + throw new PdbException("Not enough data for FrameDataRecord"); + } + rvaStart = reader.parseUnsignedIntVal(); + numBlockBytes = reader.parseUnsignedIntVal(); + numLocalBytes = reader.parseUnsignedIntVal(); + numParamBytes = reader.parseUnsignedIntVal(); + maxStackBytes = reader.parseUnsignedIntVal(); + frameFunc = reader.parseUnsignedIntVal(); + numPrologBytes = reader.parseUnsignedShortVal(); + numSavedRegBytes = reader.parseUnsignedShortVal(); + reserved = reader.parseUnsignedIntVal(); + hasSEH = (reserved & 0x01) == 0x01; + reserved >>= 1; + hasEH = (reserved & 0x01) == 0x01; + reserved >>= 1; + isFunctionStart = (reserved & 0x01) == 0x01; + reserved >>= 1; + reserved &= 0x01ffffff; + } + + /** + * Dumps the {@link FramePointerOmissionRecord}. This package-protected method is for + * debugging only. + * @param writer {@link Writer} to which to write the debug dump. + * @throws IOException On issue writing to the {@link Writer}. + */ + void dump(Writer writer) throws IOException { + writer.write("FrameDataRecord---------------------------------------------\n"); + writer.write(String.format("rvaStart: 0X%08X\n", rvaStart)); + writer.write(String.format("numBlockBytes: 0X%08X\n", numBlockBytes)); + writer.write(String.format("numLocalBytes: 0X%08X\n", numLocalBytes)); + writer.write(String.format("numParamBytes: 0X%08X\n", numParamBytes)); + writer.write(String.format("maxStackBytes: 0X%08X\n", maxStackBytes)); + writer.write(String.format("frameFunc: 0X%08X\n", frameFunc)); + writer.write(String.format("numPrologBytes: 0X%04X\n", numPrologBytes)); + writer.write(String.format("numSavedRegBytes: 0X%04X\n", numSavedRegBytes)); + writer.write( + String.format("hasStructuedExceptionHandling: %s\n", Boolean.toString(hasSEH))); + writer.write(String.format("hasExceptionHandling: %s\n", Boolean.toString(hasEH))); + writer.write(String.format("isFunctionStart: %s\n", Boolean.toString(isFunctionStart))); + writer.write("End FrameDataRecord-----------------------------------------\n"); + } +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FramePointerOmissionRecord.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FramePointerOmissionRecord.java index 7538a64f47..c28faf9847 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FramePointerOmissionRecord.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/bin/format/pdb2/pdbreader/FramePointerOmissionRecord.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. @@ -38,7 +38,7 @@ import java.util.Map; * WORD reserved : 1; * WORD cbFrame : 2; * } FPO_DATA, *PFPO_DATA; - * + * * where... * ulOffStart = The offset of the first byte of the function code. * cbProcSize = The number of bytes in the function. @@ -52,7 +52,7 @@ import java.util.Map; * cbFrame = A variable that indicates the frame type, where... * FRAME_FPO (0) = FPO frame * FRAME_TRAP (1) = Trap frame - * FRAME_TSS (2) = TSS frame + * FRAME_TSS (2) = TSS frame * FRAME_NONFPO (3) = non-FPO frame * */ @@ -198,8 +198,7 @@ public class FramePointerOmissionRecord { void dump(Writer writer) throws IOException { writer.write("FramePointerOmissionRecord----------------------------------\n"); writer.write(String.format("firstFunctionByteOffset: 0X%08X\n", firstFunctionByteOffset)); - writer.write(String.format("firstFunctionByteOffset: 0X%08X\n", firstFunctionByteOffset)); - writer.write(String.format("numFunctionBytes: 0X%08XX\n", numFunctionBytes)); + writer.write(String.format("numFunctionBytes: 0X%08X\n", numFunctionBytes)); writer.write(String.format("numLocalVariables: 0X%08X\n", numLocalVariables)); writer.write(String.format("sizeOfParametersInDwords: 0X%08X\n", sizeOfParametersInDwords)); writer.write(String.format("numFunctionPrologBytes: 0X%04X\n", numFunctionPrologBytes));