//===-- DebugNamesDWARFIndex.cpp ------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h"
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
#include "Plugins/SymbolFile/DWARF/DWARFDeclContext.h"
#include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
#include "lldb/Core/Module.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include "llvm/ADT/Sequence.h"
#include <optional>

using namespace lldb_private;
using namespace lldb;
using namespace lldb_private::dwarf;
using namespace lldb_private::plugin::dwarf;

llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>>
DebugNamesDWARFIndex::Create(Module &module, DWARFDataExtractor debug_names,
                             DWARFDataExtractor debug_str,
                             SymbolFileDWARF &dwarf) {
  auto index_up = std::make_unique<DebugNames>(debug_names.GetAsLLVMDWARF(),
                                               debug_str.GetAsLLVM());
  if (llvm::Error E = index_up->extract())
    return std::move(E);

  return std::unique_ptr<DebugNamesDWARFIndex>(new DebugNamesDWARFIndex(
      module, std::move(index_up), debug_names, debug_str, dwarf));
}

llvm::DenseSet<uint64_t>
DebugNamesDWARFIndex::GetTypeUnitSignatures(const DebugNames &debug_names) {
  llvm::DenseSet<uint64_t> result;
  for (const DebugNames::NameIndex &ni : debug_names) {
    const uint32_t num_tus = ni.getForeignTUCount();
    for (uint32_t tu = 0; tu < num_tus; ++tu)
      result.insert(ni.getForeignTUSignature(tu));
  }
  return result;
}

llvm::DenseSet<dw_offset_t>
DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
  llvm::DenseSet<dw_offset_t> result;
  for (const DebugNames::NameIndex &ni : debug_names) {
    const uint32_t num_cus = ni.getCUCount();
    for (uint32_t cu = 0; cu < num_cus; ++cu)
      result.insert(ni.getCUOffset(cu));
    const uint32_t num_tus = ni.getLocalTUCount();
    for (uint32_t tu = 0; tu < num_tus; ++tu)
      result.insert(ni.getLocalTUOffset(tu));
  }
  return result;
}

std::optional<DWARFTypeUnit *>
DebugNamesDWARFIndex::GetForeignTypeUnit(const DebugNames::Entry &entry) const {
  std::optional<uint64_t> type_sig = entry.getForeignTUTypeSignature();
  if (!type_sig.has_value())
    return std::nullopt;

  // Ask the entry for the skeleton compile unit offset and fetch the .dwo
  // file from it and get the type unit by signature from there. If we find
  // the type unit in the .dwo file, we don't need to check that the
  // DW_AT_dwo_name matches because each .dwo file can have its own type unit.
  std::optional<uint64_t> cu_offset = entry.getRelatedCUOffset();
  if (!cu_offset)
    return nullptr; // Return NULL, this is a type unit, but couldn't find it.

  DWARFUnit *cu =
      m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *cu_offset);
  if (!cu)
    return nullptr; // Return NULL, this is a type unit, but couldn't find it.

  auto dwp_sp = m_debug_info.GetDwpSymbolFile();
  if (!dwp_sp) {
    // No .dwp file, we need to load the .dwo file.
    DWARFUnit &dwo_cu = cu->GetNonSkeletonUnit();
    // We don't need the check if the type unit matches the .dwo file if we have
    // a .dwo file (not a .dwp), so we can just return the value here.
    if (!dwo_cu.IsDWOUnit())
      return nullptr; // We weren't able to load the .dwo file.
    return dwo_cu.GetSymbolFileDWARF().DebugInfo().GetTypeUnitForHash(
        *type_sig);
  }
  // We have a .dwp file, just get the type unit from there. We need to verify
  // that the type unit that ended up in the final .dwp file is the right type
  // unit. Type units have signatures which are the same across multiple .dwo
  // files, but only one of those type units will end up in the .dwp file. The
  // contents of type units for the same type can be different in different .dwo
  // files, which means the DIE offsets might not be the same between two
  // different type units. So we need to determine if this accelerator table
  // matches the type unit that ended up in the .dwp file. If it doesn't match,
  // then we need to ignore this accelerator table entry as the type unit that
  // is in the .dwp file will have its own index. In order to determine if the
  // type unit that ended up in a .dwp file matches this DebugNames::Entry, we
  // need to find the skeleton compile unit for this entry.
  DWARFTypeUnit *foreign_tu = dwp_sp->DebugInfo().GetTypeUnitForHash(*type_sig);
  if (!foreign_tu)
    return nullptr; // Return NULL, this is a type unit, but couldn't find it.

  DWARFBaseDIE cu_die = cu->GetUnitDIEOnly();
  DWARFBaseDIE tu_die = foreign_tu->GetUnitDIEOnly();
  llvm::StringRef cu_dwo_name =
      cu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
  llvm::StringRef tu_dwo_name =
      tu_die.GetAttributeValueAsString(DW_AT_dwo_name, nullptr);
  if (cu_dwo_name == tu_dwo_name)
    return foreign_tu; // We found a match!
  return nullptr; // Return NULL, this is a type unit, but couldn't find it.
}

