Coverage Report

Created: 2023-11-11 10:31

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