12#include "llvm/Support/MathExtras.h"
13#include "llvm/Support/Threading.h"
54 return "Mach-O core file debugging plug-in.";
62 ListenerSP listener_sp,
65 lldb::ProcessSP process_sp;
66 if (crash_file && !can_connect) {
67 const size_t header_size =
sizeof(llvm::MachO::mach_header);
69 crash_file->
GetPath(), header_size, 0);
70 if (data_sp && data_sp->GetByteSize() == header_size) {
74 llvm::MachO::mach_header mach_header;
76 if (mach_header.filetype == llvm::MachO::MH_CORE)
77 process_sp = std::make_shared<ProcessMachCore>(target_sp, listener_sp,
86 bool plugin_specified_by_name) {
87 if (plugin_specified_by_name)
98 nullptr,
nullptr,
nullptr));
111 ListenerSP listener_sp,
114 m_core_range_infos(), m_core_module_sp(), m_core_file(core_file),
131 Log *log(
GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
132 llvm::MachO::mach_header header;
137 if (header.magic == llvm::MachO::MH_CIGAM ||
138 header.magic == llvm::MachO::MH_CIGAM_64) {
139 header.magic = llvm::byteswap<uint32_t>(header.magic);
140 header.cputype = llvm::byteswap<uint32_t>(header.cputype);
141 header.cpusubtype = llvm::byteswap<uint32_t>(header.cpusubtype);
142 header.filetype = llvm::byteswap<uint32_t>(header.filetype);
143 header.ncmds = llvm::byteswap<uint32_t>(header.ncmds);
144 header.sizeofcmds = llvm::byteswap<uint32_t>(header.sizeofcmds);
145 header.flags = llvm::byteswap<uint32_t>(header.flags);
148 if (header.magic == llvm::MachO::MH_MAGIC ||
149 header.magic == llvm::MachO::MH_MAGIC_64) {
154 switch (header.filetype) {
155 case llvm::MachO::MH_DYLINKER:
157 "ProcessMachCore::%s found a user "
158 "process dyld binary image at 0x%" PRIx64,
163 case llvm::MachO::MH_EXECUTE:
166 if ((header.flags & llvm::MachO::MH_DYLDLINK) == 0) {
168 "ProcessMachCore::%s found a mach "
169 "kernel binary image at 0x%" PRIx64,
186 bool ranges_are_sorted =
true;
188 for (
uint32_t i = 0; i < num_sections; ++i) {
194 section_vm_addr, section->
GetByteSize(), file_range);
196 if (vm_addr > section_vm_addr)
197 ranges_are_sorted =
false;
203 last_entry->
data.GetRangeEnd() == range_entry.
data.GetRangeBase()) {
205 last_entry->
data.SetRangeEnd(range_entry.
data.GetRangeEnd());
214 if (permissions == 0)
215 permissions = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;
217 section_vm_addr, section->
GetByteSize(), permissions));
220 if (!ranges_are_sorted) {
227 Log *log(
GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
229 bool found_main_binary_definitively =
false;
231 addr_t objfile_binary_value;
232 bool objfile_binary_value_is_offset;
233 UUID objfile_binary_uuid;
237 objfile_binary_value_is_offset,
238 objfile_binary_uuid, type)) {
240 log->
Printf(
"ProcessMachCore::LoadBinariesViaMetadata: using binary hint "
241 "from 'main bin spec' "
242 "LC_NOTE with UUID %s value 0x%" PRIx64
243 " value is offset %d and type %d",
245 objfile_binary_value, objfile_binary_value_is_offset, type);
254 found_main_binary_definitively =
true;
259 const bool force_symbol_search =
true;
260 const bool notify =
true;
261 const bool set_address_in_target =
true;
263 this, llvm::StringRef(), objfile_binary_uuid,
264 objfile_binary_value, objfile_binary_value_is_offset,
265 force_symbol_search, notify, set_address_in_target)) {
266 found_main_binary_definitively =
true;
277 if (!found_main_binary_definitively) {
281 if (corefile_identifier.find(
"UUID=") != std::string::npos) {
282 size_t p = corefile_identifier.find(
"UUID=") + strlen(
"UUID=");
283 std::string uuid_str = corefile_identifier.substr(p, 36);
286 log->
Printf(
"Got a UUID from LC_IDENT/kern ver str LC_NOTE: %s",
289 if (corefile_identifier.find(
"stext=") != std::string::npos) {
290 size_t p = corefile_identifier.find(
"stext=") + strlen(
"stext=");
291 if (corefile_identifier[p] ==
'0' && corefile_identifier[p + 1] ==
'x') {
293 ::strtoul(corefile_identifier.c_str() + p,
nullptr, 16);
295 log->
Printf(
"Got a load address from LC_IDENT/kern ver str "
296 "LC_NOTE: 0x%" PRIx64,
303 if (corefile_identifier.find(
"Darwin Kernel") != std::string::npos &&
307 "ProcessMachCore::LoadBinariesViaMetadata: Found kernel binary via "
308 "LC_IDENT/kern ver str LC_NOTE");
310 found_main_binary_definitively =
true;
311 }
else if (ident_uuid.
IsValid()) {
314 const bool value_is_offset =
false;
315 const bool force_symbol_search =
true;
316 const bool notify =
true;
317 const bool set_address_in_target =
true;
319 this, llvm::StringRef(), ident_uuid, ident_binary_addr,
320 value_is_offset, force_symbol_search, notify,
321 set_address_in_target)) {
322 found_main_binary_definitively =
true;
331 found_main_binary_definitively =
true;
344 Log *log(
GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
350 std::vector<addr_t> dylds_found;
351 std::vector<addr_t> kernels_found;
354 for (
size_t i = 0; i < num_core_aranges; ++i) {
358 for (
lldb::addr_t section_vm_addr = section_vm_addr_start;
359 section_vm_addr < section_vm_addr_end; section_vm_addr += 0x1000) {
363 dylds_found.push_back(dyld);
365 kernels_found.push_back(kernel);
372 if (dylds_found.size() > 0)
374 if (kernels_found.size() > 0)
378 if (kernels_found.size() < 2)
398 addr_t better_kernel_address =
406 "ProcessMachCore::%s: Using "
407 "the kernel address "
408 "from DynamicLoaderDarwinKernel",
415 Log *log(
GetLog(LLDBLog::DynamicLoader | LLDBLog::Process));
427 "ProcessMachCore::%s: Using kernel "
434 "ProcessMachCore::%s: Using user process dyld "
435 "image at 0x%" PRIx64,
442 "ProcessMachCore::%s: Using user process dyld "
443 "image at 0x%" PRIx64,
448 "ProcessMachCore::%s: Using kernel "
469 for (
size_t i = 0; i < core_range_infos_size; i++) {
472 ent->
data = lldb::ePermissionsReadable | lldb::ePermissionsExecutable;
481 error.SetErrorString(
"invalid core module");
486 if (core_objfile ==
nullptr) {
487 error.SetErrorString(
"invalid core object file");
505 if (address_mask != 0) {
520 if (old_thread_list.
GetSize(
false) == 0) {
527 for (
lldb::tid_t tid = 0; tid < num_threads; ++tid) {
534 for (
uint32_t i = 0; i < num_threads; ++i)
537 return new_thread_list.
GetSize(
false) > 0;
566 size_t bytes_read = 0;
585 while (bytes_read < size) {
586 const addr_t curr_addr = addr + bytes_read;
590 if (core_memory_entry) {
593 const size_t bytes_to_read =
594 std::min(size - bytes_read, (
size_t)bytes_left);
595 const size_t curr_bytes_read = core_objfile->
CopyData(
596 core_memory_entry->
data.GetRangeBase() + offset, bytes_to_read,
597 (
char *)buf + bytes_read);
598 if (curr_bytes_read == 0)
600 bytes_read += curr_bytes_read;
604 error.SetErrorStringWithFormat(
605 "core file does not contain 0x%" PRIx64, curr_addr);
619 if (permission_entry) {
620 if (permission_entry->
Contains(load_addr)) {
623 const Flags permissions(permission_entry->
data);
634 }
else if (load_addr < permission_entry->GetRangeBase()) {
657 static llvm::once_flag g_once_flag;
659 llvm::call_once(g_once_flag, []() {
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
#define LLDB_PLUGIN_DEFINE(PluginName)
static llvm::StringRef GetPluginNameStatic()
static lldb::addr_t SearchForDarwinKernel(lldb_private::Process *process)
static llvm::StringRef GetPluginNameStatic()
static llvm::StringRef GetPluginNameStatic()
bool ParseHeader() override
Attempts to parse the object header.
bool WarnBeforeDetach() const override
Before lldb detaches from a process, it warns the user that they are about to lose their debug sessio...
static llvm::StringRef GetPluginDescriptionStatic()
size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Status &error) override
Read of memory from a process.
VMRangeToFileOffset m_core_aranges
friend class ThreadMachCore
void LoadBinariesViaMetadata()
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.
CorefilePreference GetCorefilePreference()
If a core file can be interpreted multiple ways, this establishes which style wins.
bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override
Check if a plug-in instance can debug the file in module.
void CleanupMemoryRegionPermissions()
lldb_private::ObjectFile * GetCoreObjectFile()
ProcessMachCore(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec &core_file)
llvm::StringRef m_dyld_plugin_name
lldb_private::DynamicLoader * GetDynamicLoader() override
Get the dynamic loader plug-in for this process.
lldb_private::Status DoDestroy() override
static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, const lldb_private::FileSpec *crash_file_path, bool can_connect)
void RefreshStateAfterStop() override
Currently called as part of ShouldStop.
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.
static llvm::StringRef GetPluginNameStatic()
bool IsAlive() override
Check if a process is still alive.
void CreateMemoryRegions()
bool CheckAddressForDyldOrKernel(lldb::addr_t addr, lldb::addr_t &dyld, lldb::addr_t &kernel)
VMRangeToPermissions m_core_range_infos
lldb_private::Status DoLoadCore() override
void LoadBinariesViaExhaustiveSearch()
lldb_private::FileSpec m_core_file
void LoadBinariesAndSetDYLD()
lldb::addr_t m_mach_kernel_addr
lldb::addr_t GetImageInfoAddress() override
Get the image information address for the current process.
~ProcessMachCore() override
lldb::ModuleSP m_core_module_sp
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...
An architecture specification class.
bool IsValid() const
Tests if this ArchSpec is valid.
A plug-in interface definition class for dynamic loaders.
static lldb::ModuleSP LoadBinaryWithUUIDAndAddress(Process *process, llvm::StringRef name, UUID uuid, lldb::addr_t value, bool value_is_offset, bool force_symbol_search, bool notify, bool set_address_in_target)
Find/load a binary into lldb given a UUID and the address where it is loaded in memory,...
static DynamicLoader * FindPlugin(Process *process, llvm::StringRef plugin_name)
Find a dynamic loader plugin for a given process.
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 Printf(const char *format,...) __attribute__((format(printf
Prefer using LLDB_LOGF whenever possible.
void SetMapped(OptionalBool val)
void SetReadable(OptionalBool val)
void SetExecutable(OptionalBool val)
void SetWritable(OptionalBool val)
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)
A plug-in interface definition class for object file parsers.
virtual std::string GetIdentifierString()
Some object files may have an identifier string embedded in them, e.g.
virtual uint32_t GetNumThreadContexts()
virtual bool LoadCoreFileImages(lldb_private::Process &process)
Load binaries listed in a corefile.
@ 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
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
virtual lldb::addr_t GetAddressMask()
Some object files may have the number of bits used for addressing embedded in them,...
virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &value, bool &value_is_offset, UUID &uuid, ObjectFile::BinaryType &type)
When the ObjectFile is a core file, lldb needs to locate the "binary" in the core file.
BinaryType
If we have a corefile binary hint, this enum specifies the binary type which we can use to select the...
@ eBinaryTypeUser
kernel binary
virtual llvm::StringRef GetPluginName()=0
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...
virtual void Finalize()
This object is about to be destroyed, do any necessary cleanup.
void SetCodeAddressMask(lldb::addr_t code_address_mask)
void SetCanJIT(bool can_jit)
Sets whether executing JIT-compiled code in this process is possible.
lldb::DynamicLoaderUP m_dyld_up
void SetDataAddressMask(lldb::addr_t data_address_mask)
ThreadList m_thread_list
The threads for this process as the user will see them.
Target & GetTarget()
Get the target object pointer for this module.
const Entry * GetEntryAtIndex(size_t i) const
Entry * GetMutableEntryAtIndex(size_t i)
const Entry * FindEntryThatContainsOrFollows(B addr) const
void Append(const Entry &entry)
Entry * FindEntryThatContains(B addr)
size_t GetNumSections(uint32_t depth) const
lldb::SectionSP GetSectionAtIndex(size_t idx) const
uint32_t GetPermissions() const
Get the permissions as OR'ed bits from lldb::Permissions.
lldb::offset_t GetFileOffset() const
lldb::addr_t GetFileAddress() const
lldb::addr_t GetByteSize() const
lldb::offset_t GetFileSize() const
bool SetArchitecture(const ArchSpec &arch_spec, bool set_platform=false, bool merge=true)
Set the architecture for this target.
void AddThread(const lldb::ThreadSP &thread_sp)
uint32_t GetSize(bool can_update=true)
lldb::ThreadSP GetThreadAtIndex(uint32_t idx, bool can_update=true)
void RefreshStateAfterStop()
bool SetFromStringRef(llvm::StringRef str)
std::string GetAsString(llvm::StringRef separator="-") const
#define LLDB_INVALID_ADDRESS
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.
bool Contains(BaseType r) const
BaseType GetRangeBase() const
void SetRangeEnd(BaseType end)
void SetRangeBase(BaseType b)
Set the start value for the range, and keep the same size.
BaseType GetRangeEnd() const