Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read support MODI Streams and typical associated Symbol Records #412

Merged
merged 42 commits into from
Feb 15, 2023
Merged
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
557d91e
Add modi stream models.
Washi1337 Feb 2, 2023
9165e2d
Add PdbModule.
Washi1337 Feb 2, 2023
a03c509
Add SerializedPdbModule.
Washi1337 Feb 2, 2023
957ed70
Add S_OBJNAME symbol read support.
Washi1337 Feb 2, 2023
7d0d26f
Add S_COMPILE2 and S_COMPILE3 read support.
Washi1337 Feb 2, 2023
4e1efa2
Add PdbModule tests.
Washi1337 Feb 3, 2023
5b4d554
BUGFIX: Off-by-one error in CompileAttributes enum.
Washi1337 Feb 3, 2023
3fbe7ce
Extract TpiStreamCache helper class.
Washi1337 Feb 3, 2023
2eaede0
Extract generic TryGetLeafRecord.
Washi1337 Feb 3, 2023
4f076ee
Add read support for LF_STRING_ID, LF_SUBSTR_LIST, LF_BUILDINFO, S_BU…
Washi1337 Feb 3, 2023
8ed4f00
Add read support for S_LOCAL.
Washi1337 Feb 4, 2023
39858dd
Add read support for S_DEFRANGE_REGISTER_REL.
Washi1337 Feb 4, 2023
3ec9eb6
Add read support for S_DEFRANGE_FRAMEPOINTER[_FULLSCOPE].
Washi1337 Feb 4, 2023
d80c675
Add read support for S_REGREL32.
Washi1337 Feb 4, 2023
c3ebbbe
Add read support for S_FRAMEPROC.
Washi1337 Feb 4, 2023
dc95b6f
Add read support for S_UNAMESPACE.
Washi1337 Feb 10, 2023
3d8994e
Add read support S_BPREL32. Rename RelativeRegister to RegisterRelative.
Washi1337 Feb 10, 2023
30b691c
Add read support for S_CALLSITEINFO.
Washi1337 Feb 10, 2023
6c7ec13
Add read support for LF_FUNC_ID, S_CALLERS and S_CALLEES.
Washi1337 Feb 10, 2023
7e97353
Add read support for S_ENVBLOCK.
Washi1337 Feb 10, 2023
15a77af
Extract ICodeViewSymbol, ICodeViewSymbolProvider, IScopeCodeViewSymbol.
Washi1337 Feb 11, 2023
7c26b11
Add read support for S_GPROC32, S_GPROC32_ID, S_LPROC32 and S_LPROC32…
Washi1337 Feb 11, 2023
2434937
Extract SymbolStreamReader class to remove code duplication.
Washi1337 Feb 11, 2023
99cb155
Nest symbols into procedure symbols when possible.
Washi1337 Feb 11, 2023
a3b907d
Add read support for S_THUNK32.
Washi1337 Feb 11, 2023
28c8bac
Add read support S_GDATA32, S_LDATA32. Add missing xmldocs.
Washi1337 Feb 11, 2023
daec1aa
Remove S_END entries from symbol lists.
Washi1337 Feb 11, 2023
1e64abb
Add read support S_COFFGROUP.
Washi1337 Feb 12, 2023
e938ba5
Add read support for S_DEFRANGE_REGISTER.
Washi1337 Feb 12, 2023
11fcc6f
Add read support for S_FILESTATIC.
Washi1337 Feb 12, 2023
a5ebe86
Add read support for S_FRAMECOOKIE.
Washi1337 Feb 12, 2023
d09c911
Add read support for S_INLINESITE.
Washi1337 Feb 12, 2023
f898516
Add read support for S_LABEL32.
Washi1337 Feb 12, 2023
da8973b
Add read support for S_REGISTER.
Washi1337 Feb 12, 2023
63f4fbe
Add read support S_SECTION.
Washi1337 Feb 12, 2023
9546e45
Add helper ToString methods.
Washi1337 Feb 12, 2023
2bab60b
Extract ICodeViewLeaf, ITpiLeaf, IIpiLeaf. Rename XXXIdLeaf to XXXIde…
Washi1337 Feb 15, 2023
2243883
Fix casing for some code view leaf kinds.
Washi1337 Feb 15, 2023
39025b9
Improve readability in lookahead of symbol stream reader.
Washi1337 Feb 15, 2023
8420b2b
Rename ID leaf tests to adhere to new naming scheme.
Washi1337 Feb 15, 2023
2e1aaed
Let DataSymbol implement IVariableSymbol. Replace redundant xmldoc wi…
Washi1337 Feb 15, 2023
8f49471
Fix nullability for DataSymbol.Name
Washi1337 Feb 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Extract TpiStreamCache helper class.
Washi1337 committed Feb 3, 2023
commit 3fbe7ce9ccf9e0c2b6b4fd1102f58f3f1593e56f
20 changes: 20 additions & 0 deletions src/AsmResolver.Symbols.Pdb/Leaves/BuildInfoLeaf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Collections.Generic;