DWARFUnit *
DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {

  if (std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry))
    return foreign_tu.value();

  // Look for a DWARF unit offset (CU offset or local TU offset) as they are
  // both offsets into the .debug_info section.
  std::optional<uint64_t> unit_offset = entry.getCUOffset();
  if (!unit_offset)
    unit_offset = entry.getLocalTUOffset();
  if (unit_offset) {
    if (DWARFUnit *cu = m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo,
                                                     *unit_offset))
      return &cu->GetNonSkeletonUnit();
  }
  return nullptr;
}

DWARFDIE DebugNamesDWARFIndex::GetDIE(const DebugNames::Entry &entry) const {
  DWARFUnit *unit = GetNonSkeletonUnit(entry);
  std::optional<uint64_t> die_offset = entry.getDIEUnitOffset();
  if (!unit || !die_offset)
    return DWARFDIE();
  if (DWARFDIE die = unit->GetDIE(unit->GetOffset() + *die_offset))
    return die;

  m_module.ReportErrorIfModifyDetected(
      "the DWARF debug information has been modified (bad offset {0:x} in "
      "debug_names section)\n",
      *die_offset);
  return DWARFDIE();
}

bool DebugNamesDWARFIndex::ProcessEntry(
    const DebugNames::Entry &entry,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  DWARFDIE die = GetDIE(entry);
  if (!die)
    return true;
  // Clang used to erroneously emit index entries for declaration DIEs in case
  // when the definition is in a type unit (llvm.org/pr77696).
  if (die.IsStructUnionOrClass() &&
      die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
    return true;
  return callback(die);
}

void DebugNamesDWARFIndex::MaybeLogLookupError(llvm::Error error,
                                               const DebugNames::NameIndex &ni,
                                               llvm::StringRef name) {
  // Ignore SentinelErrors, log everything else.
  LLDB_LOG_ERROR(
      GetLog(DWARFLog::Lookups),
      handleErrors(std::move(error), [](const DebugNames::SentinelError &) {}),
      "Failed to parse index entries for index at {1:x}, name {2}: {0}",
      ni.getUnitOffset(), name);
}

void DebugNamesDWARFIndex::GetGlobalVariables(
    ConstString basename, llvm::function_ref<bool(DWARFDIE die)> callback) {
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(basename.GetStringRef())) {
    if (entry.tag() != DW_TAG_variable)
      continue;

    if (!ProcessEntry(entry, callback))
      return;
  }

  m_fallback.GetGlobalVariables(basename, callback);
}

void DebugNamesDWARFIndex::GetGlobalVariables(
    const RegularExpression &regex,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
    for (DebugNames::NameTableEntry nte: ni) {
      Mangled mangled_name(nte.getString());
      if (!mangled_name.NameMatches(regex))
        continue;

      uint64_t entry_offset = nte.getEntryOffset();
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
        if (entry_or->tag() != DW_TAG_variable)
          continue;

        if (!ProcessEntry(*entry_or, callback))
          return;
      }
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
    }
  }

  m_fallback.GetGlobalVariables(regex, callback);
}

