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 
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(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_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)
68  return LLDB_INVALID_ADDRESS;
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 
75 llvm::Optional<uint16_t>
77  return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
78 }
79 
80 llvm::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 llvm::None;
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  lldbassert(cci.m_symbols_by_va.empty() &&
117  "Addr to symbol map is already built!");
118  uint16_t modi = cci.m_id.modi;
119  const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
120  for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
121  if (!SymbolHasAddress(*iter))
122  continue;
123 
126  if (va == LLDB_INVALID_ADDRESS)
127  continue;
128 
129  PdbCompilandSymId cu_sym_id(modi, iter.offset());
130 
131  // It's rare, but we could have multiple symbols with the same address
132  // because of identical comdat folding. Right now, the first one will win.
133  cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
134  }
135 }
136 
137 std::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
138  std::vector<SymbolAndUid> result;
139 
140  llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va);
141  if (!modi)
142  return result;
143 
145  if (cci.m_symbols_by_va.empty())
147 
148  // The map is sorted by starting address of the symbol. So for example
149  // we could (in theory) have this situation
150  //
151  // [------------------]
152  // [----------]
153  // [-----------]
154  // [-------------]
155  // [----]
156  // [-----]
157  // ^ Address we're searching for
158  // In order to find this, we use the upper_bound of the key value which would
159  // be the first symbol whose starting address is higher than the element we're
160  // searching for.
161 
162  auto ub = cci.m_symbols_by_va.upper_bound(va);
163 
164  for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
165  PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
166  CVSymbol sym = ReadSymbolRecord(cu_sym_id);
167 
169  if (SymbolIsCode(sym))
170  sol = GetSegmentOffsetAndLength(sym);
171  else
172  sol.so = GetSegmentAndOffset(sym);
173 
175  if (start == LLDB_INVALID_ADDRESS)
176  continue;
177 
178  lldb::addr_t end = start + sol.length;
179  if (va >= start && va < end)
180  result.push_back({std::move(sym), iter->second});
181  }
182 
183  return result;
184 }
185 
187  const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
188  auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
189  lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
190  return *iter;
191 }
192 
194  return symrecords().readRecord(global.offset);
195 }
lldb_private::npdb::CompilandIndexItem::m_debug_stream
llvm::pdb::ModuleDebugStreamRef m_debug_stream
Definition: CompileUnitIndex.h:48
lldb_private::npdb::CompileUnitIndex::GetCompiland
const CompilandIndexItem * GetCompiland(uint16_t modi) const
Definition: CompileUnitIndex.cpp:194
lldb_private::npdb::GetSegmentAndOffset
SegmentOffset GetSegmentAndOffset(const llvm::codeview::CVSymbol &sym)
lldb_private::npdb::PdbIndex::compilands
CompileUnitIndex & compilands()
Definition: PdbIndex.h:142
lldb_private::npdb::SegmentOffsetLength
Definition: PdbUtil.h:95
lldb-defines.h
lldb_private::npdb::PdbIndex
PdbIndex - Lazy access to the important parts of a PDB file.
Definition: PdbIndex.h:47
lldb_private::npdb::PdbCompilandSymId
Definition: PdbSymUid.h:44
lldb_private::npdb::SegmentOffset
Definition: PdbUtil.h:88
lldb_private::npdb::GetSegmentOffsetAndLength
SegmentOffsetLength GetSegmentOffsetAndLength(const llvm::codeview::CVSymbol &sym)
lldb_private::npdb
Definition: CodeViewRegisterMapping.h:16
lldb_private::npdb::PdbIndex::m_va_to_modi
llvm::IntervalMap< lldb::addr_t, uint16_t > m_va_to_modi
Maps virtual address to module index.
Definition: PdbIndex.h:102
lldb_private::npdb::PdbCompilandSymId::modi
uint16_t modi
Definition: PdbSymUid.h:49
lldb_private::npdb::PdbIndex::ReadSymbolRecord
llvm::codeview::CVSymbol ReadSymbolRecord(PdbCompilandSymId cu_sym) const
Definition: PdbIndex.cpp:186
lldb_private::npdb::PdbIndex::BuildAddrToSymbolMap
void BuildAddrToSymbolMap(CompilandIndexItem &cci)
Definition: PdbIndex.cpp:115
lldb_private::npdb::PdbGlobalSymId::offset
uint32_t offset
Definition: PdbSymUid.h:63
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
PdbIndex.h
lldb_private::npdb::PdbIndex::GetModuleIndexForVa
llvm::Optional< uint16_t > GetModuleIndexForVa(lldb::addr_t va) const
Definition: PdbIndex.cpp:80
lldb_private::npdb::CompileUnitIndex::GetOrCreateCompiland
CompilandIndexItem & GetOrCreateCompiland(uint16_t modi)
Definition: CompileUnitIndex.cpp:133
LLDBAssert.h
lldb_private::npdb::PdbGlobalSymId
Definition: PdbSymUid.h:57
llvm::pdb
Definition: DWARFLocationExpression.h:23
lldb_private::npdb::PdbIndex::dbi
llvm::pdb::DbiStream & dbi()
Definition: PdbIndex.h:121
lldb_private::npdb::PdbCompilandSymId::offset
uint32_t offset
Definition: PdbSymUid.h:54
lldb_private::npdb::SegmentOffset::segment
uint16_t segment
Definition: PdbUtil.h:91
lldb_private::npdb::PdbIndex::create
static llvm::Expected< std::unique_ptr< PdbIndex > > create(llvm::pdb::PDBFile *)
Definition: PdbIndex.cpp:42
lldb_private::npdb::PdbIndex::m_load_address
lldb::addr_t m_load_address
The address at which the program has been loaded into memory.
Definition: PdbIndex.h:105
lldb_private::npdb::SymbolIsCode
bool SymbolIsCode(const llvm::codeview::CVSymbol &sym)
lldb_private::npdb::SegmentOffsetLength::so
SegmentOffset so
Definition: PdbUtil.h:99
PdbUtil.h
lldb_private::npdb::SymbolHasAddress
bool SymbolHasAddress(const llvm::codeview::CVSymbol &sym)
lldbassert
#define lldbassert(x)
Definition: LLDBAssert.h:15
lldb_private::npdb::PdbIndex::FindSymbolsByVa
std::vector< SymbolAndUid > FindSymbolsByVa(lldb::addr_t va)
Definition: PdbIndex.cpp:137
lldb_private::npdb::SegmentOffset::offset
uint32_t offset
Definition: PdbUtil.h:92
lldb_private::npdb::CompilandIndexItem
Represents a single compile unit.
Definition: CompileUnitIndex.h:39
uint32_t
lldb_private::npdb::CompilandIndexItem::m_id
PdbCompilandId m_id
Definition: CompileUnitIndex.h:45
lldb_private::npdb::PdbCompilandId::modi
uint16_t modi
Definition: PdbSymUid.h:41
lldb_private::npdb::PdbIndex::MakeVirtualAddress
lldb::addr_t MakeVirtualAddress(uint16_t segment, uint32_t offset) const
Definition: PdbIndex.cpp:61
uint16_t
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
lldb_private::npdb::PdbIndex::symrecords
llvm::pdb::SymbolStream & symrecords()
Definition: PdbIndex.h:139
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
llvm::codeview
Definition: DWARFLocationExpression.h:20
lldb_private::npdb::SegmentOffsetLength::length
uint32_t length
Definition: PdbUtil.h:100
lldb_private::npdb::PdbIndex::GetModuleIndexForAddr
llvm::Optional< uint16_t > GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const
Definition: PdbIndex.cpp:76
lldb_private::npdb::PdbIndex::PdbIndex
PdbIndex()
Definition: PdbIndex.cpp:31
lldb_private::npdb::CompilandIndexItem::m_symbols_by_va
std::map< lldb::addr_t, PdbSymUid > m_symbols_by_va
Definition: CompileUnitIndex.h:62
lldb_private::npdb::PdbSymUid
Definition: PdbSymUid.h:91
ASSIGN_PTR_OR_RETURN
#define ASSIGN_PTR_OR_RETURN(result_ptr, expr)
Definition: PdbIndex.cpp:33
lldb_private::npdb::PdbIndex::ParseSectionContribs
void ParseSectionContribs()
Definition: PdbIndex.cpp:88