Index: lldb/bindings/interface/SBAttachInfo.i =================================================================== --- lldb/bindings/interface/SBAttachInfo.i +++ lldb/bindings/interface/SBAttachInfo.i @@ -112,6 +112,16 @@ void SetListener (lldb::SBListener &listener); + + const char * + GetScriptedProcessClassName() const; + + void SetScriptedProcessClassName(const char *class_name); + + lldb::SBStructuredData + GetScriptedProcessDictionary() const; + + void SetScriptedProcessDictionary(lldb::SBStructuredData dict); }; } // namespace lldb Index: lldb/include/lldb/API/SBAttachInfo.h =================================================================== --- lldb/include/lldb/API/SBAttachInfo.h +++ lldb/include/lldb/API/SBAttachInfo.h @@ -164,6 +164,14 @@ /// allows a different listener to be used to listen for process events. void SetListener(SBListener &listener); + const char *GetScriptedProcessClassName() const; + + void SetScriptedProcessClassName(const char *class_name); + + lldb::SBStructuredData GetScriptedProcessDictionary() const; + + void SetScriptedProcessDictionary(lldb::SBStructuredData dict); + protected: friend class SBTarget; Index: lldb/include/lldb/API/SBStructuredData.h =================================================================== --- lldb/include/lldb/API/SBStructuredData.h +++ lldb/include/lldb/API/SBStructuredData.h @@ -90,6 +90,7 @@ size_t GetStringValue(char *dst, size_t dst_len) const; protected: + friend class SBAttachInfo; friend class SBLaunchInfo; friend class SBDebugger; friend class SBTarget; Index: lldb/include/lldb/Target/Process.h =================================================================== --- lldb/include/lldb/Target/Process.h +++ lldb/include/lldb/Target/Process.h @@ -192,6 +192,28 @@ lldb::ListenerSP GetListenerForProcess(Debugger &debugger); + bool IsScriptedProcess() const { + return !m_scripted_process_class_name.empty(); + } + + std::string GetScriptedProcessClassName() const { + return m_scripted_process_class_name; + } + + void SetScriptedProcessClassName(std::string name) { + m_scripted_process_class_name = name; + } + + lldb_private::StructuredData::DictionarySP + GetScriptedProcessDictionarySP() const { + return m_scripted_process_dictionary_sp; + } + + void SetScriptedProcessDictionarySP( + lldb_private::StructuredData::DictionarySP dictionary_sp) { + m_scripted_process_dictionary_sp = dictionary_sp; + } + protected: lldb::ListenerSP m_listener_sp; lldb::ListenerSP m_hijack_listener_sp; @@ -209,6 +231,11 @@ false; // Use an async attach where we start the attach and return // immediately (used by GUI programs with --waitfor so they can // call SBProcess::Stop() to cancel attach) + std::string m_scripted_process_class_name; // The name of the class that will + // manage a scripted process. + StructuredData::DictionarySP + m_scripted_process_dictionary_sp; // A dictionary that holds key/value + // pairs passed to the scripted process. }; // This class tracks the Modification state of the process. Things that can Index: lldb/source/API/SBAttachInfo.cpp =================================================================== --- lldb/source/API/SBAttachInfo.cpp +++ lldb/source/API/SBAttachInfo.cpp @@ -10,6 +10,7 @@ #include "Utils.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBListener.h" +#include "lldb/API/SBStructuredData.h" #include "lldb/Target/Process.h" #include "lldb/Utility/Instrumentation.h" @@ -251,3 +252,48 @@ m_opaque_sp->SetListener(listener.GetSP()); } + +const char *SBAttachInfo::GetScriptedProcessClassName() const { + LLDB_INSTRUMENT_VA(this); + + // Constify this string so that it is saved in the string pool. Otherwise it + // would be freed when this function goes out of scope. + ConstString class_name(m_opaque_sp->GetScriptedProcessClassName().c_str()); + return class_name.AsCString(); +} + +void SBAttachInfo::SetScriptedProcessClassName(const char *class_name) { + LLDB_INSTRUMENT_VA(this, class_name); + + m_opaque_sp->SetScriptedProcessClassName(class_name); +} + +lldb::SBStructuredData SBAttachInfo::GetScriptedProcessDictionary() const { + LLDB_INSTRUMENT_VA(this); + + lldb_private::StructuredData::DictionarySP dict_sp = + m_opaque_sp->GetScriptedProcessDictionarySP(); + + SBStructuredData data; + data.m_impl_up->SetObjectSP(dict_sp); + + return data; +} + +void SBAttachInfo::SetScriptedProcessDictionary(lldb::SBStructuredData dict) { + LLDB_INSTRUMENT_VA(this, dict); + if (!dict.IsValid() || !dict.m_impl_up) + return; + + StructuredData::ObjectSP obj_sp = dict.m_impl_up->GetObjectSP(); + + if (!obj_sp) + return; + + StructuredData::DictionarySP dict_sp = + std::make_shared(obj_sp); + if (!dict_sp || dict_sp->GetType() == lldb::eStructuredDataTypeInvalid) + return; + + m_opaque_sp->SetScriptedProcessDictionarySP(dict_sp); +} Index: lldb/source/Commands/CMakeLists.txt =================================================================== --- lldb/source/Commands/CMakeLists.txt +++ lldb/source/Commands/CMakeLists.txt @@ -39,6 +39,7 @@ CommandObjectWatchpoint.cpp CommandObjectWatchpointCommand.cpp CommandOptionArgumentTable.cpp + CommandOptionsProcessAttach.cpp CommandOptionsProcessLaunch.cpp LINK_LIBS Index: lldb/source/Commands/CommandObjectPlatform.cpp =================================================================== --- lldb/source/Commands/CommandObjectPlatform.cpp +++ lldb/source/Commands/CommandObjectPlatform.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CommandObjectPlatform.h" +#include "CommandOptionsProcessAttach.h" #include "CommandOptionsProcessLaunch.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -1138,8 +1139,11 @@ : CommandObjectParsed(interpreter, "platform process launch", "Launch a new process on a remote platform.", "platform process launch program", - eCommandRequiresTarget | eCommandTryTargetAPILock) { + eCommandRequiresTarget | eCommandTryTargetAPILock), + m_class_options("scripted process", true, 'C', 'k', 'v', 0) { m_all_options.Append(&m_options); + m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_ALL); m_all_options.Finalize(); CommandArgumentData run_arg_arg{eArgTypeRunArgs, eArgRepeatStar}; m_arguments.push_back({run_arg_arg}); @@ -1174,6 +1178,15 @@ m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture(); } + if (!m_class_options.GetName().empty()) { + m_options.launch_info.SetProcessPluginName("ScriptedProcess"); + m_options.launch_info.SetScriptedProcessClassName( + m_class_options.GetName()); + m_options.launch_info.SetScriptedProcessDictionarySP( + m_class_options.GetStructuredData()); + target->SetProcessLaunchInfo(m_options.launch_info); + } + if (argc > 0) { if (m_options.launch_info.GetExecutableFile()) { // We already have an executable file, so we will use this and all @@ -1217,6 +1230,7 @@ } CommandOptionsProcessLaunch m_options; + OptionGroupPythonClassWithDict m_class_options; OptionGroupOptions m_all_options; }; @@ -1566,71 +1580,16 @@ class CommandObjectPlatformProcessAttach : public CommandObjectParsed { public: - class CommandOptions : public Options { - public: - CommandOptions() { - // Keep default values of all options in one place: OptionParsingStarting - // () - OptionParsingStarting(nullptr); - } - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override { - Status error; - char short_option = (char)m_getopt_table[option_idx].val; - switch (short_option) { - case 'p': { - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - if (option_arg.getAsInteger(0, pid)) { - error.SetErrorStringWithFormat("invalid process ID '%s'", - option_arg.str().c_str()); - } else { - attach_info.SetProcessID(pid); - } - } break; - - case 'P': - attach_info.SetProcessPluginName(option_arg); - break; - - case 'n': - attach_info.GetExecutableFile().SetFile(option_arg, - FileSpec::Style::native); - break; - - case 'w': - attach_info.SetWaitForLaunch(true); - break; - - default: - llvm_unreachable("Unimplemented option"); - } - return error; - } - - void OptionParsingStarting(ExecutionContext *execution_context) override { - attach_info.Clear(); - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::makeArrayRef(g_platform_process_attach_options); - } - - // Options table: Required for subclasses of Options. - - static OptionDefinition g_option_table[]; - - // Instance variables to hold the values for command options. - - ProcessAttachInfo attach_info; - }; - CommandObjectPlatformProcessAttach(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "platform process attach", "Attach to a process.", - "platform process attach ") {} + "platform process attach "), + m_class_options("scripted process", true, 'C', 'k', 'v', 0) { + m_all_options.Append(&m_options); + m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + } ~CommandObjectPlatformProcessAttach() override = default; @@ -1638,6 +1597,15 @@ PlatformSP platform_sp( GetDebugger().GetPlatformList().GetSelectedPlatform()); if (platform_sp) { + + if (!m_class_options.GetName().empty()) { + m_options.attach_info.SetProcessPluginName("ScriptedProcess"); + m_options.attach_info.SetScriptedProcessClassName( + m_class_options.GetName()); + m_options.attach_info.SetScriptedProcessDictionarySP( + m_class_options.GetStructuredData()); + } + Status err; ProcessSP remote_process_sp = platform_sp->Attach( m_options.attach_info, GetDebugger(), nullptr, err); @@ -1653,10 +1621,12 @@ return result.Succeeded(); } - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: - CommandOptions m_options; + CommandOptionsProcessAttach m_options; + OptionGroupPythonClassWithDict m_class_options; + OptionGroupOptions m_all_options; }; class CommandObjectPlatformProcess : public CommandObjectMultiword { Index: lldb/source/Commands/CommandObjectProcess.cpp =================================================================== --- lldb/source/Commands/CommandObjectProcess.cpp +++ lldb/source/Commands/CommandObjectProcess.cpp @@ -9,6 +9,7 @@ #include "CommandObjectProcess.h" #include "CommandObjectBreakpoint.h" #include "CommandObjectTrace.h" +#include "CommandOptionsProcessAttach.h" #include "CommandOptionsProcessLaunch.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointIDList.h" @@ -303,77 +304,20 @@ #pragma mark CommandObjectProcessAttach class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach { public: - class CommandOptions : public Options { - public: - CommandOptions() { - // Keep default values of all options in one place: OptionParsingStarting - // () - OptionParsingStarting(nullptr); - } - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override { - Status error; - const int short_option = m_getopt_table[option_idx].val; - switch (short_option) { - case 'c': - attach_info.SetContinueOnceAttached(true); - break; - - case 'p': { - lldb::pid_t pid; - if (option_arg.getAsInteger(0, pid)) { - error.SetErrorStringWithFormat("invalid process ID '%s'", - option_arg.str().c_str()); - } else { - attach_info.SetProcessID(pid); - } - } break; - - case 'P': - attach_info.SetProcessPluginName(option_arg); - break; - - case 'n': - attach_info.GetExecutableFile().SetFile(option_arg, - FileSpec::Style::native); - break; - - case 'w': - attach_info.SetWaitForLaunch(true); - break; - - case 'i': - attach_info.SetIgnoreExisting(false); - break; - - default: - llvm_unreachable("Unimplemented option"); - } - return error; - } - - void OptionParsingStarting(ExecutionContext *execution_context) override { - attach_info.Clear(); - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::makeArrayRef(g_process_attach_options); - } - - ProcessAttachInfo attach_info; - }; - CommandObjectProcessAttach(CommandInterpreter &interpreter) : CommandObjectProcessLaunchOrAttach( interpreter, "process attach", "Attach to a process.", - "process attach ", 0, "attach") {} + "process attach ", 0, "attach"), + m_class_options("scripted process", true, 'C', 'k', 'v', 0) { + m_all_options.Append(&m_options); + m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + } ~CommandObjectProcessAttach() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: bool DoExecute(Args &command, CommandReturnObject &result) override { @@ -408,6 +352,14 @@ } } + if (!m_class_options.GetName().empty()) { + m_options.attach_info.SetProcessPluginName("ScriptedProcess"); + m_options.attach_info.SetScriptedProcessClassName( + m_class_options.GetName()); + m_options.attach_info.SetScriptedProcessDictionarySP( + m_class_options.GetStructuredData()); + } + // Record the old executable module, we want to issue a warning if the // process of attaching changed the current executable (like somebody said // "file foo" then attached to a PID whose executable was bar.) @@ -482,7 +434,9 @@ return result.Succeeded(); } - CommandOptions m_options; + CommandOptionsProcessAttach m_options; + OptionGroupPythonClassWithDict m_class_options; + OptionGroupOptions m_all_options; }; // CommandObjectProcessContinue Index: lldb/source/Commands/CommandOptionsProcessAttach.h =================================================================== --- /dev/null +++ lldb/source/Commands/CommandOptionsProcessAttach.h @@ -0,0 +1,47 @@ +//===-- CommandOptionsProcessAttach.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSATTACH_H +#define LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSATTACH_H + +#include "lldb/Interpreter/Options.h" +#include "lldb/Target/Process.h" + +namespace lldb_private { + +// CommandOptionsProcessAttach + +class CommandOptionsProcessAttach : public lldb_private::OptionGroup { +public: + CommandOptionsProcessAttach() { + // Keep default values of all options in one place: OptionParsingStarting + // () + OptionParsingStarting(nullptr); + } + + ~CommandOptionsProcessAttach() override = default; + + lldb_private::Status + SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + lldb_private::ExecutionContext *execution_context) override; + + void OptionParsingStarting( + lldb_private::ExecutionContext *execution_context) override { + attach_info.Clear(); + } + + llvm::ArrayRef GetDefinitions() override; + + // Instance variables to hold the values for command options. + + lldb_private::ProcessAttachInfo attach_info; +}; // CommandOptionsProcessAttach + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSATTACH_H Index: lldb/source/Commands/CommandOptionsProcessAttach.cpp =================================================================== --- /dev/null +++ lldb/source/Commands/CommandOptionsProcessAttach.cpp @@ -0,0 +1,76 @@ +//===-- CommandOptionsProcessAttach.cpp -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "CommandOptionsProcessAttach.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandOptionArgumentTable.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/ArrayRef.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_process_attach +#include "CommandOptions.inc" + +Status CommandOptionsProcessAttach::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = g_process_attach_options[option_idx].short_option; + switch (short_option) { + case 'c': + attach_info.SetContinueOnceAttached(true); + break; + + case 'p': { + lldb::pid_t pid; + if (option_arg.getAsInteger(0, pid)) { + error.SetErrorStringWithFormat("invalid process ID '%s'", + option_arg.str().c_str()); + } else { + attach_info.SetProcessID(pid); + } + } break; + + case 'P': + attach_info.SetProcessPluginName(option_arg); + break; + + case 'n': + attach_info.GetExecutableFile().SetFile(option_arg, + FileSpec::Style::native); + break; + + case 'w': + attach_info.SetWaitForLaunch(true); + break; + + case 'i': + attach_info.SetIgnoreExisting(false); + break; + + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +llvm::ArrayRef CommandOptionsProcessAttach::GetDefinitions() { + return llvm::makeArrayRef(g_process_attach_options); +}