summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp
blob: 9ba9a4e0b87df159bffb373e0d72702cd9950311 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//===-- AppleDWARFIndex.cpp ------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Plugins/SymbolFile/DWARF/AppleDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"

#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Function.h"

using namespace lldb_private;
using namespace lldb;

std::unique_ptr<AppleDWARFIndex> AppleDWARFIndex::Create(
    Module &module, DWARFDataExtractor apple_names,
    DWARFDataExtractor apple_namespaces, DWARFDataExtractor apple_types,
    DWARFDataExtractor apple_objc, DWARFDataExtractor debug_str) {
  auto apple_names_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
      apple_names, debug_str, ".apple_names");
  if (!apple_names_table_up->IsValid())
    apple_names_table_up.reset();

  auto apple_namespaces_table_up =
      llvm::make_unique<DWARFMappedHash::MemoryTable>(
          apple_namespaces, debug_str, ".apple_namespaces");
  if (!apple_namespaces_table_up->IsValid())
    apple_namespaces_table_up.reset();

  auto apple_types_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
      apple_types, debug_str, ".apple_types");
  if (!apple_types_table_up->IsValid())
    apple_types_table_up.reset();

  auto apple_objc_table_up = llvm::make_unique<DWARFMappedHash::MemoryTable>(
      apple_objc, debug_str, ".apple_objc");
  if (!apple_objc_table_up->IsValid())
    apple_objc_table_up.reset();

  if (apple_names_table_up || apple_names_table_up || apple_types_table_up ||
      apple_objc_table_up)
    return llvm::make_unique<AppleDWARFIndex>(
        module, std::move(apple_names_table_up),
        std::move(apple_namespaces_table_up), std::move(apple_types_table_up),
        std::move(apple_objc_table_up));

  return nullptr;
}

void AppleDWARFIndex::GetGlobalVariables(ConstString name, DIEArray &offsets) {
  if (!m_apple_names_up)
    return;

  const char *name_cstr = name.GetCString();
  llvm::StringRef basename;
  llvm::StringRef context;

  if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context,
                                                      basename))
    basename = name_cstr;

  m_apple_names_up->FindByName(basename, offsets);
}

void AppleDWARFIndex::GetGlobalVariables(const RegularExpression &regex,
                                         DIEArray &offsets) {
  if (!m_apple_names_up)
    return;

  DWARFMappedHash::DIEInfoArray hash_data;
  if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data))
    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
}

void AppleDWARFIndex::GetGlobalVariables(const DWARFUnit &cu,
                                         DIEArray &offsets) {
  if (!m_apple_names_up)
    return;

  DWARFMappedHash::DIEInfoArray hash_data;
  if (m_apple_names_up->AppendAllDIEsInRange(
          cu.GetOffset(), cu.GetNextCompileUnitOffset(), hash_data))
    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
}

void AppleDWARFIndex::GetObjCMethods(ConstString class_name,
                                     DIEArray &offsets) {
  if (m_apple_objc_up)
    m_apple_objc_up->FindByName(class_name.GetStringRef(), offsets);
}

void AppleDWARFIndex::GetCompleteObjCClass(ConstString class_name,
                                           bool must_be_implementation,
                                           DIEArray &offsets) {
  if (m_apple_types_up) {
    m_apple_types_up->FindCompleteObjCClassByName(
        class_name.GetStringRef(), offsets, must_be_implementation);
  }
}

void AppleDWARFIndex::GetTypes(ConstString name, DIEArray &offsets) {
  if (m_apple_types_up)
    m_apple_types_up->FindByName(name.GetStringRef(), offsets);
}

void AppleDWARFIndex::GetTypes(const DWARFDeclContext &context,
                               DIEArray &offsets) {
  if (!m_apple_types_up)
    return;

  Log *log = LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
                                          DWARF_LOG_LOOKUPS);
  const bool has_tag = m_apple_types_up->GetHeader().header_data.ContainsAtom(
      DWARFMappedHash::eAtomTypeTag);
  const bool has_qualified_name_hash =
      m_apple_types_up->GetHeader().header_data.ContainsAtom(
          DWARFMappedHash::eAtomTypeQualNameHash);
  const ConstString type_name(context[0].name);
  const dw_tag_t tag = context[0].tag;
  if (has_tag && has_qualified_name_hash) {
    const char *qualified_name = context.GetQualifiedName();
    const uint32_t qualified_name_hash = llvm::djbHash(qualified_name);
    if (log)
      m_module.LogMessage(log, "FindByNameAndTagAndQualifiedNameHash()");
    m_apple_types_up->FindByNameAndTagAndQualifiedNameHash(
        type_name.GetStringRef(), tag, qualified_name_hash, offsets);
  } else if (has_tag) {
    if (log)
      m_module.LogMessage(log, "FindByNameAndTag()");
    m_apple_types_up->FindByNameAndTag(type_name.GetStringRef(), tag, offsets);
  } else
    m_apple_types_up->FindByName(type_name.GetStringRef(), offsets);
}

