1343181Sdim//===-- PdbIndex.cpp --------------------------------------------*- C++ -*-===//
2343181Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6343181Sdim//
7343181Sdim//===----------------------------------------------------------------------===//
8343181Sdim
9343181Sdim#include "PdbIndex.h"
10343181Sdim#include "PdbUtil.h"
11343181Sdim
12343181Sdim#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
13343181Sdim#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
14343181Sdim#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
15343181Sdim#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
16343181Sdim#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17343181Sdim#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
18343181Sdim#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
19343181Sdim#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
20343181Sdim#include "llvm/Object/COFF.h"
21343181Sdim#include "llvm/Support/Error.h"
22343181Sdim
23343181Sdim#include "lldb/Utility/LLDBAssert.h"
24343181Sdim#include "lldb/lldb-defines.h"
25343181Sdim
26343181Sdimusing namespace lldb_private;
27343181Sdimusing namespace lldb_private::npdb;
28343181Sdimusing namespace llvm::codeview;
29343181Sdimusing namespace llvm::pdb;
30343181Sdim
31343181SdimPdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {}
32343181Sdim
33343181Sdim#define ASSIGN_PTR_OR_RETURN(result_ptr, expr)                                 \
34343181Sdim  {                                                                            \
35343181Sdim    auto expected_result = expr;                                               \
36343181Sdim    if (!expected_result)                                                      \
37343181Sdim      return expected_result.takeError();                                      \
38343181Sdim    result_ptr = &expected_result.get();                                       \
39343181Sdim  }
40343181Sdim
41343181Sdimllvm::Expected<std::unique_ptr<PdbIndex>>
42343181SdimPdbIndex::create(std::unique_ptr<llvm::pdb::PDBFile> file) {
43343181Sdim  lldbassert(file);
44343181Sdim
45343181Sdim  std::unique_ptr<PdbIndex> result(new PdbIndex());
46343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
47343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
48343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
49343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
50343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
51343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
52343181Sdim  ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
53343181Sdim
54343181Sdim  result->m_tpi->buildHashMap();
55343181Sdim
56343181Sdim  result->m_file = std::move(file);
57343181Sdim
58343181Sdim  return std::move(result);
59343181Sdim}
60343181Sdim
61343181Sdimlldb::addr_t PdbIndex::MakeVirtualAddress(uint16_t segment,
62343181Sdim                                          uint32_t offset) const {
63343181Sdim  // Segment indices are 1-based.
64343181Sdim  lldbassert(segment > 0);
65343181Sdim
66343181Sdim  uint32_t max_section = dbi().getSectionHeaders().size();
67343181Sdim  lldbassert(segment <= max_section + 1);
68343181Sdim
69343181Sdim  // If this is an absolute symbol, it's indicated by the magic section index
70343181Sdim  // |max_section+1|.  In this case, the offset is meaningless, so just return.
71343181Sdim  if (segment == max_section + 1)
72343181Sdim    return LLDB_INVALID_ADDRESS;
73343181Sdim
74343181Sdim  const llvm::object::coff_section &cs = dbi().getSectionHeaders()[segment - 1];
75343181Sdim  return m_load_address + static_cast<lldb::addr_t>(cs.VirtualAddress) +
76343181Sdim         static_cast<lldb::addr_t>(offset);
77343181Sdim}
78343181Sdim
79343181Sdimlldb::addr_t PdbIndex::MakeVirtualAddress(const SegmentOffset &so) const {
80343181Sdim  return MakeVirtualAddress(so.segment, so.offset);
81343181Sdim}
82343181Sdim
83343181Sdimllvm::Optional<uint16_t>
84343181SdimPdbIndex::GetModuleIndexForAddr(uint16_t segment, uint32_t offset) const {
85343181Sdim  return GetModuleIndexForVa(MakeVirtualAddress(segment, offset));
86343181Sdim}
87343181Sdim
88343181Sdimllvm::Optional<uint16_t> PdbIndex::GetModuleIndexForVa(lldb::addr_t va) const {
89343181Sdim  auto iter = m_va_to_modi.find(va);
90343181Sdim  if (iter == m_va_to_modi.end())
91343181Sdim    return llvm::None;
92343181Sdim
93343181Sdim  return iter.value();
94343181Sdim}
95343181Sdim
96343181Sdimvoid PdbIndex::ParseSectionContribs() {
97343181Sdim  class Visitor : public ISectionContribVisitor {
98343181Sdim    PdbIndex &m_ctx;
99343181Sdim    llvm::IntervalMap<uint64_t, uint16_t> &m_imap;
100343181Sdim
101343181Sdim  public:
102343181Sdim    Visitor(PdbIndex &ctx, llvm::IntervalMap<uint64_t, uint16_t> &imap)
103343181Sdim        : m_ctx(ctx), m_imap(imap) {}
104343181Sdim
105343181Sdim    void visit(const SectionContrib &C) override {
106343181Sdim      if (C.Size == 0)
107343181Sdim        return;
108343181Sdim
109343181Sdim      uint64_t va = m_ctx.MakeVirtualAddress(C.ISect, C.Off);
110343181Sdim      uint64_t end = va + C.Size;
111343181Sdim      // IntervalMap's start and end represent a closed range, not a half-open
112343181Sdim      // range, so we have to subtract 1.
113343181Sdim      m_imap.insert(va, end - 1, C.Imod);
114343181Sdim    }
115343181Sdim    void visit(const SectionContrib2 &C) override { visit(C.Base); }
116343181Sdim  };
117343181Sdim  Visitor v(*this, m_va_to_modi);
118343181Sdim  dbi().visitSectionContributions(v);
119343181Sdim}
120343181Sdim
121343181Sdimvoid PdbIndex::BuildAddrToSymbolMap(CompilandIndexItem &cci) {
122343181Sdim  lldbassert(cci.m_symbols_by_va.empty() &&
123343181Sdim             "Addr to symbol map is already built!");
124343181Sdim  uint16_t modi = cci.m_id.modi;
125343181Sdim  const CVSymbolArray &syms = cci.m_debug_stream.getSymbolArray();
126343181Sdim  for (auto iter = syms.begin(); iter != syms.end(); ++iter) {
127343181Sdim    if (!SymbolHasAddress(*iter))
128343181Sdim      continue;
129343181Sdim
130343181Sdim    SegmentOffset so = GetSegmentAndOffset(*iter);
131343181Sdim    lldb::addr_t va = MakeVirtualAddress(so);
132343181Sdim
133343181Sdim    PdbCompilandSymId cu_sym_id(modi, iter.offset());
134343181Sdim
135353358Sdim    // It's rare, but we could have multiple symbols with the same address
136353358Sdim    // because of identical comdat folding.  Right now, the first one will win.
137343181Sdim    cci.m_symbols_by_va.insert(std::make_pair(va, PdbSymUid(cu_sym_id)));
138343181Sdim  }
139343181Sdim}
140343181Sdim
141343181Sdimstd::vector<SymbolAndUid> PdbIndex::FindSymbolsByVa(lldb::addr_t va) {
142343181Sdim  std::vector<SymbolAndUid> result;
143343181Sdim
144343181Sdim  llvm::Optional<uint16_t> modi = GetModuleIndexForVa(va);
145343181Sdim  if (!modi)
146343181Sdim    return result;
147343181Sdim
148343181Sdim  CompilandIndexItem &cci = compilands().GetOrCreateCompiland(*modi);
149343181Sdim  if (cci.m_symbols_by_va.empty())
150343181Sdim    BuildAddrToSymbolMap(cci);
151343181Sdim
152343181Sdim  // The map is sorted by starting address of the symbol.  So for example
153343181Sdim  // we could (in theory) have this situation
154343181Sdim  //
155343181Sdim  // [------------------]
156343181Sdim  //    [----------]
157343181Sdim  //      [-----------]
158343181Sdim  //          [-------------]
159343181Sdim  //            [----]
160343181Sdim  //               [-----]
161343181Sdim  //             ^ Address we're searching for
162343181Sdim  // In order to find this, we use the upper_bound of the key value which would
163343181Sdim  // be the first symbol whose starting address is higher than the element we're
164343181Sdim  // searching for.
165343181Sdim
166343181Sdim  auto ub = cci.m_symbols_by_va.upper_bound(va);
167343181Sdim
168343181Sdim  for (auto iter = cci.m_symbols_by_va.begin(); iter != ub; ++iter) {
169343181Sdim    PdbCompilandSymId cu_sym_id = iter->second.asCompilandSym();
170343181Sdim    CVSymbol sym = ReadSymbolRecord(cu_sym_id);
171343181Sdim
172343181Sdim    SegmentOffsetLength sol;
173343181Sdim    if (SymbolIsCode(sym))
174343181Sdim      sol = GetSegmentOffsetAndLength(sym);
175343181Sdim    else
176343181Sdim      sol.so = GetSegmentAndOffset(sym);
177343181Sdim
178343181Sdim    lldb::addr_t start = MakeVirtualAddress(sol.so);
179343181Sdim    lldb::addr_t end = start + sol.length;
180343181Sdim    if (va >= start && va < end)
181343181Sdim      result.push_back({std::move(sym), iter->second});
182343181Sdim  }
183343181Sdim
184343181Sdim  return result;
185343181Sdim}
186343181Sdim
187343181SdimCVSymbol PdbIndex::ReadSymbolRecord(PdbCompilandSymId cu_sym) const {
188343181Sdim  const CompilandIndexItem *cci = compilands().GetCompiland(cu_sym.modi);
189343181Sdim  auto iter = cci->m_debug_stream.getSymbolArray().at(cu_sym.offset);
190343181Sdim  lldbassert(iter != cci->m_debug_stream.getSymbolArray().end());
191343181Sdim  return *iter;
192343181Sdim}
193343181Sdim
194343181SdimCVSymbol PdbIndex::ReadSymbolRecord(PdbGlobalSymId global) const {
195343181Sdim  return symrecords().readRecord(global.offset);
196343181Sdim}
197