xref: /llvm-project/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp (revision 2fe8327406050d2585d2ced910a678e28caefcf5)
180814287SRaphael Isemann //===-- PdbIndex.cpp ------------------------------------------------------===//
2307f5ae8SZachary Turner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6307f5ae8SZachary Turner //
7307f5ae8SZachary Turner //===----------------------------------------------------------------------===//
8307f5ae8SZachary Turner 
9307f5ae8SZachary Turner #include "PdbIndex.h"
10307f5ae8SZachary Turner #include "PdbUtil.h"
11307f5ae8SZachary Turner 
12307f5ae8SZachary Turner #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
13307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
14307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
15307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
16307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
18307f5ae8SZachary Turner #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
192f7efbc9SZachary Turner #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20307f5ae8SZachary Turner #include "llvm/Object/COFF.h"
21307f5ae8SZachary Turner #include "llvm/Support/Error.h"
22307f5ae8SZachary Turner 
23307f5ae8SZachary Turner #include "lldb/Utility/LLDBAssert.h"
24307f5ae8SZachary Turner #include "lldb/lldb-defines.h"
25f190ce62SKazu Hirata #include <optional>
26307f5ae8SZachary Turner 
27307f5ae8SZachary Turner using namespace lldb_private;
28307f5ae8SZachary Turner using namespace lldb_private::npdb;
29307f5ae8SZachary Turner using namespace llvm::codeview;
30307f5ae8SZachary Turner using namespace llvm::pdb;
31307f5ae8SZachary Turner 
PdbIndex()32307f5ae8SZachary Turner PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
33307f5ae8SZachary Turner 
34307f5ae8SZachary Turner #define ASSIGN_PTR_OR_RETURN(result_ptr, expr)                                 \
35307f5ae8SZachary Turner   {                                                                            \
36307f5ae8SZachary Turner     auto expected_result = expr;                                               \
37307f5ae8SZachary Turner     if (!expected_result)                                                      \
38307f5ae8SZachary Turner       return expected_result.takeError();                                      \
39307f5ae8SZachary Turner     result_ptr = &expected_result.get();                                       \
40307f5ae8SZachary Turner   }
41307f5ae8SZachary Turner 
42307f5ae8SZachary Turner llvm::Expected<std::unique_ptr<PdbIndex>>
create(llvm::pdb::PDBFile * file)43242e1e99SZequan Wu PdbIndex::create(llvm::pdb::PDBFile *file) {
44307f5ae8SZachary Turner   lldbassert(file);
45307f5ae8SZachary Turner 
46307f5ae8SZachary Turner   std::unique_ptr<PdbIndex> result(new PdbIndex());
47307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
48307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
49307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
50307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
51307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
52307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
53307f5ae8SZachary Turner   ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
54307f5ae8SZachary Turner 
552f7efbc9SZachary Turner   result->m_tpi->buildHashMap();
562f7efbc9SZachary Turner 
57242e1e99SZequan Wu   result->m_file = file;
58307f5ae8SZachary Turner 
59307f5ae8SZachary Turner   return std::move(result);
60307f5ae8SZachary Turner }
61307f5ae8SZachary Turner 
MakeVirtualAddress(uint16_t segment,uint32_t offset) const62307f5ae8SZachary Turner lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
63307f5ae8SZachary Turner                                           uint32_t offset) const {
64307f5ae8SZachary Turner   uint32_t max_section = dbi().getSectionHeaders().size();
658a790e65SZequan Wu   // Segment indices are 1-based.
66307f5ae8SZachary Turner   // If this is an absolute symbol, it's indicated by the magic section index
67307f5ae8SZachary Turner   // |max_section+1|.  In this case, the offset is meaningless, so just return.
688a790e65SZequan Wu   if (segment == 0 || segment > max_section)
69307f5ae8SZachary Turner     return LLDB_INVALID_ADDRESS;
70307f5ae8SZachary Turner 
71307f5ae8SZachary Turner   const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
72307f5ae8SZachary Turner   return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
73307f5ae8SZachary Turner          static_cast<lldb::addr_t>(offset);
74307f5ae8SZachary Turner }
75307f5ae8SZachary Turner 
GetModuleIndexForAddr(uint16_t segment,uint32_t offset) const76*2fe83274SKazu Hirata std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,
77*2fe83274SKazu Hirata                                                         uint32_t offset) const {
78307f5ae8SZachary Turner   return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
79307f5ae8SZachary Turner }
80307f5ae8SZachary Turner 
GetModuleIndexForVa(lldb::addr_t va) const81*2fe83274SKazu Hirata std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
82307f5ae8SZachary Turner   auto iter = m_va_to_modi.find(va);
83307f5ae8SZachary Turner   if (iter == m_va_to_modi.end())
84343523d0SKazu Hirata     return std::nullopt;
85307f5ae8SZachary Turner 
86307f5ae8SZachary Turner   return iter.value();
87307f5ae8SZachary Turner }
88307f5ae8SZachary Turner 
ParseSectionContribs()89307f5ae8SZachary Turner void PdbIndex::ParseSectionContribs() {
90307f5ae8SZachary Turner   class Visitor : public ISectionContribVisitor {
91307f5ae8SZachary Turner     PdbIndex &m_ctx;
92307f5ae8SZachary Turner     llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
93307f5ae8SZachary Turner 
94307f5ae8SZachary Turner   public:
95307f5ae8SZachary Turner     Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
96307f5ae8SZachary Turner         : m_ctx(ctx), m_imap(imap) {}
97307f5ae8SZachary Turner 
98307f5ae8SZachary Turner     void visit(const SectionContrib &C) override {
992f7efbc9SZachary Turner       if (C.Size == 0)
1002f7efbc9SZachary Turner         return;
1012f7efbc9SZachary Turner 
102307f5ae8SZachary Turner       uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
1038a790e65SZequan Wu       if (va == LLDB_INVALID_ADDRESS)
1048a790e65SZequan Wu         return;
105307f5ae8SZachary Turner       uint64_t end = va + C.Size;
106307f5ae8SZachary Turner       // IntervalMap's start and end represent a closed range, not a half-open
107307f5ae8SZachary Turner       // range, so we have to subtract 1.
108307f5ae8SZachary Turner       m_imap.insert(va, end - 1, C.Imod);
109307f5ae8SZachary Turner     }
110307f5ae8SZachary Turner     void visit(const SectionContrib2 &C) override { visit(C.Base); }
111307f5ae8SZachary Turner   };
112307f5ae8SZachary Turner   Visitor v(*this, m_va_to_modi);
113307f5ae8SZachary Turner   dbi().visitSectionContributions(v);
114307f5ae8SZachary Turner }
115307f5ae8SZachary Turner 
BuildAddrToSymbolMap(CompilandIndexItem & cci)116307f5ae8SZachary Turner void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
117307f5ae8SZachary Turner   lldbassert(cci.m_symbols_by_va.empty() &&
118307f5ae8SZachary Turner              "Addr to symbol map is already built!");
1196284aee9SZachary Turner   uint16_t modi = cci.m_id.modi;
120307f5ae8SZachary Turner   const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
121307f5ae8SZachary Turner   for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
122307f5ae8SZachary Turner     if (!SymbolHasAddress(*iter))
123307f5ae8SZachary Turner       continue;
124307f5ae8SZachary Turner 
125307f5ae8SZachary Turner     SegmentOffset so = GetSegmentAndOffset(*iter);
1268a790e65SZequan Wu     lldb::addr_t va = MakeVirtualAddress(so.segment, so.offset);
1278a790e65SZequan Wu     if (va == LLDB_INVALID_ADDRESS)
1288a790e65SZequan Wu       continue;
129307f5ae8SZachary Turner 
130579264bdSZachary Turner     PdbCompilandSymId cu_sym_id(modi, iter.offset());
131307f5ae8SZachary Turner 
13238d4a6c4SAdrian McCarthy     // It's rare, but we could have multiple symbols with the same address
13338d4a6c4SAdrian McCarthy     // because of identical comdat folding.  Right now, the first one will win.
13410ac299aSZachary Turner     cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
135307f5ae8SZachary Turner   }
136307f5ae8SZachary Turner }
137307f5ae8SZachary Turner 
FindSymbolsByVa(lldb::addr_t va)138307f5ae8SZachary Turner std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
139307f5ae8SZachary Turner   std::vector<SymbolAndUid> result;
140307f5ae8SZachary Turner 
141*2fe83274SKazu Hirata   std::optional<uint16_t> modi = GetModuleIndexForVa(va);
142307f5ae8SZachary Turner   if (!modi)
143307f5ae8SZachary Turner     return result;
144307f5ae8SZachary Turner 
145307f5ae8SZachary Turner   CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
146307f5ae8SZachary Turner   if (cci.m_symbols_by_va.empty())
147307f5ae8SZachary Turner     BuildAddrToSymbolMap(cci);
148307f5ae8SZachary Turner 
149307f5ae8SZachary Turner   // The map is sorted by starting address of the symbol.  So for example
150307f5ae8SZachary Turner   // we could (in theory) have this situation
151307f5ae8SZachary Turner   //
152307f5ae8SZachary Turner   // [------------------]
153307f5ae8SZachary Turner   //    [----------]
154307f5ae8SZachary Turner   //      [-----------]
155307f5ae8SZachary Turner   //          [-------------]
156307f5ae8SZachary Turner   //            [----]
157307f5ae8SZachary Turner   //               [-----]
158307f5ae8SZachary Turner   //             ^ Address we're searching for
159307f5ae8SZachary Turner   // In order to find this, we use the upper_bound of the key value which would
160307f5ae8SZachary Turner   // be the first symbol whose starting address is higher than the element we're
161307f5ae8SZachary Turner   // searching for.
162307f5ae8SZachary Turner 
163307f5ae8SZachary Turner   auto ub = cci.m_symbols_by_va.upper_bound(va);
164307f5ae8SZachary Turner 
165307f5ae8SZachary Turner   for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
1666284aee9SZachary Turner     PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
167307f5ae8SZachary Turner     CVSymbol sym = ReadSymbolRecord(cu_sym_id);
168307f5ae8SZachary Turner 
169307f5ae8SZachary Turner     SegmentOffsetLength sol;
170307f5ae8SZachary Turner     if (SymbolIsCode(sym))
171307f5ae8SZachary Turner       sol = GetSegmentOffsetAndLength(sym);
172307f5ae8SZachary Turner     else
173307f5ae8SZachary Turner       sol.so = GetSegmentAndOffset(sym);
174307f5ae8SZachary Turner 
1758a790e65SZequan Wu     lldb::addr_t start = MakeVirtualAddress(sol.so.segment, sol.so.offset);
1768a790e65SZequan Wu     if (start == LLDB_INVALID_ADDRESS)
1778a790e65SZequan Wu       continue;
1788a790e65SZequan Wu 
179307f5ae8SZachary Turner     lldb::addr_t end = start + sol.length;
180307f5ae8SZachary Turner     if (va >= start && va < end)
181307f5ae8SZachary Turner       result.push_back({std::move(sym), iter->second});
182307f5ae8SZachary Turner   }
183307f5ae8SZachary Turner 
184307f5ae8SZachary Turner   return result;
185307f5ae8SZachary Turner }
186307f5ae8SZachary Turner 
ReadSymbolRecord(PdbCompilandSymId cu_sym) const1876284aee9SZachary Turner CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {
1886284aee9SZachary Turner   const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
189579264bdSZachary Turner   auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
190307f5ae8SZachary Turner   lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
191307f5ae8SZachary Turner   return *iter;
192307f5ae8SZachary Turner }
1933790029dSZachary Turner 
ReadSymbolRecord(PdbGlobalSymId global) const1943790029dSZachary Turner CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
1953790029dSZachary Turner   return symrecords().readRecord(global.offset);
1963790029dSZachary Turner }
197