diff options
Diffstat (limited to 'lldb')
134 files changed, 3164 insertions, 609 deletions
diff --git a/lldb/bindings/python/python-wrapper.swig b/lldb/bindings/python/python-wrapper.swig index 3d1d04e..2c30d53 100644 --- a/lldb/bindings/python/python-wrapper.swig +++ b/lldb/bindings/python/python-wrapper.swig @@ -229,78 +229,6 @@ PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject return pfunc(SWIGBridge::ToSWIGWrapper(std::move(debugger_sp)), dict); } -PythonObject lldb_private::python::SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( - const char *python_class_name, const char *session_dictionary_name, - const StructuredDataImpl &args_impl, - const lldb::BreakpointSP &breakpoint_sp) { - - if (python_class_name == NULL || python_class_name[0] == '\0' || - !session_dictionary_name) - return PythonObject(); - - PyErr_Cleaner py_err_cleaner(true); - - auto dict = PythonModule::MainModule().ResolveName<PythonDictionary>( - session_dictionary_name); - auto pfunc = PythonObject::ResolveNameWithDictionary<PythonCallable>( - python_class_name, dict); - - if (!pfunc.IsAllocated()) - return PythonObject(); - - PythonObject result = - pfunc(SWIGBridge::ToSWIGWrapper(breakpoint_sp), SWIGBridge::ToSWIGWrapper(args_impl), dict); - // FIXME: At this point we should check that the class we found supports all - // the methods that we need. - - if (result.IsAllocated()) { - // Check that __callback__ is defined: - auto callback_func = result.ResolveName<PythonCallable>("__callback__"); - if (callback_func.IsAllocated()) - return result; - } - return PythonObject(); -} - -unsigned int lldb_private::python::SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - void *implementor, const char *method_name, - lldb_private::SymbolContext *sym_ctx) { - PyErr_Cleaner py_err_cleaner(false); - PythonObject self(PyRefType::Borrowed, static_cast<PyObject *>(implementor)); - auto pfunc = self.ResolveName<PythonCallable>(method_name); - - if (!pfunc.IsAllocated()) - return 0; - - PythonObject result = sym_ctx ? pfunc(SWIGBridge::ToSWIGWrapper(*sym_ctx)) : pfunc(); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return 0; - } - - // The callback will return a bool, but we're need to also return ints - // so we're squirrelling the bool through as an int... And if you return - // nothing, we'll continue. - if (strcmp(method_name, "__callback__") == 0) { - if (result.get() == Py_False) - return 0; - else - return 1; - } - - long long ret_val = unwrapOrSetPythonException(As<long long>(result)); - - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - return 0; - } - - return ret_val; -} - // wrapper that calls an optional instance member of an object taking no // arguments static PyObject *LLDBSwigPython_CallOptionalMember( @@ -554,6 +482,18 @@ void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBStream(PyObject * dat return sb_ptr; } +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject * data) { + lldb::SBSymbolContext *sb_ptr = nullptr; + + int valid_cast = + SWIG_ConvertPtr(data, (void **)&sb_ptr, SWIGTYPE_p_lldb__SBSymbolContext, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBValue(PyObject * data) { lldb::SBValue *sb_ptr = NULL; diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 8c30b6e..fc84e58 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -323,4 +323,30 @@ else() set(LLDB_CAN_USE_DEBUGSERVER OFF) endif() +# In a cross-compile build, we need to skip building the generated +# lldb-rpc sources in the first phase of host build so that they can +# get built using the just-built Clang toolchain in the second phase. +if (NOT DEFINED LLDB_CAN_USE_LLDB_RPC_SERVER) + set(LLDB_CAN_USE_LLDB_RPC_SERVER OFF) +else() + if ((CMAKE_CROSSCOMPILING OR LLVM_HOST_TRIPLE MATCHES "${LLVM_DEFAULT_TARGET_TRIPLE}") AND + CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows") + set(LLDB_CAN_USE_LLDB_RPC_SERVER ON) + else() + set(LLDB_CAN_USE_LLDB_RPC_SERVER OFF) + endif() +endif() + + +if (NOT DEFINED LLDB_BUILD_LLDBRPC) + set(LLDB_BUILD_LLDBRPC OFF) +else() + if (CMAKE_CROSSCOMPILING) + set(LLDB_BUILD_LLDBRPC OFF CACHE BOOL "") + get_host_tool_path(lldb-rpc-gen LLDB_RPC_GEN_EXE lldb_rpc_gen_exe lldb_rpc_gen_target) + else() + set(LLDB_BUILD_LLDBRPC ON CACHE BOOL "") + endif() +endif() + include(LLDBGenerateConfig) diff --git a/lldb/docs/index.rst b/lldb/docs/index.rst index d49d0d8..a981c0a 100644 --- a/lldb/docs/index.rst +++ b/lldb/docs/index.rst @@ -86,6 +86,7 @@ current state, follow the links to their respective issues: * `RISC-V <https://github.com/llvm/llvm-project/issues/55383>`_ * `LoongArch <https://github.com/llvm/llvm-project/issues/112693>`_ +* `WebAssembly <https://github.com/llvm/llvm-project/issues/150449>`_ Get Involved ------------ diff --git a/lldb/docs/resources/build.rst b/lldb/docs/resources/build.rst index 4bbec89..0db8c92 100644 --- a/lldb/docs/resources/build.rst +++ b/lldb/docs/resources/build.rst @@ -204,12 +204,13 @@ checked out above, but now we will have multiple build-trees: Run CMake with ``-B`` pointing to a new directory for the provided build-tree\ :sup:`1` and the positional argument pointing to the ``llvm`` -directory in the source-tree. Note that we leave out LLDB here and only include +directory in the source-tree.\ :sup:`2` Note that we leave out LLDB here and only include Clang. Then we build the ``ALL`` target with ninja: :: $ cmake -B /path/to/llvm-build -G Ninja \ + -DCMAKE_BUILD_TYPE=[<build type>] \ -DLLVM_ENABLE_PROJECTS=clang \ -DCMAKE_BUILD_TYPE=Release \ [<more cmake options>] /path/to/llvm-project/llvm @@ -238,6 +239,8 @@ remove it from the Ninja command. #. The ``-B`` argument was undocumented for a while and is only officially supported since `CMake version 3.14 <https://cmake.org/cmake/help/v3.14/release/3.14.html#command-line>`_ + #. If you want to have a standalone LLDB build with tests enabled, you also + need to pass in ``-DLLVM_ENABLE_RUNTIME='libcxx;libcxxabi;libunwind'`` to your CMake invocation when configuring your LLVM standalone build. .. _CommonCMakeOptions: diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md index 80c6809..41628cf 100644 --- a/lldb/docs/resources/lldbgdbremote.md +++ b/lldb/docs/resources/lldbgdbremote.md @@ -1998,6 +1998,22 @@ threads (live system debug) / cores (JTAG) in your program have stopped and allows LLDB to display and control your program correctly. +## qWasmCallStack + +Get the Wasm call stack for the given thread id. This returns a hex-encoded +list of PC values, one for each frame of the call stack. To match the Wasm +specification, the addresses are encoded in little endian byte order, even if +the endian of the Wasm runtime's host is not little endian. + +``` +send packet: $qWasmCallStack:202dbe040#08 +read packet: $9c01000000000040e501000000000040fe01000000000040# +``` + +**Priority to Implement:** Only required for Wasm support. This packed is +supported by the [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) +and [V8](https://v8.dev) Wasm runtimes. + ## qWatchpointSupportInfo Get the number of hardware watchpoints available on the remote target. diff --git a/lldb/include/lldb/API/SBSymbolContext.h b/lldb/include/lldb/API/SBSymbolContext.h index ae9fd84..128b0b6 100644 --- a/lldb/include/lldb/API/SBSymbolContext.h +++ b/lldb/include/lldb/API/SBSymbolContext.h @@ -80,6 +80,8 @@ protected: lldb_private::SymbolContext *get() const; + friend class lldb_private::ScriptInterpreter; + private: std::unique_ptr<lldb_private::SymbolContext> m_opaque_up; }; diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h index 0e4a1d7..0322fd9 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverScripted.h @@ -12,6 +12,7 @@ #include "lldb/Breakpoint/BreakpointResolver.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h" #include "lldb/lldb-forward.h" namespace lldb_private { @@ -64,7 +65,8 @@ private: std::string m_class_name; lldb::SearchDepth m_depth; StructuredDataImpl m_args; - StructuredData::GenericSP m_implementation_sp; + Status m_error; + lldb::ScriptedBreakpointInterfaceSP m_interface_sp; BreakpointResolverScripted(const BreakpointResolverScripted &) = delete; const BreakpointResolverScripted & diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 909ee08..d5e291f3 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -17,6 +17,7 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" +#include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseSet.h" @@ -488,8 +489,9 @@ public: /// be non-null. /// /// This function is thread-safe. - void ForEach(std::function<bool(const lldb::ModuleSP &module_sp)> const - &callback) const; + void + ForEach(std::function<IterationAction(const lldb::ModuleSP &module_sp)> const + &callback) const; /// Returns true if 'callback' returns true for one of the modules /// in this ModuleList. diff --git a/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h new file mode 100644 index 0000000..28d6ed9 --- /dev/null +++ b/lldb/include/lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// 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_INTERPRETER_INTERFACES_SCRIPTEDBREAKPOINTINTERFACE_H +#define LLDB_INTERPRETER_INTERFACES_SCRIPTEDBREAKPOINTINTERFACE_H + +#include "ScriptedInterface.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { +class ScriptedBreakpointInterface : public ScriptedInterface { +public: + virtual llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, lldb::BreakpointSP break_sp, + const StructuredDataImpl &args_sp) = 0; + + /// "ResolverCallback" will get called when a new module is loaded. The + /// new module information is passed in sym_ctx. The Resolver will add + /// any breakpoint locations it found in that module. + virtual bool ResolverCallback(SymbolContext sym_ctx) { return true; } + virtual lldb::SearchDepth GetDepth() { return lldb::eSearchDepthModule; } + virtual std::optional<std::string> GetShortHelp() { return nullptr; } +}; +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_INTERFACES_SCRIPTEDSTOPHOOKINTERFACE_H diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index f1c3eef..dffb9b8 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -18,6 +18,7 @@ #include "lldb/API/SBLaunchInfo.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBSymbolContext.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/SearchFilter.h" @@ -29,6 +30,7 @@ #include "lldb/Interpreter/Interfaces/ScriptedProcessInterface.h" #include "lldb/Interpreter/Interfaces/ScriptedThreadInterface.h" #include "lldb/Interpreter/ScriptObject.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StructuredData.h" @@ -257,26 +259,6 @@ public: return false; } - virtual StructuredData::GenericSP - CreateScriptedBreakpointResolver(const char *class_name, - const StructuredDataImpl &args_data, - lldb::BreakpointSP &bkpt_sp) { - return StructuredData::GenericSP(); - } - - virtual bool - ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP implementor_sp, - SymbolContext *sym_ctx) - { - return false; - } - - virtual lldb::SearchDepth - ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP implementor_sp) - { - return lldb::eSearchDepthModule; - } - virtual StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { return StructuredData::ObjectSP(); @@ -566,6 +548,11 @@ public: return {}; } + virtual lldb::ScriptedBreakpointInterfaceSP + CreateScriptedBreakpointInterface() { + return {}; + } + virtual StructuredData::ObjectSP CreateStructuredDataFromScriptObject(ScriptObject obj) { return {}; @@ -580,6 +567,9 @@ public: lldb::StreamSP GetOpaqueTypeFromSBStream(const lldb::SBStream &stream) const; + SymbolContext + GetOpaqueTypeFromSBSymbolContext(const lldb::SBSymbolContext &sym_ctx) const; + lldb::BreakpointSP GetOpaqueTypeFromSBBreakpoint(const lldb::SBBreakpoint &breakpoint) const; diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 637b077..7e66e31 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2619,7 +2619,7 @@ void PruneThreadPlans(); void ResetExtendedCrashInfoDict() { // StructuredData::Dictionary is add only, so we have to make a new one: - m_crash_info_dict_sp.reset(new StructuredData::Dictionary()); + m_crash_info_dict_sp = std::make_shared<StructuredData::Dictionary>(); } size_t AddImageToken(lldb::addr_t image_ptr); diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h index 8a66296..e5a6e942 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -174,6 +174,11 @@ protected: /// change the frame if this is the first time GetSelectedFrame is called. std::optional<uint32_t> m_selected_frame_idx; + /// Protect access to m_selected_frame_idx. Always acquire after m_list_mutex + /// to avoid lock inversion. A recursive mutex because GetSelectedFrameIndex + /// may indirectly call SetSelectedFrame. + std::recursive_mutex m_selected_frame_mutex; + /// The number of concrete frames fetched while filling the frame list. This /// is only used when synthetic frames are enabled. uint32_t m_concrete_frames_fetched; diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 2bc85a2..483dce9 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -188,6 +188,7 @@ class Scalar; class ScriptInterpreter; class ScriptInterpreterLocker; class ScriptedMetadata; +class ScriptedBreakpointInterface; class ScriptedPlatformInterface; class ScriptedProcessInterface; class ScriptedStopHookInterface; @@ -418,6 +419,8 @@ typedef std::shared_ptr<lldb_private::ScriptedThreadInterface> ScriptedThreadInterfaceSP; typedef std::shared_ptr<lldb_private::ScriptedThreadPlanInterface> ScriptedThreadPlanInterfaceSP; +typedef std::shared_ptr<lldb_private::ScriptedBreakpointInterface> + ScriptedBreakpointInterfaceSP; typedef std::shared_ptr<lldb_private::Section> SectionSP; typedef std::unique_ptr<lldb_private::SectionList> SectionListUP; typedef std::weak_ptr<lldb_private::Section> SectionWP; diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index 90c8e32..24236e7 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -294,9 +294,11 @@ def parseOptionsAndInitTestdirs(): "Custom libc++ requires both --libcxx-include-dir and --libcxx-library-dir" ) sys.exit(-1) - configuration.libcxx_include_dir = args.libcxx_include_dir - configuration.libcxx_include_target_dir = args.libcxx_include_target_dir - configuration.libcxx_library_dir = args.libcxx_library_dir + else: + configuration.libcxx_include_dir = args.libcxx_include_dir + configuration.libcxx_include_target_dir = args.libcxx_include_target_dir + configuration.libcxx_library_dir = args.libcxx_library_dir + configuration.cmake_build_type = args.cmake_build_type.lower() if args.channels: diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py index 459460b..599f787 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py +++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py @@ -45,7 +45,7 @@ class GDBRemoteTestBase(TestBase): self.yaml2obj(yaml_path, obj_path) return self.dbg.CreateTarget(obj_path) - def connect(self, target): + def connect(self, target, plugin="gdb-remote"): """ Create a process by connecting to the mock GDB server. @@ -54,7 +54,7 @@ class GDBRemoteTestBase(TestBase): listener = self.dbg.GetListener() error = lldb.SBError() process = target.ConnectRemote( - listener, self.server.get_connect_url(), "gdb-remote", error + listener, self.server.get_connect_url(), plugin, error ) self.assertTrue(error.Success(), error.description) self.assertTrue(process, PROCESS_IS_VALID) diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 63fadb5..a74961e 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1380,6 +1380,9 @@ class Base(unittest.TestCase): def isAArch64MTE(self): return self.isAArch64() and "mte" in self.getCPUInfo() + def isAArch64MTEStoreOnly(self): + return self.isAArch64() and "mtestoreonly" in self.getCPUInfo() + def isAArch64GCS(self): return self.isAArch64() and "gcs" in self.getCPUInfo() diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index 197c98c..fdd6b3b 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -302,7 +302,7 @@ list(REMOVE_ITEM root_public_headers ${root_private_headers}) find_program(unifdef_EXECUTABLE unifdef) -add_custom_target(liblldb-header-staging DEPENDS ${lldb_staged_headers} ${lldb_header_staging_dir}/lldb-defines.h) +add_custom_target(liblldb-header-staging) if (LLDB_BUILD_FRAMEWORK) add_custom_target(lldb-framework-fixup-all-headers) @@ -326,6 +326,9 @@ foreach(header set(copy_command ${CMAKE_COMMAND} -E copy ${header} ${staged_header}) endif() + add_custom_target(liblldb-stage-header-${basename} DEPENDS ${staged_header}) + add_dependencies(liblldb-stage-header-${basename} lldb-sbapi-dwarf-enums) + add_dependencies(liblldb-header-staging liblldb-stage-header-${basename}) add_custom_command( DEPENDS ${header} OUTPUT ${staged_header} COMMAND ${copy_command} @@ -337,6 +340,7 @@ foreach(header set(output_header $<TARGET_FILE_DIR:liblldb>/Headers/${basename}) add_custom_target(lldb-framework-fixup-header-${basename} DEPENDS ${staged_header}) + add_dependencies(lldb-framework-fixup-header-${basename} liblldb-stage-header-${basename}) add_dependencies(lldb-framework-fixup-all-headers lldb-framework-fixup-header-${basename}) add_custom_command(TARGET lldb-framework-fixup-header-${basename} POST_BUILD diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp index 00f2871..f58902d 100644 --- a/lldb/source/API/SBType.cpp +++ b/lldb/source/API/SBType.cpp @@ -184,7 +184,7 @@ SBType SBType::GetPointerType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetPointerType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetPointerType())); } SBType SBType::GetPointeeType() { @@ -192,7 +192,7 @@ SBType SBType::GetPointeeType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetPointeeType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetPointeeType())); } SBType SBType::GetReferenceType() { @@ -200,7 +200,7 @@ SBType SBType::GetReferenceType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetReferenceType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetReferenceType())); } SBType SBType::GetTypedefedType() { @@ -208,7 +208,7 @@ SBType SBType::GetTypedefedType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetTypedefedType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetTypedefedType())); } SBType SBType::GetDereferencedType() { @@ -216,7 +216,7 @@ SBType SBType::GetDereferencedType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetDereferencedType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetDereferencedType())); } SBType SBType::GetArrayElementType() { @@ -224,8 +224,8 @@ SBType SBType::GetArrayElementType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl( - m_opaque_sp->GetCompilerType(true).GetArrayElementType(nullptr)))); + return SBType(std::make_shared<TypeImpl>( + m_opaque_sp->GetCompilerType(true).GetArrayElementType(nullptr))); } SBType SBType::GetArrayType(uint64_t size) { @@ -233,8 +233,8 @@ SBType SBType::GetArrayType(uint64_t size) { if (!IsValid()) return SBType(); - return SBType(TypeImplSP( - new TypeImpl(m_opaque_sp->GetCompilerType(true).GetArrayType(size)))); + return SBType(std::make_shared<TypeImpl>( + m_opaque_sp->GetCompilerType(true).GetArrayType(size))); } SBType SBType::GetVectorElementType() { @@ -245,7 +245,7 @@ SBType SBType::GetVectorElementType() { CompilerType vector_element_type; if (m_opaque_sp->GetCompilerType(true).IsVectorType(&vector_element_type, nullptr)) - type_sb.SetSP(TypeImplSP(new TypeImpl(vector_element_type))); + type_sb.SetSP(std::make_shared<TypeImpl>(vector_element_type)); } return type_sb; } @@ -421,14 +421,14 @@ lldb::SBType SBType::GetUnqualifiedType() { if (!IsValid()) return SBType(); - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetUnqualifiedType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetUnqualifiedType())); } lldb::SBType SBType::GetCanonicalType() { LLDB_INSTRUMENT_VA(this); if (IsValid()) - return SBType(TypeImplSP(new TypeImpl(m_opaque_sp->GetCanonicalType()))); + return SBType(std::make_shared<TypeImpl>(m_opaque_sp->GetCanonicalType())); return SBType(); } @@ -508,7 +508,7 @@ SBTypeMember SBType::GetDirectBaseClassAtIndex(uint32_t idx) { idx, &bit_offset); if (base_class_type.IsValid()) sb_type_member.reset(new TypeMemberImpl( - TypeImplSP(new TypeImpl(base_class_type)), bit_offset)); + std::make_shared<TypeImpl>(base_class_type), bit_offset)); } return sb_type_member; } @@ -524,7 +524,7 @@ SBTypeMember SBType::GetVirtualBaseClassAtIndex(uint32_t idx) { idx, &bit_offset); if (base_class_type.IsValid()) sb_type_member.reset(new TypeMemberImpl( - TypeImplSP(new TypeImpl(base_class_type)), bit_offset)); + std::make_shared<TypeImpl>(base_class_type), bit_offset)); } return sb_type_member; } @@ -546,16 +546,15 @@ SBTypeEnumMemberList SBType::GetEnumMembers() { if (IsValid()) { CompilerType this_type(m_opaque_sp->GetCompilerType(true)); if (this_type.IsValid()) { - this_type.ForEachEnumerator([&sb_enum_member_list]( - const CompilerType &integer_type, - ConstString name, - const llvm::APSInt &value) -> bool { - SBTypeEnumMember enum_member( - lldb::TypeEnumMemberImplSP(new TypeEnumMemberImpl( - lldb::TypeImplSP(new TypeImpl(integer_type)), name, value))); - sb_enum_member_list.Append(enum_member); - return true; // Keep iterating - }); + this_type.ForEachEnumerator( + [&sb_enum_member_list](const CompilerType &integer_type, + ConstString name, + const llvm::APSInt &value) -> bool { + SBTypeEnumMember enum_member(std::make_shared<TypeEnumMemberImpl>( + std::make_shared<TypeImpl>(integer_type), name, value)); + sb_enum_member_list.Append(enum_member); + return true; // Keep iterating + }); } } return sb_enum_member_list; @@ -578,9 +577,9 @@ SBTypeMember SBType::GetFieldAtIndex(uint32_t idx) { ConstString name; if (!name_sstr.empty()) name.SetCString(name_sstr.c_str()); - sb_type_member.reset( - new TypeMemberImpl(TypeImplSP(new TypeImpl(field_type)), bit_offset, - name, bitfield_bit_size, is_bitfield)); + sb_type_member.reset(new TypeMemberImpl( + std::make_shared<TypeImpl>(field_type), bit_offset, name, + bitfield_bit_size, is_bitfield)); } } } @@ -978,7 +977,7 @@ SBType SBTypeMemberFunction::GetType() { SBType sb_type; if (m_opaque_sp) { - sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetType()))); + sb_type.SetSP(std::make_shared<TypeImpl>(m_opaque_sp->GetType())); } return sb_type; } @@ -988,7 +987,7 @@ lldb::SBType SBTypeMemberFunction::GetReturnType() { SBType sb_type; if (m_opaque_sp) { - sb_type.SetSP(lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetReturnType()))); + sb_type.SetSP(std::make_shared<TypeImpl>(m_opaque_sp->GetReturnType())); } return sb_type; } @@ -1007,7 +1006,7 @@ lldb::SBType SBTypeMemberFunction::GetArgumentTypeAtIndex(uint32_t i) { SBType sb_type; if (m_opaque_sp) { sb_type.SetSP( - lldb::TypeImplSP(new TypeImpl(m_opaque_sp->GetArgumentAtIndex(i)))); + std::make_shared<TypeImpl>(m_opaque_sp->GetArgumentAtIndex(i))); } return sb_type; } diff --git a/lldb/source/API/SBTypeFilter.cpp b/lldb/source/API/SBTypeFilter.cpp index f1b5bc9..e10d269 100644 --- a/lldb/source/API/SBTypeFilter.cpp +++ b/lldb/source/API/SBTypeFilter.cpp @@ -19,7 +19,7 @@ using namespace lldb_private; SBTypeFilter::SBTypeFilter() { LLDB_INSTRUMENT_VA(this); } SBTypeFilter::SBTypeFilter(uint32_t options) - : m_opaque_sp(TypeFilterImplSP(new TypeFilterImpl(options))) { + : m_opaque_sp(std::make_shared<TypeFilterImpl>(options)) { LLDB_INSTRUMENT_VA(this, options); } diff --git a/lldb/source/API/SBTypeNameSpecifier.cpp b/lldb/source/API/SBTypeNameSpecifier.cpp index 308b1cd..dd81720 100644 --- a/lldb/source/API/SBTypeNameSpecifier.cpp +++ b/lldb/source/API/SBTypeNameSpecifier.cpp @@ -38,8 +38,8 @@ SBTypeNameSpecifier::SBTypeNameSpecifier(SBType type) { LLDB_INSTRUMENT_VA(this, type); if (type.IsValid()) - m_opaque_sp = TypeNameSpecifierImplSP( - new TypeNameSpecifierImpl(type.m_opaque_sp->GetCompilerType(true))); + m_opaque_sp = std::make_shared<TypeNameSpecifierImpl>( + type.m_opaque_sp->GetCompilerType(true)); } SBTypeNameSpecifier::SBTypeNameSpecifier(const lldb::SBTypeNameSpecifier &rhs) diff --git a/lldb/source/API/SBTypeSynthetic.cpp b/lldb/source/API/SBTypeSynthetic.cpp index 19a4c53..5ebc884 100644 --- a/lldb/source/API/SBTypeSynthetic.cpp +++ b/lldb/source/API/SBTypeSynthetic.cpp @@ -24,8 +24,8 @@ SBTypeSynthetic SBTypeSynthetic::CreateWithClassName(const char *data, if (!data || data[0] == 0) return SBTypeSynthetic(); - return SBTypeSynthetic(ScriptedSyntheticChildrenSP( - new ScriptedSyntheticChildren(options, data, ""))); + return SBTypeSynthetic( + std::make_shared<ScriptedSyntheticChildren>(options, data, "")); } SBTypeSynthetic SBTypeSynthetic::CreateWithScriptCode(const char *data, @@ -34,8 +34,8 @@ SBTypeSynthetic SBTypeSynthetic::CreateWithScriptCode(const char *data, if (!data || data[0] == 0) return SBTypeSynthetic(); - return SBTypeSynthetic(ScriptedSyntheticChildrenSP( - new ScriptedSyntheticChildren(options, "", data))); + return SBTypeSynthetic( + std::make_shared<ScriptedSyntheticChildren>(options, "", data)); } SBTypeSynthetic::SBTypeSynthetic(const lldb::SBTypeSynthetic &rhs) diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index d878eb4..e300ece 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -1120,11 +1120,11 @@ void SBValue::SetSP(const lldb::ValueObjectSP &sp) { lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue(); bool use_synthetic = target_sp->TargetProperties::GetEnableSyntheticValue(); - m_opaque_sp = ValueImplSP(new ValueImpl(sp, use_dynamic, use_synthetic)); + m_opaque_sp = std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic); } else - m_opaque_sp = ValueImplSP(new ValueImpl(sp, eNoDynamicValues, true)); + m_opaque_sp = std::make_shared<ValueImpl>(sp, eNoDynamicValues, true); } else - m_opaque_sp = ValueImplSP(new ValueImpl(sp, eNoDynamicValues, false)); + m_opaque_sp = std::make_shared<ValueImpl>(sp, eNoDynamicValues, false); } void SBValue::SetSP(const lldb::ValueObjectSP &sp, @@ -1155,14 +1155,14 @@ void SBValue::SetSP(const lldb::ValueObjectSP &sp, bool use_synthetic) { void SBValue::SetSP(const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic) { - m_opaque_sp = ValueImplSP(new ValueImpl(sp, use_dynamic, use_synthetic)); + m_opaque_sp = std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic); } void SBValue::SetSP(const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic, const char *name) { m_opaque_sp = - ValueImplSP(new ValueImpl(sp, use_dynamic, use_synthetic, name)); + std::make_shared<ValueImpl>(sp, use_dynamic, use_synthetic, name); } bool SBValue::GetExpressionPath(SBStream &description) { diff --git a/lldb/source/Breakpoint/Breakpoint.cpp b/lldb/source/Breakpoint/Breakpoint.cpp index d757bc4..1544bf8 100644 --- a/lldb/source/Breakpoint/Breakpoint.cpp +++ b/lldb/source/Breakpoint/Breakpoint.cpp @@ -83,8 +83,7 @@ StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() { if (!m_name_list.empty()) { StructuredData::ArraySP names_array_sp(new StructuredData::Array()); for (auto name : m_name_list) { - names_array_sp->AddItem( - StructuredData::StringSP(new StructuredData::String(name))); + names_array_sp->AddItem(std::make_shared<StructuredData::String>(name)); } breakpoint_contents_sp->AddItem(Breakpoint::GetKey(OptionNames::Names), names_array_sp); diff --git a/lldb/source/Breakpoint/BreakpointResolverName.cpp b/lldb/source/Breakpoint/BreakpointResolverName.cpp index edde1c9..21024a4 100644 --- a/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -195,10 +195,10 @@ StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() { StructuredData::ArraySP names_sp(new StructuredData::Array()); StructuredData::ArraySP name_masks_sp(new StructuredData::Array()); for (auto lookup : m_lookups) { - names_sp->AddItem(StructuredData::StringSP( - new StructuredData::String(lookup.GetName().GetStringRef()))); - name_masks_sp->AddItem(StructuredData::UnsignedIntegerSP( - new StructuredData::UnsignedInteger(lookup.GetNameTypeMask()))); + names_sp->AddItem(std::make_shared<StructuredData::String>( + lookup.GetName().GetStringRef())); + name_masks_sp->AddItem(std::make_shared<StructuredData::UnsignedInteger>( + lookup.GetNameTypeMask())); } options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp); options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp); diff --git a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp index 2457052..701caba 100644 --- a/lldb/source/Breakpoint/BreakpointResolverScripted.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverScripted.cpp @@ -35,7 +35,7 @@ BreakpointResolverScripted::BreakpointResolverScripted( void BreakpointResolverScripted::CreateImplementationIfNeeded( BreakpointSP breakpoint_sp) { - if (m_implementation_sp) + if (m_interface_sp) return; if (m_class_name.empty()) @@ -50,8 +50,27 @@ void BreakpointResolverScripted::CreateImplementationIfNeeded( if (!script_interp) return; - m_implementation_sp = script_interp->CreateScriptedBreakpointResolver( - m_class_name.c_str(), m_args, breakpoint_sp); + m_interface_sp = script_interp->CreateScriptedBreakpointInterface(); + if (!m_interface_sp) { + m_error = Status::FromErrorStringWithFormat( + "BreakpointResolverScripted::%s () - ERROR: %s", __FUNCTION__, + "Script interpreter couldn't create Scripted Breakpoint Interface"); + return; + } + + auto obj_or_err = + m_interface_sp->CreatePluginObject(m_class_name, breakpoint_sp, m_args); + if (!obj_or_err) { + m_error = Status::FromError(obj_or_err.takeError()); + return; + } + + StructuredData::ObjectSP object_sp = *obj_or_err; + if (!object_sp || !object_sp->IsValid()) { + m_error = Status::FromErrorStringWithFormat( + "ScriptedBreakpoint::%s () - ERROR: %s", __FUNCTION__, + "Failed to create valid script object"); + } } void BreakpointResolverScripted::NotifyBreakpointSet() { @@ -104,13 +123,10 @@ ScriptInterpreter *BreakpointResolverScripted::GetScriptInterpreter() { Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback( SearchFilter &filter, SymbolContext &context, Address *addr) { bool should_continue = true; - if (!m_implementation_sp) + if (!m_interface_sp) return Searcher::eCallbackReturnStop; - ScriptInterpreter *interp = GetScriptInterpreter(); - should_continue = interp->ScriptedBreakpointResolverSearchCallback( - m_implementation_sp, - &context); + should_continue = m_interface_sp->ResolverCallback(context); if (should_continue) return Searcher::eCallbackReturnContinue; @@ -120,25 +136,21 @@ Searcher::CallbackReturn BreakpointResolverScripted::SearchCallback( lldb::SearchDepth BreakpointResolverScripted::GetDepth() { lldb::SearchDepth depth = lldb::eSearchDepthModule; - if (m_implementation_sp) { - ScriptInterpreter *interp = GetScriptInterpreter(); - depth = interp->ScriptedBreakpointResolverSearchDepth( - m_implementation_sp); - } + if (m_interface_sp) + depth = m_interface_sp->GetDepth(); + return depth; } void BreakpointResolverScripted::GetDescription(Stream *s) { StructuredData::GenericSP generic_sp; - std::string short_help; + std::optional<std::string> short_help; - if (m_implementation_sp) { - ScriptInterpreter *interp = GetScriptInterpreter(); - interp->GetShortHelpForCommandObject(m_implementation_sp, - short_help); + if (m_interface_sp) { + short_help = m_interface_sp->GetShortHelp(); } - if (!short_help.empty()) - s->PutCString(short_help.c_str()); + if (short_help && !short_help->empty()) + s->PutCString(short_help->c_str()); else s->Printf("python class = %s", m_class_name.c_str()); } diff --git a/lldb/source/Commands/CommandCompletions.cpp b/lldb/source/Commands/CommandCompletions.cpp index 3e22309..b2fc893 100644 --- a/lldb/source/Commands/CommandCompletions.cpp +++ b/lldb/source/Commands/CommandCompletions.cpp @@ -571,7 +571,7 @@ void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter, lldb::eDescriptionLevelInitial); request.TryCompleteCurrentArg(module->GetUUID().GetAsString(), strm.GetString()); - return true; + return IterationAction::Continue; }); } diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp index 10dc273..3049eb8 100644 --- a/lldb/source/Commands/CommandObjectCommands.cpp +++ b/lldb/source/Commands/CommandObjectCommands.cpp @@ -25,6 +25,7 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/StringList.h" #include "llvm/ADT/StringRef.h" +#include <memory> #include <optional> using namespace lldb; @@ -467,7 +468,7 @@ protected: // Verify & handle any options/arguments passed to the alias command OptionArgVectorSP option_arg_vector_sp = - OptionArgVectorSP(new OptionArgVector); + std::make_shared<OptionArgVector>(); const bool include_aliases = true; // Look up the command using command's name first. This is to resolve @@ -543,7 +544,7 @@ protected: CommandObject *cmd_obj = command_obj_sp.get(); CommandObject *sub_cmd_obj = nullptr; OptionArgVectorSP option_arg_vector_sp = - OptionArgVectorSP(new OptionArgVector); + std::make_shared<OptionArgVector>(); while (cmd_obj->IsMultiwordObject() && !args.empty()) { auto sub_command = args[0].ref(); @@ -2504,9 +2505,9 @@ protected: CommandObjectSP new_cmd_sp; if (m_options.m_class_name.empty()) { - new_cmd_sp.reset(new CommandObjectPythonFunction( + new_cmd_sp = std::make_shared<CommandObjectPythonFunction>( m_interpreter, m_cmd_name, m_options.m_funct_name, - m_options.m_short_help, m_synchronicity, m_completion_type)); + m_options.m_short_help, m_synchronicity, m_completion_type); } else { ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); if (!interpreter) { @@ -2528,9 +2529,9 @@ protected: if (!result.Succeeded()) return; } else - new_cmd_sp.reset(new CommandObjectScriptingObjectRaw( + new_cmd_sp = std::make_shared<CommandObjectScriptingObjectRaw>( m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity, - m_completion_type)); + m_completion_type); } // Assume we're going to succeed... diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index 7e42ef2..5692699 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -901,10 +901,9 @@ void CommandObjectFrameRecognizerAdd::DoExecute(Args &command, StackFrameRecognizerSP(new ScriptedStackFrameRecognizer( interpreter, m_options.m_class_name.c_str())); if (m_options.m_regex) { - auto module = - RegularExpressionSP(new RegularExpression(m_options.m_module)); + auto module = std::make_shared<RegularExpression>(m_options.m_module); auto func = - RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); + std::make_shared<RegularExpression>(m_options.m_symbols.front()); GetTarget().GetFrameRecognizerManager().AddRecognizer( recognizer_sp, module, func, Mangled::NamePreference::ePreferDemangled, m_options.m_first_instruction_only); diff --git a/lldb/source/Core/IOHandlerCursesGUI.cpp b/lldb/source/Core/IOHandlerCursesGUI.cpp index 7f0e0fc..3976630 100644 --- a/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -22,6 +22,7 @@ #if defined(__APPLE__) #include <deque> #endif +#include <memory> #include <string> #include "lldb/Core/Debugger.h" @@ -6536,7 +6537,7 @@ public: if (process && process->IsAlive() && StateIsStoppedState(process->GetState(), true)) { if (submenus.size() == 7) - menu.AddSubmenu(MenuSP(new Menu(Menu::Type::Separator))); + menu.AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator)); else if (submenus.size() > 8) submenus.erase(submenus.begin() + 8, submenus.end()); @@ -6558,9 +6559,9 @@ public: if (queue_name && queue_name[0]) thread_menu_title.Printf(" %s", queue_name); } - menu.AddSubmenu( - MenuSP(new Menu(thread_menu_title.GetString().str().c_str(), - nullptr, menu_char, thread_sp->GetID()))); + menu.AddSubmenu(std::make_shared<Menu>( + thread_menu_title.GetString().str().c_str(), nullptr, menu_char, + thread_sp->GetID())); } } else if (submenus.size() > 7) { // Remove the separator and any other thread submenu items that were @@ -7573,70 +7574,67 @@ void IOHandlerCursesGUI::Activate() { MenuSP exit_menuitem_sp( new Menu("Exit", nullptr, 'x', ApplicationDelegate::eMenuID_LLDBExit)); exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit); - lldb_menu_sp->AddSubmenu(MenuSP(new Menu( - "About LLDB", nullptr, 'a', ApplicationDelegate::eMenuID_LLDBAbout))); - lldb_menu_sp->AddSubmenu(MenuSP(new Menu(Menu::Type::Separator))); + lldb_menu_sp->AddSubmenu(std::make_shared<Menu>( + "About LLDB", nullptr, 'a', ApplicationDelegate::eMenuID_LLDBAbout)); + lldb_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator)); lldb_menu_sp->AddSubmenu(exit_menuitem_sp); MenuSP target_menu_sp(new Menu("Target", "F2", KEY_F(2), ApplicationDelegate::eMenuID_Target)); - target_menu_sp->AddSubmenu(MenuSP(new Menu( - "Create", nullptr, 'c', ApplicationDelegate::eMenuID_TargetCreate))); - target_menu_sp->AddSubmenu(MenuSP(new Menu( - "Delete", nullptr, 'd', ApplicationDelegate::eMenuID_TargetDelete))); + target_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Create", nullptr, 'c', ApplicationDelegate::eMenuID_TargetCreate)); + target_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Delete", nullptr, 'd', ApplicationDelegate::eMenuID_TargetDelete)); MenuSP process_menu_sp(new Menu("Process", "F3", KEY_F(3), ApplicationDelegate::eMenuID_Process)); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Attach", nullptr, 'a', ApplicationDelegate::eMenuID_ProcessAttach))); - process_menu_sp->AddSubmenu( - MenuSP(new Menu("Detach and resume", nullptr, 'd', - ApplicationDelegate::eMenuID_ProcessDetachResume))); - process_menu_sp->AddSubmenu( - MenuSP(new Menu("Detach suspended", nullptr, 's', - ApplicationDelegate::eMenuID_ProcessDetachSuspended))); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Launch", nullptr, 'l', ApplicationDelegate::eMenuID_ProcessLaunch))); - process_menu_sp->AddSubmenu(MenuSP(new Menu(Menu::Type::Separator))); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Attach", nullptr, 'a', ApplicationDelegate::eMenuID_ProcessAttach)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Detach and resume", nullptr, 'd', + ApplicationDelegate::eMenuID_ProcessDetachResume)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Detach suspended", nullptr, 's', + ApplicationDelegate::eMenuID_ProcessDetachSuspended)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Launch", nullptr, 'l', ApplicationDelegate::eMenuID_ProcessLaunch)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>(Menu::Type::Separator)); process_menu_sp->AddSubmenu( - MenuSP(new Menu("Continue", nullptr, 'c', - ApplicationDelegate::eMenuID_ProcessContinue))); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Halt", nullptr, 'h', ApplicationDelegate::eMenuID_ProcessHalt))); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Kill", nullptr, 'k', ApplicationDelegate::eMenuID_ProcessKill))); + std::make_shared<Menu>("Continue", nullptr, 'c', + ApplicationDelegate::eMenuID_ProcessContinue)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Halt", nullptr, 'h', ApplicationDelegate::eMenuID_ProcessHalt)); + process_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Kill", nullptr, 'k', ApplicationDelegate::eMenuID_ProcessKill)); MenuSP thread_menu_sp(new Menu("Thread", "F4", KEY_F(4), ApplicationDelegate::eMenuID_Thread)); - thread_menu_sp->AddSubmenu(MenuSP(new Menu( - "Step In", nullptr, 'i', ApplicationDelegate::eMenuID_ThreadStepIn))); + thread_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Step In", nullptr, 'i', ApplicationDelegate::eMenuID_ThreadStepIn)); thread_menu_sp->AddSubmenu( - MenuSP(new Menu("Step Over", nullptr, 'v', - ApplicationDelegate::eMenuID_ThreadStepOver))); - thread_menu_sp->AddSubmenu(MenuSP(new Menu( - "Step Out", nullptr, 'o', ApplicationDelegate::eMenuID_ThreadStepOut))); + std::make_shared<Menu>("Step Over", nullptr, 'v', + ApplicationDelegate::eMenuID_ThreadStepOver)); + thread_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Step Out", nullptr, 'o', ApplicationDelegate::eMenuID_ThreadStepOut)); MenuSP view_menu_sp( new Menu("View", "F5", KEY_F(5), ApplicationDelegate::eMenuID_View)); + view_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Backtrace", nullptr, 't', ApplicationDelegate::eMenuID_ViewBacktrace)); + view_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Registers", nullptr, 'r', ApplicationDelegate::eMenuID_ViewRegisters)); + view_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Source", nullptr, 's', ApplicationDelegate::eMenuID_ViewSource)); + view_menu_sp->AddSubmenu(std::make_shared<Menu>( + "Variables", nullptr, 'v', ApplicationDelegate::eMenuID_ViewVariables)); view_menu_sp->AddSubmenu( - MenuSP(new Menu("Backtrace", nullptr, 't', - ApplicationDelegate::eMenuID_ViewBacktrace))); - view_menu_sp->AddSubmenu( - MenuSP(new Menu("Registers", nullptr, 'r', - ApplicationDelegate::eMenuID_ViewRegisters))); - view_menu_sp->AddSubmenu(MenuSP(new Menu( - "Source", nullptr, 's', ApplicationDelegate::eMenuID_ViewSource))); - view_menu_sp->AddSubmenu( - MenuSP(new Menu("Variables", nullptr, 'v', - ApplicationDelegate::eMenuID_ViewVariables))); - view_menu_sp->AddSubmenu( - MenuSP(new Menu("Breakpoints", nullptr, 'b', - ApplicationDelegate::eMenuID_ViewBreakpoints))); + std::make_shared<Menu>("Breakpoints", nullptr, 'b', + ApplicationDelegate::eMenuID_ViewBreakpoints)); MenuSP help_menu_sp( new Menu("Help", "F6", KEY_F(6), ApplicationDelegate::eMenuID_Help)); - help_menu_sp->AddSubmenu(MenuSP(new Menu( - "GUI Help", nullptr, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp))); + help_menu_sp->AddSubmenu(std::make_shared<Menu>( + "GUI Help", nullptr, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp)); m_app_up->Initialize(); WindowSP &main_window_sp = m_app_up->GetMainWindow(); diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index d5ddf6e..d2e5be8 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -1077,12 +1077,12 @@ bool ModuleList::LoadScriptingResourcesInTarget(Target *target, } void ModuleList::ForEach( - std::function<bool(const ModuleSP &module_sp)> const &callback) const { + std::function<IterationAction(const ModuleSP &module_sp)> const &callback) + const { std::lock_guard<std::recursive_mutex> guard(m_modules_mutex); for (const auto &module_sp : m_modules) { assert(module_sp != nullptr); - // If the callback returns false, then stop iterating and break out - if (!callback(module_sp)) + if (callback(module_sp) == IterationAction::Stop) break; } } diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 122f230..7862fb8 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -422,9 +422,8 @@ FormatManager::GetCategory(ConstString category_name, bool can_create) { if (!can_create) return lldb::TypeCategoryImplSP(); - m_categories_map.Add( - category_name, - lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name))); + m_categories_map.Add(category_name, + std::make_shared<TypeCategoryImpl>(this, category_name)); return GetCategory(category_name); } diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index 719264b..9412dd3 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -19,7 +19,7 @@ TypeCategoryMap::TypeCategoryMap(IFormatChangeListener *lst) : m_map_mutex(), listener(lst), m_map(), m_active_categories() { ConstString default_cs("default"); lldb::TypeCategoryImplSP default_sp = - lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs)); + std::make_shared<TypeCategoryImpl>(listener, default_cs); Add(default_cs, default_sp); Enable(default_cs, First); } diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 05fcc4d..c2f8bb3 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -16,6 +16,7 @@ #include "lldb/ValueObject/ValueObject.h" #include "llvm/Support/MathExtras.h" #include <cstdint> +#include <memory> using namespace lldb; using namespace lldb_private; @@ -62,10 +63,9 @@ void ValueObjectPrinter::Init( m_summary.assign(""); m_error.assign(""); m_val_summary_ok = false; - m_printed_instance_pointers = - printed_instance_pointers - ? printed_instance_pointers - : InstancePointersSetSP(new InstancePointersSet()); + m_printed_instance_pointers = printed_instance_pointers + ? printed_instance_pointers + : std::make_shared<InstancePointersSet>(); SetupMostSpecializedValue(); } diff --git a/lldb/source/Host/common/FileSystem.cpp b/lldb/source/Host/common/FileSystem.cpp index 5153a0a9..00919fe 100644 --- a/lldb/source/Host/common/FileSystem.cpp +++ b/lldb/source/Host/common/FileSystem.cpp @@ -35,6 +35,7 @@ #include <algorithm> #include <fstream> +#include <memory> #include <optional> #include <vector> @@ -288,8 +289,7 @@ FileSystem::CreateWritableDataBuffer(const llvm::Twine &path, uint64_t size, is_volatile); if (!buffer) return {}; - return std::shared_ptr<WritableDataBufferLLVM>( - new WritableDataBufferLLVM(std::move(buffer))); + return std::make_shared<WritableDataBufferLLVM>(std::move(buffer)); } std::shared_ptr<DataBuffer> @@ -300,7 +300,7 @@ FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, GetMemoryBuffer<llvm::MemoryBuffer>(path, size, offset, is_volatile); if (!buffer) return {}; - return std::shared_ptr<DataBufferLLVM>(new DataBufferLLVM(std::move(buffer))); + return std::make_shared<DataBufferLLVM>(std::move(buffer)); } std::shared_ptr<WritableDataBuffer> diff --git a/lldb/source/Host/windows/MainLoopWindows.cpp b/lldb/source/Host/windows/MainLoopWindows.cpp index a1de895c..c0b1079 100644 --- a/lldb/source/Host/windows/MainLoopWindows.cpp +++ b/lldb/source/Host/windows/MainLoopWindows.cpp @@ -14,6 +14,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/WindowsError.h" #include <algorithm> +#include <atomic> #include <cassert> #include <ctime> #include <io.h> @@ -222,7 +223,7 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp, if (m_read_fds.find(waitable_handle) != m_read_fds.end()) { error = Status::FromErrorStringWithFormat( - "File descriptor %d already monitored.", waitable_handle); + "File descriptor %p already monitored.", waitable_handle); return nullptr; } @@ -234,7 +235,7 @@ MainLoopWindows::RegisterReadObject(const IOObjectSP &object_sp, } else { DWORD file_type = GetFileType(waitable_handle); if (file_type != FILE_TYPE_PIPE) { - error = Status::FromErrorStringWithFormat("Unsupported file type %d", + error = Status::FromErrorStringWithFormat("Unsupported file type %ld", file_type); return nullptr; } diff --git a/lldb/source/Host/windows/PipeWindows.cpp b/lldb/source/Host/windows/PipeWindows.cpp index 0b495ff..001396f 100644 --- a/lldb/source/Host/windows/PipeWindows.cpp +++ b/lldb/source/Host/windows/PipeWindows.cpp @@ -279,7 +279,8 @@ llvm::Expected<size_t> PipeWindows::Read(void *buf, size_t size, return Status(failure_error, eErrorTypeWin32).takeError(); DWORD timeout_msec = - timeout ? ceil<std::chrono::milliseconds>(*timeout).count() : INFINITE; + timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count() + : INFINITE; DWORD wait_result = ::WaitForSingleObject(m_read_overlapped.hEvent, timeout_msec); if (wait_result != WAIT_OBJECT_0) { @@ -324,7 +325,8 @@ llvm::Expected<size_t> PipeWindows::Write(const void *buf, size_t size, return Status(failure_error, eErrorTypeWin32).takeError(); DWORD timeout_msec = - timeout ? ceil<std::chrono::milliseconds>(*timeout).count() : INFINITE; + timeout ? std::chrono::ceil<std::chrono::milliseconds>(*timeout).count() + : INFINITE; DWORD wait_result = ::WaitForSingleObject(m_write_overlapped.hEvent, timeout_msec); if (wait_result != WAIT_OBJECT_0) { diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index da545f1..a0080cf 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -135,8 +135,7 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, bool synchronous_execution) : Broadcaster(debugger.GetBroadcasterManager(), CommandInterpreter::GetStaticBroadcasterClass().str()), - Properties( - OptionValuePropertiesSP(new OptionValueProperties("interpreter"))), + Properties(std::make_shared<OptionValueProperties>("interpreter")), IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), m_debugger(debugger), m_synchronous_execution(true), m_skip_lldbinit_files(false), m_skip_app_init_files(false), diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index ae913e6..5ee19ff 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -116,6 +116,13 @@ lldb::StreamSP ScriptInterpreter::GetOpaqueTypeFromSBStream( return nullptr; } +SymbolContext ScriptInterpreter::GetOpaqueTypeFromSBSymbolContext( + const lldb::SBSymbolContext &sb_sym_ctx) const { + if (sb_sym_ctx.m_opaque_up) + return *sb_sym_ctx.m_opaque_up.get(); + return {}; +} + std::optional<MemoryRegionInfo> ScriptInterpreter::GetOpaqueTypeFromSBMemoryRegionInfo( const lldb::SBMemoryRegionInfo &mem_region) const { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 6231f0f..47b137a 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -225,7 +225,7 @@ public: ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx); if (context_md_iter == m_metadata_map.end()) { - context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + context_md = std::make_shared<ASTContextMetadata>(dst_ctx); m_metadata_map[dst_ctx] = context_md; } else { context_md = context_md_iter->second; @@ -438,7 +438,7 @@ public: if (context_md_iter == m_metadata_map.end()) { ASTContextMetadataSP context_md = - ASTContextMetadataSP(new ASTContextMetadata(dst_ctx)); + std::make_shared<ASTContextMetadata>(dst_ctx); m_metadata_map[dst_ctx] = context_md; return context_md; } @@ -462,7 +462,7 @@ public: if (delegate_iter == delegates.end()) { ImporterDelegateSP delegate = - ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx)); + std::make_shared<ASTImporterDelegate>(*this, dst_ctx, src_ctx); delegates[src_ctx] = delegate; return delegate; } diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp index 7fe76a6..a5cee5d 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp @@ -23,10 +23,10 @@ lldb::ModuleSP GetPreferredAsanModule(const Target &target) { target.GetImages().ForEach([&](const lldb::ModuleSP &m) { if (pattern.match(m->GetFileSpec().GetFilename().GetStringRef())) { module = m; - return false; + return IterationAction::Stop; } - return true; + return IterationAction::Continue; }); return module; diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index ab9d991..cbc6f14 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -35,7 +35,9 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibStdcppUniquePointer.cpp MsvcStl.cpp MsvcStlAtomic.cpp + MsvcStlDeque.cpp MsvcStlSmartPointer.cpp + MsvcStlTree.cpp MsvcStlTuple.cpp MsvcStlUnordered.cpp MsvcStlVariant.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 80dc460..46753c5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -1363,6 +1363,28 @@ static void RegisterStdStringSummaryProvider( summary_sp); } +static void RegisterStdStringViewSummaryProvider( + const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty, + llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) { + // std::string_view + category_sp->AddTypeSummary( + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + string_ty, eFormatterMatchExact), + summary_sp); + + // std::basic_string_view<char, std::char_traits<char>> + // NativePDB has spaces at different positions compared to PDB and DWARF, so + // use a regex and make them optional. + category_sp->AddTypeSummary( + std::make_shared<lldb_private::TypeNameSpecifierImpl>( + llvm::formatv( + "^std::basic_string_view<{0}, ?std::char_traits<{0}> ?>$", + char_ty) + .str(), + eFormatterMatchRegex), + summary_sp); +} + static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) return; @@ -1409,27 +1431,27 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); cpp_category_sp->AddTypeSynthetic( - "^std::(__debug::)?map<.+> >(( )?&)?$", eFormatterMatchRegex, + "^std::__debug::map<.+> >(( )?&)?$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); cpp_category_sp->AddTypeSynthetic( - "^std::(__debug)?deque<.+>(( )?&)?$", eFormatterMatchRegex, + "^std::__debug::deque<.+>(( )?&)?$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_deref_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider"))); cpp_category_sp->AddTypeSynthetic( - "^std::(__debug::)?set<.+> >(( )?&)?$", eFormatterMatchRegex, + "^std::__debug::set<.+> >(( )?&)?$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_deref_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); cpp_category_sp->AddTypeSynthetic( - "^std::(__debug::)?multimap<.+> >(( )?&)?$", eFormatterMatchRegex, + "^std::__debug::multimap<.+> >(( )?&)?$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_deref_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); cpp_category_sp->AddTypeSynthetic( - "^std::(__debug::)?multiset<.+> >(( )?&)?$", eFormatterMatchRegex, + "^std::__debug::multiset<.+> >(( )?&)?$", eFormatterMatchRegex, SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_deref_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider"))); @@ -1462,30 +1484,29 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libstdc++ std::__debug::vector summary provider", "^std::__debug::vector<.+>(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::map summary provider", - "^std::(__debug::)?map<.+> >(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::ContainerSizeSummaryProvider, + "libstdc++ debug std::map summary provider", + "^std::__debug::map<.+> >(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::set summary provider", - "^std::(__debug::)?set<.+> >(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::ContainerSizeSummaryProvider, + "libstdc++ debug std::set summary provider", + "^std::__debug::set<.+> >(( )?&)?$", stl_summary_flags, true); - AddCXXSummary( - cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::deque summary provider", - "^std::(__debug::)?deque<.+>(( )?&)?$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, + "libstdc++ debug std::deque summary provider", + "^std::__debug::deque<.+>(( )?&)?$", stl_summary_flags, true); AddCXXSummary( cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::multimap summary provider", - "^std::(__debug::)?multimap<.+> >(( )?&)?$", stl_summary_flags, true); + "libstdc++ debug std::multimap summary provider", + "^std::__debug::multimap<.+> >(( )?&)?$", stl_summary_flags, true); AddCXXSummary( cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, - "libstdc++ std::multiset summary provider", - "^std::(__debug::)?multiset<.+> >(( )?&)?$", stl_summary_flags, true); + "libstdc++ debug std::multiset summary provider", + "^std::__debug::multiset<.+> >(( )?&)?$", stl_summary_flags, true); AddCXXSummary(cpp_category_sp, lldb_private::formatters::ContainerSizeSummaryProvider, @@ -1672,6 +1693,30 @@ GenericUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *children, *valobj_sp); } +static SyntheticChildrenFrontEnd * +GenericMapLikeSyntheticFrontEndCreator(CXXSyntheticChildren *children, + ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlMapLike(*valobj_sp)) + return MsvcStlMapLikeSyntheticFrontEndCreator(valobj_sp); + return new ScriptedSyntheticChildren::FrontEnd( + "lldb.formatters.cpp.gnu_libstdcpp.StdMapLikeSynthProvider", *valobj_sp); +} + +static SyntheticChildrenFrontEnd * +GenericDequeSyntheticFrontEndCreator(CXXSyntheticChildren *children, + ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + + if (IsMsvcStlDeque(*valobj_sp)) + return MsvcStlDequeSyntheticFrontEndCreator(children, valobj_sp); + return new ScriptedSyntheticChildren::FrontEnd( + "lldb.formatters.cpp.gnu_libstdcpp.StdDequeSynthProvider", *valobj_sp); +} + /// Load formatters that are formatting types from more than one STL static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { if (!cpp_category_sp) @@ -1749,6 +1794,14 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSynthetic(cpp_category_sp, GenericOptionalSyntheticFrontEndCreator, "std::optional synthetic children", "^std::optional<.+>(( )?&)?$", stl_deref_flags, true); + AddCXXSynthetic(cpp_category_sp, GenericDequeSyntheticFrontEndCreator, + "std::deque container synthetic children", + "^std::deque<.+>(( )?&)?$", stl_deref_flags, true); + + AddCXXSynthetic(cpp_category_sp, GenericMapLikeSyntheticFrontEndCreator, + "std::(multi)?map/set synthetic children", + "^std::(multi)?(map|set)<.+>(( )?&)?$", stl_synth_flags, + true); AddCXXSummary(cpp_category_sp, GenericSmartPointerSummaryProvider, "MSVC STL/libstdc++ std::shared_ptr summary provider", @@ -1786,6 +1839,13 @@ static void LoadCommonStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "MSVC STL/libstdc++ std unordered container summary provider", "^std::unordered_(multi)?(map|set)<.+> ?>$", stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, + "MSVC STL/libstdc++ std::(multi)?map/set summary provider", + "^std::(multi)?(map|set)<.+>(( )?&)?$", stl_summary_flags, + true); + AddCXXSummary(cpp_category_sp, ContainerSizeSummaryProvider, + "MSVC STL/libstd++ std::deque summary provider", + "^std::deque<.+>(( )?&)?$", stl_summary_flags, true); } static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { @@ -1825,6 +1885,36 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { MsvcStlStringSummaryProvider<StringElementType::UTF32>, "MSVC STL std::u32string summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::string_view", "char", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::ASCII>, + "MSVC STL std::string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u8string_view", "char8_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF8>, + "MSVC STL std::u8string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u16string_view", "char16_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF16>, + "MSVC STL std::u16string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::u32string_view", "char32_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, + MsvcStlStringViewSummaryProvider<StringElementType::UTF32>, + "MSVC STL std::u32string_view summary provider")); + RegisterStdStringViewSummaryProvider( + cpp_category_sp, "std::wstring_view", "wchar_t", + std::make_shared<CXXFunctionSummaryFormat>( + stl_summary_flags, MsvcStlWStringViewSummaryProvider, + "MSVC STL std::wstring_view summary provider")); + stl_summary_flags.SetDontShowChildren(false); AddCXXSynthetic(cpp_category_sp, MsvcStlAtomicSyntheticFrontEndCreator, @@ -1834,6 +1924,14 @@ static void LoadMsvcStlFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { AddCXXSummary(cpp_category_sp, MsvcStlAtomicSummaryProvider, "MSVC STL std::atomic summary provider", "^std::atomic<.+>$", stl_summary_flags, true); + AddCXXSynthetic(cpp_category_sp, MsvcStlTreeIterSyntheticFrontEndCreator, + "MSVC STL tree iterator synthetic children", + "^std::_Tree(_const)?_iterator<.+>(( )?&)?$", stl_synth_flags, + true); + AddCXXSummary(cpp_category_sp, MsvcStlTreeIterSummaryProvider, + "MSVC STL tree iterator summary", + "^std::_Tree(_const)?_iterator<.+>(( )?&)?$", stl_summary_flags, + true); } static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp index 5d0f20b..8fb305b 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.cpp @@ -112,6 +112,33 @@ static bool formatStringImpl(ValueObject &valobj, Stream &stream, return true; } +template <StringPrinter::StringElementType element_type> +static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options, + std::string prefix_token) { + auto data_sp = valobj.GetChildMemberWithName("_Mydata"); + auto size_sp = valobj.GetChildMemberWithName("_Mysize"); + if (!data_sp || !size_sp) + return false; + + bool success = false; + uint64_t size = size_sp->GetValueAsUnsigned(0, &success); + if (!success) { + stream << "Summary Unavailable"; + return true; + } + + StreamString scratch_stream; + success = StringBufferSummaryProvider<element_type>( + scratch_stream, summary_options, data_sp, size, prefix_token); + + if (success) + stream << scratch_stream.GetData(); + else + stream << "Summary Unavailable"; + return true; +} + bool lldb_private::formatters::IsMsvcStlStringType(ValueObject &valobj) { std::vector<uint32_t> indexes; return valobj.GetCompilerType().GetIndexOfChildMemberWithName("_Mypair", true, @@ -153,3 +180,39 @@ bool lldb_private::formatters::MsvcStlStringSummaryProvider< return MsvcStlStringSummaryProviderImpl<StringElementType::UTF32>( valobj, stream, summary_options, "U"); } + +bool lldb_private::formatters::MsvcStlWStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF16>(valobj, stream, + summary_options, "L"); +} + +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::ASCII>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::ASCII>(valobj, stream, + summary_options, ""); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF8>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF8>(valobj, stream, + summary_options, "u8"); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF16>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF16>(valobj, stream, + summary_options, "u"); +} +template <> +bool lldb_private::formatters::MsvcStlStringViewSummaryProvider< + StringElementType::UTF32>(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options) { + return formatStringViewImpl<StringElementType::UTF32>(valobj, stream, + summary_options, "U"); +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h index e2a015a..8a49181 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStl.h @@ -29,6 +29,15 @@ bool MsvcStlWStringSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // VC 2015+ std::wstring +template <StringPrinter::StringElementType element_type> +bool MsvcStlStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &summary_options); // std::{u8,u16,u32}?string_view + +bool MsvcStlWStringViewSummaryProvider( + ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); // std::wstring_view + // MSVC STL std::shared_ptr<> and std::weak_ptr<> bool IsMsvcStlSmartPointer(ValueObject &valobj); bool MsvcStlSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, @@ -91,6 +100,23 @@ bool IsMsvcStlUnordered(ValueObject &valobj); SyntheticChildrenFrontEnd * MsvcStlUnorderedSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp); +bool IsMsvcStlTreeIter(ValueObject &valobj); +bool MsvcStlTreeIterSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); +lldb_private::SyntheticChildrenFrontEnd * +MsvcStlTreeIterSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + +// std::map,set,multimap,multiset +bool IsMsvcStlMapLike(ValueObject &valobj); +lldb_private::SyntheticChildrenFrontEnd * +MsvcStlMapLikeSyntheticFrontEndCreator(lldb::ValueObjectSP valobj_sp); + +// MSVC STL std::deque<> +bool IsMsvcStlDeque(ValueObject &valobj); +SyntheticChildrenFrontEnd * +MsvcStlDequeSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); } // namespace formatters } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp new file mode 100644 index 0000000..8733543 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp @@ -0,0 +1,174 @@ +//===-- MsvcStlDeque.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 "MsvcStl.h" + +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/DataFormatters/TypeSynthetic.h" + +using namespace lldb; + +namespace lldb_private { +namespace formatters { + +class MsvcStlDequeSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + MsvcStlDequeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; + +private: + ValueObject *m_map = nullptr; + ExecutionContextRef m_exe_ctx_ref; + + size_t m_block_size = 0; + size_t m_offset = 0; + size_t m_map_size = 0; + + size_t m_element_size = 0; + CompilerType m_element_type; + + uint32_t m_size = 0; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd:: + MsvcStlDequeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +llvm::Expected<uint32_t> lldb_private::formatters:: + MsvcStlDequeSyntheticFrontEnd::CalculateNumChildren() { + if (!m_map) + return llvm::createStringError("Failed to read size"); + return m_size; +} + +lldb::ValueObjectSP +lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + if (idx >= m_size || !m_map) + return nullptr; + ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); + if (!process_sp) + return nullptr; + + // _EEN_DS = _Block_size + // _Map[(($i + _Myoff) / _EEN_DS) % _Mapsize][($i + _Myoff) % _EEN_DS] + size_t first_idx = ((idx + m_offset) / m_block_size) % m_map_size; + lldb::addr_t first_address = m_map->GetValueAsUnsigned(0) + + first_idx * process_sp->GetAddressByteSize(); + + Status err; + lldb::addr_t second_base = + process_sp->ReadPointerFromMemory(first_address, err); + if (err.Fail()) + return nullptr; + + size_t second_idx = (idx + m_offset) % m_block_size; + size_t second_address = second_base + second_idx * m_element_size; + + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(name.GetString(), second_address, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +lldb::ChildCacheState +lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() { + m_size = 0; + m_map = nullptr; + m_element_type.Clear(); + + auto storage_sp = m_backend.GetChildAtNamePath({"_Mypair", "_Myval2"}); + if (!storage_sp) + return lldb::eRefetch; + + auto deque_type = m_backend.GetCompilerType(); + if (!deque_type) + return lldb::eRefetch; + + auto block_size_decl = deque_type.GetStaticFieldWithName("_Block_size"); + if (!block_size_decl) + return lldb::eRefetch; + auto block_size = block_size_decl.GetConstantValue(); + if (!block_size.IsValid()) + return lldb::eRefetch; + + auto element_type = deque_type.GetTypeTemplateArgument(0); + if (!element_type) + return lldb::eRefetch; + auto element_size = element_type.GetByteSize(nullptr); + if (!element_size) + return lldb::eRefetch; + + auto offset_sp = storage_sp->GetChildMemberWithName("_Myoff"); + auto map_size_sp = storage_sp->GetChildMemberWithName("_Mapsize"); + auto map_sp = storage_sp->GetChildMemberWithName("_Map"); + auto size_sp = storage_sp->GetChildMemberWithName("_Mysize"); + if (!offset_sp || !map_size_sp || !map_sp || !size_sp) + return lldb::eRefetch; + + bool ok = false; + uint64_t offset = offset_sp->GetValueAsUnsigned(0, &ok); + if (!ok) + return lldb::eRefetch; + + uint64_t map_size = map_size_sp->GetValueAsUnsigned(0, &ok); + if (!ok) + return lldb::eRefetch; + + uint64_t size = size_sp->GetValueAsUnsigned(0, &ok); + if (!ok) + return lldb::eRefetch; + + m_map = map_sp.get(); + m_exe_ctx_ref = m_backend.GetExecutionContextRef(); + m_block_size = block_size.ULongLong(); + m_offset = offset; + m_map_size = map_size; + m_element_size = *element_size; + m_element_type = element_type; + m_size = size; + return lldb::eRefetch; +} + +llvm::Expected<size_t> lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_map) + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + if (auto optional_idx = ExtractIndexFromString(name.GetCString())) + return *optional_idx; + + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); +} + +bool lldb_private::formatters::IsMsvcStlDeque(ValueObject &valobj) { + if (auto valobj_sp = valobj.GetNonSyntheticValue()) + return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr; + return false; +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::MsvcStlDequeSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return new MsvcStlDequeSyntheticFrontEnd(valobj_sp); +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp new file mode 100644 index 0000000..ddf6c27 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlTree.cpp @@ -0,0 +1,407 @@ +//===-- MsvcStlTree.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 "MsvcStl.h" + +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/Status.h" +#include "lldb/ValueObject/ValueObject.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-forward.h" +#include <cstdint> +#include <optional> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +// A Node looks as follows: +// struct _Tree_node { +// _Tree_node *_Left; +// _Tree_node *_Parent; +// _Tree_node *_Right; +// char _Color; +// char _Isnil; // true (!= 0) if head or nil node +// value_type _Myval; +// }; + +namespace { + +class MapEntry { +public: + MapEntry() = default; + explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} + explicit MapEntry(ValueObject *entry) + : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} + + ValueObjectSP left() const { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetSyntheticChildAtOffset( + 0, m_entry_sp->GetCompilerType(), true); + } + + ValueObjectSP right() const { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetSyntheticChildAtOffset( + 2 * m_entry_sp->GetProcessSP()->GetAddressByteSize(), + m_entry_sp->GetCompilerType(), true); + } + + ValueObjectSP parent() const { + if (!m_entry_sp) + return m_entry_sp; + return m_entry_sp->GetSyntheticChildAtOffset( + m_entry_sp->GetProcessSP()->GetAddressByteSize(), + m_entry_sp->GetCompilerType(), true); + } + + uint64_t value() const { + if (!m_entry_sp) + return 0; + return m_entry_sp->GetValueAsUnsigned(0); + } + + bool is_nil() const { + if (!m_entry_sp) + return true; + auto isnil_sp = m_entry_sp->GetChildMemberWithName("_Isnil"); + if (!isnil_sp) + return true; + return isnil_sp->GetValueAsUnsigned(1) != 0; + } + + bool error() const { + if (!m_entry_sp) + return true; + return m_entry_sp->GetError().Fail(); + } + + bool is_nullptr() const { return (value() == 0); } + + ValueObjectSP GetEntry() const { return m_entry_sp; } + + void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; } + + bool operator==(const MapEntry &rhs) const { + return (rhs.m_entry_sp.get() == m_entry_sp.get()); + } + +private: + ValueObjectSP m_entry_sp; +}; + +class MapIterator { +public: + MapIterator(ValueObject *entry, size_t depth = 0) + : m_entry(entry), m_max_depth(depth) {} + + MapIterator() = default; + + ValueObjectSP value() { return m_entry.GetEntry(); } + + ValueObjectSP advance(size_t count) { + ValueObjectSP fail; + if (m_error) + return fail; + size_t steps = 0; + while (count > 0) { + next(); + count--, steps++; + if (m_error || m_entry.is_nullptr() || (steps > m_max_depth)) + return fail; + } + return m_entry.GetEntry(); + } + +private: + /// Mimicks _Tree_unchecked_const_iterator::operator++() + void next() { + if (m_entry.is_nullptr()) + return; + MapEntry right(m_entry.right()); + if (!right.is_nil()) { + m_entry = tree_min(std::move(right)); + return; + } + size_t steps = 0; + MapEntry pnode(m_entry.parent()); + while (!pnode.is_nil() && + m_entry.value() == MapEntry(pnode.right()).value()) { + m_entry = pnode; + steps++; + if (steps > m_max_depth) { + m_entry = MapEntry(); + return; + } + pnode.SetEntry(m_entry.parent()); + } + m_entry = std::move(pnode); + } + + /// Mimicks MSVC STL's _Min() algorithm (finding the leftmost node in the + /// subtree). + MapEntry tree_min(MapEntry pnode) { + if (pnode.is_nullptr()) + return MapEntry(); + MapEntry left(pnode.left()); + size_t steps = 0; + while (!left.is_nil()) { + if (left.error()) { + m_error = true; + return MapEntry(); + } + pnode = left; + left.SetEntry(pnode.left()); + steps++; + if (steps > m_max_depth) + return MapEntry(); + } + return pnode; + } + + MapEntry m_entry; + size_t m_max_depth = 0; + bool m_error = false; +}; + +} // namespace + +namespace lldb_private { +namespace formatters { +class MsvcStlTreeSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + MsvcStlTreeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~MsvcStlTreeSyntheticFrontEnd() override = default; + + llvm::Expected<uint32_t> CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; + + lldb::ChildCacheState Update() override; + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; + +private: + /// Returns the ValueObject for the _Tree_node at index \ref idx. + /// + /// \param[in] idx The child index that we're looking to get the value for. + /// + /// \param[in] max_depth The maximum search depth after which we stop trying + /// to find the node for. + /// + /// \returns On success, returns the ValueObjectSP corresponding to the + /// _Tree_node's _Myval member. + /// On failure, nullptr is returned. + ValueObjectSP GetValueAt(size_t idx, size_t max_depth); + + ValueObject *m_tree = nullptr; + ValueObject *m_begin_node = nullptr; + size_t m_count = UINT32_MAX; + std::map<size_t, MapIterator> m_iterators; +}; + +class MsvcStlTreeIterSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + MsvcStlTreeIterSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) {} + + llvm::Expected<uint32_t> CalculateNumChildren() override { + if (!m_inner_sp) + return 0; + return m_inner_sp->GetNumChildren(); + } + + lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override { + if (!m_inner_sp) + return nullptr; + return m_inner_sp->GetChildAtIndex(idx); + } + + lldb::ChildCacheState Update() override; + + llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override { + if (!m_inner_sp) + return llvm::createStringError("There are no children."); + return m_inner_sp->GetIndexOfChildWithName(name); + } + + lldb::ValueObjectSP GetSyntheticValue() override { return m_inner_sp; } + +private: + ValueObjectSP m_inner_sp; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd:: + MsvcStlTreeSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp) { + if (valobj_sp) + Update(); +} + +llvm::Expected<uint32_t> +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::CalculateNumChildren() { + if (m_count != UINT32_MAX) + return m_count; + + if (m_tree == nullptr) + return 0; + + if (auto node_sp = m_tree->GetChildMemberWithName("_Mysize")) { + m_count = node_sp->GetValueAsUnsigned(0); + return m_count; + } + + return llvm::createStringError("Failed to read size."); +} + +ValueObjectSP +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::GetValueAt( + size_t idx, size_t max_depth) { + MapIterator iterator(m_begin_node, max_depth); + + size_t advance_by = idx; + if (idx > 0) { + // If we have already created the iterator for the previous + // index, we can start from there and advance by 1. + auto cached_iterator = m_iterators.find(idx - 1); + if (cached_iterator != m_iterators.end()) { + iterator = cached_iterator->second; + advance_by = 1; + } + } + + ValueObjectSP iterated_sp(iterator.advance(advance_by)); + if (!iterated_sp) + // this tree is garbage - stop + return nullptr; + + ValueObjectSP value_sp = iterated_sp->GetChildMemberWithName("_Myval"); + if (!value_sp) + return nullptr; + + m_iterators[idx] = iterator; + + return value_sp; +} + +lldb::ValueObjectSP +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::GetChildAtIndex( + uint32_t idx) { + uint32_t num_children = CalculateNumChildrenIgnoringErrors(); + if (idx >= num_children) + return nullptr; + + if (m_tree == nullptr || m_begin_node == nullptr) + return nullptr; + + ValueObjectSP val_sp = GetValueAt(idx, /*max_depth=*/num_children); + if (!val_sp) { + // this will stop all future searches until an Update() happens + m_tree = nullptr; + return nullptr; + } + + // at this point we have a valid pair + // we need to copy current_sp into a new object otherwise we will end up with + // all items named _Myval + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return val_sp->Clone(ConstString(name.GetString())); +} + +lldb::ChildCacheState +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::Update() { + m_count = UINT32_MAX; + m_tree = m_begin_node = nullptr; + m_iterators.clear(); + m_tree = + m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myval2"}).get(); + if (!m_tree) + return lldb::ChildCacheState::eRefetch; + + m_begin_node = m_tree->GetChildAtNamePath({"_Myhead", "_Left"}).get(); + + return lldb::ChildCacheState::eRefetch; +} + +llvm::Expected<size_t> +lldb_private::formatters::MsvcStlTreeSyntheticFrontEnd::GetIndexOfChildWithName( + ConstString name) { + auto optional_idx = formatters::ExtractIndexFromString(name.GetCString()); + if (!optional_idx) { + return llvm::createStringError("Type has no child named '%s'", + name.AsCString()); + } + return *optional_idx; +} + +lldb::ChildCacheState MsvcStlTreeIterSyntheticFrontEnd::Update() { + m_inner_sp = nullptr; + auto node_sp = m_backend.GetChildMemberWithName("_Ptr"); + if (!node_sp) + return lldb::eRefetch; + + MapEntry entry(node_sp.get()); + if (entry.is_nil()) + return lldb::eRefetch; // end + + m_inner_sp = node_sp->GetChildMemberWithName("_Myval"); + return lldb::eRefetch; +} + +bool formatters::IsMsvcStlTreeIter(ValueObject &valobj) { + return valobj.GetChildMemberWithName("_Ptr") != nullptr; +} + +bool formatters::MsvcStlTreeIterSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + auto valobj_sp = valobj.GetNonSyntheticValue(); + if (!valobj_sp) + return false; + auto node_sp = valobj_sp->GetChildMemberWithName("_Ptr"); + if (!node_sp) + return false; + + MapEntry entry(node_sp.get()); + if (entry.is_nil()) { + stream.Printf("end"); + return true; + } + + auto value_sp = node_sp->GetChildMemberWithName("_Myval"); + if (!value_sp) + return false; + + auto *summary = value_sp->GetSummaryAsCString(); + if (summary) + stream << summary; + return true; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::MsvcStlTreeIterSyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new MsvcStlTreeIterSyntheticFrontEnd(valobj_sp) + : nullptr); +} + +bool formatters::IsMsvcStlMapLike(ValueObject &valobj) { + return valobj.GetChildMemberWithName("_Mypair") != nullptr; +} + +SyntheticChildrenFrontEnd * +lldb_private::formatters::MsvcStlMapLikeSyntheticFrontEndCreator( + lldb::ValueObjectSP valobj_sp) { + return (valobj_sp ? new MsvcStlTreeSyntheticFrontEnd(valobj_sp) : nullptr); +} diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 4fcdebe..cca721e 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -3462,7 +3462,7 @@ public: *exception, eValueTypeVariableArgument); exception = exception->GetDynamicValue(eDynamicDontRunTarget); - m_arguments = ValueObjectListSP(new ValueObjectList()); + m_arguments = std::make_shared<ValueObjectList>(); m_arguments->Append(exception); m_stop_desc = "hit Objective-C exception"; diff --git a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp index fe28213..25e9888 100644 --- a/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp +++ b/lldb/source/Plugins/ObjectFile/Minidump/MinidumpFileBuilder.cpp @@ -201,7 +201,7 @@ Status MinidumpFileBuilder::AddSystemInfo() { return error; }; - llvm::minidump::SystemInfo sys_info; + llvm::minidump::SystemInfo sys_info{}; sys_info.ProcessorArch = static_cast<llvm::support::little_t<ProcessorArchitecture>>(arch); // Global offset to beginning of a csd_string in a data section @@ -378,7 +378,7 @@ Status MinidumpFileBuilder::AddModuleList() { helper_data.AppendData(&signature, sizeof(llvm::support::ulittle32_t)); helper_data.AppendData(uuid.begin(), uuid.size()); - llvm::minidump::Module m; + llvm::minidump::Module m{}; m.BaseOfImage = static_cast<llvm::support::ulittle64_t>( mod->GetObjectFile()->GetBaseAddress().GetLoadAddress(&target)); m.SizeOfImage = static_cast<llvm::support::ulittle32_t>(mod_size); @@ -745,7 +745,7 @@ lldb_private::Status MinidumpFileBuilder::AddMiscInfo() { if (error.Fail()) return error; - lldb_private::minidump::MinidumpMiscInfo misc_info; + lldb_private::minidump::MinidumpMiscInfo misc_info{}; misc_info.size = static_cast<llvm::support::ulittle32_t>( sizeof(lldb_private::minidump::MinidumpMiscInfo)); // Default set flags1 to 0, in case that we will not be able to diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 54869001..07c5a52 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -805,7 +805,7 @@ Status PlatformDarwinKernel::GetSharedModuleKernel( if (FileSystem::Instance().Exists(possible_kernel)) { ModuleSpec kern_spec(possible_kernel); kern_spec.GetUUID() = module_spec.GetUUID(); - module_sp.reset(new Module(kern_spec)); + module_sp = std::make_shared<Module>(kern_spec); if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec(kern_spec)) { // The dSYM is next to the binary (that's the only @@ -835,7 +835,7 @@ Status PlatformDarwinKernel::GetSharedModuleKernel( kern_spec.GetUUID() = module_spec.GetUUID(); kern_spec.GetSymbolFileSpec() = possible_kernel_dsym; - module_sp.reset(new Module(kern_spec)); + module_sp = std::make_shared<Module>(kern_spec); if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec(kern_spec)) { if (did_create_ptr) diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index bd9b1b8..3413360 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -29,3 +29,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) add_subdirectory(FreeBSDKernel) +add_subdirectory(wasm) diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp index 7adc006..d21dac2 100644 --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -44,7 +44,8 @@ NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( NativeProcessFreeBSD &process = native_thread.GetProcess(); g_register_flags_detector.DetectFields( process.GetAuxValue(AuxVector::AUXV_FREEBSD_AT_HWCAP).value_or(0), - process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0)); + process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2).value_or(0), + /*hwcap3=*/0); } return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); diff --git a/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/lldb/source/Plugins/Process/Linux/CMakeLists.txt index 33af2e2..bb69016 100644 --- a/lldb/source/Plugins/Process/Linux/CMakeLists.txt +++ b/lldb/source/Plugins/Process/Linux/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginProcessLinux NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp + NativeRegisterContextLinux_arm64dbreg.cpp NativeRegisterContextLinux_loongarch64.cpp NativeRegisterContextLinux_ppc64le.cpp NativeRegisterContextLinux_riscv64.cpp diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index dc7fb10..fdafacf 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -23,13 +23,19 @@ #include <elf.h> #include <sys/uio.h> +#if defined(__arm64__) || defined(__aarch64__) +#include "NativeRegisterContextLinux_arm64dbreg.h" +#include "lldb/Host/linux/Ptrace.h" +#include <asm/ptrace.h> +#endif + #define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(m_fpr)) #ifndef PTRACE_GETVFPREGS #define PTRACE_GETVFPREGS 27 #define PTRACE_SETVFPREGS 28 #endif -#ifndef PTRACE_GETHBPREGS +#if defined(__arm__) && !defined(PTRACE_GETHBPREGS) #define PTRACE_GETHBPREGS 29 #define PTRACE_SETHBPREGS 30 #endif @@ -342,7 +348,8 @@ NativeRegisterContextLinux_arm::SetHardwareBreakpoint(lldb::addr_t addr, m_hbr_regs[bp_index].control = control_value; // PTRACE call to set corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, bp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, + bp_index); if (error.Fail()) { m_hbr_regs[bp_index].address = 0; @@ -375,7 +382,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareBreakpoint(uint32_t hw_idx) { m_hbr_regs[hw_idx].address = 0; // PTRACE call to clear corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK, hw_idx); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, + hw_idx); if (error.Fail()) { m_hbr_regs[hw_idx].control = tempControl; @@ -435,7 +443,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareBreakpoints() { m_hbr_regs[i].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeBREAK, i); + error = + WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeBREAK, i); if (error.Fail()) { m_hbr_regs[i].control = tempControl; @@ -555,7 +564,8 @@ uint32_t NativeRegisterContextLinux_arm::SetHardwareWatchpoint( m_hwp_regs[wp_index].control = control_value; // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, + wp_index); if (error.Fail()) { m_hwp_regs[wp_index].address = 0; @@ -590,7 +600,8 @@ bool NativeRegisterContextLinux_arm::ClearHardwareWatchpoint( m_hwp_regs[wp_index].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, wp_index); + error = WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, + wp_index); if (error.Fail()) { m_hwp_regs[wp_index].control = tempControl; @@ -623,7 +634,8 @@ Status NativeRegisterContextLinux_arm::ClearAllHardwareWatchpoints() { m_hwp_regs[i].address = 0; // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH, i); + error = + WriteHardwareDebugRegs(NativeRegisterContextDBReg::eDREGTypeWATCH, i); if (error.Fail()) { m_hwp_regs[i].control = tempControl; @@ -723,6 +735,7 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { return Status(); } +#ifdef __arm__ unsigned int cap_val; error = NativeProcessLinux::PtraceWrapper(PTRACE_GETHBPREGS, m_thread.GetID(), @@ -737,16 +750,21 @@ Status NativeRegisterContextLinux_arm::ReadHardwareDebugInfo() { m_refresh_hwdebug_info = false; return error; +#else // __aarch64__ + return arm64::ReadHardwareDebugInfo(m_thread.GetID(), m_max_hwp_supported, + m_max_hbp_supported); +#endif // ifdef __arm__ } -Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, - int hwb_index) { +Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs( + NativeRegisterContextDBReg::DREGType hwbType, int hwb_index) { Status error; +#ifdef __arm__ lldb::addr_t *addr_buf; uint32_t *ctrl_buf; - if (hwbType == eDREGTypeWATCH) { + if (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) { addr_buf = &m_hwp_regs[hwb_index].address; ctrl_buf = &m_hwp_regs[hwb_index].control; @@ -781,6 +799,17 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, } return error; +#else // __aarch64__ + uint32_t max_supported = + (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) + ? m_max_hwp_supported + : m_max_hbp_supported; + auto ®s = (hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH) + ? m_hwp_regs + : m_hbr_regs; + return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported, + regs); +#endif // ifdef __arm__ } uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index 15b4660..3a31d68 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h @@ -12,6 +12,7 @@ #define lldb_NativeRegisterContextLinux_arm_h #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" #include "Plugins/Process/Utility/lldb-arm-register-enums.h" @@ -74,9 +75,6 @@ public: bool WatchpointIsEnabled(uint32_t wp_index); - // Debug register type select - enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; - protected: Status DoReadRegisterValue(uint32_t offset, const char *reg_name, uint32_t size, RegisterValue &value) override; @@ -102,18 +100,10 @@ private: uint32_t m_gpr_arm[k_num_gpr_registers_arm]; RegisterInfoPOSIX_arm::FPU m_fpr; - // Debug register info for hardware breakpoints and watchpoints management. - struct DREG { - lldb::addr_t address; // Breakpoint/watchpoint address value. - lldb::addr_t hit_addr; // Address at which last watchpoint trigger exception - // occurred. - lldb::addr_t real_addr; // Address value that should cause target to stop. - uint32_t control; // Breakpoint/watchpoint control value. - uint32_t refcount; // Serves as enable/disable and reference counter. - }; - - struct DREG m_hbr_regs[16]; // Arm native linux hardware breakpoints - struct DREG m_hwp_regs[16]; // Arm native linux hardware watchpoints + std::array<NativeRegisterContextDBReg::DREG, 16> + m_hbr_regs; // Arm native linux hardware breakpoints + std::array<NativeRegisterContextDBReg::DREG, 16> + m_hwp_regs; // Arm native linux hardware watchpoints uint32_t m_max_hwp_supported; uint32_t m_max_hbp_supported; @@ -125,7 +115,8 @@ private: Status ReadHardwareDebugInfo(); - Status WriteHardwareDebugRegs(int hwbType, int hwb_index); + Status WriteHardwareDebugRegs(NativeRegisterContextDBReg::DREGType hwbType, + int hwb_index); uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 884c7d4b..294a446 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -8,8 +8,9 @@ #if defined(__arm64__) || defined(__aarch64__) -#include "NativeRegisterContextLinux_arm.h" #include "NativeRegisterContextLinux_arm64.h" +#include "NativeRegisterContextLinux_arm.h" +#include "NativeRegisterContextLinux_arm64dbreg.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/common/NativeProcessProtocol.h" @@ -162,10 +163,13 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS); + std::optional<uint64_t> auxv_at_hwcap3 = + process.GetAuxValue(AuxVector::AUXV_AT_HWCAP3); std::lock_guard<std::mutex> lock(g_register_flags_detector_mutex); if (!g_register_flags_detector.HasDetected()) g_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0), - auxv_at_hwcap2.value_or(0)); + auxv_at_hwcap2.value_or(0), + auxv_at_hwcap3.value_or(0)); auto register_info_up = std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets); @@ -1143,29 +1147,11 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { ::pid_t tid = m_thread.GetID(); - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - Status error; - - ioVec.iov_base = &dreg_state; - ioVec.iov_len = sizeof(dreg_state); - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - + Status error = arm64::ReadHardwareDebugInfo(tid, m_max_hwp_supported, + m_max_hbp_supported); if (error.Fail()) return error.ToError(); - m_max_hwp_supported = dreg_state.dbg_info & 0xff; - - regset = NT_ARM_HW_BREAK; - error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, - &ioVec, ioVec.iov_len); - - if (error.Fail()) - return error.ToError(); - - m_max_hbp_supported = dreg_state.dbg_info & 0xff; m_refresh_hwdebug_info = false; return llvm::Error::success(); @@ -1173,38 +1159,11 @@ llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { llvm::Error NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; - int regset; - - memset(&dreg_state, 0, sizeof(dreg_state)); - ioVec.iov_base = &dreg_state; - - switch (hwbType) { - case eDREGTypeWATCH: - regset = NT_ARM_HW_WATCH; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; - } - break; - case eDREGTypeBREAK: - regset = NT_ARM_HW_BREAK; - ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + - (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control; - } - break; - } - - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - ®set, &ioVec, ioVec.iov_len) + uint32_t max_supported = + (hwbType == eDREGTypeWATCH) ? m_max_hwp_supported : m_max_hbp_supported; + auto ®s = (hwbType == eDREGTypeWATCH) ? m_hwp_regs : m_hbp_regs; + return arm64::WriteHardwareDebugRegs(hwbType, m_thread.GetID(), max_supported, + regs) .ToError(); } diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp new file mode 100644 index 0000000..53ee8fd --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.cpp @@ -0,0 +1,77 @@ +//===-- NativeRegisterContextLinux_arm64dbreg.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm64__) || defined(__aarch64__) + +#include "NativeRegisterContextLinux_arm64dbreg.h" +#include "lldb/Host/linux/Ptrace.h" + +#include <asm/ptrace.h> +// System includes - They have to be included after framework includes because +// they define some macros which collide with variable names in other modules +#include <sys/uio.h> +// NT_PRSTATUS and NT_FPREGSET definition +#include <elf.h> + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_linux; + +static Status ReadHardwareDebugInfoHelper(int regset, ::pid_t tid, + uint32_t &max_supported) { + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Status error; + + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof(dreg_state); + error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, + &ioVec, ioVec.iov_len); + + if (error.Fail()) + return error; + + max_supported = dreg_state.dbg_info & 0xff; + return error; +} + +Status lldb_private::process_linux::arm64::ReadHardwareDebugInfo( + ::pid_t tid, uint32_t &max_hwp_supported, uint32_t &max_hbp_supported) { + Status error = + ReadHardwareDebugInfoHelper(NT_ARM_HW_WATCH, tid, max_hwp_supported); + + if (error.Fail()) + return error; + + return ReadHardwareDebugInfoHelper(NT_ARM_HW_BREAK, tid, max_hbp_supported); +} + +Status lldb_private::process_linux::arm64::WriteHardwareDebugRegs( + int hwbType, ::pid_t tid, uint32_t max_supported, + const std::array<NativeRegisterContextDBReg::DREG, 16> ®s) { + int regset = hwbType == NativeRegisterContextDBReg::eDREGTypeWATCH + ? NT_ARM_HW_WATCH + : NT_ARM_HW_BREAK; + + struct user_hwdebug_state dreg_state; + memset(&dreg_state, 0, sizeof(dreg_state)); + for (uint32_t i = 0; i < max_supported; i++) { + dreg_state.dbg_regs[i].addr = regs[i].address; + dreg_state.dbg_regs[i].ctrl = regs[i].control; + } + + struct iovec ioVec; + ioVec.iov_base = &dreg_state; + ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + + (sizeof(dreg_state.dbg_regs[0]) * max_supported); + + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, + &ioVec, ioVec.iov_len); +} + +#endif // defined (__arm64__) || defined (__aarch64__) diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h new file mode 100644 index 0000000..bca2178 --- /dev/null +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64dbreg.h @@ -0,0 +1,31 @@ +//===-- NativeRegisterContextLinux_arm64dbreg.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 +// +//===----------------------------------------------------------------------===// + +// When debugging 32-bit processes, Arm64 lldb-server should use 64-bit ptrace +// interfaces. 32-bit ptrace interfaces should only be used by 32-bit server. +// These functions are split out to be reused in both 32-bit and 64-bit register +// context for 64-bit server. + +#include "Plugins/Process/Linux/NativeProcessLinux.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg.h" +#include "lldb/Utility/Status.h" + +namespace lldb_private { +namespace process_linux { +namespace arm64 { + +Status ReadHardwareDebugInfo(::pid_t tid, uint32_t &max_hwp_supported, + uint32_t &max_hbp_supported); + +Status WriteHardwareDebugRegs( + int hwbType, ::pid_t tid, uint32_t max_supported, + const std::array<NativeRegisterContextDBReg::DREG, 16> ®s); + +} // namespace arm64 +} // namespace process_linux +} // namespace lldb_private diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/lldb/source/Plugins/Process/Utility/AuxVector.cpp index f495ffb..d660bfe 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.cpp +++ b/lldb/source/Plugins/Process/Utility/AuxVector.cpp @@ -84,6 +84,7 @@ const char *AuxVector::GetEntryName(EntryType type) const { case ENTRY_NAME(AUXV_AT_BASE_PLATFORM); break; case ENTRY_NAME(AUXV_AT_RANDOM); break; case ENTRY_NAME(AUXV_AT_HWCAP2); break; + case ENTRY_NAME(AUXV_AT_HWCAP3); break; case ENTRY_NAME(AUXV_AT_EXECFN); break; case ENTRY_NAME(AUXV_AT_SYSINFO); break; case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break; @@ -91,6 +92,8 @@ const char *AuxVector::GetEntryName(EntryType type) const { case ENTRY_NAME(AUXV_AT_L1D_CACHESHAPE); break; case ENTRY_NAME(AUXV_AT_L2_CACHESHAPE); break; case ENTRY_NAME(AUXV_AT_L3_CACHESHAPE); break; + case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP3); break; + case ENTRY_NAME(AUXV_FREEBSD_AT_HWCAP4); break; } #undef ENTRY_NAME diff --git a/lldb/source/Plugins/Process/Utility/AuxVector.h b/lldb/source/Plugins/Process/Utility/AuxVector.h index 2670b34..ad6b70e 100644 --- a/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -57,6 +57,7 @@ public: AUXV_AT_BASE_PLATFORM = 24, ///< String identifying real platforms. AUXV_AT_RANDOM = 25, ///< Address of 16 random bytes. AUXV_AT_HWCAP2 = 26, ///< Extension of AT_HWCAP. + AUXV_AT_HWCAP3 = 29, ///< Extension of AT_HWCAP. AUXV_AT_EXECFN = 31, ///< Filename of executable. AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system /// calls and other nice things. @@ -69,6 +70,10 @@ public: // Platform specific values which may overlap the Linux values. AUXV_FREEBSD_AT_HWCAP = 25, ///< FreeBSD specific AT_HWCAP value. + // FreeBSD and Linux use the same AT_HWCAP2 value. + AUXV_FREEBSD_AT_HWCAP3 = 38, ///< FreeBSD specific AT_HWCAP3 value. + AUXV_FREEBSD_AT_HWCAP4 = 39, ///< FreeBSD specific AT_HWCAP4 value. + }; std::optional<uint64_t> GetAuxValue(enum EntryType entry_type) const; diff --git a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h index e17a700..9b6ecd3 100644 --- a/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h +++ b/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg.h @@ -51,7 +51,6 @@ public: lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; -protected: // Debug register type select enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; @@ -64,6 +63,7 @@ protected: uint32_t control; // Breakpoint/watchpoint control value. }; +protected: std::array<struct DREG, 16> m_hbp_regs; // hardware breakpoints std::array<struct DREG, 16> m_hwp_regs; // hardware watchpoints diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp index 042940b..330a24a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.cpp @@ -26,11 +26,15 @@ #define HWCAP2_EBF16 (1ULL << 32) #define HWCAP2_FPMR (1ULL << 48) +#define HWCAP3_MTE_STORE_ONLY (1ULL << 1) + using namespace lldb_private; Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { (void)hwcap; + (void)hwcap3; if (!(hwcap2 & HWCAP2_FPMR)) return {}; @@ -53,8 +57,10 @@ Arm64RegisterFlagsDetector::DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2) { Arm64RegisterFlagsDetector::Fields Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap, - uint64_t hwcap2) { + uint64_t hwcap2, + uint64_t hwcap3) { (void)hwcap2; + (void)hwcap3; if (!(hwcap & HWCAP_GCS)) return {}; @@ -67,8 +73,10 @@ Arm64RegisterFlagsDetector::DetectGCSFeatureFields(uint64_t hwcap, } Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { (void)hwcap; + (void)hwcap3; if (!(hwcap2 & HWCAP2_SME)) return {}; @@ -83,8 +91,8 @@ Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) { } Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, - uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { (void)hwcap; if (!(hwcap2 & HWCAP2_MTE)) @@ -94,16 +102,29 @@ Arm64RegisterFlagsDetector::DetectMTECtrlFields(uint64_t hwcap, // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines // used to build the value. + std::vector<RegisterFlags::Field> fields; + fields.reserve(4); + if (hwcap3 & HWCAP3_MTE_STORE_ONLY) + fields.push_back({"STORE_ONLY", 19}); + static const FieldEnum tcf_enum( "tcf_enum", {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}}); - return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT. - {"TCF", 1, 2, &tcf_enum}, - {"TAGGED_ADDR_ENABLE", 0}}; + + fields.insert( + std::end(fields), + {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT. + {"TCF", 1, 2, &tcf_enum}, + {"TAGGED_ADDR_ENABLE", 0}}); + + return fields; } Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { + (void)hwcap3; + static const FieldEnum rmode_enum( "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}}); @@ -142,10 +163,12 @@ Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) { } Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { // fpsr's contents are constant. (void)hwcap; (void)hwcap2; + (void)hwcap3; return { // Bits 31-28 are N/Z/C/V, only used by AArch32. @@ -162,7 +185,10 @@ Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) { } Arm64RegisterFlagsDetector::Fields -Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { +Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { + (void)hwcap3; + // The fields here are a combination of the Arm manual's SPSR_EL1, // plus a few changes where Linux has decided not to make use of them at all, // or at least not from userspace. @@ -207,9 +233,10 @@ Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) { return cpsr_fields; } -void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2) { +void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3) { for (auto ® : m_registers) - reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2)); + reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2, hwcap3)); m_has_detected = true; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h index 7daebcc..aec2bf9 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterFlagsDetector_arm64.h @@ -40,7 +40,7 @@ public: /// If called more than once, fields will be redetected each time from /// scratch. If the target would not have this register at all, the list of /// fields will be left empty. - void DetectFields(uint64_t hwcap, uint64_t hwcap2); + void DetectFields(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3); /// Add the field information of any registers named in this class, /// to the relevant RegisterInfo instances. Note that this will be done @@ -53,15 +53,22 @@ public: private: using Fields = std::vector<RegisterFlags::Field>; - using DetectorFn = std::function<Fields(uint64_t, uint64_t)>; + using DetectorFn = std::function<Fields(uint64_t, uint64_t, uint64_t)>; - static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2); - static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2); + static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectFPMRFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); + static Fields DetectGCSFeatureFields(uint64_t hwcap, uint64_t hwcap2, + uint64_t hwcap3); struct RegisterEntry { RegisterEntry(llvm::StringRef name, unsigned size, DetectorFn detector) diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index bd02bb0..d5046d3 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -96,14 +96,19 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS(); if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) { AuxVector aux_vec(process->GetAuxvData()); - std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue( - os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP - : AuxVector::AUXV_AT_HWCAP); + bool is_freebsd = os == llvm::Triple::FreeBSD; + std::optional<uint64_t> auxv_at_hwcap = + aux_vec.GetAuxValue(is_freebsd ? AuxVector::AUXV_FREEBSD_AT_HWCAP + : AuxVector::AUXV_AT_HWCAP); std::optional<uint64_t> auxv_at_hwcap2 = aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); + std::optional<uint64_t> auxv_at_hwcap3 = + is_freebsd ? std::nullopt + : aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP3); m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0), - auxv_at_hwcap2.value_or(0)); + auxv_at_hwcap2.value_or(0), + auxv_at_hwcap3.value_or(0)); m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(), GetRegisterCount()); } diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index a2c34dd..f610422 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -323,6 +323,11 @@ ProcessGDBRemote::~ProcessGDBRemote() { KillDebugserverProcess(); } +std::shared_ptr<ThreadGDBRemote> +ProcessGDBRemote::CreateThread(lldb::tid_t tid) { + return std::make_shared<ThreadGDBRemote>(*this, tid); +} + bool ProcessGDBRemote::ParsePythonTargetDefinition( const FileSpec &target_definition_fspec) { ScriptInterpreter *interpreter = @@ -1594,7 +1599,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + thread_sp = CreateThread(tid); LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.", thread_sp.get(), thread_sp->GetID()); } else { @@ -1726,7 +1731,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (!thread_sp) { // Create the thread if we need to - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + thread_sp = CreateThread(tid); m_thread_list_real.AddThread(thread_sp); } } @@ -4783,7 +4788,8 @@ bool ParseRegisters( } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { reg_info.format = eFormatAddressInfo; reg_info.encoding = eEncodingUint; - } else if (gdb_type == "float") { + } else if (gdb_type == "float" || gdb_type == "ieee_single" || + gdb_type == "ieee_double") { reg_info.format = eFormatFloat; reg_info.encoding = eEncodingIEEE754; } else if (gdb_type == "aarch64v" || @@ -5260,17 +5266,17 @@ llvm::Error ProcessGDBRemote::LoadModules() { loaded_modules.Remove(removed_modules); m_process->GetTarget().ModulesDidUnload(removed_modules, false); - new_modules.ForEach([&target](const lldb::ModuleSP module_sp) -> bool { + new_modules.ForEach([&target](const lldb::ModuleSP module_sp) { lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); if (!obj) - return true; + return IterationAction::Continue; if (obj->GetType() != ObjectFile::Type::eTypeExecutable) - return true; + return IterationAction::Continue; lldb::ModuleSP module_copy_sp = module_sp; target.SetExecutableModule(module_copy_sp, eLoadDependentsNo); - return false; + return IterationAction::Stop; }); loaded_modules.AppendIfNeeded(new_modules); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index 7ae3383..7c3dfb1 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -246,6 +246,8 @@ protected: ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid); + bool SupportsMemoryTagging() override; /// Broadcaster event bits definitions. diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 17a421a..b0b8fae 100644 --- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -408,7 +408,7 @@ void ProcessMinidump::BuildMemoryRegions() { to_add.back().SetName(module_sp->GetFileSpec().GetPath().c_str()); } } - return true; + return IterationAction::Continue; }); m_memory_regions->insert(m_memory_regions->end(), to_add.begin(), to_add.end()); diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt new file mode 100644 index 0000000..ff8a3c7 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginProcessWasm PLUGIN + ProcessWasm.cpp + ThreadWasm.cpp + UnwindWasm.cpp + + LINK_LIBS + lldbCore + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp new file mode 100644 index 0000000..5eeabec --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 "ProcessWasm.h" +#include "ThreadWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Value.h" +#include "lldb/Utility/DataBufferHeap.h" + +#include "lldb/Target/UnixSignals.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(ProcessWasm) + +ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp) + : ProcessGDBRemote(target_sp, listener_sp) { + assert(target_sp); + // Wasm doesn't have any Unix-like signals as a platform concept, but pretend + // like it does to appease LLDB. + m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture()); +} + +void ProcessWasm::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + }); +} + +void ProcessWasm::DebuggerInitialize(Debugger &debugger) { + ProcessGDBRemote::DebuggerInitialize(debugger); +} + +llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); } + +llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; } + +llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() { + return "GDB Remote protocol based WebAssembly debugging plug-in."; +} + +void ProcessWasm::Terminate() { + PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance); +} + +lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect) { + if (crash_file_path == nullptr) + return std::make_shared<ProcessWasm>(target_sp, listener_sp); + return {}; +} + +bool ProcessWasm::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + if (plugin_specified_by_name) + return true; + + if (Module *exe_module = target_sp->GetExecutableModulePointer()) { + if (ObjectFile *exe_objfile = exe_module->GetObjectFile()) + return exe_objfile->GetArchitecture().GetMachine() == + llvm::Triple::wasm32; + } + + // However, if there is no wasm module, we return false, otherwise, + // we might use ProcessWasm to attach gdb remote. + return false; +} + +std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) { + return std::make_shared<ThreadWasm>(*this, tid); +} + +size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) { + wasm_addr_t wasm_addr(vm_addr); + + switch (wasm_addr.GetType()) { + case WasmAddressType::Memory: + case WasmAddressType::Object: + return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error); + case WasmAddressType::Invalid: + error.FromErrorStringWithFormat( + "Wasm read failed for invalid address 0x%" PRIx64, vm_addr); + return 0; + } +} + +llvm::Expected<std::vector<lldb::addr_t>> +ProcessWasm::GetWasmCallStack(lldb::tid_t tid) { + StreamString packet; + packet.Printf("qWasmCallStack:"); + packet.Printf("%" PRIx64, tid); + + StringExtractorGDBRemote response; + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) != + GDBRemoteCommunication::PacketResult::Success) + return llvm::createStringError("failed to send qWasmCallStack"); + + if (!response.IsNormalResponse()) + return llvm::createStringError("failed to get response for qWasmCallStack"); + + WritableDataBufferSP data_buffer_sp = + std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0); + const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc'); + if (bytes == 0 || bytes % sizeof(uint64_t) != 0) + return llvm::createStringError("invalid response for qWasmCallStack"); + + // To match the Wasm specification, the addresses are encoded in little endian + // byte order. + DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle, + GetAddressByteSize()); + lldb::offset_t offset = 0; + std::vector<lldb::addr_t> call_stack_pcs; + while (offset < bytes) + call_stack_pcs.push_back(data.GetU64(&offset)); + + return call_stack_pcs; +} diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h new file mode 100644 index 0000000..bab14a8 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// 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_PLUGINS_PROCESS_WASM_PROCESSWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H + +#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" + +namespace lldb_private { +namespace wasm { + +/// Each WebAssembly module has separated address spaces for Code and Memory. +/// A WebAssembly module also has a Data section which, when the module is +/// loaded, gets mapped into a region in the module Memory. +enum WasmAddressType : uint8_t { Memory = 0x00, Object = 0x01, Invalid = 0xff }; + +/// For the purpose of debugging, we can represent all these separated 32-bit +/// address spaces with a single virtual 64-bit address space. The +/// wasm_addr_t provides this encoding using bitfields. +struct wasm_addr_t { + uint64_t offset : 32; + uint64_t module_id : 30; + uint64_t type : 2; + + wasm_addr_t(lldb::addr_t addr) + : offset(addr & 0x00000000ffffffff), + module_id((addr & 0x00ffffff00000000) >> 32), type(addr >> 62) {} + + wasm_addr_t(WasmAddressType type, uint32_t module_id, uint32_t offset) + : offset(offset), module_id(module_id), type(type) {} + + WasmAddressType GetType() { return static_cast<WasmAddressType>(type); } + + operator lldb::addr_t() { return *(uint64_t *)this; } +}; + +static_assert(sizeof(wasm_addr_t) == 8, ""); + +/// ProcessWasm provides the access to the Wasm program state +/// retrieved from the Wasm engine. +class ProcessWasm : public process_gdb_remote::ProcessGDBRemote { +public: + ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + ~ProcessWasm() override = default; + + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect); + + static void Initialize(); + static void DebuggerInitialize(Debugger &debugger); + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic(); + static llvm::StringRef GetPluginDescriptionStatic(); + + llvm::StringRef GetPluginName() override; + + size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + /// Retrieve the current call stack from the WebAssembly remote process. + llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack(lldb::tid_t tid); + +protected: + std::shared_ptr<process_gdb_remote::ThreadGDBRemote> + CreateThread(lldb::tid_t tid) override; + +private: + friend class UnwindWasm; + process_gdb_remote::GDBRemoteDynamicRegisterInfoSP &GetRegisterInfo() { + return m_register_info_sp; + } + + ProcessWasm(const ProcessWasm &); + const ProcessWasm &operator=(const ProcessWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp new file mode 100644 index 0000000..a6553ff --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// 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 "ThreadWasm.h" + +#include "ProcessWasm.h" +#include "UnwindWasm.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +Unwind &ThreadWasm::GetUnwinder() { + if (!m_unwinder_up) { + assert(CalculateTarget()->GetArchitecture().GetMachine() == + llvm::Triple::wasm32); + m_unwinder_up.reset(new wasm::UnwindWasm(*this)); + } + return *m_unwinder_up; +} + +llvm::Expected<std::vector<lldb::addr_t>> ThreadWasm::GetWasmCallStack() { + if (ProcessSP process_sp = GetProcess()) { + ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get()); + return wasm_process->GetWasmCallStack(GetID()); + } + return llvm::createStringError("no process"); +} diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.h b/lldb/source/Plugins/Process/wasm/ThreadWasm.h new file mode 100644 index 0000000..1c90f58 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.h @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// +// 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_PLUGINS_PROCESS_WASM_THREADWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H + +#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h" + +namespace lldb_private { +namespace wasm { + +/// ProcessWasm provides the access to the Wasm program state +/// retrieved from the Wasm engine. +class ThreadWasm : public process_gdb_remote::ThreadGDBRemote { +public: + ThreadWasm(Process &process, lldb::tid_t tid) + : process_gdb_remote::ThreadGDBRemote(process, tid) {} + ~ThreadWasm() override = default; + + /// Retrieve the current call stack from the WebAssembly remote process. + llvm::Expected<std::vector<lldb::addr_t>> GetWasmCallStack(); + +protected: + Unwind &GetUnwinder() override; + + ThreadWasm(const ThreadWasm &); + const ThreadWasm &operator=(const ThreadWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp new file mode 100644 index 0000000..99845dd --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 "UnwindWasm.h" +#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h" +#include "ProcessWasm.h" +#include "ThreadWasm.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; +using namespace process_gdb_remote; +using namespace wasm; + +class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext { +public: + WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread, + uint32_t concrete_frame_idx, + GDBRemoteDynamicRegisterInfoSP ®_info_sp, + uint64_t pc) + : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false, + false) { + // Wasm does not have a fixed set of registers but relies on a mechanism + // named local and global variables to store information such as the stack + // pointer. The only actual register is the PC. + PrivateSetRegisterValue(0, pc); + } +}; + +lldb::RegisterContextSP +UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) { + if (m_frames.size() <= frame->GetFrameIndex()) + return lldb::RegisterContextSP(); + + ThreadSP thread = frame->GetThread(); + ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread.get()); + ProcessWasm *wasm_process = + static_cast<ProcessWasm *>(thread->GetProcess().get()); + + return std::make_shared<WasmGDBRemoteRegisterContext>( + *gdb_thread, frame->GetConcreteFrameIndex(), + wasm_process->GetRegisterInfo(), m_frames[frame->GetFrameIndex()]); +} + +uint32_t UnwindWasm::DoGetFrameCount() { + if (m_unwind_complete) + return m_frames.size(); + + m_unwind_complete = true; + m_frames.clear(); + + ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread()); + llvm::Expected<std::vector<lldb::addr_t>> call_stack_pcs = + wasm_thread.GetWasmCallStack(); + if (!call_stack_pcs) { + LLDB_LOG_ERROR(GetLog(LLDBLog::Unwind), call_stack_pcs.takeError(), + "Failed to get Wasm callstack: {0}"); + m_frames.clear(); + return 0; + } + + m_frames = *call_stack_pcs; + return m_frames.size(); +} + +bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, + lldb::addr_t &pc, + bool &behaves_like_zeroth_frame) { + if (m_frames.size() == 0) + DoGetFrameCount(); + + if (frame_idx >= m_frames.size()) + return false; + + behaves_like_zeroth_frame = (frame_idx == 0); + cfa = 0; + pc = m_frames[frame_idx]; + return true; +} diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h new file mode 100644 index 0000000..ff5e06d --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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_PLUGINS_PROCESS_WASM_UNWINDWASM_H +#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_UNWINDWASM_H + +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Unwind.h" +#include <vector> + +namespace lldb_private { +namespace wasm { + +/// UnwindWasm manages stack unwinding for a WebAssembly process. +class UnwindWasm : public lldb_private::Unwind { +public: + UnwindWasm(lldb_private::Thread &thread) : Unwind(thread) {} + ~UnwindWasm() override = default; + +protected: + void DoClear() override { + m_frames.clear(); + m_unwind_complete = false; + } + + uint32_t DoGetFrameCount() override; + + bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, + lldb::addr_t &pc, + bool &behaves_like_zeroth_frame) override; + + lldb::RegisterContextSP + DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; + +private: + std::vector<lldb::addr_t> m_frames; + bool m_unwind_complete = false; + + UnwindWasm(const UnwindWasm &); + const UnwindWasm &operator=(const UnwindWasm &) = delete; +}; + +} // namespace wasm +} // namespace lldb_private + +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt index db9e11b..0437094 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/CMakeLists.txt @@ -26,6 +26,7 @@ add_lldb_library(lldbPluginScriptInterpreterPythonInterfaces PLUGIN ScriptedProcessPythonInterface.cpp ScriptedPythonInterface.cpp ScriptedStopHookPythonInterface.cpp + ScriptedBreakpointPythonInterface.cpp ScriptedThreadPlanPythonInterface.cpp ScriptedThreadPythonInterface.cpp diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp index 1fd3299..d43036d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.cpp @@ -29,6 +29,7 @@ void ScriptInterpreterPythonInterfaces::Initialize() { ScriptedPlatformPythonInterface::Initialize(); ScriptedProcessPythonInterface::Initialize(); ScriptedStopHookPythonInterface::Initialize(); + ScriptedBreakpointPythonInterface::Initialize(); ScriptedThreadPlanPythonInterface::Initialize(); } @@ -37,6 +38,7 @@ void ScriptInterpreterPythonInterfaces::Terminate() { ScriptedPlatformPythonInterface::Terminate(); ScriptedProcessPythonInterface::Terminate(); ScriptedStopHookPythonInterface::Terminate(); + ScriptedBreakpointPythonInterface::Terminate(); ScriptedThreadPlanPythonInterface::Terminate(); } diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h index 26c80b7..02dc065 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptInterpreterPythonInterfaces.h @@ -16,6 +16,7 @@ #if LLDB_ENABLE_PYTHON #include "OperatingSystemPythonInterface.h" +#include "ScriptedBreakpointPythonInterface.h" #include "ScriptedPlatformPythonInterface.h" #include "ScriptedProcessPythonInterface.h" #include "ScriptedStopHookPythonInterface.h" diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp new file mode 100644 index 0000000..660edaa --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.cpp @@ -0,0 +1,100 @@ +//===----------------------------------------------------------------------===// +// +// 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 "lldb/Core/PluginManager.h" +#include "lldb/Host/Config.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Log.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "../lldb-python.h" + +#include "../SWIGPythonBridge.h" +#include "../ScriptInterpreterPythonImpl.h" +#include "ScriptedBreakpointPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; + +ScriptedBreakpointPythonInterface::ScriptedBreakpointPythonInterface( + ScriptInterpreterPythonImpl &interpreter) + : ScriptedBreakpointInterface(), ScriptedPythonInterface(interpreter) {} + +llvm::Expected<StructuredData::GenericSP> +ScriptedBreakpointPythonInterface::CreatePluginObject( + llvm::StringRef class_name, lldb::BreakpointSP break_sp, + const StructuredDataImpl &args_sp) { + return ScriptedPythonInterface::CreatePluginObject(class_name, nullptr, + break_sp, args_sp); +} + +bool ScriptedBreakpointPythonInterface::ResolverCallback( + SymbolContext sym_ctx) { + Status error; + + StructuredData::ObjectSP obj = Dispatch("__callback__", error, sym_ctx); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + Log *log = GetLog(LLDBLog::Script); + LLDB_LOG(log, "Error calling __callback__ method: {1}", error); + return true; + } + return obj->GetBooleanValue(); +} + +lldb::SearchDepth ScriptedBreakpointPythonInterface::GetDepth() { + Status error; + StructuredData::ObjectSP obj = Dispatch("__get_depth__", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + return lldb::eSearchDepthModule; + } + uint64_t value = obj->GetUnsignedIntegerValue(); + if (value <= lldb::kLastSearchDepthKind) + return (lldb::SearchDepth)value; + // This is what we were doing on error before, though I'm not sure that's + // better than returning eSearchDepthInvalid. + return lldb::eSearchDepthModule; +} + +std::optional<std::string> ScriptedBreakpointPythonInterface::GetShortHelp() { + Status error; + StructuredData::ObjectSP obj = Dispatch("get_short_help", error); + + if (!ScriptedInterface::CheckStructuredDataObject(LLVM_PRETTY_FUNCTION, obj, + error)) { + return {}; + } + + return obj->GetAsString()->GetValue().str(); +} + +void ScriptedBreakpointPythonInterface::Initialize() { + const std::vector<llvm::StringRef> ci_usages = { + "breakpoint set -P classname [-k key -v value ...]"}; + const std::vector<llvm::StringRef> api_usages = { + "SBTarget.BreakpointCreateFromScript"}; + PluginManager::RegisterPlugin( + GetPluginNameStatic(), + llvm::StringRef("Create a breakpoint that chooses locations based on " + "user-created callbacks"), + CreateInstance, eScriptLanguagePython, {ci_usages, api_usages}); +} + +void ScriptedBreakpointPythonInterface::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +#endif diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h new file mode 100644 index 0000000..27bdd871 --- /dev/null +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedBreakpointPythonInterface.h @@ -0,0 +1,53 @@ +//===-- ScriptedBreakpointPythonInterface.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_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" +#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h" + +#if LLDB_ENABLE_PYTHON + +#include "ScriptedPythonInterface.h" + +namespace lldb_private { +class ScriptedBreakpointPythonInterface : public ScriptedBreakpointInterface, + public ScriptedPythonInterface, + public PluginInterface { +public: + ScriptedBreakpointPythonInterface(ScriptInterpreterPythonImpl &interpreter); + + llvm::Expected<StructuredData::GenericSP> + CreatePluginObject(llvm::StringRef class_name, lldb::BreakpointSP break_sp, + const StructuredDataImpl &args_sp) override; + + llvm::SmallVector<AbstractMethodRequirement> + GetAbstractMethodRequirements() const override { + return llvm::SmallVector<AbstractMethodRequirement>({{"__callback__", 2}}); + } + + bool ResolverCallback(SymbolContext sym_ctx) override; + lldb::SearchDepth GetDepth() override; + std::optional<std::string> GetShortHelp() override; + + static void Initialize(); + + static void Terminate(); + + static llvm::StringRef GetPluginNameStatic() { + return "ScriptedBreakpointPythonInterface"; + } + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_INTERFACES_SCRIPTEDBREAKPOINTPYTHONINTERFACE_H diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp index cf11c06..b49d1d8 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.cpp @@ -17,6 +17,7 @@ #include "../ScriptInterpreterPythonImpl.h" #include "ScriptedPythonInterface.h" +#include "lldb/Symbol/SymbolContext.h" #include <optional> using namespace lldb; @@ -80,6 +81,20 @@ ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( } template <> +SymbolContext +ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>( + python::PythonObject &p, Status &error) { + if (lldb::SBSymbolContext *sb_symbol_context = + reinterpret_cast<lldb::SBSymbolContext *>( + python::LLDBSWIGPython_CastPyObjectToSBSymbolContext(p.get()))) + return m_interpreter.GetOpaqueTypeFromSBSymbolContext(*sb_symbol_context); + error = Status::FromErrorString( + "Couldn't cast lldb::SBSymbolContext to lldb_private::SymbolContext."); + + return {}; +} + +template <> lldb::DataExtractorSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::DataExtractorSP>( python::PythonObject &p, Status &error) { diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index b38b65e..f769d3d 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -432,6 +432,10 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(lldb::BreakpointSP arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::ProcessSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg); } @@ -452,6 +456,10 @@ protected: return python::SWIGBridge::ToSWIGWrapper(arg); } + python::PythonObject Transform(const SymbolContext &arg) { + return python::SWIGBridge::ToSWIGWrapper(arg); + } + python::PythonObject Transform(lldb::StreamSP arg) { return python::SWIGBridge::ToSWIGWrapper(arg.get()); } @@ -556,6 +564,11 @@ Event *ScriptedPythonInterface::ExtractValueFromPythonObject<Event *>( python::PythonObject &p, Status &error); template <> +SymbolContext +ScriptedPythonInterface::ExtractValueFromPythonObject<SymbolContext>( + python::PythonObject &p, Status &error); + +template <> lldb::StreamSP ScriptedPythonInterface::ExtractValueFromPythonObject<lldb::StreamSP>( python::PythonObject &p, Status &error); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h index 504b3aa..4137786 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -151,15 +151,6 @@ public: const char *session_dictionary_name, lldb::DebuggerSP debugger_sp); - static python::PythonObject LLDBSwigPythonCreateScriptedBreakpointResolver( - const char *python_class_name, const char *session_dictionary_name, - const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp); - - static unsigned int - LLDBSwigPythonCallBreakpointResolver(void *implementor, - const char *method_name, - lldb_private::SymbolContext *sym_ctx); - static size_t LLDBSwigPython_CalculateNumChildren(PyObject *implementor, uint32_t max); @@ -270,6 +261,7 @@ void *LLDBSWIGPython_CastPyObjectToSBLaunchInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBError(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBEvent(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data); +void *LLDBSWIGPython_CastPyObjectToSBSymbolContext(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBMemoryRegionInfo(PyObject *data); void *LLDBSWIGPython_CastPyObjectToSBExecutionContext(PyObject *data); diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 0c864dc..ce77569 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -1496,7 +1496,7 @@ lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments( } if (py_return.get()) { PythonList result_list(PyRefType::Borrowed, py_return.get()); - ValueObjectListSP result = ValueObjectListSP(new ValueObjectList()); + ValueObjectListSP result = std::make_shared<ValueObjectList>(); for (size_t i = 0; i < result_list.GetSize(); i++) { PyObject *item = result_list.GetItemAtIndex(i).get(); lldb::SBValue *sb_value_ptr = @@ -1550,6 +1550,11 @@ ScriptInterpreterPythonImpl::CreateScriptedStopHookInterface() { return std::make_shared<ScriptedStopHookPythonInterface>(*this); } +ScriptedBreakpointInterfaceSP +ScriptInterpreterPythonImpl::CreateScriptedBreakpointInterface() { + return std::make_shared<ScriptedBreakpointPythonInterface>(*this); +} + ScriptedThreadInterfaceSP ScriptInterpreterPythonImpl::CreateScriptedThreadInterface() { return std::make_shared<ScriptedThreadPythonInterface>(*this); @@ -1576,75 +1581,6 @@ ScriptInterpreterPythonImpl::CreateStructuredDataFromScriptObject( return py_obj.CreateStructuredObject(); } -StructuredData::GenericSP -ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( - const char *class_name, const StructuredDataImpl &args_data, - lldb::BreakpointSP &bkpt_sp) { - - if (class_name == nullptr || class_name[0] == '\0') - return StructuredData::GenericSP(); - - if (!bkpt_sp.get()) - return StructuredData::GenericSP(); - - Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); - ScriptInterpreterPythonImpl *python_interpreter = - GetPythonInterpreter(debugger); - - if (!python_interpreter) - return StructuredData::GenericSP(); - - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - - PythonObject ret_val = - SWIGBridge::LLDBSwigPythonCreateScriptedBreakpointResolver( - class_name, python_interpreter->m_dictionary_name.c_str(), args_data, - bkpt_sp); - - return StructuredData::GenericSP( - new StructuredPythonObject(std::move(ret_val))); -} - -bool ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchCallback( - StructuredData::GenericSP implementor_sp, SymbolContext *sym_ctx) { - bool should_continue = false; - - if (implementor_sp) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - should_continue = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - implementor_sp->GetValue(), "__callback__", sym_ctx); - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - } - return should_continue; -} - -lldb::SearchDepth -ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( - StructuredData::GenericSP implementor_sp) { - int depth_as_int = lldb::eSearchDepthModule; - if (implementor_sp) { - Locker py_lock(this, - Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); - depth_as_int = SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - implementor_sp->GetValue(), "__get_depth__", nullptr); - if (PyErr_Occurred()) { - PyErr_Print(); - PyErr_Clear(); - } - } - if (depth_as_int == lldb::eSearchDepthInvalid) - return lldb::eSearchDepthModule; - - if (depth_as_int <= lldb::kLastSearchDepthKind) - return (lldb::SearchDepth)depth_as_int; - return lldb::eSearchDepthModule; -} - StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { @@ -3047,7 +2983,7 @@ bool ScriptInterpreterPythonImpl::SetOptionValueForCommandObject( lldb::ExecutionContextRefSP exe_ctx_ref_sp; if (exe_ctx) - exe_ctx_ref_sp.reset(new ExecutionContextRef(exe_ctx)); + exe_ctx_ref_sp = std::make_shared<ExecutionContextRef>(exe_ctx); PythonObject ctx_ref_obj = SWIGBridge::ToSWIGWrapper(exe_ctx_ref_sp); bool py_return = unwrapOrSetPythonException(As<bool>( diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 5d77608..4698b82a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -81,17 +81,6 @@ public: CreateStructuredDataFromScriptObject(ScriptObject obj) override; StructuredData::GenericSP - CreateScriptedBreakpointResolver(const char *class_name, - const StructuredDataImpl &args_data, - lldb::BreakpointSP &bkpt_sp) override; - bool ScriptedBreakpointResolverSearchCallback( - StructuredData::GenericSP implementor_sp, - SymbolContext *sym_ctx) override; - - lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( - StructuredData::GenericSP implementor_sp) override; - - StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; lldb::ValueObjectListSP @@ -105,6 +94,9 @@ public: lldb::ScriptedStopHookInterfaceSP CreateScriptedStopHookInterface() override; + lldb::ScriptedBreakpointInterfaceSP + CreateScriptedBreakpointInterface() override; + lldb::ScriptedThreadInterfaceSP CreateScriptedThreadInterface() override; lldb::ScriptedThreadPlanInterfaceSP diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index 82f18c5..867f6a6 100644 --- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -574,8 +574,7 @@ public: return config_sp; // Handle source stream flags. - auto source_flags_sp = - StructuredData::DictionarySP(new StructuredData::Dictionary()); + auto source_flags_sp = std::make_shared<StructuredData::Dictionary>(); config_sp->AddItem("source-flags", source_flags_sp); source_flags_sp->AddBooleanItem("any-process", m_include_any_process); @@ -591,8 +590,7 @@ public: // Handle filter rules if (!m_filter_rules.empty()) { - auto json_filter_rules_sp = - StructuredData::ArraySP(new StructuredData::Array); + auto json_filter_rules_sp = std::make_shared<StructuredData::Array>(); config_sp->AddItem("filter-rules", json_filter_rules_sp); for (auto &rule_sp : m_filter_rules) { if (!rule_sp) diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp index e5ba029..1e51dda 100644 --- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp +++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp @@ -46,6 +46,7 @@ #include <cstring> #include <dirent.h> #include <dlfcn.h> +#include <memory> #include <optional> #include <pwd.h> @@ -188,7 +189,7 @@ std::optional<ModuleSpec> SymbolLocatorDebugSymbols::LocateExecutableObjectFile( exe_spec.GetFileSpec() = module_spec.GetFileSpec(); exe_spec.GetUUID() = module_spec.GetUUID(); ModuleSP module_sp; - module_sp.reset(new Module(exe_spec)); + module_sp = std::make_shared<Module>(exe_spec); if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec(exe_spec)) { success = true; @@ -630,7 +631,7 @@ static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, exe_spec.GetFileSpec() = module_spec.GetFileSpec(); exe_spec.GetUUID() = module_spec.GetUUID(); ModuleSP module_sp; - module_sp.reset(new Module(exe_spec)); + module_sp = std::make_shared<Module>(exe_spec); if (module_sp && module_sp->GetObjectFile() && module_sp->MatchesModuleSpec(exe_spec)) { success = true; diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp index 7cf8750..aaa4ccd 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AbortWithPayloadFrameRecognizer.cpp @@ -128,7 +128,7 @@ AbortWithPayloadFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { Value *cur_value; StackFrame *frame = frame_sp.get(); - ValueObjectListSP arguments_sp = ValueObjectListSP(new ValueObjectList()); + ValueObjectListSP arguments_sp = std::make_shared<ValueObjectList>(); auto add_to_arguments = [&](llvm::StringRef name, Value *value, bool dynamic) { diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 0a886e5..b7adae4 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -9,6 +9,7 @@ #include <algorithm> #include <cstdio> #include <iterator> +#include <memory> #include <optional> #include "lldb/Core/Module.h" @@ -246,7 +247,7 @@ public: TypeAppendVisitor(TypeListImpl &type_list) : m_type_list(type_list) {} bool operator()(const lldb::TypeSP &type) { - m_type_list.Append(TypeImplSP(new TypeImpl(type))); + m_type_list.Append(std::make_shared<TypeImpl>(type)); return true; } diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp index 9da06e8..7e58e8b 100644 --- a/lldb/source/Target/InstrumentationRuntime.cpp +++ b/lldb/source/Target/InstrumentationRuntime.cpp @@ -49,10 +49,10 @@ void InstrumentationRuntime::ModulesDidLoad( return; } - module_list.ForEach([this](const lldb::ModuleSP module_sp) -> bool { + module_list.ForEach([this](const lldb::ModuleSP module_sp) { const FileSpec &file_spec = module_sp->GetFileSpec(); if (!file_spec) - return true; // Keep iterating. + return IterationAction::Continue; const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary(); if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) || @@ -62,16 +62,16 @@ void InstrumentationRuntime::ModulesDidLoad( Activate(); if (!IsActive()) SetRuntimeModuleSP({}); // Don't cache module if activation failed. - return false; // Stop iterating, we're done. + return IterationAction::Stop; } } - return true; + return IterationAction::Continue; }); } lldb::ThreadCollectionSP InstrumentationRuntime::GetBacktracesFromExtendedStopInfo( StructuredData::ObjectSP info) { - return ThreadCollectionSP(new ThreadCollection()); + return std::make_shared<ThreadCollection>(); } diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 8000cd0..e9d9c8f 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -2076,6 +2076,13 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, trap_opcode_size = sizeof(g_loongarch_opcode); } break; + case llvm::Triple::wasm32: { + // Unreachable (0x00) triggers an unconditional trap. + static const uint8_t g_wasm_opcode[] = {0x00}; + trap_opcode = g_wasm_opcode; + trap_opcode_size = sizeof(g_wasm_opcode); + } break; + default: return 0; } diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 16cd254..aedfc52 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -783,6 +783,8 @@ void StackFrameList::SelectMostRelevantFrame() { uint32_t StackFrameList::GetSelectedFrameIndex(SelectMostRelevant select_most_relevant) { + std::lock_guard<std::recursive_mutex> guard(m_selected_frame_mutex); + if (!m_selected_frame_idx && select_most_relevant) SelectMostRelevantFrame(); if (!m_selected_frame_idx) { @@ -798,6 +800,8 @@ StackFrameList::GetSelectedFrameIndex(SelectMostRelevant select_most_relevant) { uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { std::shared_lock<std::shared_mutex> guard(m_list_mutex); + std::lock_guard<std::recursive_mutex> selected_frame_guard( + m_selected_frame_mutex); const_iterator pos; const_iterator begin = m_frames.begin(); @@ -851,6 +855,8 @@ void StackFrameList::Clear() { std::unique_lock<std::shared_mutex> guard(m_list_mutex); m_frames.clear(); m_concrete_frames_fetched = 0; + std::lock_guard<std::recursive_mutex> selected_frame_guard( + m_selected_frame_mutex); m_selected_frame_idx.reset(); } diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index d23c1fa..9d5116c 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -41,7 +41,7 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { ValueObjectListSP args = m_interpreter->GetRecognizedArguments(m_python_object_sp, frame); - auto args_synthesized = ValueObjectListSP(new ValueObjectList()); + auto args_synthesized = std::make_shared<ValueObjectList>(); if (args) { for (const auto &o : args->GetObjects()) args_synthesized->Append(ValueObjectRecognizerSynthesizedValue::Create( diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 86ae7dd..4f39f60 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -36,6 +36,7 @@ #include "lldb/Host/StreamFile.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/Interfaces/ScriptedBreakpointInterface.h" #include "lldb/Interpreter/Interfaces/ScriptedStopHookInterface.h" #include "lldb/Interpreter/OptionGroupWatchpoint.h" #include "lldb/Interpreter/OptionValues.h" @@ -2487,9 +2488,9 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec, ModuleList found_modules; m_images.FindModules(module_spec_copy, found_modules); - found_modules.ForEach([&](const ModuleSP &found_module) -> bool { + found_modules.ForEach([&](const ModuleSP &found_module) { old_modules.push_back(found_module); - return true; + return IterationAction::Continue; }); } diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 78e1270..dca96cc 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -428,8 +428,8 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { top_most_line_entry.line = call_site.GetLine(); top_most_line_entry.column = call_site.GetColumn(); FileSpec call_site_file_spec = call_site.GetFile(); - top_most_line_entry.original_file_sp.reset( - new SupportFile(call_site_file_spec)); + top_most_line_entry.original_file_sp = + std::make_shared<SupportFile>(call_site_file_spec); top_most_line_entry.range = range; top_most_line_entry.file_sp.reset(); top_most_line_entry.ApplyFileMappings( diff --git a/lldb/test/API/commands/register/register/aarch64_mte_ctrl_register/TestMTECtrlRegister.py b/lldb/test/API/commands/register/register/aarch64_mte_ctrl_register/TestMTECtrlRegister.py index 2570f26..c003d87 100644 --- a/lldb/test/API/commands/register/register/aarch64_mte_ctrl_register/TestMTECtrlRegister.py +++ b/lldb/test/API/commands/register/register/aarch64_mte_ctrl_register/TestMTECtrlRegister.py @@ -34,29 +34,41 @@ class MTECtrlRegisterTestCase(TestBase): substrs=["stop reason = breakpoint 1."], ) - def check_mte_ctrl(async_err, sync_err): + has_store_only = self.isAArch64MTEStoreOnly() + + def check_mte_ctrl(async_err, sync_err, store_only): # Bit 0 = tagged addressing enabled # Bit 1 = synchronous faults # Bit 2 = asynchronous faults - value = "0x{:016x}".format((async_err << 2) | (sync_err << 1) | 1) + # Bit 19 = store only checking mode + value = "0x{:016x}".format( + (store_only << 19) | (async_err << 2) | (sync_err << 1) | 1 + ) expected = [value] if self.hasXMLSupport(): + fields = "(" + if has_store_only: + fields += f"STORE_ONLY = {store_only}, " + tfc_modes = ["NONE", "SYNC", "ASYNC", "ASYMM"] - expected.append( - f"(TAGS = 0, TCF = TCF_{tfc_modes[async_err << 1 | sync_err]}, TAGGED_ADDR_ENABLE = 1)".format( - async_err, sync_err - ) - ) + fields += f"TAGS = 0, TCF = TCF_{tfc_modes[async_err << 1 | sync_err]}, TAGGED_ADDR_ENABLE = 1)" + + expected.append(fields) self.expect("register read mte_ctrl", substrs=expected) # We start enabled with synchronous faults. - check_mte_ctrl(0, 1) + check_mte_ctrl(0, 1, 0) # Change to asynchronous faults. self.runCmd("register write mte_ctrl 5") - check_mte_ctrl(1, 0) + check_mte_ctrl(1, 0, 0) # This would return to synchronous faults if we did not restore the # previous value. self.expect("expression setup_mte()", substrs=["= 0"]) - check_mte_ctrl(1, 0) + check_mte_ctrl(1, 0, 0) + + # Store only checking requires FEAT_MTE_STORE_ONLY. + if has_store_only: + self.runCmd(f"register write mte_ctrl {1 | (1 << 19)}") + check_mte_ctrl(0, 0, 1) diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py index 0a1003a..634940d 100644 --- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/TestScriptedResolver.py @@ -235,11 +235,13 @@ class TestScriptedResolver(TestBase): substrs=["2"], msg="Was only passed modules", ) - + print(f"Made first breakpoint: {bkpt}") + bkpt = None # Make a breakpoint that asks for modules, check that we didn't get any files: bkpt = target.BreakpointCreateFromScript( "resolver.ResolverModuleDepth", extra_args, module_list, file_list ) + print(f"Made Second breakpoint: {bkpt}") self.assertGreater( bkpt.GetNumLocations(), 0, "ResolverModuleDepth got no locations." ) diff --git a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py index 8b91702..85c73401 100644 --- a/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py +++ b/lldb/test/API/functionalities/breakpoint/scripted_bkpt/resolver.py @@ -13,6 +13,7 @@ class Resolver: Resolver.got_files = 0 def __callback__(self, sym_ctx): + print("Resolver callback called") sym_name = "not_a_real_function_name" sym_item = self.extra_args.GetValueForKey("symbol") if sym_item.IsValid(): @@ -34,9 +35,18 @@ class Resolver: return if sym_ctx.module.IsValid(): + print(f"Looking for {sym_name}") sym = sym_ctx.module.FindSymbol(sym_name, lldb.eSymbolTypeCode) if sym.IsValid(): + print(f"Adding location at {sym.GetStartAddress()} to {self.bkpt}") self.bkpt.AddLocation(sym.GetStartAddress()) + print(f"After addition: {self.bkpt}") + else: + print("Didn't find it, however...") + + print(f"GotFiles: {Resolver.got_files}") + for func in Resolver.func_list: + print(f"Function: func") def get_short_help(self): return "I am a python breakpoint resolver" @@ -46,17 +56,31 @@ class ResolverModuleDepth(Resolver): def __get_depth__(self): return lldb.eSearchDepthModule + def __callback__(self, sym_ctx): + print(f"About to call the Resolver callback for {self.bkpt}") + Resolver.__callback__(self, sym_ctx) + print("Called the callback for ResolverModuleDepth") + class ResolverCUDepth(Resolver): def __get_depth__(self): return lldb.eSearchDepthCompUnit + def __callback__(self, sym_ctx): + Resolver.__callback__(self, sym_ctx) + class ResolverFuncDepth(Resolver): def __get_depth__(self): return lldb.eSearchDepthFunction + def __callback__(self, sym_ctx): + Resolver.__callback__(self, sym_ctx) + class ResolverBadDepth(Resolver): def __get_depth__(self): return lldb.kLastSearchDepthKind + 1 + + def __callback__(self, sym_ctx): + Resolver.__callback__(self, sym_ctx) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py index f52f6f7..2332eff 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/deque/TestDataFormatterGenericDeque.py @@ -3,9 +3,6 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil -USE_LIBSTDCPP = "USE_LIBSTDCPP" -USE_LIBCPP = "USE_LIBCPP" - class GenericDequeDataFormatterTestCase(TestBase): def findVariable(self, name): @@ -56,8 +53,7 @@ class GenericDequeDataFormatterTestCase(TestBase): ], ) - def do_test(self, stdlib_type): - self.build(dictionary={stdlib_type: "1"}) + def do_test(self): (_, process, _, bkpt) = lldbutil.run_to_source_breakpoint( self, "break here", lldb.SBFileSpec("main.cpp") ) @@ -135,15 +131,22 @@ class GenericDequeDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) def test_libstdcpp(self): - self.do_test(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test() @add_test_categories(["libc++"]) def test_libcpp(self): - self.do_test(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test() - def do_test_ref_and_ptr(self, stdlib_type: str): + def do_test_ref_and_ptr(self): """Test formatting of std::deque& and std::deque*""" - self.build(dictionary={stdlib_type: "1"}) (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "stop here", lldb.SBFileSpec("main.cpp", False) ) @@ -157,8 +160,15 @@ class GenericDequeDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) def test_libstdcpp_ref_and_ptr(self): - self.do_test_ref_and_ptr(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_ref_and_ptr() @add_test_categories(["libc++"]) def test_libcpp_ref_and_ptr(self): - self.do_test_ref_and_ptr(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_ref_and_ptr() + + @add_test_categories(["msvcstl"]) + def test_msvcstl_ref_and_ptr(self): + self.build() + self.do_test_ref_and_ptr() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py index 5851588..07d6c96 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/TestDataFormatterStdMap.py @@ -21,7 +21,7 @@ class StdMapDataFormatterTestCase(TestBase): ] return ValueCheck(children=pair_children) - def do_test(self): + def do_test(self, *, supports_end_iter=False): """Test that that file and class static variables display correctly.""" self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) @@ -143,6 +143,9 @@ class StdMapDataFormatterTestCase(TestBase): ValueCheck(name="second", value="0"), ], ) + if supports_end_iter: + self.expect("frame variable it_end", substrs=["= end"]) + self.expect("frame variable const_it_end", substrs=["= end"]) # check that MightHaveChildren() gets it right self.assertTrue( @@ -343,3 +346,9 @@ class StdMapDataFormatterTestCase(TestBase): dictionary={"USE_LIBSTDCPP": 1, "CXXFLAGS_EXTRAS": "-D_GLIBCXX_DEBUG"} ) self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test(supports_end_iter=True) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/main.cpp index 91bdf0b..a626f17 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/map/main.cpp @@ -26,6 +26,8 @@ int main() { intint_map::iterator it = ii.begin(); intint_map::const_iterator const_it = ii.cbegin(); std::printf("%d %d\n", it->second, const_it->second); + intint_map::iterator it_end = ii.end(); + intint_map::const_iterator const_it_end = ii.cend(); thefoo_rw(1); // Set break point at this line. ii[2] = 0; diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py index 5c0e159..7ac7971 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multimap/TestDataFormatterGenericMultiMap.py @@ -9,9 +9,6 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil -USE_LIBSTDCPP = "USE_LIBSTDCPP" -USE_LIBCPP = "USE_LIBCPP" - class GenericMultiMapDataFormatterTestCase(TestBase): def setUp(self): @@ -38,9 +35,8 @@ class GenericMultiMapDataFormatterTestCase(TestBase): var_name, type=self.getVariableType(var_name), children=children ) - def do_test_with_run_command(self, stdlib_type): + def do_test_with_run_command(self): """Test that that file and class static variables display correctly.""" - self.build(dictionary={stdlib_type: "1"}) self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) bkpt = self.target().FindBreakpointByID( @@ -331,9 +327,17 @@ class GenericMultiMapDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) @skipIf(compiler="clang", compiler_version=["<", "9.0"]) def test_with_run_command_libstdcpp(self): - self.do_test_with_run_command(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_with_run_command() @skipIf(compiler="clang", compiler_version=["<", "9.0"]) @add_test_categories(["libc++"]) def test_with_run_command_libcpp(self): - self.do_test_with_run_command(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_with_run_command() + + @add_test_categories(["msvcstl"]) + def test_with_run_command_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test_with_run_command() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py index 24ab4de..7e922fc 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/multiset/TestDataFormatterGenericMultiSet.py @@ -8,9 +8,6 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil -USE_LIBSTDCPP = "USE_LIBSTDCPP" -USE_LIBCPP = "USE_LIBCPP" - class GenericMultiSetDataFormatterTestCase(TestBase): def setUp(self): @@ -37,9 +34,8 @@ class GenericMultiSetDataFormatterTestCase(TestBase): var_name, type=self.getVariableType(var_name), children=children ) - def do_test_with_run_command(self, stdlib_type): + def do_test_with_run_command(self): """Test that that file and class static variables display correctly.""" - self.build(dictionary={stdlib_type: "1"}) (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set break point at this line.", lldb.SBFileSpec("main.cpp", False) ) @@ -129,9 +125,8 @@ class GenericMultiSetDataFormatterTestCase(TestBase): ], ) - def do_test_ref_and_ptr(self, stdlib_type): + def do_test_ref_and_ptr(self): """Test that the data formatters work on ref and ptr.""" - self.build(dictionary={stdlib_type: "1"}) (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint( self, "Stop here to check by ref and ptr.", @@ -145,16 +140,31 @@ class GenericMultiSetDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) def test_with_run_command_libstdcpp(self): - self.do_test_with_run_command(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_with_run_command() @add_test_categories(["libc++"]) def test_with_run_command_libcpp(self): - self.do_test_with_run_command(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_with_run_command() + + @add_test_categories(["msvcstl"]) + def test_with_run_command_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test_with_run_command() @add_test_categories(["libstdcxx"]) def test_ref_and_ptr_libstdcpp(self): - self.do_test_ref_and_ptr(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_ref_and_ptr() @add_test_categories(["libc++"]) def test_ref_and_ptr_libcpp(self): - self.do_test_ref_and_ptr(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_ref_and_ptr() + + @add_test_categories(["msvcstl"]) + def test_ref_and_ptr_msvcstl(self): + self.build() + self.do_test_ref_and_ptr() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py index d3d6ef55..1ac5e32 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/TestDataFormatterGenericSet.py @@ -8,9 +8,6 @@ from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * from lldbsuite.test import lldbutil -USE_LIBSTDCPP = "USE_LIBSTDCPP" -USE_LIBCPP = "USE_LIBCPP" - class GenericSetDataFormatterTestCase(TestBase): def setUp(self): @@ -37,9 +34,8 @@ class GenericSetDataFormatterTestCase(TestBase): var_name, type=self.getVariableType(var_name), children=children ) - def do_test_with_run_command(self, stdlib_type): + def do_test_with_run_command(self): """Test that that file and class static variables display correctly.""" - self.build(dictionary={stdlib_type: "1"}) (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint( self, "Set break point at this line.", lldb.SBFileSpec("main.cpp", False) ) @@ -74,6 +70,7 @@ class GenericSetDataFormatterTestCase(TestBase): "[5] = 5", ], ) + lldbutil.continue_to_breakpoint(process, bkpt) self.check("ii", 7) @@ -129,15 +126,22 @@ class GenericSetDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) def test_with_run_command_libstdcpp(self): - self.do_test_with_run_command(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_with_run_command() @add_test_categories(["libc++"]) def test_with_run_command_libcpp(self): - self.do_test_with_run_command(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_with_run_command() - def do_test_ref_and_ptr(self, stdlib_type): + @add_test_categories(["msvcstl"]) + def test_with_run_command_msvcstl(self): + # No flags, because the "msvcstl" category checks that the MSVC STL is used by default. + self.build() + self.do_test_with_run_command() + + def do_test_ref_and_ptr(self): """Test that the data formatters work on ref and ptr.""" - self.build(dictionary={stdlib_type: "1"}) (self.target, process, _, bkpt) = lldbutil.run_to_source_breakpoint( self, "Stop here to check by ref and ptr.", @@ -152,8 +156,15 @@ class GenericSetDataFormatterTestCase(TestBase): @add_test_categories(["libstdcxx"]) def test_ref_and_ptr_libstdcpp(self): - self.do_test_ref_and_ptr(USE_LIBSTDCPP) + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test_ref_and_ptr() @add_test_categories(["libc++"]) def test_ref_and_ptr_libcpp(self): - self.do_test_ref_and_ptr(USE_LIBCPP) + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test_ref_and_ptr() + + @add_test_categories(["msvcstl"]) + def test_ref_and_ptr_msvcstl(self): + self.build() + self.do_test_ref_and_ptr() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/main.cpp index 314d1e7..b029421 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/set/main.cpp @@ -27,8 +27,8 @@ int main() { ii.insert(3); ii.insert(4); ii.insert(5); - thefoo_rw(1); // Set break point at this line. + thefoo_rw(1); // Set break point at this line. ii.insert(6); thefoo_rw(1); // Set break point at this line. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py index 8c053f0..1811418 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py @@ -78,9 +78,6 @@ class StdStringViewDataFormatterTestCase(TestBase): "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"' ) self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""') - self.expect_var_path( - "oops", type="std::string_view", summary='"Hellooo World\\n"' - ) # GetSummary returns None so can't be checked by expect_var_path, so we # use the str representation instead @@ -163,3 +160,8 @@ class StdStringViewDataFormatterTestCase(TestBase): def test_libcxx(self): self.build(dictionary={"USE_LIBCPP": 1}) self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvcstl(self): + self.build() + self.do_test() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp index 1e164786b..e8781fb 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/main.cpp @@ -95,7 +95,6 @@ int main() { std::string_view *null_str = nullptr; std::string hello = "Hellooo "; - std::string_view oops = hello + "World\n"; q_source[0] = 'H'; // Set break point at this line. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile new file mode 100644 index 0000000..4f79c0a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +CXXFLAGS_EXTRAS := -std=c++20 + +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py new file mode 100644 index 0000000..1e35a0f --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py @@ -0,0 +1,44 @@ +# coding=utf8 +""" +Test std::u8string_view summary. +""" + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class StdU8StringViewDataFormatterTestCase(TestBase): + def do_test(self): + lldbutil.run_to_source_breakpoint( + self, "Set break point at this line.", lldb.SBFileSpec("main.cpp") + ) + + self.expect( + "frame variable", + substrs=[ + '(std::u8string_view) u8_string_small = u8"🍄"', + '(std::u8string_view) u8_string = u8"❤️👍📄📁😃🧑🌾"', + '(std::u8string_view) u8_empty = u8""', + '(std::u8string_view) u8_text = u8"ABCd"', + ], + ) + + @expectedFailureAll(bugnumber="No libc++ formatters for std::u8string_view yet.") + @add_test_categories(["libc++"]) + def test_libcxx(self): + self.build(dictionary={"USE_LIBCPP": 1}) + self.do_test() + + @expectedFailureAll(bugnumber="No libstdc++ formatters for std::u8string_view yet.") + @add_test_categories(["libstdcxx"]) + def test_libstdcxx(self): + self.build(dictionary={"USE_LIBSTDCPP": 1}) + self.do_test() + + @add_test_categories(["msvcstl"]) + def test_msvc(self): + self.build() + self.do_test() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp new file mode 100644 index 0000000..458e783 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/main.cpp @@ -0,0 +1,12 @@ +#include <cstdio> +#include <string_view> + +int main() { + std::u8string_view u8_string_small(u8"🍄"); + std::u8string_view u8_string(u8"❤️👍📄📁😃🧑🌾"); + std::u8string_view u8_empty(u8""); + std::u8string_view u8_text(u8"ABC"); + u8_text = u8"ABCd"; + + std::puts("// Set break point at this line."); +} diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py index 9a70f67..db5b5a0 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py @@ -692,6 +692,9 @@ class TestGDBServerTargetXML(GDBRemoteTestBase): "0102030405060708" # t4 "0102030405060708" # t5 "0102030405060708" # t6 + "6162636465666768" # pc + "0000C03F" # ft0 + "e07a6147a8a40940" # ft1 ) def qXferRead(self, obj, annex, offset, length): @@ -737,6 +740,10 @@ class TestGDBServerTargetXML(GDBRemoteTestBase): <reg name="t6" bitsize="64" type="int"/> <reg name="pc" bitsize="64" type="code_ptr"/> </feature> + <feature name='org.gnu.gdb.riscv.fpu'> + <reg name='ft0' bitsize='32' type='ieee_single'/> + <reg name='ft1' bitsize='64' type='ieee_double'/> + </feature> </target>""", False, ) @@ -799,6 +806,10 @@ class TestGDBServerTargetXML(GDBRemoteTestBase): self.match("register read x29", ["t4 = 0x0807060504030201"]) self.match("register read x30", ["t5 = 0x0807060504030201"]) self.match("register read x31", ["t6 = 0x0807060504030201"]) + self.match("register read pc", ["pc = 0x6867666564636261"]) + # test FPU registers + self.match("register read ft0", ["ft0 = 1.5"]) + self.match("register read ft1", ["ft1 = 3.2053990913985757"]) @skipIfXmlSupportMissing @skipIfRemote diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py index 733f40b..445f422 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py @@ -8,7 +8,6 @@ from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase LLDB_INVALID_ADDRESS = lldb.LLDB_INVALID_ADDRESS load_address = 0x400000000 - def format_register_value(val): """ Encode each byte by two hex digits in little-endian order. @@ -35,6 +34,8 @@ class MyResponder(MockGDBServerResponder): def respond(self, packet): if packet[0:13] == "qRegisterInfo": return self.qRegisterInfo(packet[13:]) + if packet.startswith("qWasmCallStack"): + return self.qWasmCallStack() return MockGDBServerResponder.respond(self, packet) def qSupported(self, client_supported): @@ -47,7 +48,7 @@ class MyResponder(MockGDBServerResponder): return "" def qfThreadInfo(self): - return "OK" + return "m1," def qRegisterInfo(self, index): if index == 0: @@ -61,7 +62,7 @@ class MyResponder(MockGDBServerResponder): ) def haltReason(self): - return "T05thread:1;" + return "T02thread:1;" def readRegister(self, register): return format_register_value(self.current_pc) @@ -89,6 +90,10 @@ class MyResponder(MockGDBServerResponder): file.close() return result + def qWasmCallStack(self): + # Return two 64-bit addresses: 0x40000000000001B3, 0x40000000000001FE + return "b301000000000040fe01000000000040" + class TestWasm(GDBRemoteTestBase): @skipIfAsan @@ -104,7 +109,7 @@ class TestWasm(GDBRemoteTestBase): self.server.responder = MyResponder(obj_path, "test_wasm") target = self.dbg.CreateTarget("") - process = self.connect(target) + process = self.connect(target, "wasm") lldbutil.expect_state_changes( self, self.dbg.GetListener(), process, [lldb.eStateStopped] ) @@ -174,7 +179,7 @@ class TestWasm(GDBRemoteTestBase): ) target = self.dbg.CreateTarget("") - process = self.connect(target) + process = self.connect(target, "wasm") lldbutil.expect_state_changes( self, self.dbg.GetListener(), process, [lldb.eStateStopped] ) @@ -230,7 +235,7 @@ class TestWasm(GDBRemoteTestBase): self.server.responder = MyResponder(obj_path) target = self.dbg.CreateTarget("") - process = self.connect(target) + process = self.connect(target, "wasm") lldbutil.expect_state_changes( self, self.dbg.GetListener(), process, [lldb.eStateStopped] ) @@ -272,3 +277,14 @@ class TestWasm(GDBRemoteTestBase): self.assertEqual( LLDB_INVALID_ADDRESS, debug_line_section.GetLoadAddress(target) ) + + thread = process.GetThreadAtIndex(0) + self.assertTrue(thread.IsValid()) + + frame = thread.GetFrameAtIndex(0) + self.assertTrue(frame.IsValid()) + self.assertEqual(frame.GetPC(), 0x40000000000001B3) + + frame = thread.GetFrameAtIndex(1) + self.assertTrue(frame.IsValid()) + self.assertEqual(frame.GetPC(), 0x40000000000001FE) diff --git a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py index bfdc822..825e1a4 100644 --- a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py +++ b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py @@ -10,8 +10,8 @@ from lldbsuite.test.lldbtest import * class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): NO_DEBUG_INFO_TESTCASE = True - MTE_BUF_ADDR = hex(0xFFFF82C74000) - BUF_ADDR = hex(0xFFFF82C73000) + MTE_BUF_ADDR = hex(0xFFFFA733B000) + BUF_ADDR = hex(0xFFFFA733A000) @skipIfLLVMTargetMissing("AArch64") def test_mte_tag_core_file_memory_region(self): @@ -215,7 +215,7 @@ class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): self.expect( "bt", substrs=[ - "* thread #1, name = 'a.out.mte', stop reason = SIGSEGV: sync tag check fault (fault address=0xffff82c74010)" + "* thread #1, name = 'a.out.mte', stop reason = SIGSEGV: sync tag check fault (fault address=0xffffa733b010)" ], ) @@ -231,12 +231,15 @@ class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase): self.runCmd("target create --core core.mte") # The expected value is: # * Allowed tags value of 0xFFFF, shifted up by 3 resulting in 0x7fff8. + # * Bit 19 set to 0, which means that store only checking is disabled. # * Bit 1 set to enable synchronous tag faults. # * Bit 0 set to enable the tagged address ABI. expected = ["mte_ctrl = 0x000000000007fffb"] if self.hasXMLSupport(): - expected.append("(TAGS = 65535, TCF = TCF_SYNC, TAGGED_ADDR_ENABLE = 1)") + expected.append( + "(STORE_ONLY = 0, TAGS = 65535, TCF = TCF_SYNC, TAGGED_ADDR_ENABLE = 1)" + ) self.expect("register read mte_ctrl", substrs=expected) diff --git a/lldb/test/API/linux/aarch64/mte_core_file/core.mte b/lldb/test/API/linux/aarch64/mte_core_file/core.mte Binary files differindex 84a3266..188d06d 100644 --- a/lldb/test/API/linux/aarch64/mte_core_file/core.mte +++ b/lldb/test/API/linux/aarch64/mte_core_file/core.mte diff --git a/lldb/test/API/linux/aarch64/mte_core_file/core.nomte b/lldb/test/API/linux/aarch64/mte_core_file/core.nomte Binary files differindex 201f288..454ff83 100644 --- a/lldb/test/API/linux/aarch64/mte_core_file/core.nomte +++ b/lldb/test/API/linux/aarch64/mte_core_file/core.nomte diff --git a/lldb/test/API/linux/aarch64/mte_core_file/main.c b/lldb/test/API/linux/aarch64/mte_core_file/main.c index 6537edd..5974594 100644 --- a/lldb/test/API/linux/aarch64/mte_core_file/main.c +++ b/lldb/test/API/linux/aarch64/mte_core_file/main.c @@ -23,7 +23,7 @@ int main(int argc, char const *argv[]) { #ifdef NO_MTE - *(char *)(0) = 0; + __builtin_trap(); #endif if (prctl(PR_SET_TAGGED_ADDR_CTRL, diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 6449ac5..b786edc 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -132,6 +132,10 @@ if(TARGET lldb-framework) add_lldb_test_dependency(lldb-framework) endif() +if (LLDB_CAN_USE_LLDB_RPC_SERVER) + add_lldb_test_dependency(lldb-rpc-generate-sources) +endif() + # Add dependencies that are not exported targets when building standalone. if(NOT LLDB_BUILT_STANDALONE) add_lldb_test_dependency( @@ -249,7 +253,8 @@ llvm_canonicalize_cmake_booleans( LLDB_TEST_SHELL_DISABLE_REMOTE LLDB_TOOL_LLDB_SERVER_BUILD LLDB_USE_SYSTEM_DEBUGSERVER - LLDB_IS_64_BITS) + LLDB_IS_64_BITS + LLDB_BUILD_LLDBRPC) # Configure the individual test suites. add_subdirectory(API) diff --git a/lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h b/lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h diff --git a/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test new file mode 100644 index 0000000..15fcf8f --- /dev/null +++ b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test @@ -0,0 +1,9 @@ +RUN: %lldb-rpc-gen --output-dir=%t %S/../Inputs/SBDummy.h + +RUN: ls %t | FileCheck %s + +# We're just making sure that the tool emits the class names, +# methods and skipped methods file in the output directory. +CHECK: SBAPI.def +CHECK: SBClasses.def +CHECK: SkippedMethods.txt diff --git a/lldb/test/Shell/RPC/Generator/lit.local.cfg b/lldb/test/Shell/RPC/Generator/lit.local.cfg new file mode 100644 index 0000000..db94947 --- /dev/null +++ b/lldb/test/Shell/RPC/Generator/lit.local.cfg @@ -0,0 +1,3 @@ +# All tests for the tool need lldb-rpc-gen to be built. +if not config.lldb_has_lldbrpc: + config.unsupported = True diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py index 42968128..728f634 100644 --- a/lldb/test/Shell/helper/toolchain.py +++ b/lldb/test/Shell/helper/toolchain.py @@ -156,6 +156,16 @@ def use_lldb_substitutions(config): extra_args=["platform"], unresolved="ignore", ), + ToolSubst( + "%lldb-rpc-gen", + command=FindTool("lldb-rpc-gen"), + # We need the LLDB build directory root to pass into the tool, not the test build root. + extra_args=[ + "-p " + config.lldb_build_directory + "/..", + '--extra-arg="-resource-dir=' + config.clang_resource_dir + '"', + ], + unresolved="ignore", + ), "lldb-test", "lldb-dap", ToolSubst( diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in index 5be5359..beaa41e 100644 --- a/lldb/test/Shell/lit.site.cfg.py.in +++ b/lldb/test/Shell/lit.site.cfg.py.in @@ -33,6 +33,7 @@ config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@" config.have_lldb_server = @LLDB_TOOL_LLDB_SERVER_BUILD@ config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@ config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@" +config.lldb_has_lldbrpc = @LLDB_BUILD_LLDBRPC@ # The shell tests use their own module caches. config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell") config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-shell") diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt index 6804dc2..e2f0395 100644 --- a/lldb/tools/CMakeLists.txt +++ b/lldb/tools/CMakeLists.txt @@ -10,6 +10,12 @@ add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL) add_lldb_tool_subdirectory(lldb-instr) add_lldb_tool_subdirectory(lldb-dap) +if (LLDB_BUILD_LLDBRPC) + add_lldb_tool_subdirectory(lldb-rpc-gen) +endif() +if (LLDB_CAN_USE_LLDB_RPC_SERVER) + add_subdirectory(lldb-rpc) +endif() if (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_lldb_tool_subdirectory(darwin-debug) diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 8be384c..102b2ab 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -21,6 +21,7 @@ #include <mach/exception_types.h> #include <mach/mach_vm.h> #include <mach/task_info.h> +#include <memory> #include <pwd.h> #include <string> #include <sys/stat.h> @@ -5410,9 +5411,8 @@ RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) { JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array()); for (nub_size_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) { - medata_array_sp->AddItem( - JSONGenerator::IntegerSP(new JSONGenerator::Integer( - tid_stop_info.details.exception.data[i]))); + medata_array_sp->AddItem(std::make_shared<JSONGenerator::Integer>( + tid_stop_info.details.exception.data[i])); } thread_dict_sp->AddItem("medata", medata_array_sp); } diff --git a/lldb/tools/lldb-rpc-gen/CMakeLists.txt b/lldb/tools/lldb-rpc-gen/CMakeLists.txt new file mode 100644 index 0000000..65b7643 --- /dev/null +++ b/lldb/tools/lldb-rpc-gen/CMakeLists.txt @@ -0,0 +1,23 @@ +add_lldb_tool(lldb-rpc-gen + RPCCommon.cpp + server/RPCServerHeaderEmitter.cpp + server/RPCServerSourceEmitter.cpp + lldb-rpc-gen.cpp + + CLANG_LIBS + clangAST + clangBasic + clangCodeGen + clangFrontend + clangLex + clangRewrite + clangSerialization + clangTooling + + LINK_COMPONENTS + Support + ) + +if (NOT DEFINED LLDB_RPC_GEN_EXE) + set(LLDB_RPC_GEN_EXE $<TARGET_FILE:lldb-rpc-gen> CACHE STRING "Executable that generates lldb-rpc-server") +endif() diff --git a/lldb/tools/lldb-rpc-gen/RPCCommon.cpp b/lldb/tools/lldb-rpc-gen/RPCCommon.cpp new file mode 100644 index 0000000..7af6ee3 --- /dev/null +++ b/lldb/tools/lldb-rpc-gen/RPCCommon.cpp @@ -0,0 +1,493 @@ +//===-- RPCCommon.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 "RPCCommon.h" + +#include "clang/AST/AST.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Mangle.h" +#include "clang/Lex/Lexer.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" + +#include <cstring> + +using namespace clang; + +// We intentionally do not generate some classes because they are currently +// inconvenient, they aren't really used by most consumers, or we're not sure +// why they exist. +static constexpr llvm::StringRef DisallowedClasses[] = { + "SBCommunication", // This class is pretty much unused by consumers, so we + // skip it. + "SBInputReader", // This class is pretty much unused by consumers, so we + // skip it. + "SBCommandPluginInterface", // This class uses virtual functions, and the SB + // API should not have those, so we skip this + // class. + "SBCommand", // There's nothing too difficult about this one, but many of + // its methods take a SBCommandPluginInterface pointer so + // there's no reason to support this. +}; + +// NOTE: In lldb-rpc-gen, we use mangled names when we need to work with +// functions. We do this because we support many functions that have overloads, +// and mangled names have no ambiguity which makes it easier to keep track of. +// This is also possible since the LLDB SB API is stable. + +// We intentionally avoid generating certain methods either because they are +// difficult to support correctly or they aren't really used much from C++. +// NOTE: These methods are marked as deprecated using LLDB_DEPRECATED. +// Normally this macro defines to the deprecated annotation, but this +// functionality is removed in SBDefines.h when generating SWIG bindings which +// we use for testing. Because of this, there is no annotation for the tool to +// pick up on so this list will be used while we have this restriction in +// SBDefines.h. +static constexpr llvm::StringRef DisallowedMethods[] = { + // The threading functionality in SBHostOS is deprecated and thus we do not + // generate them. It would be ideal to add the annotations to the methods + // and then support not generating deprecated methods. However, without + // annotations the generator generates most things correctly. This one is + // problematic because it returns a pointer to an "opaque" structure + // (thread_t) that is not `void *`, so special casing it is more effort than + // it's worth. + "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE", + "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE", + "_ZN4lldb8SBHostOS13ThreadCreatedEPKc", +}; + +static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = { + "SBHostOS", + "SBReproducer", +}; + +static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = { + "SBHostOS", + "SBReproducer", + "SBStream", + "SBProgress", +}; + +static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = { + "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm", + "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh", + "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym", + "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm", + "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm", + "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim", + "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm", + "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym", + "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm", + "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm", + "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim", + "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm", + "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm", + "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm", + "_ZN4lldb10SBDebugger13DispatchInputEPKvm", + "_ZN4lldb6SBFile4ReadEPhmPm", + "_ZN4lldb6SBFile5WriteEPKhmPm", + "_ZNK4lldb10SBFileSpec7GetPathEPcm", + "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm", + "_ZN4lldb8SBModule10GetVersionEPjj", + "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm", + "_ZNK4lldb9SBProcess9GetSTDOUTEPcm", + "_ZNK4lldb9SBProcess9GetSTDERREPcm", + "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm", + "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE", + "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE", + "_ZNK4lldb16SBStructuredData14GetStringValueEPcm", + "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_" + "14SBFileSpecListES6_", + "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE", + "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm", + "_ZN4lldb8SBTarget15GetInstructionsEyPKvm", + "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm", + "_ZN4lldb8SBThread18GetStopDescriptionEPcm", + // The below mangled names are used for dummy methods in shell tests + // that test the emitters' output. If you're adding any new mangled names + // from the actual SB API to this list please add them above. + "_ZN4lldb33SBRPC_" + "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm", + "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm", + "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm", +}; + +// These classes inherit from rpc::ObjectRef directly (as opposed to +// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI +// breaking, so we preserve that compatibility here. +// +// lldb-rpc-gen emits classes as LocalObjectRefs by default. +// +// FIXME: Does it matter which one it emits by default? +static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = { + "SBAddress", + "SBBreakpointName", + "SBCommandInterpreter", + "SBCommandReturnObject", + "SBError", + "SBExecutionContext", + "SBExpressionOptions", + "SBFileSpec", + "SBFileSpecList", + "SBFormat", + "SBFunction", + "SBHistoricalFrame", + "SBHistoricalLineEntry", + "SBHistoricalLineEntryList", + "SBLineEntry", + "SBStream", + "SBStringList", + "SBStructuredData", + "SBSymbolContext", + "SBSymbolContextList", + "SBTypeMember", + "SBTypeSummaryOptions", + "SBValueList", +}; + +QualType lldb_rpc_gen::GetUnderlyingType(QualType T) { + QualType UnderlyingType; + if (T->isPointerType()) + UnderlyingType = T->getPointeeType(); + else if (T->isReferenceType()) + UnderlyingType = T.getNonReferenceType(); + else + UnderlyingType = T; + + return UnderlyingType; +} + +QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) { + return GetUnderlyingType(T).getUnqualifiedType(); +} + +std::string lldb_rpc_gen::GetMangledName(ASTContext &Context, + CXXMethodDecl *MDecl) { + std::string Mangled; + llvm::raw_string_ostream MangledStream(Mangled); + + GlobalDecl GDecl; + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(MDecl)) + GDecl = GlobalDecl(CtorDecl, Ctor_Complete); + else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(MDecl)) + GDecl = GlobalDecl(DtorDecl, Dtor_Deleting); + else + GDecl = GlobalDecl(MDecl); + + MangleContext *MC = Context.createMangleContext(); + MC->mangleName(GDecl, MangledStream); + return Mangled; +} + +bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) { + auto CheckTypeForLLDBPrivate = [](const Type *Ty) { + if (!Ty) + return false; + const auto *CXXRDecl = Ty->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + const auto *NSDecl = + llvm::dyn_cast<NamespaceDecl>(CXXRDecl->getDeclContext()); + if (!NSDecl) + return false; + return NSDecl->getName() == "lldb_private"; + }; + + // First, get the underlying type (remove qualifications and strip off any + // pointers/references). Then we'll need to desugar this type. This will + // remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll + // actually see something like "std::shared_ptr<lldb_private::Debugger>". + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const Type *DesugaredType = + UnqualifiedUnderlyingType->getUnqualifiedDesugaredType(); + assert(DesugaredType && "DesugaredType from a valid Type is nullptr!"); + + // Check the type itself. + if (CheckTypeForLLDBPrivate(DesugaredType)) + return true; + + // If that didn't work, it's possible that the type has a template argument + // that is an lldb_private type. + if (const auto *TemplateSDecl = + llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>( + DesugaredType->getAsCXXRecordDecl())) { + for (const TemplateArgument &TA : + TemplateSDecl->getTemplateArgs().asArray()) { + if (TA.getKind() != TemplateArgument::Type) + continue; + if (CheckTypeForLLDBPrivate(TA.getAsType().getTypePtr())) + return true; + } + } + return false; +} + +bool lldb_rpc_gen::TypeIsSBClass(QualType T) { + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; // SB Classes are always C++ classes + + return CXXRDecl->getName().starts_with("SB"); +} + +bool lldb_rpc_gen::TypeIsConstCharPtr(QualType T) { + if (!T->isPointerType()) + return false; + + QualType UnderlyingType = T->getPointeeType(); + if (!UnderlyingType.isConstQualified()) + return false; + + // NOTE: We should be able to do `UnderlyingType->isCharType` but that will + // return true for `const uint8_t *` since that is effectively an unsigned + // char pointer. We currently do not support pointers other than `const char + // *` and `const char **`. + + // NOTE: Checking that the underlying type is a signed integer works on Darwin + // platforms, but Linux platforms expect that the underlying type is an + // unsigned integer. + return UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_S) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::SChar) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::Char_U) || + UnderlyingType->isSpecificBuiltinType(BuiltinType::UChar); +} + +bool lldb_rpc_gen::TypeIsConstCharPtrPtr(QualType T) { + if (!T->isPointerType()) + return false; + + return TypeIsConstCharPtr(T->getPointeeType()); +} + +bool lldb_rpc_gen::TypeIsDisallowedClass(QualType T) { + QualType UUT = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UUT->getAsCXXRecordDecl(); + if (!CXXRDecl) + return false; + + llvm::StringRef DeclName = CXXRDecl->getName(); + for (const llvm::StringRef DisallowedClass : DisallowedClasses) + if (DeclName == DisallowedClass) + return true; + return false; +} + +bool lldb_rpc_gen::TypeIsCallbackFunctionPointer(QualType T) { + return T->isFunctionPointerType(); +} + +bool lldb_rpc_gen::MethodIsDisallowed(ASTContext &Context, + CXXMethodDecl *MDecl) { + bool isDisallowed = false; + std::string MangledName = lldb_rpc_gen::GetMangledName(Context, MDecl); + if (llvm::is_contained(DisallowedMethods, MangledName)) + isDisallowed = true; + + if (MDecl->hasAttrs()) { + for (auto *attr : MDecl->getAttrs()) { + if (strcmp(attr->getAttrName()->getNameStart(), "deprecated") == 0) + isDisallowed = true; + } + } + return isDisallowed; +} + +// NOTE: There's possibly a more clever way to do this, but we're keeping +// the string replacement way here. Here is why it is written this way: +// By the time we have already created a `Method` object, we have extracted the +// `QualifiedName` and the relevant QualTypes for parameters/return types, many +// of which contains "lldb::" in them. To change it in a way that would be +// friendly to liblldbrpc, we would need to have a way of replacing that +// namespace at the time of creating a Method, and only for liblldbrpc methods. +// IMO this would complicate Method more than what I'm doing here, and not +// necessarily for any more benefit. +// In clang-tools-extra, there is a ChangeNamespaces tool which tries to do +// something similar to this. It also operates primarily on string replacement, +// but uses more sophisticated clang tooling to do so. +// For now, this will do what we need it to do. +std::string +lldb_rpc_gen::ReplaceLLDBNamespaceWithRPCNamespace(std::string Name) { + const char *lldb_namespace = "lldb::"; + auto Pos = Name.find(lldb_namespace); + while (Pos != std::string::npos) { + constexpr size_t SizeOfLLDBNamespace = 6; + Name.replace(Pos, SizeOfLLDBNamespace, "lldb_rpc::"); + Pos = Name.find(lldb_namespace); + } + return Name; +} + +std::string lldb_rpc_gen::StripLLDBNamespace(std::string Name) { + const char *lldb_namespace = "lldb::"; + auto Pos = Name.find(lldb_namespace); + if (Pos != std::string::npos) { + constexpr size_t SizeOfLLDBNamespace = 6; + Name = Name.substr(Pos + SizeOfLLDBNamespace); + } + return Name; +} + +bool lldb_rpc_gen::SBClassRequiresDefaultCtor(const std::string &ClassName) { + return !llvm::is_contained(ClassesWithoutDefaultCtor, ClassName); +} + +bool lldb_rpc_gen::SBClassRequiresCopyCtorAssign(const std::string &ClassName) { + return !llvm::is_contained(ClassesWithoutCopyOperations, ClassName); +} + +bool lldb_rpc_gen::SBClassInheritsFromObjectRef(const std::string &ClassName) { + return llvm::is_contained(ClassesThatInheritFromObjectRef, ClassName); +} + +std::string lldb_rpc_gen::GetSBClassNameFromType(QualType T) { + assert(lldb_rpc_gen::TypeIsSBClass(T) && + "Cannot get SBClass name from non-SB class type!"); + + QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T); + const auto *CXXRDecl = UnqualifiedUnderlyingType->getAsCXXRecordDecl(); + assert(CXXRDecl && "SB class was not CXXRecordDecl!"); + if (!CXXRDecl) + return std::string(); + + return CXXRDecl->getName().str(); +} +lldb_rpc_gen::Method::Method(CXXMethodDecl *MDecl, const PrintingPolicy &Policy, + ASTContext &Context) + : Policy(Policy), Context(Context), + QualifiedName(MDecl->getQualifiedNameAsString()), + BaseName(MDecl->getNameAsString()), + MangledName(lldb_rpc_gen::GetMangledName(Context, MDecl)), + ReturnType(MDecl->getReturnType()), IsConst(MDecl->isConst()), + IsInstance(MDecl->isInstance()), IsCtor(isa<CXXConstructorDecl>(MDecl)), + IsCopyAssign(MDecl->isCopyAssignmentOperator()), + IsMoveAssign(MDecl->isMoveAssignmentOperator()), + IsDtor(isa<CXXDestructorDecl>(MDecl)), + IsConversionMethod(isa<CXXConversionDecl>(MDecl)) { + uint8_t UnnamedArgIdx = 0; + bool PrevParamWasPointer = false; + for (const auto *ParamDecl : MDecl->parameters()) { + Param param; + if (ParamDecl->hasDefaultArg()) + param.DefaultValueText = + Lexer::getSourceText( + CharSourceRange::getTokenRange( + ParamDecl->getDefaultArg()->getSourceRange()), + Context.getSourceManager(), Context.getLangOpts()) + .str(); + + param.IsFollowedByLen = false; + param.Name = ParamDecl->getNameAsString(); + // If the parameter has no name, we'll generate one + if (param.Name.empty()) { + param.Name = "arg" + std::to_string(UnnamedArgIdx); + UnnamedArgIdx++; + } + param.Type = ParamDecl->getType(); + + // FIXME: Instead of using this heuristic, the ideal thing would be to add + // annotations to the SBAPI methods themselves. For now, we have a list of + // methods that we know will need this. + if (PrevParamWasPointer) { + PrevParamWasPointer = false; + const bool IsIntegerType = param.Type->isIntegerType() && + !param.Type->isBooleanType() && + !param.Type->isEnumeralType(); + if (IsIntegerType && llvm::is_contained(MethodsWithPointerPlusLen, + llvm::StringRef(MangledName))) + Params.back().IsFollowedByLen = true; + } + + if (param.Type->isPointerType() && + !lldb_rpc_gen::TypeIsConstCharPtr(param.Type) && + !param.Type->isFunctionPointerType()) + PrevParamWasPointer = true; + + if (param.Type->isFunctionPointerType()) + ContainsFunctionPointerParameter = true; + + Params.push_back(param); + } + + if (IsInstance) + ThisType = MDecl->getThisType(); + + if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(MDecl)) { + IsExplicitCtorOrConversionMethod = CtorDecl->isExplicit(); + IsCopyCtor = CtorDecl->isCopyConstructor(); + IsMoveCtor = CtorDecl->isMoveConstructor(); + } else if (const auto *ConversionDecl = dyn_cast<CXXConversionDecl>(MDecl)) + IsExplicitCtorOrConversionMethod = ConversionDecl->isExplicit(); +} + +// Adding a '<' allows us to use Methods in ordered containers. +// The ordering is on memory addresses. +bool lldb_rpc_gen::Method::operator<(const lldb_rpc_gen::Method &rhs) const { + return this < &rhs; +} + +std::string +lldb_rpc_gen::Method::CreateParamListAsString(GenerationKind Generation, + bool IncludeDefaultValue) const { + assert((!IncludeDefaultValue || Generation == eLibrary) && + "Default values should only be emitted on the library side!"); + + std::vector<std::string> ParamList; + + if (Generation == eLibrary && RequiresConnectionParameter()) + ParamList.push_back("const rpc::Connection &connection"); + + for (const auto &Param : Params) { + std::string ParamString; + llvm::raw_string_ostream ParamStringStream(ParamString); + + if (Generation == eLibrary) + ParamStringStream << lldb_rpc_gen::ReplaceLLDBNamespaceWithRPCNamespace( + Param.Type.getAsString(Policy)); + else + ParamStringStream << Param.Type.getAsString(Policy); + + ParamStringStream << " " << Param.Name; + if (IncludeDefaultValue && Generation == eLibrary && + !Param.DefaultValueText.empty()) + ParamStringStream << " = " + << lldb_rpc_gen::ReplaceLLDBNamespaceWithRPCNamespace( + Param.DefaultValueText); + + ParamList.push_back(ParamString); + } + + return llvm::join(ParamList, ", "); +} + +bool lldb_rpc_gen::Method::RequiresConnectionParameter() const { + if (!IsCtor && IsInstance) + return false; + if (IsCopyCtor || IsMoveCtor) + return false; + for (const auto &Param : Params) { + // We can re-use the connection from our parameter if possible. + // Const-qualified parameters are input parameters and already + // have a valid connection to provide to the current method. + if (TypeIsSBClass(Param.Type) && + GetUnderlyingType(Param.Type).isConstQualified()) + return false; + } + + return true; +} diff --git a/lldb/tools/lldb-rpc-gen/RPCCommon.h b/lldb/tools/lldb-rpc-gen/RPCCommon.h new file mode 100644 index 0000000..2a309d0 --- /dev/null +++ b/lldb/tools/lldb-rpc-gen/RPCCommon.h @@ -0,0 +1,107 @@ +//===-- RPCCommon.h -------------------------------------------------------===// +// +// 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_RPC_GEN_RPCCOMMON_H +#define LLDB_RPC_GEN_RPCCOMMON_H + +#include "clang/AST/AST.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/raw_ostream.h" + +#include <string> + +using namespace clang; + +namespace lldb_rpc_gen { +QualType GetUnderlyingType(QualType T); +QualType GetUnqualifiedUnderlyingType(QualType T); +std::string GetMangledName(ASTContext &Context, CXXMethodDecl *MDecl); + +bool TypeIsFromLLDBPrivate(QualType T); +bool TypeIsSBClass(QualType T); +bool TypeIsConstCharPtr(QualType T); +bool TypeIsConstCharPtrPtr(QualType T); +bool TypeIsDisallowedClass(QualType T); +bool TypeIsCallbackFunctionPointer(QualType T); + +bool MethodIsDisallowed(ASTContext &Context, CXXMethodDecl *MDecl); + +std::string ReplaceLLDBNamespaceWithRPCNamespace(std::string Name); +std::string StripLLDBNamespace(std::string Name); +bool SBClassRequiresDefaultCtor(const std::string &ClassName); +bool SBClassRequiresCopyCtorAssign(const std::string &ClassName); +bool SBClassInheritsFromObjectRef(const std::string &ClassName); +std::string GetSBClassNameFromType(QualType T); +struct Param { + std::string Name; + QualType Type; + std::string DefaultValueText; + bool IsFollowedByLen; +}; + +enum GenerationKind : bool { eServer, eLibrary }; + +struct Method { + enum Type { eOther, eConstructor, eDestructor }; + + Method(CXXMethodDecl *MDecl, const PrintingPolicy &Policy, + ASTContext &Context); + + // Adding a '<' allows us to use Methods in ordered containers. + // The ordering is on memory addresses. + bool operator<(const lldb_rpc_gen::Method &rhs) const; + const PrintingPolicy &Policy; + const ASTContext &Context; + std::string QualifiedName; + std::string BaseName; + std::string MangledName; + QualType ReturnType; + QualType ThisType; + std::vector<Param> Params; + bool IsConst = false; + bool IsInstance = false; + bool IsCtor = false; + bool IsCopyCtor = false; + bool IsCopyAssign = false; + bool IsMoveCtor = false; + bool IsMoveAssign = false; + bool IsDtor = false; + bool IsConversionMethod = false; + bool IsExplicitCtorOrConversionMethod = false; + bool ContainsFunctionPointerParameter = false; + + std::string CreateParamListAsString(GenerationKind Generation, + bool IncludeDefaultValue = false) const; + + bool RequiresConnectionParameter() const; +}; + +std::string +GetDefaultArgumentsForConstructor(std::string ClassName, + const lldb_rpc_gen::Method &method); + +class FileEmitter { +protected: + FileEmitter(std::unique_ptr<llvm::ToolOutputFile> &&OutputFile) + : OutputFile(std::move(OutputFile)), IndentLevel(0) {} + void EmitLine(const std::string &line) { + for (auto i = 0; i < IndentLevel; i++) + OutputFile->os() << " "; + + OutputFile->os() << line << "\n"; + } + + void EmitNewLine() { OutputFile->os() << "\n"; } + + std::unique_ptr<llvm::ToolOutputFile> OutputFile; + uint8_t IndentLevel; +}; +} // namespace lldb_rpc_gen +#endif // LLDB_RPC_GEN_RPCCOMMON_H diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp b/lldb/tools/lldb-rpc-gen/lldb-rpc-gen.cpp index e6b601e..9b48796 100644 --- a/lldb/tools/lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp +++ b/lldb/tools/lldb-rpc-gen/lldb-rpc-gen.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "RPCCommon.h" -#include "RPCServerHeaderEmitter.h" -#include "RPCServerSourceEmitter.h" +#include "server/RPCServerHeaderEmitter.h" +#include "server/RPCServerSourceEmitter.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" @@ -40,15 +40,15 @@ static llvm::cl::opt<std::string> llvm::cl::desc("Directory to output generated files to"), llvm::cl::init(""), llvm::cl::cat(RPCGenCategory)); -static std::string GetLibraryOutputDirectory() { +static std::string GetServerOutputDirectory() { llvm::SmallString<128> Path(OutputDir.getValue()); - llvm::sys::path::append(Path, "lib"); + llvm::sys::path::append(Path, "server"); return std::string(Path); } static std::unique_ptr<llvm::ToolOutputFile> CreateOutputFile(llvm::StringRef OutputDir, llvm::StringRef Filename) { - llvm::SmallString<128> Path(OutputDir); + llvm::SmallString<256> Path(OutputDir); llvm::sys::path::append(Path, Filename); std::error_code EC; @@ -100,9 +100,8 @@ public: for (CXXMethodDecl *MDecl : RDecl->methods()) { const std::string MangledName = lldb_rpc_gen::GetMangledName(Context, MDecl); - const bool IsDisallowed = lldb_rpc_gen::MethodIsDisallowed(MangledName); - const bool HasCallbackParameter = - lldb_rpc_gen::HasCallbackParameter(MDecl); + const bool IsDisallowed = + lldb_rpc_gen::MethodIsDisallowed(Context, MDecl); SupportLevel MethodSupportLevel = GetMethodSupportLevel(MDecl); if (MethodSupportLevel == eImplemented && !IsDisallowed) { const lldb_rpc_gen::Method Method(MDecl, Policy, Context); @@ -314,9 +313,9 @@ bool EmitClassNamesFile(std::set<std::string> &ClassNames) { if (!ClassNamesFile) return false; - ClassNamesFile->os() << "#ifndef SBCLASS\n"; - ClassNamesFile->os() << "#error \"SBClass must be defined\"\n"; - ClassNamesFile->os() << "#endif\n"; + ClassNamesFile->os() << "#ifndef SBCLASS\n" + << "#error \"SBClass must be defined\"\n" + << "#endif\n"; for (const auto &ClassName : ClassNames) { if (ClassName == "SBStream" || ClassName == "SBProgress") @@ -340,9 +339,9 @@ bool EmitMethodNamesFile(std::set<std::string> &MangledMethodNames) { if (!MethodNamesFile) return false; - MethodNamesFile->os() << "#ifndef GENERATE_SBAPI\n"; - MethodNamesFile->os() << "#error \"GENERATE_SBAPI must be defined\"\n"; - MethodNamesFile->os() << "#endif\n"; + MethodNamesFile->os() << "#ifndef GENERATE_SBAPI\n" + << "#error \"GENERATE_SBAPI must be defined\"\n" + << "#endif\n"; for (const auto &MangledName : MangledMethodNames) { MethodNamesFile->os() << "GENERATE_SBAPI(" << MangledName << ")\n"; @@ -358,9 +357,8 @@ bool EmitSkippedMethodsFile(std::set<std::string> &SkippedMethodNames) { if (!File) return false; - for (const auto &Skipped : SkippedMethodNames) { + for (const auto &Skipped : SkippedMethodNames) File->os() << Skipped << "\n"; - } File->keep(); return true; } @@ -381,6 +379,14 @@ int main(int argc, const char *argv[]) { return 1; } + // Create the output directory if the user specified one does not exist. + if (!llvm::sys::fs::exists(OutputDir.getValue())) { + llvm::sys::fs::create_directory(OutputDir.getValue()); + } + + if (!llvm::sys::fs::exists(GetServerOutputDirectory())) { + llvm::sys::fs::create_directory(GetServerOutputDirectory()); + } CommonOptionsParser &OP = ExpectedParser.get(); auto PCHOpts = std::make_shared<PCHContainerOperations>(); PCHOpts->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>()); diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerHeaderEmitter.cpp b/lldb/tools/lldb-rpc-gen/server/RPCServerHeaderEmitter.cpp index 30a18e3..30a18e3 100644 --- a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerHeaderEmitter.cpp +++ b/lldb/tools/lldb-rpc-gen/server/RPCServerHeaderEmitter.cpp diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerHeaderEmitter.h b/lldb/tools/lldb-rpc-gen/server/RPCServerHeaderEmitter.h index a0e4f47..a0e4f47 100644 --- a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerHeaderEmitter.h +++ b/lldb/tools/lldb-rpc-gen/server/RPCServerHeaderEmitter.h diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerSourceEmitter.cpp b/lldb/tools/lldb-rpc-gen/server/RPCServerSourceEmitter.cpp index a6d2528..a6d2528 100644 --- a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerSourceEmitter.cpp +++ b/lldb/tools/lldb-rpc-gen/server/RPCServerSourceEmitter.cpp diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerSourceEmitter.h b/lldb/tools/lldb-rpc-gen/server/RPCServerSourceEmitter.h index a371dc1..a371dc1 100644 --- a/lldb/tools/lldb-rpc/lldb-rpc-gen/server/RPCServerSourceEmitter.h +++ b/lldb/tools/lldb-rpc-gen/server/RPCServerSourceEmitter.h diff --git a/lldb/tools/lldb-rpc/CMakeLists.txt b/lldb/tools/lldb-rpc/CMakeLists.txt new file mode 100644 index 0000000..fdd6cf9 --- /dev/null +++ b/lldb/tools/lldb-rpc/CMakeLists.txt @@ -0,0 +1,22 @@ +include(CheckCXXCompilerFlag) +# Umbrella target for the entire framework is a default target. +add_custom_target(lldb-rpc ALL) + +if(LLDB_CODESIGN_IDENTITY) + # Use explicit LLDB identity + set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY}) +else() + # Use explicit LLVM identity or default to ad-hoc signing if empty + if(NOT LLVM_CODESIGNING_IDENTITY) + set(LLVM_CODESIGNING_IDENTITY -) + endif() +endif() + +# LLDBRPCGeneration.cmake needs the LLDB_RPC_GEN_EXE variable +# which gets defined in the lldb-rpc-gen folder, so we're adding +# this folder before we add that file. +add_lldb_tool_subdirectory(lldb-rpc-gen) +include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCGeneration.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCHeaders.cmake) + +add_dependencies(lldb-rpc lldb-rpc-generate-sources liblldbrpc-headers) diff --git a/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake b/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake new file mode 100644 index 0000000..a4cacf8 --- /dev/null +++ b/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake @@ -0,0 +1,80 @@ +if (NOT DEFINED LLDB_RPC_GEN_EXE) + message(FATAL_ERROR + "Unable to generate lldb-rpc sources because LLDB_RPC_GEN_EXE is not + defined. If you are cross-compiling, please build lldb-rpc-gen for your host + platform.") +endif() +set(lldb_rpc_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(lldb_rpc_server_generated_source_dir "${lldb_rpc_generated_dir}/server") + +file(GLOB api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SB*.h) +# We don't generate SBCommunication +list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBCommunication.h) +# SBDefines.h is mostly definitions and forward declarations, nothing to +# generate. +list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBDefines.h) + +# Generate the list of byproducts. Note that we cannot just glob the files in +# the directory with the generated sources because BYPRODUCTS needs to be known +# at configure time but the files are generated at build time. +set(lldb_rpc_gen_byproducts + ${lldb_rpc_generated_dir}/SBClasses.def + ${lldb_rpc_generated_dir}/SBAPI.def + ${lldb_rpc_generated_dir}/lldb.py + ${lldb_rpc_server_generated_source_dir}/SBAPI.h +) + +set(lldb_rpc_gen_server_impl_files) +foreach(path ${api_headers}) + get_filename_component(filename_no_ext ${path} NAME_WLE) + + set(server_header_file "Server_${filename_no_ext}.h") + list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_header_file}") + + set(server_impl_file "Server_${filename_no_ext}.cpp") + list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_impl_file}") + list(APPEND lldb_rpc_gen_server_impl_files "${lldb_rpc_server_generated_source_dir}/${server_impl_file}") + +endforeach() + +# Make sure that the clang-resource-dir is set correctly or else the tool will +# fail to run. This is only needed when we do a standalone build. +set(clang_resource_dir_arg) +if (TARGET clang-resource-headers) + set(clang_resource_headers_dir + $<TARGET_PROPERTY:clang-resource-headers,INTERFACE_INCLUDE_DIRECTORIES>) + set(clang_resource_dir_arg --extra-arg="-resource-dir=${clang_resource_headers_dir}/..") +else() + set(clang_resource_dir_arg --extra-arg="-resource-dir=${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}") +endif() + +set(sysroot_arg) +if (DEFINED TOOLCHAIN_TARGET_SYSROOTFS) + set(sysroot_arg --extra-arg="-resource-dir=${TOOLCHAIN_TARGET_SYSROOTFS}") +endif() + +add_custom_command(OUTPUT ${lldb_rpc_gen_byproducts} + COMMAND ${CMAKE_COMMAND} -E make_directory + ${lldb_rpc_generated_dir} + + COMMAND ${CMAKE_COMMAND} -E make_directory + ${lldb_rpc_server_generated_source_dir} + + COMMAND ${LLDB_RPC_GEN_EXE} + -p ${CMAKE_BINARY_DIR} + --output-dir=${lldb_rpc_generated_dir} + ${sysroot_arg} + --extra-arg="-USWIG" + ${api_headers} + + DEPENDS ${LLDB_RPC_GEN_EXE} ${api_headers} + COMMENT "Generating sources for lldb-rpc-server..." + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} +) + +add_custom_target(lldb-rpc-generate-sources + DEPENDS + ${lldb_rpc_gen_byproducts} + lldb-sbapi-dwarf-enums) + +add_dependencies(lldb-rpc-generate-sources clang-resource-headers) diff --git a/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake b/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake new file mode 100644 index 0000000..6c363f4 --- /dev/null +++ b/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake @@ -0,0 +1,101 @@ +set(derived_headers_location "${CMAKE_CURRENT_BINARY_DIR}/DerivedHeaders") + +# Obtain the original headers from their staged location in the build directory. +set(original_headers_location "${CMAKE_BINARY_DIR}/include/lldb") +set(headers_to_process + SBDefines.h + lldb-defines.h + lldb-enumerations.h + lldb-types.h +) + +file(MAKE_DIRECTORY ${derived_headers_location}) + +# Take the original headers and convert them RPC as necessary using the conversion script. +set(original_headers) +set(derived_headers) +foreach(header ${headers_to_process}) + set(original_header "${original_headers_location}/${header}") + + get_filename_component(header_filename ${header} NAME) + string(REPLACE "lldb-" "lldb-rpc-" rpc_header_filename "${header_filename}") + set(derived_header "${derived_headers_location}/${rpc_header_filename}") + + list(APPEND original_headers "${original_header}") + list(APPEND derived_headers "${derived_header}") + add_custom_command(OUTPUT ${derived_header} + COMMAND ${Python3_EXECUTABLE} ${LLDB_SOURCE_DIR}/scripts/convert-lldb-header-to-rpc-header.py + ${original_header} ${derived_header} + DEPENDS ${original_header} + + COMMENT "Creating ${derived_header}" + ) +endforeach() + +# Do the same thing for any header files that were autogenerated. +set(generated_headers_to_process + API/SBLanguages.h +) +foreach(header ${generated_headers_to_process}) + set(original_header "${LLDB_OBJ_DIR}/include/lldb/${header}") + + get_filename_component(header_filename ${header} NAME) + string(REPLACE "lldb-" "lldb-rpc-" rpc_header_filename "${header_filename}") + set(derived_header "${derived_headers_location}/${rpc_header_filename}") + + list(APPEND original_headers "${original_header}") + list(APPEND derived_headers "${derived_header}") + add_custom_command(OUTPUT ${derived_header} + COMMAND ${CMAKE_COMMAND} -E copy ${original_header} ${derived_header} + COMMAND ${Python3_EXECUTABLE} ${LLDB_SOURCE_DIR}/scripts/convert-lldb-header-to-rpc-header.py + ${original_header} ${derived_header} + DEPENDS lldb-sbapi-dwarf-enums + + COMMENT "Creating ${derived_header}" + ) +endforeach() + +add_custom_target(copy-aux-rpc-headers DEPENDS ${derived_headers}) +add_dependencies(copy-aux-rpc-headers liblldb-header-staging) + +list(APPEND public_headers + ${derived_headers_location}/SBDefines.h + ${derived_headers_location}/SBLanguages.h + ${derived_headers_location}/lldb-rpc-enumerations.h + ${derived_headers_location}/lldb-rpc-types.h + ${derived_headers_location}/lldb-rpc-defines.h +) + +# Collect and preprocess headers for the framework bundle +set(version_header + ${derived_headers_location}/lldb-rpc-defines.h +) + +function(FixIncludePaths in subfolder out) + get_filename_component(base_name ${in} NAME) + set(parked_header ${CMAKE_CURRENT_BINARY_DIR}/ParkedHeaders/${subfolder}/${base_name}) + set(${out} ${parked_header} PARENT_SCOPE) + find_program(unifdef_EXECUTABLE unifdef) + + add_custom_command(OUTPUT ${parked_header} + COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py + -f lldb_rpc -i ${in} -o ${parked_header} -p ${unifdef_EXECUTABLE} --unifdef_guards USWIG + DEPENDS ${in} + COMMENT "Fixing includes in ${in}" + ) +endfunction() + +set(preprocessed_headers) + +# Apply include-paths fix and any version fix on all headers and park them. +foreach(source_header ${public_headers}) + FixIncludePaths(${source_header} Headers parked_header) + list(APPEND preprocessed_headers ${parked_header}) +endforeach() + +# Wrap header preprocessing in a target, so liblldbrpc can depend on. +add_custom_target(liblldbrpc-headers DEPENDS ${preprocessed_headers}) +add_dependencies(liblldbrpc-headers copy-aux-rpc-headers liblldb-header-staging) +set_target_properties(liblldbrpc-headers PROPERTIES + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ParkedHeaders +) diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index f7b5e3a..fbb005b 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -80,20 +80,6 @@ lldb_private::python::SWIGBridge::LLDBSwigPythonCreateCommandObject( return python::PythonObject(); } -python::PythonObject lldb_private::python::SWIGBridge:: - LLDBSwigPythonCreateScriptedBreakpointResolver( - const char *python_class_name, const char *session_dictionary_name, - const StructuredDataImpl &args, const lldb::BreakpointSP &bkpt_sp) { - return python::PythonObject(); -} - -unsigned int -lldb_private::python::SWIGBridge::LLDBSwigPythonCallBreakpointResolver( - void *implementor, const char *method_name, - lldb_private::SymbolContext *sym_ctx) { - return 0; -} - size_t lldb_private::python::SWIGBridge::LLDBSwigPython_CalculateNumChildren( PyObject *implementor, uint32_t max) { return 0; @@ -144,6 +130,11 @@ lldb_private::python::LLDBSWIGPython_CastPyObjectToSBStream(PyObject *data) { return nullptr; } +void *lldb_private::python::LLDBSWIGPython_CastPyObjectToSBSymbolContext( + PyObject *data) { + return nullptr; +} + void * lldb_private::python::LLDBSWIGPython_CastPyObjectToSBValue(PyObject *data) { return nullptr; |