28#include "llvm/BinaryFormat/ELF.h"
29#include "llvm/Support/Threading.h"
38namespace ELF = llvm::ELF;
43 return "ELF core dump plug-in.";
51 lldb::ListenerSP listener_sp,
54 lldb::ProcessSP process_sp;
55 if (crash_file && !can_connect) {
59 const size_t header_size =
sizeof(llvm::ELF::Elf64_Ehdr);
62 crash_file->
GetPath(), header_size, 0);
63 if (data_sp && data_sp->GetByteSize() == header_size &&
68 if (elf_header.
Parse(data, &data_offset)) {
73 if (elf_header.
e_type == llvm::ELF::ET_CORE)
74 process_sp = std::make_shared<ProcessElfCore>(target_sp, listener_sp,
83 bool plugin_specified_by_name) {
88 nullptr,
nullptr,
nullptr));
100 lldb::ListenerSP listener_sp,
126 last_entry->
data.GetRangeEnd() == range_entry.
data.GetRangeBase() &&
129 last_entry->
data.SetRangeEnd(range_entry.
data.GetRangeEnd());
137 ((header.
p_flags & llvm::ELF::PF_R) ? lldb::ePermissionsReadable : 0u) |
138 ((header.
p_flags & llvm::ELF::PF_W) ? lldb::ePermissionsWritable : 0u) |
139 ((header.
p_flags & llvm::ELF::PF_X) ? lldb::ePermissionsExecutable : 0u);
163 error.SetErrorString(
"invalid core module");
168 if (core ==
nullptr) {
169 error.SetErrorString(
"invalid core object file");
173 llvm::ArrayRef<elf::ELFProgramHeader> segments = core->
ProgramHeaders();
174 if (segments.size() == 0) {
175 error.SetErrorString(
"core file has no segments");
183 bool ranges_are_sorted =
true;
195 if (H.p_type == llvm::ELF::PT_NOTE) {
200 if (H.p_type == llvm::ELF::PT_LOAD) {
202 if (vm_addr > last_addr)
203 ranges_are_sorted =
false;
205 }
else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) {
207 if (tag_addr > last_addr)
208 ranges_are_sorted =
false;
209 tag_addr = last_addr;
213 if (!ranges_are_sorted) {
231 bool siginfo_signal_found =
false;
232 bool prstatus_signal_found =
false;
235 if (thread_data.signo != 0)
236 siginfo_signal_found =
true;
237 if (thread_data.prstatus_sig != 0)
238 prstatus_signal_found =
true;
240 if (!siginfo_signal_found) {
243 if (prstatus_signal_found) {
245 thread_data.signo = thread_data.prstatus_sig;
256 if (!exe_module_sp) {
287 for (
lldb::tid_t tid = 0; tid < num_threads; ++tid) {
292 return new_thread_list.
GetSize(
false) > 0;
306 if (lldb::ABISP abi_sp =
GetABI())
307 addr = abi_sp->FixAnyAddress(addr);
319 if (permission_entry) {
320 if (permission_entry->
Contains(load_addr)) {
323 const Flags permissions(permission_entry->
data);
343 }
else if (load_addr < permission_entry->GetRangeBase()) {
369 if (core_objfile ==
nullptr)
375 if (address_range ==
nullptr || address_range->
GetRangeEnd() < addr) {
376 error.SetErrorStringWithFormat(
"core file does not contain 0x%" PRIx64,
385 size_t bytes_to_read = size;
386 size_t bytes_copied = 0;
392 if (file_start == file_end)
397 if (file_end > file_start + offset)
398 bytes_left = file_end - (file_start + offset);
400 if (bytes_to_read > bytes_left)
401 bytes_to_read = bytes_left;
406 core_objfile->
CopyData(offset + file_start, bytes_to_read, buf);
411llvm::Expected<std::vector<lldb::addr_t>>
414 if (core_objfile ==
nullptr)
415 return llvm::createStringError(llvm::inconvertibleErrorCode(),
416 "No core object file.");
418 llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
420 if (!tag_manager_or_err)
421 return tag_manager_or_err.takeError();
431 if (!tag_entry || (addr + len) >= tag_entry->
GetRangeEnd())
432 return llvm::createStringError(llvm::inconvertibleErrorCode(),
433 "No tag segment that covers this range.");
438 return core_objfile->
CopyData(offset, length, dst);
450 static llvm::once_flag g_once_flag;
452 llvm::call_once(g_once_flag, []() {
472 int pr_version = data.
GetU32(&offset);
477 LLDB_LOGF(log,
"FreeBSD PRSTATUS unexpected version %d", pr_version);
500 int pr_version = data.
GetU32(&offset);
505 LLDB_LOGF(log,
"FreeBSD PRPSINFO unexpected version %d", pr_version);
525 return llvm::make_error<llvm::StringError>(
526 "Error parsing NetBSD core(5) notes: Unsupported procinfo version",
527 llvm::inconvertibleErrorCode());
531 return llvm::make_error<llvm::StringError>(
532 "Error parsing NetBSD core(5) notes: Unsupported procinfo size",
533 llvm::inconvertibleErrorCode());
535 cpi_signo = data.
GetU32(&offset);
542 cpi_pid = data.
GetU32(&offset);
552 cpi_nlwps = data.
GetU32(&offset);
555 cpi_siglwp = data.
GetU32(&offset);
557 return llvm::Error::success();
564 int version = data.
GetU32(&offset);
572llvm::Expected<std::vector<CoreNote>>
575 std::vector<CoreNote> result;
579 if (!note.
Parse(segment, &offset))
580 return llvm::make_error<llvm::StringError>(
581 "Unable to parse note segment", llvm::inconvertibleErrorCode());
583 size_t note_start = offset;
584 size_t note_size = llvm::alignTo(note.
n_descsz, 4);
586 result.push_back({note,
DataExtractor(segment, note_start, note_size)});
590 return std::move(result);
595 bool lp64 = (arch.
GetMachine() == llvm::Triple::aarch64 ||
599 bool have_prstatus =
false;
600 bool have_prpsinfo =
false;
602 for (
const auto ¬e : notes) {
603 if (note.info.n_name !=
"FreeBSD")
606 if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
607 (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
612 have_prstatus =
false;
613 have_prpsinfo =
false;
616 switch (note.info.n_type) {
617 case ELF::NT_PRSTATUS:
618 have_prstatus =
true;
621 case ELF::NT_PRPSINFO:
622 have_prpsinfo =
true;
625 case ELF::NT_FREEBSD_THRMISC: {
627 thread_data.
name = note.data.GetCStr(&offset, 20);
630 case ELF::NT_FREEBSD_PROCSTAT_AUXV:
635 thread_data.
notes.push_back(note);
639 if (!have_prstatus) {
640 return llvm::make_error<llvm::StringError>(
641 "Could not find NT_PRSTATUS note in core file.",
642 llvm::inconvertibleErrorCode());
645 return llvm::Error::success();
672 bool had_nt_regs =
false;
681 for (
const auto ¬e : notes) {
682 llvm::StringRef name = note.info.n_name;
684 if (name ==
"NetBSD-CORE") {
694 }
else if (name.consume_front(
"NetBSD-CORE@")) {
696 if (name.getAsInteger(10, tid))
697 return llvm::make_error<llvm::StringError>(
698 "Error parsing NetBSD core(5) notes: Cannot convert LWP ID "
700 llvm::inconvertibleErrorCode());
703 case llvm::Triple::aarch64: {
714 thread_data.
tid = tid;
716 return llvm::make_error<llvm::StringError>(
717 "Could not find general purpose registers note in core file.",
718 llvm::inconvertibleErrorCode());
721 if (!had_nt_regs || tid != thread_data.
tid)
722 return llvm::make_error<llvm::StringError>(
723 "Error parsing NetBSD core(5) notes: Unexpected order "
724 "of NOTEs PT_GETFPREG before PT_GETREG",
725 llvm::inconvertibleErrorCode());
726 thread_data.
notes.push_back(note);
729 case llvm::Triple::x86: {
740 thread_data.
tid = tid;
742 return llvm::make_error<llvm::StringError>(
743 "Could not find general purpose registers note in core file.",
744 llvm::inconvertibleErrorCode());
747 if (!had_nt_regs || tid != thread_data.
tid)
748 return llvm::make_error<llvm::StringError>(
749 "Error parsing NetBSD core(5) notes: Unexpected order "
750 "of NOTEs PT_GETFPREG before PT_GETREG",
751 llvm::inconvertibleErrorCode());
752 thread_data.
notes.push_back(note);
755 case llvm::Triple::x86_64: {
766 thread_data.
tid = tid;
768 return llvm::make_error<llvm::StringError>(
769 "Could not find general purpose registers note in core file.",
770 llvm::inconvertibleErrorCode());
773 if (!had_nt_regs || tid != thread_data.
tid)
774 return llvm::make_error<llvm::StringError>(
775 "Error parsing NetBSD core(5) notes: Unexpected order "
776 "of NOTEs PT_GETFPREG before PT_GETREG",
777 llvm::inconvertibleErrorCode());
778 thread_data.
notes.push_back(note);
792 return llvm::make_error<llvm::StringError>(
793 "Error parsing NetBSD core(5) notes: No threads information "
794 "specified in notes",
795 llvm::inconvertibleErrorCode());
798 return llvm::make_error<llvm::StringError>(
799 "Error parsing NetBSD core(5) notes: Mismatch between the number "
800 "of LWPs in netbsd_elfcore_procinfo and the number of LWPs specified "
802 llvm::inconvertibleErrorCode());
814 if (data.tid == siglwp) {
822 return llvm::make_error<llvm::StringError>(
823 "Error parsing NetBSD core(5) notes: Signal passed to unknown LWP",
824 llvm::inconvertibleErrorCode());
827 return llvm::Error::success();
832 for (
const auto ¬e : notes) {
835 if (!llvm::StringRef(note.info.n_name).startswith(
"OpenBSD"))
838 switch (note.info.n_type) {
849 thread_data.
notes.push_back(note);
854 return llvm::make_error<llvm::StringError>(
855 "Could not find general purpose registers note in core file.",
856 llvm::inconvertibleErrorCode());
859 return llvm::Error::success();
876 bool have_prstatus =
false;
877 bool have_prpsinfo =
false;
879 for (
const auto ¬e : notes) {
880 if (note.info.n_name !=
"CORE" && note.info.n_name !=
"LINUX")
883 if ((note.info.n_type == ELF::NT_PRSTATUS && have_prstatus) ||
884 (note.info.n_type == ELF::NT_PRPSINFO && have_prpsinfo)) {
889 have_prstatus =
false;
890 have_prpsinfo =
false;
893 switch (note.info.n_type) {
894 case ELF::NT_PRSTATUS: {
895 have_prstatus =
true;
903 size_t len = note.data.GetByteSize() - header_size;
907 case ELF::NT_PRPSINFO: {
908 have_prpsinfo =
true;
917 case ELF::NT_SIGINFO: {
929 const uint64_t count = note.data.GetAddress(&offset);
930 note.data.GetAddress(&offset);
931 for (uint64_t i = 0; i < count; ++i) {
933 entry.
start = note.data.GetAddress(&offset);
934 entry.
end = note.data.GetAddress(&offset);
935 entry.
file_ofs = note.data.GetAddress(&offset);
938 for (uint64_t i = 0; i < count; ++i) {
939 const char *path = note.data.GetCStr(&offset);
949 thread_data.
notes.push_back(note);
956 return llvm::Error::success();
965 assert(segment_header.
p_type == llvm::ELF::PT_NOTE);
969 return notes_or_error.takeError();
971 case llvm::Triple::FreeBSD:
973 case llvm::Triple::Linux:
975 case llvm::Triple::NetBSD:
977 case llvm::Triple::OpenBSD:
980 return llvm::make_error<llvm::StringError>(
981 "Don't know how to parse core file. Unsupported OS.",
982 llvm::inconvertibleErrorCode());
1001 if (target_arch.
IsMIPS()) {
1021 const bool add_exe_file_as_first_arg =
false;
1023 add_exe_file_as_first_arg);
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
#define LLDB_PLUGIN_DEFINE(PluginName)
static void ParseOpenBSDProcInfo(ThreadData &thread_data, const DataExtractor &data)
static void ParseFreeBSDPrPsInfo(ProcessElfCore &process, const DataExtractor &data, bool lp64)
static void ParseFreeBSDPrStatus(ThreadData &thread_data, const DataExtractor &data, bool lp64)
static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data, uint32_t &cpi_nlwps, uint32_t &cpi_signo, uint32_t &cpi_siglwp, uint32_t &cpi_pid)
static llvm::StringRef GetPluginNameStatic()
Generic COFF object file reader.
lldb_private::DataExtractor GetSegmentData(const elf::ELFProgramHeader &H)
llvm::ArrayRef< elf::ELFProgramHeader > ProgramHeaders()
std::vector< NT_FILE_Entry > m_nt_file_entries
lldb::addr_t GetImageInfoAddress() override
Get the image information address for the current process.
lldb::addr_t AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header)
lldb_private::DataExtractor m_auxv
llvm::Error parseLinuxNotes(llvm::ArrayRef< lldb_private::CoreNote > notes)
A description of a linux process usually contains the following NOTE entries:
llvm::Error ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader &segment_header, const lldb_private::DataExtractor &segment_data)
Parse Thread context from PT_NOTE segment and store it in the thread list A note segment consists of ...
std::vector< ThreadData > m_thread_data
lldb_private::FileSpec m_core_file
bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list) override
Update the thread list following process plug-in's specific logic.
size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Status &error) override
Read of memory from a process.
VMRangeToPermissions m_core_range_infos
static llvm::StringRef GetPluginDescriptionStatic()
llvm::Expected< std::vector< lldb_private::CoreNote > > parseSegment(const lldb_private::DataExtractor &segment)
lldb::addr_t AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header)
~ProcessElfCore() override
llvm::Error parseFreeBSDNotes(llvm::ArrayRef< lldb_private::CoreNote > notes)
VMRangeToFileOffset m_core_aranges
lldb_private::Status DoGetMemoryRegionInfo(lldb::addr_t load_addr, lldb_private::MemoryRegionInfo ®ion_info) override
DoGetMemoryRegionInfo is called by GetMemoryRegionInfo after it has removed non address bits from loa...
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Status &error) override
Actually do the reading of memory from a process.
VMRangeToFileOffset m_core_tag_ranges
llvm::Error parseNetBSDNotes(llvm::ArrayRef< lldb_private::CoreNote > notes)
NetBSD specific Thread context from PT_NOTE segment.
lldb_private::Status DoLoadCore() override
ProcessElfCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const lldb_private::FileSpec &core_file)
lldb_private::DynamicLoader * GetDynamicLoader() override
Get the dynamic loader plug-in for this process.
llvm::Expected< std::vector< lldb::addr_t > > ReadMemoryTags(lldb::addr_t addr, size_t len) override
Read memory tags for the range addr to addr+len.
lldb_private::DataExtractor GetAuxvData() override
bool IsAlive() override
Check if a process is still alive.
uint32_t GetNumThreadContexts()
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const lldb_private::FileSpec *crash_file_path, bool can_connect)
llvm::Error parseOpenBSDNotes(llvm::ArrayRef< lldb_private::CoreNote > notes)
void RefreshStateAfterStop() override
Currently called as part of ShouldStop.
lldb_private::ArchSpec GetArchitecture()
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
bool GetProcessInfo(lldb_private::ProcessInstanceInfo &info) override
static llvm::StringRef GetPluginNameStatic()
lldb::ModuleSP m_core_module_sp
lldb_private::Status DoDestroy() override
A section + offset based address class.
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
bool IsValid() const
Check if the object state is valid.
An architecture specification class.
void MergeFrom(const ArchSpec &other)
Merges fields from another ArchSpec into this ArchSpec.
bool IsMIPS() const
if MIPS architecture return true.
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
A subclass of DataBuffer that stores a data buffer on the heap.
A plug-in interface definition class for dynamic loaders.
static DynamicLoader * FindPlugin(Process *process, llvm::StringRef plugin_name)
Find a dynamic loader plugin for a given process.
void SetFile(llvm::StringRef path, Style style)
Change the file specified with a new path.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
static FileSystem & Instance()
std::shared_ptr< DataBuffer > CreateDataBuffer(const llvm::Twine &path, uint64_t size=0, uint64_t offset=0)
Create memory buffer from path.
bool Test(ValueType bit) const
Test a single flag bit.
void SetMapped(OptionalBool val)
void SetMemoryTagged(OptionalBool val)
void SetReadable(OptionalBool val)
void SetExecutable(OptionalBool val)
void SetWritable(OptionalBool val)
virtual std::vector< lldb::addr_t > UnpackTagsFromCoreFileSegment(CoreReaderFn reader, lldb::addr_t tag_segment_virtual_address, lldb::addr_t tag_segment_data_address, lldb::addr_t addr, size_t len) const =0
static Status GetSharedModule(const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, llvm::SmallVectorImpl< lldb::ModuleSP > *old_modules, bool *did_create_ptr, bool always_create=false)
ArchSpec & GetArchitecture()
A plug-in interface definition class for object file parsers.
virtual lldb_private::Address GetImageInfoAddress(Target *target)
Similar to Process::GetImageInfoAddress().
@ eTypeCoreFile
A core file that has a checkpoint of a program's execution state.
size_t CopyData(lldb::offset_t offset, size_t length, void *dst) const
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
Base class for all processes that don't represent a live process, such as coredumps or processes trac...
void SetExecutableFile(const FileSpec &exe_file, bool add_exe_file_as_first_arg)
void SetArchitecture(const ArchSpec &arch)
void SetProcessID(lldb::pid_t pid)
virtual void Finalize()
This object is about to be destroyed, do any necessary cleanup.
lldb::pid_t GetID() const
Returns the pid of the process or LLDB_INVALID_PROCESS_ID if there is no known pid.
void SetUnixSignals(lldb::UnixSignalsSP &&signals_sp)
void SetCanJIT(bool can_jit)
Sets whether executing JIT-compiled code in this process is possible.
lldb::DynamicLoaderUP m_dyld_up
llvm::Expected< const MemoryTagManager * > GetMemoryTagManager()
If this architecture and process supports memory tagging, return a tag manager that can be used to ma...
lldb::ByteOrder GetByteOrder() const
void SetID(lldb::pid_t new_pid)
Sets the stored pid.
uint32_t GetAddressByteSize() const
ThreadList m_thread_list
The threads for this process as the user will see them.
const lldb::UnixSignalsSP & GetUnixSignals()
const lldb::ABISP & GetABI()
Target & GetTarget()
Get the target object pointer for this module.
const Entry * FindEntryStartsAt(B addr) const
const Entry * FindEntryThatContainsOrFollows(B addr) const
void Append(const Entry &entry)
Entry * FindEntryThatContains(B addr)
llvm::Error ToError() const
bool Fail() const
Test for error condition.
lldb::ModuleSP GetOrCreateModule(const ModuleSpec &module_spec, bool notify, Status *error_ptr=nullptr)
Find a binary on the system and return its Module, or return an existing Module that is already in th...
bool SetArchitecture(const ArchSpec &arch_spec, bool set_platform=false, bool merge=true)
Set the architecture for this target.
lldb::ModuleSP GetExecutableModule()
Gets the module for the main executable.
const ArchSpec & GetArchitecture() const
void SetExecutableModule(lldb::ModuleSP &module_sp, LoadDependentFiles load_dependent_files=eLoadDependentsDefault)
Set the main executable module.
void AddThread(const lldb::ThreadSP &thread_sp)
uint32_t GetSize(bool can_update=true)
static lldb::UnixSignalsSP Create(const ArchSpec &arch)
#define LLDB_INVALID_ADDRESS
@ NT_PROCINFO_CPI_SIGIGNORE_SIZE
@ NT_PROCINFO_CPI_NAME_SIZE
@ NT_PROCINFO_CPI_RUID_SIZE
@ NT_PROCINFO_CPI_SVUID_SIZE
@ NT_PROCINFO_CPI_SIGCODE_SIZE
@ NT_PROCINFO_CPI_SVGID_SIZE
@ NT_PROCINFO_CPI_EUID_SIZE
@ NT_PROCINFO_CPI_PPID_SIZE
@ NT_PROCINFO_CPI_RGID_SIZE
@ NT_PROCINFO_CPI_SIGCATCH_SIZE
@ NT_PROCINFO_CPI_SIGMASK_SIZE
@ NT_PROCINFO_CPI_SID_SIZE
@ NT_PROCINFO_CPI_SIGPEND_SIZE
@ NT_PROCINFO_CPI_EGID_SIZE
@ NT_PROCINFO_CPI_PGRP_SIZE
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
lldb_private::Status Parse(const lldb_private::DataExtractor &data, const lldb_private::ArchSpec &arch)
static size_t GetSize(const lldb_private::ArchSpec &arch)
lldb_private::Status Parse(const lldb_private::DataExtractor &data, const lldb_private::ArchSpec &arch)
lldb_private::Status Parse(const lldb_private::DataExtractor &data, const lldb_private::ArchSpec &arch)
bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
Parse an ELFNote entry from the given DataExtractor starting at position offset.
lldb_private::DataExtractor gpregset
std::vector< lldb_private::CoreNote > notes
bool Contains(BaseType r) const
BaseType GetRangeBase() const
void SetRangeEnd(BaseType end)
SizeType GetByteSize() const
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
BaseType GetRangeEnd() const