Currently a Module has a std::optional<UnwindTable> which is created when the UnwindTable is requested from outside the Module. The idea is to delay its creation until the Module has an ObjectFile initialized, which will have been done by the time we're doing an unwind. However, Module::GetUnwindTable wasn't doing any locking, so it was possible for two threads to ask for the UnwindTable for the first time, one would be created and returned while another thread would create one, destroy the first in the process of emplacing it. It was an uncommon crash, but it was possible. Grabbing the Module's mutex would be one way to address it, but when loading ELF binaries, we start creating the SymbolTable on one thread (ObjectFileELF) grabbing the Module's mutex, and then spin up worker threads to parse the individual DWARF compilation units, which then try to also get the UnwindTable and deadlock if they try to get the Module's mutex. This changes Module to have a concrete UnwindTable as an ivar, and when it adds an ObjectFile or SymbolFileVendor, it will call the Update method on it, which will re-evaluate which sections exist in the ObjectFile/SymbolFile. UnwindTable used to have an Initialize method which set all the sections, and an Update method which would set some of them if they weren't set. I unified these with the Initialize method taking a `force` option to re-initialize the section pointers even if they had been done already before. This is addressing a rare crash report we've received, and also a failure Adrian spotted on the -fsanitize=address CI bot last week, it's still uncommon with ASAN but it can happen with the standard testsuite. rdar://128876433
98 lines
3.5 KiB
C++
98 lines
3.5 KiB
C++
//===-- UnwindTable.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_SYMBOL_UNWINDTABLE_H
|
|
#define LLDB_SYMBOL_UNWINDTABLE_H
|
|
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <optional>
|
|
|
|
#include "lldb/lldb-private.h"
|
|
|
|
namespace lldb_private {
|
|
|
|
// A class which holds all the FuncUnwinders objects for a given ObjectFile.
|
|
// The UnwindTable is populated with FuncUnwinders objects lazily during the
|
|
// debug session.
|
|
|
|
class UnwindTable {
|
|
public:
|
|
/// Create an Unwind table using the data in the given module.
|
|
explicit UnwindTable(Module &module);
|
|
|
|
~UnwindTable();
|
|
|
|
lldb_private::CallFrameInfo *GetObjectFileUnwindInfo();
|
|
|
|
lldb_private::DWARFCallFrameInfo *GetEHFrameInfo();
|
|
lldb_private::DWARFCallFrameInfo *GetDebugFrameInfo();
|
|
|
|
lldb_private::CompactUnwindInfo *GetCompactUnwindInfo();
|
|
|
|
ArmUnwindInfo *GetArmUnwindInfo();
|
|
SymbolFile *GetSymbolFile();
|
|
|
|
lldb::FuncUnwindersSP GetFuncUnwindersContainingAddress(const Address &addr,
|
|
SymbolContext &sc);
|
|
|
|
bool GetAllowAssemblyEmulationUnwindPlans();
|
|
|
|
// Normally when we create a new FuncUnwinders object we track it in this
|
|
// UnwindTable so it can be reused later. But for the target modules show-
|
|
// unwind we want to create brand new UnwindPlans for the function of
|
|
// interest - so ignore any existing FuncUnwinders for that function and
|
|
// don't add this new one to our UnwindTable. This FuncUnwinders object does
|
|
// have a reference to the UnwindTable but the lifetime of this uncached
|
|
// FuncUnwinders is expected to be short so in practice this will not be a
|
|
// problem.
|
|
lldb::FuncUnwindersSP
|
|
GetUncachedFuncUnwindersContainingAddress(const Address &addr,
|
|
const SymbolContext &sc);
|
|
|
|
ArchSpec GetArchitecture();
|
|
|
|
/// Called after an ObjectFile/SymbolFile has been added to a Module to add
|
|
/// any new unwind sections that may now be available.
|
|
void ModuleWasUpdated();
|
|
|
|
private:
|
|
void Dump(Stream &s);
|
|
|
|
void Initialize();
|
|
std::optional<AddressRange> GetAddressRange(const Address &addr,
|
|
const SymbolContext &sc);
|
|
|
|
typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
|
|
typedef collection::iterator iterator;
|
|
typedef collection::const_iterator const_iterator;
|
|
|
|
Module &m_module;
|
|
collection m_unwinds;
|
|
|
|
bool m_scanned_all_unwind_sources; // true when we have looked at the
|
|
// ObjectFile and SymbolFile for all
|
|
// sources of unwind information; false if
|
|
// we haven't done that yet, or one of the
|
|
// files has been updated in the Module.
|
|
std::mutex m_mutex;
|
|
|
|
std::unique_ptr<CallFrameInfo> m_object_file_unwind_up;
|
|
std::unique_ptr<DWARFCallFrameInfo> m_eh_frame_up;
|
|
std::unique_ptr<DWARFCallFrameInfo> m_debug_frame_up;
|
|
std::unique_ptr<CompactUnwindInfo> m_compact_unwind_up;
|
|
std::unique_ptr<ArmUnwindInfo> m_arm_unwind_up;
|
|
|
|
UnwindTable(const UnwindTable &) = delete;
|
|
const UnwindTable &operator=(const UnwindTable &) = delete;
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // LLDB_SYMBOL_UNWINDTABLE_H
|