diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 |
commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp | |
parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
download | src-14f1b3e8826ce43b978db93a62d1166055db5394.tar.gz src-14f1b3e8826ce43b978db93a62d1166055db5394.zip |
Vendor import of lldb trunk r290819:vendor/lldb/lldb-trunk-r290819
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=311128
svn path=/vendor/lldb/lldb-trunk-r290819/; revision=311129; tag=vendor/lldb/lldb-trunk-r290819
Diffstat (limited to 'source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp')
-rw-r--r-- | source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp | 1834 |
1 files changed, 834 insertions, 1000 deletions
diff --git a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 898677df616b..dae33f6257d1 100644 --- a/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -16,9 +16,9 @@ // Other libraries and framework includes #include "lldb/Core/Debugger.h" -#include "lldb/Core/PluginManager.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/UUID.h" #include "lldb/Host/ConnectionFileDescriptor.h" @@ -42,1168 +42,1002 @@ #define USEC_PER_SEC 1000000 // Project includes +#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "ProcessKDP.h" #include "ProcessKDPLog.h" #include "ThreadKDP.h" -#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" -#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" using namespace lldb; using namespace lldb_private; namespace { - static PropertyDefinition - g_properties[] = - { - { "packet-timeout" , OptionValue::eTypeUInt64 , true , 5, NULL, NULL, "Specify the default packet timeout in seconds." }, - { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL } - }; - - enum - { - ePropertyPacketTimeout - }; - - class PluginProperties : public Properties - { - public: - - static ConstString - GetSettingName () - { - return ProcessKDP::GetPluginNameStatic(); - } +static PropertyDefinition g_properties[] = { + {"packet-timeout", OptionValue::eTypeUInt64, true, 5, NULL, NULL, + "Specify the default packet timeout in seconds."}, + {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL}}; - PluginProperties() : - Properties () - { - m_collection_sp.reset (new OptionValueProperties(GetSettingName())); - m_collection_sp->Initialize(g_properties); - } - - virtual - ~PluginProperties() - { - } - - uint64_t - GetPacketTimeout() - { - const uint32_t idx = ePropertyPacketTimeout; - return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); - } - }; +enum { ePropertyPacketTimeout }; - typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; +class PluginProperties : public Properties { +public: + static ConstString GetSettingName() { + return ProcessKDP::GetPluginNameStatic(); + } + + PluginProperties() : Properties() { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); + } + + virtual ~PluginProperties() {} + + uint64_t GetPacketTimeout() { + const uint32_t idx = ePropertyPacketTimeout; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + NULL, idx, g_properties[idx].default_uint_value); + } +}; + +typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP; + +static const ProcessKDPPropertiesSP &GetGlobalPluginProperties() { + static ProcessKDPPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp.reset(new PluginProperties()); + return g_settings_sp; +} - static const ProcessKDPPropertiesSP & - GetGlobalPluginProperties() - { - static ProcessKDPPropertiesSP g_settings_sp; - if (!g_settings_sp) - g_settings_sp.reset (new PluginProperties ()); - return g_settings_sp; - } - } // anonymous namespace end static const lldb::tid_t g_kernel_tid = 1; -ConstString -ProcessKDP::GetPluginNameStatic() -{ - static ConstString g_name("kdp-remote"); - return g_name; +ConstString ProcessKDP::GetPluginNameStatic() { + static ConstString g_name("kdp-remote"); + return g_name; } -const char * -ProcessKDP::GetPluginDescriptionStatic() -{ - return "KDP Remote protocol based debugging plug-in for darwin kernel debugging."; +const char *ProcessKDP::GetPluginDescriptionStatic() { + return "KDP Remote protocol based debugging plug-in for darwin kernel " + "debugging."; } -void -ProcessKDP::Terminate() -{ - PluginManager::UnregisterPlugin (ProcessKDP::CreateInstance); +void ProcessKDP::Terminate() { + PluginManager::UnregisterPlugin(ProcessKDP::CreateInstance); } - -lldb::ProcessSP -ProcessKDP::CreateInstance (TargetSP target_sp, - ListenerSP listener_sp, - const FileSpec *crash_file_path) -{ - lldb::ProcessSP process_sp; - if (crash_file_path == NULL) - process_sp.reset(new ProcessKDP (target_sp, listener_sp)); - return process_sp; +lldb::ProcessSP ProcessKDP::CreateInstance(TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path) { + lldb::ProcessSP process_sp; + if (crash_file_path == NULL) + process_sp.reset(new ProcessKDP(target_sp, listener_sp)); + return process_sp; } -bool -ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) -{ - if (plugin_specified_by_name) - return true; - - // For now we are just making sure the file exists for a given module - Module *exe_module = target_sp->GetExecutableModulePointer(); - if (exe_module) - { - const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple(); - switch (triple_ref.getOS()) - { - case llvm::Triple::Darwin: // Should use "macosx" for desktop and "ios" for iOS, but accept darwin just in case - case llvm::Triple::MacOSX: // For desktop targets - case llvm::Triple::IOS: // For arm targets - case llvm::Triple::TvOS: - case llvm::Triple::WatchOS: - if (triple_ref.getVendor() == llvm::Triple::Apple) - { - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && - exe_objfile->GetStrata() == ObjectFile::eStrataKernel) - return true; - } - break; - - default: - break; - } +bool ProcessKDP::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) { + if (plugin_specified_by_name) + return true; + + // For now we are just making sure the file exists for a given module + Module *exe_module = target_sp->GetExecutableModulePointer(); + if (exe_module) { + const llvm::Triple &triple_ref = target_sp->GetArchitecture().GetTriple(); + switch (triple_ref.getOS()) { + case llvm::Triple::Darwin: // Should use "macosx" for desktop and "ios" for + // iOS, but accept darwin just in case + case llvm::Triple::MacOSX: // For desktop targets + case llvm::Triple::IOS: // For arm targets + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + if (triple_ref.getVendor() == llvm::Triple::Apple) { + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + if (exe_objfile->GetType() == ObjectFile::eTypeExecutable && + exe_objfile->GetStrata() == ObjectFile::eStrataKernel) + return true; + } + break; + + default: + break; } - return false; + } + return false; } //---------------------------------------------------------------------- // ProcessKDP constructor //---------------------------------------------------------------------- -ProcessKDP::ProcessKDP(TargetSP target_sp, ListenerSP listener_sp) : - Process (target_sp, listener_sp), - m_comm("lldb.process.kdp-remote.communication"), - m_async_broadcaster (NULL, "lldb.process.kdp-remote.async-broadcaster"), - m_dyld_plugin_name (), - m_kernel_load_addr (LLDB_INVALID_ADDRESS), - m_command_sp(), - m_kernel_thread_wp() -{ - m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); - m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue"); - const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout(); - if (timeout_seconds > 0) - m_comm.SetPacketTimeout(timeout_seconds); +ProcessKDP::ProcessKDP(TargetSP target_sp, ListenerSP listener_sp) + : Process(target_sp, listener_sp), + m_comm("lldb.process.kdp-remote.communication"), + m_async_broadcaster(NULL, "lldb.process.kdp-remote.async-broadcaster"), + m_dyld_plugin_name(), m_kernel_load_addr(LLDB_INVALID_ADDRESS), + m_command_sp(), m_kernel_thread_wp() { + m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, + "async thread should exit"); + m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, + "async thread continue"); + const uint64_t timeout_seconds = + GetGlobalPluginProperties()->GetPacketTimeout(); + if (timeout_seconds > 0) + m_comm.SetPacketTimeout(std::chrono::seconds(timeout_seconds)); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ProcessKDP::~ProcessKDP() -{ - Clear(); - // We need to call finalize on the process before destroying ourselves - // to make sure all of the broadcaster cleanup goes as planned. If we - // destruct this class, then Process::~Process() might have problems - // trying to fully destroy the broadcaster. - Finalize(); +ProcessKDP::~ProcessKDP() { + Clear(); + // We need to call finalize on the process before destroying ourselves + // to make sure all of the broadcaster cleanup goes as planned. If we + // destruct this class, then Process::~Process() might have problems + // trying to fully destroy the broadcaster. + Finalize(); } //---------------------------------------------------------------------- // PluginInterface //---------------------------------------------------------------------- -lldb_private::ConstString -ProcessKDP::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ProcessKDP::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ProcessKDP::GetPluginVersion() -{ - return 1; -} +uint32_t ProcessKDP::GetPluginVersion() { return 1; } -Error -ProcessKDP::WillLaunch (Module* module) -{ - Error error; - error.SetErrorString ("launching not supported in kdp-remote plug-in"); - return error; +Error ProcessKDP::WillLaunch(Module *module) { + Error error; + error.SetErrorString("launching not supported in kdp-remote plug-in"); + return error; } -Error -ProcessKDP::WillAttachToProcessWithID (lldb::pid_t pid) -{ - Error error; - error.SetErrorString ("attaching to a by process ID not supported in kdp-remote plug-in"); - return error; +Error ProcessKDP::WillAttachToProcessWithID(lldb::pid_t pid) { + Error error; + error.SetErrorString( + "attaching to a by process ID not supported in kdp-remote plug-in"); + return error; } -Error -ProcessKDP::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) -{ - Error error; - error.SetErrorString ("attaching to a by process name not supported in kdp-remote plug-in"); - return error; +Error ProcessKDP::WillAttachToProcessWithName(const char *process_name, + bool wait_for_launch) { + Error error; + error.SetErrorString( + "attaching to a by process name not supported in kdp-remote plug-in"); + return error; } -bool -ProcessKDP::GetHostArchitecture(ArchSpec &arch) -{ - uint32_t cpu = m_comm.GetCPUType(); - if (cpu) - { - uint32_t sub = m_comm.GetCPUSubtype(); - arch.SetArchitecture(eArchTypeMachO, cpu, sub); - // Leave architecture vendor as unspecified unknown - arch.GetTriple().setVendor(llvm::Triple::UnknownVendor); - arch.GetTriple().setVendorName(llvm::StringRef()); - return true; - } - arch.Clear(); - return false; +bool ProcessKDP::GetHostArchitecture(ArchSpec &arch) { + uint32_t cpu = m_comm.GetCPUType(); + if (cpu) { + uint32_t sub = m_comm.GetCPUSubtype(); + arch.SetArchitecture(eArchTypeMachO, cpu, sub); + // Leave architecture vendor as unspecified unknown + arch.GetTriple().setVendor(llvm::Triple::UnknownVendor); + arch.GetTriple().setVendorName(llvm::StringRef()); + return true; + } + arch.Clear(); + return false; } -Error -ProcessKDP::DoConnectRemote (Stream *strm, const char *remote_url) -{ - Error error; - - // Don't let any JIT happen when doing KDP as we can't allocate - // memory and we don't want to be mucking with threads that might - // already be handling exceptions - SetCanJIT(false); +Error ProcessKDP::DoConnectRemote(Stream *strm, llvm::StringRef remote_url) { + Error error; - if (remote_url == NULL || remote_url[0] == '\0') - { - error.SetErrorStringWithFormat ("invalid connection URL '%s'", remote_url); - return error; - } + // Don't let any JIT happen when doing KDP as we can't allocate + // memory and we don't want to be mucking with threads that might + // already be handling exceptions + SetCanJIT(false); - std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor()); - if (conn_ap.get()) - { - // Only try once for now. - // TODO: check if we should be retrying? - const uint32_t max_retry_count = 1; - for (uint32_t retry_count = 0; retry_count < max_retry_count; ++retry_count) - { - if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess) - break; - usleep (100000); - } + if (remote_url.empty()) { + error.SetErrorStringWithFormat("empty connection URL"); + return error; + } + + std::unique_ptr<ConnectionFileDescriptor> conn_ap( + new ConnectionFileDescriptor()); + if (conn_ap.get()) { + // Only try once for now. + // TODO: check if we should be retrying? + const uint32_t max_retry_count = 1; + for (uint32_t retry_count = 0; retry_count < max_retry_count; + ++retry_count) { + if (conn_ap->Connect(remote_url, &error) == eConnectionStatusSuccess) + break; + usleep(100000); } - - if (conn_ap->IsConnected()) - { - const TCPSocket& socket = static_cast<const TCPSocket&>(*conn_ap->GetReadObject()); - const uint16_t reply_port = socket.GetLocalPortNumber(); - - if (reply_port != 0) - { - m_comm.SetConnection(conn_ap.release()); - - if (m_comm.SendRequestReattach(reply_port)) - { - if (m_comm.SendRequestConnect(reply_port, reply_port, "Greetings from LLDB...")) - { - m_comm.GetVersion(); - - Target &target = GetTarget(); - ArchSpec kernel_arch; - // The host architecture - GetHostArchitecture(kernel_arch); - ArchSpec target_arch = target.GetArchitecture(); - // Merge in any unspecified stuff into the target architecture in - // case the target arch isn't set at all or incompletely. - target_arch.MergeFrom(kernel_arch); - target.SetArchitecture(target_arch); - - /* Get the kernel's UUID and load address via KDP_KERNELVERSION packet. */ - /* An EFI kdp session has neither UUID nor load address. */ - - UUID kernel_uuid = m_comm.GetUUID (); - addr_t kernel_load_addr = m_comm.GetLoadAddress (); - - if (m_comm.RemoteIsEFI ()) - { - // Select an invalid plugin name for the dynamic loader so one doesn't get used - // since EFI does its own manual loading via python scripting - static ConstString g_none_dynamic_loader("none"); - m_dyld_plugin_name = g_none_dynamic_loader; - - if (kernel_uuid.IsValid()) { - // If EFI passed in a UUID= try to lookup UUID - // The slide will not be provided. But the UUID - // lookup will be used to launch EFI debug scripts - // from the dSYM, that can load all of the symbols. - ModuleSpec module_spec; - module_spec.GetUUID() = kernel_uuid; - module_spec.GetArchitecture() = target.GetArchitecture(); - - // Lookup UUID locally, before attempting dsymForUUID like action - module_spec.GetSymbolFileSpec() = Symbols::LocateExecutableSymbolFile(module_spec); - if (module_spec.GetSymbolFileSpec()) - { - ModuleSpec executable_module_spec = Symbols::LocateExecutableObjectFile (module_spec); - if (executable_module_spec.GetFileSpec().Exists()) - { - module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); - } - } - if (!module_spec.GetSymbolFileSpec() || !module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile (module_spec, true); - - if (module_spec.GetFileSpec().Exists()) - { - ModuleSP module_sp(new Module (module_spec)); - if (module_sp.get() && module_sp->GetObjectFile()) - { - // Get the current target executable - ModuleSP exe_module_sp (target.GetExecutableModule ()); - - // Make sure you don't already have the right module loaded and they will be uniqued - if (exe_module_sp.get() != module_sp.get()) - target.SetExecutableModule (module_sp, false); - } - } - } - } - else if (m_comm.RemoteIsDarwinKernel ()) - { - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - if (kernel_load_addr != LLDB_INVALID_ADDRESS) - { - m_kernel_load_addr = kernel_load_addr; - } - } - - // Set the thread ID - UpdateThreadListIfNeeded (); - SetID (1); - GetThreadList (); - SetPrivateState (eStateStopped); - StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream()); - if (async_strm_sp) - { - const char *cstr; - if ((cstr = m_comm.GetKernelVersion ()) != NULL) - { - async_strm_sp->Printf ("Version: %s\n", cstr); - async_strm_sp->Flush(); - } -// if ((cstr = m_comm.GetImagePath ()) != NULL) -// { -// async_strm_sp->Printf ("Image Path: %s\n", cstr); -// async_strm_sp->Flush(); -// } - } + } + + if (conn_ap->IsConnected()) { + const TCPSocket &socket = + static_cast<const TCPSocket &>(*conn_ap->GetReadObject()); + const uint16_t reply_port = socket.GetLocalPortNumber(); + + if (reply_port != 0) { + m_comm.SetConnection(conn_ap.release()); + + if (m_comm.SendRequestReattach(reply_port)) { + if (m_comm.SendRequestConnect(reply_port, reply_port, + "Greetings from LLDB...")) { + m_comm.GetVersion(); + + Target &target = GetTarget(); + ArchSpec kernel_arch; + // The host architecture + GetHostArchitecture(kernel_arch); + ArchSpec target_arch = target.GetArchitecture(); + // Merge in any unspecified stuff into the target architecture in + // case the target arch isn't set at all or incompletely. + target_arch.MergeFrom(kernel_arch); + target.SetArchitecture(target_arch); + + /* Get the kernel's UUID and load address via KDP_KERNELVERSION + * packet. */ + /* An EFI kdp session has neither UUID nor load address. */ + + UUID kernel_uuid = m_comm.GetUUID(); + addr_t kernel_load_addr = m_comm.GetLoadAddress(); + + if (m_comm.RemoteIsEFI()) { + // Select an invalid plugin name for the dynamic loader so one + // doesn't get used + // since EFI does its own manual loading via python scripting + static ConstString g_none_dynamic_loader("none"); + m_dyld_plugin_name = g_none_dynamic_loader; + + if (kernel_uuid.IsValid()) { + // If EFI passed in a UUID= try to lookup UUID + // The slide will not be provided. But the UUID + // lookup will be used to launch EFI debug scripts + // from the dSYM, that can load all of the symbols. + ModuleSpec module_spec; + module_spec.GetUUID() = kernel_uuid; + module_spec.GetArchitecture() = target.GetArchitecture(); + + // Lookup UUID locally, before attempting dsymForUUID like action + module_spec.GetSymbolFileSpec() = + Symbols::LocateExecutableSymbolFile(module_spec); + if (module_spec.GetSymbolFileSpec()) { + ModuleSpec executable_module_spec = + Symbols::LocateExecutableObjectFile(module_spec); + if (executable_module_spec.GetFileSpec().Exists()) { + module_spec.GetFileSpec() = + executable_module_spec.GetFileSpec(); } - else - { - error.SetErrorString("KDP_REATTACH failed"); + } + if (!module_spec.GetSymbolFileSpec() || + !module_spec.GetSymbolFileSpec()) + Symbols::DownloadObjectAndSymbolFile(module_spec, true); + + if (module_spec.GetFileSpec().Exists()) { + ModuleSP module_sp(new Module(module_spec)); + if (module_sp.get() && module_sp->GetObjectFile()) { + // Get the current target executable + ModuleSP exe_module_sp(target.GetExecutableModule()); + + // Make sure you don't already have the right module loaded + // and they will be uniqued + if (exe_module_sp.get() != module_sp.get()) + target.SetExecutableModule(module_sp, false); } + } } - else - { - error.SetErrorString("KDP_REATTACH failed"); + } else if (m_comm.RemoteIsDarwinKernel()) { + m_dyld_plugin_name = + DynamicLoaderDarwinKernel::GetPluginNameStatic(); + if (kernel_load_addr != LLDB_INVALID_ADDRESS) { + m_kernel_load_addr = kernel_load_addr; } + } + + // Set the thread ID + UpdateThreadListIfNeeded(); + SetID(1); + GetThreadList(); + SetPrivateState(eStateStopped); + StreamSP async_strm_sp(target.GetDebugger().GetAsyncOutputStream()); + if (async_strm_sp) { + const char *cstr; + if ((cstr = m_comm.GetKernelVersion()) != NULL) { + async_strm_sp->Printf("Version: %s\n", cstr); + async_strm_sp->Flush(); + } + // if ((cstr = m_comm.GetImagePath ()) != NULL) + // { + // async_strm_sp->Printf ("Image Path: + // %s\n", cstr); + // async_strm_sp->Flush(); + // } + } + } else { + error.SetErrorString("KDP_REATTACH failed"); } - else - { - error.SetErrorString("invalid reply port from UDP connection"); - } - } - else - { - if (error.Success()) - error.SetErrorStringWithFormat ("failed to connect to '%s'", remote_url); + } else { + error.SetErrorString("KDP_REATTACH failed"); + } + } else { + error.SetErrorString("invalid reply port from UDP connection"); } - if (error.Fail()) - m_comm.Disconnect(); - - return error; + } else { + if (error.Success()) + error.SetErrorStringWithFormat("failed to connect to '%s'", + remote_url.str().c_str()); + } + if (error.Fail()) + m_comm.Disconnect(); + + return error; } //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- -Error -ProcessKDP::DoLaunch (Module *exe_module, - ProcessLaunchInfo &launch_info) -{ - Error error; - error.SetErrorString ("launching not supported in kdp-remote plug-in"); - return error; +Error ProcessKDP::DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) { + Error error; + error.SetErrorString("launching not supported in kdp-remote plug-in"); + return error; } -Error -ProcessKDP::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) -{ - Error error; - error.SetErrorString ("attach to process by ID is not suppported in kdp remote debugging"); - return error; +Error ProcessKDP::DoAttachToProcessWithID( + lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { + Error error; + error.SetErrorString( + "attach to process by ID is not suppported in kdp remote debugging"); + return error; } -Error -ProcessKDP::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) -{ - Error error; - error.SetErrorString ("attach to process by name is not suppported in kdp remote debugging"); - return error; +Error ProcessKDP::DoAttachToProcessWithName( + const char *process_name, const ProcessAttachInfo &attach_info) { + Error error; + error.SetErrorString( + "attach to process by name is not suppported in kdp remote debugging"); + return error; } +void ProcessKDP::DidAttach(ArchSpec &process_arch) { + Process::DidAttach(process_arch); -void -ProcessKDP::DidAttach (ArchSpec &process_arch) -{ - Process::DidAttach(process_arch); - - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); - if (log) - log->Printf ("ProcessKDP::DidAttach()"); - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - GetHostArchitecture(process_arch); - } + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); + if (log) + log->Printf("ProcessKDP::DidAttach()"); + if (GetID() != LLDB_INVALID_PROCESS_ID) { + GetHostArchitecture(process_arch); + } } -addr_t -ProcessKDP::GetImageInfoAddress() -{ - return m_kernel_load_addr; -} +addr_t ProcessKDP::GetImageInfoAddress() { return m_kernel_load_addr; } -lldb_private::DynamicLoader * -ProcessKDP::GetDynamicLoader () -{ - if (m_dyld_ap.get() == NULL) - m_dyld_ap.reset (DynamicLoader::FindPlugin(this, m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString())); - return m_dyld_ap.get(); +lldb_private::DynamicLoader *ProcessKDP::GetDynamicLoader() { + if (m_dyld_ap.get() == NULL) + m_dyld_ap.reset(DynamicLoader::FindPlugin( + this, + m_dyld_plugin_name.IsEmpty() ? NULL : m_dyld_plugin_name.GetCString())); + return m_dyld_ap.get(); } -Error -ProcessKDP::WillResume () -{ - return Error(); -} +Error ProcessKDP::WillResume() { return Error(); } -Error -ProcessKDP::DoResume () -{ - Error error; - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); - // Only start the async thread if we try to do any process control - if (!m_async_thread.IsJoinable()) - StartAsyncThread(); - - bool resume = false; - - // With KDP there is only one thread we can tell what to do - ThreadSP kernel_thread_sp (m_thread_list.FindThreadByProtocolID(g_kernel_tid)); - - if (kernel_thread_sp) - { - const StateType thread_resume_state = kernel_thread_sp->GetTemporaryResumeState(); - - if (log) - log->Printf ("ProcessKDP::DoResume() thread_resume_state = %s", StateAsCString(thread_resume_state)); - switch (thread_resume_state) - { - case eStateSuspended: - // Nothing to do here when a thread will stay suspended - // we just leave the CPU mask bit set to zero for the thread - if (log) - log->Printf ("ProcessKDP::DoResume() = suspended???"); - break; - - case eStateStepping: - { - lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext()); - - if (reg_ctx_sp) - { - if (log) - log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);"); - reg_ctx_sp->HardwareSingleStep (true); - resume = true; - } - else - { - error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID()); - } - } - break; - - case eStateRunning: - { - lldb::RegisterContextSP reg_ctx_sp (kernel_thread_sp->GetRegisterContext()); - - if (reg_ctx_sp) - { - if (log) - log->Printf ("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (false);"); - reg_ctx_sp->HardwareSingleStep (false); - resume = true; - } - else - { - error.SetErrorStringWithFormat("KDP thread 0x%llx has no register context", kernel_thread_sp->GetID()); - } - } - break; +Error ProcessKDP::DoResume() { + Error error; + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); + // Only start the async thread if we try to do any process control + if (!m_async_thread.IsJoinable()) + StartAsyncThread(); - default: - // The only valid thread resume states are listed above - assert (!"invalid thread resume state"); - break; - } - } + bool resume = false; + + // With KDP there is only one thread we can tell what to do + ThreadSP kernel_thread_sp(m_thread_list.FindThreadByProtocolID(g_kernel_tid)); + + if (kernel_thread_sp) { + const StateType thread_resume_state = + kernel_thread_sp->GetTemporaryResumeState(); - if (resume) - { + if (log) + log->Printf("ProcessKDP::DoResume() thread_resume_state = %s", + StateAsCString(thread_resume_state)); + switch (thread_resume_state) { + case eStateSuspended: + // Nothing to do here when a thread will stay suspended + // we just leave the CPU mask bit set to zero for the thread + if (log) + log->Printf("ProcessKDP::DoResume() = suspended???"); + break; + + case eStateStepping: { + lldb::RegisterContextSP reg_ctx_sp( + kernel_thread_sp->GetRegisterContext()); + + if (reg_ctx_sp) { if (log) - log->Printf ("ProcessKDP::DoResume () sending resume"); - - if (m_comm.SendRequestResume ()) - { - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue); - SetPrivateState(eStateRunning); - } - else - error.SetErrorString ("KDP resume failed"); - } - else - { - error.SetErrorString ("kernel thread is suspended"); + log->Printf( + "ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep (true);"); + reg_ctx_sp->HardwareSingleStep(true); + resume = true; + } else { + error.SetErrorStringWithFormat( + "KDP thread 0x%llx has no register context", + kernel_thread_sp->GetID()); + } + } break; + + case eStateRunning: { + lldb::RegisterContextSP reg_ctx_sp( + kernel_thread_sp->GetRegisterContext()); + + if (reg_ctx_sp) { + if (log) + log->Printf("ProcessKDP::DoResume () reg_ctx_sp->HardwareSingleStep " + "(false);"); + reg_ctx_sp->HardwareSingleStep(false); + resume = true; + } else { + error.SetErrorStringWithFormat( + "KDP thread 0x%llx has no register context", + kernel_thread_sp->GetID()); + } + } break; + + default: + // The only valid thread resume states are listed above + assert(!"invalid thread resume state"); + break; } - - return error; -} + } -lldb::ThreadSP -ProcessKDP::GetKernelThread() -{ - // KDP only tells us about one thread/core. Any other threads will usually - // be the ones that are read from memory by the OS plug-ins. - - ThreadSP thread_sp (m_kernel_thread_wp.lock()); - if (!thread_sp) - { - thread_sp.reset(new ThreadKDP (*this, g_kernel_tid)); - m_kernel_thread_wp = thread_sp; - } - return thread_sp; + if (resume) { + if (log) + log->Printf("ProcessKDP::DoResume () sending resume"); + + if (m_comm.SendRequestResume()) { + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncContinue); + SetPrivateState(eStateRunning); + } else + error.SetErrorString("KDP resume failed"); + } else { + error.SetErrorString("kernel thread is suspended"); + } + + return error; } +lldb::ThreadSP ProcessKDP::GetKernelThread() { + // KDP only tells us about one thread/core. Any other threads will usually + // be the ones that are read from memory by the OS plug-ins. + ThreadSP thread_sp(m_kernel_thread_wp.lock()); + if (!thread_sp) { + thread_sp.reset(new ThreadKDP(*this, g_kernel_tid)); + m_kernel_thread_wp = thread_sp; + } + return thread_sp; +} - -bool -ProcessKDP::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) -{ - // locker will keep a mutex locked until it goes out of scope - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_THREAD)); - if (log && log->GetMask().Test(KDP_LOG_VERBOSE)) - log->Printf ("ProcessKDP::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); - - // Even though there is a CPU mask, it doesn't mean we can see each CPU - // individually, there is really only one. Lets call this thread 1. - ThreadSP thread_sp (old_thread_list.FindThreadByProtocolID(g_kernel_tid, false)); - if (!thread_sp) - thread_sp = GetKernelThread (); - new_thread_list.AddThread(thread_sp); - - return new_thread_list.GetSize(false) > 0; +bool ProcessKDP::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + // locker will keep a mutex locked until it goes out of scope + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD)); + if (log && log->GetMask().Test(KDP_LOG_VERBOSE)) + log->Printf("ProcessKDP::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); + + // Even though there is a CPU mask, it doesn't mean we can see each CPU + // individually, there is really only one. Lets call this thread 1. + ThreadSP thread_sp( + old_thread_list.FindThreadByProtocolID(g_kernel_tid, false)); + if (!thread_sp) + thread_sp = GetKernelThread(); + new_thread_list.AddThread(thread_sp); + + return new_thread_list.GetSize(false) > 0; } -void -ProcessKDP::RefreshStateAfterStop () -{ - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). - m_thread_list.RefreshStateAfterStop(); +void ProcessKDP::RefreshStateAfterStop() { + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + m_thread_list.RefreshStateAfterStop(); } -Error -ProcessKDP::DoHalt (bool &caused_stop) -{ - Error error; - - if (m_comm.IsRunning()) - { - if (m_destroy_in_process) - { - // If we are attemping to destroy, we need to not return an error to - // Halt or DoDestroy won't get called. - // We are also currently running, so send a process stopped event - SetPrivateState (eStateStopped); - } - else - { - error.SetErrorString ("KDP cannot interrupt a running kernel"); - } +Error ProcessKDP::DoHalt(bool &caused_stop) { + Error error; + + if (m_comm.IsRunning()) { + if (m_destroy_in_process) { + // If we are attemping to destroy, we need to not return an error to + // Halt or DoDestroy won't get called. + // We are also currently running, so send a process stopped event + SetPrivateState(eStateStopped); + } else { + error.SetErrorString("KDP cannot interrupt a running kernel"); } - return error; + } + return error; } -Error -ProcessKDP::DoDetach(bool keep_stopped) -{ - Error error; - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (log) - log->Printf ("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); - - if (m_comm.IsRunning()) - { - // We are running and we can't interrupt a running kernel, so we need - // to just close the connection to the kernel and hope for the best - } - else - { - // If we are going to keep the target stopped, then don't send the disconnect message. - if (!keep_stopped && m_comm.IsConnected()) - { - const bool success = m_comm.SendRequestDisconnect(); - if (log) - { - if (success) - log->PutCString ("ProcessKDP::DoDetach() detach packet sent successfully"); - else - log->PutCString ("ProcessKDP::DoDetach() connection channel shutdown failed"); - } - m_comm.Disconnect (); - } +Error ProcessKDP::DoDetach(bool keep_stopped) { + Error error; + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); + if (log) + log->Printf("ProcessKDP::DoDetach(keep_stopped = %i)", keep_stopped); + + if (m_comm.IsRunning()) { + // We are running and we can't interrupt a running kernel, so we need + // to just close the connection to the kernel and hope for the best + } else { + // If we are going to keep the target stopped, then don't send the + // disconnect message. + if (!keep_stopped && m_comm.IsConnected()) { + const bool success = m_comm.SendRequestDisconnect(); + if (log) { + if (success) + log->PutCString( + "ProcessKDP::DoDetach() detach packet sent successfully"); + else + log->PutCString( + "ProcessKDP::DoDetach() connection channel shutdown failed"); + } + m_comm.Disconnect(); } - StopAsyncThread (); - m_comm.Clear(); - - SetPrivateState (eStateDetached); - ResumePrivateStateThread(); - - //KillDebugserverProcess (); - return error; + } + StopAsyncThread(); + m_comm.Clear(); + + SetPrivateState(eStateDetached); + ResumePrivateStateThread(); + + // KillDebugserverProcess (); + return error; } -Error -ProcessKDP::DoDestroy () -{ - // For KDP there really is no difference between destroy and detach - bool keep_stopped = false; - return DoDetach(keep_stopped); +Error ProcessKDP::DoDestroy() { + // For KDP there really is no difference between destroy and detach + bool keep_stopped = false; + return DoDetach(keep_stopped); } //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ -bool -ProcessKDP::IsAlive () -{ - return m_comm.IsConnected() && Process::IsAlive(); +bool ProcessKDP::IsAlive() { + return m_comm.IsConnected() && Process::IsAlive(); } //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ -size_t -ProcessKDP::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) -{ - uint8_t *data_buffer = (uint8_t *) buf; - if (m_comm.IsConnected()) - { - const size_t max_read_size = 512; - size_t total_bytes_read = 0; - - // Read the requested amount of memory in 512 byte chunks - while (total_bytes_read < size) - { - size_t bytes_to_read_this_request = size - total_bytes_read; - if (bytes_to_read_this_request > max_read_size) - { - bytes_to_read_this_request = max_read_size; - } - size_t bytes_read = m_comm.SendRequestReadMemory (addr + total_bytes_read, - data_buffer + total_bytes_read, - bytes_to_read_this_request, error); - total_bytes_read += bytes_read; - if (error.Fail() || bytes_read == 0) - { - return total_bytes_read; - } - } - +size_t ProcessKDP::DoReadMemory(addr_t addr, void *buf, size_t size, + Error &error) { + uint8_t *data_buffer = (uint8_t *)buf; + if (m_comm.IsConnected()) { + const size_t max_read_size = 512; + size_t total_bytes_read = 0; + + // Read the requested amount of memory in 512 byte chunks + while (total_bytes_read < size) { + size_t bytes_to_read_this_request = size - total_bytes_read; + if (bytes_to_read_this_request > max_read_size) { + bytes_to_read_this_request = max_read_size; + } + size_t bytes_read = m_comm.SendRequestReadMemory( + addr + total_bytes_read, data_buffer + total_bytes_read, + bytes_to_read_this_request, error); + total_bytes_read += bytes_read; + if (error.Fail() || bytes_read == 0) { return total_bytes_read; + } } - error.SetErrorString ("not connected"); - return 0; -} -size_t -ProcessKDP::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) -{ - if (m_comm.IsConnected()) - return m_comm.SendRequestWriteMemory (addr, buf, size, error); - error.SetErrorString ("not connected"); - return 0; + return total_bytes_read; + } + error.SetErrorString("not connected"); + return 0; } -lldb::addr_t -ProcessKDP::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) -{ - error.SetErrorString ("memory allocation not suppported in kdp remote debugging"); - return LLDB_INVALID_ADDRESS; +size_t ProcessKDP::DoWriteMemory(addr_t addr, const void *buf, size_t size, + Error &error) { + if (m_comm.IsConnected()) + return m_comm.SendRequestWriteMemory(addr, buf, size, error); + error.SetErrorString("not connected"); + return 0; } -Error -ProcessKDP::DoDeallocateMemory (lldb::addr_t addr) -{ - Error error; - error.SetErrorString ("memory deallocation not suppported in kdp remote debugging"); - return error; +lldb::addr_t ProcessKDP::DoAllocateMemory(size_t size, uint32_t permissions, + Error &error) { + error.SetErrorString( + "memory allocation not suppported in kdp remote debugging"); + return LLDB_INVALID_ADDRESS; } -Error -ProcessKDP::EnableBreakpointSite (BreakpointSite *bp_site) -{ - if (m_comm.LocalBreakpointsAreSupported ()) - { - Error error; - if (!bp_site->IsEnabled()) - { - if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress())) - { - bp_site->SetEnabled(true); - bp_site->SetType (BreakpointSite::eExternal); - } - else - { - error.SetErrorString ("KDP set breakpoint failed"); - } - } - return error; - } - return EnableSoftwareBreakpoint (bp_site); +Error ProcessKDP::DoDeallocateMemory(lldb::addr_t addr) { + Error error; + error.SetErrorString( + "memory deallocation not suppported in kdp remote debugging"); + return error; } -Error -ProcessKDP::DisableBreakpointSite (BreakpointSite *bp_site) -{ - if (m_comm.LocalBreakpointsAreSupported ()) - { - Error error; - if (bp_site->IsEnabled()) - { - BreakpointSite::Type bp_type = bp_site->GetType(); - if (bp_type == BreakpointSite::eExternal) - { - if (m_destroy_in_process && m_comm.IsRunning()) - { - // We are trying to destroy our connection and we are running - bp_site->SetEnabled(false); - } - else - { - if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) - bp_site->SetEnabled(false); - else - error.SetErrorString ("KDP remove breakpoint failed"); - } - } - else - { - error = DisableSoftwareBreakpoint (bp_site); - } - } - return error; +Error ProcessKDP::EnableBreakpointSite(BreakpointSite *bp_site) { + if (m_comm.LocalBreakpointsAreSupported()) { + Error error; + if (!bp_site->IsEnabled()) { + if (m_comm.SendRequestBreakpoint(true, bp_site->GetLoadAddress())) { + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eExternal); + } else { + error.SetErrorString("KDP set breakpoint failed"); + } } - return DisableSoftwareBreakpoint (bp_site); + return error; + } + return EnableSoftwareBreakpoint(bp_site); } -Error -ProcessKDP::EnableWatchpoint (Watchpoint *wp, bool notify) -{ +Error ProcessKDP::DisableBreakpointSite(BreakpointSite *bp_site) { + if (m_comm.LocalBreakpointsAreSupported()) { Error error; - error.SetErrorString ("watchpoints are not suppported in kdp remote debugging"); + if (bp_site->IsEnabled()) { + BreakpointSite::Type bp_type = bp_site->GetType(); + if (bp_type == BreakpointSite::eExternal) { + if (m_destroy_in_process && m_comm.IsRunning()) { + // We are trying to destroy our connection and we are running + bp_site->SetEnabled(false); + } else { + if (m_comm.SendRequestBreakpoint(false, bp_site->GetLoadAddress())) + bp_site->SetEnabled(false); + else + error.SetErrorString("KDP remove breakpoint failed"); + } + } else { + error = DisableSoftwareBreakpoint(bp_site); + } + } return error; + } + return DisableSoftwareBreakpoint(bp_site); } -Error -ProcessKDP::DisableWatchpoint (Watchpoint *wp, bool notify) -{ - Error error; - error.SetErrorString ("watchpoints are not suppported in kdp remote debugging"); - return error; +Error ProcessKDP::EnableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + error.SetErrorString( + "watchpoints are not suppported in kdp remote debugging"); + return error; } -void -ProcessKDP::Clear() -{ - m_thread_list.Clear(); +Error ProcessKDP::DisableWatchpoint(Watchpoint *wp, bool notify) { + Error error; + error.SetErrorString( + "watchpoints are not suppported in kdp remote debugging"); + return error; } -Error -ProcessKDP::DoSignal (int signo) -{ - Error error; - error.SetErrorString ("sending signals is not suppported in kdp remote debugging"); - return error; +void ProcessKDP::Clear() { m_thread_list.Clear(); } + +Error ProcessKDP::DoSignal(int signo) { + Error error; + error.SetErrorString( + "sending signals is not suppported in kdp remote debugging"); + return error; } -void -ProcessKDP::Initialize() -{ - static std::once_flag g_once_flag; - - std::call_once(g_once_flag, []() - { - PluginManager::RegisterPlugin (GetPluginNameStatic(), - GetPluginDescriptionStatic(), - CreateInstance, - DebuggerInitialize); - - Log::Callbacks log_callbacks = { - ProcessKDPLog::DisableLog, - ProcessKDPLog::EnableLog, - ProcessKDPLog::ListLogCategories - }; - - Log::RegisterLogChannel (ProcessKDP::GetPluginNameStatic(), log_callbacks); - }); +void ProcessKDP::Initialize() { + static std::once_flag g_once_flag; + + std::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + + Log::Callbacks log_callbacks = {ProcessKDPLog::DisableLog, + ProcessKDPLog::EnableLog, + ProcessKDPLog::ListLogCategories}; + + Log::RegisterLogChannel(ProcessKDP::GetPluginNameStatic(), log_callbacks); + }); } -void -ProcessKDP::DebuggerInitialize (lldb_private::Debugger &debugger) -{ - if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) - { - const bool is_global_setting = true; - PluginManager::CreateSettingForProcessPlugin (debugger, - GetGlobalPluginProperties()->GetValueProperties(), - ConstString ("Properties for the kdp-remote process plug-in."), - is_global_setting); - } +void ProcessKDP::DebuggerInitialize(lldb_private::Debugger &debugger) { + if (!PluginManager::GetSettingForProcessPlugin( + debugger, PluginProperties::GetSettingName())) { + const bool is_global_setting = true; + PluginManager::CreateSettingForProcessPlugin( + debugger, GetGlobalPluginProperties()->GetValueProperties(), + ConstString("Properties for the kdp-remote process plug-in."), + is_global_setting); + } } -bool -ProcessKDP::StartAsyncThread () -{ - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - - if (log) - log->Printf ("ProcessKDP::StartAsyncThread ()"); +bool ProcessKDP::StartAsyncThread() { + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - if (m_async_thread.IsJoinable()) - return true; + if (log) + log->Printf("ProcessKDP::StartAsyncThread ()"); - m_async_thread = ThreadLauncher::LaunchThread("<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL); - return m_async_thread.IsJoinable(); -} + if (m_async_thread.IsJoinable()) + return true; -void -ProcessKDP::StopAsyncThread () -{ - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); - - if (log) - log->Printf ("ProcessKDP::StopAsyncThread ()"); - - m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); - - // Stop the stdio thread - if (m_async_thread.IsJoinable()) - m_async_thread.Join(nullptr); + m_async_thread = ThreadLauncher::LaunchThread( + "<lldb.process.kdp-remote.async>", ProcessKDP::AsyncThread, this, NULL); + return m_async_thread.IsJoinable(); } +void ProcessKDP::StopAsyncThread() { + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); -void * -ProcessKDP::AsyncThread (void *arg) -{ - ProcessKDP *process = (ProcessKDP*) arg; - - const lldb::pid_t pid = process->GetID(); + if (log) + log->Printf("ProcessKDP::StopAsyncThread ()"); - Log *log (ProcessKDPLog::GetLogIfAllCategoriesSet (KDP_LOG_PROCESS)); - if (log) - log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread starting...", arg, pid); - - ListenerSP listener_sp (Listener::MakeListener("ProcessKDP::AsyncThread")); - EventSP event_sp; - const uint32_t desired_event_mask = eBroadcastBitAsyncContinue | - eBroadcastBitAsyncThreadShouldExit; - - - if (listener_sp->StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask) - { - bool done = false; - while (!done) - { - if (log) - log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", - pid); - if (listener_sp->WaitForEvent (NULL, event_sp)) - { - uint32_t event_type = event_sp->GetType(); - if (log) - log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") Got an event of type: %d...", - pid, - event_type); - - // When we are running, poll for 1 second to try and get an exception - // to indicate the process has stopped. If we don't get one, check to - // make sure no one asked us to exit - bool is_running = false; - DataExtractor exc_reply_packet; - do - { - switch (event_type) - { - case eBroadcastBitAsyncContinue: - { - is_running = true; - if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds (exc_reply_packet, 1 * USEC_PER_SEC)) - { - ThreadSP thread_sp (process->GetKernelThread()); - if (thread_sp) - { - lldb::RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); - if (reg_ctx_sp) - reg_ctx_sp->InvalidateAllRegisters(); - static_cast<ThreadKDP *>(thread_sp.get())->SetStopInfoFrom_KDP_EXCEPTION (exc_reply_packet); - } - - // TODO: parse the stop reply packet - is_running = false; - process->SetPrivateState(eStateStopped); - } - else - { - // Check to see if we are supposed to exit. There is no way to - // interrupt a running kernel, so all we can do is wait for an - // exception or detach... - if (listener_sp->GetNextEvent(event_sp)) - { - // We got an event, go through the loop again - event_type = event_sp->GetType(); - } - } - } - break; - - case eBroadcastBitAsyncThreadShouldExit: - if (log) - log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", - pid); - done = true; - is_running = false; - break; - - default: - if (log) - log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") got unknown event 0x%8.8x", - pid, - event_type); - done = true; - is_running = false; - break; - } - } while (is_running); - } - else - { - if (log) - log->Printf ("ProcessKDP::AsyncThread (pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", - pid); - done = true; + m_async_broadcaster.BroadcastEvent(eBroadcastBitAsyncThreadShouldExit); + + // Stop the stdio thread + if (m_async_thread.IsJoinable()) + m_async_thread.Join(nullptr); +} + +void *ProcessKDP::AsyncThread(void *arg) { + ProcessKDP *process = (ProcessKDP *)arg; + + const lldb::pid_t pid = process->GetID(); + + Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_PROCESS)); + if (log) + log->Printf("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 + ") thread starting...", + arg, pid); + + ListenerSP listener_sp(Listener::MakeListener("ProcessKDP::AsyncThread")); + EventSP event_sp; + const uint32_t desired_event_mask = + eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; + + if (listener_sp->StartListeningForEvents(&process->m_async_broadcaster, + desired_event_mask) == + desired_event_mask) { + bool done = false; + while (!done) { + if (log) + log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp)...", + pid); + if (listener_sp->GetEvent(event_sp, llvm::None)) { + uint32_t event_type = event_sp->GetType(); + if (log) + log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 + ") Got an event of type: %d...", + pid, event_type); + + // When we are running, poll for 1 second to try and get an exception + // to indicate the process has stopped. If we don't get one, check to + // make sure no one asked us to exit + bool is_running = false; + DataExtractor exc_reply_packet; + do { + switch (event_type) { + case eBroadcastBitAsyncContinue: { + is_running = true; + if (process->m_comm.WaitForPacketWithTimeoutMicroSeconds( + exc_reply_packet, 1 * USEC_PER_SEC)) { + ThreadSP thread_sp(process->GetKernelThread()); + if (thread_sp) { + lldb::RegisterContextSP reg_ctx_sp( + thread_sp->GetRegisterContext()); + if (reg_ctx_sp) + reg_ctx_sp->InvalidateAllRegisters(); + static_cast<ThreadKDP *>(thread_sp.get()) + ->SetStopInfoFrom_KDP_EXCEPTION(exc_reply_packet); + } + + // TODO: parse the stop reply packet + is_running = false; + process->SetPrivateState(eStateStopped); + } else { + // Check to see if we are supposed to exit. There is no way to + // interrupt a running kernel, so all we can do is wait for an + // exception or detach... + if (listener_sp->GetEvent(event_sp, + std::chrono::microseconds(0))) { + // We got an event, go through the loop again + event_type = event_sp->GetType(); + } } - } + } break; + + case eBroadcastBitAsyncThreadShouldExit: + if (log) + log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 + ") got eBroadcastBitAsyncThreadShouldExit...", + pid); + done = true; + is_running = false; + break; + + default: + if (log) + log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 + ") got unknown event 0x%8.8x", + pid, event_type); + done = true; + is_running = false; + break; + } + } while (is_running); + } else { + if (log) + log->Printf("ProcessKDP::AsyncThread (pid = %" PRIu64 + ") listener.WaitForEvent (NULL, event_sp) => false", + pid); + done = true; + } } - - if (log) - log->Printf ("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 ") thread exiting...", - arg, - pid); + } - process->m_async_thread.Reset(); - return NULL; -} + if (log) + log->Printf("ProcessKDP::AsyncThread (arg = %p, pid = %" PRIu64 + ") thread exiting...", + arg, pid); + process->m_async_thread.Reset(); + return NULL; +} -class CommandObjectProcessKDPPacketSend : public CommandObjectParsed -{ +class CommandObjectProcessKDPPacketSend : public CommandObjectParsed { private: - - OptionGroupOptions m_option_group; - OptionGroupUInt64 m_command_byte; - OptionGroupString m_packet_data; - - virtual Options * - GetOptions () - { - return &m_option_group; - } - + OptionGroupOptions m_option_group; + OptionGroupUInt64 m_command_byte; + OptionGroupString m_packet_data; + + virtual Options *GetOptions() { return &m_option_group; } public: - CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "process plugin packet send", - "Send a custom packet through the KDP protocol by specifying the command byte and the packet payload data. A packet will be sent with a correct header and payload, and the raw result bytes will be displayed as a string value. ", - NULL), - m_option_group (interpreter), - m_command_byte(LLDB_OPT_SET_1, true , "command", 'c', 0, eArgTypeNone, "Specify the command byte to use when sending the KDP request packet.", 0), - m_packet_data (LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, "Specify packet payload bytes as a hex ASCII string with no spaces or hex prefixes.", NULL) - { - m_option_group.Append (&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append (&m_packet_data , LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Finalize(); - } - - ~CommandObjectProcessKDPPacketSend () - { - } - - bool - DoExecute (Args& command, CommandReturnObject &result) - { - const size_t argc = command.GetArgumentCount(); - if (argc == 0) - { - if (!m_command_byte.GetOptionValue().OptionWasSet()) - { - result.AppendError ("the --command option must be set to a valid command byte"); - result.SetStatus (eReturnStatusFailed); - } - else - { - const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0); - if (command_byte > 0 && command_byte <= UINT8_MAX) - { - ProcessKDP *process = (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr(); - if (process) - { - const StateType state = process->GetState(); - - if (StateIsStoppedState (state, true)) - { - std::vector<uint8_t> payload_bytes; - const char *ascii_hex_bytes_cstr = m_packet_data.GetOptionValue().GetCurrentValue(); - if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) - { - StringExtractor extractor(ascii_hex_bytes_cstr); - const size_t ascii_hex_bytes_cstr_len = extractor.GetStringRef().size(); - if (ascii_hex_bytes_cstr_len & 1) - { - result.AppendErrorWithFormat ("payload data must contain an even number of ASCII hex characters: '%s'", ascii_hex_bytes_cstr); - result.SetStatus (eReturnStatusFailed); - return false; - } - payload_bytes.resize(ascii_hex_bytes_cstr_len/2); - if (extractor.GetHexBytes(&payload_bytes[0], payload_bytes.size(), '\xdd') != payload_bytes.size()) - { - result.AppendErrorWithFormat ("payload data must only contain ASCII hex characters (no spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - Error error; - DataExtractor reply; - process->GetCommunication().SendRawRequest (command_byte, - payload_bytes.empty() ? NULL : payload_bytes.data(), - payload_bytes.size(), - reply, - error); - - if (error.Success()) - { - // Copy the binary bytes into a hex ASCII string for the result - StreamString packet; - packet.PutBytesAsRawHex8(reply.GetDataStart(), - reply.GetByteSize(), - endian::InlHostByteOrder(), - endian::InlHostByteOrder()); - result.AppendMessage(packet.GetString().c_str()); - result.SetStatus (eReturnStatusSuccessFinishResult); - return true; - } - else - { - const char *error_cstr = error.AsCString(); - if (error_cstr && error_cstr[0]) - result.AppendError (error_cstr); - else - result.AppendErrorWithFormat ("unknown error 0x%8.8x", error.GetError()); - result.SetStatus (eReturnStatusFailed); - return false; - } - } - else - { - result.AppendErrorWithFormat ("process must be stopped in order to send KDP packets, state is %s", StateAsCString (state)); - result.SetStatus (eReturnStatusFailed); - } - } - else - { - result.AppendError ("invalid process"); - result.SetStatus (eReturnStatusFailed); - } + CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process plugin packet send", + "Send a custom packet through the KDP protocol by " + "specifying the command byte and the packet " + "payload data. A packet will be sent with a " + "correct header and payload, and the raw result " + "bytes will be displayed as a string value. ", + NULL), + m_option_group(), + m_command_byte(LLDB_OPT_SET_1, true, "command", 'c', 0, eArgTypeNone, + "Specify the command byte to use when sending the KDP " + "request packet.", + 0), + m_packet_data(LLDB_OPT_SET_1, false, "payload", 'p', 0, eArgTypeNone, + "Specify packet payload bytes as a hex ASCII string with " + "no spaces or hex prefixes.", + NULL) { + m_option_group.Append(&m_command_byte, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_packet_data, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Finalize(); + } + + ~CommandObjectProcessKDPPacketSend() {} + + bool DoExecute(Args &command, CommandReturnObject &result) { + const size_t argc = command.GetArgumentCount(); + if (argc == 0) { + if (!m_command_byte.GetOptionValue().OptionWasSet()) { + result.AppendError( + "the --command option must be set to a valid command byte"); + result.SetStatus(eReturnStatusFailed); + } else { + const uint64_t command_byte = + m_command_byte.GetOptionValue().GetUInt64Value(0); + if (command_byte > 0 && command_byte <= UINT8_MAX) { + ProcessKDP *process = + (ProcessKDP *)m_interpreter.GetExecutionContext().GetProcessPtr(); + if (process) { + const StateType state = process->GetState(); + + if (StateIsStoppedState(state, true)) { + std::vector<uint8_t> payload_bytes; + const char *ascii_hex_bytes_cstr = + m_packet_data.GetOptionValue().GetCurrentValue(); + if (ascii_hex_bytes_cstr && ascii_hex_bytes_cstr[0]) { + StringExtractor extractor(ascii_hex_bytes_cstr); + const size_t ascii_hex_bytes_cstr_len = + extractor.GetStringRef().size(); + if (ascii_hex_bytes_cstr_len & 1) { + result.AppendErrorWithFormat("payload data must contain an " + "even number of ASCII hex " + "characters: '%s'", + ascii_hex_bytes_cstr); + result.SetStatus(eReturnStatusFailed); + return false; } - else - { - result.AppendErrorWithFormat ("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte); - result.SetStatus (eReturnStatusFailed); + payload_bytes.resize(ascii_hex_bytes_cstr_len / 2); + if (extractor.GetHexBytes(payload_bytes, '\xdd') != + payload_bytes.size()) { + result.AppendErrorWithFormat("payload data must only contain " + "ASCII hex characters (no " + "spaces or hex prefixes): '%s'", + ascii_hex_bytes_cstr); + result.SetStatus(eReturnStatusFailed); + return false; } + } + Error error; + DataExtractor reply; + process->GetCommunication().SendRawRequest( + command_byte, + payload_bytes.empty() ? NULL : payload_bytes.data(), + payload_bytes.size(), reply, error); + + if (error.Success()) { + // Copy the binary bytes into a hex ASCII string for the result + StreamString packet; + packet.PutBytesAsRawHex8( + reply.GetDataStart(), reply.GetByteSize(), + endian::InlHostByteOrder(), endian::InlHostByteOrder()); + result.AppendMessage(packet.GetString()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } else { + const char *error_cstr = error.AsCString(); + if (error_cstr && error_cstr[0]) + result.AppendError(error_cstr); + else + result.AppendErrorWithFormat("unknown error 0x%8.8x", + error.GetError()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else { + result.AppendErrorWithFormat("process must be stopped in order " + "to send KDP packets, state is %s", + StateAsCString(state)); + result.SetStatus(eReturnStatusFailed); } + } else { + result.AppendError("invalid process"); + result.SetStatus(eReturnStatusFailed); + } + } else { + result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64 + ", valid values are 1 - 255", + command_byte); + result.SetStatus(eReturnStatusFailed); } - else - { - result.AppendErrorWithFormat ("'%s' takes no arguments, only options.", m_cmd_name.c_str()); - result.SetStatus (eReturnStatusFailed); - } - return false; + } + } else { + result.AppendErrorWithFormat("'%s' takes no arguments, only options.", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); } + return false; + } }; -class CommandObjectProcessKDPPacket : public CommandObjectMultiword -{ +class CommandObjectProcessKDPPacket : public CommandObjectMultiword { private: - public: - CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) : - CommandObjectMultiword (interpreter, - "process plugin packet", - "Commands that deal with KDP remote packets.", - NULL) - { - LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessKDPPacketSend (interpreter))); - } - - ~CommandObjectProcessKDPPacket () - { - } + CommandObjectProcessKDPPacket(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "process plugin packet", + "Commands that deal with KDP remote packets.", + NULL) { + LoadSubCommand( + "send", + CommandObjectSP(new CommandObjectProcessKDPPacketSend(interpreter))); + } + + ~CommandObjectProcessKDPPacket() {} }; -class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword -{ +class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword { public: - CommandObjectMultiwordProcessKDP(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "process plugin", "Commands for operating on a ProcessKDP process.", - "process plugin <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessKDPPacket (interpreter))); - } - - ~CommandObjectMultiwordProcessKDP () - { - } + CommandObjectMultiwordProcessKDP(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "process plugin", + "Commands for operating on a ProcessKDP process.", + "process plugin <subcommand> [<subcommand-options>]") { + LoadSubCommand("packet", CommandObjectSP(new CommandObjectProcessKDPPacket( + interpreter))); + } + + ~CommandObjectMultiwordProcessKDP() {} }; -CommandObject * -ProcessKDP::GetPluginCommandObject() -{ - if (!m_command_sp) - m_command_sp.reset (new CommandObjectMultiwordProcessKDP (GetTarget().GetDebugger().GetCommandInterpreter())); - return m_command_sp.get(); +CommandObject *ProcessKDP::GetPluginCommandObject() { + if (!m_command_sp) + m_command_sp.reset(new CommandObjectMultiwordProcessKDP( + GetTarget().GetDebugger().GetCommandInterpreter())); + return m_command_sp.get(); } - |