void DebugNamesDWARFIndex::GetGlobalVariables(
    DWARFUnit &cu, llvm::function_ref<bool(DWARFDIE die)> callback) {
  uint64_t cu_offset = cu.GetOffset();
  bool found_entry_for_cu = false;
  for (const DebugNames::NameIndex &ni : *m_debug_names_up) {
    // Check if this name index contains an entry for the given CU.
    bool cu_matches = false;
    for (uint32_t i = 0; i < ni.getCUCount(); ++i) {
      if (ni.getCUOffset(i) == cu_offset) {
        cu_matches = true;
        break;
      }
    }
    if (!cu_matches)
      continue;

    for (DebugNames::NameTableEntry nte : ni) {
      uint64_t entry_offset = nte.getEntryOffset();
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
        if (entry_or->tag() != DW_TAG_variable)
          continue;
        if (entry_or->getCUOffset() != cu_offset)
          continue;

        found_entry_for_cu = true;
        if (!ProcessEntry(*entry_or, callback))
          return;
      }
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
    }
  }
  // If no name index for that particular CU was found, fallback to
  // creating the manual index.
  if (!found_entry_for_cu)
    m_fallback.GetGlobalVariables(cu, callback);
}

void DebugNamesDWARFIndex::GetCompleteObjCClass(
    ConstString class_name, bool must_be_implementation,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  // Keep a list of incomplete types as fallback for when we don't find the
  // complete type.
  std::vector<DWARFDIE> incomplete_types;

  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(class_name.GetStringRef())) {
    if (entry.tag() != DW_TAG_structure_type &&
        entry.tag() != DW_TAG_class_type)
      continue;

    DWARFDIE die = GetDIE(entry);
    if (!die) {
      // Report invalid
      continue;
    }
    DWARFUnit *cu = die.GetCU();
    if (!cu->Supports_DW_AT_APPLE_objc_complete_type()) {
      incomplete_types.push_back(die);
      continue;
    }

    if (die.GetAttributeValueAsUnsigned(DW_AT_APPLE_objc_complete_type, 0)) {
      // If we find the complete version we're done.
      callback(die);
      return;
    }
    incomplete_types.push_back(die);
  }

  for (DWARFDIE die : incomplete_types)
    if (!callback(die))
      return;

  m_fallback.GetCompleteObjCClass(class_name, must_be_implementation, callback);
}

namespace {
using Entry = llvm::DWARFDebugNames::Entry;

/// If `entry` and all of its parents have an `IDX_parent`, use that information
/// to build and return a list of at most `max_parents` parent Entries.
/// `entry` itself is not included in the list.
/// If any parent does not have an `IDX_parent`, or the Entry data is corrupted,
/// nullopt is returned.
std::optional<llvm::SmallVector<Entry, 4>>
getParentChain(Entry entry,
               uint32_t max_parents = std::numeric_limits<uint32_t>::max()) {
  llvm::SmallVector<Entry, 4> parent_entries;

  do {
    if (!entry.hasParentInformation())
      return std::nullopt;

    llvm::Expected<std::optional<Entry>> parent = entry.getParentDIEEntry();
    if (!parent) {
      // Bad data.
      LLDB_LOG_ERROR(
          GetLog(DWARFLog::Lookups), parent.takeError(),
          "Failed to extract parent entry from a non-empty IDX_parent");
      return std::nullopt;
    }

    // Last parent in the chain.
    if (!parent->has_value())
      break;

    parent_entries.push_back(**parent);
    entry = **parent;
  } while (parent_entries.size() < max_parents);

  return parent_entries;
}
} // namespace