namespace AsmResolver.Symbols.Pdb.Leaves;

public class BuildInfoLeaf : CodeViewLeaf
{
protected BuildInfoLeaf(uint typeIndex)
: base(typeIndex)
{
}

public override CodeViewLeafKind LeafKind => CodeViewLeafKind.BuildInfo;

public IList<string> Entries
{
get;
}

protected virtual IList<string> GetEntries() => new List<string>();
}
1 change: 1 addition & 0 deletions src/AsmResolver.Symbols.Pdb/Leaves/CodeViewLeaf.cs
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ internal static CodeViewLeaf FromReaderNoHeader(
Array => new SerializedArrayTypeRecord(context, typeIndex, dataReader),
ArgList => new SerializedArgumentListLeaf(context, typeIndex, dataReader),
BClass => new SerializedBaseClassField(context, typeIndex, ref dataReader),
BuildInfo => new SerializedBuildInfoLeaf(context, typeIndex, dataReader),
Class or Interface or Structure => new SerializedClassTypeRecord(kind, context, typeIndex, dataReader),
BitField => new SerializedBitFieldTypeRecord(context, typeIndex, dataReader),
Enum => new SerializedEnumTypeRecord(context, typeIndex, dataReader),
2 changes: 1 addition & 1 deletion src/AsmResolver.Symbols.Pdb/Leaves/CodeViewLeafKind.cs
Original file line number Diff line number Diff line change
@@ -152,7 +152,7 @@ public enum CodeViewLeafKind : ushort

FuncId = 0x1601,
MFuncId = 0x1602,
Buildinfo = 0x1603,
BuildInfo = 0x1603,
SubstrList = 0x1604,
StringId = 0x1605,

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using AsmResolver.IO;

namespace AsmResolver.Symbols.Pdb.Leaves.Serialized;

public class SerializedBuildInfoLeaf : BuildInfoLeaf
{
private readonly PdbReaderContext _context;
private readonly BinaryStreamReader _reader;

public SerializedBuildInfoLeaf(PdbReaderContext context, uint typeIndex, BinaryStreamReader reader)
: base(typeIndex)
{
_context = context;
_reader = reader;


}

protected override IList<string> GetEntries()
{
var result = new List<string>();

var reader = _reader.Fork();
uint count = reader.ReadUInt32();

for (int i = 0; i < count; i++)
{
uint index = reader.ReadUInt32();
if (!_context.ParentImage.TryGetLeafRecord(index, out var leaf))
{

}
}

return result;
}
}
7 changes: 6 additions & 1 deletion src/AsmResolver.Symbols.Pdb/Metadata/Tpi/TpiStream.cs
Original file line number Diff line number Diff line change
@@ -11,7 +11,12 @@ public abstract class TpiStream : SegmentBase
/// <summary>
/// Gets the default fixed MSF stream index for the TPI stream.
/// </summary>
public const int StreamIndex = 2;
public const int TpiStreamIndex = 2;

/// <summary>
/// Gets the default fixed MSF stream index for the IPI stream.
/// </summary>
public const int IpiStreamIndex = 4;

internal const uint TpiStreamHeaderSize =
sizeof(TpiStreamVersion) // Version
29 changes: 27 additions & 2 deletions src/AsmResolver.Symbols.Pdb/PdbImage.cs
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ public static PdbImage FromFile(MsfFile file, PdbReaderParameters readerParamete
}

/// <summary>
/// Attempts to obtain a type record from the TPI or IPI stream based on its type index.
/// Attempts to obtain a type record from the TPI stream based on its type index.
/// </summary>
/// <param name="typeIndex">The type index.</param>
/// <param name="leaf">The resolved type.</param>
@@ -115,7 +115,7 @@ public virtual bool TryGetLeafRecord(uint typeIndex, [NotNullWhen(true)] out Cod
}

/// <summary>
/// Obtains a type record from the TPI or IPI stream based on its type index.
/// Obtains a type record from the TPI stream based on its type index.
/// </summary>
/// <param name="typeIndex">The type index.</param>
/// <returns>The resolved type.</returns>
@@ -127,6 +127,31 @@ public CodeViewLeaf GetLeafRecord(uint typeIndex)
return type;
}

