Files
clang-p2996/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
Michael Buch 28d14904c0 [lldb][SymbolFileDWARF] Share GetDIEToType between SymbolFiles of a SymbolFileDWARFDebugMap (#120569)
The problem here manifests as follows:
1. We are stopped in main.o, so the first `ParseTypeFromDWARF` on
`FooImpl<char>` gets called on `main.o`'s SymbolFile. This adds a
mapping from *declaration die* -> `TypeSP` into `main.o`'s
`GetDIEToType` map.
2. We then `CompleteType(FooImpl<char>)`. Depending on the order of
entries in the debug-map, this might call `CompleteType` on `lib.o`'s
SymbolFile. In which case, `GetDIEToType().lookup(decl_die)` will return
a `nullptr`. This is already a bit iffy because some of the surrounding
code assumes we don't call `CompleteTypeFromDWARF` with a `nullptr`
`Type*`. E.g., `CompleteEnumType` blindly dereferences it (though enums
will never encounter this because their definition is fetched in
ParseEnum, unlike for structures).
3. While in `CompleteTypeFromDWARF`, we call `ParseTypeFromDWARF` again.
This will parse the member function `FooImpl::Create` and its return
type which is a typedef to `FooImpl*`. But now we're inside `lib.o`'s
SymbolFile, so we call it on the definition DIE. In step (2) we just
inserted a `nullptr` into `GetDIEToType` for the definition DIE, so we
trivially return a `nullptr` from `ParseTypeFromDWARF`. Instead of
reporting back this parse failure to the user LLDB trucks on and marks
`FooImpl::Ref` to be `void*`.

This test-case will trigger an assert in `TypeSystemClang::VerifyDecl`
even if we just `frame var` (but only in debug-builds). In release
builds where this function is a no-op, we'll create an incorrect Clang
AST node for the `Ref` typedef.

The proposed fix here is to share the `GetDIEToType` map between
SymbolFiles if a debug-map exists.

**Alternatives considered**
* Check the `GetDIEToType` map of the `SymbolFile` that the declaration
DIE belongs to. The assumption here being that if we called
`ParseTypeFromDWARF` on a declaration, the `GetDIEToType` map that the
result was inserted into was the one on that DIE's SymbolFile. This was
the first version of this patch, but that felt like a weaker version
sharing the map. It complicates the code in `CompleteType` and is less
consistent with the other bookkeeping structures we already share
between SymbolFiles
* Return from `SymbolFileDWARF::CompleteType` if there is no type in the
current `GetDIEToType`. Then `SymbolFileDWARFDebugMap::CompleteType`
could continue to the next `SymbolFile` which does own the type. But
that didn't quite work because we remove the
`GetForwardCompilerTypeToDie` entry in `SymbolFile::CompleteType`, which
`SymbolFileDWARFDebugMap::CompleteType` relies upon for iterating
2024-12-23 11:51:28 +00:00

99 lines
3.5 KiB
C++

//===-- SymbolFileDWARFDwo.h ------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H
#define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H
#include "SymbolFileDWARF.h"
#include <optional>
namespace lldb_private::plugin {
namespace dwarf {
class SymbolFileDWARFDwo : public SymbolFileDWARF {
/// LLVM RTTI support.
static char ID;
public:
/// LLVM RTTI support.
/// \{
bool isA(const void *ClassID) const override {
return ClassID == &ID || SymbolFileDWARF::isA(ClassID);
}
static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
/// \}
SymbolFileDWARFDwo(SymbolFileDWARF &m_base_symbol_file,
lldb::ObjectFileSP objfile, uint32_t id);
~SymbolFileDWARFDwo() override = default;
DWARFCompileUnit *GetDWOCompileUnitForHash(uint64_t hash);
void GetObjCMethods(ConstString class_name,
llvm::function_ref<bool(DWARFDIE die)> callback) override;
llvm::Expected<lldb::TypeSystemSP>
GetTypeSystemForLanguage(lldb::LanguageType language) override;
DWARFDIE
GetDIE(const DIERef &die_ref) override;
lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
const lldb::offset_t data_offset,
const uint8_t op) const override;
uint64_t GetDebugInfoSize(bool load_all_debug_info = false) override;
bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
lldb::offset_t &offset,
std::vector<Value> &stack) const override;
void FindGlobalVariables(ConstString name,
const CompilerDeclContext &parent_decl_ctx,
uint32_t max_matches,
VariableList &variables) override;
SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; }
bool GetDebugInfoIndexWasLoadedFromCache() const override;
void SetDebugInfoIndexWasLoadedFromCache() override;
bool GetDebugInfoIndexWasSavedToCache() const override;
void SetDebugInfoIndexWasSavedToCache() override;
bool GetDebugInfoHadFrameVariableErrors() const override;
void SetDebugInfoHadFrameVariableErrors() override;
SymbolFileDWARF *GetDIERefSymbolFile(const DIERef &die_ref) override;
protected:
llvm::DenseMap<const DWARFDebugInfoEntry *, Type *> &GetDIEToType() override;
DIEToVariableSP &GetDIEToVariable() override;
llvm::DenseMap<lldb::opaque_compiler_type_t, DIERef> &
GetForwardDeclCompilerTypeToDIE() override;
UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap() override;
DWARFDIE FindDefinitionDIE(const DWARFDIE &die) override;
lldb::TypeSP
FindCompleteObjCDefinitionTypeForDIE(const DWARFDIE &die,
ConstString type_name,
bool must_be_implementation) override;
/// If this file contains exactly one compile unit, this function will return
/// it. Otherwise it returns nullptr.
DWARFCompileUnit *FindSingleCompileUnit();
SymbolFileDWARF &m_base_symbol_file;
};
} // namespace dwarf
} // namespace lldb_private::plugin
#endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_SYMBOLFILEDWARFDWO_H