[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