llvm / llvm/llvm-project

pdb issues after reading the microsoft/pdb-rs/ docs

Open
#206,120 6 comments 0 reactions 0 assignees View on GitHub
debuginfo
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

Filing this as a meta-bug to track issues/questions after reading through https://github.com/microsoft/pdb-rs/blob/main/docs/index.md

1) Multi-page Stream Directory Page Map

LLVM's https://llvm.org/docs/PDB/MsfFile.html specifies that `SuperBlock::BlockMapAddr` is a *single* page, and the LLVM implementation matches. https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/msf.md#stream-directory-location-on-disk says it's a list of page numbers, and looking the microsoft-pdb source, it seems LLVM is wrong here.

This puts an unnecessary limit on the size of the stream directory (Chromium has hit this before increasing the page size), and what's worse it means LLVM wouldn't be able to *read* PDBs with such large stream directories.

This is probably the most important thing to fix.

2) https://github.com/microsoft/pdb-rs/blob/main/docs/codeview/symbols/symbols.md#symbol-record-framing says padding for CodeView symbols should be 0xf1, 0xf2, 0xf3 (for the first, second, and third padding byte as needed). I don't think LLVM does this, but I'm not sure it's that important.

3) For the Named Stream Map (https://llvm.org/docs/PDB/PdbStream.html#named-stream-map) in the PDB Stream, there's a hash table which uses "present" and "deleted" bit vectors (https://llvm.org/docs/PDB/HashTable.html#present-and-deleted-bit-vectors). The pdb-rs docs say (https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/pdbi_stream.md#named-streams) that "Invariant: present_mask_size == deleted_mask_size". The LLVM docs don't mention that, so the reader may be tempted to use a zero-sized deleted bitvector if it's empty. Not sure what LLVM does; maybe the docs just need updating (assuming pdb-rs is correct, we should double check).

4) In the PDB stream, LLVM emits a mysterious 0 after the named stream map: https://github.com/llvm/llvm-project/blob/60908dc9955337898ce3e2c21a3425cf073abe43/llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp#L73. It was added in 05d5e6136f5a3f5de28ae64077200bbdc2cacfb4, but there's no explanation in the commit message and it's not mentioned in the docs. In the reader, LLVM ignores it as an unknown feature code.

The pdb-rs docs calls this the name index table: https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/pdbi_stream.md#name-index-table-obsolete We should understand and document this better.

5) In the TPI/IPI hash streams, there is a subtream that contains the hash values of the TPI/IPI records. LLVM carefully writes the same hash values as the microsoft-pdb code. The pdb-rs docs says the purpose of these substreams is not clear (https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/tpi_stream.md#hash-value-substream) "It is not clear what the purpose of the Hash Value Substream is."

It does seem like this gets used, and that the modulus used for the hashes matters. In 8371da385a5dd08e0161368bb87b6b8cb3001d6a LLVM increased the modulus, as it sped up symbol lookup in PDBs with large TPI/IPI streams, see discussion on https://reviews.llvm.org/D56942 It would be interesting to understand this better.

6) https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/dbi_sections.md#dbi-section-contributions-substream points out that "[the Section Contributions Substream] is one of the largest substreams of the DBI Stream. Its size typically accounts for 50% to 70% of the size of the DBI Stream." I wonder if, when compiling with `/Gy`, we end up with one section contribution *per function*, and if it would be possible to merge adjacent contributions here.

7) https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/dbi_stream.md#dbi-edit-and-continue-substream says encoders should emit an empty EC DBI substream. The LLVM docs don't really describe it: https://llvm.org/docs/PDB/DbiStream.html#ec-substream However, LLVM does emit a name map here: https://github.com/llvm/llvm-project/blob/fdf30ae699ac10d0568e2d4a83da1327dd74255f/llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp#L427

and IIRC (I could be wrong though) LLVM's PDB reader gets upset if the substream is empty. It would be good to understand this better.

8) In the hash tables for publics/globals, LLVM sorts the entries within each bucket first by symbol name, and then by symbol offset: https://github.com/llvm/llvm-project/blob/7f8faef330ec0f02eafe65c33d1796491c3e3aee/llvm/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp#L222-L227

However, the pdb-rs docs say (https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/globals.md#building-the-name-table point 4) to sort only by symbol offset. That seems potentially cheaper :) Who's right though? What does the microsoft-pdb code do?

9) https://github.com/microsoft/pdb-rs/blob/main/docs/pdb/names_stream.md says "Because the size of string_data must be a multiple of 4, there may be padding bytes at the end of string_data." I don't see LLVM padding this string table in https://github.com/llvm/llvm-project/blob/7f8faef330ec0f02eafe65c33d1796491c3e3aee/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp#L218

What does microsoft-pdb do?

Contributor guide

Open the contributing guide

Research direction

Start with the linked microsoft/pdb-rs documentation and the cited LLVM PDB source files, including InfoStreamBuilder.cpp, DbiStreamBuilder.cpp, GSIStreamBuilder.cpp, and PDBStringTableBuilder.cpp. Check each of the nine discrepancies against the referenced LLVM and microsoft-pdb behavior; done means the behavior is verified and the affected documentation or implementation work is clearly identified.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers, documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.