void AppleDWARFIndex::GetNamespaces(ConstString name, DIEArray &offsets) {
  if (m_apple_namespaces_up)
    m_apple_namespaces_up->FindByName(name.GetStringRef(), offsets);
}

static bool KeepFunctionDIE(DWARFDIE die, uint32_t name_type_mask) {
  bool looking_for_methods = name_type_mask & eFunctionNameTypeMethod;
  bool looking_for_functions = name_type_mask & eFunctionNameTypeBase;
  if (looking_for_methods && looking_for_functions)
    return true;
  return looking_for_methods == die.IsMethod();
}

void AppleDWARFIndex::GetFunctions(
    ConstString name, DWARFDebugInfo &info,
    llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
                            lldb_private::SymbolContextList &sc_list)>
        resolve_function,
    llvm::function_ref<CompilerDeclContext(lldb::user_id_t type_uid)>
        get_decl_context_containing_uid,
    const CompilerDeclContext *parent_decl_ctx, uint32_t name_type_mask,
    bool include_inlines, SymbolContextList &sc_list) {
  if (!m_apple_names_up)
    return;

  std::set<const DWARFDebugInfoEntry *> resolved_dies;
  DIEArray offsets;

  uint32_t num_matches = 0;

  if (name_type_mask & eFunctionNameTypeFull) {
    // If they asked for the full name, match what they typed.  At some
    // point we may want to canonicalize this (strip double spaces, etc.
    // For now, we just add all the dies that we find by exact match.
    num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
    for (uint32_t i = 0; i < num_matches; i++) {
      const DIERef &die_ref = offsets[i];
      DWARFDIE die = info.GetDIE(die_ref);
      if (die) {
        if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
          continue; // The containing decl contexts don't match

        if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
          if (resolve_function(die, include_inlines, sc_list))
            resolved_dies.insert(die.GetDIE());
        }
      } else
        ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
    }
  }

  if (name_type_mask & eFunctionNameTypeSelector) {
    if (parent_decl_ctx && parent_decl_ctx->IsValid())
      return; // no selectors in namespaces

    num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);
    // Now make sure these are actually ObjC methods.  In this case we can
    // simply look up the name, and if it is an ObjC method name, we're
    // good.

    for (uint32_t i = 0; i < num_matches; i++) {
      const DIERef &die_ref = offsets[i];
      DWARFDIE die = info.GetDIE(die_ref);
      if (die) {
        const char *die_name = die.GetName();
        if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) {
          if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
            if (resolve_function(die, include_inlines, sc_list))
              resolved_dies.insert(die.GetDIE());
          }
        }
      } else
        ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
    }
    offsets.clear();
  }

  if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) ||
      name_type_mask & eFunctionNameTypeBase) {
    // The apple_names table stores just the "base name" of C++ methods in
    // the table.  So we have to extract the base name, look that up, and
    // if there is any other information in the name we were passed in we
    // have to post-filter based on that.

    // FIXME: Arrange the logic above so that we don't calculate the base
    // name twice:
    num_matches = m_apple_names_up->FindByName(name.GetStringRef(), offsets);

    for (uint32_t i = 0; i < num_matches; i++) {
      const DIERef &die_ref = offsets[i];
      DWARFDIE die = info.GetDIE(die_ref);
      if (die) {
        if (!SymbolFileDWARF::DIEInDeclContext(parent_decl_ctx, die))
          continue; // The containing decl contexts don't match

        if (!KeepFunctionDIE(die, name_type_mask))
          continue;

        if (resolved_dies.find(die.GetDIE()) != resolved_dies.end())
          continue;

        // If we get to here, the die is good, and we should add it:
        if (resolve_function(die, include_inlines, sc_list))
          resolved_dies.insert(die.GetDIE());
      } else
        ReportInvalidDIEOffset(die_ref.die_offset, name.GetStringRef());
    }
    offsets.clear();
  }
}

void AppleDWARFIndex::GetFunctions(
    const RegularExpression &regex, DWARFDebugInfo &info,
    llvm::function_ref<bool(const DWARFDIE &die, bool include_inlines,
                            lldb_private::SymbolContextList &sc_list)>
        resolve_function,
    bool include_inlines, SymbolContextList &sc_list) {
  if (!m_apple_names_up)
    return;

  DIEArray offsets;
  DWARFMappedHash::DIEInfoArray hash_data;
  if (m_apple_names_up->AppendAllDIEsThatMatchingRegex(regex, hash_data)) {
    DWARFMappedHash::ExtractDIEArray(hash_data, offsets);
    ParseFunctions(offsets, info, resolve_function, include_inlines, sc_list);
  }
}

void AppleDWARFIndex::ReportInvalidDIEOffset(dw_offset_t offset,
                                             llvm::StringRef name) {
  m_module.ReportErrorIfModifyDetected(
      "the DWARF debug information has been modified (accelerator table had "
      "bad die 0x%8.8x for '%s')\n",
      offset, name.str().c_str());
}

void AppleDWARFIndex::Dump(Stream &s) {
  // TODO: Implement dumping.
}
OpenPOWER on IntegriCloud