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