[Lldb-commits] [lldb] r210864 - Added the ability to save core files:
Greg Clayton
gclayton at apple.com
Thu Jun 12 17:54:12 PDT 2014
Author: gclayton
Date: Thu Jun 12 19:54:12 2014
New Revision: 210864
URL: http://llvm.org/viewvc/llvm-project?rev=210864&view=rev
Log:
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.
Modified:
lldb/trunk/include/lldb/Core/PluginManager.h
lldb/trunk/include/lldb/lldb-private-interfaces.h
lldb/trunk/source/Commands/CommandObjectProcess.cpp
lldb/trunk/source/Core/PluginManager.cpp
lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp
Modified: lldb/trunk/include/lldb/Core/PluginManager.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/PluginManager.h?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/PluginManager.h (original)
+++ lldb/trunk/include/lldb/Core/PluginManager.h Thu Jun 12 19:54:12 2014
@@ -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
Modified: lldb/trunk/include/lldb/lldb-private-interfaces.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-private-interfaces.h?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-private-interfaces.h (original)
+++ lldb/trunk/include/lldb/lldb-private-interfaces.h Thu Jun 12 19:54:12 2014
@@ -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);
Modified: lldb/trunk/source/Commands/CommandObjectProcess.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectProcess.cpp?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectProcess.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectProcess.cpp Thu Jun 12 19:54:12 2014
@@ -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::CommandOb
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 ()
Modified: lldb/trunk/source/Core/PluginManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/PluginManager.cpp?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/source/Core/PluginManager.cpp (original)
+++ lldb/trunk/source/Core/PluginManager.cpp Thu Jun 12 19:54:12 2014
@@ -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<ObjectFileInstance> ObjectFileInstances;
@@ -1111,7 +1113,8 @@ PluginManager::RegisterPlugin (const Con
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 Con
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::GetObjectFileCreateMemory
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
Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp (original)
+++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp Thu Jun 12 19:54:12 2014
@@ -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; i<n; ++ i)
+ data.PutChar(0);
+ }
+ return reg_byte_size;
+ }
+ }
+ // Just write zeros if all else fails
+ for (size_t i=0; i<reg_byte_size; ++ i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool
+ Create_LC_THREAD (Thread *thread, Stream &data)
+ {
+ RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
+ 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; i<n; ++ i)
+// data.PutChar(0);
+
+ // Write out the EXC registers
+ data.PutHex32 (EXCRegSet);
+ data.PutHex32 (sizeof(EXC)/sizeof(uint64_t));
+ WriteRegister (reg_ctx, "trapno", NULL, 4, data);
+ WriteRegister (reg_ctx, "err", NULL, 4, data);
+ WriteRegister (reg_ctx, "faultvaddr", NULL, 8, data);
+ return true;
+ }
+ return false;
+ }
+
protected:
virtual int
DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
@@ -552,7 +677,8 @@ ObjectFileMachO::Initialize()
GetPluginDescriptionStatic(),
CreateInstance,
CreateMemoryInstance,
- GetModuleSpecifications);
+ GetModuleSpecifications,
+ SaveCore);
}
void
@@ -5025,3 +5151,290 @@ ObjectFileMachO::SetLoadAddress (Target
return changed;
}
+bool
+ObjectFileMachO::SaveCore (const lldb::ProcessSP &process_sp,
+ const FileSpec &outfile,
+ Error &error)
+{
+ if (process_sp)
+ {
+ Target &target = process_sp->GetTarget();
+ 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_command_64> 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<StreamString> 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;
+}
+
Modified: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h (original)
+++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h Thu Jun 12 19:54:12 2014
@@ -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);
Modified: lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp?rev=210864&r1=210863&r2=210864&view=diff
==============================================================================
--- lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp (original)
+++ lldb/trunk/tools/debugserver/source/MacOSX/MachVMMemory.cpp Thu Jun 12 19:54:12 2014
@@ -99,10 +99,11 @@ MachVMMemory::GetMemoryRegionInfo(task_t
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;
More information about the lldb-commits
mailing list