-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Proposal: Embed sources in PDBs #12625
Comments
I'm super stoked. Skimming through it most things look good. One comment is that while the proposal of additional files and embedding existing files is separate in implementation ... accepting it partially would be a pretty awkward situation. So I would recommend we review those pieces together. |
Is this intended to support both csc and vbc? |
Yes. Also F# at some point. |
@gafter Yes. Also, I am rewriting this now to reflect the decisions made in our meeting today. |
I'd love to see this, but it would be even better if the |
@gafter @tmat @jaredpar @agocke I've updated the proposal text to match the outcome of our design review. Please review. @erik-kallen Thanks for the feedback. The revised proposal addresses it. :) |
LGTM. A couple of things:
|
Yes, re deflate. Focusing on the rest first. It appears to me that SourceText.Encoding captures BOM. Moreover, the checksum computation itself is re-encoding except for an optimization for small files AFAICT. |
It is not re-encoding when we read the files from command line - the command line compiler calls http://source.roslyn.io/#Microsoft.CodeAnalysis/EncodedStringText.cs,81 thru http://source.roslyn.io/#Microsoft.CodeAnalysis/CommandLine/CommonCompiler.cs,157, which ultimately ends up here: http://source.roslyn.io/#Microsoft.CodeAnalysis/Text/SourceText.cs,102. Not all encodings allow text to be round-tripped afaik. |
OK, my (incorrect) recollection was based on the < 80KB case taking another code path through which we read to a byte[] and there the comment that says it's easy to get checksum up front for this case so I was thinking we didn't do it up front for larger stream, but we do. I actually checked for exactly this reason a little while ago, but I read wrong. :( I don't believe the BOM is an issue because the Encoding captures that in its "preamble". Another source of non-roundtripability would be invalid input for the given encoding. I wish that were just an error, but it looks like it isn't. :( Just so I understand the full exposure, is there another case where round-tripping would fail? (Not saying one case isn't enough, I just want to make sure I understand all the cases before proposing a fix and that I add all the right test cases.) |
If an encoding maps two different byte sequences to a single char then we have a problem. |
OK. I'm going to try the following approach as discussed offline:
|
Overall LGTM. One small question:
Is this feature limited to portable PDB or does it apply to all PDBs? |
All PDBs. |
Update:
|
Update: above is done and #12353 is ready for review. |
Closing as the only missing piece (Windows PDB support) which does not impact the command-line or API spec is now tracked by #13707. The rest is in. |
This looks really really nice, but... I can't see a way to pass the |
So there's an answer to the /embed question over on Stack Overflow and as far as I can tell that seems to be working. DotPeek would find at least some of the source files and looks to me like it's identifying them as embedded. I can also see the embedded metadata. When debugging in VS2017 it doesn't find the source files though. (I checked Code very quickly also.) Is there some other step we need to take to make this work in a debugger? Does anyone know if VS2017 or Code supports this for debugging or has anyone gotten it to work? Also, I do have SourceLink enabled (if that's even needed), and tried turning just my code off, and turned off source files must match exactly, but it made no difference. |
The answer on StackOverflow is correct as to how to pass /embed:X via csproj using @(EmbeddedFiles) items. However, the VS debugger does not yet support embedded source. cc @gregg-miskelly. |
Correct, the debugger doesn't yet support extracting sources from the PDB. At one point there was talk of some team creating a stand-alone tool to extract them out so you could point the debugger at them, not sure if anyone made this. The VS Debugger does support SourceLink if that works for your scenario. cc @caslan |
@gregg-miskelly The source extraction tool might be something that could be added to http://github.com/dotnet/symreader-converter. |
For this scenario I'm part of team using Stash so I think we may be out of luck -ctaggart/SourceLink#39. Regardless, the idea of embedding the source and keeping it independent of how we host our repo was very appealing. I was wondering, though, if it would be practical (as a workaround - direct debugger support would obviously be so much better) to use sourcelink with a URL to indicate the symbol file and path and then read and serve them up from an asp.net core project. |
@jdasilva I am not certain if this is what you are suggesting, but you could certainly build yourself a tiny HTTP server that would take URLs like:
And run:
And then stream back the results. |
@gregg-miskelly Are the get commands part of http://github.com/dotnet/symreader-converter? That's basically what I had in mind. If that library (or some other one) would read the source files out of the pdb, you could just read and deliver them as part of the little server. I was thinking an asp.net core project. |
I've logged a new issue to expose the /embed option through MSBuild: #19127 |
Fixes xamarin#18968 We provide a mapping to the checked in source files via SourceLink.json and the rest of the generated/untracked sources are embedded into the PDB to provide a more comprehensive debugging experience. Since we invoke CSC directly, there were a few workarounds that had to be implemented (ex: implementing a helper script to account for untracked sources instead of simply using the EmbedUntrackedSources MSBuild property). As for testing, the newly added support was validated via the sourcelink dotnet tool which confirmed all the sources in the PDB either had valid urls or were embedded. sourcelink test Microsoft.MacCatalyst.pdb —> sourcelink test passed: Microsoft.MacCatalyst.pdb The PDB size does increase in size after embedding; for example, Microsoft.MacCatalyst.pdb went from 5 MB to 15.7 MB. But considering it would significantly help improve the debugging experience, be consistent with Android’s offerings, and it’s a highlighted attribute on the NuGet package explorer I think it’s a worthy size increase. Refs: dotnet/android#7298 dotnet/roslyn#12625 https://github.com/dotnet/sourcelink/tree/main/docs
Fixes #18968 We provide a mapping to the checked in source files via SourceLink.json and the rest of the generated/untracked sources are embedded into the PDB to provide a more comprehensive debugging experience. Since we invoke CSC directly, there were a few workarounds that had to be implemented (ex: implementing a helper script to account for untracked sources instead of simply using the EmbedUntrackedSources MSBuild property). As for testing, the newly added support was validated via the dotnet sourcelink tool which confirmed all the sources in the PDB either had valid urls or were embedded. `sourcelink test Microsoft.MacCatalyst.pdb` —> `sourcelink test passed: Microsoft.MacCatalyst.pdb` The PDB size does increase in size after embedding; Microsoft.MacCatalyst.pdb went from 5 MB to 15.7 MB. But considering it would significantly help improve the debugging experience, be consistent with Android’s offerings, and it’s a highlighted attribute on the NuGet package explorer I think it’s a worthy size increase. Refs: dotnet/android#7298 dotnet/roslyn#12625 https://github.com/dotnet/sourcelink/tree/main/docs --------- Co-authored-by: Rolf Bjarne Kvinge <[email protected]> Co-authored-by: Alex Soto <[email protected]> Co-authored-by: Michael Cummings (MSFT) <[email protected]> Co-authored-by: GitHub Actions Autoformatter <[email protected]>
Implementation progress
Windows PDB support is tracked by #13707.
This proposal addresses #5397, which requests a feature for embedding source code inside of a PDB.
Scenarios
Recap from #5397
Also
Command Line Usage
Since common usage will already leverage a source server and only require generated code to be embedded, we need to be able to specify the files to embed individually.
Proposal: Add a new
/embed
switch for vbc.exe and csc.exe:/embed
: embeds all source files in the PDB./embed:<file list>
: embeds specific files in the PDB.<file list>
shall be parsed exactly as/additionalfile
with semicolon separation and wildcard expansion./embed
./embed
without /debug: we can't embed text in the PDB if we're not emitting a PDB./embed
shall be included in the PDB regardless of whether or not there are sequence points targeting it.Examples
#line directives
There is also a scenario where debugging requires external files that are not part of the compilation and are lined up to the actual source code via #line directives.
Proposal: A file targeted by a #line directive shall be embedded in the PDB if either the target file or the referencing source file are embedded.
Example
source.cs
example.xyz
Source Generators
This feature would pair nicely with https://github.com/dotnet/roslyn/blob/features/source-generators/docs/features/generators.md if/when both land, allowing generator output to be debugged without any requirement to acquire (or regenerate) the output by some other means.
We might choose to handle embedding source generator output in one of 3 ways:
After much discussion about an earlier version of this proposal, there was a strong desire to keep the command-line interface minimal, so I think (1) or (2) should be preferred. I personally think always embedding generator output is the best option as it means that generators get good debuggability with no fuss. We could always add a command-line or generator API opt-out later if there was anyone pushing back on embedding the generator output.
I propose that we open a separate follow-up issue to track how to integrate these two features after both have arrived in a common branch and discuss 1-3 or other alternatives there.
Command Line API
Proposal: Add a property to
Microsoft.CodeAnalysis.CommandLineArguments
to indicate a list of files to be embedded in the PDB.Note that if /embed is specified without arguments it is surfaced here by appending the full set of source files to this list and not via a separate API.
Emit API
It should be possible to embed source and additional text via public API without routing through the command-line compiler interface.
Proposal:
NOTE: Additions of optional parameters below to be done in the usual binary-compat-preserving way.
Note that it is the caller's responsibility to the gather source and non-source text as appropriate. Text will line up with corresponding source/sequence points by the existing mechanism for de-duping debug documents generated by source trees,
#line
, and#pragma checksum
: i.e. paths will be normalized and then compared case-insensitively for VB and case-sensitively for C#.Compression
Files beyond a trivial size should be compressed in the PDB. Deflate format will be used. Tiny files do not benefit from compression and can even waste cycles making the file bigger so we should have a threshold at which we start to compress.
Encoding
Any source text created from raw bytes/stream shall be copied (or compressed and copied) to the PDB without decoding and re-encoding bytes -> chars -> bytes. This is required since encodings do not always round-trip and the checksum must match the original stream.
A source text created by other means (e.g. string + encoding) in which its checksum will be calculated by encoding to bytes via SoruceText.Encoding, will have its text encoded with SourceText.Encoding.
See also CanBeEmbedded requirements above,
Portable PDB Representation
In portable PDBs, we will put the embedded source as a custom debug info entry (with a new GUID allocated for it) parented by the document entry.
The blob will have a leading int32, which when zero indicate the remaining bytes are the raw, uncompressed text, and when positive indicates that the remaining bytes are comrpessed by deflate and the positive value is the byte size when decompressed.
Portable PDB spec is being updated accordingly: dotnet/corefx#10560
Windows PDB Representation
The traditional Windows PDB already had a provision for embedded source, which we will use via ISymUnmanagedDocumentWriter::SetSource.
The corresponding method for reading back the embedded source returned E_NOTIMPL until recently, but I have made the change to implement it and an update to the nuget package is pending.
The blob format will be identical to the portable PDB. This is already a diasymreader custom PDB "injected source" so we can define the source portion as we wish. Using the same blob for Windows and portable PDBs opens up optimizations in the implementation (less copying) and also simplifies it.
The text was updated successfully, but these errors were encountered: