Skip to content

Commit

Permalink
add a small test program to get il offset + metadata tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
Swatinem committed Jul 20, 2022
1 parent 61ecb41 commit d869c4f
Show file tree
Hide file tree
Showing 2 changed files with 181 additions and 0 deletions.
165 changes: 165 additions & 0 deletions samples/foo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
using System;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;

[assembly: DebuggableAttribute(true, false)]

class StackTraceSample
{
[STAThread]
static void Main(string[] args)
{
StackTraceSample sample = new StackTraceSample();
var module = sample.GetType().Module;
Console.WriteLine("Module: {0}", module);

Console.WriteLine("Offset Unknown: {0}", StackFrame.OFFSET_UNKNOWN);

sample.MyPublicMethod();

/*try
{
sample.MyPublicMethod();
}
catch (Exception)
{
using (SentrySdk.Init("https://eb18e953812b41c3aeb042e666fd3b5c@o447951.ingest.sentry.io/5428537"))
{
// The following exception is captured and sent to Sentry
throw null;
}
}*/
}

public void MyPublicMethod()
{
MyProtectedMethod();
}

protected void MyProtectedMethod()
{
MyInternalClass mic = new MyInternalClass();
}

class MyInternalClass
{
public MyInternalClass()
{
ThrowsException();
}

public string GetPdbId(Module module)
{
var name = module.FullyQualifiedName;
if (!File.Exists(name))
{
return null;
}
using var stream = File.OpenRead(name);
var peReader = new PEReader(stream);

var codeView = peReader.ReadDebugDirectory()
.FirstOrDefault(d => d.Type == DebugDirectoryEntryType.CodeView);
if (codeView.Type == DebugDirectoryEntryType.Unknown)
{
return null;
}

var data = peReader.ReadCodeViewDebugDirectoryData(codeView);

var signature = data.Guid;
var age = data.Age;
var file = data.Path;

// Version Major=any, Minor=0x504d of the data format has the same structure as above.
// The Age shall be 1. The format of the .pdb file that this PE/COFF file was built with is Portable PDB.
// The Major version specified in the entry indicates the version of the Portable PDB format.
// Together 16B of the Guid concatenated with 4B of the TimeDateStamp field of the entry form a PDB ID that
// should be used to match the PE/COFF image with the associated PDB (instead of Guid and Age).
// Matching PDB ID is stored in the #Pdb stream of the .pdb file.
// See https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2
if (codeView.MinorVersion == 0x504d)
{
return String.Format("{0}-{1:x}", signature, codeView.Stamp);
}
return String.Format("{0}-{1:x}", signature, age);
}

public void ThrowsException()
{
try
{
throw new Exception("A problem was encountered.");
}
catch (Exception)
{
// Create a StackTrace that captures filename,
// line number and column information.
StackTrace st = new StackTrace(true);
string stackIndent = "";
for (int i = 0; i < st.FrameCount; i++)
{
// Note that at this level, there are four
// stack frames, one for each method invocation.
StackFrame sf = st.GetFrame(i);
var method = sf.GetMethod();

Console.WriteLine();
Console.WriteLine(stackIndent + " Method: {0}",
method);
Console.WriteLine(stackIndent + " File: {0}",
sf.GetFileName());
Console.WriteLine(stackIndent + " Line Number: {0}",
sf.GetFileLineNumber());

var offset = sf.GetILOffset();
var token = method.MetadataToken;

Console.WriteLine();
Console.WriteLine(stackIndent + " IL Offset: {0}",
offset);
Console.WriteLine(stackIndent + " Metadata Token: 0x{0:X8}",
token);

// the top byte is the token type, the lower three bytes are the record id
// See: https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms404456(v=vs.100)#metadata-token-structure
var tokenType = token & 0xff000000;
// See https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/cortokentype-enumeration
if (tokenType == 0x06000000)
{
var recordId = token & 0x00ffffff;

Console.WriteLine(stackIndent + " MethodDef Record ID: {0}",
recordId);
}

var module = method.Module;

Console.WriteLine();
Console.WriteLine(stackIndent + " Module Name: {0}",
module.FullyQualifiedName);
Console.WriteLine(stackIndent + " Module Metadata Token: 0x{0:X8}",
module.MetadataToken);

// > In unmanaged metadata, the GUID returned by the ModuleVersionId property is referred to as the mvid, and is stored in the GUID heap.
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.module.moduleversionid?view=net-6.0#remarks
Console.WriteLine(stackIndent + " Module Version Id: {0}",
module.ModuleVersionId);

Console.WriteLine(stackIndent + " PdbId: {0}",
GetPdbId(module) ?? "<unknown>");

stackIndent += " ";
}

Console.WriteLine();

//throw e;
throw;
}
}
}

}
16 changes: 16 additions & 0 deletions samples/foo/foo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<!--<Nullable>enable</Nullable>-->
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="../../src/Sentry/Sentry.csproj" />
</ItemGroup>

</Project>

0 comments on commit d869c4f

Please sign in to comment.