From ac6ec349d3a2892c9aa54d17ee68ca3493c3c1e2 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Sun, 16 Oct 2022 14:01:37 -0400 Subject: [PATCH 1/3] Add support for reading LProcRef and ProcRef --- .../Records/CodeViewSymbol.cs | 2 + .../Records/ProcedureReferenceSymbol.cs | 96 +++++++++++++++++++ .../SerializedProcedureReferenceSymbol.cs | 27 ++++++ 3 files changed, 125 insertions(+) create mode 100644 src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs create mode 100644 src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs diff --git a/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs index 5869c3acd..21d6191af 100644 --- a/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs +++ b/src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs @@ -34,6 +34,8 @@ public static CodeViewSymbol FromReader(PdbReaderContext context, ref BinaryStre CodeViewSymbolType.Pub32 => new SerializedPublicSymbol(dataReader), CodeViewSymbolType.Udt => new SerializedUserDefinedTypeSymbol(context, dataReader), CodeViewSymbolType.Constant => new SerializedConstantSymbol(context, dataReader), + CodeViewSymbolType.ProcRef => new SerializedProcedureReferenceSymbol(dataReader, false), + CodeViewSymbolType.LProcRef => new SerializedProcedureReferenceSymbol(dataReader, true), _ => new UnknownSymbol(type, dataReader.ReadToEnd()) }; } diff --git a/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs new file mode 100644 index 000000000..6697275aa --- /dev/null +++ b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs @@ -0,0 +1,96 @@ +namespace AsmResolver.Symbols.Pdb.Records; + +/// +/// Represents a procedure reference symbol stored in a PDB symbol stream. +/// +public class ProcedureReferenceSymbol : CodeViewSymbol +{ + private readonly LazyVariable _name; + private readonly bool _local; + + /// + /// Initializes a new empty symbol. + /// + /// If true, this represents a local procedure reference. + protected ProcedureReferenceSymbol(bool local) + { + _name = new LazyVariable(GetName); + _local = local; + } + + /// + /// Creates a new symbol. + /// + /// The checksum of the referenced symbol name. + /// The offset within the segment the symbol starts at. + /// Index of the module that contains this procedure record. + /// The name of the symbol. + /// If true, this represents a local procedure reference. + public ProcedureReferenceSymbol(uint checksum, uint offset, ushort module, Utf8String name, bool local) + { + Checksum = checksum; + Offset = offset; + Module = module; + _name = new LazyVariable(name); + _local = local; + } + + /// + public override CodeViewSymbolType CodeViewSymbolType + { + get + { + return _local ? CodeViewSymbolType.LProcRef : CodeViewSymbolType.ProcRef; + } + } + + /// + /// Gets the checksum of the referenced symbol name. The checksum used is the + /// one specified in the header of the global symbols stream or static symbols stream. + /// + public uint Checksum + { + get; + set; + } + + /// + /// Gets the offset of the procedure symbol record from the beginning of the + /// $$SYMBOL table for the module. + /// + public uint Offset + { + get; + set; + } + + /// + /// Index of the module that contains this procedure record. + /// + public ushort Module + { + get; + set; + } + + /// + /// Gets or sets the name of the symbol. + /// + public Utf8String Name + { + get => _name.Value; + set => _name.Value = value; + } + + /// + /// Obtains the name of the symbol. + /// + /// The name. + /// + /// This method is called upon initialization of the property. + /// + protected virtual Utf8String GetName() => Utf8String.Empty; + + /// + public override string ToString() => $"{CodeViewSymbolType}: [{Module:X4}:{Offset:X8}] {Name}"; +} diff --git a/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs new file mode 100644 index 000000000..e165013c0 --- /dev/null +++ b/src/AsmResolver.Symbols.Pdb/Records/Serialized/SerializedProcedureReferenceSymbol.cs @@ -0,0 +1,27 @@ +using AsmResolver.IO; + +namespace AsmResolver.Symbols.Pdb.Records.Serialized; + +/// +/// Represents a lazily initialized implementation of that is read from a PDB image. +/// +public class SerializedProcedureReferenceSymbol : ProcedureReferenceSymbol +{ + private readonly BinaryStreamReader _nameReader; + + /// + /// Reads a public symbol from the provided input stream. + /// + /// The input stream to read from. + /// If true, this represents a local procedure reference. + public SerializedProcedureReferenceSymbol(BinaryStreamReader reader, bool local) : base(local) + { + Checksum = reader.ReadUInt32(); + Offset = reader.ReadUInt32(); + Module = reader.ReadUInt16(); + _nameReader = reader; + } + + /// + protected override Utf8String GetName() => _nameReader.Fork().ReadUtf8String(); +} From 6d88d4849d3c69f112b2d713eea5b08d72584ee1 Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Fri, 4 Nov 2022 16:45:12 -0400 Subject: [PATCH 2/3] Add ProcedureReferenceSymbolTest --- .../Records/ProcedureReferenceSymbolTest.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs diff --git a/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs new file mode 100644 index 000000000..3ea9e1dbd --- /dev/null +++ b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs @@ -0,0 +1,21 @@ +using System.Linq; +using AsmResolver.Symbols.Pdb.Records; +using Xunit; + +namespace AsmResolver.Symbols.Pdb.Tests.Records; + +public class ProcedureReferenceSymbolTest : IClassFixture +{ + private readonly MockPdbFixture _fixture; + + public ProcedureReferenceSymbolTest(MockPdbFixture fixture) + { + _fixture = fixture; + } + + [Fact] + public void Name() + { + Assert.Equal("DllMain", _fixture.SimplePdb.Symbols.OfType().First().Name); + } +} From 7b8bf60fc4281cec3cea22d8f724f40d6c1333af Mon Sep 17 00:00:00 2001 From: Jeremy Pritts Date: Fri, 4 Nov 2022 16:59:36 -0400 Subject: [PATCH 3/3] Local Procedure Reference test --- .../Records/ProcedureReferenceSymbol.cs | 5 +++++ .../Records/ProcedureReferenceSymbolTest.cs | 8 +++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs index 6697275aa..0ee3f5782 100644 --- a/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs +++ b/src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs @@ -44,6 +44,11 @@ public override CodeViewSymbolType CodeViewSymbolType } } + /// + /// Is the symbol a Local Procedure Reference? + /// + public bool IsLocal => _local; + /// /// Gets the checksum of the referenced symbol name. The checksum used is the /// one specified in the header of the global symbols stream or static symbols stream. diff --git a/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs index 3ea9e1dbd..ae534649b 100644 --- a/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs +++ b/test/AsmResolver.Symbols.Pdb.Tests/Records/ProcedureReferenceSymbolTest.cs @@ -16,6 +16,12 @@ public ProcedureReferenceSymbolTest(MockPdbFixture fixture) [Fact] public void Name() { - Assert.Equal("DllMain", _fixture.SimplePdb.Symbols.OfType().First().Name); + Assert.Equal("DllMain", _fixture.SimplePdb.Symbols.OfType().First(s => !s.IsLocal).Name); + } + + [Fact] + public void LocalName() + { + Assert.Equal("__get_entropy", _fixture.SimplePdb.Symbols.OfType().First(s => s.IsLocal).Name); } }