/// <summary>
/// Attempts to obtain an ID record from the IPI stream based on its ID index.
/// </summary>
/// <param name="idIndex">The ID index.</param>
/// <param name="leaf">The resolved leaf.</param>
/// <returns><c>true</c> if the leaf was found, <c>false</c> otherwise.</returns>
public virtual bool TryGetIdLeafRecord(uint idIndex, [NotNullWhen(true)] out CodeViewLeaf? leaf)
{
leaf = null;
return false;
}

/// <summary>
/// Obtains an ID record from the IPI stream based on its ID index.
/// </summary>
/// <param name="idIndex">The ID index.</param>
/// <returns>The resolved leaf</returns>
/// <exception cref="ArgumentException">Occurs when the ID index is invalid.</exception>
public CodeViewLeaf GetIdLeafRecord(uint idIndex)
{
if (!TryGetIdLeafRecord(idIndex, out var leaf))
throw new ArgumentException("Invalid ID index.");
return leaf;
}

/// <summary>
/// Obtains a collection of symbols stored in the symbol record stream of the PDB image.
/// </summary>
28 changes: 28 additions & 0 deletions src/AsmResolver.Symbols.Pdb/Records/BuildInfoSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using AsmResolver.Symbols.Pdb.Leaves;

namespace AsmResolver.Symbols.Pdb.Records;

public class BuildInfoSymbol : CodeViewSymbol
{
private readonly LazyVariable<BuildInfoLeaf?> _info;

protected BuildInfoSymbol()
{
_info = new LazyVariable<BuildInfoLeaf?>(GetInfo);
}

public BuildInfoSymbol(BuildInfoLeaf info)
{
_info = new LazyVariable<BuildInfoLeaf?>(info);
}

public override CodeViewSymbolType CodeViewSymbolType => CodeViewSymbolType.BuildInfo;

public BuildInfoLeaf? Info
{
get => _info.Value;
set => _info.Value = value;
}

protected virtual BuildInfoLeaf? GetInfo() => null;
}
18 changes: 10 additions & 8 deletions src/AsmResolver.Symbols.Pdb/Records/CodeViewSymbol.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using AsmResolver.IO;
using AsmResolver.Symbols.Pdb.Records.Serialized;
using static AsmResolver.Symbols.Pdb.Records.CodeViewSymbolType;

namespace AsmResolver.Symbols.Pdb.Records;

