From a2715cf108d1fc433ffd76102998dbc470720103 Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Fri, 13 Jun 2014 00:54:12 +0000 Subject: [PATCH] Added the ability to save core files: (lldb) file /bin/ls (lldb) b malloc (lldb) run (lldb) process save-core /tmp/ls.core Each ObjectFile plug-in now has the option to save core files by registering a new static callback. llvm-svn: 210864 --- lldb/include/lldb/Core/PluginManager.h | 5 +- lldb/include/lldb/lldb-private-interfaces.h | 1 + lldb/source/Commands/CommandObjectProcess.cpp | 67 ++++ lldb/source/Core/PluginManager.cpp | 25 +- .../Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp | 415 ++++++++++++++++++++- .../Plugins/ObjectFile/Mach-O/ObjectFileMachO.h | 5 + .../debugserver/source/MacOSX/MachVMMemory.cpp | 7 +- 7 files changed, 517 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h index 4db423d..a2ac67b 100644 --- a/lldb/include/lldb/Core/PluginManager.h +++ b/lldb/include/lldb/Core/PluginManager.h @@ -175,7 +175,8 @@ public: const char *description, ObjectFileCreateInstance create_callback, ObjectFileCreateMemoryInstance create_memory_callback, - ObjectFileGetModuleSpecifications get_module_specifications); + ObjectFileGetModuleSpecifications get_module_specifications, + ObjectFileSaveCore save_core = NULL); static bool UnregisterPlugin (ObjectFileCreateInstance create_callback); @@ -195,6 +196,8 @@ public: static ObjectFileCreateMemoryInstance GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name); + static Error + SaveCore (const lldb::ProcessSP &process_sp, const FileSpec &outfile); //------------------------------------------------------------------ // ObjectContainer diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h index 2f05d77..e6c89ab 100644 --- a/lldb/include/lldb/lldb-private-interfaces.h +++ b/lldb/include/lldb/lldb-private-interfaces.h @@ -24,6 +24,7 @@ namespace lldb_private typedef size_t (*ObjectFileGetModuleSpecifications) (const FileSpec &file, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &module_specs); typedef ObjectFile* (*ObjectFileCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec* file, lldb::offset_t file_offset, lldb::offset_t length); typedef ObjectFile* (*ObjectFileCreateMemoryInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset); + typedef bool (*ObjectFileSaveCore) (const lldb::ProcessSP &process_sp, const FileSpec &outfile, Error &error); typedef LogChannel* (*LogChannelCreateInstance) (); typedef EmulateInstruction * (*EmulateInstructionCreateInstance) (const ArchSpec &arch, InstructionType inst_type); typedef OperatingSystem* (*OperatingSystemCreateInstance) (Process *process, bool force); diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index 27c1109..92735ec 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -20,6 +20,7 @@ #include "lldb/Breakpoint/BreakpointSite.h" #include "lldb/Core/State.h" #include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/Options.h" @@ -1483,6 +1484,71 @@ protected: }; //------------------------------------------------------------------------- +// CommandObjectProcessSaveCore +//------------------------------------------------------------------------- +#pragma mark CommandObjectProcessSaveCore + +class CommandObjectProcessSaveCore : public CommandObjectParsed +{ +public: + + CommandObjectProcessSaveCore (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "process save-core", + "Save the current process as a core file using an appropriate file type.", + "process save-core FILE", + eFlagRequiresProcess | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched) + { + } + + ~CommandObjectProcessSaveCore () + { + } + +protected: + bool + DoExecute (Args& command, + CommandReturnObject &result) + { + ProcessSP process_sp = m_exe_ctx.GetProcessSP(); + if (process_sp) + { + if (command.GetArgumentCount() == 1) + { + FileSpec output_file(command.GetArgumentAtIndex(0), false); + Error error = PluginManager::SaveCore(process_sp, output_file); + if (error.Success()) + { + result.SetStatus (eReturnStatusSuccessFinishResult); + } + else + { + result.AppendErrorWithFormat ("Failed to save core file for process: %s\n", error.AsCString()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendErrorWithFormat ("'%s' takes one arguments:\nUsage: %s\n", + m_cmd_name.c_str(), + m_cmd_syntax.c_str()); + result.SetStatus (eReturnStatusFailed); + } + } + else + { + result.AppendError ("invalid process"); + result.SetStatus (eReturnStatusFailed); + return false; + } + + return result.Succeeded(); + } +}; + +//------------------------------------------------------------------------- // CommandObjectProcessStatus //------------------------------------------------------------------------- #pragma mark CommandObjectProcessStatus @@ -1853,6 +1919,7 @@ CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter LoadSubCommand ("interrupt", CommandObjectSP (new CommandObjectProcessInterrupt (interpreter))); LoadSubCommand ("kill", CommandObjectSP (new CommandObjectProcessKill (interpreter))); LoadSubCommand ("plugin", CommandObjectSP (new CommandObjectProcessPlugin (interpreter))); + LoadSubCommand ("save-core", CommandObjectSP (new CommandObjectProcessSaveCore (interpreter))); } CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess () diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp index b4ee07a..dbf7139 100644 --- a/lldb/source/Core/PluginManager.cpp +++ b/lldb/source/Core/PluginManager.cpp @@ -1078,7 +1078,8 @@ struct ObjectFileInstance description(), create_callback(NULL), create_memory_callback (NULL), - get_module_specifications (NULL) + get_module_specifications (NULL), + save_core (NULL) { } @@ -1087,6 +1088,7 @@ struct ObjectFileInstance ObjectFileCreateInstance create_callback; ObjectFileCreateMemoryInstance create_memory_callback; ObjectFileGetModuleSpecifications get_module_specifications; + ObjectFileSaveCore save_core; }; typedef std::vector ObjectFileInstances; @@ -1111,7 +1113,8 @@ PluginManager::RegisterPlugin (const ConstString &name, const char *description, ObjectFileCreateInstance create_callback, ObjectFileCreateMemoryInstance create_memory_callback, - ObjectFileGetModuleSpecifications get_module_specifications) + ObjectFileGetModuleSpecifications get_module_specifications, + ObjectFileSaveCore save_core) { if (create_callback) { @@ -1122,6 +1125,7 @@ PluginManager::RegisterPlugin (const ConstString &name, instance.description = description; instance.create_callback = create_callback; instance.create_memory_callback = create_memory_callback; + instance.save_core = save_core; instance.get_module_specifications = get_module_specifications; Mutex::Locker locker (GetObjectFileMutex ()); GetObjectFileInstances ().push_back (instance); @@ -1218,7 +1222,22 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString return NULL; } - +Error +PluginManager::SaveCore (const lldb::ProcessSP &process_sp, const FileSpec &outfile) +{ + Error error; + Mutex::Locker locker (GetObjectFileMutex ()); + ObjectFileInstances &instances = GetObjectFileInstances (); + + ObjectFileInstances::iterator pos, end = instances.end(); + for (pos = instances.begin(); pos != end; ++ pos) + { + if (pos->save_core && pos->save_core (process_sp, outfile, error)) + return error; + } + error.SetErrorString("no ObjectFile plugins were able to save a core for this process"); + return error; +} #pragma mark ObjectContainer diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index dc31eba..b858711 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/Error.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" @@ -33,6 +34,8 @@ #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadList.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" @@ -124,6 +127,128 @@ public: } } } + + + static size_t + WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data) + { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); + if (reg_info == NULL) + reg_info = reg_ctx->GetRegisterInfoByName(alt_name); + if (reg_info) + { + lldb_private::RegisterValue reg_value; + if (reg_ctx->ReadRegister(reg_info, reg_value)) + { + if (reg_info->byte_size >= reg_byte_size) + data.Write(reg_value.GetBytes(), reg_byte_size); + else + { + data.Write(reg_value.GetBytes(), reg_info->byte_size); + for (size_t i=0, n = reg_byte_size - reg_info->byte_size; iGetRegisterContext()); + if (reg_ctx_sp) + { + RegisterContext *reg_ctx = reg_ctx_sp.get(); + + data.PutHex32 (GPRRegSet); // Flavor + data.PutHex32 (sizeof(GPR)/sizeof(uint64_t)); // Number of uint64_t values that follow + WriteRegister (reg_ctx, "rax", NULL, 8, data); + WriteRegister (reg_ctx, "rbx", NULL, 8, data); + WriteRegister (reg_ctx, "rcx", NULL, 8, data); + WriteRegister (reg_ctx, "rdx", NULL, 8, data); + WriteRegister (reg_ctx, "rdi", NULL, 8, data); + WriteRegister (reg_ctx, "rsi", NULL, 8, data); + WriteRegister (reg_ctx, "rbp", NULL, 8, data); + WriteRegister (reg_ctx, "rsp", NULL, 8, data); + WriteRegister (reg_ctx, "r8", NULL, 8, data); + WriteRegister (reg_ctx, "r9", NULL, 8, data); + WriteRegister (reg_ctx, "r10", NULL, 8, data); + WriteRegister (reg_ctx, "r11", NULL, 8, data); + WriteRegister (reg_ctx, "r12", NULL, 8, data); + WriteRegister (reg_ctx, "r13", NULL, 8, data); + WriteRegister (reg_ctx, "r14", NULL, 8, data); + WriteRegister (reg_ctx, "r15", NULL, 8, data); + WriteRegister (reg_ctx, "rip", NULL, 8, data); + WriteRegister (reg_ctx, "rflags", NULL, 8, data); + WriteRegister (reg_ctx, "cs", NULL, 8, data); + WriteRegister (reg_ctx, "fs", NULL, 8, data); + WriteRegister (reg_ctx, "gs", NULL, 8, data); + +// // Write out the FPU registers +// const size_t fpu_byte_size = sizeof(FPU); +// size_t bytes_written = 0; +// data.PutHex32 (FPURegSet); +// data.PutHex32 (fpu_byte_size/sizeof(uint64_t)); +// bytes_written += data.PutHex32(0); // uint32_t pad[0] +// bytes_written += data.PutHex32(0); // uint32_t pad[1] +// bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, data); // uint16_t fcw; // "fctrl" +// bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, data); // uint16_t fsw; // "fstat" +// bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, data); // uint8_t ftw; // "ftag" +// bytes_written += data.PutHex8 (0); // uint8_t pad1; +// bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, data); // uint16_t fop; // "fop" +// bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, data); // uint32_t ip; // "fioff" +// bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, data); // uint16_t cs; // "fiseg" +// bytes_written += data.PutHex16 (0); // uint16_t pad2; +// bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, data); // uint32_t dp; // "fooff" +// bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, data); // uint16_t ds; // "foseg" +// bytes_written += data.PutHex16 (0); // uint16_t pad3; +// bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, data); // uint32_t mxcsr; +// bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, 4, data);// uint32_t mxcsrmask; +// bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, sizeof(MMSReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, sizeof(XMMReg), data); +// bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, sizeof(XMMReg), data); +// +// // Fill rest with zeros +// for (size_t i=0, n = fpu_byte_size - bytes_written; iGetTarget(); + const ArchSpec target_arch = target.GetArchitecture(); + const llvm::Triple &target_triple = target_arch.GetTriple(); + if (target_triple.getVendor() == llvm::Triple::Apple && + (target_triple.getOS() == llvm::Triple::MacOSX || + target_triple.getOS() == llvm::Triple::IOS)) + { + bool make_core = false; + switch (target_arch.GetMachine()) + { + case llvm::Triple::arm: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + make_core = true; + break; + default: + error.SetErrorStringWithFormat ("unsupported core architecture: %s", target_triple.str().c_str()); + break; + } + + if (make_core) + { + std::vector segment_load_commands; + uint32_t range_info_idx = 0; + MemoryRegionInfo range_info; + Error range_error = process_sp->GetMemoryRegionInfo(0, range_info); + if (range_error.Success()) + { + while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) + { + const addr_t addr = range_info.GetRange().GetRangeBase(); + const addr_t size = range_info.GetRange().GetByteSize(); + + if (size == 0) + break; + + // Calculate correct protections + uint32_t prot = 0; + if (range_info.GetReadable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_READ; + if (range_info.GetWritable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_WRITE; + if (range_info.GetExecutable() == MemoryRegionInfo::eYes) + prot |= VM_PROT_EXECUTE; + +// printf ("[%3u] [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") %c%c%c\n", +// range_info_idx, +// addr, +// size, +// (prot & VM_PROT_READ ) ? 'r' : '-', +// (prot & VM_PROT_WRITE ) ? 'w' : '-', +// (prot & VM_PROT_EXECUTE) ? 'x' : '-'); + + if (prot != 0) + { + segment_command_64 segment = { + LC_SEGMENT_64, // uint32_t cmd; + sizeof(segment), // uint32_t cmdsize; + {0}, // char segname[16]; + addr, // uint64_t vmaddr; + size, // uint64_t vmsize; + 0, // uint64_t fileoff; + size, // uint64_t filesize; + prot, // uint32_t maxprot; + prot, // uint32_t initprot; + 0, // uint32_t nsects; + 0 }; // uint32_t flags; + segment_load_commands.push_back(segment); + } + else + { + // No protections and a size of 1 used to be returned from old + // debugservers when we asked about a region that was past the + // last memory region and it indicates the end... + if (size == 1) + break; + } + + range_error = process_sp->GetMemoryRegionInfo(range_info.GetRange().GetRangeEnd(), range_info); + if (range_error.Fail()) + break; + } + + const uint32_t addr_byte_size = target_arch.GetAddressByteSize(); + const ByteOrder byte_order = target_arch.GetByteOrder(); + StreamString buffer (Stream::eBinary, + addr_byte_size, + byte_order); + + mach_header_64 mach_header; + mach_header.magic = MH_MAGIC_64; + mach_header.cputype = target_arch.GetMachOCPUType(); + mach_header.cpusubtype = target_arch.GetMachOCPUSubType(); + mach_header.filetype = MH_CORE; + mach_header.ncmds = segment_load_commands.size(); + mach_header.flags = 0; + mach_header.reserved = 0; + ThreadList &thread_list = process_sp->GetThreadList(); + const uint32_t num_threads = thread_list.GetSize(); + + // Make an array of LC_THREAD data items. Each one contains + // the contents of the LC_THREAD load command. The data doesn't + // contain the load command + load command size, we will + // add the load command and load command size as we emit the data. + std::vector LC_THREAD_datas(num_threads); + for (auto &LC_THREAD_data : LC_THREAD_datas) + { + LC_THREAD_data.GetFlags().Set(Stream::eBinary); + LC_THREAD_data.SetAddressByteSize(addr_byte_size); + LC_THREAD_data.SetByteOrder(byte_order); + } + for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) + { + ThreadSP thread_sp (thread_list.GetThreadAtIndex(thread_idx)); + if (thread_sp) + { + switch (mach_header.cputype) + { + case llvm::MachO::CPU_TYPE_ARM: + //RegisterContextDarwin_arm_Mach::Create_LC_THREAD (thread_sp.get(), thread_load_commands); + break; + + case llvm::MachO::CPU_TYPE_I386: + //RegisterContextDarwin_i386_Mach::Create_LC_THREAD (thread_sp.get(), thread_load_commands); + break; + + case llvm::MachO::CPU_TYPE_X86_64: + RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]); + break; + } + + } + } + + // The size of the load command is the size of the segments... + mach_header.sizeofcmds = segment_load_commands.size() * segment_load_commands[0].cmdsize; + + // and the size of all LC_THREAD load command + for (const auto &LC_THREAD_data : LC_THREAD_datas) + { + mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize(); + } + + printf ("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n", + mach_header.magic, + mach_header.cputype, + mach_header.cpusubtype, + mach_header.filetype, + mach_header.ncmds, + mach_header.sizeofcmds, + mach_header.flags, + mach_header.reserved); + + // Write the mach header + buffer.PutHex32(mach_header.magic); + buffer.PutHex32(mach_header.cputype); + buffer.PutHex32(mach_header.cpusubtype); + buffer.PutHex32(mach_header.filetype); + buffer.PutHex32(mach_header.ncmds); + buffer.PutHex32(mach_header.sizeofcmds); + buffer.PutHex32(mach_header.flags); + buffer.PutHex32(mach_header.reserved); + + // Skip the mach header and all load commands and align to the next + // 0x1000 byte boundary + addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds; + if (file_offset & 0x00000fff) + { + file_offset += 0x00001000ull; + file_offset &= (~0x00001000ull + 1); + } + + for (auto &segment : segment_load_commands) + { + segment.fileoff = file_offset; + file_offset += segment.filesize; + } + + // Write out all of the LC_THREAD load commands + for (const auto &LC_THREAD_data : LC_THREAD_datas) + { + const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize(); + buffer.PutHex32(LC_THREAD); + buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data + buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size); + } + + // Write out all of the segment load commands + for (const auto &segment : segment_load_commands) + { + printf ("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n", + segment.cmd, + segment.cmdsize, + segment.vmaddr, + segment.vmaddr + segment.vmsize, + segment.fileoff, + segment.filesize, + segment.maxprot, + segment.initprot, + segment.nsects, + segment.flags); + + buffer.PutHex32(segment.cmd); + buffer.PutHex32(segment.cmdsize); + buffer.PutRawBytes(segment.segname, sizeof(segment.segname)); + buffer.PutHex64(segment.vmaddr); + buffer.PutHex64(segment.vmsize); + buffer.PutHex64(segment.fileoff); + buffer.PutHex64(segment.filesize); + buffer.PutHex32(segment.maxprot); + buffer.PutHex32(segment.initprot); + buffer.PutHex32(segment.nsects); + buffer.PutHex32(segment.flags); + } + + File core_file; + std::string core_file_path(outfile.GetPath()); + error = core_file.Open(core_file_path.c_str(), + File::eOpenOptionWrite | + File::eOpenOptionTruncate | + File::eOpenOptionCanCreate); + if (error.Success()) + { + // Read 1 page at a time + uint8_t bytes[0x1000]; + // Write the mach header and load commands out to the core file + size_t bytes_written = buffer.GetString().size(); + error = core_file.Write(buffer.GetString().data(), bytes_written); + if (error.Success()) + { + // Now write the file data for all memory segments in the process + for (const auto &segment : segment_load_commands) + { + if (segment.fileoff != core_file.SeekFromStart(segment.fileoff)) + { + error.SetErrorStringWithFormat("unable to seek to offset 0x%" PRIx64 " in '%s'", segment.fileoff, core_file_path.c_str()); + break; + } + + printf ("Saving data for segment at 0x%llx\n", segment.vmaddr); + addr_t bytes_left = segment.vmsize; + addr_t addr = segment.vmaddr; + Error memory_read_error; + while (bytes_left > 0 && error.Success()) + { + const size_t bytes_to_read = bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left; + const size_t bytes_read = process_sp->ReadMemory(addr, bytes, bytes_to_read, memory_read_error); + if (bytes_read == bytes_to_read) + { + size_t bytes_written = bytes_read; + error = core_file.Write(bytes, bytes_written); + bytes_left -= bytes_read; + addr += bytes_read; + } + else + { + // Some pages within regions are not readable, those + // should be zero filled + memset (bytes, 0, bytes_to_read); + size_t bytes_written = bytes_to_read; + error = core_file.Write(bytes, bytes_written); + bytes_left -= bytes_to_read; + addr += bytes_to_read; + } + } + } + } + } + } + else + { + error.SetErrorString("process doesn't support getting memory region info"); + } + } + return true; // This is the right plug to handle saving core files for this process + } + } + return false; +} + diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 7b09e5f..64a4c05 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -65,6 +65,11 @@ public: lldb_private::ModuleSpecList &specs); static bool + SaveCore (const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error); + + static bool MagicBytesMatch (lldb::DataBufferSP& data_sp, lldb::addr_t offset, lldb::addr_t length); diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp index fc4108d..857955b 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp @@ -99,10 +99,11 @@ MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo if (address < start_addr) region_info->size = start_addr - address; } - // If we can't get any infor about the size from the next region, just fill - // 1 in as the byte size + // If we can't get any info about the size from the next region it means + // we asked about an address that was past all mappings, so the size + // of this region will take up all remaining address space. if (region_info->size == 0) - region_info->size = 1; + region_info->size = INVALID_NUB_ADDRESS - region_info->addr; // Not readable, writeable or executable region_info->permissions = 0; -- 2.7.4