xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- PdbIndex.cpp ------------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "PdbIndex.h"
10061da546Spatrick #include "PdbUtil.h"
11061da546Spatrick 
12061da546Spatrick #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
13061da546Spatrick #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
14061da546Spatrick #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
15061da546Spatrick #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
16061da546Spatrick #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17061da546Spatrick #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
18061da546Spatrick #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
19061da546Spatrick #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20061da546Spatrick #include "llvm/Object/COFF.h"
21061da546Spatrick #include "llvm/Support/Error.h"
22061da546Spatrick 
23061da546Spatrick #include "lldb/Utility/LLDBAssert.h"
24061da546Spatrick #include "lldb/lldb-defines.h"
25*f6aab3d8Srobert #include <optional>
26061da546Spatrick 
27061da546Spatrick using namespace lldb_private;
28061da546Spatrick using namespace lldb_private::npdb;
29061da546Spatrick using namespace llvm::codeview;
30061da546Spatrick using namespace llvm::pdb;
31061da546Spatrick 
PdbIndex()32061da546Spatrick PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
33061da546Spatrick 
34061da546Spatrick #define ASSIGN_PTR_OR_RETURN(result_ptr, expr)                                 \
35061da546Spatrick   {                                                                            \
36061da546Spatrick     auto expected_result = expr;                                               \
37061da546Spatrick     if (!expected_result)                                                      \
38061da546Spatrick       return expected_result.takeError();                                      \
39061da546Spatrick     result_ptr = &expected_result.get();                                       \
40061da546Spatrick   }
41061da546Spatrick 
42061da546Spatrick llvm::Expected<std::unique_ptr<PdbIndex>>
create(llvm::pdb::PDBFile * file)43be691f3bSpatrick PdbIndex::create(llvm::pdb::PDBFile *file) {
44061da546Spatrick   lldbassert(file);
45061da546Spatrick 
46061da546Spatrick   std::unique_ptr<PdbIndex> result(new PdbIndex());
47061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
48061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
49061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
50061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
51061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
52061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
53061da546Spatrick   ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
54061da546Spatrick 
55061da546Spatrick   result->m_tpi->buildHashMap();
56061da546Spatrick 
57be691f3bSpatrick   result->m_file = file;
58061da546Spatrick 
59061da546Spatrick   return std::move(result);
60061da546Spatrick }
61061da546Spatrick 
MakeVirtualAddress(uint16_t segment,uint32_t offset) const62061da546Spatrick lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
63061da546Spatrick                                           uint32_t offset) const {
64061da546Spatrick   uint32_t max_section = dbi().getSectionHeaders().size();
65*f6aab3d8Srobert   // Segment indices are 1-based.
66061da546Spatrick   // If this is an absolute symbol, it's indicated by the magic section index
67061da546Spatrick   // |max_section+1|.  In this case, the offset is meaningless, so just return.
68*f6aab3d8Srobert   if (segment == 0 || segment > max_section)
69061da546Spatrick     return LLDB_INVALID_ADDRESS;
70061da546Spatrick 
71061da546Spatrick   const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
72061da546Spatrick   return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
73061da546Spatrick          static_cast<lldb::addr_t>(offset);
74061da546Spatrick }
75061da546Spatrick 
GetModuleIndexForAddr(uint16_t segment,uint32_t offset) const76*f6aab3d8Srobert std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,
77*f6aab3d8Srobert                                                         uint32_t offset) const {
78061da546Spatrick   return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
79061da546Spatrick }
80061da546Spatrick 
GetModuleIndexForVa(lldb::addr_t va) const81*f6aab3d8Srobert std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
82061da546Spatrick   auto iter = m_va_to_modi.find(va);
83061da546Spatrick   if (iter == m_va_to_modi.end())
84*f6aab3d8Srobert     return std::nullopt;
85061da546Spatrick 
86061da546Spatrick   return iter.value();
87061da546Spatrick }
88061da546Spatrick 
ParseSectionContribs()89061da546Spatrick void PdbIndex::ParseSectionContribs() {
90061da546Spatrick   class Visitor : public ISectionContribVisitor {
91061da546Spatrick     PdbIndex &m_ctx;
92061da546Spatrick     llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
93061da546Spatrick 
94061da546Spatrick   public:
95061da546Spatrick     Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
96061da546Spatrick         : m_ctx(ctx), m_imap(imap) {}
97061da546Spatrick 
98061da546Spatrick     void visit(const SectionContrib &C) override {
99061da546Spatrick       if (C.Size == 0)
100061da546Spatrick         return;
101061da546Spatrick 
102061da546Spatrick       uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
103*f6aab3d8Srobert       if (va == LLDB_INVALID_ADDRESS)
104*f6aab3d8Srobert         return;
105061da546Spatrick       uint64_t end = va + C.Size;
106061da546Spatrick       // IntervalMap's start and end represent a closed range, not a half-open
107061da546Spatrick       // range, so we have to subtract 1.
108061da546Spatrick       m_imap.insert(va, end - 1, C.Imod);
109061da546Spatrick     }
110061da546Spatrick     void visit(const SectionContrib2 &C) override { visit(C.Base); }
111061da546Spatrick   };
112061da546Spatrick   Visitor v(*this, m_va_to_modi);
113061da546Spatrick   dbi().visitSectionContributions(v);
114061da546Spatrick }
115061da546Spatrick 
BuildAddrToSymbolMap(CompilandIndexItem & cci)116061da546Spatrick void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
117061da546Spatrick   lldbassert(cci.m_symbols_by_va.empty() &&
118061da546Spatrick              "Addr to symbol map is already built!");
119061da546Spatrick   uint16_t modi = cci.m_id.modi;
120061da546Spatrick   const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
121061da546Spatrick   for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
122061da546Spatrick     if (!SymbolHasAddress(*iter))
123061da546Spatrick       continue;
124061da546Spatrick 
125061da546Spatrick     SegmentOffset so = GetSegmentAndOffset(*iter);
126*f6aab3d8Srobert     lldb::addr_t va = MakeVirtualAddress(so.segment, so.offset);
127*f6aab3d8Srobert     if (va == LLDB_INVALID_ADDRESS)
128*f6aab3d8Srobert       continue;
129061da546Spatrick 
130061da546Spatrick     PdbCompilandSymId cu_sym_id(modi, iter.offset());
131061da546Spatrick 
132061da546Spatrick     // It's rare, but we could have multiple symbols with the same address
133061da546Spatrick     // because of identical comdat folding.  Right now, the first one will win.
134061da546Spatrick     cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
135061da546Spatrick   }
136061da546Spatrick }
137061da546Spatrick 
FindSymbolsByVa(lldb::addr_t va)138061da546Spatrick std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
139061da546Spatrick   std::vector<SymbolAndUid> result;
140061da546Spatrick 
141*f6aab3d8Srobert   std::optional<uint16_t> modi = GetModuleIndexForVa(va);
142061da546Spatrick   if (!modi)
143061da546Spatrick     return result;
144061da546Spatrick 
145061da546Spatrick   CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
146061da546Spatrick   if (cci.m_symbols_by_va.empty())
147061da546Spatrick     BuildAddrToSymbolMap(cci);
148061da546Spatrick 
149061da546Spatrick   // The map is sorted by starting address of the symbol.  So for example
150061da546Spatrick   // we could (in theory) have this situation
151061da546Spatrick   //
152061da546Spatrick   // [------------------]
153061da546Spatrick   //    [----------]
154061da546Spatrick   //      [-----------]
155061da546Spatrick   //          [-------------]
156061da546Spatrick   //            [----]
157061da546Spatrick   //               [-----]
158061da546Spatrick   //             ^ Address we're searching for
159061da546Spatrick   // In order to find this, we use the upper_bound of the key value which would
160061da546Spatrick   // be the first symbol whose starting address is higher than the element we're
161061da546Spatrick   // searching for.
162061da546Spatrick 
163061da546Spatrick   auto ub = cci.m_symbols_by_va.upper_bound(va);
164061da546Spatrick 
165061da546Spatrick   for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
166061da546Spatrick     PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
167061da546Spatrick     CVSymbol sym = ReadSymbolRecord(cu_sym_id);
168061da546Spatrick 
169061da546Spatrick     SegmentOffsetLength sol;
170061da546Spatrick     if (SymbolIsCode(sym))
171061da546Spatrick       sol = GetSegmentOffsetAndLength(sym);
172061da546Spatrick     else
173061da546Spatrick       sol.so = GetSegmentAndOffset(sym);
174061da546Spatrick 
175*f6aab3d8Srobert     lldb::addr_t start = MakeVirtualAddress(sol.so.segment, sol.so.offset);
176*f6aab3d8Srobert     if (start == LLDB_INVALID_ADDRESS)
177*f6aab3d8Srobert       continue;
178*f6aab3d8Srobert 
179061da546Spatrick     lldb::addr_t end = start + sol.length;
180061da546Spatrick     if (va >= start && va < end)
181061da546Spatrick       result.push_back({std::move(sym), iter->second});
182061da546Spatrick   }
183061da546Spatrick 
184061da546Spatrick   return result;
185061da546Spatrick }
186061da546Spatrick 
ReadSymbolRecord(PdbCompilandSymId cu_sym) const187061da546Spatrick CVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {
188061da546Spatrick   const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
189061da546Spatrick   auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
190061da546Spatrick   lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
191061da546Spatrick   return *iter;
192061da546Spatrick }
193061da546Spatrick 
ReadSymbolRecord(PdbGlobalSymId global) const194061da546Spatrick CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
195061da546Spatrick   return symrecords().readRecord(global.offset);
196061da546Spatrick }
197