void DebugNamesDWARFIndex::GetFullyQualifiedType(
    const DWARFDeclContext &context,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  if (context.GetSize() == 0)
    return;

  llvm::StringRef leaf_name = context[0].name;
  llvm::SmallVector<llvm::StringRef> parent_names;
  for (auto idx : llvm::seq<int>(1, context.GetSize()))
    parent_names.emplace_back(context[idx].name);

  // For each entry, grab its parent chain and check if we have a match.
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(leaf_name)) {
    if (!isType(entry.tag()))
      continue;

    // If we get a NULL foreign_tu back, the entry doesn't match the type unit
    // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
    // didn't match.
    std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
    if (foreign_tu && foreign_tu.value() == nullptr)
      continue;

    // Grab at most one extra parent, subsequent parents are not necessary to
    // test equality.
    std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
        getParentChain(entry, parent_names.size() + 1);

    if (!parent_chain) {
      // Fallback: use the base class implementation.
      if (!ProcessEntry(entry, [&](DWARFDIE die) {
            return GetFullyQualifiedTypeImpl(context, die, callback);
          }))
        return;
      continue;
    }

    if (SameParentChain(parent_names, *parent_chain)) {
      if (!ProcessEntry(entry, callback))
        return;
    }
  }
  m_fallback.GetFullyQualifiedType(context, callback);
}

bool DebugNamesDWARFIndex::SameAsEntryContext(
    const CompilerContext &query_context,
    const DebugNames::Entry &entry) const {
  // TODO: check dwarf tag matches.
  // Peek at the AT_name of `entry` and test equality to `name`.
  auto maybe_dieoffset = entry.getDIEUnitOffset();
  if (!maybe_dieoffset)
    return false;
  DWARFUnit *unit = GetNonSkeletonUnit(entry);
  if (!unit)
    return false;
  return query_context.name ==
         unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
}

bool DebugNamesDWARFIndex::SameParentChain(
    llvm::ArrayRef<llvm::StringRef> parent_names,
    llvm::ArrayRef<DebugNames::Entry> parent_entries) const {

  if (parent_entries.size() != parent_names.size())
    return false;

  auto SameAsEntryATName = [this](llvm::StringRef name,
                                  const DebugNames::Entry &entry) {
    // Peek at the AT_name of `entry` and test equality to `name`.
    auto maybe_dieoffset = entry.getDIEUnitOffset();
    if (!maybe_dieoffset)
      return false;
    DWARFUnit *unit = GetNonSkeletonUnit(entry);
    if (!unit)
      return false;
    return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
  };

  // If the AT_name of any parent fails to match the expected name, we don't
  // have a match.
  for (auto [parent_name, parent_entry] :
       llvm::zip_equal(parent_names, parent_entries))
    if (!SameAsEntryATName(parent_name, parent_entry))
      return false;
  return true;
}

bool DebugNamesDWARFIndex::SameParentChain(
    llvm::ArrayRef<CompilerContext> parent_contexts,
    llvm::ArrayRef<DebugNames::Entry> parent_entries) const {
  if (parent_entries.size() != parent_contexts.size())
    return false;

  // If the AT_name of any parent fails to match the expected name, we don't
  // have a match.
  for (auto [parent_context, parent_entry] :
       llvm::zip_equal(parent_contexts, parent_entries))
    if (!SameAsEntryContext(parent_context, parent_entry))
      return false;
  return true;
}

bool DebugNamesDWARFIndex::WithinParentChain(
    llvm::ArrayRef<CompilerContext> query_contexts,
    llvm::ArrayRef<DebugNames::Entry> parent_chain) const {
  if (query_contexts.size() == parent_chain.size())
    return SameParentChain(query_contexts, parent_chain);

  // If parent chain does not have enough entries, we can't possibly have a
  // match.
  while (!query_contexts.empty() &&
         query_contexts.size() <= parent_chain.size()) {
    if (SameAsEntryContext(query_contexts.front(), parent_chain.front())) {
      query_contexts = query_contexts.drop_front();
      parent_chain = parent_chain.drop_front();
    } else {
      // Name does not match, try next parent_chain entry if the current entry
      // is namespace because the current one can be an inline namespace.
      if (parent_chain.front().tag() != DW_TAG_namespace)
        return false;
      parent_chain = parent_chain.drop_front();
    }
  }
  return query_contexts.empty();
}

