| //===-- ProcessElfCore.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 | |
| // | |
| // Notes about Linux Process core dumps: | |
| // 1) Linux core dump is stored as ELF file. | |
| // 2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's | |
| // address space and thread contexts. | |
| // 3) PT_NOTE segment contains note entries which describes a thread context. | |
| // 4) PT_LOAD segment describes a valid contiguous range of process address | |
| // space. | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H | |
| #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H | |
| #include <functional> | |
| #include <list> | |
| #include <set> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include "lldb/Target/MemoryRegionInfo.h" | |
| #include "lldb/Target/PostMortemProcess.h" | |
| #include "lldb/Utility/Args.h" | |
| #include "lldb/Utility/Status.h" | |
| #include "Plugins/ObjectFile/ELF/ELFHeader.h" | |
| #include "Plugins/Process/elf-core/RegisterUtilities.h" | |
| struct ThreadData; | |
| class ProcessElfCore : public lldb_private::PostMortemProcess { | |
| public: | |
| // Constructors and Destructors | |
| static lldb::ProcessSP | |
| CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, | |
| const lldb_private::FileSpec *crash_file_path, | |
| bool can_connect); | |
| static void Initialize(); | |
| static void Terminate(); | |
| static llvm::StringRef GetPluginNameStatic() { return "elf-core"; } | |
| static llvm::StringRef GetPluginDescriptionStatic(); | |
| // Constructors and Destructors | |
| ProcessElfCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, | |
| const lldb_private::FileSpec &core_file); | |
| ~ProcessElfCore() override; | |
| // Check if a given Process | |
| bool CanDebug(lldb::TargetSP target_sp, | |
| bool plugin_specified_by_name) override; | |
| // Creating a new process, or attaching to an existing one | |
| lldb_private::Status DoLoadCore() override; | |
| lldb_private::DynamicLoader *GetDynamicLoader() override; | |
| // PluginInterface protocol | |
| llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } | |
| // Process Control | |
| lldb_private::Status DoDestroy() override; | |
| void RefreshStateAfterStop() override; | |
| lldb_private::Status WillResume() override { | |
| return lldb_private::Status::FromErrorStringWithFormatv( | |
| "error: {0} does not support resuming processes", GetPluginName()); | |
| } | |
| // Process Queries | |
| bool IsAlive() override; | |
| bool WarnBeforeDetach() const override { return false; } | |
| // Process Memory | |
| size_t ReadMemory(const lldb_private::ProcessAddress &addr, void *buf, | |
| size_t size, lldb_private::Status &error) override; | |
| size_t DoReadMemory(const lldb_private::ProcessAddress &addr, void *buf, | |
| size_t size, lldb_private::Status &error) override; | |
| // We do not implement DoReadMemoryTags. Instead all the work is done in | |
| // ReadMemoryTags which avoids having to unpack and repack tags. | |
| llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr, | |
| size_t len) override; | |
| lldb::addr_t GetImageInfoAddress() override; | |
| lldb_private::ArchSpec GetArchitecture(); | |
| // Returns AUXV structure found in the core file | |
| lldb_private::DataExtractor GetAuxvData() override; | |
| std::optional<Process::CoreArgs> GetCoreFileArgs() override; | |
| bool GetProcessInfo(lldb_private::ProcessInstanceInfo &info) override; | |
| protected: | |
| void Clear(); | |
| bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, | |
| lldb_private::ThreadList &new_thread_list) override; | |
| lldb_private::Status | |
| DoGetMemoryRegionInfo(lldb::addr_t load_addr, | |
| lldb_private::MemoryRegionInfo ®ion_info) override; | |
| bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); } | |
| private: | |
| struct NT_FILE_Entry { | |
| lldb::addr_t start; | |
| lldb::addr_t end; | |
| lldb::addr_t file_ofs; | |
| std::string path; | |
| }; | |
| // For ProcessElfCore only | |
| typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange; | |
| typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, FileRange> | |
| VMRangeToFileOffset; | |
| lldb::ModuleSP m_core_module_sp; | |
| std::string m_dyld_plugin_name; | |
| // True if m_thread_contexts contains valid entries | |
| bool m_thread_data_valid = false; | |
| // Contain thread data read from NOTE segments | |
| std::vector<ThreadData> m_thread_data; | |
| // AUXV structure found from the NOTE segment | |
| lldb_private::DataExtractor m_auxv; | |
| // Address ranges found in the core | |
| VMRangeToFileOffset m_core_aranges; | |
| // Information for all mapped ranges, ordered by address. | |
| std::set<lldb_private::MemoryRegionInfo, std::less<>> m_core_range_infos; | |
| // Memory tag ranges found in the core | |
| VMRangeToFileOffset m_core_tag_ranges; | |
| // NT_FILE entries found from the NOTE segment | |
| std::vector<NT_FILE_Entry> m_nt_file_entries; | |
| // Map from file path to UUID for quick lookup | |
| std::unordered_map<std::string, lldb_private::UUID> m_uuids; | |
| // Executable name found from the ELF PRPSINFO | |
| std::string m_executable_name; | |
| // Command line args found from the ELF PRPSINFO (pr_psargs) | |
| Process::CoreArgs m_process_args; | |
| // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment | |
| llvm::Error ParseThreadContextsFromNoteSegment( | |
| const elf::ELFProgramHeader &segment_header, | |
| const lldb_private::DataExtractor &segment_data); | |
| // Returns number of thread contexts stored in the core file | |
| uint32_t GetNumThreadContexts(); | |
| // Populate gnu uuid for each NT_FILE entry | |
| void UpdateBuildIdForNTFileEntries(); | |
| // Complete memory region information after all program headers are parsed. | |
| void FinalizeMemoryRegionInfos(); | |
| bool FindModuleUUID(lldb_private::ModuleSpec &spec) override; | |
| // Extract the executable module spec for the executable in this core file. | |
| bool GetMainExecutableModuleSpec(lldb_private::ModuleSpec &exe_spec); | |
| // Returns the value of certain type of note of a given start address | |
| lldb_private::UUID FindBuidIdInCoreMemory(lldb::addr_t address); | |
| // Parse a contiguous address range of the process from LOAD segment | |
| lldb::addr_t | |
| AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header); | |
| // Parse a contiguous address range from a memory tag segment | |
| lldb::addr_t | |
| AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header); | |
| llvm::Expected<std::vector<lldb_private::CoreNote>> | |
| parseSegment(const lldb_private::DataExtractor &segment); | |
| llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); | |
| llvm::Error parseNetBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); | |
| llvm::Error parseOpenBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); | |
| llvm::Error parseLinuxNotes(llvm::ArrayRef<lldb_private::CoreNote> notes); | |
| /// Find the NT_FILE entry that contains an address. | |
| std::optional<NT_FILE_Entry> | |
| GetNTFileEntryContainingAddress(lldb::addr_t addr); | |
| /// Intelligently find the NT_FILE entry for the executable's ELF header. | |
| std::optional<NT_FILE_Entry> GetNTFileEntryForExecutableELFHeader(); | |
| }; | |
| #endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_PROCESSELFCORE_H |