PdbIndex.cpp revision 343181
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
27using namespace lldb_private;
28using namespace lldb_private::npdb;
29using namespace llvm::codeview;
30using namespace llvm::pdb;
31
32PdbIndex::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
42llvm::Expected<std::unique_ptr<PdbIndex>>
43PdbIndex::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
62lldb::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
80lldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const {
81  return MakeVirtualAddress(so.segment, so.offset);
82}
83
84llvm::Optional<uint16_t>
85PdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const {
86  return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
87}
88
89llvm::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
97void 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
122void 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
143std::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
189CVSymbol 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
198CVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
199  return symrecords().readRecord(global.offset);
200}
201