diff --git a/BurnOutSharp.Builder/PortableExecutable.cs b/BurnOutSharp.Builder/PortableExecutable.cs
index 9b0ccb69..6903fd0d 100644
--- a/BurnOutSharp.Builder/PortableExecutable.cs
+++ b/BurnOutSharp.Builder/PortableExecutable.cs
@@ -174,6 +174,29 @@ namespace BurnOutSharp.Builder
#endregion
+ #region Debug Table
+
+ // Should also be in the '.debug' section
+ if (optionalHeader.Debug != null && optionalHeader.Debug.VirtualAddress != 0)
+ {
+ // If the offset for the debug table doesn't exist
+ int debugTableAddress = initialOffset
+ + (int)optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ if (debugTableAddress >= data.Length)
+ return executable;
+
+ // Try to parse the debug table
+ int endOffset = (int)(debugTableAddress + optionalHeader.CertificateTable.Size);
+ var debugTable = ParseDebugTable(data, debugTableAddress, endOffset, executable.SectionTable);
+ if (debugTable == null)
+ return null;
+
+ // Set the debug table
+ executable.DebugTable = debugTable;
+ }
+
+ #endregion
+
#region Export Table
// Should also be in the '.rsrc' section
@@ -714,6 +737,45 @@ namespace BurnOutSharp.Builder
return delayLoadDirectoryTable;
}
+ ///
+ /// Parse a Stream into a debug table
+ ///
+ /// Byte array to parse
+ /// Offset into the byte array
+ /// First address not part of the debug table
+ /// Section table to use for virtual address translation
+ /// Filled debug table on success, null on error
+ private static DebugTable ParseDebugTable(byte[] data, int offset, int endOffset, SectionHeader[] sections)
+ {
+ // TODO: Use marshalling here instead of building
+ var debugTable = new DebugTable();
+
+ var debugDirectoryTable = new List();
+
+ while (offset < endOffset)
+ {
+ var debugDirectoryEntry = new DebugDirectoryEntry();
+
+ debugDirectoryEntry.Characteristics = data.ReadUInt32(ref offset);
+ debugDirectoryEntry.TimeDateStamp = data.ReadUInt32(ref offset);
+ debugDirectoryEntry.MajorVersion = data.ReadUInt16(ref offset);
+ debugDirectoryEntry.MinorVersion = data.ReadUInt16(ref offset);
+ debugDirectoryEntry.DebugType = (DebugType)data.ReadUInt32(ref offset);
+ debugDirectoryEntry.SizeOfData = data.ReadUInt32(ref offset);
+ debugDirectoryEntry.AddressOfRawData = data.ReadUInt32(ref offset);
+ debugDirectoryEntry.PointerToRawData = data.ReadUInt32(ref offset);
+
+ debugDirectoryTable.Add(debugDirectoryEntry);
+ }
+
+ debugTable.DebugDirectoryTable = debugDirectoryTable.ToArray();
+
+ // TODO: Should we read the debug data in? Most of it is unformatted or undocumented
+ // TODO: Implement .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
+
+ return debugTable;
+ }
+
///
/// Parse a byte array into a export table
///
@@ -1298,6 +1360,30 @@ namespace BurnOutSharp.Builder
#endregion
+ #region Debug Table
+
+ // Should also be in the '.debug' section
+ if (optionalHeader.Debug != null && optionalHeader.Debug.VirtualAddress != 0)
+ {
+ // If the offset for the debug table doesn't exist
+ int debugTableAddress = initialOffset
+ + (int)optionalHeader.Debug.VirtualAddress.ConvertVirtualAddress(executable.SectionTable);
+ if (debugTableAddress >= data.Length)
+ return executable;
+
+ // Try to parse the debug table
+ data.Seek(debugTableAddress, SeekOrigin.Begin);
+ int endOffset = (int)(debugTableAddress + optionalHeader.CertificateTable.Size);
+ var debugTable = ParseDebugTable(data, endOffset, executable.SectionTable);
+ if (debugTable == null)
+ return null;
+
+ // Set the debug table
+ executable.DebugTable = debugTable;
+ }
+
+ #endregion
+
#region Export Table
// Should also be in the '.edata' section
@@ -1834,6 +1920,44 @@ namespace BurnOutSharp.Builder
return delayLoadDirectoryTable;
}
+ ///
+ /// Parse a Stream into a debug table
+ ///
+ /// Stream to parse
+ /// First address not part of the debug table
+ /// Section table to use for virtual address translation
+ /// Filled debug table on success, null on error
+ private static DebugTable ParseDebugTable(Stream data, int endOffset, SectionHeader[] sections)
+ {
+ // TODO: Use marshalling here instead of building
+ var debugTable = new DebugTable();
+
+ var debugDirectoryTable = new List();
+
+ while (data.Position < endOffset)
+ {
+ var debugDirectoryEntry = new DebugDirectoryEntry();
+
+ debugDirectoryEntry.Characteristics = data.ReadUInt32();
+ debugDirectoryEntry.TimeDateStamp = data.ReadUInt32();
+ debugDirectoryEntry.MajorVersion = data.ReadUInt16();
+ debugDirectoryEntry.MinorVersion = data.ReadUInt16();
+ debugDirectoryEntry.DebugType = (DebugType)data.ReadUInt32();
+ debugDirectoryEntry.SizeOfData = data.ReadUInt32();
+ debugDirectoryEntry.AddressOfRawData = data.ReadUInt32();
+ debugDirectoryEntry.PointerToRawData = data.ReadUInt32();
+
+ debugDirectoryTable.Add(debugDirectoryEntry);
+ }
+
+ debugTable.DebugDirectoryTable = debugDirectoryTable.ToArray();
+
+ // TODO: Should we read the debug data in? Most of it is unformatted or undocumented
+ // TODO: Implement .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
+
+ return debugTable;
+ }
+
///
/// Parse a Stream into a export table
///
diff --git a/BurnOutSharp.Models/PortableExecutable/DebugTable.cs b/BurnOutSharp.Models/PortableExecutable/DebugTable.cs
new file mode 100644
index 00000000..04468cee
--- /dev/null
+++ b/BurnOutSharp.Models/PortableExecutable/DebugTable.cs
@@ -0,0 +1,38 @@
+namespace BurnOutSharp.Models.PortableExecutable
+{
+ ///
+ /// The .debug section is used in object files to contain compiler-generated debug
+ /// information and in image files to contain all of the debug information that is
+ /// generated. This section describes the packaging of debug information in object
+ /// and image files.
+ ///
+ /// The next section describes the format of the debug directory, which can be
+ /// anywhere in the image. Subsequent sections describe the "groups" in object
+ /// files that contain debug information.
+ ///
+ /// The default for the linker is that debug information is not mapped into the
+ /// address space of the image. A .debug section exists only when debug information
+ /// is mapped in the address space.
+ ///
+ ///
+ public class DebugTable
+ {
+ ///
+ /// Image files contain an optional debug directory that indicates what form
+ /// of debug information is present and where it is. This directory consists
+ /// of an array of debug directory entries whose location and size are
+ /// indicated in the image optional header.
+ ///
+ /// The debug directory can be in a discardable .debug section (if one exists),
+ /// or it can be included in any other section in the image file, or not be
+ /// in a section at all.
+ ///
+ /// Each debug directory entry identifies the location and size of a block of
+ /// debug information. The specified RVA can be zero if the debug information
+ /// is not covered by a section header (that is, it resides in the image
+ /// file and is not mapped into the run-time address space). If it is mapped,
+ /// the RVA is its address.
+ ///
+ public DebugDirectoryEntry[] DebugDirectoryTable;
+ }
+}
diff --git a/BurnOutSharp.Models/PortableExecutable/Executable.cs b/BurnOutSharp.Models/PortableExecutable/Executable.cs
index c1e4ea54..7c9d199d 100644
--- a/BurnOutSharp.Models/PortableExecutable/Executable.cs
+++ b/BurnOutSharp.Models/PortableExecutable/Executable.cs
@@ -68,6 +68,11 @@ namespace BurnOutSharp.Models.PortableExecutable
// the object file contains managed code. The format of the metadata is not
// documented, but can be handed to the CLR interfaces for handling metadata.
+ ///
+ /// Debug table (.debug*)
+ ///
+ public DebugTable DebugTable { get; set; }
+
///
/// Export table (.edata)
///
@@ -101,9 +106,6 @@ namespace BurnOutSharp.Models.PortableExecutable
// - Delay Import Name Table
// - Delay Bound Import Address Table
// - Delay Unload Import Address Table
- // - The .debug Section
- // - [Debug Directory Entry]
- // - .debug$F (Object Only) / IMAGE_DEBUG_TYPE_FPO
// - The .drectve Section (Object Only)
// - The .pdata Section [Multiple formats per entry]
// - TLS Callback Functions