-
-
Notifications
You must be signed in to change notification settings - Fork 213
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
Line number for .NET stack traces with server-side PDB support #1740
Comments
For this case specifically, there's a work around. @SimonCropp built a library that is able to fetch the PDBs from the symbol server at build time and include them in our published app. This will make the deployed app larger though, which is usually fine (maybe not on FaaS/serverless environments though). |
Support for this was added in sentry-cli for Portable PDB uploads, and symbolication support is already live. |
Problem statement:
.NET since its inception had the default Debug and Release configurations emit debug information that was used in production, so that at runtime, exceptions could include stack traces with function names, line numbers and file paths.
That requires apps to ship
pdb
s together with the executable, which is common on server apps, and most desktop apps. Particularly internal ones where the download size and reverse engineering are not big concerns.The only motivation for server-side
pdb
support in those days were from desktop apps (such as WinForms and WPF) that wanted to have a smaller installer, or were concerned with facilitating reverse engineering of their IP.In 2011 mobile support for .NET was introduced through Xamarin, in mobile app size is critical to stay as small as possible, so Xamarin didn't include debug information in the final app. And to this day, Xamarin users don't have line numbers on stack traces in Sentry, or any other competitor (to the best of my knowledge).
This feature was requested back in 2015 but the reason this became a bigger priority now is due to .NET MAUI. And also because ASP.NET Core since .NET 3.1 (or 5?) does not include PDBs anymore in the runtime installation. So 'system' frames no longer have line numbers on stack traces. Symbols (portable
pdb
s) are made available on the nuget.org's symbol server.Goals:
Support portable PDB (ppdb) with the focus of giving line numbers for InApp frames
sentry-cli
will need to understand and upload ppdb'ssentry-cli
Line number of other frames such as system frames.
This requires fetching symbols from nuget.org
Rely on source link to render a link to the right sha/file:line
Technical details
.NET tooling, by default, generates
exe
ordll
with an accompanyingpdb
.At runtime, when you use an API to retrieve a line number or a file path, the framework makes a lookup to the
pdb
on the local directory, and find the appropriate line number and path through the pdb.sentry-dotnet/src/Sentry/Internal/MonoSentryStackTraceFactory.cs
Lines 58 to 60 in 610dee8
sentry-dotnet/src/Sentry/Extensibility/SentryStackTraceFactory.cs
Lines 178 to 188 in 610dee8
Outside of this, there's no (to my knowledge) straightforward way to get from an
Exception
instance to an over-the-wire format that a standard system can be plugged in to give line numbers and paths. In other words,Exception.ToString()
will just result in the same stack trace, but without any line numbers.The way Mono solved this in the past was through
mono-symbolicate
.The runtime generates an exception in a different format than above. It encodes the
mvid
(module version id which is the id of the pdb) and theaotid
which was added when the code as AOT (ahead of time compiled, for example on Xamarin.iOS). Mono symbolicate on the 'server' needs to prepare code in a way that is sort of a symbol server lookup protocol, by moves the pdbs to folders named by theirmvid
.This PR added support to parse that in the Sentry SDK for .NET.
In order to get this done at Sentry, we'll need to change the Sentry SDK for .NET and add the data required by the backend to find the correct
pdb
, and lookup within it.The data that has to be read at runtime, to add to the payload can be found in this PoC: https://github.com/bruno-garcia/simbolo/blob/d7340e46c45c87e4598b76f350336cb695fa00f1/Simbolo/Client.cs#L19
And an example of the lookup done this way (with .NET library): https://github.com/bruno-garcia/simbolo/blob/d7340e46c45c87e4598b76f350336cb695fa00f1/Simbolo.Backend/Symbolicate.cs#L14
The PoC above does call from native code, since it was supposed to serve as an example where we use FFI from Rust into .NET on the backend: https://github.com/bruno-garcia/simbolo/blob/d7340e46c45c87e4598b76f350336cb695fa00f1/Simbolo.NativeLib/app.c
The PoC relied on
[Mono.Cecil](https://github.com/jbevain/cecil)
. This library is very popular, widely adopted and allows for modifying the IL. On the other hands it allocates memory when reading debug info. Alternatively,System.Reflection.Metadata
can only read things, but does so in a much more optimized way.Simbolo
has a branch usingSystem.Reflection.Metadata
.The symbol lookup straight to portable
pdb
will be a solution to customers that upload their . NETpdbs
to Sentry.But this won't solve the use case for libraries published to NuGet. There, we'll need to make a symbol server lookup to nuget.org to fetch the relevant debug symbols. All .NET libraries (installed with .NET) have source link information so we know the commit sha, git repo link so we can render a link to the exact line number.
Resources
Relates to:
PPDB
For Sentry employees: Internal video intro about this problem: https://drive.google.com/file/d/1nXOtB-ChTcuCj1fqgPrbHhx83A0bvLEw/view
The text was updated successfully, but these errors were encountered: