Index: include/lldb/API/SBProcess.h =================================================================== --- include/lldb/API/SBProcess.h +++ include/lldb/API/SBProcess.h @@ -341,6 +341,10 @@ bool IsInstrumentationRuntimePresent(InstrumentationRuntimeType type); + // Save the state of the process in a core file (or mini dump on Windows). + lldb::SBError + SaveCore(const char *file_name); + protected: friend class SBAddress; friend class SBBreakpoint; Index: packages/Python/lldbsuite/test/functionalities/process_save_core/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/process_save_core/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules + Index: packages/Python/lldbsuite/test/functionalities/process_save_core/TestProcessSaveCore.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/process_save_core/TestProcessSaveCore.py @@ -0,0 +1,35 @@ +""" +Test saving a core file (or mini dump). +""" + +from __future__ import print_function + +import os, time +import lldb +from lldbsuite.test.lldbtest import * + +class ProcessSaveCoreTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + @not_remote_testsuite_ready + @skipUnlessWindows + def test_windows_mini_dump (self): + """Test that we can save a Windows mini dump.""" + self.build() + exe = os.path.join(os.getcwd(), "a.out") + core = os.path.join(os.getcwd(), "core.dmp") + target = self.dbg.CreateTarget(exe) + breakpoint = target.BreakpointCreateByName("bar") + process = target.LaunchSimple(None, None, self.get_process_working_directory()) + self.assertEqual(process.GetState(), lldb.eStateStopped) + self.assertTrue(process.SaveCore(core)) + self.assertTrue(process.Kill().Success()) + # Clean up the mini dump file. + os.unlink(core) + + Index: packages/Python/lldbsuite/test/functionalities/process_save_core/main.cpp =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/process_save_core/main.cpp @@ -0,0 +1,21 @@ +int global = 42; + +int +bar(int x) +{ + int y = 4*x + global; + return y; +} + +int +foo(int x) +{ + int y = 2*bar(3*x); + return y; +} + +int +main() +{ + return 0 * foo(1); +} Index: scripts/interface/SBProcess.i =================================================================== --- scripts/interface/SBProcess.i +++ scripts/interface/SBProcess.i @@ -398,6 +398,9 @@ bool IsInstrumentationRuntimePresent(lldb::InstrumentationRuntimeType type); + lldb::SBError + SaveCore(const char *file_name); + %pythoncode %{ def __get_is_alive__(self): '''Returns "True" if the process is currently alive, "False" otherwise''' Index: source/API/SBProcess.cpp =================================================================== --- source/API/SBProcess.cpp +++ source/API/SBProcess.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" @@ -1425,3 +1426,13 @@ return runtime_sp->IsActive(); } + +lldb::SBError +SBProcess::SaveCore(const char *file_name) +{ + ProcessSP process_sp(GetSP()); + lldb::SBFileSpec core_file(file_name); + lldb::SBError error; + error.SetError(PluginManager::SaveCore(process_sp, core_file.get())); + return error; +} Index: source/Plugins/ObjectFile/PECOFF/CMakeLists.txt =================================================================== --- source/Plugins/ObjectFile/PECOFF/CMakeLists.txt +++ source/Plugins/ObjectFile/PECOFF/CMakeLists.txt @@ -1,3 +1,4 @@ add_lldb_library(lldbPluginObjectFilePECOFF ObjectFilePECOFF.cpp + ObjectFilePECOFFMiniDump.cpp ) Index: source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h =================================================================== --- source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -95,6 +95,11 @@ 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); bool Index: source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp =================================================================== --- source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "ObjectFilePECOFF.h" +#include "ObjectFilePECOFFMiniDump.h" #include "llvm/Support/COFF.h" @@ -24,6 +25,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Core/UUID.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -42,7 +44,8 @@ GetPluginDescriptionStatic(), CreateInstance, CreateMemoryInstance, - GetModuleSpecifications); + GetModuleSpecifications, + SaveCore); } void @@ -148,6 +151,14 @@ return specs.GetSize() - initial_count; } +bool +ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error) +{ + return SaveMiniDump(process_sp, outfile, error); +} + bool ObjectFilePECOFF::MagicBytesMatch (DataBufferSP& data_sp) Index: source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFFMiniDump.h =================================================================== --- /dev/null +++ source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFFMiniDump.h @@ -0,0 +1,24 @@ +//===-- ObjectFilePECOFFMiniDump.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ObjectFilePECOFFMiniDump_h_ +#define liblldb_ObjectFilePECOFFMiniDump_h_ + +#include "lldb/Target/Process.h" + +namespace lldb_private { + +bool +SaveMiniDump(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error); + +} // namespace lldb_private + +#endif Index: source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFFMiniDump.cpp =================================================================== --- /dev/null +++ source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFFMiniDump.cpp @@ -0,0 +1,55 @@ +//===-- ObjectFilePECOFFMiniDump.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This function is separated out from ObjectFilePECOFF.cpp to name avoid name +// collisions with WinAPI preprocessor macros. + +#include "ObjectFilePECOFFMiniDump.h" +#include "lldb/Host/FileSpec.h" +#include "llvm/Support/ConvertUTF.h" + +#ifdef _WIN32 +#include "lldb/Host/windows/windows.h" +#include // for MiniDumpWriteDump +#endif + +namespace lldb_private { + +bool +SaveMiniDump(const lldb::ProcessSP &process_sp, + const lldb_private::FileSpec &outfile, + lldb_private::Error &error) +{ + if (!process_sp) return false; +#ifdef _WIN32 + HANDLE process_handle = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, process_sp->GetID()); + const std::string file_name = outfile.GetCString(); + std::wstring wide_name; + wide_name.resize(file_name.size() + 1); + char * result_ptr = reinterpret_cast(&wide_name[0]); + const UTF8 *error_ptr = nullptr; + if (!llvm::ConvertUTF8toWide(sizeof(wchar_t), file_name, result_ptr, error_ptr)) { + error.SetErrorString("cannot convert file name"); + return false; + } + HANDLE file_handle = ::CreateFileW(wide_name.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + const auto result = ::MiniDumpWriteDump(process_handle, process_sp->GetID(), file_handle, MiniDumpNormal, NULL, NULL, NULL); + ::CloseHandle(file_handle); + ::CloseHandle(process_handle); + if (!result) + { + error.SetError(::GetLastError(), lldb::eErrorTypeWin32); + return false; + } + return true; +#endif + return false; +} + +} // namesapce lldb_private