1 //===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "PdbIndex.h"
11 #include "PdbUtil.h"
12 
13 #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
14 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
15 #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
16 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18 #include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
19 #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
20 #include "llvm/Object/COFF.h"
21 #include "llvm/Support/Error.h"
22 
23 #include "lldb/Utility/LLDBAssert.h"
24 #include "lldb/lldb-defines.h"
25 
26 using namespace lldb_private;
27 using namespace lldb_private::npdb;
28 using namespace llvm::codeview;
29 using namespace llvm::pdb;
30 
31 PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
32 
33 #define ASSIGN_PTR_OR_RETURN(result_ptr, expr)                                 \
34   {                                                                            \
35     auto expected_result = expr;                                               \
36     if (!expected_result)                                                      \
37       return expected_result.takeError();                                      \
38     result_ptr = &expected_result.get();                                       \
39   }
40 
41 llvm::Expected<std::unique_ptr<PdbIndex>>
42 PdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) {
43   lldbassert(file);
44 
45   std::unique_ptr<PdbIndex> result(new PdbIndex());
46   ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
47   ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
48   ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
49   ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
50   ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
51   ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
52   ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
53 
54   result->m_file = std::move(file);
55 
56   return std::move(result);
57 }
58 
59 lldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
60                                           uint32_t offset) const {
61   // Segment indices are 1-based.
62   lldbassert(segment > 0);
63 
64   uint32_t max_section = dbi().getSectionHeaders().size();
65   lldbassert(segment <= max_section + 1);
66 
67   // If this is an absolute symbol, it's indicated by the magic section index
68   // |max_section+1|.  In this case, the offset is meaningless, so just return.
69   if (segment == max_section + 1)
70     return LLDB_INVALID_ADDRESS;
71 
72   const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
73   return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
74          static_cast<lldb::addr_t>(offset);
75 }
76 
77 lldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const {
78   return MakeVirtualAddress(so.segment, so.offset);
79 }
80 
81 llvm::Optional<uint16_t>
82 PdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const {
83   return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
84 }
85 
86 llvm::Optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
87   auto iter = m_va_to_modi.find(va);
88   if (iter == m_va_to_modi.end())
89     return llvm::None;
90 
91   return iter.value();
92 }
93 
94 void PdbIndex::ParseSectionContribs() {
95   class Visitor : public ISectionContribVisitor {
96     PdbIndex &m_ctx;
97     llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
98 
99   public:
100     Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
101         : m_ctx(ctx), m_imap(imap) {}
102 
103     void visit(const SectionContrib &C) override {
104       uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
105       uint64_t end = va + C.Size;
106       // IntervalMap's start and end represent a closed range, not a half-open
107       // range, so we have to subtract 1.
108       m_imap.insert(va, end - 1, C.Imod);
109     }
110     void visit(const SectionContrib2 &C) override { visit(C.Base); }
111   };
112   Visitor v(*this, m_va_to_modi);
113   dbi().visitSectionContributions(v);
114 }
115 
116 void PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
117   lldbassert(cci.m_symbols_by_va.empty() &&
118              "Addr to symbol map is already built!");
119   uint16_t modi = cci.m_uid.asCompiland().modi;
120   const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
121   for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
122     if (!SymbolHasAddress(*iter))
123       continue;
124 
125     SegmentOffset so = GetSegmentAndOffset(*iter);
126     lldb::addr_t va = MakeVirtualAddress(so);
127 
128     // We need to add 4 here to adjust for the codeview debug magic
129     // at the beginning of the debug info stream.
130     uint32_t sym_offset = iter.offset() + 4;
131     PdbSymUid cu_sym_uid =
132         PdbSymUid::makeCuSymId(CVSymToPDBSym(iter->kind()), modi, sym_offset);
133 
134     // If the debug info is incorrect, we could have multiple symbols with the
135     // same address.  So use try_emplace instead of insert, and the first one
136     // will win.
137     auto emplace_result = cci.m_symbols_by_va.try_emplace(va, cu_sym_uid);
138     (void)emplace_result;
139 
140     // The odds of an error in some function such as GetSegmentAndOffset or
141     // MakeVirtualAddress are much higher than the odds of encountering bad
142     // debug info, so assert that this item was inserted in the map as opposed
143     // to having already been there.
144     lldbassert(emplace_result.second);
145   }
146 }
147 
148 std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
149   std::vector<SymbolAndUid> result;
150 
151   llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va);
152   if (!modi)
153     return result;
154 
155   CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
156   if (cci.m_symbols_by_va.empty())
157     BuildAddrToSymbolMap(cci);
158 
159   // The map is sorted by starting address of the symbol.  So for example
160   // we could (in theory) have this situation
161   //
162   // [------------------]
163   //    [----------]
164   //      [-----------]
165   //          [-------------]
166   //            [----]
167   //               [-----]
168   //             ^ Address we're searching for
169   // In order to find this, we use the upper_bound of the key value which would
170   // be the first symbol whose starting address is higher than the element we're
171   // searching for.
172 
173   auto ub = cci.m_symbols_by_va.upper_bound(va);
174 
175   for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
176     const PdbCuSymId &cu_sym_id = iter->second.asCuSym();
177     CVSymbol sym = ReadSymbolRecord(cu_sym_id);
178 
179     SegmentOffsetLength sol;
180     if (SymbolIsCode(sym))
181       sol = GetSegmentOffsetAndLength(sym);
182     else
183       sol.so = GetSegmentAndOffset(sym);
184 
185     lldb::addr_t start = MakeVirtualAddress(sol.so);
186     lldb::addr_t end = start + sol.length;
187     if (va >= start && va < end)
188       result.push_back({std::move(sym), iter->second});
189   }
190 
191   return result;
192 }
193 
194 CVSymbol PdbIndex::ReadSymbolRecord(PdbCuSymId cu_sym) const {
195   // We need to subtract 4 here to adjust for the codeview debug magic
196   // at the beginning of the debug info stream.
197   PdbSymUid cuid = PdbSymUid::makeCompilandId(cu_sym.modi);
198   const CompilandIndexItem *cci = compilands().GetCompiland(cuid);
199   auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset - 4);
200   lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
201   return *iter;
202 }
203