[Go to site: main page, start]

LLDB mainline
PdbIndex.cpp
Go to the documentation of this file.
1//===-- PdbIndex.cpp ------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "PdbIndex.h"
10#include "PdbUtil.h"
11
12#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
13#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
14#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
15#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
16#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
18#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
19#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20#include "llvm/Object/COFF.h"
21#include "llvm/Support/Error.h"
22
23#include "lldb/lldb-defines.h"
24#include <optional>
25
26using namespace lldb_private;
27using namespace lldb_private::npdb;
28using namespace llvm::codeview;
29using namespace llvm::pdb;
30
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
41llvm::Expected<std::unique_ptr<PdbIndex>>
42PdbIndex::create(llvm::pdb::PDBFile *file) {
43 assert(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_tpi->buildHashMap();
55
56 result->m_file = file;
57
58 return std::move(result);
59}
60
62 uint32_t offset) const {
63 uint32_t max_section = dbi().getSectionHeaders().size();
64 // Segment indices are 1-based.
65 // If this is an absolute symbol, it's indicated by the magic section index
66 // |max_section+1|. In this case, the offset is meaningless, so just return.
67 if (segment == 0 || segment > max_section)
69
70 const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
71 return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
72 static_cast<lldb::addr_t>(offset);
73}
74
75std::optional<uint16_t> PdbIndex::GetModuleIndexForAddr(uint16_t segment,
76 uint32_t offset) const {
78}
79
80std::optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
81 auto iter = m_va_to_modi.find(va);
82 if (iter == m_va_to_modi.end())
83 return std::nullopt;
84
85 return iter.value();
86}
87
89 class Visitor : public ISectionContribVisitor {
90 PdbIndex &m_ctx;
91 llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
92
93 public:
94 Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
95 : m_ctx(ctx), m_imap(imap) {}
96
97 void visit(const SectionContrib &C) override {
98 if (C.Size == 0)
99 return;
100
101 uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
102 if (va == LLDB_INVALID_ADDRESS)
103 return;
104 uint64_t end = va + C.Size;
105 // IntervalMap's start and end represent a closed range, not a half-open
106 // range, so we have to subtract 1.
107 m_imap.insert(va, end - 1, C.Imod);
108 }
109 void visit(const SectionContrib2 &C) override { visit(C.Base); }
110 };
111 Visitor v(*this, m_va_to_modi);
112 dbi().visitSectionContributions(v);
113}
114
116 assert(cci.m_symbols_by_va.empty() && "Addr to symbol map is already built!");
117 uint16_t modi = cci.m_id.modi;
118 const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
119 for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
120 if (!SymbolHasAddress(*iter))
121 continue;
122
125 if (va == LLDB_INVALID_ADDRESS)
126 continue;
127
128 PdbCompilandSymId cu_sym_id(modi, iter.offset());
129
130 // It's rare, but we could have multiple symbols with the same address
131 // because of identical comdat folding. Right now, the first one will win.
132 cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
133 }
134}
135
136std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
137 std::vector<SymbolAndUid> result;
138
139 std::optional<uint16_t> modi = GetModuleIndexForVa(va);
140 if (!modi)
141 return result;
142
144 if (cci.m_symbols_by_va.empty())
146
147 // The map is sorted by starting address of the symbol. So for example
148 // we could (in theory) have this situation
149 //
150 // [------------------]
151 // [----------]
152 // [-----------]
153 // [-------------]
154 // [----]
155 // [-----]
156 // ^ Address we're searching for
157 // In order to find this, we use the upper_bound of the key value which would
158 // be the first symbol whose starting address is higher than the element we're
159 // searching for.
160
161 auto ub = cci.m_symbols_by_va.upper_bound(va);
162
163 for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
164 PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
165 CVSymbol sym = ReadSymbolRecord(cu_sym_id);
166
168 if (SymbolIsCode(sym))
169 sol = GetSegmentOffsetAndLength(sym);
170 else
171 sol.so = GetSegmentAndOffset(sym);
172
174 if (start == LLDB_INVALID_ADDRESS)
175 continue;
176
177 lldb::addr_t end = start + sol.length;
178 if (va >= start && va < end)
179 result.push_back({std::move(sym), iter->second});
180 }
181
182 return result;
183}
184
186 const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
187 auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
188 if (iter == cci->m_debug_stream.getSymbolArray().end()) {
189 assert(false && "missing symbol");
190 return {};
191 }
192 return *iter;
193}
194
196 return symrecords().readRecord(global.offset);
197}
#define ASSIGN_PTR_OR_RETURN(result_ptr, expr)
Definition PdbIndex.cpp:33
CompilandIndexItem & GetOrCreateCompiland(uint16_t modi)
const CompilandIndexItem * GetCompiland(uint16_t modi) const
std::vector< SymbolAndUid > FindSymbolsByVa(lldb::addr_t va)
Definition PdbIndex.cpp:136
CompileUnitIndex & compilands()
Definition PdbIndex.h:142
llvm::pdb::DbiStream & dbi()
Definition PdbIndex.h:121
void BuildAddrToSymbolMap(CompilandIndexItem &cci)
Definition PdbIndex.cpp:115
llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const
Definition PdbIndex.cpp:185
std::optional< uint16_t > GetModuleIndexForVa(lldb::addr_t va) const
Definition PdbIndex.cpp:80
CompileUnitIndex m_cus
Index of all compile units, mapping identifier to |CompilandIndexItem| instance.
Definition PdbIndex.h:96
std::optional< uint16_t > GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const
Definition PdbIndex.cpp:75
lldb::addr_t m_load_address
The address at which the program has been loaded into memory.
Definition PdbIndex.h:105
llvm::pdb::SymbolStream & symrecords()
Definition PdbIndex.h:139
llvm::IntervalMap< lldb::addr_t, uint16_t > m_va_to_modi
Maps virtual address to module index.
Definition PdbIndex.h:102
static llvm::Expected< std::unique_ptr< PdbIndex > > create(llvm::pdb::PDBFile *)
Definition PdbIndex.cpp:42
lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const
Definition PdbIndex.cpp:61
llvm::IntervalMap< lldb::addr_t, uint32_t >::Allocator m_allocator
An allocator for the interval maps.
Definition PdbIndex.h:99
#define LLDB_INVALID_ADDRESS
bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym)
SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym)
SegmentOffsetLength GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym)
bool SymbolIsCode(const llvm::codeview::CVSymbol &sym)
A class that represents a running process on the host machine.
uint64_t addr_t
Definition lldb-types.h:80
Represents a single compile unit.
llvm::pdb::ModuleDebugStreamRef m_debug_stream
std::map< lldb::addr_t, PdbSymUid > m_symbols_by_va