@@ -31,14 +32,15 @@ public static CodeViewSymbol FromReader(PdbReaderContext context, ref BinaryStre

return type switch
{
CodeViewSymbolType.Compile2 => new SerializedCompile2Symbol(dataReader),
CodeViewSymbolType.Compile3 => new SerializedCompile3Symbol(dataReader),
CodeViewSymbolType.Constant => new SerializedConstantSymbol(context, dataReader),
CodeViewSymbolType.LProcRef => new SerializedProcedureReferenceSymbol(dataReader, true),
CodeViewSymbolType.ObjName => new SerializedObjectNameSymbol(dataReader),
CodeViewSymbolType.ProcRef => new SerializedProcedureReferenceSymbol(dataReader, false),
CodeViewSymbolType.Pub32 => new SerializedPublicSymbol(dataReader),
CodeViewSymbolType.Udt => new SerializedUserDefinedTypeSymbol(context, dataReader),
BuildInfo => new SerializedBuildInfoSymbol(context, dataReader),
Compile2 => new SerializedCompile2Symbol(dataReader),
Compile3 => new SerializedCompile3Symbol(dataReader),
Constant => new SerializedConstantSymbol(context, dataReader),
LProcRef => new SerializedProcedureReferenceSymbol(dataReader, true),
ObjName => new SerializedObjectNameSymbol(dataReader),
ProcRef => new SerializedProcedureReferenceSymbol(dataReader, false),
Pub32 => new SerializedPublicSymbol(dataReader),
Udt => new SerializedUserDefinedTypeSymbol(context, dataReader),
_ => new UnknownSymbol(type, dataReader.ReadToEnd())
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using AsmResolver.IO;

namespace AsmResolver.Symbols.Pdb.Records.Serialized;

public class SerializedBuildInfoSymbol : BuildInfoSymbol
{
private readonly PdbReaderContext _context;
private readonly uint _typeIndex;

public SerializedBuildInfoSymbol(PdbReaderContext context, BinaryStreamReader reader)
{
_context = context;
_typeIndex = reader.ReadUInt32();
}
}
94 changes: 66 additions & 28 deletions src/AsmResolver.Symbols.Pdb/SerializedPdbImage.cs
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ public class SerializedPdbImage : PdbImage
{
private const int MinimalRequiredStreamCount = 5;
private readonly MsfFile _file;
private CodeViewLeaf?[]? _leaves;
private readonly TpiStreamCache _tpi;
private readonly TpiStreamCache _ipi;

/// <summary>
/// Interprets a PDB image from the provided MSF file.
@@ -35,9 +36,13 @@ public SerializedPdbImage(MsfFile file, PdbReaderParameters readerParameters)

InfoStream = InfoStream.FromReader(file.Streams[InfoStream.StreamIndex].CreateReader());
DbiStream = DbiStream.FromReader(file.Streams[DbiStream.StreamIndex].CreateReader());
TpiStream = TpiStream.FromReader(file.Streams[TpiStream.StreamIndex].CreateReader());
TpiStream = TpiStream.FromReader(file.Streams[TpiStream.TpiStreamIndex].CreateReader());
IpiStream = TpiStream.FromReader(file.Streams[TpiStream.IpiStreamIndex].CreateReader());

ReaderContext = new PdbReaderContext(this, readerParameters);

_tpi = new TpiStreamCache(ReaderContext, TpiStream);
_ipi = new TpiStreamCache(ReaderContext, IpiStream);
}

internal PdbReaderContext ReaderContext
@@ -60,39 +65,21 @@ internal TpiStream TpiStream
get;
}

[MemberNotNull(nameof(_leaves))]
private void EnsureLeavesInitialized()
internal TpiStream IpiStream
{
if (_leaves is null)
{
Interlocked.CompareExchange(ref _leaves,
new CodeViewLeaf?[TpiStream.TypeIndexEnd - TpiStream.TypeIndexBegin], null);
}
get;
}

/// <inheritdoc />
public override bool TryGetLeafRecord(uint typeIndex, [NotNullWhen(true)] out CodeViewLeaf? leaf)
{
if (typeIndex < TpiStream.TypeIndexBegin)
return base.TryGetLeafRecord(typeIndex, out leaf);

EnsureLeavesInitialized();

if (typeIndex >= TpiStream.TypeIndexBegin && typeIndex < TpiStream.TypeIndexEnd)
{
leaf = _leaves[typeIndex - TpiStream.TypeIndexBegin];
if (leaf is null && TpiStream.TryGetLeafRecordReader(typeIndex, out var reader))
{
leaf = CodeViewLeaf.FromReader(ReaderContext, typeIndex, ref reader);
Interlocked.CompareExchange(ref _leaves[typeIndex - TpiStream.TypeIndexBegin], leaf, null);
}

leaf = _leaves[typeIndex - TpiStream.TypeIndexBegin];
return leaf is not null;
}
return _tpi.TryGetRecord(typeIndex, out leaf) || base.TryGetLeafRecord(typeIndex, out leaf);
}

leaf = null;
return false;
/// <inheritdoc />
public override bool TryGetIdLeafRecord(uint idIndex, [NotNullWhen(true)] out CodeViewLeaf? leaf)
{
return _ipi.TryGetRecord(idIndex, out leaf) || base.TryGetLeafRecord(idIndex, out leaf);
}

/// <inheritdoc />
@@ -129,4 +116,55 @@ protected override IList<PdbModule> GetModules()

return result;
}

private class TpiStreamCache
{
private readonly PdbReaderContext _context;
private readonly TpiStream _stream;
private CodeViewLeaf?[]? _leaves;

public TpiStreamCache(PdbReaderContext context, TpiStream stream)
{
_context = context;
_stream = stream;
}

[MemberNotNull(nameof(_leaves))]
private void EnsureLeavesInitialized()
{
if (_leaves is null)
{
Interlocked.CompareExchange(ref _leaves,
new CodeViewLeaf?[_stream.TypeIndexEnd - _stream.TypeIndexBegin], null);
}
}

public bool TryGetRecord(uint typeIndex, out CodeViewLeaf? leaf)
{
if (typeIndex < _stream.TypeIndexBegin)
{
leaf = null;
return false;
}

EnsureLeavesInitialized();

if (typeIndex >= _stream.TypeIndexBegin && typeIndex < _stream.TypeIndexEnd)
{
leaf = _leaves[typeIndex - _stream.TypeIndexBegin];
if (leaf is null && _stream.TryGetLeafRecordReader(typeIndex, out var reader))
{
leaf = CodeViewLeaf.FromReader(_context, typeIndex, ref reader);
Interlocked.CompareExchange(ref _leaves[typeIndex - _stream.TypeIndexBegin], leaf, null);
}

leaf = _leaves[typeIndex - _stream.TypeIndexBegin];
return leaf is not null;
}

leaf = null;
return false;
}

}
}