void DebugNamesDWARFIndex::GetTypes(
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(name.GetStringRef())) {
    if (isType(entry.tag())) {
      if (!ProcessEntry(entry, callback))
        return;
    }
  }

  m_fallback.GetTypes(name, callback);
}

void DebugNamesDWARFIndex::GetTypes(
    const DWARFDeclContext &context,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  auto name = context[0].name;
  for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
    if (entry.tag() == context[0].tag) {
      if (!ProcessEntry(entry, callback))
        return;
    }
  }

  m_fallback.GetTypes(context, callback);
}

void DebugNamesDWARFIndex::GetNamespaces(
    ConstString name, llvm::function_ref<bool(DWARFDIE die)> callback) {
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(name.GetStringRef())) {
    lldb_private::dwarf::Tag entry_tag = entry.tag();
    if (entry_tag == DW_TAG_namespace ||
        entry_tag == DW_TAG_imported_declaration) {
      if (!ProcessEntry(entry, callback))
        return;
    }
  }

  m_fallback.GetNamespaces(name, callback);
}

llvm::SmallVector<CompilerContext>
DebugNamesDWARFIndex::GetTypeQueryParentContexts(TypeQuery &query) {
  std::vector<lldb_private::CompilerContext> &query_decl_context =
      query.GetContextRef();
  llvm::SmallVector<CompilerContext> parent_contexts;
  if (!query_decl_context.empty()) {
    // Skip the last entry as it's the type we're matching parents for.
    // Reverse the query decl context to match parent chain order.
    llvm::ArrayRef<CompilerContext> parent_contexts_ref(
        query_decl_context.data(), query_decl_context.size() - 1);
    for (const CompilerContext &ctx : llvm::reverse(parent_contexts_ref)) {
      // Skip any context without name because .debug_names might not encode
      // them. (e.g. annonymous namespace)
      if ((ctx.kind & CompilerContextKind::AnyType) !=
              CompilerContextKind::Invalid &&
          !ctx.name.IsEmpty())
        parent_contexts.push_back(ctx);
    }
  }
  return parent_contexts;
}

void DebugNamesDWARFIndex::GetTypesWithQuery(
    TypeQuery &query, llvm::function_ref<bool(DWARFDIE die)> callback) {
  ConstString name = query.GetTypeBasename();
  std::vector<lldb_private::CompilerContext> query_context =
      query.GetContextRef();
  if (query_context.size() <= 1 && !query.GetExactMatch())
    return GetTypes(name, callback);

  llvm::SmallVector<CompilerContext> parent_contexts =
      GetTypeQueryParentContexts(query);
  // For each entry, grab its parent chain and check if we have a match.
  for (const DebugNames::Entry &entry : m_debug_names_up->equal_range(name)) {
    if (!isType(entry.tag()))
      continue;

    // If we get a NULL foreign_tu back, the entry doesn't match the type unit
    // in the .dwp file, or we were not able to load the .dwo file or the DWO ID
    // didn't match.
    std::optional<DWARFTypeUnit *> foreign_tu = GetForeignTypeUnit(entry);
    if (foreign_tu && foreign_tu.value() == nullptr)
      continue;

    std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
        getParentChain(entry);
    if (!parent_chain) {
      // Fallback: use the base class implementation.
      if (!ProcessEntry(entry, [&](DWARFDIE die) {
            return ProcessTypeDIEMatchQuery(query, die, callback);
          }))
        return;
      continue;
    }

    if (WithinParentChain(parent_contexts, *parent_chain)) {
      if (!ProcessEntry(entry, [&](DWARFDIE die) {
            // After .debug_names filtering still sending to base class for
            // further filtering before calling the callback.
            return ProcessTypeDIEMatchQuery(query, die, callback);
          }))
        // If the callback returns false, we're done.
        return;
    }
  }
  m_fallback.GetTypesWithQuery(query, callback);
}

