Skip to content

Commit

Permalink
Merge pull request #368 from ds5678/procedure-reference-symbol
Browse files Browse the repository at this point in the history
Add support for reading LProcRef and ProcRef symbols
  • Loading branch information
Washi1337 authored Nov 5, 2022
2 parents 9c23525 + 7b8bf60 commit 87fd1ac
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
};
}
Expand Down
101 changes: 101 additions & 0 deletions src/AsmResolver.Symbols.Pdb/Records/ProcedureReferenceSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
namespace AsmResolver.Symbols.Pdb.Records;

/// <summary>
/// Represents a procedure reference symbol stored in a PDB symbol stream.
/// </summary>
public class ProcedureReferenceSymbol : CodeViewSymbol
{
private readonly LazyVariable<Utf8String> _name;
private readonly bool _local;

/// <summary>
/// Initializes a new empty symbol.
/// </summary>
/// <param name="local">If true, this represents a local procedure reference.</param>
protected ProcedureReferenceSymbol(bool local)
{
_name = new LazyVariable<Utf8String>(GetName);
_local = local;
}

/// <summary>
/// Creates a new symbol.
/// </summary>
/// <param name="checksum">The checksum of the referenced symbol name.</param>
/// <param name="offset">The offset within the segment the symbol starts at.</param>
/// <param name="module">Index of the module that contains this procedure record.</param>
/// <param name="name">The name of the symbol.</param>
/// <param name="local">If true, this represents a local procedure reference.</param>
public ProcedureReferenceSymbol(uint checksum, uint offset, ushort module, Utf8String name, bool local)
{
Checksum = checksum;
Offset = offset;
Module = module;
_name = new LazyVariable<Utf8String>(name);
_local = local;
}

/// <inheritdoc/>
public override CodeViewSymbolType CodeViewSymbolType
{
get
{
return _local ? CodeViewSymbolType.LProcRef : CodeViewSymbolType.ProcRef;
}
}

/// <summary>
/// Is the symbol a Local Procedure Reference?
/// </summary>
public bool IsLocal => _local;

/// <summary>
/// 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.
/// </summary>
public uint Checksum
{
get;
set;
}

/// <summary>
/// Gets the offset of the procedure symbol record from the beginning of the
/// $$SYMBOL table for the module.
/// </summary>
public uint Offset
{
get;
set;
}

/// <summary>
/// Index of the module that contains this procedure record.
/// </summary>
public ushort Module
{
get;
set;
}

/// <summary>
/// Gets or sets the name of the symbol.
/// </summary>
public Utf8String Name
{
get => _name.Value;
set => _name.Value = value;
}

/// <summary>
/// Obtains the name of the symbol.
/// </summary>
/// <returns>The name.</returns>
/// <remarks>
/// This method is called upon initialization of the <see cref="Name"/> property.
/// </remarks>
protected virtual Utf8String GetName() => Utf8String.Empty;

/// <inheritdoc />
public override string ToString() => $"{CodeViewSymbolType}: [{Module:X4}:{Offset:X8}] {Name}";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using AsmResolver.IO;

namespace AsmResolver.Symbols.Pdb.Records.Serialized;

/// <summary>
/// Represents a lazily initialized implementation of <see cref="ProcedureReferenceSymbol"/> that is read from a PDB image.
/// </summary>
public class SerializedProcedureReferenceSymbol : ProcedureReferenceSymbol
{
private readonly BinaryStreamReader _nameReader;

/// <summary>
/// Reads a public symbol from the provided input stream.
/// </summary>
/// <param name="reader">The input stream to read from.</param>
/// <param name="local">If true, this represents a local procedure reference.</param>
public SerializedProcedureReferenceSymbol(BinaryStreamReader reader, bool local) : base(local)
{
Checksum = reader.ReadUInt32();
Offset = reader.ReadUInt32();
Module = reader.ReadUInt16();
_nameReader = reader;
}

/// <inheritdoc />
protected override Utf8String GetName() => _nameReader.Fork().ReadUtf8String();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Linq;
using AsmResolver.Symbols.Pdb.Records;
using Xunit;

namespace AsmResolver.Symbols.Pdb.Tests.Records;

public class ProcedureReferenceSymbolTest : IClassFixture<MockPdbFixture>
{
private readonly MockPdbFixture _fixture;

public ProcedureReferenceSymbolTest(MockPdbFixture fixture)
{
_fixture = fixture;
}

[Fact]
public void Name()
{
Assert.Equal("DllMain", _fixture.SimplePdb.Symbols.OfType<ProcedureReferenceSymbol>().First(s => !s.IsLocal).Name);
}

[Fact]
public void LocalName()
{
Assert.Equal("__get_entropy", _fixture.SimplePdb.Symbols.OfType<ProcedureReferenceSymbol>().First(s => s.IsLocal).Name);
}
}

0 comments on commit 87fd1ac

Please sign in to comment.