void DebugNamesDWARFIndex::GetNamespacesWithParents(
    ConstString name, const CompilerDeclContext &parent_decl_ctx,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  std::vector<lldb_private::CompilerContext> parent_contexts =
      parent_decl_ctx.GetCompilerContext();
  llvm::SmallVector<CompilerContext> parent_named_contexts;
  std::copy_if(parent_contexts.rbegin(), parent_contexts.rend(),
               std::back_inserter(parent_named_contexts),
               [](const CompilerContext &ctx) { return !ctx.name.IsEmpty(); });
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(name.GetStringRef())) {
    lldb_private::dwarf::Tag entry_tag = entry.tag();
    if (entry_tag == DW_TAG_namespace ||
        entry_tag == DW_TAG_imported_declaration) {
      std::optional<llvm::SmallVector<Entry, 4>> parent_chain =
          getParentChain(entry);
      if (!parent_chain) {
        // Fallback: use the base class implementation.
        if (!ProcessEntry(entry, [&](DWARFDIE die) {
              return ProcessNamespaceDieMatchParents(parent_decl_ctx, die,
                                                     callback);
            }))
          return;
        continue;
      }

      if (WithinParentChain(parent_named_contexts, *parent_chain)) {
        if (!ProcessEntry(entry, [&](DWARFDIE die) {
              // After .debug_names filtering still sending to base class for
              // further filtering before calling the callback.
              return ProcessNamespaceDieMatchParents(parent_decl_ctx, die,
                                                     callback);
            }))
          // If the callback returns false, we're done.
          return;
      }
    }
  }
  m_fallback.GetNamespacesWithParents(name, parent_decl_ctx, callback);
}

void DebugNamesDWARFIndex::GetFunctions(
    const Module::LookupInfo &lookup_info, SymbolFileDWARF &dwarf,
    const CompilerDeclContext &parent_decl_ctx,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  ConstString name = lookup_info.GetLookupName();
  std::set<DWARFDebugInfoEntry *> seen;
  for (const DebugNames::Entry &entry :
       m_debug_names_up->equal_range(name.GetStringRef())) {
    Tag tag = entry.tag();
    if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
      continue;

    if (DWARFDIE die = GetDIE(entry)) {
      if (!ProcessFunctionDIE(lookup_info, die, parent_decl_ctx,
                              [&](DWARFDIE die) {
                                if (!seen.insert(die.GetDIE()).second)
                                  return true;
                                return callback(die);
                              }))
        return;
    }
  }

  m_fallback.GetFunctions(lookup_info, dwarf, parent_decl_ctx, callback);
}

void DebugNamesDWARFIndex::GetFunctions(
    const RegularExpression &regex,
    llvm::function_ref<bool(DWARFDIE die)> callback) {
  for (const DebugNames::NameIndex &ni: *m_debug_names_up) {
    for (DebugNames::NameTableEntry nte: ni) {
      if (!regex.Execute(nte.getString()))
        continue;

      uint64_t entry_offset = nte.getEntryOffset();
      llvm::Expected<DebugNames::Entry> entry_or = ni.getEntry(&entry_offset);
      for (; entry_or; entry_or = ni.getEntry(&entry_offset)) {
        Tag tag = entry_or->tag();
        if (tag != DW_TAG_subprogram && tag != DW_TAG_inlined_subroutine)
          continue;

        if (!ProcessEntry(*entry_or, callback))
          return;
      }
      MaybeLogLookupError(entry_or.takeError(), ni, nte.getString());
    }
  }

  m_fallback.GetFunctions(regex, callback);
}

void DebugNamesDWARFIndex::Dump(Stream &s) {
  m_fallback.Dump(s);

  std::string data;
  llvm::raw_string_ostream os(data);
  m_debug_names_up->dump(os);
  s.PutCString(data);
}
